All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/14] arm64: Add SMCCC v1.1 support and CVE-2017-5715
@ 2018-01-26 14:28 ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

ARM has recently published a SMC Calling Convention (SMCCC)
specification update[1] that provides an optimised calling convention
and optional, discoverable support for mitigating CVE-2017-5715. ARM
Trusted Firmware (ATF) has already gained such an implementation[2].

This series addresses a few things:

- It provides a KVM implementation of PSCI v1.0, which is a
  prerequisite for being able to discover SMCCC v1.1, together with a
  new userspace API to control the PSCI revision number that the guest
  sees.

- It allows KVM to advertise SMCCC v1.1, which is de-facto supported
  already (it never corrupts any of the guest registers).

- It implements KVM support for the ARCH_WORKAROUND_1 function that is
  used to mitigate CVE-2017-5715 in a guest (if such mitigation is
  available on the host).

- It implements SMCCC v1.1 and ARCH_WORKAROUND_1 discovery support in
  the kernel itself.

- It finally provides firmware callbacks for CVE-2017-5715 for both
  kernel and KVM.

This method is intended to fully replace the initial PSCI_GET_VERSION
approach. Although PSCI_GET_VERSION still works, it has an obvious
overhead and is called on some of the hottest paths. We expect
ARCH_WORKAROUND_1 to be much faster.

Patch 1 is already merged, and included here for reference. Patches on
top of arm64/for-next/core. Tested on Seattle and Juno, the latter
with ATF implementing SMCCC v1.1.

[1]: https://developer.arm.com/-/media/developer/pdf/ARM%20DEN%200070A%20Firmware%20interfaces%20for%20mitigating%20CVE-2017-5715_V1.0.pdf

Hopefully this link is a persistent one. It is otherwise linked to
from [3], which is persistent.

[2]: https://github.com/ARM-software/arm-trusted-firmware/pull/1240

[3]: https://developer.arm.com/support/security-update/frequently-asked-questions

Marc Zyngier (14):
  arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
  arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
  arm/arm64: KVM: Consolidate the PSCI include files
  arm/arm64: KVM: Add PSCI_VERSION helper
  arm/arm64: KVM: Add smccc accessors to PSCI code
  arm/arm64: KVM: Implement PSCI 1.0 support
  arm/arm64: KVM: Add PSCI version selection API
  arm/arm64: KVM: Advertise SMCCC v1.1
  arm/arm64: KVM: Turn kvm_psci_version into a static inline
  arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support
  arm64: KVM: Add SMCCC_ARCH_WORKAROUND_1 fast handling
  firmware/psci: Expose PSCI conduit
  firmware/psci: Expose SMCCC version through psci_ops
  arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support

 Documentation/virtual/kvm/api.txt      |   3 +-
 Documentation/virtual/kvm/arm/psci.txt |  30 +++++
 arch/arm/include/asm/kvm_host.h        |   3 +
 arch/arm/include/asm/psci.h            |  25 ----
 arch/arm/include/uapi/asm/kvm.h        |   6 +
 arch/arm/kvm/guest.c                   |  13 +++
 arch/arm/kvm/handle_exit.c             |   8 +-
 arch/arm64/include/asm/kvm_host.h      |   3 +
 arch/arm64/include/asm/kvm_psci.h      |  27 -----
 arch/arm64/include/uapi/asm/kvm.h      |   6 +
 arch/arm64/kernel/bpi.S                |  20 ++++
 arch/arm64/kernel/cpu_errata.c         |  71 +++++++++++-
 arch/arm64/kvm/guest.c                 |  14 ++-
 arch/arm64/kvm/handle_exit.c           |   9 +-
 arch/arm64/kvm/hyp/hyp-entry.S         |  20 +++-
 arch/arm64/kvm/hyp/switch.c            |  20 ++--
 drivers/firmware/psci.c                |  48 +++++++-
 include/kvm/arm_psci.h                 |  63 ++++++++++
 include/linux/arm-smccc.h              |  18 +++
 include/linux/psci.h                   |  13 +++
 virt/kvm/arm/arm.c                     |   2 +-
 virt/kvm/arm/psci.c                    | 202 +++++++++++++++++++++++++++++----
 22 files changed, 522 insertions(+), 102 deletions(-)
 create mode 100644 Documentation/virtual/kvm/arm/psci.txt
 delete mode 100644 arch/arm/include/asm/psci.h
 delete mode 100644 arch/arm64/include/asm/kvm_psci.h
 create mode 100644 include/kvm/arm_psci.h

-- 
2.14.2

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 00/14] arm64: Add SMCCC v1.1 support and CVE-2017-5715
@ 2018-01-26 14:28 ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

ARM has recently published a SMC Calling Convention (SMCCC)
specification update[1] that provides an optimised calling convention
and optional, discoverable support for mitigating CVE-2017-5715. ARM
Trusted Firmware (ATF) has already gained such an implementation[2].

This series addresses a few things:

- It provides a KVM implementation of PSCI v1.0, which is a
  prerequisite for being able to discover SMCCC v1.1, together with a
  new userspace API to control the PSCI revision number that the guest
  sees.

- It allows KVM to advertise SMCCC v1.1, which is de-facto supported
  already (it never corrupts any of the guest registers).

- It implements KVM support for the ARCH_WORKAROUND_1 function that is
  used to mitigate CVE-2017-5715 in a guest (if such mitigation is
  available on the host).

- It implements SMCCC v1.1 and ARCH_WORKAROUND_1 discovery support in
  the kernel itself.

- It finally provides firmware callbacks for CVE-2017-5715 for both
  kernel and KVM.

This method is intended to fully replace the initial PSCI_GET_VERSION
approach. Although PSCI_GET_VERSION still works, it has an obvious
overhead and is called on some of the hottest paths. We expect
ARCH_WORKAROUND_1 to be much faster.

Patch 1 is already merged, and included here for reference. Patches on
top of arm64/for-next/core. Tested on Seattle and Juno, the latter
with ATF implementing SMCCC v1.1.

[1]: https://developer.arm.com/-/media/developer/pdf/ARM%20DEN%200070A%20Firmware%20interfaces%20for%20mitigating%20CVE-2017-5715_V1.0.pdf

Hopefully this link is a persistent one. It is otherwise linked to
from [3], which is persistent.

[2]: https://github.com/ARM-software/arm-trusted-firmware/pull/1240

[3]: https://developer.arm.com/support/security-update/frequently-asked-questions

Marc Zyngier (14):
  arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
  arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
  arm/arm64: KVM: Consolidate the PSCI include files
  arm/arm64: KVM: Add PSCI_VERSION helper
  arm/arm64: KVM: Add smccc accessors to PSCI code
  arm/arm64: KVM: Implement PSCI 1.0 support
  arm/arm64: KVM: Add PSCI version selection API
  arm/arm64: KVM: Advertise SMCCC v1.1
  arm/arm64: KVM: Turn kvm_psci_version into a static inline
  arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support
  arm64: KVM: Add SMCCC_ARCH_WORKAROUND_1 fast handling
  firmware/psci: Expose PSCI conduit
  firmware/psci: Expose SMCCC version through psci_ops
  arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support

 Documentation/virtual/kvm/api.txt      |   3 +-
 Documentation/virtual/kvm/arm/psci.txt |  30 +++++
 arch/arm/include/asm/kvm_host.h        |   3 +
 arch/arm/include/asm/psci.h            |  25 ----
 arch/arm/include/uapi/asm/kvm.h        |   6 +
 arch/arm/kvm/guest.c                   |  13 +++
 arch/arm/kvm/handle_exit.c             |   8 +-
 arch/arm64/include/asm/kvm_host.h      |   3 +
 arch/arm64/include/asm/kvm_psci.h      |  27 -----
 arch/arm64/include/uapi/asm/kvm.h      |   6 +
 arch/arm64/kernel/bpi.S                |  20 ++++
 arch/arm64/kernel/cpu_errata.c         |  71 +++++++++++-
 arch/arm64/kvm/guest.c                 |  14 ++-
 arch/arm64/kvm/handle_exit.c           |   9 +-
 arch/arm64/kvm/hyp/hyp-entry.S         |  20 +++-
 arch/arm64/kvm/hyp/switch.c            |  20 ++--
 drivers/firmware/psci.c                |  48 +++++++-
 include/kvm/arm_psci.h                 |  63 ++++++++++
 include/linux/arm-smccc.h              |  18 +++
 include/linux/psci.h                   |  13 +++
 virt/kvm/arm/arm.c                     |   2 +-
 virt/kvm/arm/psci.c                    | 202 +++++++++++++++++++++++++++++----
 22 files changed, 522 insertions(+), 102 deletions(-)
 create mode 100644 Documentation/virtual/kvm/arm/psci.txt
 delete mode 100644 arch/arm/include/asm/psci.h
 delete mode 100644 arch/arm64/include/asm/kvm_psci.h
 create mode 100644 include/kvm/arm_psci.h

-- 
2.14.2

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 00/14] arm64: Add SMCCC v1.1 support and CVE-2017-5715
@ 2018-01-26 14:28 ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

ARM has recently published a SMC Calling Convention (SMCCC)
specification update[1] that provides an optimised calling convention
and optional, discoverable support for mitigating CVE-2017-5715. ARM
Trusted Firmware (ATF) has already gained such an implementation[2].

This series addresses a few things:

- It provides a KVM implementation of PSCI v1.0, which is a
  prerequisite for being able to discover SMCCC v1.1, together with a
  new userspace API to control the PSCI revision number that the guest
  sees.

- It allows KVM to advertise SMCCC v1.1, which is de-facto supported
  already (it never corrupts any of the guest registers).

- It implements KVM support for the ARCH_WORKAROUND_1 function that is
  used to mitigate CVE-2017-5715 in a guest (if such mitigation is
  available on the host).

- It implements SMCCC v1.1 and ARCH_WORKAROUND_1 discovery support in
  the kernel itself.

- It finally provides firmware callbacks for CVE-2017-5715 for both
  kernel and KVM.

This method is intended to fully replace the initial PSCI_GET_VERSION
approach. Although PSCI_GET_VERSION still works, it has an obvious
overhead and is called on some of the hottest paths. We expect
ARCH_WORKAROUND_1 to be much faster.

Patch 1 is already merged, and included here for reference. Patches on
top of arm64/for-next/core. Tested on Seattle and Juno, the latter
with ATF implementing SMCCC v1.1.

[1]: https://developer.arm.com/-/media/developer/pdf/ARM%20DEN%200070A%20Firmware%20interfaces%20for%20mitigating%20CVE-2017-5715_V1.0.pdf

Hopefully this link is a persistent one. It is otherwise linked to
from [3], which is persistent.

[2]: https://github.com/ARM-software/arm-trusted-firmware/pull/1240

[3]: https://developer.arm.com/support/security-update/frequently-asked-questions

Marc Zyngier (14):
  arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
  arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
  arm/arm64: KVM: Consolidate the PSCI include files
  arm/arm64: KVM: Add PSCI_VERSION helper
  arm/arm64: KVM: Add smccc accessors to PSCI code
  arm/arm64: KVM: Implement PSCI 1.0 support
  arm/arm64: KVM: Add PSCI version selection API
  arm/arm64: KVM: Advertise SMCCC v1.1
  arm/arm64: KVM: Turn kvm_psci_version into a static inline
  arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support
  arm64: KVM: Add SMCCC_ARCH_WORKAROUND_1 fast handling
  firmware/psci: Expose PSCI conduit
  firmware/psci: Expose SMCCC version through psci_ops
  arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support

 Documentation/virtual/kvm/api.txt      |   3 +-
 Documentation/virtual/kvm/arm/psci.txt |  30 +++++
 arch/arm/include/asm/kvm_host.h        |   3 +
 arch/arm/include/asm/psci.h            |  25 ----
 arch/arm/include/uapi/asm/kvm.h        |   6 +
 arch/arm/kvm/guest.c                   |  13 +++
 arch/arm/kvm/handle_exit.c             |   8 +-
 arch/arm64/include/asm/kvm_host.h      |   3 +
 arch/arm64/include/asm/kvm_psci.h      |  27 -----
 arch/arm64/include/uapi/asm/kvm.h      |   6 +
 arch/arm64/kernel/bpi.S                |  20 ++++
 arch/arm64/kernel/cpu_errata.c         |  71 +++++++++++-
 arch/arm64/kvm/guest.c                 |  14 ++-
 arch/arm64/kvm/handle_exit.c           |   9 +-
 arch/arm64/kvm/hyp/hyp-entry.S         |  20 +++-
 arch/arm64/kvm/hyp/switch.c            |  20 ++--
 drivers/firmware/psci.c                |  48 +++++++-
 include/kvm/arm_psci.h                 |  63 ++++++++++
 include/linux/arm-smccc.h              |  18 +++
 include/linux/psci.h                   |  13 +++
 virt/kvm/arm/arm.c                     |   2 +-
 virt/kvm/arm/psci.c                    | 202 +++++++++++++++++++++++++++++----
 22 files changed, 522 insertions(+), 102 deletions(-)
 create mode 100644 Documentation/virtual/kvm/arm/psci.txt
 delete mode 100644 arch/arm/include/asm/psci.h
 delete mode 100644 arch/arm64/include/asm/kvm_psci.h
 create mode 100644 include/kvm/arm_psci.h

-- 
2.14.2

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 01/14] arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

KVM doesn't follow the SMCCC when it comes to unimplemented calls,
and inject an UNDEF instead of returning an error. Since firmware
calls are now used for security mitigation, they are becoming more
common, and the undef is counter productive.

Instead, let's follow the SMCCC which states that -1 must be returned
to the caller when getting an unknown function number.

Cc: <stable@vger.kernel.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/handle_exit.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index c09fc5a576c7..520b0dad3c62 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -53,7 +53,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -62,7 +62,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 01/14] arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

KVM doesn't follow the SMCCC when it comes to unimplemented calls,
and inject an UNDEF instead of returning an error. Since firmware
calls are now used for security mitigation, they are becoming more
common, and the undef is counter productive.

Instead, let's follow the SMCCC which states that -1 must be returned
to the caller when getting an unknown function number.

Cc: <stable@vger.kernel.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/handle_exit.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index c09fc5a576c7..520b0dad3c62 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -53,7 +53,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -62,7 +62,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 01/14] arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

KVM doesn't follow the SMCCC when it comes to unimplemented calls,
and inject an UNDEF instead of returning an error. Since firmware
calls are now used for security mitigation, they are becoming more
common, and the undef is counter productive.

Instead, let's follow the SMCCC which states that -1 must be returned
to the caller when getting an unknown function number.

Cc: <stable@vger.kernel.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/handle_exit.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index c09fc5a576c7..520b0dad3c62 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -53,7 +53,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -62,7 +62,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 02/14] arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

KVM doesn't follow the SMCCC when it comes to unimplemented calls,
and inject an UNDEF instead of returning an error. Since firmware
calls are now used for security mitigation, they are becoming more
common, and the undef is counter productive.

Instead, let's follow the SMCCC which states that -1 must be returned
to the caller when getting an unknown function number.

Cc: <stable@vger.kernel.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index cf8bf6bf87c4..d15ac772d186 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -38,7 +38,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -47,7 +47,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 02/14] arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

KVM doesn't follow the SMCCC when it comes to unimplemented calls,
and inject an UNDEF instead of returning an error. Since firmware
calls are now used for security mitigation, they are becoming more
common, and the undef is counter productive.

Instead, let's follow the SMCCC which states that -1 must be returned
to the caller when getting an unknown function number.

Cc: <stable@vger.kernel.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index cf8bf6bf87c4..d15ac772d186 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -38,7 +38,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -47,7 +47,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 02/14] arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

KVM doesn't follow the SMCCC when it comes to unimplemented calls,
and inject an UNDEF instead of returning an error. Since firmware
calls are now used for security mitigation, they are becoming more
common, and the undef is counter productive.

Instead, let's follow the SMCCC which states that -1 must be returned
to the caller when getting an unknown function number.

Cc: <stable@vger.kernel.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index cf8bf6bf87c4..d15ac772d186 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -38,7 +38,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -47,7 +47,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 03/14] arm/arm64: KVM: Consolidate the PSCI include files
  2018-01-26 14:28 ` Marc Zyngier
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

As we're about to update the PSCI support, and because I'm lazy,
let's move the PSCI include file to include/kvm so that both
ARM architectures can find it.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/psci.h                        | 25 ----------------------
 arch/arm/kvm/handle_exit.c                         |  2 +-
 arch/arm64/kvm/handle_exit.c                       |  3 ++-
 .../asm/kvm_psci.h => include/kvm/arm_psci.h       |  6 +++---
 virt/kvm/arm/arm.c                                 |  2 +-
 virt/kvm/arm/psci.c                                |  3 ++-
 6 files changed, 9 insertions(+), 32 deletions(-)
 delete mode 100644 arch/arm/include/asm/psci.h
 rename arch/arm64/include/asm/kvm_psci.h => include/kvm/arm_psci.h (89%)

diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
deleted file mode 100644
index e1b825dfab23..000000000000
--- a/arch/arm/include/asm/psci.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * Copyright (C) 2012 ARM Limited
- */
-
-#ifndef __ASM_ARM_PSCI_H
-#define __ASM_ARM_PSCI_H
-
-extern const struct smp_operations psci_smp_ops;
-
-#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
-bool psci_smp_available(void);
-#else
-static inline bool psci_smp_available(void) { return false; }
-#endif
-
-#endif /* __ASM_ARM_PSCI_H */
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index d15ac772d186..e020cc82c4b1 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -21,7 +21,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_mmu.h>
-#include <asm/kvm_psci.h>
+#include <kvm/arm_psci.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 520b0dad3c62..97e8d64a203d 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -22,13 +22,14 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 
+#include <kvm/arm_psci.h>
+
 #include <asm/esr.h>
 #include <asm/exception.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
-#include <asm/kvm_psci.h>
 #include <asm/debug-monitors.h>
 #include <asm/traps.h>
 
diff --git a/arch/arm64/include/asm/kvm_psci.h b/include/kvm/arm_psci.h
similarity index 89%
rename from arch/arm64/include/asm/kvm_psci.h
rename to include/kvm/arm_psci.h
index bc39e557c56c..2042bb909474 100644
--- a/arch/arm64/include/asm/kvm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -15,8 +15,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __ARM64_KVM_PSCI_H__
-#define __ARM64_KVM_PSCI_H__
+#ifndef __KVM_ARM_PSCI_H__
+#define __KVM_ARM_PSCI_H__
 
 #define KVM_ARM_PSCI_0_1	1
 #define KVM_ARM_PSCI_0_2	2
@@ -24,4 +24,4 @@
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
 
-#endif /* __ARM64_KVM_PSCI_H__ */
+#endif /* __KVM_ARM_PSCI_H__ */
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 15bf026eb182..af3e98fc377e 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -31,6 +31,7 @@
 #include <linux/irqbypass.h>
 #include <trace/events/kvm.h>
 #include <kvm/arm_pmu.h>
+#include <kvm/arm_psci.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -46,7 +47,6 @@
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
-#include <asm/kvm_psci.h>
 #include <asm/sections.h>
 
 #ifdef REQUIRES_VIRT
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index f1e363bab5e8..b322e46fd142 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -21,9 +21,10 @@
 
 #include <asm/cputype.h>
 #include <asm/kvm_emulate.h>
-#include <asm/kvm_psci.h>
 #include <asm/kvm_host.h>
 
+#include <kvm/arm_psci.h>
+
 #include <uapi/linux/psci.h>
 
 /*
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 03/14] arm/arm64: KVM: Consolidate the PSCI include files
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

As we're about to update the PSCI support, and because I'm lazy,
let's move the PSCI include file to include/kvm so that both
ARM architectures can find it.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/psci.h                        | 25 ----------------------
 arch/arm/kvm/handle_exit.c                         |  2 +-
 arch/arm64/kvm/handle_exit.c                       |  3 ++-
 .../asm/kvm_psci.h => include/kvm/arm_psci.h       |  6 +++---
 virt/kvm/arm/arm.c                                 |  2 +-
 virt/kvm/arm/psci.c                                |  3 ++-
 6 files changed, 9 insertions(+), 32 deletions(-)
 delete mode 100644 arch/arm/include/asm/psci.h
 rename arch/arm64/include/asm/kvm_psci.h => include/kvm/arm_psci.h (89%)

diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
deleted file mode 100644
index e1b825dfab23..000000000000
--- a/arch/arm/include/asm/psci.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * Copyright (C) 2012 ARM Limited
- */
-
-#ifndef __ASM_ARM_PSCI_H
-#define __ASM_ARM_PSCI_H
-
-extern const struct smp_operations psci_smp_ops;
-
-#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
-bool psci_smp_available(void);
-#else
-static inline bool psci_smp_available(void) { return false; }
-#endif
-
-#endif /* __ASM_ARM_PSCI_H */
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index d15ac772d186..e020cc82c4b1 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -21,7 +21,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_mmu.h>
-#include <asm/kvm_psci.h>
+#include <kvm/arm_psci.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 520b0dad3c62..97e8d64a203d 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -22,13 +22,14 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 
+#include <kvm/arm_psci.h>
+
 #include <asm/esr.h>
 #include <asm/exception.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
-#include <asm/kvm_psci.h>
 #include <asm/debug-monitors.h>
 #include <asm/traps.h>
 
diff --git a/arch/arm64/include/asm/kvm_psci.h b/include/kvm/arm_psci.h
similarity index 89%
rename from arch/arm64/include/asm/kvm_psci.h
rename to include/kvm/arm_psci.h
index bc39e557c56c..2042bb909474 100644
--- a/arch/arm64/include/asm/kvm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -15,8 +15,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __ARM64_KVM_PSCI_H__
-#define __ARM64_KVM_PSCI_H__
+#ifndef __KVM_ARM_PSCI_H__
+#define __KVM_ARM_PSCI_H__
 
 #define KVM_ARM_PSCI_0_1	1
 #define KVM_ARM_PSCI_0_2	2
@@ -24,4 +24,4 @@
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
 
-#endif /* __ARM64_KVM_PSCI_H__ */
+#endif /* __KVM_ARM_PSCI_H__ */
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 15bf026eb182..af3e98fc377e 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -31,6 +31,7 @@
 #include <linux/irqbypass.h>
 #include <trace/events/kvm.h>
 #include <kvm/arm_pmu.h>
+#include <kvm/arm_psci.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -46,7 +47,6 @@
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
-#include <asm/kvm_psci.h>
 #include <asm/sections.h>
 
 #ifdef REQUIRES_VIRT
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index f1e363bab5e8..b322e46fd142 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -21,9 +21,10 @@
 
 #include <asm/cputype.h>
 #include <asm/kvm_emulate.h>
-#include <asm/kvm_psci.h>
 #include <asm/kvm_host.h>
 
+#include <kvm/arm_psci.h>
+
 #include <uapi/linux/psci.h>
 
 /*
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 04/14] arm/arm64: KVM: Add PSCI_VERSION helper
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

As we're about to trigger a PSCI version explosion, it doesn't
hurt to introduce a PSCI_VERSION helper that is going to be
used everywhere.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/kvm/arm_psci.h | 5 +++--
 virt/kvm/arm/psci.c    | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 2042bb909474..3a408c846c09 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -18,8 +18,9 @@
 #ifndef __KVM_ARM_PSCI_H__
 #define __KVM_ARM_PSCI_H__
 
-#define KVM_ARM_PSCI_0_1	1
-#define KVM_ARM_PSCI_0_2	2
+#define PSCI_VERSION(x,y)	((((x) & 0x7fff) << 16) | ((y) & 0xffff))
+#define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
+#define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index b322e46fd142..c00bb324e14e 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -222,7 +222,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		 * Bits[31:16] = Major Version = 0
 		 * Bits[15:0] = Minor Version = 2
 		 */
-		val = 2;
+		val = KVM_ARM_PSCI_0_2;
 		break;
 	case PSCI_0_2_FN_CPU_SUSPEND:
 	case PSCI_0_2_FN64_CPU_SUSPEND:
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 04/14] arm/arm64: KVM: Add PSCI_VERSION helper
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

As we're about to trigger a PSCI version explosion, it doesn't
hurt to introduce a PSCI_VERSION helper that is going to be
used everywhere.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/kvm/arm_psci.h | 5 +++--
 virt/kvm/arm/psci.c    | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 2042bb909474..3a408c846c09 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -18,8 +18,9 @@
 #ifndef __KVM_ARM_PSCI_H__
 #define __KVM_ARM_PSCI_H__
 
-#define KVM_ARM_PSCI_0_1	1
-#define KVM_ARM_PSCI_0_2	2
+#define PSCI_VERSION(x,y)	((((x) & 0x7fff) << 16) | ((y) & 0xffff))
+#define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
+#define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index b322e46fd142..c00bb324e14e 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -222,7 +222,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		 * Bits[31:16] = Major Version = 0
 		 * Bits[15:0] = Minor Version = 2
 		 */
-		val = 2;
+		val = KVM_ARM_PSCI_0_2;
 		break;
 	case PSCI_0_2_FN_CPU_SUSPEND:
 	case PSCI_0_2_FN64_CPU_SUSPEND:
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 04/14] arm/arm64: KVM: Add PSCI_VERSION helper
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

As we're about to trigger a PSCI version explosion, it doesn't
hurt to introduce a PSCI_VERSION helper that is going to be
used everywhere.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/kvm/arm_psci.h | 5 +++--
 virt/kvm/arm/psci.c    | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 2042bb909474..3a408c846c09 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -18,8 +18,9 @@
 #ifndef __KVM_ARM_PSCI_H__
 #define __KVM_ARM_PSCI_H__
 
-#define KVM_ARM_PSCI_0_1	1
-#define KVM_ARM_PSCI_0_2	2
+#define PSCI_VERSION(x,y)	((((x) & 0x7fff) << 16) | ((y) & 0xffff))
+#define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
+#define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index b322e46fd142..c00bb324e14e 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -222,7 +222,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		 * Bits[31:16] = Major Version = 0
 		 * Bits[15:0] = Minor Version = 2
 		 */
-		val = 2;
+		val = KVM_ARM_PSCI_0_2;
 		break;
 	case PSCI_0_2_FN_CPU_SUSPEND:
 	case PSCI_0_2_FN64_CPU_SUSPEND:
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 05/14] arm/arm64: KVM: Add smccc accessors to PSCI code
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

Instead of open coding the accesses to the various registers,
let's add explicit SMCCC accessors.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/psci.c | 52 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 10 deletions(-)

diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index c00bb324e14e..053654082bd4 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -34,6 +34,38 @@
 
 #define AFFINITY_MASK(level)	~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1)
 
+static u32 smccc_get_function(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 0);
+}
+
+static unsigned long smccc_get_arg1(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 1);
+}
+
+static unsigned long smccc_get_arg2(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 2);
+}
+
+static unsigned long smccc_get_arg3(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 3);
+}
+
+static void smccc_set_retval(struct kvm_vcpu *vcpu,
+			     unsigned long a0,
+			     unsigned long a1,
+			     unsigned long a2,
+			     unsigned long a3)
+{
+	vcpu_set_reg(vcpu, 0, a0);
+	vcpu_set_reg(vcpu, 1, a1);
+	vcpu_set_reg(vcpu, 2, a2);
+	vcpu_set_reg(vcpu, 3, a3);
+}
+
 static unsigned long psci_affinity_mask(unsigned long affinity_level)
 {
 	if (affinity_level <= 3)
@@ -79,7 +111,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	unsigned long context_id;
 	phys_addr_t target_pc;
 
-	cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
+	cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK;
 	if (vcpu_mode_is_32bit(source_vcpu))
 		cpu_id &= ~((u32) 0);
 
@@ -98,8 +130,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 			return PSCI_RET_INVALID_PARAMS;
 	}
 
-	target_pc = vcpu_get_reg(source_vcpu, 2);
-	context_id = vcpu_get_reg(source_vcpu, 3);
+	target_pc = smccc_get_arg2(source_vcpu);
+	context_id = smccc_get_arg3(source_vcpu);
 
 	kvm_reset_vcpu(vcpu);
 
@@ -118,7 +150,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	 * NOTE: We always update r0 (or x0) because for PSCI v0.1
 	 * the general puspose registers are undefined upon CPU_ON.
 	 */
-	vcpu_set_reg(vcpu, 0, context_id);
+	smccc_set_retval(vcpu, context_id, 0, 0, 0);
 	vcpu->arch.power_off = false;
 	smp_mb();		/* Make sure the above is visible */
 
@@ -138,8 +170,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
 	struct kvm *kvm = vcpu->kvm;
 	struct kvm_vcpu *tmp;
 
-	target_affinity = vcpu_get_reg(vcpu, 1);
-	lowest_affinity_level = vcpu_get_reg(vcpu, 2);
+	target_affinity = smccc_get_arg1(vcpu);
+	lowest_affinity_level = smccc_get_arg2(vcpu);
 
 	/* Determine target affinity mask */
 	target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
@@ -212,7 +244,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+	u32 psci_fn = smccc_get_function(vcpu);
 	unsigned long val;
 	int ret = 1;
 
@@ -279,14 +311,14 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		break;
 	}
 
-	vcpu_set_reg(vcpu, 0, val);
+	smccc_set_retval(vcpu, val, 0, 0, 0);
 	return ret;
 }
 
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+	u32 psci_fn = smccc_get_function(vcpu);
 	unsigned long val;
 
 	switch (psci_fn) {
@@ -304,7 +336,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 		break;
 	}
 
-	vcpu_set_reg(vcpu, 0, val);
+	smccc_set_retval(vcpu, val, 0, 0, 0);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 05/14] arm/arm64: KVM: Add smccc accessors to PSCI code
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

Instead of open coding the accesses to the various registers,
let's add explicit SMCCC accessors.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/psci.c | 52 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 10 deletions(-)

diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index c00bb324e14e..053654082bd4 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -34,6 +34,38 @@
 
 #define AFFINITY_MASK(level)	~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1)
 
+static u32 smccc_get_function(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 0);
+}
+
+static unsigned long smccc_get_arg1(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 1);
+}
+
+static unsigned long smccc_get_arg2(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 2);
+}
+
+static unsigned long smccc_get_arg3(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 3);
+}
+
+static void smccc_set_retval(struct kvm_vcpu *vcpu,
+			     unsigned long a0,
+			     unsigned long a1,
+			     unsigned long a2,
+			     unsigned long a3)
+{
+	vcpu_set_reg(vcpu, 0, a0);
+	vcpu_set_reg(vcpu, 1, a1);
+	vcpu_set_reg(vcpu, 2, a2);
+	vcpu_set_reg(vcpu, 3, a3);
+}
+
 static unsigned long psci_affinity_mask(unsigned long affinity_level)
 {
 	if (affinity_level <= 3)
@@ -79,7 +111,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	unsigned long context_id;
 	phys_addr_t target_pc;
 
-	cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
+	cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK;
 	if (vcpu_mode_is_32bit(source_vcpu))
 		cpu_id &= ~((u32) 0);
 
@@ -98,8 +130,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 			return PSCI_RET_INVALID_PARAMS;
 	}
 
-	target_pc = vcpu_get_reg(source_vcpu, 2);
-	context_id = vcpu_get_reg(source_vcpu, 3);
+	target_pc = smccc_get_arg2(source_vcpu);
+	context_id = smccc_get_arg3(source_vcpu);
 
 	kvm_reset_vcpu(vcpu);
 
@@ -118,7 +150,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	 * NOTE: We always update r0 (or x0) because for PSCI v0.1
 	 * the general puspose registers are undefined upon CPU_ON.
 	 */
-	vcpu_set_reg(vcpu, 0, context_id);
+	smccc_set_retval(vcpu, context_id, 0, 0, 0);
 	vcpu->arch.power_off = false;
 	smp_mb();		/* Make sure the above is visible */
 
@@ -138,8 +170,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
 	struct kvm *kvm = vcpu->kvm;
 	struct kvm_vcpu *tmp;
 
-	target_affinity = vcpu_get_reg(vcpu, 1);
-	lowest_affinity_level = vcpu_get_reg(vcpu, 2);
+	target_affinity = smccc_get_arg1(vcpu);
+	lowest_affinity_level = smccc_get_arg2(vcpu);
 
 	/* Determine target affinity mask */
 	target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
@@ -212,7 +244,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+	u32 psci_fn = smccc_get_function(vcpu);
 	unsigned long val;
 	int ret = 1;
 
@@ -279,14 +311,14 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		break;
 	}
 
-	vcpu_set_reg(vcpu, 0, val);
+	smccc_set_retval(vcpu, val, 0, 0, 0);
 	return ret;
 }
 
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+	u32 psci_fn = smccc_get_function(vcpu);
 	unsigned long val;
 
 	switch (psci_fn) {
@@ -304,7 +336,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 		break;
 	}
 
-	vcpu_set_reg(vcpu, 0, val);
+	smccc_set_retval(vcpu, val, 0, 0, 0);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 05/14] arm/arm64: KVM: Add smccc accessors to PSCI code
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

Instead of open coding the accesses to the various registers,
let's add explicit SMCCC accessors.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/psci.c | 52 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 10 deletions(-)

diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index c00bb324e14e..053654082bd4 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -34,6 +34,38 @@
 
 #define AFFINITY_MASK(level)	~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1)
 
+static u32 smccc_get_function(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 0);
+}
+
+static unsigned long smccc_get_arg1(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 1);
+}
+
+static unsigned long smccc_get_arg2(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 2);
+}
+
+static unsigned long smccc_get_arg3(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 3);
+}
+
+static void smccc_set_retval(struct kvm_vcpu *vcpu,
+			     unsigned long a0,
+			     unsigned long a1,
+			     unsigned long a2,
+			     unsigned long a3)
+{
+	vcpu_set_reg(vcpu, 0, a0);
+	vcpu_set_reg(vcpu, 1, a1);
+	vcpu_set_reg(vcpu, 2, a2);
+	vcpu_set_reg(vcpu, 3, a3);
+}
+
 static unsigned long psci_affinity_mask(unsigned long affinity_level)
 {
 	if (affinity_level <= 3)
@@ -79,7 +111,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	unsigned long context_id;
 	phys_addr_t target_pc;
 
-	cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
+	cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK;
 	if (vcpu_mode_is_32bit(source_vcpu))
 		cpu_id &= ~((u32) 0);
 
@@ -98,8 +130,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 			return PSCI_RET_INVALID_PARAMS;
 	}
 
-	target_pc = vcpu_get_reg(source_vcpu, 2);
-	context_id = vcpu_get_reg(source_vcpu, 3);
+	target_pc = smccc_get_arg2(source_vcpu);
+	context_id = smccc_get_arg3(source_vcpu);
 
 	kvm_reset_vcpu(vcpu);
 
@@ -118,7 +150,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	 * NOTE: We always update r0 (or x0) because for PSCI v0.1
 	 * the general puspose registers are undefined upon CPU_ON.
 	 */
-	vcpu_set_reg(vcpu, 0, context_id);
+	smccc_set_retval(vcpu, context_id, 0, 0, 0);
 	vcpu->arch.power_off = false;
 	smp_mb();		/* Make sure the above is visible */
 
@@ -138,8 +170,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
 	struct kvm *kvm = vcpu->kvm;
 	struct kvm_vcpu *tmp;
 
-	target_affinity = vcpu_get_reg(vcpu, 1);
-	lowest_affinity_level = vcpu_get_reg(vcpu, 2);
+	target_affinity = smccc_get_arg1(vcpu);
+	lowest_affinity_level = smccc_get_arg2(vcpu);
 
 	/* Determine target affinity mask */
 	target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
@@ -212,7 +244,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+	u32 psci_fn = smccc_get_function(vcpu);
 	unsigned long val;
 	int ret = 1;
 
@@ -279,14 +311,14 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 		break;
 	}
 
-	vcpu_set_reg(vcpu, 0, val);
+	smccc_set_retval(vcpu, val, 0, 0, 0);
 	return ret;
 }
 
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+	u32 psci_fn = smccc_get_function(vcpu);
 	unsigned long val;
 
 	switch (psci_fn) {
@@ -304,7 +336,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 		break;
 	}
 
-	vcpu_set_reg(vcpu, 0, val);
+	smccc_set_retval(vcpu, val, 0, 0, 0);
 	return 1;
 }
 
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 06/14] arm/arm64: KVM: Implement PSCI 1.0 support
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

PSCI 1.0 can be trivially implemented by having PSCI 0.2 and
the FEATURES call. Of, and returning 1.0 as the PSCI version.

We happily ignore everything else, as it is optional.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/kvm/arm_psci.h |  1 +
 virt/kvm/arm/psci.c    | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 3a408c846c09..e7f69c0dc249 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -21,6 +21,7 @@
 #define PSCI_VERSION(x,y)	((((x) & 0x7fff) << 16) | ((y) & 0xffff))
 #define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
+#define KVM_ARM_PSCI_1_0	PSCI_VERSION(1, 0)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 053654082bd4..6299501f7664 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -315,6 +315,47 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 	return ret;
 }
 
+static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
+{
+	u32 psci_fn = smccc_get_function(vcpu);
+	u32 feature;
+	unsigned long val;
+	int ret = 1;
+
+	switch(psci_fn) {
+	case PSCI_0_2_FN_PSCI_VERSION:
+		val = KVM_ARM_PSCI_1_0;
+		break;
+	case PSCI_1_0_FN_PSCI_FEATURES:
+		feature = smccc_get_arg1(vcpu);
+		switch(feature) {
+		case PSCI_0_2_FN_PSCI_VERSION:
+		case PSCI_0_2_FN_CPU_SUSPEND:
+		case PSCI_0_2_FN64_CPU_SUSPEND:
+		case PSCI_0_2_FN_CPU_OFF:
+		case PSCI_0_2_FN_CPU_ON:
+		case PSCI_0_2_FN64_CPU_ON:
+		case PSCI_0_2_FN_AFFINITY_INFO:
+		case PSCI_0_2_FN64_AFFINITY_INFO:
+		case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+		case PSCI_0_2_FN_SYSTEM_OFF:
+		case PSCI_0_2_FN_SYSTEM_RESET:
+		case PSCI_1_0_FN_PSCI_FEATURES:
+			val = 0;
+			break;
+		default:
+			val = PSCI_RET_NOT_SUPPORTED;
+			break;
+		}
+		break;
+	default:
+		return kvm_psci_0_2_call(vcpu);
+	}
+
+	smccc_set_retval(vcpu, val, 0, 0, 0);
+	return ret;
+}
+
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
@@ -357,6 +398,8 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
 	switch (kvm_psci_version(vcpu)) {
+	case KVM_ARM_PSCI_1_0:
+		return kvm_psci_1_0_call(vcpu);
 	case KVM_ARM_PSCI_0_2:
 		return kvm_psci_0_2_call(vcpu);
 	case KVM_ARM_PSCI_0_1:
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 06/14] arm/arm64: KVM: Implement PSCI 1.0 support
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

PSCI 1.0 can be trivially implemented by having PSCI 0.2 and
the FEATURES call. Of, and returning 1.0 as the PSCI version.

We happily ignore everything else, as it is optional.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/kvm/arm_psci.h |  1 +
 virt/kvm/arm/psci.c    | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 3a408c846c09..e7f69c0dc249 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -21,6 +21,7 @@
 #define PSCI_VERSION(x,y)	((((x) & 0x7fff) << 16) | ((y) & 0xffff))
 #define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
+#define KVM_ARM_PSCI_1_0	PSCI_VERSION(1, 0)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 053654082bd4..6299501f7664 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -315,6 +315,47 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 	return ret;
 }
 
+static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
+{
+	u32 psci_fn = smccc_get_function(vcpu);
+	u32 feature;
+	unsigned long val;
+	int ret = 1;
+
+	switch(psci_fn) {
+	case PSCI_0_2_FN_PSCI_VERSION:
+		val = KVM_ARM_PSCI_1_0;
+		break;
+	case PSCI_1_0_FN_PSCI_FEATURES:
+		feature = smccc_get_arg1(vcpu);
+		switch(feature) {
+		case PSCI_0_2_FN_PSCI_VERSION:
+		case PSCI_0_2_FN_CPU_SUSPEND:
+		case PSCI_0_2_FN64_CPU_SUSPEND:
+		case PSCI_0_2_FN_CPU_OFF:
+		case PSCI_0_2_FN_CPU_ON:
+		case PSCI_0_2_FN64_CPU_ON:
+		case PSCI_0_2_FN_AFFINITY_INFO:
+		case PSCI_0_2_FN64_AFFINITY_INFO:
+		case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+		case PSCI_0_2_FN_SYSTEM_OFF:
+		case PSCI_0_2_FN_SYSTEM_RESET:
+		case PSCI_1_0_FN_PSCI_FEATURES:
+			val = 0;
+			break;
+		default:
+			val = PSCI_RET_NOT_SUPPORTED;
+			break;
+		}
+		break;
+	default:
+		return kvm_psci_0_2_call(vcpu);
+	}
+
+	smccc_set_retval(vcpu, val, 0, 0, 0);
+	return ret;
+}
+
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
@@ -357,6 +398,8 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
 	switch (kvm_psci_version(vcpu)) {
+	case KVM_ARM_PSCI_1_0:
+		return kvm_psci_1_0_call(vcpu);
 	case KVM_ARM_PSCI_0_2:
 		return kvm_psci_0_2_call(vcpu);
 	case KVM_ARM_PSCI_0_1:
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 06/14] arm/arm64: KVM: Implement PSCI 1.0 support
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

PSCI 1.0 can be trivially implemented by having PSCI 0.2 and
the FEATURES call. Of, and returning 1.0 as the PSCI version.

We happily ignore everything else, as it is optional.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/kvm/arm_psci.h |  1 +
 virt/kvm/arm/psci.c    | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 3a408c846c09..e7f69c0dc249 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -21,6 +21,7 @@
 #define PSCI_VERSION(x,y)	((((x) & 0x7fff) << 16) | ((y) & 0xffff))
 #define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
+#define KVM_ARM_PSCI_1_0	PSCI_VERSION(1, 0)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 053654082bd4..6299501f7664 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -315,6 +315,47 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 	return ret;
 }
 
+static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
+{
+	u32 psci_fn = smccc_get_function(vcpu);
+	u32 feature;
+	unsigned long val;
+	int ret = 1;
+
+	switch(psci_fn) {
+	case PSCI_0_2_FN_PSCI_VERSION:
+		val = KVM_ARM_PSCI_1_0;
+		break;
+	case PSCI_1_0_FN_PSCI_FEATURES:
+		feature = smccc_get_arg1(vcpu);
+		switch(feature) {
+		case PSCI_0_2_FN_PSCI_VERSION:
+		case PSCI_0_2_FN_CPU_SUSPEND:
+		case PSCI_0_2_FN64_CPU_SUSPEND:
+		case PSCI_0_2_FN_CPU_OFF:
+		case PSCI_0_2_FN_CPU_ON:
+		case PSCI_0_2_FN64_CPU_ON:
+		case PSCI_0_2_FN_AFFINITY_INFO:
+		case PSCI_0_2_FN64_AFFINITY_INFO:
+		case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+		case PSCI_0_2_FN_SYSTEM_OFF:
+		case PSCI_0_2_FN_SYSTEM_RESET:
+		case PSCI_1_0_FN_PSCI_FEATURES:
+			val = 0;
+			break;
+		default:
+			val = PSCI_RET_NOT_SUPPORTED;
+			break;
+		}
+		break;
+	default:
+		return kvm_psci_0_2_call(vcpu);
+	}
+
+	smccc_set_retval(vcpu, val, 0, 0, 0);
+	return ret;
+}
+
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
@@ -357,6 +398,8 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
 	switch (kvm_psci_version(vcpu)) {
+	case KVM_ARM_PSCI_1_0:
+		return kvm_psci_1_0_call(vcpu);
 	case KVM_ARM_PSCI_0_2:
 		return kvm_psci_0_2_call(vcpu);
 	case KVM_ARM_PSCI_0_1:
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 07/14] arm/arm64: KVM: Add PSCI version selection API
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

Although we've implemented PSCI 1.0 and 1.1, nothing can select them
Since all the new PSCI versions are backward compatible, we decide to
default to the latest version of the PSCI implementation. This is no
different from doing a firmware upgrade on KVM.

But in order to give a chance to hypothetical badly implemented guests
that would have a fit by discovering something other than PSCI 0.2,
let's provide a new API that allows userspace to pick one particular
version of the API.

This is implemented as a new class of "firmware" registers, where
we expose the PSCI version. This allows the PSCI version to be
save/restored as part of a guest migration, and also set to
any supported version if the guest requires it.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 Documentation/virtual/kvm/api.txt      |  3 +-
 Documentation/virtual/kvm/arm/psci.txt | 28 ++++++++++++++
 arch/arm/include/asm/kvm_host.h        |  3 ++
 arch/arm/include/uapi/asm/kvm.h        |  6 +++
 arch/arm/kvm/guest.c                   | 13 +++++++
 arch/arm64/include/asm/kvm_host.h      |  3 ++
 arch/arm64/include/uapi/asm/kvm.h      |  6 +++
 arch/arm64/kvm/guest.c                 | 14 ++++++-
 include/kvm/arm_psci.h                 |  9 +++++
 virt/kvm/arm/psci.c                    | 68 +++++++++++++++++++++++++++++++++-
 10 files changed, 149 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/virtual/kvm/arm/psci.txt

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 57d3ee9e4bde..334905202141 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2493,7 +2493,8 @@ Possible features:
 	  and execute guest code when KVM_RUN is called.
 	- KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
 	  Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
-	- KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU.
+	- KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision
+          backward compatible with v0.2) for the CPU.
 	  Depends on KVM_CAP_ARM_PSCI_0_2.
 	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
 	  Depends on KVM_CAP_ARM_PMU_V3.
diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt
new file mode 100644
index 000000000000..2e49a4e9f084
--- /dev/null
+++ b/Documentation/virtual/kvm/arm/psci.txt
@@ -0,0 +1,28 @@
+KVM implements the PSCI (Power State Coordination Interface)
+specification in order to provide services such as CPU on/off, reset
+and power-off to the guest.
+
+The PSCI specification is regularly updated to provide new features,
+and KVM implements these updates if they make sense from a virtualization
+point of view.
+
+This means that a guest booted on two different versions of KVM can
+observe two different "firmware" revisions. This could cause issues if
+a given guest is tied to a particular PSCI revision (unlikely), or if
+a migration causes a different PSCI version to be exposed out of the
+blue to an unsuspecting guest.
+
+In order to remedy this situation, KVM exposes a set of "firmware
+pseuodo-registers" that can be manipulated using the GET/SET_ONE_REG
+interface. These registers can be saved/restored by userspace, and set
+to a convenient value if required.
+
+The following register is defined:
+
+* KVM_REG_ARM_PSCI_VERSION:
+
+  - Only valid if the vcpu has KVM_ARM_VCPU_PSCI_0_2 feature set
+  - Returns the current PSCI version on GET_ONE_REG
+  - Allows any supported PSCI version compatible with v0.2 to be set
+    with SET_ONE_REG
+  - Affects the whole VM (even if the register view is per-vcpu)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index acbf9ec7b396..e9d57060d88c 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -75,6 +75,9 @@ struct kvm_arch {
 	/* Interrupt controller */
 	struct vgic_dist	vgic;
 	int max_vcpus;
+
+	/* Mandated version of PSCI */
+	u32 psci_version;
 };
 
 #define KVM_NR_MEM_OBJS     40
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 6edd177bb1c7..47dfc99f5cd0 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -186,6 +186,12 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_VFP_FPINST		0x1009
 #define KVM_REG_ARM_VFP_FPINST2		0x100A
 
+/* KVM-as-firmware specific pseudo-registers */
+#define KVM_REG_ARM_FW			(0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_REG(r)		(KVM_REG_ARM | KVM_REG_SIZE_U64 | \
+					 KVM_REG_ARM_FW | ((r) & 0xffff))
+#define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 1e0784ebbfd6..a18f33edc471 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/kvm.h>
@@ -176,6 +177,7 @@ static unsigned long num_core_regs(void)
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
 	return num_core_regs() + kvm_arm_num_coproc_regs(vcpu)
+		+ kvm_arm_get_fw_num_regs(vcpu)
 		+ NUM_TIMER_REGS;
 }
 
@@ -196,6 +198,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		uindices++;
 	}
 
+	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
+	if (ret)
+		return ret;
+	uindices += kvm_arm_get_fw_num_regs(vcpu);
+
 	ret = copy_timer_indices(vcpu, uindices);
 	if (ret)
 		return ret;
@@ -214,6 +221,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return get_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_get_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return get_timer_reg(vcpu, reg);
 
@@ -230,6 +240,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return set_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_set_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return set_timer_reg(vcpu, reg);
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 4485ae8e98de..10af386642c6 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -73,6 +73,9 @@ struct kvm_arch {
 
 	/* Interrupt controller */
 	struct vgic_dist	vgic;
+
+	/* Mandated version of PSCI */
+	u32 psci_version;
 };
 
 #define KVM_NR_MEM_OBJS     40
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9abbf3044654..04b3256f8e6d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -206,6 +206,12 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_TIMER_CNT		ARM64_SYS_REG(3, 3, 14, 3, 2)
 #define KVM_REG_ARM_TIMER_CVAL		ARM64_SYS_REG(3, 3, 14, 0, 2)
 
+/* KVM-as-firmware specific pseudo-registers */
+#define KVM_REG_ARM_FW			(0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+					 KVM_REG_ARM_FW | ((r) & 0xffff))
+#define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 5c7f657dd207..811f04c5760e 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/kvm.h>
@@ -205,7 +206,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
 	return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu)
-                + NUM_TIMER_REGS;
+		+ kvm_arm_get_fw_num_regs(vcpu)	+ NUM_TIMER_REGS;
 }
 
 /**
@@ -225,6 +226,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		uindices++;
 	}
 
+	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
+	if (ret)
+		return ret;
+	uindices += kvm_arm_get_fw_num_regs(vcpu);
+
 	ret = copy_timer_indices(vcpu, uindices);
 	if (ret)
 		return ret;
@@ -243,6 +249,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return get_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_get_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return get_timer_reg(vcpu, reg);
 
@@ -259,6 +268,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return set_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_set_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return set_timer_reg(vcpu, reg);
 
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index e7f69c0dc249..f2fa7d752c4e 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -23,7 +23,16 @@
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
 #define KVM_ARM_PSCI_1_0	PSCI_VERSION(1, 0)
 
+#define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
+
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
 
+struct kvm_one_reg;
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+
 #endif /* __KVM_ARM_PSCI_H__ */
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 6299501f7664..682f9be6264b 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -17,6 +17,7 @@
 
 #include <linux/preempt.h>
 #include <linux/kvm_host.h>
+#include <linux/uaccess.h>
 #include <linux/wait.h>
 
 #include <asm/cputype.h>
@@ -235,8 +236,19 @@ static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu)
 {
-	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
-		return KVM_ARM_PSCI_0_2;
+	/*
+	 * Our PSCI implementation stays the same across versions from
+	 * v0.2 onward, only adding the few mandatory functions (such
+	 * as FEATURES with 1.0) that are required by newer
+	 * revisions. It is thus safe to return the latest, unless
+	 * userspace has instructed us otherwise.
+	 */
+	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
+		if (vcpu->kvm->arch.psci_version)
+			return vcpu->kvm->arch.psci_version;
+
+		return KVM_ARM_PSCI_LATEST;
+	}
 
 	return KVM_ARM_PSCI_0_1;
 }
@@ -408,3 +420,55 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	};
 }
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
+{
+	return 1;		/* PSCI version */
+}
+
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+	if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices))
+		return -EFAULT;
+
+	return 0;
+}
+
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (reg->id == KVM_REG_ARM_PSCI_VERSION) {
+		void __user *uaddr = (void __user *)(long)reg->addr;
+		u64 val;
+
+		val = kvm_psci_version(vcpu, vcpu->kvm);
+		if (val == KVM_ARM_PSCI_0_1)
+			return -EINVAL;
+		if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (reg->id == KVM_REG_ARM_PSCI_VERSION &&
+	    test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
+		void __user *uaddr = (void __user *)(long)reg->addr;
+		u64 val;
+
+		if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
+			return -EFAULT;
+
+		switch (val) {
+		case KVM_ARM_PSCI_0_2:
+		case KVM_ARM_PSCI_1_0:
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 07/14] arm/arm64: KVM: Add PSCI version selection API
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

Although we've implemented PSCI 1.0 and 1.1, nothing can select them
Since all the new PSCI versions are backward compatible, we decide to
default to the latest version of the PSCI implementation. This is no
different from doing a firmware upgrade on KVM.

But in order to give a chance to hypothetical badly implemented guests
that would have a fit by discovering something other than PSCI 0.2,
let's provide a new API that allows userspace to pick one particular
version of the API.

This is implemented as a new class of "firmware" registers, where
we expose the PSCI version. This allows the PSCI version to be
save/restored as part of a guest migration, and also set to
any supported version if the guest requires it.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 Documentation/virtual/kvm/api.txt      |  3 +-
 Documentation/virtual/kvm/arm/psci.txt | 28 ++++++++++++++
 arch/arm/include/asm/kvm_host.h        |  3 ++
 arch/arm/include/uapi/asm/kvm.h        |  6 +++
 arch/arm/kvm/guest.c                   | 13 +++++++
 arch/arm64/include/asm/kvm_host.h      |  3 ++
 arch/arm64/include/uapi/asm/kvm.h      |  6 +++
 arch/arm64/kvm/guest.c                 | 14 ++++++-
 include/kvm/arm_psci.h                 |  9 +++++
 virt/kvm/arm/psci.c                    | 68 +++++++++++++++++++++++++++++++++-
 10 files changed, 149 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/virtual/kvm/arm/psci.txt

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 57d3ee9e4bde..334905202141 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2493,7 +2493,8 @@ Possible features:
 	  and execute guest code when KVM_RUN is called.
 	- KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
 	  Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
-	- KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU.
+	- KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision
+          backward compatible with v0.2) for the CPU.
 	  Depends on KVM_CAP_ARM_PSCI_0_2.
 	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
 	  Depends on KVM_CAP_ARM_PMU_V3.
diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt
new file mode 100644
index 000000000000..2e49a4e9f084
--- /dev/null
+++ b/Documentation/virtual/kvm/arm/psci.txt
@@ -0,0 +1,28 @@
+KVM implements the PSCI (Power State Coordination Interface)
+specification in order to provide services such as CPU on/off, reset
+and power-off to the guest.
+
+The PSCI specification is regularly updated to provide new features,
+and KVM implements these updates if they make sense from a virtualization
+point of view.
+
+This means that a guest booted on two different versions of KVM can
+observe two different "firmware" revisions. This could cause issues if
+a given guest is tied to a particular PSCI revision (unlikely), or if
+a migration causes a different PSCI version to be exposed out of the
+blue to an unsuspecting guest.
+
+In order to remedy this situation, KVM exposes a set of "firmware
+pseuodo-registers" that can be manipulated using the GET/SET_ONE_REG
+interface. These registers can be saved/restored by userspace, and set
+to a convenient value if required.
+
+The following register is defined:
+
+* KVM_REG_ARM_PSCI_VERSION:
+
+  - Only valid if the vcpu has KVM_ARM_VCPU_PSCI_0_2 feature set
+  - Returns the current PSCI version on GET_ONE_REG
+  - Allows any supported PSCI version compatible with v0.2 to be set
+    with SET_ONE_REG
+  - Affects the whole VM (even if the register view is per-vcpu)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index acbf9ec7b396..e9d57060d88c 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -75,6 +75,9 @@ struct kvm_arch {
 	/* Interrupt controller */
 	struct vgic_dist	vgic;
 	int max_vcpus;
+
+	/* Mandated version of PSCI */
+	u32 psci_version;
 };
 
 #define KVM_NR_MEM_OBJS     40
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 6edd177bb1c7..47dfc99f5cd0 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -186,6 +186,12 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_VFP_FPINST		0x1009
 #define KVM_REG_ARM_VFP_FPINST2		0x100A
 
+/* KVM-as-firmware specific pseudo-registers */
+#define KVM_REG_ARM_FW			(0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_REG(r)		(KVM_REG_ARM | KVM_REG_SIZE_U64 | \
+					 KVM_REG_ARM_FW | ((r) & 0xffff))
+#define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 1e0784ebbfd6..a18f33edc471 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/kvm.h>
@@ -176,6 +177,7 @@ static unsigned long num_core_regs(void)
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
 	return num_core_regs() + kvm_arm_num_coproc_regs(vcpu)
+		+ kvm_arm_get_fw_num_regs(vcpu)
 		+ NUM_TIMER_REGS;
 }
 
@@ -196,6 +198,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		uindices++;
 	}
 
+	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
+	if (ret)
+		return ret;
+	uindices += kvm_arm_get_fw_num_regs(vcpu);
+
 	ret = copy_timer_indices(vcpu, uindices);
 	if (ret)
 		return ret;
@@ -214,6 +221,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return get_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_get_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return get_timer_reg(vcpu, reg);
 
@@ -230,6 +240,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return set_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_set_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return set_timer_reg(vcpu, reg);
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 4485ae8e98de..10af386642c6 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -73,6 +73,9 @@ struct kvm_arch {
 
 	/* Interrupt controller */
 	struct vgic_dist	vgic;
+
+	/* Mandated version of PSCI */
+	u32 psci_version;
 };
 
 #define KVM_NR_MEM_OBJS     40
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9abbf3044654..04b3256f8e6d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -206,6 +206,12 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_TIMER_CNT		ARM64_SYS_REG(3, 3, 14, 3, 2)
 #define KVM_REG_ARM_TIMER_CVAL		ARM64_SYS_REG(3, 3, 14, 0, 2)
 
+/* KVM-as-firmware specific pseudo-registers */
+#define KVM_REG_ARM_FW			(0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+					 KVM_REG_ARM_FW | ((r) & 0xffff))
+#define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 5c7f657dd207..811f04c5760e 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/kvm.h>
@@ -205,7 +206,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
 	return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu)
-                + NUM_TIMER_REGS;
+		+ kvm_arm_get_fw_num_regs(vcpu)	+ NUM_TIMER_REGS;
 }
 
 /**
@@ -225,6 +226,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		uindices++;
 	}
 
+	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
+	if (ret)
+		return ret;
+	uindices += kvm_arm_get_fw_num_regs(vcpu);
+
 	ret = copy_timer_indices(vcpu, uindices);
 	if (ret)
 		return ret;
@@ -243,6 +249,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return get_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_get_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return get_timer_reg(vcpu, reg);
 
@@ -259,6 +268,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return set_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_set_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return set_timer_reg(vcpu, reg);
 
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index e7f69c0dc249..f2fa7d752c4e 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -23,7 +23,16 @@
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
 #define KVM_ARM_PSCI_1_0	PSCI_VERSION(1, 0)
 
+#define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
+
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
 
+struct kvm_one_reg;
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+
 #endif /* __KVM_ARM_PSCI_H__ */
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 6299501f7664..682f9be6264b 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -17,6 +17,7 @@
 
 #include <linux/preempt.h>
 #include <linux/kvm_host.h>
+#include <linux/uaccess.h>
 #include <linux/wait.h>
 
 #include <asm/cputype.h>
@@ -235,8 +236,19 @@ static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu)
 {
-	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
-		return KVM_ARM_PSCI_0_2;
+	/*
+	 * Our PSCI implementation stays the same across versions from
+	 * v0.2 onward, only adding the few mandatory functions (such
+	 * as FEATURES with 1.0) that are required by newer
+	 * revisions. It is thus safe to return the latest, unless
+	 * userspace has instructed us otherwise.
+	 */
+	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
+		if (vcpu->kvm->arch.psci_version)
+			return vcpu->kvm->arch.psci_version;
+
+		return KVM_ARM_PSCI_LATEST;
+	}
 
 	return KVM_ARM_PSCI_0_1;
 }
@@ -408,3 +420,55 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	};
 }
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
+{
+	return 1;		/* PSCI version */
+}
+
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+	if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices))
+		return -EFAULT;
+
+	return 0;
+}
+
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (reg->id == KVM_REG_ARM_PSCI_VERSION) {
+		void __user *uaddr = (void __user *)(long)reg->addr;
+		u64 val;
+
+		val = kvm_psci_version(vcpu, vcpu->kvm);
+		if (val == KVM_ARM_PSCI_0_1)
+			return -EINVAL;
+		if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (reg->id == KVM_REG_ARM_PSCI_VERSION &&
+	    test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
+		void __user *uaddr = (void __user *)(long)reg->addr;
+		u64 val;
+
+		if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
+			return -EFAULT;
+
+		switch (val) {
+		case KVM_ARM_PSCI_0_2:
+		case KVM_ARM_PSCI_1_0:
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 07/14] arm/arm64: KVM: Add PSCI version selection API
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

Although we've implemented PSCI 1.0 and 1.1, nothing can select them
Since all the new PSCI versions are backward compatible, we decide to
default to the latest version of the PSCI implementation. This is no
different from doing a firmware upgrade on KVM.

But in order to give a chance to hypothetical badly implemented guests
that would have a fit by discovering something other than PSCI 0.2,
let's provide a new API that allows userspace to pick one particular
version of the API.

This is implemented as a new class of "firmware" registers, where
we expose the PSCI version. This allows the PSCI version to be
save/restored as part of a guest migration, and also set to
any supported version if the guest requires it.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 Documentation/virtual/kvm/api.txt      |  3 +-
 Documentation/virtual/kvm/arm/psci.txt | 28 ++++++++++++++
 arch/arm/include/asm/kvm_host.h        |  3 ++
 arch/arm/include/uapi/asm/kvm.h        |  6 +++
 arch/arm/kvm/guest.c                   | 13 +++++++
 arch/arm64/include/asm/kvm_host.h      |  3 ++
 arch/arm64/include/uapi/asm/kvm.h      |  6 +++
 arch/arm64/kvm/guest.c                 | 14 ++++++-
 include/kvm/arm_psci.h                 |  9 +++++
 virt/kvm/arm/psci.c                    | 68 +++++++++++++++++++++++++++++++++-
 10 files changed, 149 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/virtual/kvm/arm/psci.txt

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 57d3ee9e4bde..334905202141 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2493,7 +2493,8 @@ Possible features:
 	  and execute guest code when KVM_RUN is called.
 	- KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
 	  Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
-	- KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU.
+	- KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision
+          backward compatible with v0.2) for the CPU.
 	  Depends on KVM_CAP_ARM_PSCI_0_2.
 	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
 	  Depends on KVM_CAP_ARM_PMU_V3.
diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt
new file mode 100644
index 000000000000..2e49a4e9f084
--- /dev/null
+++ b/Documentation/virtual/kvm/arm/psci.txt
@@ -0,0 +1,28 @@
+KVM implements the PSCI (Power State Coordination Interface)
+specification in order to provide services such as CPU on/off, reset
+and power-off to the guest.
+
+The PSCI specification is regularly updated to provide new features,
+and KVM implements these updates if they make sense from a virtualization
+point of view.
+
+This means that a guest booted on two different versions of KVM can
+observe two different "firmware" revisions. This could cause issues if
+a given guest is tied to a particular PSCI revision (unlikely), or if
+a migration causes a different PSCI version to be exposed out of the
+blue to an unsuspecting guest.
+
+In order to remedy this situation, KVM exposes a set of "firmware
+pseuodo-registers" that can be manipulated using the GET/SET_ONE_REG
+interface. These registers can be saved/restored by userspace, and set
+to a convenient value if required.
+
+The following register is defined:
+
+* KVM_REG_ARM_PSCI_VERSION:
+
+  - Only valid if the vcpu has KVM_ARM_VCPU_PSCI_0_2 feature set
+  - Returns the current PSCI version on GET_ONE_REG
+  - Allows any supported PSCI version compatible with v0.2 to be set
+    with SET_ONE_REG
+  - Affects the whole VM (even if the register view is per-vcpu)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index acbf9ec7b396..e9d57060d88c 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -75,6 +75,9 @@ struct kvm_arch {
 	/* Interrupt controller */
 	struct vgic_dist	vgic;
 	int max_vcpus;
+
+	/* Mandated version of PSCI */
+	u32 psci_version;
 };
 
 #define KVM_NR_MEM_OBJS     40
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 6edd177bb1c7..47dfc99f5cd0 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -186,6 +186,12 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_VFP_FPINST		0x1009
 #define KVM_REG_ARM_VFP_FPINST2		0x100A
 
+/* KVM-as-firmware specific pseudo-registers */
+#define KVM_REG_ARM_FW			(0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_REG(r)		(KVM_REG_ARM | KVM_REG_SIZE_U64 | \
+					 KVM_REG_ARM_FW | ((r) & 0xffff))
+#define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 1e0784ebbfd6..a18f33edc471 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/kvm.h>
@@ -176,6 +177,7 @@ static unsigned long num_core_regs(void)
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
 	return num_core_regs() + kvm_arm_num_coproc_regs(vcpu)
+		+ kvm_arm_get_fw_num_regs(vcpu)
 		+ NUM_TIMER_REGS;
 }
 
@@ -196,6 +198,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		uindices++;
 	}
 
+	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
+	if (ret)
+		return ret;
+	uindices += kvm_arm_get_fw_num_regs(vcpu);
+
 	ret = copy_timer_indices(vcpu, uindices);
 	if (ret)
 		return ret;
@@ -214,6 +221,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return get_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_get_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return get_timer_reg(vcpu, reg);
 
@@ -230,6 +240,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return set_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_set_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return set_timer_reg(vcpu, reg);
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 4485ae8e98de..10af386642c6 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -73,6 +73,9 @@ struct kvm_arch {
 
 	/* Interrupt controller */
 	struct vgic_dist	vgic;
+
+	/* Mandated version of PSCI */
+	u32 psci_version;
 };
 
 #define KVM_NR_MEM_OBJS     40
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9abbf3044654..04b3256f8e6d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -206,6 +206,12 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_TIMER_CNT		ARM64_SYS_REG(3, 3, 14, 3, 2)
 #define KVM_REG_ARM_TIMER_CVAL		ARM64_SYS_REG(3, 3, 14, 0, 2)
 
+/* KVM-as-firmware specific pseudo-registers */
+#define KVM_REG_ARM_FW			(0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+					 KVM_REG_ARM_FW | ((r) & 0xffff))
+#define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 5c7f657dd207..811f04c5760e 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/kvm.h>
@@ -205,7 +206,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
 	return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu)
-                + NUM_TIMER_REGS;
+		+ kvm_arm_get_fw_num_regs(vcpu)	+ NUM_TIMER_REGS;
 }
 
 /**
@@ -225,6 +226,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		uindices++;
 	}
 
+	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
+	if (ret)
+		return ret;
+	uindices += kvm_arm_get_fw_num_regs(vcpu);
+
 	ret = copy_timer_indices(vcpu, uindices);
 	if (ret)
 		return ret;
@@ -243,6 +249,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return get_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_get_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return get_timer_reg(vcpu, reg);
 
@@ -259,6 +268,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
 		return set_core_reg(vcpu, reg);
 
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
+		return kvm_arm_set_fw_reg(vcpu, reg);
+
 	if (is_timer_reg(reg->id))
 		return set_timer_reg(vcpu, reg);
 
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index e7f69c0dc249..f2fa7d752c4e 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -23,7 +23,16 @@
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
 #define KVM_ARM_PSCI_1_0	PSCI_VERSION(1, 0)
 
+#define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
+
 int kvm_psci_version(struct kvm_vcpu *vcpu);
 int kvm_psci_call(struct kvm_vcpu *vcpu);
 
+struct kvm_one_reg;
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+
 #endif /* __KVM_ARM_PSCI_H__ */
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 6299501f7664..682f9be6264b 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -17,6 +17,7 @@
 
 #include <linux/preempt.h>
 #include <linux/kvm_host.h>
+#include <linux/uaccess.h>
 #include <linux/wait.h>
 
 #include <asm/cputype.h>
@@ -235,8 +236,19 @@ static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
 
 int kvm_psci_version(struct kvm_vcpu *vcpu)
 {
-	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
-		return KVM_ARM_PSCI_0_2;
+	/*
+	 * Our PSCI implementation stays the same across versions from
+	 * v0.2 onward, only adding the few mandatory functions (such
+	 * as FEATURES with 1.0) that are required by newer
+	 * revisions. It is thus safe to return the latest, unless
+	 * userspace has instructed us otherwise.
+	 */
+	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
+		if (vcpu->kvm->arch.psci_version)
+			return vcpu->kvm->arch.psci_version;
+
+		return KVM_ARM_PSCI_LATEST;
+	}
 
 	return KVM_ARM_PSCI_0_1;
 }
@@ -408,3 +420,55 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	};
 }
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
+{
+	return 1;		/* PSCI version */
+}
+
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+	if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices))
+		return -EFAULT;
+
+	return 0;
+}
+
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (reg->id == KVM_REG_ARM_PSCI_VERSION) {
+		void __user *uaddr = (void __user *)(long)reg->addr;
+		u64 val;
+
+		val = kvm_psci_version(vcpu, vcpu->kvm);
+		if (val == KVM_ARM_PSCI_0_1)
+			return -EINVAL;
+		if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	if (reg->id == KVM_REG_ARM_PSCI_VERSION &&
+	    test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
+		void __user *uaddr = (void __user *)(long)reg->addr;
+		u64 val;
+
+		if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
+			return -EFAULT;
+
+		switch (val) {
+		case KVM_ARM_PSCI_0_2:
+		case KVM_ARM_PSCI_1_0:
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 08/14] arm/arm64: KVM: Advertise SMCCC v1.1
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

The new SMC Calling Convention (v1.1) allows for a reduced overhead
when calling into the firmware, and provides a new feature discovery
mechanism.

Make it visible to KVM guests.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 Documentation/virtual/kvm/arm/psci.txt | 12 +++++++-----
 arch/arm/kvm/handle_exit.c             |  2 +-
 arch/arm64/kvm/handle_exit.c           |  2 +-
 include/kvm/arm_psci.h                 |  2 +-
 include/linux/arm-smccc.h              | 13 +++++++++++++
 virt/kvm/arm/psci.c                    | 24 +++++++++++++++++++++++-
 6 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt
index 2e49a4e9f084..aafdab887b04 100644
--- a/Documentation/virtual/kvm/arm/psci.txt
+++ b/Documentation/virtual/kvm/arm/psci.txt
@@ -13,7 +13,7 @@ a migration causes a different PSCI version to be exposed out of the
 blue to an unsuspecting guest.
 
 In order to remedy this situation, KVM exposes a set of "firmware
-pseuodo-registers" that can be manipulated using the GET/SET_ONE_REG
+pseudo-registers" that can be manipulated using the GET/SET_ONE_REG
 interface. These registers can be saved/restored by userspace, and set
 to a convenient value if required.
 
@@ -21,8 +21,10 @@ The following register is defined:
 
 * KVM_REG_ARM_PSCI_VERSION:
 
-  - Only valid if the vcpu has KVM_ARM_VCPU_PSCI_0_2 feature set
-  - Returns the current PSCI version on GET_ONE_REG
-  - Allows any supported PSCI version compatible with v0.2 to be set
-    with SET_ONE_REG
+  - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set
+    (and thus has already been initialized)
+  - Returns the current PSCI version on GET_ONE_REG (defaulting to the
+    highest PSCI version implemented by KVM and compatible with v0.2)
+  - Allows any PSCI version implemented by KVM and compatible with
+    v0.2 to be set with SET_ONE_REG
   - Affects the whole VM (even if the register view is per-vcpu)
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index e020cc82c4b1..a4520c7118d2 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -36,7 +36,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		      kvm_vcpu_hvc_get_imm(vcpu));
 	vcpu->stat.hvc_exit_stat++;
 
-	ret = kvm_psci_call(vcpu);
+	ret = kvm_hvc_call_handler(vcpu);
 	if (ret < 0) {
 		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 97e8d64a203d..bb6e1518d819 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -52,7 +52,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 			    kvm_vcpu_hvc_get_imm(vcpu));
 	vcpu->stat.hvc_exit_stat++;
 
-	ret = kvm_psci_call(vcpu);
+	ret = kvm_hvc_call_handler(vcpu);
 	if (ret < 0) {
 		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index f2fa7d752c4e..4876bfac2195 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -26,7 +26,7 @@
 #define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
-int kvm_psci_call(struct kvm_vcpu *vcpu);
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
 struct kvm_one_reg;
 
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 4c5bca38c653..dc68aa5a7261 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -60,6 +60,19 @@
 #define ARM_SMCCC_QUIRK_NONE		0
 #define ARM_SMCCC_QUIRK_QCOM_A6		1 /* Save/restore register a6 */
 
+#define ARM_SMCCC_VERSION_1_0		0x10000
+#define ARM_SMCCC_VERSION_1_1		0x10001
+
+#define ARM_SMCCC_VERSION_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0)
+
+#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 1)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 682f9be6264b..3bb336ac7d7d 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/preempt.h>
 #include <linux/kvm_host.h>
 #include <linux/uaccess.h>
@@ -353,6 +354,7 @@ static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
 		case PSCI_0_2_FN_SYSTEM_OFF:
 		case PSCI_0_2_FN_SYSTEM_RESET:
 		case PSCI_1_0_FN_PSCI_FEATURES:
+		case ARM_SMCCC_VERSION_FUNC_ID:
 			val = 0;
 			break;
 		default:
@@ -407,7 +409,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
  * Errors:
  * -EINVAL: Unrecognized PSCI function
  */
-int kvm_psci_call(struct kvm_vcpu *vcpu)
+static int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
 	switch (kvm_psci_version(vcpu)) {
 	case KVM_ARM_PSCI_1_0:
@@ -421,6 +423,26 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 	};
 }
 
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
+{
+	u32 func_id = smccc_get_function(vcpu);
+	u32 val;
+
+	switch (func_id) {
+	case ARM_SMCCC_VERSION_FUNC_ID:
+		val = ARM_SMCCC_VERSION_1_1;
+		break;
+	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
+		val = -1;	/* Nothing supported yet */
+		break;
+	default:
+		return kvm_psci_call(vcpu);
+	}
+
+	smccc_set_retval(vcpu, val, 0, 0, 0);
+	return 1;
+}
+
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
 	return 1;		/* PSCI version */
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 08/14] arm/arm64: KVM: Advertise SMCCC v1.1
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

The new SMC Calling Convention (v1.1) allows for a reduced overhead
when calling into the firmware, and provides a new feature discovery
mechanism.

Make it visible to KVM guests.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 Documentation/virtual/kvm/arm/psci.txt | 12 +++++++-----
 arch/arm/kvm/handle_exit.c             |  2 +-
 arch/arm64/kvm/handle_exit.c           |  2 +-
 include/kvm/arm_psci.h                 |  2 +-
 include/linux/arm-smccc.h              | 13 +++++++++++++
 virt/kvm/arm/psci.c                    | 24 +++++++++++++++++++++++-
 6 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt
index 2e49a4e9f084..aafdab887b04 100644
--- a/Documentation/virtual/kvm/arm/psci.txt
+++ b/Documentation/virtual/kvm/arm/psci.txt
@@ -13,7 +13,7 @@ a migration causes a different PSCI version to be exposed out of the
 blue to an unsuspecting guest.
 
 In order to remedy this situation, KVM exposes a set of "firmware
-pseuodo-registers" that can be manipulated using the GET/SET_ONE_REG
+pseudo-registers" that can be manipulated using the GET/SET_ONE_REG
 interface. These registers can be saved/restored by userspace, and set
 to a convenient value if required.
 
@@ -21,8 +21,10 @@ The following register is defined:
 
 * KVM_REG_ARM_PSCI_VERSION:
 
-  - Only valid if the vcpu has KVM_ARM_VCPU_PSCI_0_2 feature set
-  - Returns the current PSCI version on GET_ONE_REG
-  - Allows any supported PSCI version compatible with v0.2 to be set
-    with SET_ONE_REG
+  - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set
+    (and thus has already been initialized)
+  - Returns the current PSCI version on GET_ONE_REG (defaulting to the
+    highest PSCI version implemented by KVM and compatible with v0.2)
+  - Allows any PSCI version implemented by KVM and compatible with
+    v0.2 to be set with SET_ONE_REG
   - Affects the whole VM (even if the register view is per-vcpu)
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index e020cc82c4b1..a4520c7118d2 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -36,7 +36,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		      kvm_vcpu_hvc_get_imm(vcpu));
 	vcpu->stat.hvc_exit_stat++;
 
-	ret = kvm_psci_call(vcpu);
+	ret = kvm_hvc_call_handler(vcpu);
 	if (ret < 0) {
 		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 97e8d64a203d..bb6e1518d819 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -52,7 +52,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 			    kvm_vcpu_hvc_get_imm(vcpu));
 	vcpu->stat.hvc_exit_stat++;
 
-	ret = kvm_psci_call(vcpu);
+	ret = kvm_hvc_call_handler(vcpu);
 	if (ret < 0) {
 		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index f2fa7d752c4e..4876bfac2195 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -26,7 +26,7 @@
 #define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
-int kvm_psci_call(struct kvm_vcpu *vcpu);
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
 struct kvm_one_reg;
 
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 4c5bca38c653..dc68aa5a7261 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -60,6 +60,19 @@
 #define ARM_SMCCC_QUIRK_NONE		0
 #define ARM_SMCCC_QUIRK_QCOM_A6		1 /* Save/restore register a6 */
 
+#define ARM_SMCCC_VERSION_1_0		0x10000
+#define ARM_SMCCC_VERSION_1_1		0x10001
+
+#define ARM_SMCCC_VERSION_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0)
+
+#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 1)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 682f9be6264b..3bb336ac7d7d 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/preempt.h>
 #include <linux/kvm_host.h>
 #include <linux/uaccess.h>
@@ -353,6 +354,7 @@ static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
 		case PSCI_0_2_FN_SYSTEM_OFF:
 		case PSCI_0_2_FN_SYSTEM_RESET:
 		case PSCI_1_0_FN_PSCI_FEATURES:
+		case ARM_SMCCC_VERSION_FUNC_ID:
 			val = 0;
 			break;
 		default:
@@ -407,7 +409,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
  * Errors:
  * -EINVAL: Unrecognized PSCI function
  */
-int kvm_psci_call(struct kvm_vcpu *vcpu)
+static int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
 	switch (kvm_psci_version(vcpu)) {
 	case KVM_ARM_PSCI_1_0:
@@ -421,6 +423,26 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 	};
 }
 
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
+{
+	u32 func_id = smccc_get_function(vcpu);
+	u32 val;
+
+	switch (func_id) {
+	case ARM_SMCCC_VERSION_FUNC_ID:
+		val = ARM_SMCCC_VERSION_1_1;
+		break;
+	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
+		val = -1;	/* Nothing supported yet */
+		break;
+	default:
+		return kvm_psci_call(vcpu);
+	}
+
+	smccc_set_retval(vcpu, val, 0, 0, 0);
+	return 1;
+}
+
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
 	return 1;		/* PSCI version */
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 08/14] arm/arm64: KVM: Advertise SMCCC v1.1
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

The new SMC Calling Convention (v1.1) allows for a reduced overhead
when calling into the firmware, and provides a new feature discovery
mechanism.

Make it visible to KVM guests.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 Documentation/virtual/kvm/arm/psci.txt | 12 +++++++-----
 arch/arm/kvm/handle_exit.c             |  2 +-
 arch/arm64/kvm/handle_exit.c           |  2 +-
 include/kvm/arm_psci.h                 |  2 +-
 include/linux/arm-smccc.h              | 13 +++++++++++++
 virt/kvm/arm/psci.c                    | 24 +++++++++++++++++++++++-
 6 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt
index 2e49a4e9f084..aafdab887b04 100644
--- a/Documentation/virtual/kvm/arm/psci.txt
+++ b/Documentation/virtual/kvm/arm/psci.txt
@@ -13,7 +13,7 @@ a migration causes a different PSCI version to be exposed out of the
 blue to an unsuspecting guest.
 
 In order to remedy this situation, KVM exposes a set of "firmware
-pseuodo-registers" that can be manipulated using the GET/SET_ONE_REG
+pseudo-registers" that can be manipulated using the GET/SET_ONE_REG
 interface. These registers can be saved/restored by userspace, and set
 to a convenient value if required.
 
@@ -21,8 +21,10 @@ The following register is defined:
 
 * KVM_REG_ARM_PSCI_VERSION:
 
-  - Only valid if the vcpu has KVM_ARM_VCPU_PSCI_0_2 feature set
-  - Returns the current PSCI version on GET_ONE_REG
-  - Allows any supported PSCI version compatible with v0.2 to be set
-    with SET_ONE_REG
+  - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set
+    (and thus has already been initialized)
+  - Returns the current PSCI version on GET_ONE_REG (defaulting to the
+    highest PSCI version implemented by KVM and compatible with v0.2)
+  - Allows any PSCI version implemented by KVM and compatible with
+    v0.2 to be set with SET_ONE_REG
   - Affects the whole VM (even if the register view is per-vcpu)
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index e020cc82c4b1..a4520c7118d2 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -36,7 +36,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		      kvm_vcpu_hvc_get_imm(vcpu));
 	vcpu->stat.hvc_exit_stat++;
 
-	ret = kvm_psci_call(vcpu);
+	ret = kvm_hvc_call_handler(vcpu);
 	if (ret < 0) {
 		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 97e8d64a203d..bb6e1518d819 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -52,7 +52,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 			    kvm_vcpu_hvc_get_imm(vcpu));
 	vcpu->stat.hvc_exit_stat++;
 
-	ret = kvm_psci_call(vcpu);
+	ret = kvm_hvc_call_handler(vcpu);
 	if (ret < 0) {
 		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index f2fa7d752c4e..4876bfac2195 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -26,7 +26,7 @@
 #define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
 
 int kvm_psci_version(struct kvm_vcpu *vcpu);
-int kvm_psci_call(struct kvm_vcpu *vcpu);
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
 struct kvm_one_reg;
 
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 4c5bca38c653..dc68aa5a7261 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -60,6 +60,19 @@
 #define ARM_SMCCC_QUIRK_NONE		0
 #define ARM_SMCCC_QUIRK_QCOM_A6		1 /* Save/restore register a6 */
 
+#define ARM_SMCCC_VERSION_1_0		0x10000
+#define ARM_SMCCC_VERSION_1_1		0x10001
+
+#define ARM_SMCCC_VERSION_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0)
+
+#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 1)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 682f9be6264b..3bb336ac7d7d 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/preempt.h>
 #include <linux/kvm_host.h>
 #include <linux/uaccess.h>
@@ -353,6 +354,7 @@ static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
 		case PSCI_0_2_FN_SYSTEM_OFF:
 		case PSCI_0_2_FN_SYSTEM_RESET:
 		case PSCI_1_0_FN_PSCI_FEATURES:
+		case ARM_SMCCC_VERSION_FUNC_ID:
 			val = 0;
 			break;
 		default:
@@ -407,7 +409,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
  * Errors:
  * -EINVAL: Unrecognized PSCI function
  */
-int kvm_psci_call(struct kvm_vcpu *vcpu)
+static int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
 	switch (kvm_psci_version(vcpu)) {
 	case KVM_ARM_PSCI_1_0:
@@ -421,6 +423,26 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 	};
 }
 
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
+{
+	u32 func_id = smccc_get_function(vcpu);
+	u32 val;
+
+	switch (func_id) {
+	case ARM_SMCCC_VERSION_FUNC_ID:
+		val = ARM_SMCCC_VERSION_1_1;
+		break;
+	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
+		val = -1;	/* Nothing supported yet */
+		break;
+	default:
+		return kvm_psci_call(vcpu);
+	}
+
+	smccc_set_retval(vcpu, val, 0, 0, 0);
+	return 1;
+}
+
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
 	return 1;		/* PSCI version */
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 09/14] arm/arm64: KVM: Turn kvm_psci_version into a static inline
  2018-01-26 14:28 ` Marc Zyngier
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

We're about to need kvm_psci_version in HYP too. So let's turn it
into a static inline, and pass the kvm structure as a second
parameter (so that HYP can do a kern_hyp_va on it).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/switch.c | 20 ++++++++++++--------
 include/kvm/arm_psci.h      | 27 ++++++++++++++++++++++++++-
 virt/kvm/arm/psci.c         | 23 ++---------------------
 3 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 036e1f3d77a6..408c04d789a5 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -19,6 +19,8 @@
 #include <linux/jump_label.h>
 #include <uapi/linux/psci.h>
 
+#include <kvm/arm_psci.h>
+
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
@@ -350,14 +352,16 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 
 	if (exit_code == ARM_EXCEPTION_TRAP &&
 	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 ||
-	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32) &&
-	    vcpu_get_reg(vcpu, 0) == PSCI_0_2_FN_PSCI_VERSION) {
-		u64 val = PSCI_RET_NOT_SUPPORTED;
-		if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
-			val = 2;
-
-		vcpu_set_reg(vcpu, 0, val);
-		goto again;
+	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32)) {
+		u32 val = vcpu_get_reg(vcpu, 0);
+
+		if (val == PSCI_0_2_FN_PSCI_VERSION) {
+			val = kvm_psci_version(vcpu, kern_hyp_va(vcpu->kvm));
+			if (unlikely(val == KVM_ARM_PSCI_0_1))
+				val = PSCI_RET_NOT_SUPPORTED;
+			vcpu_set_reg(vcpu, 0, val);
+			goto again;
+		}
 	}
 
 	if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 4876bfac2195..32978b578002 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -18,6 +18,8 @@
 #ifndef __KVM_ARM_PSCI_H__
 #define __KVM_ARM_PSCI_H__
 
+#include <linux/kvm_host.h>
+
 #define PSCI_VERSION(x,y)	((((x) & 0x7fff) << 16) | ((y) & 0xffff))
 #define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
@@ -25,7 +27,30 @@
 
 #define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
 
-int kvm_psci_version(struct kvm_vcpu *vcpu);
+/*
+ * We need the KVM pointer independently from the vcpu as we can call
+ * this from HYP, and need to apply kern_hyp_va on it...
+ */
+static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm)
+{
+	/*
+	 * Our PSCI implementation stays the same across versions from
+	 * v0.2 onward, only adding the few mandatory functions (such
+	 * as FEATURES with 1.0) that are required by newer
+	 * revisions. It is thus safe to return the latest, unless
+	 * userspace has instructed us otherwise.
+	 */
+	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
+		if (kvm->arch.psci_version)
+			return kvm->arch.psci_version;
+
+		return KVM_ARM_PSCI_LATEST;
+	}
+
+	return KVM_ARM_PSCI_0_1;
+}
+
+
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
 struct kvm_one_reg;
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 3bb336ac7d7d..a021b62ed762 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -126,7 +126,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	if (!vcpu)
 		return PSCI_RET_INVALID_PARAMS;
 	if (!vcpu->arch.power_off) {
-		if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
+		if (kvm_psci_version(source_vcpu, kvm) != KVM_ARM_PSCI_0_1)
 			return PSCI_RET_ALREADY_ON;
 		else
 			return PSCI_RET_INVALID_PARAMS;
@@ -235,25 +235,6 @@ static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
 	kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET);
 }
 
-int kvm_psci_version(struct kvm_vcpu *vcpu)
-{
-	/*
-	 * Our PSCI implementation stays the same across versions from
-	 * v0.2 onward, only adding the few mandatory functions (such
-	 * as FEATURES with 1.0) that are required by newer
-	 * revisions. It is thus safe to return the latest, unless
-	 * userspace has instructed us otherwise.
-	 */
-	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
-		if (vcpu->kvm->arch.psci_version)
-			return vcpu->kvm->arch.psci_version;
-
-		return KVM_ARM_PSCI_LATEST;
-	}
-
-	return KVM_ARM_PSCI_0_1;
-}
-
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
@@ -411,7 +392,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
  */
 static int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
-	switch (kvm_psci_version(vcpu)) {
+	switch (kvm_psci_version(vcpu, vcpu->kvm)) {
 	case KVM_ARM_PSCI_1_0:
 		return kvm_psci_1_0_call(vcpu);
 	case KVM_ARM_PSCI_0_2:
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 09/14] arm/arm64: KVM: Turn kvm_psci_version into a static inline
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

We're about to need kvm_psci_version in HYP too. So let's turn it
into a static inline, and pass the kvm structure as a second
parameter (so that HYP can do a kern_hyp_va on it).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/switch.c | 20 ++++++++++++--------
 include/kvm/arm_psci.h      | 27 ++++++++++++++++++++++++++-
 virt/kvm/arm/psci.c         | 23 ++---------------------
 3 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 036e1f3d77a6..408c04d789a5 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -19,6 +19,8 @@
 #include <linux/jump_label.h>
 #include <uapi/linux/psci.h>
 
+#include <kvm/arm_psci.h>
+
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
@@ -350,14 +352,16 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 
 	if (exit_code == ARM_EXCEPTION_TRAP &&
 	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 ||
-	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32) &&
-	    vcpu_get_reg(vcpu, 0) == PSCI_0_2_FN_PSCI_VERSION) {
-		u64 val = PSCI_RET_NOT_SUPPORTED;
-		if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
-			val = 2;
-
-		vcpu_set_reg(vcpu, 0, val);
-		goto again;
+	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32)) {
+		u32 val = vcpu_get_reg(vcpu, 0);
+
+		if (val == PSCI_0_2_FN_PSCI_VERSION) {
+			val = kvm_psci_version(vcpu, kern_hyp_va(vcpu->kvm));
+			if (unlikely(val == KVM_ARM_PSCI_0_1))
+				val = PSCI_RET_NOT_SUPPORTED;
+			vcpu_set_reg(vcpu, 0, val);
+			goto again;
+		}
 	}
 
 	if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 4876bfac2195..32978b578002 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -18,6 +18,8 @@
 #ifndef __KVM_ARM_PSCI_H__
 #define __KVM_ARM_PSCI_H__
 
+#include <linux/kvm_host.h>
+
 #define PSCI_VERSION(x,y)	((((x) & 0x7fff) << 16) | ((y) & 0xffff))
 #define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
 #define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
@@ -25,7 +27,30 @@
 
 #define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
 
-int kvm_psci_version(struct kvm_vcpu *vcpu);
+/*
+ * We need the KVM pointer independently from the vcpu as we can call
+ * this from HYP, and need to apply kern_hyp_va on it...
+ */
+static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm)
+{
+	/*
+	 * Our PSCI implementation stays the same across versions from
+	 * v0.2 onward, only adding the few mandatory functions (such
+	 * as FEATURES with 1.0) that are required by newer
+	 * revisions. It is thus safe to return the latest, unless
+	 * userspace has instructed us otherwise.
+	 */
+	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
+		if (kvm->arch.psci_version)
+			return kvm->arch.psci_version;
+
+		return KVM_ARM_PSCI_LATEST;
+	}
+
+	return KVM_ARM_PSCI_0_1;
+}
+
+
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
 struct kvm_one_reg;
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index 3bb336ac7d7d..a021b62ed762 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -126,7 +126,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	if (!vcpu)
 		return PSCI_RET_INVALID_PARAMS;
 	if (!vcpu->arch.power_off) {
-		if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
+		if (kvm_psci_version(source_vcpu, kvm) != KVM_ARM_PSCI_0_1)
 			return PSCI_RET_ALREADY_ON;
 		else
 			return PSCI_RET_INVALID_PARAMS;
@@ -235,25 +235,6 @@ static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
 	kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET);
 }
 
-int kvm_psci_version(struct kvm_vcpu *vcpu)
-{
-	/*
-	 * Our PSCI implementation stays the same across versions from
-	 * v0.2 onward, only adding the few mandatory functions (such
-	 * as FEATURES with 1.0) that are required by newer
-	 * revisions. It is thus safe to return the latest, unless
-	 * userspace has instructed us otherwise.
-	 */
-	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) {
-		if (vcpu->kvm->arch.psci_version)
-			return vcpu->kvm->arch.psci_version;
-
-		return KVM_ARM_PSCI_LATEST;
-	}
-
-	return KVM_ARM_PSCI_0_1;
-}
-
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
@@ -411,7 +392,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
  */
 static int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
-	switch (kvm_psci_version(vcpu)) {
+	switch (kvm_psci_version(vcpu, vcpu->kvm)) {
 	case KVM_ARM_PSCI_1_0:
 		return kvm_psci_1_0_call(vcpu);
 	case KVM_ARM_PSCI_0_2:
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 10/14] arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

A new feature of SMCCC 1.1 is that it offers firmware-based CPU
workarounds. In particular, SMCCC_ARCH_WORKAROUND_1 provides
BP hardening for CVE-2017-5715.

If the host has some mitigation for this issue, report that
we deal with it using SMCCC_ARCH_WORKAROUND_1, as we apply the
host workaround on every guest exit.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/arm-smccc.h |  5 +++++
 virt/kvm/arm/psci.c       | 17 +++++++++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index dc68aa5a7261..e1ef944ef1da 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -73,6 +73,11 @@
 			   ARM_SMCCC_SMC_32,				\
 			   0, 1)
 
+#define ARM_SMCCC_ARCH_WORKAROUND_1					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x8000)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index a021b62ed762..5677d16abc71 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -407,14 +407,27 @@ static int kvm_psci_call(struct kvm_vcpu *vcpu)
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
 	u32 func_id = smccc_get_function(vcpu);
-	u32 val;
+	u32 val, feature;
 
 	switch (func_id) {
 	case ARM_SMCCC_VERSION_FUNC_ID:
 		val = ARM_SMCCC_VERSION_1_1;
 		break;
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-		val = -1;	/* Nothing supported yet */
+		feature = smccc_get_arg1(vcpu);
+		switch(feature) {
+#ifdef CONFIG_ARM64
+		case ARM_SMCCC_ARCH_WORKAROUND_1:
+			if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR))
+				val = 0;
+			else
+				val = -1;
+			break;
+#endif
+		default:
+			val = -1;
+			break;
+		}
 		break;
 	default:
 		return kvm_psci_call(vcpu);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 10/14] arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

A new feature of SMCCC 1.1 is that it offers firmware-based CPU
workarounds. In particular, SMCCC_ARCH_WORKAROUND_1 provides
BP hardening for CVE-2017-5715.

If the host has some mitigation for this issue, report that
we deal with it using SMCCC_ARCH_WORKAROUND_1, as we apply the
host workaround on every guest exit.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/arm-smccc.h |  5 +++++
 virt/kvm/arm/psci.c       | 17 +++++++++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index dc68aa5a7261..e1ef944ef1da 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -73,6 +73,11 @@
 			   ARM_SMCCC_SMC_32,				\
 			   0, 1)
 
+#define ARM_SMCCC_ARCH_WORKAROUND_1					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x8000)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index a021b62ed762..5677d16abc71 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -407,14 +407,27 @@ static int kvm_psci_call(struct kvm_vcpu *vcpu)
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
 	u32 func_id = smccc_get_function(vcpu);
-	u32 val;
+	u32 val, feature;
 
 	switch (func_id) {
 	case ARM_SMCCC_VERSION_FUNC_ID:
 		val = ARM_SMCCC_VERSION_1_1;
 		break;
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-		val = -1;	/* Nothing supported yet */
+		feature = smccc_get_arg1(vcpu);
+		switch(feature) {
+#ifdef CONFIG_ARM64
+		case ARM_SMCCC_ARCH_WORKAROUND_1:
+			if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR))
+				val = 0;
+			else
+				val = -1;
+			break;
+#endif
+		default:
+			val = -1;
+			break;
+		}
 		break;
 	default:
 		return kvm_psci_call(vcpu);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 10/14] arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

A new feature of SMCCC 1.1 is that it offers firmware-based CPU
workarounds. In particular, SMCCC_ARCH_WORKAROUND_1 provides
BP hardening for CVE-2017-5715.

If the host has some mitigation for this issue, report that
we deal with it using SMCCC_ARCH_WORKAROUND_1, as we apply the
host workaround on every guest exit.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/arm-smccc.h |  5 +++++
 virt/kvm/arm/psci.c       | 17 +++++++++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index dc68aa5a7261..e1ef944ef1da 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -73,6 +73,11 @@
 			   ARM_SMCCC_SMC_32,				\
 			   0, 1)
 
+#define ARM_SMCCC_ARCH_WORKAROUND_1					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x8000)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
index a021b62ed762..5677d16abc71 100644
--- a/virt/kvm/arm/psci.c
+++ b/virt/kvm/arm/psci.c
@@ -407,14 +407,27 @@ static int kvm_psci_call(struct kvm_vcpu *vcpu)
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
 	u32 func_id = smccc_get_function(vcpu);
-	u32 val;
+	u32 val, feature;
 
 	switch (func_id) {
 	case ARM_SMCCC_VERSION_FUNC_ID:
 		val = ARM_SMCCC_VERSION_1_1;
 		break;
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-		val = -1;	/* Nothing supported yet */
+		feature = smccc_get_arg1(vcpu);
+		switch(feature) {
+#ifdef CONFIG_ARM64
+		case ARM_SMCCC_ARCH_WORKAROUND_1:
+			if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR))
+				val = 0;
+			else
+				val = -1;
+			break;
+#endif
+		default:
+			val = -1;
+			break;
+		}
 		break;
 	default:
 		return kvm_psci_call(vcpu);
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 11/14] arm64: KVM: Add SMCCC_ARCH_WORKAROUND_1 fast handling
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

We want SMCCC_ARCH_WORKAROUND_1 to be fast. As fast as possible.
So let's intercept it as early as we can by testing for the
function call number as soon as we've identified a HVC call
coming from the guest.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/hyp-entry.S | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index e4f37b9dd47c..f36464bd57c5 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/linkage.h>
 
 #include <asm/alternative.h>
@@ -64,10 +65,11 @@ alternative_endif
 	lsr	x0, x1, #ESR_ELx_EC_SHIFT
 
 	cmp	x0, #ESR_ELx_EC_HVC64
+	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
 	b.ne	el1_trap
 
-	mrs	x1, vttbr_el2		// If vttbr is valid, the 64bit guest
-	cbnz	x1, el1_trap		// called HVC
+	mrs	x1, vttbr_el2		// If vttbr is valid, the guest
+	cbnz	x1, el1_hvc_guest	// called HVC
 
 	/* Here, we're pretty sure the host called HVC. */
 	ldp	x0, x1, [sp], #16
@@ -100,6 +102,20 @@ alternative_endif
 
 	eret
 
+el1_hvc_guest:
+	/*
+	 * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1.
+	 * The workaround has already been applied on the host,
+	 * so let's quickly get back to the guest. We don't bother
+	 * restoring x1, as it can be clobbered anyway.
+	 */
+	ldr	x1, [sp]				// Guest's x0
+	eor	w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1
+	cbnz	w1, el1_trap
+	mov	x0, x1
+	add	sp, sp, #16
+	eret
+
 el1_trap:
 	/*
 	 * x0: ESR_EC
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 11/14] arm64: KVM: Add SMCCC_ARCH_WORKAROUND_1 fast handling
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

We want SMCCC_ARCH_WORKAROUND_1 to be fast. As fast as possible.
So let's intercept it as early as we can by testing for the
function call number as soon as we've identified a HVC call
coming from the guest.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/hyp-entry.S | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index e4f37b9dd47c..f36464bd57c5 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/linkage.h>
 
 #include <asm/alternative.h>
@@ -64,10 +65,11 @@ alternative_endif
 	lsr	x0, x1, #ESR_ELx_EC_SHIFT
 
 	cmp	x0, #ESR_ELx_EC_HVC64
+	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
 	b.ne	el1_trap
 
-	mrs	x1, vttbr_el2		// If vttbr is valid, the 64bit guest
-	cbnz	x1, el1_trap		// called HVC
+	mrs	x1, vttbr_el2		// If vttbr is valid, the guest
+	cbnz	x1, el1_hvc_guest	// called HVC
 
 	/* Here, we're pretty sure the host called HVC. */
 	ldp	x0, x1, [sp], #16
@@ -100,6 +102,20 @@ alternative_endif
 
 	eret
 
+el1_hvc_guest:
+	/*
+	 * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1.
+	 * The workaround has already been applied on the host,
+	 * so let's quickly get back to the guest. We don't bother
+	 * restoring x1, as it can be clobbered anyway.
+	 */
+	ldr	x1, [sp]				// Guest's x0
+	eor	w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1
+	cbnz	w1, el1_trap
+	mov	x0, x1
+	add	sp, sp, #16
+	eret
+
 el1_trap:
 	/*
 	 * x0: ESR_EC
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 11/14] arm64: KVM: Add SMCCC_ARCH_WORKAROUND_1 fast handling
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

We want SMCCC_ARCH_WORKAROUND_1 to be fast. As fast as possible.
So let's intercept it as early as we can by testing for the
function call number as soon as we've identified a HVC call
coming from the guest.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/hyp-entry.S | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index e4f37b9dd47c..f36464bd57c5 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/linkage.h>
 
 #include <asm/alternative.h>
@@ -64,10 +65,11 @@ alternative_endif
 	lsr	x0, x1, #ESR_ELx_EC_SHIFT
 
 	cmp	x0, #ESR_ELx_EC_HVC64
+	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
 	b.ne	el1_trap
 
-	mrs	x1, vttbr_el2		// If vttbr is valid, the 64bit guest
-	cbnz	x1, el1_trap		// called HVC
+	mrs	x1, vttbr_el2		// If vttbr is valid, the guest
+	cbnz	x1, el1_hvc_guest	// called HVC
 
 	/* Here, we're pretty sure the host called HVC. */
 	ldp	x0, x1, [sp], #16
@@ -100,6 +102,20 @@ alternative_endif
 
 	eret
 
+el1_hvc_guest:
+	/*
+	 * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1.
+	 * The workaround has already been applied on the host,
+	 * so let's quickly get back to the guest. We don't bother
+	 * restoring x1, as it can be clobbered anyway.
+	 */
+	ldr	x1, [sp]				// Guest's x0
+	eor	w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1
+	cbnz	w1, el1_trap
+	mov	x0, x1
+	add	sp, sp, #16
+	eret
+
 el1_trap:
 	/*
 	 * x0: ESR_EC
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 12/14] firmware/psci: Expose PSCI conduit
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

In order to call into the firmware to apply workarounds, it is
useful to find out whether we're using HVC or SMC. Let's expose
this through the psci_ops.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/firmware/psci.c | 26 +++++++++++++++++++++-----
 include/linux/psci.h    |  7 +++++++
 2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 8b25d31e8401..570187e5d084 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -59,7 +59,9 @@ bool psci_tos_resident_on(int cpu)
 	return cpu == resident_cpu;
 }
 
-struct psci_operations psci_ops;
+struct psci_operations psci_ops = {
+	.conduit = PSCI_CONDUIT_NONE,
+};
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
 				unsigned long, unsigned long);
@@ -210,6 +212,20 @@ static unsigned long psci_migrate_info_up_cpu(void)
 			      0, 0, 0);
 }
 
+static void set_conduit(enum psci_conduit conduit)
+{
+	switch (conduit) {
+	case PSCI_CONDUIT_HVC:
+		invoke_psci_fn = __invoke_psci_fn_hvc;
+		break;
+	case PSCI_CONDUIT_SMC:
+		invoke_psci_fn = __invoke_psci_fn_smc;
+		break;
+	}
+
+	psci_ops.conduit = conduit;
+}
+
 static int get_set_conduit_method(struct device_node *np)
 {
 	const char *method;
@@ -222,9 +238,9 @@ static int get_set_conduit_method(struct device_node *np)
 	}
 
 	if (!strcmp("hvc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	} else if (!strcmp("smc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 	} else {
 		pr_warn("invalid \"method\" property: %s\n", method);
 		return -EINVAL;
@@ -654,9 +670,9 @@ int __init psci_acpi_init(void)
 	pr_info("probing for conduit method from ACPI.\n");
 
 	if (acpi_psci_use_hvc())
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	else
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 
 	return psci_probe();
 }
diff --git a/include/linux/psci.h b/include/linux/psci.h
index f724fd8c78e8..f2679e5faa4f 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -25,6 +25,12 @@ bool psci_tos_resident_on(int cpu);
 int psci_cpu_init_idle(unsigned int cpu);
 int psci_cpu_suspend_enter(unsigned long index);
 
+enum psci_conduit {
+	PSCI_CONDUIT_NONE,
+	PSCI_CONDUIT_SMC,
+	PSCI_CONDUIT_HVC,
+};
+
 struct psci_operations {
 	u32 (*get_version)(void);
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -34,6 +40,7 @@ struct psci_operations {
 	int (*affinity_info)(unsigned long target_affinity,
 			unsigned long lowest_affinity_level);
 	int (*migrate_info_type)(void);
+	enum psci_conduit conduit;
 };
 
 extern struct psci_operations psci_ops;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 12/14] firmware/psci: Expose PSCI conduit
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

In order to call into the firmware to apply workarounds, it is
useful to find out whether we're using HVC or SMC. Let's expose
this through the psci_ops.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/firmware/psci.c | 26 +++++++++++++++++++++-----
 include/linux/psci.h    |  7 +++++++
 2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 8b25d31e8401..570187e5d084 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -59,7 +59,9 @@ bool psci_tos_resident_on(int cpu)
 	return cpu == resident_cpu;
 }
 
-struct psci_operations psci_ops;
+struct psci_operations psci_ops = {
+	.conduit = PSCI_CONDUIT_NONE,
+};
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
 				unsigned long, unsigned long);
@@ -210,6 +212,20 @@ static unsigned long psci_migrate_info_up_cpu(void)
 			      0, 0, 0);
 }
 
+static void set_conduit(enum psci_conduit conduit)
+{
+	switch (conduit) {
+	case PSCI_CONDUIT_HVC:
+		invoke_psci_fn = __invoke_psci_fn_hvc;
+		break;
+	case PSCI_CONDUIT_SMC:
+		invoke_psci_fn = __invoke_psci_fn_smc;
+		break;
+	}
+
+	psci_ops.conduit = conduit;
+}
+
 static int get_set_conduit_method(struct device_node *np)
 {
 	const char *method;
@@ -222,9 +238,9 @@ static int get_set_conduit_method(struct device_node *np)
 	}
 
 	if (!strcmp("hvc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	} else if (!strcmp("smc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 	} else {
 		pr_warn("invalid \"method\" property: %s\n", method);
 		return -EINVAL;
@@ -654,9 +670,9 @@ int __init psci_acpi_init(void)
 	pr_info("probing for conduit method from ACPI.\n");
 
 	if (acpi_psci_use_hvc())
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	else
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 
 	return psci_probe();
 }
diff --git a/include/linux/psci.h b/include/linux/psci.h
index f724fd8c78e8..f2679e5faa4f 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -25,6 +25,12 @@ bool psci_tos_resident_on(int cpu);
 int psci_cpu_init_idle(unsigned int cpu);
 int psci_cpu_suspend_enter(unsigned long index);
 
+enum psci_conduit {
+	PSCI_CONDUIT_NONE,
+	PSCI_CONDUIT_SMC,
+	PSCI_CONDUIT_HVC,
+};
+
 struct psci_operations {
 	u32 (*get_version)(void);
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -34,6 +40,7 @@ struct psci_operations {
 	int (*affinity_info)(unsigned long target_affinity,
 			unsigned long lowest_affinity_level);
 	int (*migrate_info_type)(void);
+	enum psci_conduit conduit;
 };
 
 extern struct psci_operations psci_ops;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 12/14] firmware/psci: Expose PSCI conduit
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

In order to call into the firmware to apply workarounds, it is
useful to find out whether we're using HVC or SMC. Let's expose
this through the psci_ops.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/firmware/psci.c | 26 +++++++++++++++++++++-----
 include/linux/psci.h    |  7 +++++++
 2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 8b25d31e8401..570187e5d084 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -59,7 +59,9 @@ bool psci_tos_resident_on(int cpu)
 	return cpu == resident_cpu;
 }
 
-struct psci_operations psci_ops;
+struct psci_operations psci_ops = {
+	.conduit = PSCI_CONDUIT_NONE,
+};
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
 				unsigned long, unsigned long);
@@ -210,6 +212,20 @@ static unsigned long psci_migrate_info_up_cpu(void)
 			      0, 0, 0);
 }
 
+static void set_conduit(enum psci_conduit conduit)
+{
+	switch (conduit) {
+	case PSCI_CONDUIT_HVC:
+		invoke_psci_fn = __invoke_psci_fn_hvc;
+		break;
+	case PSCI_CONDUIT_SMC:
+		invoke_psci_fn = __invoke_psci_fn_smc;
+		break;
+	}
+
+	psci_ops.conduit = conduit;
+}
+
 static int get_set_conduit_method(struct device_node *np)
 {
 	const char *method;
@@ -222,9 +238,9 @@ static int get_set_conduit_method(struct device_node *np)
 	}
 
 	if (!strcmp("hvc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	} else if (!strcmp("smc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 	} else {
 		pr_warn("invalid \"method\" property: %s\n", method);
 		return -EINVAL;
@@ -654,9 +670,9 @@ int __init psci_acpi_init(void)
 	pr_info("probing for conduit method from ACPI.\n");
 
 	if (acpi_psci_use_hvc())
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	else
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 
 	return psci_probe();
 }
diff --git a/include/linux/psci.h b/include/linux/psci.h
index f724fd8c78e8..f2679e5faa4f 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -25,6 +25,12 @@ bool psci_tos_resident_on(int cpu);
 int psci_cpu_init_idle(unsigned int cpu);
 int psci_cpu_suspend_enter(unsigned long index);
 
+enum psci_conduit {
+	PSCI_CONDUIT_NONE,
+	PSCI_CONDUIT_SMC,
+	PSCI_CONDUIT_HVC,
+};
+
 struct psci_operations {
 	u32 (*get_version)(void);
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -34,6 +40,7 @@ struct psci_operations {
 	int (*affinity_info)(unsigned long target_affinity,
 			unsigned long lowest_affinity_level);
 	int (*migrate_info_type)(void);
+	enum psci_conduit conduit;
 };
 
 extern struct psci_operations psci_ops;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 13/14] firmware/psci: Expose SMCCC version through psci_ops
  2018-01-26 14:28 ` Marc Zyngier
  (?)
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

Since PSCI 1.0 allows the SMCCC version to be (indirectly) probed,
let's do that at boot time, and expose the version of the calling
convention as part of the psci_ops structure.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/firmware/psci.c | 22 ++++++++++++++++++++++
 include/linux/psci.h    |  6 ++++++
 2 files changed, 28 insertions(+)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 570187e5d084..b260bbf637a2 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -509,6 +509,27 @@ static void __init psci_init_migrate(void)
 	pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
 }
 
+static void __init psci_init_smccc(u32 ver)
+{
+	int feature = PSCI_RET_NOT_SUPPORTED;
+
+	if (PSCI_VERSION_MAJOR(ver) > 1 ||
+	    (PSCI_VERSION_MAJOR(ver) == 1 && PSCI_VERSION_MINOR(ver) >= 0))
+		feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
+
+	if (feature == PSCI_RET_NOT_SUPPORTED) {
+		psci_ops.variant = SMCCC_VARIANT_1_0;
+	} else {
+		ver = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
+		if (ver != ARM_SMCCC_VERSION_1_1)
+			psci_ops.variant = SMCCC_VARIANT_1_0;
+		else
+			psci_ops.variant = SMCCC_VARIANT_1_1;
+	}
+
+	pr_info("SMC Calling Convention v1.%d\n", psci_ops.variant);
+}
+
 static void __init psci_0_2_set_functions(void)
 {
 	pr_info("Using standard PSCI v0.2 function IDs\n");
@@ -555,6 +576,7 @@ static int __init psci_probe(void)
 	psci_0_2_set_functions();
 
 	psci_init_migrate();
+	psci_init_smccc(ver);
 
 	if (PSCI_VERSION_MAJOR(ver) >= 1) {
 		psci_init_cpu_suspend();
diff --git a/include/linux/psci.h b/include/linux/psci.h
index f2679e5faa4f..83fd16a37be3 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -31,6 +31,11 @@ enum psci_conduit {
 	PSCI_CONDUIT_HVC,
 };
 
+enum smccc_variant {
+	SMCCC_VARIANT_1_0,
+	SMCCC_VARIANT_1_1,
+};
+
 struct psci_operations {
 	u32 (*get_version)(void);
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -41,6 +46,7 @@ struct psci_operations {
 			unsigned long lowest_affinity_level);
 	int (*migrate_info_type)(void);
 	enum psci_conduit conduit;
+	enum smccc_variant variant;
 };
 
 extern struct psci_operations psci_ops;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 13/14] firmware/psci: Expose SMCCC version through psci_ops
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

Since PSCI 1.0 allows the SMCCC version to be (indirectly) probed,
let's do that at boot time, and expose the version of the calling
convention as part of the psci_ops structure.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/firmware/psci.c | 22 ++++++++++++++++++++++
 include/linux/psci.h    |  6 ++++++
 2 files changed, 28 insertions(+)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 570187e5d084..b260bbf637a2 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -509,6 +509,27 @@ static void __init psci_init_migrate(void)
 	pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
 }
 
+static void __init psci_init_smccc(u32 ver)
+{
+	int feature = PSCI_RET_NOT_SUPPORTED;
+
+	if (PSCI_VERSION_MAJOR(ver) > 1 ||
+	    (PSCI_VERSION_MAJOR(ver) == 1 && PSCI_VERSION_MINOR(ver) >= 0))
+		feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
+
+	if (feature == PSCI_RET_NOT_SUPPORTED) {
+		psci_ops.variant = SMCCC_VARIANT_1_0;
+	} else {
+		ver = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
+		if (ver != ARM_SMCCC_VERSION_1_1)
+			psci_ops.variant = SMCCC_VARIANT_1_0;
+		else
+			psci_ops.variant = SMCCC_VARIANT_1_1;
+	}
+
+	pr_info("SMC Calling Convention v1.%d\n", psci_ops.variant);
+}
+
 static void __init psci_0_2_set_functions(void)
 {
 	pr_info("Using standard PSCI v0.2 function IDs\n");
@@ -555,6 +576,7 @@ static int __init psci_probe(void)
 	psci_0_2_set_functions();
 
 	psci_init_migrate();
+	psci_init_smccc(ver);
 
 	if (PSCI_VERSION_MAJOR(ver) >= 1) {
 		psci_init_cpu_suspend();
diff --git a/include/linux/psci.h b/include/linux/psci.h
index f2679e5faa4f..83fd16a37be3 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -31,6 +31,11 @@ enum psci_conduit {
 	PSCI_CONDUIT_HVC,
 };
 
+enum smccc_variant {
+	SMCCC_VARIANT_1_0,
+	SMCCC_VARIANT_1_1,
+};
+
 struct psci_operations {
 	u32 (*get_version)(void);
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -41,6 +46,7 @@ struct psci_operations {
 			unsigned long lowest_affinity_level);
 	int (*migrate_info_type)(void);
 	enum psci_conduit conduit;
+	enum smccc_variant variant;
 };
 
 extern struct psci_operations psci_ops;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 13/14] firmware/psci: Expose SMCCC version through psci_ops
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

Since PSCI 1.0 allows the SMCCC version to be (indirectly) probed,
let's do that at boot time, and expose the version of the calling
convention as part of the psci_ops structure.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/firmware/psci.c | 22 ++++++++++++++++++++++
 include/linux/psci.h    |  6 ++++++
 2 files changed, 28 insertions(+)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 570187e5d084..b260bbf637a2 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -509,6 +509,27 @@ static void __init psci_init_migrate(void)
 	pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
 }
 
+static void __init psci_init_smccc(u32 ver)
+{
+	int feature = PSCI_RET_NOT_SUPPORTED;
+
+	if (PSCI_VERSION_MAJOR(ver) > 1 ||
+	    (PSCI_VERSION_MAJOR(ver) == 1 && PSCI_VERSION_MINOR(ver) >= 0))
+		feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
+
+	if (feature == PSCI_RET_NOT_SUPPORTED) {
+		psci_ops.variant = SMCCC_VARIANT_1_0;
+	} else {
+		ver = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
+		if (ver != ARM_SMCCC_VERSION_1_1)
+			psci_ops.variant = SMCCC_VARIANT_1_0;
+		else
+			psci_ops.variant = SMCCC_VARIANT_1_1;
+	}
+
+	pr_info("SMC Calling Convention v1.%d\n", psci_ops.variant);
+}
+
 static void __init psci_0_2_set_functions(void)
 {
 	pr_info("Using standard PSCI v0.2 function IDs\n");
@@ -555,6 +576,7 @@ static int __init psci_probe(void)
 	psci_0_2_set_functions();
 
 	psci_init_migrate();
+	psci_init_smccc(ver);
 
 	if (PSCI_VERSION_MAJOR(ver) >= 1) {
 		psci_init_cpu_suspend();
diff --git a/include/linux/psci.h b/include/linux/psci.h
index f2679e5faa4f..83fd16a37be3 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -31,6 +31,11 @@ enum psci_conduit {
 	PSCI_CONDUIT_HVC,
 };
 
+enum smccc_variant {
+	SMCCC_VARIANT_1_0,
+	SMCCC_VARIANT_1_1,
+};
+
 struct psci_operations {
 	u32 (*get_version)(void);
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -41,6 +46,7 @@ struct psci_operations {
 			unsigned long lowest_affinity_level);
 	int (*migrate_info_type)(void);
 	enum psci_conduit conduit;
+	enum smccc_variant variant;
 };
 
 extern struct psci_operations psci_ops;
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-26 14:28 ` Marc Zyngier
@ 2018-01-26 14:28   ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
It is lovely. Really.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kernel/bpi.S        | 20 ++++++++++++
 arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
index 76225c2611ea..add7e08a018d 100644
--- a/arch/arm64/kernel/bpi.S
+++ b/arch/arm64/kernel/bpi.S
@@ -17,6 +17,7 @@
  */
 
 #include <linux/linkage.h>
+#include <linux/arm-smccc.h>
 
 .macro ventry target
 	.rept 31
@@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
 	.endr
 	ldp	x29, x30, [sp], #16
 ENTRY(__qcom_hyp_sanitize_link_stack_end)
+
+.macro smccc_workaround_1 inst
+	sub	sp, sp, #(8 * 4)
+	stp	x2, x3, [sp, #(16 * 0)]
+	stp	x0, x1, [sp, #(16 * 1)]
+	orr	w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
+	\inst	#0
+	ldp	x2, x3, [sp, #(16 * 0)]
+	ldp	x0, x1, [sp, #(16 * 1)]
+	add	sp, sp, #(8 * 4)
+.endm
+
+ENTRY(__smccc_workaround_1_smc_start)
+	smccc_workaround_1	smc
+ENTRY(__smccc_workaround_1_smc_end)
+
+ENTRY(__smccc_workaround_1_hvc_start)
+	smccc_workaround_1	hvc
+ENTRY(__smccc_workaround_1_hvc_end)
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index ed6881882231..f1501873f2e4 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
 extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
 extern char __qcom_hyp_sanitize_link_stack_start[];
 extern char __qcom_hyp_sanitize_link_stack_end[];
+extern char __smccc_workaround_1_smc_start[];
+extern char __smccc_workaround_1_smc_end[];
+extern char __smccc_workaround_1_hvc_start[];
+extern char __smccc_workaround_1_hvc_end[];
 
 static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
 				const char *hyp_vecs_end)
@@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
 #define __psci_hyp_bp_inval_end			NULL
 #define __qcom_hyp_sanitize_link_stack_start	NULL
 #define __qcom_hyp_sanitize_link_stack_end	NULL
+#define __smccc_workaround_1_smc_start		NULL
+#define __smccc_workaround_1_smc_end		NULL
+#define __smccc_workaround_1_hvc_start		NULL
+#define __smccc_workaround_1_hvc_end		NULL
 
 static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
 				      const char *hyp_vecs_start,
@@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
 	__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
 }
 
+#include <uapi/linux/psci.h>
+#include <linux/arm-smccc.h>
 #include <linux/psci.h>
 
+static void call_smc_arch_workaround_1(void)
+{
+	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
+	asm volatile("smc	#0\n"
+		     : "+r" (w0));
+}
+
+static void call_hvc_arch_workaround_1(void)
+{
+	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
+	asm volatile("hvc	#0\n"
+		     : "+r" (w0));
+}
+
+static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
+{
+	bp_hardening_cb_t cb;
+	void *smccc_start, *smccc_end;
+	struct arm_smccc_res res;
+
+	if (psci_ops.variant == SMCCC_VARIANT_1_0)
+		return false;
+
+	switch (psci_ops.conduit) {
+	case PSCI_CONDUIT_HVC:
+		arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
+			      &res);
+		if (res.a0)
+			return false;
+		cb = call_hvc_arch_workaround_1;
+		smccc_start = __smccc_workaround_1_hvc_start;
+		smccc_end = __smccc_workaround_1_hvc_end;
+		break;
+
+	case PSCI_CONDUIT_SMC:
+		arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
+			      &res);
+		if (res.a0)
+			return false;
+		cb = call_smc_arch_workaround_1;
+		smccc_start = __smccc_workaround_1_smc_start;
+		smccc_end = __smccc_workaround_1_smc_end;
+		break;
+
+	default:
+		return false;
+	}
+
+	install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
+
+	return true;
+}
+
 static int enable_psci_bp_hardening(void *data)
 {
 	const struct arm64_cpu_capabilities *entry = data;
 
-	if (psci_ops.get_version)
+	if (psci_ops.get_version) {
+		if (check_smccc_arch_workaround_1(entry))
+			return 0;
+
 		install_bp_hardening_cb(entry,
 				       (bp_hardening_cb_t)psci_ops.get_version,
 				       __psci_hyp_bp_inval_start,
 				       __psci_hyp_bp_inval_end);
+	}
 
 	return 0;
 }
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-26 14:28   ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
It is lovely. Really.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kernel/bpi.S        | 20 ++++++++++++
 arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
index 76225c2611ea..add7e08a018d 100644
--- a/arch/arm64/kernel/bpi.S
+++ b/arch/arm64/kernel/bpi.S
@@ -17,6 +17,7 @@
  */
 
 #include <linux/linkage.h>
+#include <linux/arm-smccc.h>
 
 .macro ventry target
 	.rept 31
@@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
 	.endr
 	ldp	x29, x30, [sp], #16
 ENTRY(__qcom_hyp_sanitize_link_stack_end)
+
+.macro smccc_workaround_1 inst
+	sub	sp, sp, #(8 * 4)
+	stp	x2, x3, [sp, #(16 * 0)]
+	stp	x0, x1, [sp, #(16 * 1)]
+	orr	w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
+	\inst	#0
+	ldp	x2, x3, [sp, #(16 * 0)]
+	ldp	x0, x1, [sp, #(16 * 1)]
+	add	sp, sp, #(8 * 4)
+.endm
+
+ENTRY(__smccc_workaround_1_smc_start)
+	smccc_workaround_1	smc
+ENTRY(__smccc_workaround_1_smc_end)
+
+ENTRY(__smccc_workaround_1_hvc_start)
+	smccc_workaround_1	hvc
+ENTRY(__smccc_workaround_1_hvc_end)
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index ed6881882231..f1501873f2e4 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
 extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
 extern char __qcom_hyp_sanitize_link_stack_start[];
 extern char __qcom_hyp_sanitize_link_stack_end[];
+extern char __smccc_workaround_1_smc_start[];
+extern char __smccc_workaround_1_smc_end[];
+extern char __smccc_workaround_1_hvc_start[];
+extern char __smccc_workaround_1_hvc_end[];
 
 static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
 				const char *hyp_vecs_end)
@@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
 #define __psci_hyp_bp_inval_end			NULL
 #define __qcom_hyp_sanitize_link_stack_start	NULL
 #define __qcom_hyp_sanitize_link_stack_end	NULL
+#define __smccc_workaround_1_smc_start		NULL
+#define __smccc_workaround_1_smc_end		NULL
+#define __smccc_workaround_1_hvc_start		NULL
+#define __smccc_workaround_1_hvc_end		NULL
 
 static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
 				      const char *hyp_vecs_start,
@@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
 	__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
 }
 
+#include <uapi/linux/psci.h>
+#include <linux/arm-smccc.h>
 #include <linux/psci.h>
 
+static void call_smc_arch_workaround_1(void)
+{
+	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
+	asm volatile("smc	#0\n"
+		     : "+r" (w0));
+}
+
+static void call_hvc_arch_workaround_1(void)
+{
+	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
+	asm volatile("hvc	#0\n"
+		     : "+r" (w0));
+}
+
+static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
+{
+	bp_hardening_cb_t cb;
+	void *smccc_start, *smccc_end;
+	struct arm_smccc_res res;
+
+	if (psci_ops.variant == SMCCC_VARIANT_1_0)
+		return false;
+
+	switch (psci_ops.conduit) {
+	case PSCI_CONDUIT_HVC:
+		arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
+			      &res);
+		if (res.a0)
+			return false;
+		cb = call_hvc_arch_workaround_1;
+		smccc_start = __smccc_workaround_1_hvc_start;
+		smccc_end = __smccc_workaround_1_hvc_end;
+		break;
+
+	case PSCI_CONDUIT_SMC:
+		arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
+			      &res);
+		if (res.a0)
+			return false;
+		cb = call_smc_arch_workaround_1;
+		smccc_start = __smccc_workaround_1_smc_start;
+		smccc_end = __smccc_workaround_1_smc_end;
+		break;
+
+	default:
+		return false;
+	}
+
+	install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
+
+	return true;
+}
+
 static int enable_psci_bp_hardening(void *data)
 {
 	const struct arm64_cpu_capabilities *entry = data;
 
-	if (psci_ops.get_version)
+	if (psci_ops.get_version) {
+		if (check_smccc_arch_workaround_1(entry))
+			return 0;
+
 		install_bp_hardening_cb(entry,
 				       (bp_hardening_cb_t)psci_ops.get_version,
 				       __psci_hyp_bp_inval_start,
 				       __psci_hyp_bp_inval_end);
+	}
 
 	return 0;
 }
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-26 14:28   ` Marc Zyngier
  (?)
@ 2018-01-26 15:50     ` Robin Murphy
  -1 siblings, 0 replies; 67+ messages in thread
From: Robin Murphy @ 2018-01-26 15:50 UTC (permalink / raw)
  To: Marc Zyngier, linux-kernel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 26/01/18 14:28, Marc Zyngier wrote:
> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
> It is lovely. Really.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>   arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>   arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>   2 files changed, 90 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
> index 76225c2611ea..add7e08a018d 100644
> --- a/arch/arm64/kernel/bpi.S
> +++ b/arch/arm64/kernel/bpi.S
> @@ -17,6 +17,7 @@
>    */
>   
>   #include <linux/linkage.h>
> +#include <linux/arm-smccc.h>
>   
>   .macro ventry target
>   	.rept 31
> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>   	.endr
>   	ldp	x29, x30, [sp], #16
>   ENTRY(__qcom_hyp_sanitize_link_stack_end)
> +
> +.macro smccc_workaround_1 inst
> +	sub	sp, sp, #(8 * 4)
> +	stp	x2, x3, [sp, #(16 * 0)]

This seems unnecessarily confusing - using either units of registers, or 
of register pairs, is fine, but mixing both in the same sequence just 
hurts more than it needs to.

> +	stp	x0, x1, [sp, #(16 * 1)]
> +	orr	w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1

Writing this as a MOV like a sane person would make things 0.37% more 
lovely, I promise ;)

> +	\inst	#0
> +	ldp	x2, x3, [sp, #(16 * 0)]
> +	ldp	x0, x1, [sp, #(16 * 1)]
> +	add	sp, sp, #(8 * 4)
> +.endm
> +
> +ENTRY(__smccc_workaround_1_smc_start)
> +	smccc_workaround_1	smc
> +ENTRY(__smccc_workaround_1_smc_end)
> +
> +ENTRY(__smccc_workaround_1_hvc_start)
> +	smccc_workaround_1	hvc
> +ENTRY(__smccc_workaround_1_hvc_end)

That said, should we not be implementing this lot in smccc-call.S...

> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index ed6881882231..f1501873f2e4 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>   extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>   extern char __qcom_hyp_sanitize_link_stack_start[];
>   extern char __qcom_hyp_sanitize_link_stack_end[];
> +extern char __smccc_workaround_1_smc_start[];
> +extern char __smccc_workaround_1_smc_end[];
> +extern char __smccc_workaround_1_hvc_start[];
> +extern char __smccc_workaround_1_hvc_end[];
>   
>   static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>   				const char *hyp_vecs_end)
> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>   #define __psci_hyp_bp_inval_end			NULL
>   #define __qcom_hyp_sanitize_link_stack_start	NULL
>   #define __qcom_hyp_sanitize_link_stack_end	NULL
> +#define __smccc_workaround_1_smc_start		NULL
> +#define __smccc_workaround_1_smc_end		NULL
> +#define __smccc_workaround_1_hvc_start		NULL
> +#define __smccc_workaround_1_hvc_end		NULL
>   
>   static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>   				      const char *hyp_vecs_start,
> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>   	__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>   }
>   
> +#include <uapi/linux/psci.h>
> +#include <linux/arm-smccc.h>
>   #include <linux/psci.h>
>   
> +static void call_smc_arch_workaround_1(void)
> +{
> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +	asm volatile("smc	#0\n"
> +		     : "+r" (w0));
> +}
> +
> +static void call_hvc_arch_workaround_1(void)
> +{
> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +	asm volatile("hvc	#0\n"
> +		     : "+r" (w0));
> +}

...such that these could simply be something like:

static void call_{smc,hvc}_arch_workaround_1(void)
{
	arm_smccc_v1_1_{smc,hvc}(ARM_SMCCC_ARCH_WORKAROUND_1);
}

?

Robin.

> +
> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
> +{
> +	bp_hardening_cb_t cb;
> +	void *smccc_start, *smccc_end;
> +	struct arm_smccc_res res;
> +
> +	if (psci_ops.variant == SMCCC_VARIANT_1_0)
> +		return false;
> +
> +	switch (psci_ops.conduit) {
> +	case PSCI_CONDUIT_HVC:
> +		arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +			      &res);
> +		if (res.a0)
> +			return false;
> +		cb = call_hvc_arch_workaround_1;
> +		smccc_start = __smccc_workaround_1_hvc_start;
> +		smccc_end = __smccc_workaround_1_hvc_end;
> +		break;
> +
> +	case PSCI_CONDUIT_SMC:
> +		arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +			      &res);
> +		if (res.a0)
> +			return false;
> +		cb = call_smc_arch_workaround_1;
> +		smccc_start = __smccc_workaround_1_smc_start;
> +		smccc_end = __smccc_workaround_1_smc_end;
> +		break;
> +
> +	default:
> +		return false;
> +	}
> +
> +	install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
> +
> +	return true;
> +}
> +
>   static int enable_psci_bp_hardening(void *data)
>   {
>   	const struct arm64_cpu_capabilities *entry = data;
>   
> -	if (psci_ops.get_version)
> +	if (psci_ops.get_version) {
> +		if (check_smccc_arch_workaround_1(entry))
> +			return 0;
> +
>   		install_bp_hardening_cb(entry,
>   				       (bp_hardening_cb_t)psci_ops.get_version,
>   				       __psci_hyp_bp_inval_start,
>   				       __psci_hyp_bp_inval_end);
> +	}
>   
>   	return 0;
>   }
> 

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-26 15:50     ` Robin Murphy
  0 siblings, 0 replies; 67+ messages in thread
From: Robin Murphy @ 2018-01-26 15:50 UTC (permalink / raw)
  To: Marc Zyngier, linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Jon Masters, Will Deacon, Catalin Marinas

On 26/01/18 14:28, Marc Zyngier wrote:
> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
> It is lovely. Really.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>   arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>   arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>   2 files changed, 90 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
> index 76225c2611ea..add7e08a018d 100644
> --- a/arch/arm64/kernel/bpi.S
> +++ b/arch/arm64/kernel/bpi.S
> @@ -17,6 +17,7 @@
>    */
>   
>   #include <linux/linkage.h>
> +#include <linux/arm-smccc.h>
>   
>   .macro ventry target
>   	.rept 31
> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>   	.endr
>   	ldp	x29, x30, [sp], #16
>   ENTRY(__qcom_hyp_sanitize_link_stack_end)
> +
> +.macro smccc_workaround_1 inst
> +	sub	sp, sp, #(8 * 4)
> +	stp	x2, x3, [sp, #(16 * 0)]

This seems unnecessarily confusing - using either units of registers, or 
of register pairs, is fine, but mixing both in the same sequence just 
hurts more than it needs to.

> +	stp	x0, x1, [sp, #(16 * 1)]
> +	orr	w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1

Writing this as a MOV like a sane person would make things 0.37% more 
lovely, I promise ;)

> +	\inst	#0
> +	ldp	x2, x3, [sp, #(16 * 0)]
> +	ldp	x0, x1, [sp, #(16 * 1)]
> +	add	sp, sp, #(8 * 4)
> +.endm
> +
> +ENTRY(__smccc_workaround_1_smc_start)
> +	smccc_workaround_1	smc
> +ENTRY(__smccc_workaround_1_smc_end)
> +
> +ENTRY(__smccc_workaround_1_hvc_start)
> +	smccc_workaround_1	hvc
> +ENTRY(__smccc_workaround_1_hvc_end)

That said, should we not be implementing this lot in smccc-call.S...

> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index ed6881882231..f1501873f2e4 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>   extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>   extern char __qcom_hyp_sanitize_link_stack_start[];
>   extern char __qcom_hyp_sanitize_link_stack_end[];
> +extern char __smccc_workaround_1_smc_start[];
> +extern char __smccc_workaround_1_smc_end[];
> +extern char __smccc_workaround_1_hvc_start[];
> +extern char __smccc_workaround_1_hvc_end[];
>   
>   static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>   				const char *hyp_vecs_end)
> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>   #define __psci_hyp_bp_inval_end			NULL
>   #define __qcom_hyp_sanitize_link_stack_start	NULL
>   #define __qcom_hyp_sanitize_link_stack_end	NULL
> +#define __smccc_workaround_1_smc_start		NULL
> +#define __smccc_workaround_1_smc_end		NULL
> +#define __smccc_workaround_1_hvc_start		NULL
> +#define __smccc_workaround_1_hvc_end		NULL
>   
>   static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>   				      const char *hyp_vecs_start,
> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>   	__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>   }
>   
> +#include <uapi/linux/psci.h>
> +#include <linux/arm-smccc.h>
>   #include <linux/psci.h>
>   
> +static void call_smc_arch_workaround_1(void)
> +{
> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +	asm volatile("smc	#0\n"
> +		     : "+r" (w0));
> +}
> +
> +static void call_hvc_arch_workaround_1(void)
> +{
> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +	asm volatile("hvc	#0\n"
> +		     : "+r" (w0));
> +}

...such that these could simply be something like:

static void call_{smc,hvc}_arch_workaround_1(void)
{
	arm_smccc_v1_1_{smc,hvc}(ARM_SMCCC_ARCH_WORKAROUND_1);
}

?

Robin.

> +
> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
> +{
> +	bp_hardening_cb_t cb;
> +	void *smccc_start, *smccc_end;
> +	struct arm_smccc_res res;
> +
> +	if (psci_ops.variant == SMCCC_VARIANT_1_0)
> +		return false;
> +
> +	switch (psci_ops.conduit) {
> +	case PSCI_CONDUIT_HVC:
> +		arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +			      &res);
> +		if (res.a0)
> +			return false;
> +		cb = call_hvc_arch_workaround_1;
> +		smccc_start = __smccc_workaround_1_hvc_start;
> +		smccc_end = __smccc_workaround_1_hvc_end;
> +		break;
> +
> +	case PSCI_CONDUIT_SMC:
> +		arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +			      &res);
> +		if (res.a0)
> +			return false;
> +		cb = call_smc_arch_workaround_1;
> +		smccc_start = __smccc_workaround_1_smc_start;
> +		smccc_end = __smccc_workaround_1_smc_end;
> +		break;
> +
> +	default:
> +		return false;
> +	}
> +
> +	install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
> +
> +	return true;
> +}
> +
>   static int enable_psci_bp_hardening(void *data)
>   {
>   	const struct arm64_cpu_capabilities *entry = data;
>   
> -	if (psci_ops.get_version)
> +	if (psci_ops.get_version) {
> +		if (check_smccc_arch_workaround_1(entry))
> +			return 0;
> +
>   		install_bp_hardening_cb(entry,
>   				       (bp_hardening_cb_t)psci_ops.get_version,
>   				       __psci_hyp_bp_inval_start,
>   				       __psci_hyp_bp_inval_end);
> +	}
>   
>   	return 0;
>   }
> 

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-26 15:50     ` Robin Murphy
  0 siblings, 0 replies; 67+ messages in thread
From: Robin Murphy @ 2018-01-26 15:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 26/01/18 14:28, Marc Zyngier wrote:
> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
> It is lovely. Really.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>   arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>   arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>   2 files changed, 90 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
> index 76225c2611ea..add7e08a018d 100644
> --- a/arch/arm64/kernel/bpi.S
> +++ b/arch/arm64/kernel/bpi.S
> @@ -17,6 +17,7 @@
>    */
>   
>   #include <linux/linkage.h>
> +#include <linux/arm-smccc.h>
>   
>   .macro ventry target
>   	.rept 31
> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>   	.endr
>   	ldp	x29, x30, [sp], #16
>   ENTRY(__qcom_hyp_sanitize_link_stack_end)
> +
> +.macro smccc_workaround_1 inst
> +	sub	sp, sp, #(8 * 4)
> +	stp	x2, x3, [sp, #(16 * 0)]

This seems unnecessarily confusing - using either units of registers, or 
of register pairs, is fine, but mixing both in the same sequence just 
hurts more than it needs to.

> +	stp	x0, x1, [sp, #(16 * 1)]
> +	orr	w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1

Writing this as a MOV like a sane person would make things 0.37% more 
lovely, I promise ;)

> +	\inst	#0
> +	ldp	x2, x3, [sp, #(16 * 0)]
> +	ldp	x0, x1, [sp, #(16 * 1)]
> +	add	sp, sp, #(8 * 4)
> +.endm
> +
> +ENTRY(__smccc_workaround_1_smc_start)
> +	smccc_workaround_1	smc
> +ENTRY(__smccc_workaround_1_smc_end)
> +
> +ENTRY(__smccc_workaround_1_hvc_start)
> +	smccc_workaround_1	hvc
> +ENTRY(__smccc_workaround_1_hvc_end)

That said, should we not be implementing this lot in smccc-call.S...

> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index ed6881882231..f1501873f2e4 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>   extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>   extern char __qcom_hyp_sanitize_link_stack_start[];
>   extern char __qcom_hyp_sanitize_link_stack_end[];
> +extern char __smccc_workaround_1_smc_start[];
> +extern char __smccc_workaround_1_smc_end[];
> +extern char __smccc_workaround_1_hvc_start[];
> +extern char __smccc_workaround_1_hvc_end[];
>   
>   static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>   				const char *hyp_vecs_end)
> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>   #define __psci_hyp_bp_inval_end			NULL
>   #define __qcom_hyp_sanitize_link_stack_start	NULL
>   #define __qcom_hyp_sanitize_link_stack_end	NULL
> +#define __smccc_workaround_1_smc_start		NULL
> +#define __smccc_workaround_1_smc_end		NULL
> +#define __smccc_workaround_1_hvc_start		NULL
> +#define __smccc_workaround_1_hvc_end		NULL
>   
>   static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>   				      const char *hyp_vecs_start,
> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>   	__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>   }
>   
> +#include <uapi/linux/psci.h>
> +#include <linux/arm-smccc.h>
>   #include <linux/psci.h>
>   
> +static void call_smc_arch_workaround_1(void)
> +{
> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +	asm volatile("smc	#0\n"
> +		     : "+r" (w0));
> +}
> +
> +static void call_hvc_arch_workaround_1(void)
> +{
> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +	asm volatile("hvc	#0\n"
> +		     : "+r" (w0));
> +}

...such that these could simply be something like:

static void call_{smc,hvc}_arch_workaround_1(void)
{
	arm_smccc_v1_1_{smc,hvc}(ARM_SMCCC_ARCH_WORKAROUND_1);
}

?

Robin.

> +
> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
> +{
> +	bp_hardening_cb_t cb;
> +	void *smccc_start, *smccc_end;
> +	struct arm_smccc_res res;
> +
> +	if (psci_ops.variant == SMCCC_VARIANT_1_0)
> +		return false;
> +
> +	switch (psci_ops.conduit) {
> +	case PSCI_CONDUIT_HVC:
> +		arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +			      &res);
> +		if (res.a0)
> +			return false;
> +		cb = call_hvc_arch_workaround_1;
> +		smccc_start = __smccc_workaround_1_hvc_start;
> +		smccc_end = __smccc_workaround_1_hvc_end;
> +		break;
> +
> +	case PSCI_CONDUIT_SMC:
> +		arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +			      ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +			      &res);
> +		if (res.a0)
> +			return false;
> +		cb = call_smc_arch_workaround_1;
> +		smccc_start = __smccc_workaround_1_smc_start;
> +		smccc_end = __smccc_workaround_1_smc_end;
> +		break;
> +
> +	default:
> +		return false;
> +	}
> +
> +	install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
> +
> +	return true;
> +}
> +
>   static int enable_psci_bp_hardening(void *data)
>   {
>   	const struct arm64_cpu_capabilities *entry = data;
>   
> -	if (psci_ops.get_version)
> +	if (psci_ops.get_version) {
> +		if (check_smccc_arch_workaround_1(entry))
> +			return 0;
> +
>   		install_bp_hardening_cb(entry,
>   				       (bp_hardening_cb_t)psci_ops.get_version,
>   				       __psci_hyp_bp_inval_start,
>   				       __psci_hyp_bp_inval_end);
> +	}
>   
>   	return 0;
>   }
> 

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-26 15:50     ` Robin Murphy
@ 2018-01-26 16:07       ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 16:07 UTC (permalink / raw)
  To: Robin Murphy, linux-kernel, linux-arm-kernel, kvmarm
  Cc: Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

Hi Robin,

On 26/01/18 15:50, Robin Murphy wrote:
> On 26/01/18 14:28, Marc Zyngier wrote:
>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>> It is lovely. Really.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>   arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>   arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>   2 files changed, 90 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>> index 76225c2611ea..add7e08a018d 100644
>> --- a/arch/arm64/kernel/bpi.S
>> +++ b/arch/arm64/kernel/bpi.S
>> @@ -17,6 +17,7 @@
>>    */
>>   
>>   #include <linux/linkage.h>
>> +#include <linux/arm-smccc.h>
>>   
>>   .macro ventry target
>>   	.rept 31
>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>   	.endr
>>   	ldp	x29, x30, [sp], #16
>>   ENTRY(__qcom_hyp_sanitize_link_stack_end)
>> +
>> +.macro smccc_workaround_1 inst
>> +	sub	sp, sp, #(8 * 4)
>> +	stp	x2, x3, [sp, #(16 * 0)]
> 
> This seems unnecessarily confusing - using either units of registers, or 
> of register pairs, is fine, but mixing both in the same sequence just 
> hurts more than it needs to.

Point taken.

> 
>> +	stp	x0, x1, [sp, #(16 * 1)]
>> +	orr	w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
> 
> Writing this as a MOV like a sane person would make things 0.37% more 
> lovely, I promise ;)

But I swear that's what the assembler actually generates! Do I still get
the additional loveliness? ;-) I'll MOV it up.

> 
>> +	\inst	#0
>> +	ldp	x2, x3, [sp, #(16 * 0)]
>> +	ldp	x0, x1, [sp, #(16 * 1)]
>> +	add	sp, sp, #(8 * 4)
>> +.endm
>> +
>> +ENTRY(__smccc_workaround_1_smc_start)
>> +	smccc_workaround_1	smc
>> +ENTRY(__smccc_workaround_1_smc_end)
>> +
>> +ENTRY(__smccc_workaround_1_hvc_start)
>> +	smccc_workaround_1	hvc
>> +ENTRY(__smccc_workaround_1_hvc_end)
> 
> That said, should we not be implementing this lot in smccc-call.S...

Wouldn't work. We *copy* that code in the KVM vectors, see
__install_bp_hardening_cb and __copy_hyp_vect_bpi...

Yes, I know.

> 
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index ed6881882231..f1501873f2e4 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>   extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>   extern char __qcom_hyp_sanitize_link_stack_start[];
>>   extern char __qcom_hyp_sanitize_link_stack_end[];
>> +extern char __smccc_workaround_1_smc_start[];
>> +extern char __smccc_workaround_1_smc_end[];
>> +extern char __smccc_workaround_1_hvc_start[];
>> +extern char __smccc_workaround_1_hvc_end[];
>>   
>>   static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>   				const char *hyp_vecs_end)
>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>   #define __psci_hyp_bp_inval_end			NULL
>>   #define __qcom_hyp_sanitize_link_stack_start	NULL
>>   #define __qcom_hyp_sanitize_link_stack_end	NULL
>> +#define __smccc_workaround_1_smc_start		NULL
>> +#define __smccc_workaround_1_smc_end		NULL
>> +#define __smccc_workaround_1_hvc_start		NULL
>> +#define __smccc_workaround_1_hvc_end		NULL
>>   
>>   static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>   				      const char *hyp_vecs_start,
>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>   	__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>   }
>>   
>> +#include <uapi/linux/psci.h>
>> +#include <linux/arm-smccc.h>
>>   #include <linux/psci.h>
>>   
>> +static void call_smc_arch_workaround_1(void)
>> +{
>> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>> +	asm volatile("smc	#0\n"
>> +		     : "+r" (w0));
>> +}
>> +
>> +static void call_hvc_arch_workaround_1(void)
>> +{
>> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>> +	asm volatile("hvc	#0\n"
>> +		     : "+r" (w0));
>> +}
> 
> ...such that these could simply be something like:
> 
> static void call_{smc,hvc}_arch_workaround_1(void)
> {
> 	arm_smccc_v1_1_{smc,hvc}(ARM_SMCCC_ARCH_WORKAROUND_1);
> }
> 
> ?

That we could do. And maybe define them inline in arm-smccc.h so that we
don't get any extra call (we'd just need a way to declare x0-x3 as being
clobbered).

I'll have a go at it.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-26 16:07       ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 16:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Robin,

On 26/01/18 15:50, Robin Murphy wrote:
> On 26/01/18 14:28, Marc Zyngier wrote:
>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>> It is lovely. Really.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>   arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>   arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>   2 files changed, 90 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>> index 76225c2611ea..add7e08a018d 100644
>> --- a/arch/arm64/kernel/bpi.S
>> +++ b/arch/arm64/kernel/bpi.S
>> @@ -17,6 +17,7 @@
>>    */
>>   
>>   #include <linux/linkage.h>
>> +#include <linux/arm-smccc.h>
>>   
>>   .macro ventry target
>>   	.rept 31
>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>   	.endr
>>   	ldp	x29, x30, [sp], #16
>>   ENTRY(__qcom_hyp_sanitize_link_stack_end)
>> +
>> +.macro smccc_workaround_1 inst
>> +	sub	sp, sp, #(8 * 4)
>> +	stp	x2, x3, [sp, #(16 * 0)]
> 
> This seems unnecessarily confusing - using either units of registers, or 
> of register pairs, is fine, but mixing both in the same sequence just 
> hurts more than it needs to.

Point taken.

> 
>> +	stp	x0, x1, [sp, #(16 * 1)]
>> +	orr	w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
> 
> Writing this as a MOV like a sane person would make things 0.37% more 
> lovely, I promise ;)

But I swear that's what the assembler actually generates! Do I still get
the additional loveliness? ;-) I'll MOV it up.

> 
>> +	\inst	#0
>> +	ldp	x2, x3, [sp, #(16 * 0)]
>> +	ldp	x0, x1, [sp, #(16 * 1)]
>> +	add	sp, sp, #(8 * 4)
>> +.endm
>> +
>> +ENTRY(__smccc_workaround_1_smc_start)
>> +	smccc_workaround_1	smc
>> +ENTRY(__smccc_workaround_1_smc_end)
>> +
>> +ENTRY(__smccc_workaround_1_hvc_start)
>> +	smccc_workaround_1	hvc
>> +ENTRY(__smccc_workaround_1_hvc_end)
> 
> That said, should we not be implementing this lot in smccc-call.S...

Wouldn't work. We *copy* that code in the KVM vectors, see
__install_bp_hardening_cb and __copy_hyp_vect_bpi...

Yes, I know.

> 
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index ed6881882231..f1501873f2e4 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>   extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>   extern char __qcom_hyp_sanitize_link_stack_start[];
>>   extern char __qcom_hyp_sanitize_link_stack_end[];
>> +extern char __smccc_workaround_1_smc_start[];
>> +extern char __smccc_workaround_1_smc_end[];
>> +extern char __smccc_workaround_1_hvc_start[];
>> +extern char __smccc_workaround_1_hvc_end[];
>>   
>>   static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>   				const char *hyp_vecs_end)
>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>   #define __psci_hyp_bp_inval_end			NULL
>>   #define __qcom_hyp_sanitize_link_stack_start	NULL
>>   #define __qcom_hyp_sanitize_link_stack_end	NULL
>> +#define __smccc_workaround_1_smc_start		NULL
>> +#define __smccc_workaround_1_smc_end		NULL
>> +#define __smccc_workaround_1_hvc_start		NULL
>> +#define __smccc_workaround_1_hvc_end		NULL
>>   
>>   static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>   				      const char *hyp_vecs_start,
>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>   	__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>   }
>>   
>> +#include <uapi/linux/psci.h>
>> +#include <linux/arm-smccc.h>
>>   #include <linux/psci.h>
>>   
>> +static void call_smc_arch_workaround_1(void)
>> +{
>> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>> +	asm volatile("smc	#0\n"
>> +		     : "+r" (w0));
>> +}
>> +
>> +static void call_hvc_arch_workaround_1(void)
>> +{
>> +	register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>> +	asm volatile("hvc	#0\n"
>> +		     : "+r" (w0));
>> +}
> 
> ...such that these could simply be something like:
> 
> static void call_{smc,hvc}_arch_workaround_1(void)
> {
> 	arm_smccc_v1_1_{smc,hvc}(ARM_SMCCC_ARCH_WORKAROUND_1);
> }
> 
> ?

That we could do. And maybe define them inline in arm-smccc.h so that we
don't get any extra call (we'd just need a way to declare x0-x3 as being
clobbered).

I'll have a go at it.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 03/14] arm/arm64: KVM: Consolidate the PSCI include files
  2018-01-26 14:28   ` Marc Zyngier
  (?)
@ 2018-01-26 18:10     ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 18:10 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Catalin Marinas, Will Deacon, Peter Maydell, Christoffer Dall,
	Lorenzo Pieralisi, Mark Rutland, Jon Masters

On 26/01/18 14:28, Marc Zyngier wrote:
> As we're about to update the PSCI support, and because I'm lazy,
> let's move the PSCI include file to include/kvm so that both
> ARM architectures can find it.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/include/asm/psci.h                        | 25 ----------------------
>  arch/arm/kvm/handle_exit.c                         |  2 +-
>  arch/arm64/kvm/handle_exit.c                       |  3 ++-
>  .../asm/kvm_psci.h => include/kvm/arm_psci.h       |  6 +++---
>  virt/kvm/arm/arm.c                                 |  2 +-
>  virt/kvm/arm/psci.c                                |  3 ++-
>  6 files changed, 9 insertions(+), 32 deletions(-)
>  delete mode 100644 arch/arm/include/asm/psci.h
>  rename arch/arm64/include/asm/kvm_psci.h => include/kvm/arm_psci.h (89%)
> 
> diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
> deleted file mode 100644
> index e1b825dfab23..000000000000
> --- a/arch/arm/include/asm/psci.h
> +++ /dev/null
> @@ -1,25 +0,0 @@
> -/*
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - *
> - * Copyright (C) 2012 ARM Limited
> - */
> -
> -#ifndef __ASM_ARM_PSCI_H
> -#define __ASM_ARM_PSCI_H
> -
> -extern const struct smp_operations psci_smp_ops;
> -
> -#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
> -bool psci_smp_available(void);
> -#else
> -static inline bool psci_smp_available(void) { return false; }
> -#endif
> -
> -#endif /* __ASM_ARM_PSCI_H */

Doh. I deleted the wrong file. That was supposed to be kvm_psci.h, and
not psci.h. Not sure how I managed that one...

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 03/14] arm/arm64: KVM: Consolidate the PSCI include files
@ 2018-01-26 18:10     ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 18:10 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, kvmarm
  Cc: Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Jon Masters

On 26/01/18 14:28, Marc Zyngier wrote:
> As we're about to update the PSCI support, and because I'm lazy,
> let's move the PSCI include file to include/kvm so that both
> ARM architectures can find it.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/include/asm/psci.h                        | 25 ----------------------
>  arch/arm/kvm/handle_exit.c                         |  2 +-
>  arch/arm64/kvm/handle_exit.c                       |  3 ++-
>  .../asm/kvm_psci.h => include/kvm/arm_psci.h       |  6 +++---
>  virt/kvm/arm/arm.c                                 |  2 +-
>  virt/kvm/arm/psci.c                                |  3 ++-
>  6 files changed, 9 insertions(+), 32 deletions(-)
>  delete mode 100644 arch/arm/include/asm/psci.h
>  rename arch/arm64/include/asm/kvm_psci.h => include/kvm/arm_psci.h (89%)
> 
> diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
> deleted file mode 100644
> index e1b825dfab23..000000000000
> --- a/arch/arm/include/asm/psci.h
> +++ /dev/null
> @@ -1,25 +0,0 @@
> -/*
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - *
> - * Copyright (C) 2012 ARM Limited
> - */
> -
> -#ifndef __ASM_ARM_PSCI_H
> -#define __ASM_ARM_PSCI_H
> -
> -extern const struct smp_operations psci_smp_ops;
> -
> -#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
> -bool psci_smp_available(void);
> -#else
> -static inline bool psci_smp_available(void) { return false; }
> -#endif
> -
> -#endif /* __ASM_ARM_PSCI_H */

Doh. I deleted the wrong file. That was supposed to be kvm_psci.h, and
not psci.h. Not sure how I managed that one...

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 03/14] arm/arm64: KVM: Consolidate the PSCI include files
@ 2018-01-26 18:10     ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-26 18:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 26/01/18 14:28, Marc Zyngier wrote:
> As we're about to update the PSCI support, and because I'm lazy,
> let's move the PSCI include file to include/kvm so that both
> ARM architectures can find it.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/include/asm/psci.h                        | 25 ----------------------
>  arch/arm/kvm/handle_exit.c                         |  2 +-
>  arch/arm64/kvm/handle_exit.c                       |  3 ++-
>  .../asm/kvm_psci.h => include/kvm/arm_psci.h       |  6 +++---
>  virt/kvm/arm/arm.c                                 |  2 +-
>  virt/kvm/arm/psci.c                                |  3 ++-
>  6 files changed, 9 insertions(+), 32 deletions(-)
>  delete mode 100644 arch/arm/include/asm/psci.h
>  rename arch/arm64/include/asm/kvm_psci.h => include/kvm/arm_psci.h (89%)
> 
> diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
> deleted file mode 100644
> index e1b825dfab23..000000000000
> --- a/arch/arm/include/asm/psci.h
> +++ /dev/null
> @@ -1,25 +0,0 @@
> -/*
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - *
> - * Copyright (C) 2012 ARM Limited
> - */
> -
> -#ifndef __ASM_ARM_PSCI_H
> -#define __ASM_ARM_PSCI_H
> -
> -extern const struct smp_operations psci_smp_ops;
> -
> -#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
> -bool psci_smp_available(void);
> -#else
> -static inline bool psci_smp_available(void) { return false; }
> -#endif
> -
> -#endif /* __ASM_ARM_PSCI_H */

Doh. I deleted the wrong file. That was supposed to be kvm_psci.h, and
not psci.h. Not sure how I managed that one...

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-26 14:28   ` Marc Zyngier
@ 2018-01-28 23:08     ` Ard Biesheuvel
  -1 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-28 23:08 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Linux Kernel Mailing List, linux-arm-kernel, kvmarm,
	Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
> It is lovely. Really.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 90 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
> index 76225c2611ea..add7e08a018d 100644
> --- a/arch/arm64/kernel/bpi.S
> +++ b/arch/arm64/kernel/bpi.S
> @@ -17,6 +17,7 @@
>   */
>
>  #include <linux/linkage.h>
> +#include <linux/arm-smccc.h>
>
>  .macro ventry target
>         .rept 31
> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>         .endr
>         ldp     x29, x30, [sp], #16
>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
> +
> +.macro smccc_workaround_1 inst
> +       sub     sp, sp, #(8 * 4)
> +       stp     x2, x3, [sp, #(16 * 0)]
> +       stp     x0, x1, [sp, #(16 * 1)]
> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
> +       \inst   #0
> +       ldp     x2, x3, [sp, #(16 * 0)]
> +       ldp     x0, x1, [sp, #(16 * 1)]
> +       add     sp, sp, #(8 * 4)
> +.endm
> +
> +ENTRY(__smccc_workaround_1_smc_start)
> +       smccc_workaround_1      smc
> +ENTRY(__smccc_workaround_1_smc_end)
> +
> +ENTRY(__smccc_workaround_1_hvc_start)
> +       smccc_workaround_1      hvc
> +ENTRY(__smccc_workaround_1_hvc_end)
> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index ed6881882231..f1501873f2e4 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>  extern char __qcom_hyp_sanitize_link_stack_start[];
>  extern char __qcom_hyp_sanitize_link_stack_end[];
> +extern char __smccc_workaround_1_smc_start[];
> +extern char __smccc_workaround_1_smc_end[];
> +extern char __smccc_workaround_1_hvc_start[];
> +extern char __smccc_workaround_1_hvc_end[];
>
>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>                                 const char *hyp_vecs_end)
> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>  #define __psci_hyp_bp_inval_end                        NULL
>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>  #define __qcom_hyp_sanitize_link_stack_end     NULL
> +#define __smccc_workaround_1_smc_start         NULL
> +#define __smccc_workaround_1_smc_end           NULL
> +#define __smccc_workaround_1_hvc_start         NULL
> +#define __smccc_workaround_1_hvc_end           NULL
>
>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>                                       const char *hyp_vecs_start,
> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>  }
>
> +#include <uapi/linux/psci.h>
> +#include <linux/arm-smccc.h>
>  #include <linux/psci.h>
>
> +static void call_smc_arch_workaround_1(void)
> +{
> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +       asm volatile("smc       #0\n"
> +                    : "+r" (w0));
> +}
> +
> +static void call_hvc_arch_workaround_1(void)
> +{
> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +       asm volatile("hvc       #0\n"
> +                    : "+r" (w0));
> +}
> +
> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
> +{
> +       bp_hardening_cb_t cb;
> +       void *smccc_start, *smccc_end;
> +       struct arm_smccc_res res;
> +
> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
> +               return false;
> +
> +       switch (psci_ops.conduit) {
> +       case PSCI_CONDUIT_HVC:
> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +                             &res);
> +               if (res.a0)
> +                       return false;
> +               cb = call_hvc_arch_workaround_1;
> +               smccc_start = __smccc_workaround_1_hvc_start;
> +               smccc_end = __smccc_workaround_1_hvc_end;
> +               break;
> +
> +       case PSCI_CONDUIT_SMC:
> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +                             &res);

This compiles to

 4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
 4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
 4b0:   d2800007        mov     x7, #0x0                        // #0
 4b4:   d2800006        mov     x6, #0x0                        // #0
 4b8:   d2800005        mov     x5, #0x0                        // #0
 4bc:   d2800004        mov     x4, #0x0                        // #0
 4c0:   d2800003        mov     x3, #0x0                        // #0
 4c4:   d2800002        mov     x2, #0x0                        // #0
 4c8:   f2b00001        movk    x1, #0x8000, lsl #16
 4cc:   94000000        bl      0 <__arm_smccc_smc>

so it seems we're missing a UL suffix somewhere.

Also, adding some printks here reveals that this function is called 32
times in total, i.e., 4 times per CPU on my Overdrive. This is with
the patches applied onto v4.15-rc9, so perhaps the rework takes care
of this?


> +               if (res.a0)
> +                       return false;
> +               cb = call_smc_arch_workaround_1;
> +               smccc_start = __smccc_workaround_1_smc_start;
> +               smccc_end = __smccc_workaround_1_smc_end;
> +               break;
> +
> +       default:
> +               return false;
> +       }
> +
> +       install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
> +
> +       return true;
> +}
> +
>  static int enable_psci_bp_hardening(void *data)
>  {
>         const struct arm64_cpu_capabilities *entry = data;
>
> -       if (psci_ops.get_version)
> +       if (psci_ops.get_version) {
> +               if (check_smccc_arch_workaround_1(entry))
> +                       return 0;
> +
>                 install_bp_hardening_cb(entry,
>                                        (bp_hardening_cb_t)psci_ops.get_version,
>                                        __psci_hyp_bp_inval_start,
>                                        __psci_hyp_bp_inval_end);
> +       }
>
>         return 0;
>  }
> --
> 2.14.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-28 23:08     ` Ard Biesheuvel
  0 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-28 23:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
> It is lovely. Really.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 90 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
> index 76225c2611ea..add7e08a018d 100644
> --- a/arch/arm64/kernel/bpi.S
> +++ b/arch/arm64/kernel/bpi.S
> @@ -17,6 +17,7 @@
>   */
>
>  #include <linux/linkage.h>
> +#include <linux/arm-smccc.h>
>
>  .macro ventry target
>         .rept 31
> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>         .endr
>         ldp     x29, x30, [sp], #16
>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
> +
> +.macro smccc_workaround_1 inst
> +       sub     sp, sp, #(8 * 4)
> +       stp     x2, x3, [sp, #(16 * 0)]
> +       stp     x0, x1, [sp, #(16 * 1)]
> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
> +       \inst   #0
> +       ldp     x2, x3, [sp, #(16 * 0)]
> +       ldp     x0, x1, [sp, #(16 * 1)]
> +       add     sp, sp, #(8 * 4)
> +.endm
> +
> +ENTRY(__smccc_workaround_1_smc_start)
> +       smccc_workaround_1      smc
> +ENTRY(__smccc_workaround_1_smc_end)
> +
> +ENTRY(__smccc_workaround_1_hvc_start)
> +       smccc_workaround_1      hvc
> +ENTRY(__smccc_workaround_1_hvc_end)
> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index ed6881882231..f1501873f2e4 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>  extern char __qcom_hyp_sanitize_link_stack_start[];
>  extern char __qcom_hyp_sanitize_link_stack_end[];
> +extern char __smccc_workaround_1_smc_start[];
> +extern char __smccc_workaround_1_smc_end[];
> +extern char __smccc_workaround_1_hvc_start[];
> +extern char __smccc_workaround_1_hvc_end[];
>
>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>                                 const char *hyp_vecs_end)
> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>  #define __psci_hyp_bp_inval_end                        NULL
>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>  #define __qcom_hyp_sanitize_link_stack_end     NULL
> +#define __smccc_workaround_1_smc_start         NULL
> +#define __smccc_workaround_1_smc_end           NULL
> +#define __smccc_workaround_1_hvc_start         NULL
> +#define __smccc_workaround_1_hvc_end           NULL
>
>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>                                       const char *hyp_vecs_start,
> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>  }
>
> +#include <uapi/linux/psci.h>
> +#include <linux/arm-smccc.h>
>  #include <linux/psci.h>
>
> +static void call_smc_arch_workaround_1(void)
> +{
> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +       asm volatile("smc       #0\n"
> +                    : "+r" (w0));
> +}
> +
> +static void call_hvc_arch_workaround_1(void)
> +{
> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
> +       asm volatile("hvc       #0\n"
> +                    : "+r" (w0));
> +}
> +
> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
> +{
> +       bp_hardening_cb_t cb;
> +       void *smccc_start, *smccc_end;
> +       struct arm_smccc_res res;
> +
> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
> +               return false;
> +
> +       switch (psci_ops.conduit) {
> +       case PSCI_CONDUIT_HVC:
> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +                             &res);
> +               if (res.a0)
> +                       return false;
> +               cb = call_hvc_arch_workaround_1;
> +               smccc_start = __smccc_workaround_1_hvc_start;
> +               smccc_end = __smccc_workaround_1_hvc_end;
> +               break;
> +
> +       case PSCI_CONDUIT_SMC:
> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
> +                             &res);

This compiles to

 4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
 4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
 4b0:   d2800007        mov     x7, #0x0                        // #0
 4b4:   d2800006        mov     x6, #0x0                        // #0
 4b8:   d2800005        mov     x5, #0x0                        // #0
 4bc:   d2800004        mov     x4, #0x0                        // #0
 4c0:   d2800003        mov     x3, #0x0                        // #0
 4c4:   d2800002        mov     x2, #0x0                        // #0
 4c8:   f2b00001        movk    x1, #0x8000, lsl #16
 4cc:   94000000        bl      0 <__arm_smccc_smc>

so it seems we're missing a UL suffix somewhere.

Also, adding some printks here reveals that this function is called 32
times in total, i.e., 4 times per CPU on my Overdrive. This is with
the patches applied onto v4.15-rc9, so perhaps the rework takes care
of this?


> +               if (res.a0)
> +                       return false;
> +               cb = call_smc_arch_workaround_1;
> +               smccc_start = __smccc_workaround_1_smc_start;
> +               smccc_end = __smccc_workaround_1_smc_end;
> +               break;
> +
> +       default:
> +               return false;
> +       }
> +
> +       install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
> +
> +       return true;
> +}
> +
>  static int enable_psci_bp_hardening(void *data)
>  {
>         const struct arm64_cpu_capabilities *entry = data;
>
> -       if (psci_ops.get_version)
> +       if (psci_ops.get_version) {
> +               if (check_smccc_arch_workaround_1(entry))
> +                       return 0;
> +
>                 install_bp_hardening_cb(entry,
>                                        (bp_hardening_cb_t)psci_ops.get_version,
>                                        __psci_hyp_bp_inval_start,
>                                        __psci_hyp_bp_inval_end);
> +       }
>
>         return 0;
>  }
> --
> 2.14.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-28 23:08     ` Ard Biesheuvel
@ 2018-01-29  9:36       ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-29  9:36 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Linux Kernel Mailing List, linux-arm-kernel, kvmarm,
	Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 28/01/18 23:08, Ard Biesheuvel wrote:
> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>> It is lovely. Really.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 90 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>> index 76225c2611ea..add7e08a018d 100644
>> --- a/arch/arm64/kernel/bpi.S
>> +++ b/arch/arm64/kernel/bpi.S
>> @@ -17,6 +17,7 @@
>>   */
>>
>>  #include <linux/linkage.h>
>> +#include <linux/arm-smccc.h>
>>
>>  .macro ventry target
>>         .rept 31
>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>         .endr
>>         ldp     x29, x30, [sp], #16
>>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
>> +
>> +.macro smccc_workaround_1 inst
>> +       sub     sp, sp, #(8 * 4)
>> +       stp     x2, x3, [sp, #(16 * 0)]
>> +       stp     x0, x1, [sp, #(16 * 1)]
>> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
>> +       \inst   #0
>> +       ldp     x2, x3, [sp, #(16 * 0)]
>> +       ldp     x0, x1, [sp, #(16 * 1)]
>> +       add     sp, sp, #(8 * 4)
>> +.endm
>> +
>> +ENTRY(__smccc_workaround_1_smc_start)
>> +       smccc_workaround_1      smc
>> +ENTRY(__smccc_workaround_1_smc_end)
>> +
>> +ENTRY(__smccc_workaround_1_hvc_start)
>> +       smccc_workaround_1      hvc
>> +ENTRY(__smccc_workaround_1_hvc_end)
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index ed6881882231..f1501873f2e4 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>  extern char __qcom_hyp_sanitize_link_stack_start[];
>>  extern char __qcom_hyp_sanitize_link_stack_end[];
>> +extern char __smccc_workaround_1_smc_start[];
>> +extern char __smccc_workaround_1_smc_end[];
>> +extern char __smccc_workaround_1_hvc_start[];
>> +extern char __smccc_workaround_1_hvc_end[];
>>
>>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>                                 const char *hyp_vecs_end)
>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>  #define __psci_hyp_bp_inval_end                        NULL
>>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>>  #define __qcom_hyp_sanitize_link_stack_end     NULL
>> +#define __smccc_workaround_1_smc_start         NULL
>> +#define __smccc_workaround_1_smc_end           NULL
>> +#define __smccc_workaround_1_hvc_start         NULL
>> +#define __smccc_workaround_1_hvc_end           NULL
>>
>>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>                                       const char *hyp_vecs_start,
>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>  }
>>
>> +#include <uapi/linux/psci.h>
>> +#include <linux/arm-smccc.h>
>>  #include <linux/psci.h>
>>
>> +static void call_smc_arch_workaround_1(void)
>> +{
>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>> +       asm volatile("smc       #0\n"
>> +                    : "+r" (w0));
>> +}
>> +
>> +static void call_hvc_arch_workaround_1(void)
>> +{
>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>> +       asm volatile("hvc       #0\n"
>> +                    : "+r" (w0));
>> +}
>> +
>> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
>> +{
>> +       bp_hardening_cb_t cb;
>> +       void *smccc_start, *smccc_end;
>> +       struct arm_smccc_res res;
>> +
>> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
>> +               return false;
>> +
>> +       switch (psci_ops.conduit) {
>> +       case PSCI_CONDUIT_HVC:
>> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>> +                             &res);
>> +               if (res.a0)
>> +                       return false;
>> +               cb = call_hvc_arch_workaround_1;
>> +               smccc_start = __smccc_workaround_1_hvc_start;
>> +               smccc_end = __smccc_workaround_1_hvc_end;
>> +               break;
>> +
>> +       case PSCI_CONDUIT_SMC:
>> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>> +                             &res);
> 
> This compiles to
> 
>  4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
>  4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
>  4b0:   d2800007        mov     x7, #0x0                        // #0
>  4b4:   d2800006        mov     x6, #0x0                        // #0
>  4b8:   d2800005        mov     x5, #0x0                        // #0
>  4bc:   d2800004        mov     x4, #0x0                        // #0
>  4c0:   d2800003        mov     x3, #0x0                        // #0
>  4c4:   d2800002        mov     x2, #0x0                        // #0
>  4c8:   f2b00001        movk    x1, #0x8000, lsl #16
>  4cc:   94000000        bl      0 <__arm_smccc_smc>
> 
> so it seems we're missing a UL suffix somewhere.

Yeah, this seems to stem from ARM_SMCCC_FAST_CALL, which is bit 31 and
isn't advertised as unsigned. It still works because both x0 and x1 are
used as 32bit quantities in this particular SMC context, but that has
the potential of triggering unexpected behaviours in broken implementations.

I'll have a look at it.

> Also, adding some printks here reveals that this function is called 32
> times in total, i.e., 4 times per CPU on my Overdrive. This is with
> the patches applied onto v4.15-rc9, so perhaps the rework takes care
> of this?

There is some ugly explosion in the number of callbacks as all of the
various implementations all share the same capability number. We can
take a shortcut and do an MIDR check early instead of late though.

But Suzuki is also reworking some of this, so I'll have a check with him.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-29  9:36       ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-29  9:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 28/01/18 23:08, Ard Biesheuvel wrote:
> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>> It is lovely. Really.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 90 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>> index 76225c2611ea..add7e08a018d 100644
>> --- a/arch/arm64/kernel/bpi.S
>> +++ b/arch/arm64/kernel/bpi.S
>> @@ -17,6 +17,7 @@
>>   */
>>
>>  #include <linux/linkage.h>
>> +#include <linux/arm-smccc.h>
>>
>>  .macro ventry target
>>         .rept 31
>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>         .endr
>>         ldp     x29, x30, [sp], #16
>>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
>> +
>> +.macro smccc_workaround_1 inst
>> +       sub     sp, sp, #(8 * 4)
>> +       stp     x2, x3, [sp, #(16 * 0)]
>> +       stp     x0, x1, [sp, #(16 * 1)]
>> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
>> +       \inst   #0
>> +       ldp     x2, x3, [sp, #(16 * 0)]
>> +       ldp     x0, x1, [sp, #(16 * 1)]
>> +       add     sp, sp, #(8 * 4)
>> +.endm
>> +
>> +ENTRY(__smccc_workaround_1_smc_start)
>> +       smccc_workaround_1      smc
>> +ENTRY(__smccc_workaround_1_smc_end)
>> +
>> +ENTRY(__smccc_workaround_1_hvc_start)
>> +       smccc_workaround_1      hvc
>> +ENTRY(__smccc_workaround_1_hvc_end)
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index ed6881882231..f1501873f2e4 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>  extern char __qcom_hyp_sanitize_link_stack_start[];
>>  extern char __qcom_hyp_sanitize_link_stack_end[];
>> +extern char __smccc_workaround_1_smc_start[];
>> +extern char __smccc_workaround_1_smc_end[];
>> +extern char __smccc_workaround_1_hvc_start[];
>> +extern char __smccc_workaround_1_hvc_end[];
>>
>>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>                                 const char *hyp_vecs_end)
>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>  #define __psci_hyp_bp_inval_end                        NULL
>>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>>  #define __qcom_hyp_sanitize_link_stack_end     NULL
>> +#define __smccc_workaround_1_smc_start         NULL
>> +#define __smccc_workaround_1_smc_end           NULL
>> +#define __smccc_workaround_1_hvc_start         NULL
>> +#define __smccc_workaround_1_hvc_end           NULL
>>
>>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>                                       const char *hyp_vecs_start,
>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>  }
>>
>> +#include <uapi/linux/psci.h>
>> +#include <linux/arm-smccc.h>
>>  #include <linux/psci.h>
>>
>> +static void call_smc_arch_workaround_1(void)
>> +{
>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>> +       asm volatile("smc       #0\n"
>> +                    : "+r" (w0));
>> +}
>> +
>> +static void call_hvc_arch_workaround_1(void)
>> +{
>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>> +       asm volatile("hvc       #0\n"
>> +                    : "+r" (w0));
>> +}
>> +
>> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
>> +{
>> +       bp_hardening_cb_t cb;
>> +       void *smccc_start, *smccc_end;
>> +       struct arm_smccc_res res;
>> +
>> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
>> +               return false;
>> +
>> +       switch (psci_ops.conduit) {
>> +       case PSCI_CONDUIT_HVC:
>> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>> +                             &res);
>> +               if (res.a0)
>> +                       return false;
>> +               cb = call_hvc_arch_workaround_1;
>> +               smccc_start = __smccc_workaround_1_hvc_start;
>> +               smccc_end = __smccc_workaround_1_hvc_end;
>> +               break;
>> +
>> +       case PSCI_CONDUIT_SMC:
>> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>> +                             &res);
> 
> This compiles to
> 
>  4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
>  4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
>  4b0:   d2800007        mov     x7, #0x0                        // #0
>  4b4:   d2800006        mov     x6, #0x0                        // #0
>  4b8:   d2800005        mov     x5, #0x0                        // #0
>  4bc:   d2800004        mov     x4, #0x0                        // #0
>  4c0:   d2800003        mov     x3, #0x0                        // #0
>  4c4:   d2800002        mov     x2, #0x0                        // #0
>  4c8:   f2b00001        movk    x1, #0x8000, lsl #16
>  4cc:   94000000        bl      0 <__arm_smccc_smc>
> 
> so it seems we're missing a UL suffix somewhere.

Yeah, this seems to stem from ARM_SMCCC_FAST_CALL, which is bit 31 and
isn't advertised as unsigned. It still works because both x0 and x1 are
used as 32bit quantities in this particular SMC context, but that has
the potential of triggering unexpected behaviours in broken implementations.

I'll have a look at it.

> Also, adding some printks here reveals that this function is called 32
> times in total, i.e., 4 times per CPU on my Overdrive. This is with
> the patches applied onto v4.15-rc9, so perhaps the rework takes care
> of this?

There is some ugly explosion in the number of callbacks as all of the
various implementations all share the same capability number. We can
take a shortcut and do an MIDR check early instead of late though.

But Suzuki is also reworking some of this, so I'll have a check with him.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-29  9:36       ` Marc Zyngier
@ 2018-01-29  9:42         ` Ard Biesheuvel
  -1 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29  9:42 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Linux Kernel Mailing List, linux-arm-kernel, kvmarm,
	Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 29 January 2018 at 09:36, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 28/01/18 23:08, Ard Biesheuvel wrote:
>> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>>> It is lovely. Really.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> ---
>>>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>>  2 files changed, 90 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>>> index 76225c2611ea..add7e08a018d 100644
>>> --- a/arch/arm64/kernel/bpi.S
>>> +++ b/arch/arm64/kernel/bpi.S
>>> @@ -17,6 +17,7 @@
>>>   */
>>>
>>>  #include <linux/linkage.h>
>>> +#include <linux/arm-smccc.h>
>>>
>>>  .macro ventry target
>>>         .rept 31
>>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>>         .endr
>>>         ldp     x29, x30, [sp], #16
>>>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
>>> +
>>> +.macro smccc_workaround_1 inst
>>> +       sub     sp, sp, #(8 * 4)
>>> +       stp     x2, x3, [sp, #(16 * 0)]
>>> +       stp     x0, x1, [sp, #(16 * 1)]
>>> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
>>> +       \inst   #0
>>> +       ldp     x2, x3, [sp, #(16 * 0)]
>>> +       ldp     x0, x1, [sp, #(16 * 1)]
>>> +       add     sp, sp, #(8 * 4)
>>> +.endm
>>> +
>>> +ENTRY(__smccc_workaround_1_smc_start)
>>> +       smccc_workaround_1      smc
>>> +ENTRY(__smccc_workaround_1_smc_end)
>>> +
>>> +ENTRY(__smccc_workaround_1_hvc_start)
>>> +       smccc_workaround_1      hvc
>>> +ENTRY(__smccc_workaround_1_hvc_end)
>>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>>> index ed6881882231..f1501873f2e4 100644
>>> --- a/arch/arm64/kernel/cpu_errata.c
>>> +++ b/arch/arm64/kernel/cpu_errata.c
>>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>>  extern char __qcom_hyp_sanitize_link_stack_start[];
>>>  extern char __qcom_hyp_sanitize_link_stack_end[];
>>> +extern char __smccc_workaround_1_smc_start[];
>>> +extern char __smccc_workaround_1_smc_end[];
>>> +extern char __smccc_workaround_1_hvc_start[];
>>> +extern char __smccc_workaround_1_hvc_end[];
>>>
>>>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>>                                 const char *hyp_vecs_end)
>>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>  #define __psci_hyp_bp_inval_end                        NULL
>>>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>>>  #define __qcom_hyp_sanitize_link_stack_end     NULL
>>> +#define __smccc_workaround_1_smc_start         NULL
>>> +#define __smccc_workaround_1_smc_end           NULL
>>> +#define __smccc_workaround_1_hvc_start         NULL
>>> +#define __smccc_workaround_1_hvc_end           NULL
>>>
>>>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>                                       const char *hyp_vecs_start,
>>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>>  }
>>>
>>> +#include <uapi/linux/psci.h>
>>> +#include <linux/arm-smccc.h>
>>>  #include <linux/psci.h>
>>>
>>> +static void call_smc_arch_workaround_1(void)
>>> +{
>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>> +       asm volatile("smc       #0\n"
>>> +                    : "+r" (w0));
>>> +}
>>> +
>>> +static void call_hvc_arch_workaround_1(void)
>>> +{
>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>> +       asm volatile("hvc       #0\n"
>>> +                    : "+r" (w0));
>>> +}
>>> +
>>> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
>>> +{
>>> +       bp_hardening_cb_t cb;
>>> +       void *smccc_start, *smccc_end;
>>> +       struct arm_smccc_res res;
>>> +
>>> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
>>> +               return false;
>>> +
>>> +       switch (psci_ops.conduit) {
>>> +       case PSCI_CONDUIT_HVC:
>>> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>> +                             &res);
>>> +               if (res.a0)
>>> +                       return false;
>>> +               cb = call_hvc_arch_workaround_1;
>>> +               smccc_start = __smccc_workaround_1_hvc_start;
>>> +               smccc_end = __smccc_workaround_1_hvc_end;
>>> +               break;
>>> +
>>> +       case PSCI_CONDUIT_SMC:
>>> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>> +                             &res);
>>
>> This compiles to
>>
>>  4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
>>  4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
>>  4b0:   d2800007        mov     x7, #0x0                        // #0
>>  4b4:   d2800006        mov     x6, #0x0                        // #0
>>  4b8:   d2800005        mov     x5, #0x0                        // #0
>>  4bc:   d2800004        mov     x4, #0x0                        // #0
>>  4c0:   d2800003        mov     x3, #0x0                        // #0
>>  4c4:   d2800002        mov     x2, #0x0                        // #0
>>  4c8:   f2b00001        movk    x1, #0x8000, lsl #16
>>  4cc:   94000000        bl      0 <__arm_smccc_smc>
>>
>> so it seems we're missing a UL suffix somewhere.
>
> Yeah, this seems to stem from ARM_SMCCC_FAST_CALL, which is bit 31 and
> isn't advertised as unsigned. It still works because both x0 and x1 are
> used as 32bit quantities in this particular SMC context, but that has
> the potential of triggering unexpected behaviours in broken implementations.
>

Are you sure about that? To me, it looks like this code

static int32_t smccc_arch_features(u_register_t arg)
{
    switch (arg) {
    case SMCCC_VERSION:
    case SMCCC_ARCH_FEATURES:
        return SMC_OK;
#if WORKAROUND_CVE_2017_5715
    case SMCCC_ARCH_WORKAROUND_1:
        return SMC_OK;
#endif
    default:
        return SMC_UNK;
    }
}

will end up comparing 0xffffffff80008000 to 0x80008000, and fail
(which is what it did when I tried it)



>> Also, adding some printks here reveals that this function is called 32
>> times in total, i.e., 4 times per CPU on my Overdrive. This is with
>> the patches applied onto v4.15-rc9, so perhaps the rework takes care
>> of this?
>
> There is some ugly explosion in the number of callbacks as all of the
> various implementations all share the same capability number. We can
> take a shortcut and do an MIDR check early instead of late though.
>
> But Suzuki is also reworking some of this, so I'll have a check with him.
>
> Thanks,
>
>         M.
> --
> Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-29  9:42         ` Ard Biesheuvel
  0 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29  9:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 29 January 2018 at 09:36, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 28/01/18 23:08, Ard Biesheuvel wrote:
>> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>>> It is lovely. Really.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> ---
>>>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>>  2 files changed, 90 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>>> index 76225c2611ea..add7e08a018d 100644
>>> --- a/arch/arm64/kernel/bpi.S
>>> +++ b/arch/arm64/kernel/bpi.S
>>> @@ -17,6 +17,7 @@
>>>   */
>>>
>>>  #include <linux/linkage.h>
>>> +#include <linux/arm-smccc.h>
>>>
>>>  .macro ventry target
>>>         .rept 31
>>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>>         .endr
>>>         ldp     x29, x30, [sp], #16
>>>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
>>> +
>>> +.macro smccc_workaround_1 inst
>>> +       sub     sp, sp, #(8 * 4)
>>> +       stp     x2, x3, [sp, #(16 * 0)]
>>> +       stp     x0, x1, [sp, #(16 * 1)]
>>> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
>>> +       \inst   #0
>>> +       ldp     x2, x3, [sp, #(16 * 0)]
>>> +       ldp     x0, x1, [sp, #(16 * 1)]
>>> +       add     sp, sp, #(8 * 4)
>>> +.endm
>>> +
>>> +ENTRY(__smccc_workaround_1_smc_start)
>>> +       smccc_workaround_1      smc
>>> +ENTRY(__smccc_workaround_1_smc_end)
>>> +
>>> +ENTRY(__smccc_workaround_1_hvc_start)
>>> +       smccc_workaround_1      hvc
>>> +ENTRY(__smccc_workaround_1_hvc_end)
>>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>>> index ed6881882231..f1501873f2e4 100644
>>> --- a/arch/arm64/kernel/cpu_errata.c
>>> +++ b/arch/arm64/kernel/cpu_errata.c
>>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>>  extern char __qcom_hyp_sanitize_link_stack_start[];
>>>  extern char __qcom_hyp_sanitize_link_stack_end[];
>>> +extern char __smccc_workaround_1_smc_start[];
>>> +extern char __smccc_workaround_1_smc_end[];
>>> +extern char __smccc_workaround_1_hvc_start[];
>>> +extern char __smccc_workaround_1_hvc_end[];
>>>
>>>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>>                                 const char *hyp_vecs_end)
>>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>  #define __psci_hyp_bp_inval_end                        NULL
>>>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>>>  #define __qcom_hyp_sanitize_link_stack_end     NULL
>>> +#define __smccc_workaround_1_smc_start         NULL
>>> +#define __smccc_workaround_1_smc_end           NULL
>>> +#define __smccc_workaround_1_hvc_start         NULL
>>> +#define __smccc_workaround_1_hvc_end           NULL
>>>
>>>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>                                       const char *hyp_vecs_start,
>>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>>  }
>>>
>>> +#include <uapi/linux/psci.h>
>>> +#include <linux/arm-smccc.h>
>>>  #include <linux/psci.h>
>>>
>>> +static void call_smc_arch_workaround_1(void)
>>> +{
>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>> +       asm volatile("smc       #0\n"
>>> +                    : "+r" (w0));
>>> +}
>>> +
>>> +static void call_hvc_arch_workaround_1(void)
>>> +{
>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>> +       asm volatile("hvc       #0\n"
>>> +                    : "+r" (w0));
>>> +}
>>> +
>>> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
>>> +{
>>> +       bp_hardening_cb_t cb;
>>> +       void *smccc_start, *smccc_end;
>>> +       struct arm_smccc_res res;
>>> +
>>> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
>>> +               return false;
>>> +
>>> +       switch (psci_ops.conduit) {
>>> +       case PSCI_CONDUIT_HVC:
>>> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>> +                             &res);
>>> +               if (res.a0)
>>> +                       return false;
>>> +               cb = call_hvc_arch_workaround_1;
>>> +               smccc_start = __smccc_workaround_1_hvc_start;
>>> +               smccc_end = __smccc_workaround_1_hvc_end;
>>> +               break;
>>> +
>>> +       case PSCI_CONDUIT_SMC:
>>> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>> +                             &res);
>>
>> This compiles to
>>
>>  4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
>>  4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
>>  4b0:   d2800007        mov     x7, #0x0                        // #0
>>  4b4:   d2800006        mov     x6, #0x0                        // #0
>>  4b8:   d2800005        mov     x5, #0x0                        // #0
>>  4bc:   d2800004        mov     x4, #0x0                        // #0
>>  4c0:   d2800003        mov     x3, #0x0                        // #0
>>  4c4:   d2800002        mov     x2, #0x0                        // #0
>>  4c8:   f2b00001        movk    x1, #0x8000, lsl #16
>>  4cc:   94000000        bl      0 <__arm_smccc_smc>
>>
>> so it seems we're missing a UL suffix somewhere.
>
> Yeah, this seems to stem from ARM_SMCCC_FAST_CALL, which is bit 31 and
> isn't advertised as unsigned. It still works because both x0 and x1 are
> used as 32bit quantities in this particular SMC context, but that has
> the potential of triggering unexpected behaviours in broken implementations.
>

Are you sure about that? To me, it looks like this code

static int32_t smccc_arch_features(u_register_t arg)
{
    switch (arg) {
    case SMCCC_VERSION:
    case SMCCC_ARCH_FEATURES:
        return SMC_OK;
#if WORKAROUND_CVE_2017_5715
    case SMCCC_ARCH_WORKAROUND_1:
        return SMC_OK;
#endif
    default:
        return SMC_UNK;
    }
}

will end up comparing 0xffffffff80008000 to 0x80008000, and fail
(which is what it did when I tried it)



>> Also, adding some printks here reveals that this function is called 32
>> times in total, i.e., 4 times per CPU on my Overdrive. This is with
>> the patches applied onto v4.15-rc9, so perhaps the rework takes care
>> of this?
>
> There is some ugly explosion in the number of callbacks as all of the
> various implementations all share the same capability number. We can
> take a shortcut and do an MIDR check early instead of late though.
>
> But Suzuki is also reworking some of this, so I'll have a check with him.
>
> Thanks,
>
>         M.
> --
> Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 13/14] firmware/psci: Expose SMCCC version through psci_ops
  2018-01-26 14:28   ` Marc Zyngier
  (?)
@ 2018-01-29 10:03     ` Ard Biesheuvel
  -1 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29 10:03 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Linux Kernel Mailing List, linux-arm-kernel, kvmarm,
	Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
> Since PSCI 1.0 allows the SMCCC version to be (indirectly) probed,
> let's do that at boot time, and expose the version of the calling
> convention as part of the psci_ops structure.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  drivers/firmware/psci.c | 22 ++++++++++++++++++++++
>  include/linux/psci.h    |  6 ++++++
>  2 files changed, 28 insertions(+)
>
> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> index 570187e5d084..b260bbf637a2 100644
> --- a/drivers/firmware/psci.c
> +++ b/drivers/firmware/psci.c
> @@ -509,6 +509,27 @@ static void __init psci_init_migrate(void)
>         pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
>  }
>
> +static void __init psci_init_smccc(u32 ver)
> +{
> +       int feature = PSCI_RET_NOT_SUPPORTED;
> +
> +       if (PSCI_VERSION_MAJOR(ver) > 1 ||
> +           (PSCI_VERSION_MAJOR(ver) == 1 && PSCI_VERSION_MINOR(ver) >= 0))

'PSCI_VERSION_MAJOR(ver) >= 1' should be sufficient here, no?

> +               feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
> +
> +       if (feature == PSCI_RET_NOT_SUPPORTED) {
> +               psci_ops.variant = SMCCC_VARIANT_1_0;
> +       } else {
> +               ver = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
> +               if (ver != ARM_SMCCC_VERSION_1_1)
> +                       psci_ops.variant = SMCCC_VARIANT_1_0;
> +               else
> +                       psci_ops.variant = SMCCC_VARIANT_1_1;
> +       }
> +
> +       pr_info("SMC Calling Convention v1.%d\n", psci_ops.variant);
> +}
> +
>  static void __init psci_0_2_set_functions(void)
>  {
>         pr_info("Using standard PSCI v0.2 function IDs\n");
> @@ -555,6 +576,7 @@ static int __init psci_probe(void)
>         psci_0_2_set_functions();
>
>         psci_init_migrate();
> +       psci_init_smccc(ver);
>
>         if (PSCI_VERSION_MAJOR(ver) >= 1) {
>                 psci_init_cpu_suspend();
> diff --git a/include/linux/psci.h b/include/linux/psci.h
> index f2679e5faa4f..83fd16a37be3 100644
> --- a/include/linux/psci.h
> +++ b/include/linux/psci.h
> @@ -31,6 +31,11 @@ enum psci_conduit {
>         PSCI_CONDUIT_HVC,
>  };
>
> +enum smccc_variant {
> +       SMCCC_VARIANT_1_0,
> +       SMCCC_VARIANT_1_1,
> +};
> +
>  struct psci_operations {
>         u32 (*get_version)(void);
>         int (*cpu_suspend)(u32 state, unsigned long entry_point);
> @@ -41,6 +46,7 @@ struct psci_operations {
>                         unsigned long lowest_affinity_level);
>         int (*migrate_info_type)(void);
>         enum psci_conduit conduit;
> +       enum smccc_variant variant;
>  };
>
>  extern struct psci_operations psci_ops;
> --
> 2.14.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 13/14] firmware/psci: Expose SMCCC version through psci_ops
@ 2018-01-29 10:03     ` Ard Biesheuvel
  0 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29 10:03 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Linux Kernel Mailing List, Christoffer Dall,
	Jon Masters, kvmarm, linux-arm-kernel

On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
> Since PSCI 1.0 allows the SMCCC version to be (indirectly) probed,
> let's do that at boot time, and expose the version of the calling
> convention as part of the psci_ops structure.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  drivers/firmware/psci.c | 22 ++++++++++++++++++++++
>  include/linux/psci.h    |  6 ++++++
>  2 files changed, 28 insertions(+)
>
> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> index 570187e5d084..b260bbf637a2 100644
> --- a/drivers/firmware/psci.c
> +++ b/drivers/firmware/psci.c
> @@ -509,6 +509,27 @@ static void __init psci_init_migrate(void)
>         pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
>  }
>
> +static void __init psci_init_smccc(u32 ver)
> +{
> +       int feature = PSCI_RET_NOT_SUPPORTED;
> +
> +       if (PSCI_VERSION_MAJOR(ver) > 1 ||
> +           (PSCI_VERSION_MAJOR(ver) == 1 && PSCI_VERSION_MINOR(ver) >= 0))

'PSCI_VERSION_MAJOR(ver) >= 1' should be sufficient here, no?

> +               feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
> +
> +       if (feature == PSCI_RET_NOT_SUPPORTED) {
> +               psci_ops.variant = SMCCC_VARIANT_1_0;
> +       } else {
> +               ver = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
> +               if (ver != ARM_SMCCC_VERSION_1_1)
> +                       psci_ops.variant = SMCCC_VARIANT_1_0;
> +               else
> +                       psci_ops.variant = SMCCC_VARIANT_1_1;
> +       }
> +
> +       pr_info("SMC Calling Convention v1.%d\n", psci_ops.variant);
> +}
> +
>  static void __init psci_0_2_set_functions(void)
>  {
>         pr_info("Using standard PSCI v0.2 function IDs\n");
> @@ -555,6 +576,7 @@ static int __init psci_probe(void)
>         psci_0_2_set_functions();
>
>         psci_init_migrate();
> +       psci_init_smccc(ver);
>
>         if (PSCI_VERSION_MAJOR(ver) >= 1) {
>                 psci_init_cpu_suspend();
> diff --git a/include/linux/psci.h b/include/linux/psci.h
> index f2679e5faa4f..83fd16a37be3 100644
> --- a/include/linux/psci.h
> +++ b/include/linux/psci.h
> @@ -31,6 +31,11 @@ enum psci_conduit {
>         PSCI_CONDUIT_HVC,
>  };
>
> +enum smccc_variant {
> +       SMCCC_VARIANT_1_0,
> +       SMCCC_VARIANT_1_1,
> +};
> +
>  struct psci_operations {
>         u32 (*get_version)(void);
>         int (*cpu_suspend)(u32 state, unsigned long entry_point);
> @@ -41,6 +46,7 @@ struct psci_operations {
>                         unsigned long lowest_affinity_level);
>         int (*migrate_info_type)(void);
>         enum psci_conduit conduit;
> +       enum smccc_variant variant;
>  };
>
>  extern struct psci_operations psci_ops;
> --
> 2.14.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 13/14] firmware/psci: Expose SMCCC version through psci_ops
@ 2018-01-29 10:03     ` Ard Biesheuvel
  0 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29 10:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
> Since PSCI 1.0 allows the SMCCC version to be (indirectly) probed,
> let's do that at boot time, and expose the version of the calling
> convention as part of the psci_ops structure.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  drivers/firmware/psci.c | 22 ++++++++++++++++++++++
>  include/linux/psci.h    |  6 ++++++
>  2 files changed, 28 insertions(+)
>
> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> index 570187e5d084..b260bbf637a2 100644
> --- a/drivers/firmware/psci.c
> +++ b/drivers/firmware/psci.c
> @@ -509,6 +509,27 @@ static void __init psci_init_migrate(void)
>         pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
>  }
>
> +static void __init psci_init_smccc(u32 ver)
> +{
> +       int feature = PSCI_RET_NOT_SUPPORTED;
> +
> +       if (PSCI_VERSION_MAJOR(ver) > 1 ||
> +           (PSCI_VERSION_MAJOR(ver) == 1 && PSCI_VERSION_MINOR(ver) >= 0))

'PSCI_VERSION_MAJOR(ver) >= 1' should be sufficient here, no?

> +               feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
> +
> +       if (feature == PSCI_RET_NOT_SUPPORTED) {
> +               psci_ops.variant = SMCCC_VARIANT_1_0;
> +       } else {
> +               ver = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
> +               if (ver != ARM_SMCCC_VERSION_1_1)
> +                       psci_ops.variant = SMCCC_VARIANT_1_0;
> +               else
> +                       psci_ops.variant = SMCCC_VARIANT_1_1;
> +       }
> +
> +       pr_info("SMC Calling Convention v1.%d\n", psci_ops.variant);
> +}
> +
>  static void __init psci_0_2_set_functions(void)
>  {
>         pr_info("Using standard PSCI v0.2 function IDs\n");
> @@ -555,6 +576,7 @@ static int __init psci_probe(void)
>         psci_0_2_set_functions();
>
>         psci_init_migrate();
> +       psci_init_smccc(ver);
>
>         if (PSCI_VERSION_MAJOR(ver) >= 1) {
>                 psci_init_cpu_suspend();
> diff --git a/include/linux/psci.h b/include/linux/psci.h
> index f2679e5faa4f..83fd16a37be3 100644
> --- a/include/linux/psci.h
> +++ b/include/linux/psci.h
> @@ -31,6 +31,11 @@ enum psci_conduit {
>         PSCI_CONDUIT_HVC,
>  };
>
> +enum smccc_variant {
> +       SMCCC_VARIANT_1_0,
> +       SMCCC_VARIANT_1_1,
> +};
> +
>  struct psci_operations {
>         u32 (*get_version)(void);
>         int (*cpu_suspend)(u32 state, unsigned long entry_point);
> @@ -41,6 +46,7 @@ struct psci_operations {
>                         unsigned long lowest_affinity_level);
>         int (*migrate_info_type)(void);
>         enum psci_conduit conduit;
> +       enum smccc_variant variant;
>  };
>
>  extern struct psci_operations psci_ops;
> --
> 2.14.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 12/14] firmware/psci: Expose PSCI conduit
  2018-01-26 14:28   ` Marc Zyngier
@ 2018-01-29 10:04     ` Ard Biesheuvel
  -1 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29 10:04 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Linux Kernel Mailing List, linux-arm-kernel, kvmarm,
	Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
> In order to call into the firmware to apply workarounds, it is
> useful to find out whether we're using HVC or SMC. Let's expose
> this through the psci_ops.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  drivers/firmware/psci.c | 26 +++++++++++++++++++++-----
>  include/linux/psci.h    |  7 +++++++
>  2 files changed, 28 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> index 8b25d31e8401..570187e5d084 100644
> --- a/drivers/firmware/psci.c
> +++ b/drivers/firmware/psci.c
> @@ -59,7 +59,9 @@ bool psci_tos_resident_on(int cpu)
>         return cpu == resident_cpu;
>  }
>
> -struct psci_operations psci_ops;
> +struct psci_operations psci_ops = {
> +       .conduit = PSCI_CONDUIT_NONE,
> +};
>
>  typedef unsigned long (psci_fn)(unsigned long, unsigned long,
>                                 unsigned long, unsigned long);
> @@ -210,6 +212,20 @@ static unsigned long psci_migrate_info_up_cpu(void)
>                               0, 0, 0);
>  }
>
> +static void set_conduit(enum psci_conduit conduit)
> +{
> +       switch (conduit) {
> +       case PSCI_CONDUIT_HVC:
> +               invoke_psci_fn = __invoke_psci_fn_hvc;
> +               break;
> +       case PSCI_CONDUIT_SMC:
> +               invoke_psci_fn = __invoke_psci_fn_smc;
> +               break;

I get a GCC warning here about PSCI_CONDUIT_NONE not being handled.

> +       }
> +
> +       psci_ops.conduit = conduit;
> +}
> +
>  static int get_set_conduit_method(struct device_node *np)
>  {
>         const char *method;
> @@ -222,9 +238,9 @@ static int get_set_conduit_method(struct device_node *np)
>         }
>
>         if (!strcmp("hvc", method)) {
> -               invoke_psci_fn = __invoke_psci_fn_hvc;
> +               set_conduit(PSCI_CONDUIT_HVC);
>         } else if (!strcmp("smc", method)) {
> -               invoke_psci_fn = __invoke_psci_fn_smc;
> +               set_conduit(PSCI_CONDUIT_SMC);
>         } else {
>                 pr_warn("invalid \"method\" property: %s\n", method);
>                 return -EINVAL;
> @@ -654,9 +670,9 @@ int __init psci_acpi_init(void)
>         pr_info("probing for conduit method from ACPI.\n");
>
>         if (acpi_psci_use_hvc())
> -               invoke_psci_fn = __invoke_psci_fn_hvc;
> +               set_conduit(PSCI_CONDUIT_HVC);
>         else
> -               invoke_psci_fn = __invoke_psci_fn_smc;
> +               set_conduit(PSCI_CONDUIT_SMC);
>
>         return psci_probe();
>  }
> diff --git a/include/linux/psci.h b/include/linux/psci.h
> index f724fd8c78e8..f2679e5faa4f 100644
> --- a/include/linux/psci.h
> +++ b/include/linux/psci.h
> @@ -25,6 +25,12 @@ bool psci_tos_resident_on(int cpu);
>  int psci_cpu_init_idle(unsigned int cpu);
>  int psci_cpu_suspend_enter(unsigned long index);
>
> +enum psci_conduit {
> +       PSCI_CONDUIT_NONE,
> +       PSCI_CONDUIT_SMC,
> +       PSCI_CONDUIT_HVC,
> +};
> +
>  struct psci_operations {
>         u32 (*get_version)(void);
>         int (*cpu_suspend)(u32 state, unsigned long entry_point);
> @@ -34,6 +40,7 @@ struct psci_operations {
>         int (*affinity_info)(unsigned long target_affinity,
>                         unsigned long lowest_affinity_level);
>         int (*migrate_info_type)(void);
> +       enum psci_conduit conduit;
>  };
>
>  extern struct psci_operations psci_ops;
> --
> 2.14.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 12/14] firmware/psci: Expose PSCI conduit
@ 2018-01-29 10:04     ` Ard Biesheuvel
  0 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
> In order to call into the firmware to apply workarounds, it is
> useful to find out whether we're using HVC or SMC. Let's expose
> this through the psci_ops.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  drivers/firmware/psci.c | 26 +++++++++++++++++++++-----
>  include/linux/psci.h    |  7 +++++++
>  2 files changed, 28 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> index 8b25d31e8401..570187e5d084 100644
> --- a/drivers/firmware/psci.c
> +++ b/drivers/firmware/psci.c
> @@ -59,7 +59,9 @@ bool psci_tos_resident_on(int cpu)
>         return cpu == resident_cpu;
>  }
>
> -struct psci_operations psci_ops;
> +struct psci_operations psci_ops = {
> +       .conduit = PSCI_CONDUIT_NONE,
> +};
>
>  typedef unsigned long (psci_fn)(unsigned long, unsigned long,
>                                 unsigned long, unsigned long);
> @@ -210,6 +212,20 @@ static unsigned long psci_migrate_info_up_cpu(void)
>                               0, 0, 0);
>  }
>
> +static void set_conduit(enum psci_conduit conduit)
> +{
> +       switch (conduit) {
> +       case PSCI_CONDUIT_HVC:
> +               invoke_psci_fn = __invoke_psci_fn_hvc;
> +               break;
> +       case PSCI_CONDUIT_SMC:
> +               invoke_psci_fn = __invoke_psci_fn_smc;
> +               break;

I get a GCC warning here about PSCI_CONDUIT_NONE not being handled.

> +       }
> +
> +       psci_ops.conduit = conduit;
> +}
> +
>  static int get_set_conduit_method(struct device_node *np)
>  {
>         const char *method;
> @@ -222,9 +238,9 @@ static int get_set_conduit_method(struct device_node *np)
>         }
>
>         if (!strcmp("hvc", method)) {
> -               invoke_psci_fn = __invoke_psci_fn_hvc;
> +               set_conduit(PSCI_CONDUIT_HVC);
>         } else if (!strcmp("smc", method)) {
> -               invoke_psci_fn = __invoke_psci_fn_smc;
> +               set_conduit(PSCI_CONDUIT_SMC);
>         } else {
>                 pr_warn("invalid \"method\" property: %s\n", method);
>                 return -EINVAL;
> @@ -654,9 +670,9 @@ int __init psci_acpi_init(void)
>         pr_info("probing for conduit method from ACPI.\n");
>
>         if (acpi_psci_use_hvc())
> -               invoke_psci_fn = __invoke_psci_fn_hvc;
> +               set_conduit(PSCI_CONDUIT_HVC);
>         else
> -               invoke_psci_fn = __invoke_psci_fn_smc;
> +               set_conduit(PSCI_CONDUIT_SMC);
>
>         return psci_probe();
>  }
> diff --git a/include/linux/psci.h b/include/linux/psci.h
> index f724fd8c78e8..f2679e5faa4f 100644
> --- a/include/linux/psci.h
> +++ b/include/linux/psci.h
> @@ -25,6 +25,12 @@ bool psci_tos_resident_on(int cpu);
>  int psci_cpu_init_idle(unsigned int cpu);
>  int psci_cpu_suspend_enter(unsigned long index);
>
> +enum psci_conduit {
> +       PSCI_CONDUIT_NONE,
> +       PSCI_CONDUIT_SMC,
> +       PSCI_CONDUIT_HVC,
> +};
> +
>  struct psci_operations {
>         u32 (*get_version)(void);
>         int (*cpu_suspend)(u32 state, unsigned long entry_point);
> @@ -34,6 +40,7 @@ struct psci_operations {
>         int (*affinity_info)(unsigned long target_affinity,
>                         unsigned long lowest_affinity_level);
>         int (*migrate_info_type)(void);
> +       enum psci_conduit conduit;
>  };
>
>  extern struct psci_operations psci_ops;
> --
> 2.14.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-29  9:42         ` Ard Biesheuvel
@ 2018-01-29 10:07           ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-29 10:07 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Linux Kernel Mailing List, linux-arm-kernel, kvmarm,
	Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 29/01/18 09:42, Ard Biesheuvel wrote:
> On 29 January 2018 at 09:36, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> On 28/01/18 23:08, Ard Biesheuvel wrote:
>>> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>>>> It is lovely. Really.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> ---
>>>>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>>>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>>>  2 files changed, 90 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>>>> index 76225c2611ea..add7e08a018d 100644
>>>> --- a/arch/arm64/kernel/bpi.S
>>>> +++ b/arch/arm64/kernel/bpi.S
>>>> @@ -17,6 +17,7 @@
>>>>   */
>>>>
>>>>  #include <linux/linkage.h>
>>>> +#include <linux/arm-smccc.h>
>>>>
>>>>  .macro ventry target
>>>>         .rept 31
>>>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>>>         .endr
>>>>         ldp     x29, x30, [sp], #16
>>>>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
>>>> +
>>>> +.macro smccc_workaround_1 inst
>>>> +       sub     sp, sp, #(8 * 4)
>>>> +       stp     x2, x3, [sp, #(16 * 0)]
>>>> +       stp     x0, x1, [sp, #(16 * 1)]
>>>> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
>>>> +       \inst   #0
>>>> +       ldp     x2, x3, [sp, #(16 * 0)]
>>>> +       ldp     x0, x1, [sp, #(16 * 1)]
>>>> +       add     sp, sp, #(8 * 4)
>>>> +.endm
>>>> +
>>>> +ENTRY(__smccc_workaround_1_smc_start)
>>>> +       smccc_workaround_1      smc
>>>> +ENTRY(__smccc_workaround_1_smc_end)
>>>> +
>>>> +ENTRY(__smccc_workaround_1_hvc_start)
>>>> +       smccc_workaround_1      hvc
>>>> +ENTRY(__smccc_workaround_1_hvc_end)
>>>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>>>> index ed6881882231..f1501873f2e4 100644
>>>> --- a/arch/arm64/kernel/cpu_errata.c
>>>> +++ b/arch/arm64/kernel/cpu_errata.c
>>>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>>>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>>>  extern char __qcom_hyp_sanitize_link_stack_start[];
>>>>  extern char __qcom_hyp_sanitize_link_stack_end[];
>>>> +extern char __smccc_workaround_1_smc_start[];
>>>> +extern char __smccc_workaround_1_smc_end[];
>>>> +extern char __smccc_workaround_1_hvc_start[];
>>>> +extern char __smccc_workaround_1_hvc_end[];
>>>>
>>>>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>>>                                 const char *hyp_vecs_end)
>>>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>>  #define __psci_hyp_bp_inval_end                        NULL
>>>>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>>>>  #define __qcom_hyp_sanitize_link_stack_end     NULL
>>>> +#define __smccc_workaround_1_smc_start         NULL
>>>> +#define __smccc_workaround_1_smc_end           NULL
>>>> +#define __smccc_workaround_1_hvc_start         NULL
>>>> +#define __smccc_workaround_1_hvc_end           NULL
>>>>
>>>>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>>                                       const char *hyp_vecs_start,
>>>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>>>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>>>  }
>>>>
>>>> +#include <uapi/linux/psci.h>
>>>> +#include <linux/arm-smccc.h>
>>>>  #include <linux/psci.h>
>>>>
>>>> +static void call_smc_arch_workaround_1(void)
>>>> +{
>>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>>> +       asm volatile("smc       #0\n"
>>>> +                    : "+r" (w0));
>>>> +}
>>>> +
>>>> +static void call_hvc_arch_workaround_1(void)
>>>> +{
>>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>>> +       asm volatile("hvc       #0\n"
>>>> +                    : "+r" (w0));
>>>> +}
>>>> +
>>>> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
>>>> +{
>>>> +       bp_hardening_cb_t cb;
>>>> +       void *smccc_start, *smccc_end;
>>>> +       struct arm_smccc_res res;
>>>> +
>>>> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
>>>> +               return false;
>>>> +
>>>> +       switch (psci_ops.conduit) {
>>>> +       case PSCI_CONDUIT_HVC:
>>>> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>>> +                             &res);
>>>> +               if (res.a0)
>>>> +                       return false;
>>>> +               cb = call_hvc_arch_workaround_1;
>>>> +               smccc_start = __smccc_workaround_1_hvc_start;
>>>> +               smccc_end = __smccc_workaround_1_hvc_end;
>>>> +               break;
>>>> +
>>>> +       case PSCI_CONDUIT_SMC:
>>>> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>>> +                             &res);
>>>
>>> This compiles to
>>>
>>>  4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
>>>  4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
>>>  4b0:   d2800007        mov     x7, #0x0                        // #0
>>>  4b4:   d2800006        mov     x6, #0x0                        // #0
>>>  4b8:   d2800005        mov     x5, #0x0                        // #0
>>>  4bc:   d2800004        mov     x4, #0x0                        // #0
>>>  4c0:   d2800003        mov     x3, #0x0                        // #0
>>>  4c4:   d2800002        mov     x2, #0x0                        // #0
>>>  4c8:   f2b00001        movk    x1, #0x8000, lsl #16
>>>  4cc:   94000000        bl      0 <__arm_smccc_smc>
>>>
>>> so it seems we're missing a UL suffix somewhere.
>>
>> Yeah, this seems to stem from ARM_SMCCC_FAST_CALL, which is bit 31 and
>> isn't advertised as unsigned. It still works because both x0 and x1 are
>> used as 32bit quantities in this particular SMC context, but that has
>> the potential of triggering unexpected behaviours in broken implementations.
>>
> 
> Are you sure about that? To me, it looks like this code
> 
> static int32_t smccc_arch_features(u_register_t arg)
> {
>     switch (arg) {
>     case SMCCC_VERSION:
>     case SMCCC_ARCH_FEATURES:
>         return SMC_OK;
> #if WORKAROUND_CVE_2017_5715
>     case SMCCC_ARCH_WORKAROUND_1:
>         return SMC_OK;
> #endif
>     default:
>         return SMC_UNK;
>     }
> }
> 
> will end up comparing 0xffffffff80008000 to 0x80008000, and fail
> (which is what it did when I tried it)

Good point. Only a0 is guaranteed to be evaluated as a 32bit register,
and parameters can be used either way. Funny how long this stayed
unnoticed. How about the patch below?

	M.

>From bbb79f54808b94c187cb1cbe56fecc0e2241576a Mon Sep 17 00:00:00 2001
From: Marc Zyngier <marc.zyngier@arm.com>
Date: Mon, 29 Jan 2018 09:48:28 +0000
Subject: [PATCH] arm/arm64: smccc: Make function identifiers an unsigned
 quantity

Function identifiers are a 32bit, unsigned quantify. But we never
tell so to the compiler, resulting in the following:

 4ac:   b26187e0        mov     x0, #0xffffffff80000001

We thus rely on the firmware narrowing it for us, which is not
always a reasonable expectation.

Cc: stable@vger.kernel.org
Reported-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/arm-smccc.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index ab1e86111953..e2af4ff772a1 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -14,14 +14,16 @@
 #ifndef __LINUX_ARM_SMCCC_H
 #define __LINUX_ARM_SMCCC_H
 
+#include <uapi/linux/const.h>
+
 /*
  * This file provides common defines for ARM SMC Calling Convention as
  * specified in
  * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
  */
 
-#define ARM_SMCCC_STD_CALL		0
-#define ARM_SMCCC_FAST_CALL		1
+#define ARM_SMCCC_STD_CALL	        _AC(0,U)
+#define ARM_SMCCC_FAST_CALL	        _AC(1,U)
 #define ARM_SMCCC_TYPE_SHIFT		31
 
 #define ARM_SMCCC_SMC_32		0
-- 
2.14.2

-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-29 10:07           ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-29 10:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/01/18 09:42, Ard Biesheuvel wrote:
> On 29 January 2018 at 09:36, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> On 28/01/18 23:08, Ard Biesheuvel wrote:
>>> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>>>> It is lovely. Really.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> ---
>>>>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>>>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>>>  2 files changed, 90 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>>>> index 76225c2611ea..add7e08a018d 100644
>>>> --- a/arch/arm64/kernel/bpi.S
>>>> +++ b/arch/arm64/kernel/bpi.S
>>>> @@ -17,6 +17,7 @@
>>>>   */
>>>>
>>>>  #include <linux/linkage.h>
>>>> +#include <linux/arm-smccc.h>
>>>>
>>>>  .macro ventry target
>>>>         .rept 31
>>>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>>>         .endr
>>>>         ldp     x29, x30, [sp], #16
>>>>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
>>>> +
>>>> +.macro smccc_workaround_1 inst
>>>> +       sub     sp, sp, #(8 * 4)
>>>> +       stp     x2, x3, [sp, #(16 * 0)]
>>>> +       stp     x0, x1, [sp, #(16 * 1)]
>>>> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
>>>> +       \inst   #0
>>>> +       ldp     x2, x3, [sp, #(16 * 0)]
>>>> +       ldp     x0, x1, [sp, #(16 * 1)]
>>>> +       add     sp, sp, #(8 * 4)
>>>> +.endm
>>>> +
>>>> +ENTRY(__smccc_workaround_1_smc_start)
>>>> +       smccc_workaround_1      smc
>>>> +ENTRY(__smccc_workaround_1_smc_end)
>>>> +
>>>> +ENTRY(__smccc_workaround_1_hvc_start)
>>>> +       smccc_workaround_1      hvc
>>>> +ENTRY(__smccc_workaround_1_hvc_end)
>>>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>>>> index ed6881882231..f1501873f2e4 100644
>>>> --- a/arch/arm64/kernel/cpu_errata.c
>>>> +++ b/arch/arm64/kernel/cpu_errata.c
>>>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>>>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>>>  extern char __qcom_hyp_sanitize_link_stack_start[];
>>>>  extern char __qcom_hyp_sanitize_link_stack_end[];
>>>> +extern char __smccc_workaround_1_smc_start[];
>>>> +extern char __smccc_workaround_1_smc_end[];
>>>> +extern char __smccc_workaround_1_hvc_start[];
>>>> +extern char __smccc_workaround_1_hvc_end[];
>>>>
>>>>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>>>                                 const char *hyp_vecs_end)
>>>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>>  #define __psci_hyp_bp_inval_end                        NULL
>>>>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>>>>  #define __qcom_hyp_sanitize_link_stack_end     NULL
>>>> +#define __smccc_workaround_1_smc_start         NULL
>>>> +#define __smccc_workaround_1_smc_end           NULL
>>>> +#define __smccc_workaround_1_hvc_start         NULL
>>>> +#define __smccc_workaround_1_hvc_end           NULL
>>>>
>>>>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>>                                       const char *hyp_vecs_start,
>>>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>>>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>>>  }
>>>>
>>>> +#include <uapi/linux/psci.h>
>>>> +#include <linux/arm-smccc.h>
>>>>  #include <linux/psci.h>
>>>>
>>>> +static void call_smc_arch_workaround_1(void)
>>>> +{
>>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>>> +       asm volatile("smc       #0\n"
>>>> +                    : "+r" (w0));
>>>> +}
>>>> +
>>>> +static void call_hvc_arch_workaround_1(void)
>>>> +{
>>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>>> +       asm volatile("hvc       #0\n"
>>>> +                    : "+r" (w0));
>>>> +}
>>>> +
>>>> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
>>>> +{
>>>> +       bp_hardening_cb_t cb;
>>>> +       void *smccc_start, *smccc_end;
>>>> +       struct arm_smccc_res res;
>>>> +
>>>> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
>>>> +               return false;
>>>> +
>>>> +       switch (psci_ops.conduit) {
>>>> +       case PSCI_CONDUIT_HVC:
>>>> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>>> +                             &res);
>>>> +               if (res.a0)
>>>> +                       return false;
>>>> +               cb = call_hvc_arch_workaround_1;
>>>> +               smccc_start = __smccc_workaround_1_hvc_start;
>>>> +               smccc_end = __smccc_workaround_1_hvc_end;
>>>> +               break;
>>>> +
>>>> +       case PSCI_CONDUIT_SMC:
>>>> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>>> +                             &res);
>>>
>>> This compiles to
>>>
>>>  4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
>>>  4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
>>>  4b0:   d2800007        mov     x7, #0x0                        // #0
>>>  4b4:   d2800006        mov     x6, #0x0                        // #0
>>>  4b8:   d2800005        mov     x5, #0x0                        // #0
>>>  4bc:   d2800004        mov     x4, #0x0                        // #0
>>>  4c0:   d2800003        mov     x3, #0x0                        // #0
>>>  4c4:   d2800002        mov     x2, #0x0                        // #0
>>>  4c8:   f2b00001        movk    x1, #0x8000, lsl #16
>>>  4cc:   94000000        bl      0 <__arm_smccc_smc>
>>>
>>> so it seems we're missing a UL suffix somewhere.
>>
>> Yeah, this seems to stem from ARM_SMCCC_FAST_CALL, which is bit 31 and
>> isn't advertised as unsigned. It still works because both x0 and x1 are
>> used as 32bit quantities in this particular SMC context, but that has
>> the potential of triggering unexpected behaviours in broken implementations.
>>
> 
> Are you sure about that? To me, it looks like this code
> 
> static int32_t smccc_arch_features(u_register_t arg)
> {
>     switch (arg) {
>     case SMCCC_VERSION:
>     case SMCCC_ARCH_FEATURES:
>         return SMC_OK;
> #if WORKAROUND_CVE_2017_5715
>     case SMCCC_ARCH_WORKAROUND_1:
>         return SMC_OK;
> #endif
>     default:
>         return SMC_UNK;
>     }
> }
> 
> will end up comparing 0xffffffff80008000 to 0x80008000, and fail
> (which is what it did when I tried it)

Good point. Only a0 is guaranteed to be evaluated as a 32bit register,
and parameters can be used either way. Funny how long this stayed
unnoticed. How about the patch below?

	M.

>From bbb79f54808b94c187cb1cbe56fecc0e2241576a Mon Sep 17 00:00:00 2001
From: Marc Zyngier <marc.zyngier@arm.com>
Date: Mon, 29 Jan 2018 09:48:28 +0000
Subject: [PATCH] arm/arm64: smccc: Make function identifiers an unsigned
 quantity

Function identifiers are a 32bit, unsigned quantify. But we never
tell so to the compiler, resulting in the following:

 4ac:   b26187e0        mov     x0, #0xffffffff80000001

We thus rely on the firmware narrowing it for us, which is not
always a reasonable expectation.

Cc: stable at vger.kernel.org
Reported-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/arm-smccc.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index ab1e86111953..e2af4ff772a1 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -14,14 +14,16 @@
 #ifndef __LINUX_ARM_SMCCC_H
 #define __LINUX_ARM_SMCCC_H
 
+#include <uapi/linux/const.h>
+
 /*
  * This file provides common defines for ARM SMC Calling Convention as
  * specified in
  * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
  */
 
-#define ARM_SMCCC_STD_CALL		0
-#define ARM_SMCCC_FAST_CALL		1
+#define ARM_SMCCC_STD_CALL	        _AC(0,U)
+#define ARM_SMCCC_FAST_CALL	        _AC(1,U)
 #define ARM_SMCCC_TYPE_SHIFT		31
 
 #define ARM_SMCCC_SMC_32		0
-- 
2.14.2

-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH 12/14] firmware/psci: Expose PSCI conduit
  2018-01-29 10:04     ` Ard Biesheuvel
@ 2018-01-29 10:08       ` Marc Zyngier
  -1 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-29 10:08 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Linux Kernel Mailing List, linux-arm-kernel, kvmarm,
	Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 29/01/18 10:04, Ard Biesheuvel wrote:
> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> In order to call into the firmware to apply workarounds, it is
>> useful to find out whether we're using HVC or SMC. Let's expose
>> this through the psci_ops.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  drivers/firmware/psci.c | 26 +++++++++++++++++++++-----
>>  include/linux/psci.h    |  7 +++++++
>>  2 files changed, 28 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
>> index 8b25d31e8401..570187e5d084 100644
>> --- a/drivers/firmware/psci.c
>> +++ b/drivers/firmware/psci.c
>> @@ -59,7 +59,9 @@ bool psci_tos_resident_on(int cpu)
>>         return cpu == resident_cpu;
>>  }
>>
>> -struct psci_operations psci_ops;
>> +struct psci_operations psci_ops = {
>> +       .conduit = PSCI_CONDUIT_NONE,
>> +};
>>
>>  typedef unsigned long (psci_fn)(unsigned long, unsigned long,
>>                                 unsigned long, unsigned long);
>> @@ -210,6 +212,20 @@ static unsigned long psci_migrate_info_up_cpu(void)
>>                               0, 0, 0);
>>  }
>>
>> +static void set_conduit(enum psci_conduit conduit)
>> +{
>> +       switch (conduit) {
>> +       case PSCI_CONDUIT_HVC:
>> +               invoke_psci_fn = __invoke_psci_fn_hvc;
>> +               break;
>> +       case PSCI_CONDUIT_SMC:
>> +               invoke_psci_fn = __invoke_psci_fn_smc;
>> +               break;
> 
> I get a GCC warning here about PSCI_CONDUIT_NONE not being handled.


Yup, I fixed it already.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 12/14] firmware/psci: Expose PSCI conduit
@ 2018-01-29 10:08       ` Marc Zyngier
  0 siblings, 0 replies; 67+ messages in thread
From: Marc Zyngier @ 2018-01-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/01/18 10:04, Ard Biesheuvel wrote:
> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> In order to call into the firmware to apply workarounds, it is
>> useful to find out whether we're using HVC or SMC. Let's expose
>> this through the psci_ops.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  drivers/firmware/psci.c | 26 +++++++++++++++++++++-----
>>  include/linux/psci.h    |  7 +++++++
>>  2 files changed, 28 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
>> index 8b25d31e8401..570187e5d084 100644
>> --- a/drivers/firmware/psci.c
>> +++ b/drivers/firmware/psci.c
>> @@ -59,7 +59,9 @@ bool psci_tos_resident_on(int cpu)
>>         return cpu == resident_cpu;
>>  }
>>
>> -struct psci_operations psci_ops;
>> +struct psci_operations psci_ops = {
>> +       .conduit = PSCI_CONDUIT_NONE,
>> +};
>>
>>  typedef unsigned long (psci_fn)(unsigned long, unsigned long,
>>                                 unsigned long, unsigned long);
>> @@ -210,6 +212,20 @@ static unsigned long psci_migrate_info_up_cpu(void)
>>                               0, 0, 0);
>>  }
>>
>> +static void set_conduit(enum psci_conduit conduit)
>> +{
>> +       switch (conduit) {
>> +       case PSCI_CONDUIT_HVC:
>> +               invoke_psci_fn = __invoke_psci_fn_hvc;
>> +               break;
>> +       case PSCI_CONDUIT_SMC:
>> +               invoke_psci_fn = __invoke_psci_fn_smc;
>> +               break;
> 
> I get a GCC warning here about PSCI_CONDUIT_NONE not being handled.


Yup, I fixed it already.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
  2018-01-29 10:07           ` Marc Zyngier
@ 2018-01-29 10:17             ` Ard Biesheuvel
  -1 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29 10:17 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Linux Kernel Mailing List, linux-arm-kernel, kvmarm,
	Mark Rutland, Peter Maydell, Lorenzo Pieralisi, Catalin Marinas,
	Will Deacon, Jon Masters, Christoffer Dall

On 29 January 2018 at 10:07, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 29/01/18 09:42, Ard Biesheuvel wrote:
>> On 29 January 2018 at 09:36, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>> On 28/01/18 23:08, Ard Biesheuvel wrote:
>>>> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>>>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>>>>> It is lovely. Really.
>>>>>
>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>> ---
>>>>>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>>>>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>>>>  2 files changed, 90 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>>>>> index 76225c2611ea..add7e08a018d 100644
>>>>> --- a/arch/arm64/kernel/bpi.S
>>>>> +++ b/arch/arm64/kernel/bpi.S
>>>>> @@ -17,6 +17,7 @@
>>>>>   */
>>>>>
>>>>>  #include <linux/linkage.h>
>>>>> +#include <linux/arm-smccc.h>
>>>>>
>>>>>  .macro ventry target
>>>>>         .rept 31
>>>>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>>>>         .endr
>>>>>         ldp     x29, x30, [sp], #16
>>>>>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
>>>>> +
>>>>> +.macro smccc_workaround_1 inst
>>>>> +       sub     sp, sp, #(8 * 4)
>>>>> +       stp     x2, x3, [sp, #(16 * 0)]
>>>>> +       stp     x0, x1, [sp, #(16 * 1)]
>>>>> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
>>>>> +       \inst   #0
>>>>> +       ldp     x2, x3, [sp, #(16 * 0)]
>>>>> +       ldp     x0, x1, [sp, #(16 * 1)]
>>>>> +       add     sp, sp, #(8 * 4)
>>>>> +.endm
>>>>> +
>>>>> +ENTRY(__smccc_workaround_1_smc_start)
>>>>> +       smccc_workaround_1      smc
>>>>> +ENTRY(__smccc_workaround_1_smc_end)
>>>>> +
>>>>> +ENTRY(__smccc_workaround_1_hvc_start)
>>>>> +       smccc_workaround_1      hvc
>>>>> +ENTRY(__smccc_workaround_1_hvc_end)
>>>>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>>>>> index ed6881882231..f1501873f2e4 100644
>>>>> --- a/arch/arm64/kernel/cpu_errata.c
>>>>> +++ b/arch/arm64/kernel/cpu_errata.c
>>>>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>>>>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>>>>  extern char __qcom_hyp_sanitize_link_stack_start[];
>>>>>  extern char __qcom_hyp_sanitize_link_stack_end[];
>>>>> +extern char __smccc_workaround_1_smc_start[];
>>>>> +extern char __smccc_workaround_1_smc_end[];
>>>>> +extern char __smccc_workaround_1_hvc_start[];
>>>>> +extern char __smccc_workaround_1_hvc_end[];
>>>>>
>>>>>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>>>>                                 const char *hyp_vecs_end)
>>>>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>>>  #define __psci_hyp_bp_inval_end                        NULL
>>>>>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>>>>>  #define __qcom_hyp_sanitize_link_stack_end     NULL
>>>>> +#define __smccc_workaround_1_smc_start         NULL
>>>>> +#define __smccc_workaround_1_smc_end           NULL
>>>>> +#define __smccc_workaround_1_hvc_start         NULL
>>>>> +#define __smccc_workaround_1_hvc_end           NULL
>>>>>
>>>>>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>>>                                       const char *hyp_vecs_start,
>>>>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>>>>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>>>>  }
>>>>>
>>>>> +#include <uapi/linux/psci.h>
>>>>> +#include <linux/arm-smccc.h>
>>>>>  #include <linux/psci.h>
>>>>>
>>>>> +static void call_smc_arch_workaround_1(void)
>>>>> +{
>>>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>>>> +       asm volatile("smc       #0\n"
>>>>> +                    : "+r" (w0));
>>>>> +}
>>>>> +
>>>>> +static void call_hvc_arch_workaround_1(void)
>>>>> +{
>>>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>>>> +       asm volatile("hvc       #0\n"
>>>>> +                    : "+r" (w0));
>>>>> +}
>>>>> +
>>>>> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
>>>>> +{
>>>>> +       bp_hardening_cb_t cb;
>>>>> +       void *smccc_start, *smccc_end;
>>>>> +       struct arm_smccc_res res;
>>>>> +
>>>>> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
>>>>> +               return false;
>>>>> +
>>>>> +       switch (psci_ops.conduit) {
>>>>> +       case PSCI_CONDUIT_HVC:
>>>>> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>>>> +                             &res);
>>>>> +               if (res.a0)
>>>>> +                       return false;
>>>>> +               cb = call_hvc_arch_workaround_1;
>>>>> +               smccc_start = __smccc_workaround_1_hvc_start;
>>>>> +               smccc_end = __smccc_workaround_1_hvc_end;
>>>>> +               break;
>>>>> +
>>>>> +       case PSCI_CONDUIT_SMC:
>>>>> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>>>> +                             &res);
>>>>
>>>> This compiles to
>>>>
>>>>  4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
>>>>  4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
>>>>  4b0:   d2800007        mov     x7, #0x0                        // #0
>>>>  4b4:   d2800006        mov     x6, #0x0                        // #0
>>>>  4b8:   d2800005        mov     x5, #0x0                        // #0
>>>>  4bc:   d2800004        mov     x4, #0x0                        // #0
>>>>  4c0:   d2800003        mov     x3, #0x0                        // #0
>>>>  4c4:   d2800002        mov     x2, #0x0                        // #0
>>>>  4c8:   f2b00001        movk    x1, #0x8000, lsl #16
>>>>  4cc:   94000000        bl      0 <__arm_smccc_smc>
>>>>
>>>> so it seems we're missing a UL suffix somewhere.
>>>
>>> Yeah, this seems to stem from ARM_SMCCC_FAST_CALL, which is bit 31 and
>>> isn't advertised as unsigned. It still works because both x0 and x1 are
>>> used as 32bit quantities in this particular SMC context, but that has
>>> the potential of triggering unexpected behaviours in broken implementations.
>>>
>>
>> Are you sure about that? To me, it looks like this code
>>
>> static int32_t smccc_arch_features(u_register_t arg)
>> {
>>     switch (arg) {
>>     case SMCCC_VERSION:
>>     case SMCCC_ARCH_FEATURES:
>>         return SMC_OK;
>> #if WORKAROUND_CVE_2017_5715
>>     case SMCCC_ARCH_WORKAROUND_1:
>>         return SMC_OK;
>> #endif
>>     default:
>>         return SMC_UNK;
>>     }
>> }
>>
>> will end up comparing 0xffffffff80008000 to 0x80008000, and fail
>> (which is what it did when I tried it)
>
> Good point. Only a0 is guaranteed to be evaluated as a 32bit register,
> and parameters can be used either way. Funny how long this stayed
> unnoticed. How about the patch below?
>
>         M.
>
> From bbb79f54808b94c187cb1cbe56fecc0e2241576a Mon Sep 17 00:00:00 2001
> From: Marc Zyngier <marc.zyngier@arm.com>
> Date: Mon, 29 Jan 2018 09:48:28 +0000
> Subject: [PATCH] arm/arm64: smccc: Make function identifiers an unsigned
>  quantity
>
> Function identifiers are a 32bit, unsigned quantify. But we never

quantiTy ^^^

> tell so to the compiler, resulting in the following:
>
>  4ac:   b26187e0        mov     x0, #0xffffffff80000001
>
> We thus rely on the firmware narrowing it for us, which is not
> always a reasonable expectation.
>
> Cc: stable@vger.kernel.org
> Reported-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  include/linux/arm-smccc.h | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
> index ab1e86111953..e2af4ff772a1 100644
> --- a/include/linux/arm-smccc.h
> +++ b/include/linux/arm-smccc.h
> @@ -14,14 +14,16 @@
>  #ifndef __LINUX_ARM_SMCCC_H
>  #define __LINUX_ARM_SMCCC_H
>
> +#include <uapi/linux/const.h>
> +
>  /*
>   * This file provides common defines for ARM SMC Calling Convention as
>   * specified in
>   * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
>   */
>
> -#define ARM_SMCCC_STD_CALL             0
> -#define ARM_SMCCC_FAST_CALL            1
> +#define ARM_SMCCC_STD_CALL             _AC(0,U)
> +#define ARM_SMCCC_FAST_CALL            _AC(1,U)
>  #define ARM_SMCCC_TYPE_SHIFT           31
>
>  #define ARM_SMCCC_SMC_32               0
> --
> 2.14.2
>

Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support
@ 2018-01-29 10:17             ` Ard Biesheuvel
  0 siblings, 0 replies; 67+ messages in thread
From: Ard Biesheuvel @ 2018-01-29 10:17 UTC (permalink / raw)
  To: linux-arm-kernel

On 29 January 2018 at 10:07, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 29/01/18 09:42, Ard Biesheuvel wrote:
>> On 29 January 2018 at 09:36, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>> On 28/01/18 23:08, Ard Biesheuvel wrote:
>>>> On 26 January 2018 at 14:28, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>>>> Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1.
>>>>> It is lovely. Really.
>>>>>
>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>> ---
>>>>>  arch/arm64/kernel/bpi.S        | 20 ++++++++++++
>>>>>  arch/arm64/kernel/cpu_errata.c | 71 +++++++++++++++++++++++++++++++++++++++++-
>>>>>  2 files changed, 90 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
>>>>> index 76225c2611ea..add7e08a018d 100644
>>>>> --- a/arch/arm64/kernel/bpi.S
>>>>> +++ b/arch/arm64/kernel/bpi.S
>>>>> @@ -17,6 +17,7 @@
>>>>>   */
>>>>>
>>>>>  #include <linux/linkage.h>
>>>>> +#include <linux/arm-smccc.h>
>>>>>
>>>>>  .macro ventry target
>>>>>         .rept 31
>>>>> @@ -85,3 +86,22 @@ ENTRY(__qcom_hyp_sanitize_link_stack_start)
>>>>>         .endr
>>>>>         ldp     x29, x30, [sp], #16
>>>>>  ENTRY(__qcom_hyp_sanitize_link_stack_end)
>>>>> +
>>>>> +.macro smccc_workaround_1 inst
>>>>> +       sub     sp, sp, #(8 * 4)
>>>>> +       stp     x2, x3, [sp, #(16 * 0)]
>>>>> +       stp     x0, x1, [sp, #(16 * 1)]
>>>>> +       orr     w0, wzr, #ARM_SMCCC_ARCH_WORKAROUND_1
>>>>> +       \inst   #0
>>>>> +       ldp     x2, x3, [sp, #(16 * 0)]
>>>>> +       ldp     x0, x1, [sp, #(16 * 1)]
>>>>> +       add     sp, sp, #(8 * 4)
>>>>> +.endm
>>>>> +
>>>>> +ENTRY(__smccc_workaround_1_smc_start)
>>>>> +       smccc_workaround_1      smc
>>>>> +ENTRY(__smccc_workaround_1_smc_end)
>>>>> +
>>>>> +ENTRY(__smccc_workaround_1_hvc_start)
>>>>> +       smccc_workaround_1      hvc
>>>>> +ENTRY(__smccc_workaround_1_hvc_end)
>>>>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>>>>> index ed6881882231..f1501873f2e4 100644
>>>>> --- a/arch/arm64/kernel/cpu_errata.c
>>>>> +++ b/arch/arm64/kernel/cpu_errata.c
>>>>> @@ -70,6 +70,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
>>>>>  extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
>>>>>  extern char __qcom_hyp_sanitize_link_stack_start[];
>>>>>  extern char __qcom_hyp_sanitize_link_stack_end[];
>>>>> +extern char __smccc_workaround_1_smc_start[];
>>>>> +extern char __smccc_workaround_1_smc_end[];
>>>>> +extern char __smccc_workaround_1_hvc_start[];
>>>>> +extern char __smccc_workaround_1_hvc_end[];
>>>>>
>>>>>  static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
>>>>>                                 const char *hyp_vecs_end)
>>>>> @@ -116,6 +120,10 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>>>  #define __psci_hyp_bp_inval_end                        NULL
>>>>>  #define __qcom_hyp_sanitize_link_stack_start   NULL
>>>>>  #define __qcom_hyp_sanitize_link_stack_end     NULL
>>>>> +#define __smccc_workaround_1_smc_start         NULL
>>>>> +#define __smccc_workaround_1_smc_end           NULL
>>>>> +#define __smccc_workaround_1_hvc_start         NULL
>>>>> +#define __smccc_workaround_1_hvc_end           NULL
>>>>>
>>>>>  static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
>>>>>                                       const char *hyp_vecs_start,
>>>>> @@ -142,17 +150,78 @@ static void  install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
>>>>>         __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
>>>>>  }
>>>>>
>>>>> +#include <uapi/linux/psci.h>
>>>>> +#include <linux/arm-smccc.h>
>>>>>  #include <linux/psci.h>
>>>>>
>>>>> +static void call_smc_arch_workaround_1(void)
>>>>> +{
>>>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>>>> +       asm volatile("smc       #0\n"
>>>>> +                    : "+r" (w0));
>>>>> +}
>>>>> +
>>>>> +static void call_hvc_arch_workaround_1(void)
>>>>> +{
>>>>> +       register int w0 asm("w0") = ARM_SMCCC_ARCH_WORKAROUND_1;
>>>>> +       asm volatile("hvc       #0\n"
>>>>> +                    : "+r" (w0));
>>>>> +}
>>>>> +
>>>>> +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
>>>>> +{
>>>>> +       bp_hardening_cb_t cb;
>>>>> +       void *smccc_start, *smccc_end;
>>>>> +       struct arm_smccc_res res;
>>>>> +
>>>>> +       if (psci_ops.variant == SMCCC_VARIANT_1_0)
>>>>> +               return false;
>>>>> +
>>>>> +       switch (psci_ops.conduit) {
>>>>> +       case PSCI_CONDUIT_HVC:
>>>>> +               arm_smccc_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>>>> +                             &res);
>>>>> +               if (res.a0)
>>>>> +                       return false;
>>>>> +               cb = call_hvc_arch_workaround_1;
>>>>> +               smccc_start = __smccc_workaround_1_hvc_start;
>>>>> +               smccc_end = __smccc_workaround_1_hvc_end;
>>>>> +               break;
>>>>> +
>>>>> +       case PSCI_CONDUIT_SMC:
>>>>> +               arm_smccc_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
>>>>> +                             ARM_SMCCC_ARCH_WORKAROUND_1, 0, 0, 0, 0, 0, 0,
>>>>> +                             &res);
>>>>
>>>> This compiles to
>>>>
>>>>  4a8:   928fffe1        mov     x1, #0xffffffffffff8000         // #-32768
>>>>  4ac:   b26187e0        mov     x0, #0xffffffff80000001         // #-2147483647
>>>>  4b0:   d2800007        mov     x7, #0x0                        // #0
>>>>  4b4:   d2800006        mov     x6, #0x0                        // #0
>>>>  4b8:   d2800005        mov     x5, #0x0                        // #0
>>>>  4bc:   d2800004        mov     x4, #0x0                        // #0
>>>>  4c0:   d2800003        mov     x3, #0x0                        // #0
>>>>  4c4:   d2800002        mov     x2, #0x0                        // #0
>>>>  4c8:   f2b00001        movk    x1, #0x8000, lsl #16
>>>>  4cc:   94000000        bl      0 <__arm_smccc_smc>
>>>>
>>>> so it seems we're missing a UL suffix somewhere.
>>>
>>> Yeah, this seems to stem from ARM_SMCCC_FAST_CALL, which is bit 31 and
>>> isn't advertised as unsigned. It still works because both x0 and x1 are
>>> used as 32bit quantities in this particular SMC context, but that has
>>> the potential of triggering unexpected behaviours in broken implementations.
>>>
>>
>> Are you sure about that? To me, it looks like this code
>>
>> static int32_t smccc_arch_features(u_register_t arg)
>> {
>>     switch (arg) {
>>     case SMCCC_VERSION:
>>     case SMCCC_ARCH_FEATURES:
>>         return SMC_OK;
>> #if WORKAROUND_CVE_2017_5715
>>     case SMCCC_ARCH_WORKAROUND_1:
>>         return SMC_OK;
>> #endif
>>     default:
>>         return SMC_UNK;
>>     }
>> }
>>
>> will end up comparing 0xffffffff80008000 to 0x80008000, and fail
>> (which is what it did when I tried it)
>
> Good point. Only a0 is guaranteed to be evaluated as a 32bit register,
> and parameters can be used either way. Funny how long this stayed
> unnoticed. How about the patch below?
>
>         M.
>
> From bbb79f54808b94c187cb1cbe56fecc0e2241576a Mon Sep 17 00:00:00 2001
> From: Marc Zyngier <marc.zyngier@arm.com>
> Date: Mon, 29 Jan 2018 09:48:28 +0000
> Subject: [PATCH] arm/arm64: smccc: Make function identifiers an unsigned
>  quantity
>
> Function identifiers are a 32bit, unsigned quantify. But we never

quantiTy ^^^

> tell so to the compiler, resulting in the following:
>
>  4ac:   b26187e0        mov     x0, #0xffffffff80000001
>
> We thus rely on the firmware narrowing it for us, which is not
> always a reasonable expectation.
>
> Cc: stable at vger.kernel.org
> Reported-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  include/linux/arm-smccc.h | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
> index ab1e86111953..e2af4ff772a1 100644
> --- a/include/linux/arm-smccc.h
> +++ b/include/linux/arm-smccc.h
> @@ -14,14 +14,16 @@
>  #ifndef __LINUX_ARM_SMCCC_H
>  #define __LINUX_ARM_SMCCC_H
>
> +#include <uapi/linux/const.h>
> +
>  /*
>   * This file provides common defines for ARM SMC Calling Convention as
>   * specified in
>   * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
>   */
>
> -#define ARM_SMCCC_STD_CALL             0
> -#define ARM_SMCCC_FAST_CALL            1
> +#define ARM_SMCCC_STD_CALL             _AC(0,U)
> +#define ARM_SMCCC_FAST_CALL            _AC(1,U)
>  #define ARM_SMCCC_TYPE_SHIFT           31
>
>  #define ARM_SMCCC_SMC_32               0
> --
> 2.14.2
>

Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

^ permalink raw reply	[flat|nested] 67+ messages in thread

end of thread, other threads:[~2018-01-29 10:17 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-26 14:28 [PATCH 00/14] arm64: Add SMCCC v1.1 support and CVE-2017-5715 Marc Zyngier
2018-01-26 14:28 ` Marc Zyngier
2018-01-26 14:28 ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 01/14] arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 02/14] arm: " Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 03/14] arm/arm64: KVM: Consolidate the PSCI include files Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 18:10   ` Marc Zyngier
2018-01-26 18:10     ` Marc Zyngier
2018-01-26 18:10     ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 04/14] arm/arm64: KVM: Add PSCI_VERSION helper Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 05/14] arm/arm64: KVM: Add smccc accessors to PSCI code Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 06/14] arm/arm64: KVM: Implement PSCI 1.0 support Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 07/14] arm/arm64: KVM: Add PSCI version selection API Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 08/14] arm/arm64: KVM: Advertise SMCCC v1.1 Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 09/14] arm/arm64: KVM: Turn kvm_psci_version into a static inline Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 10/14] arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 11/14] arm64: KVM: Add SMCCC_ARCH_WORKAROUND_1 fast handling Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 12/14] firmware/psci: Expose PSCI conduit Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-29 10:04   ` Ard Biesheuvel
2018-01-29 10:04     ` Ard Biesheuvel
2018-01-29 10:08     ` Marc Zyngier
2018-01-29 10:08       ` Marc Zyngier
2018-01-26 14:28 ` [PATCH 13/14] firmware/psci: Expose SMCCC version through psci_ops Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-29 10:03   ` Ard Biesheuvel
2018-01-29 10:03     ` Ard Biesheuvel
2018-01-29 10:03     ` Ard Biesheuvel
2018-01-26 14:28 ` [PATCH 14/14] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support Marc Zyngier
2018-01-26 14:28   ` Marc Zyngier
2018-01-26 15:50   ` Robin Murphy
2018-01-26 15:50     ` Robin Murphy
2018-01-26 15:50     ` Robin Murphy
2018-01-26 16:07     ` Marc Zyngier
2018-01-26 16:07       ` Marc Zyngier
2018-01-28 23:08   ` Ard Biesheuvel
2018-01-28 23:08     ` Ard Biesheuvel
2018-01-29  9:36     ` Marc Zyngier
2018-01-29  9:36       ` Marc Zyngier
2018-01-29  9:42       ` Ard Biesheuvel
2018-01-29  9:42         ` Ard Biesheuvel
2018-01-29 10:07         ` Marc Zyngier
2018-01-29 10:07           ` Marc Zyngier
2018-01-29 10:17           ` Ard Biesheuvel
2018-01-29 10:17             ` Ard Biesheuvel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.