All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/9] KVM: arm64: Add support for hypercall services selection
@ 2022-04-23  0:03 ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Hello,

Continuing the discussion from [1], the series tries to add support
for the userspace to elect the hypercall services that it wishes
to expose to the guest, rather than the guest discovering them
unconditionally. The idea employed by the series was taken from
[1] as suggested by Marc Z.

In a broad sense, the concept is similar to the current implementation
of PSCI interface- create a 'firmware psuedo-register' to handle the
firmware revisions. The series extends this idea to all the other
hypercalls such as TRNG (True Random Number Generator), PV_TIME
(Paravirtualized Time), and PTP (Precision Time protocol).

For better categorization and future scaling, these firmware registers
are categorized based on the service call owners. Also, unlike the
existing firmware psuedo-registers, they hold the features supported
in the form of a bitmap.

During the VM initialization, the registers holds an upper-limit of
the features supported by each one of them. It's expected that the
userspace discover the features provided by each register via GET_ONE_REG,
and writeback the desired values using SET_ONE_REG. KVM allows this
modification only until the VM has started.

Some of the standard function-ids, such as ARM_SMCCC_VERSION_FUNC_ID,
need not be associated with a feature bit. For such ids, the series
introduced an allowed-list (in kvm_hvc_call_default_allowed()), that holds
all such ids. As a result, the functions that are not elected by userspace,
or if they are not a part of this allowed-list, will be denied for when
the guests invoke them.

Older VMMs can simply ignore this interface and the hypercall services
will be exposed unconditionally to the guests, thus ensuring backward
compatibility.

The patches are based off of mainline kernel 5.18-rc3, with the selftest
patches from [2] applied.

Patch-1 factors out the non-PSCI related interface from psci.c to
hypercalls.c, as the series would extend the list in the upcoming
patches.

Patch-2 sets up the framework for the bitmap firmware psuedo-registers.
It includes read/write support for the registers, and a helper to check
if a particular hypercall service is supported for the guest.
It also adds the register KVM_REG_ARM_STD_HYP_BMAP to support ARM's
standard secure services.

Patch-3 introduces the firmware register, KVM_REG_ARM_STD_HYP_BMAP,
which holds the standard hypervisor services (such as PV_TIME).

Patch-4 introduces the firmware register, KVM_REG_ARM_VENDOR_HYP_BMAP,
which holds the vendor specific hypercall services.

Patch-5,6 Add the necessary documentation for the newly added firmware
registers.

Patch-7 imports the SMCCC definitions from linux/arm-smccc.h into tools/
for further use in selftests.

Patch-8 adds the selftest to test the guest (using 'hvc') and userspace
interfaces (SET/GET_ONE_REG).

Patch-9 adds these firmware registers into the get-reg-list selftest.

[1]: https://lore.kernel.org/kvmarm/874kbcpmlq.wl-maz@kernel.org/T/
[2]: https://lore.kernel.org/all/20220409184549.1681189-1-oupton@google.com/

Regards,
Raghavendra

v5 -> v6:

Addressed the comments by Marc and Gavin:

- Bitmaps are represented using 'unsigned long' inctead of 'u64' (Marc).
- Replaced the array holding the allowed-list,
  hvc_func_default_allowed_list[], which looked up the func_id using a
  loop, with a switch-case statement (Marc).
- kvm_arm_set_fw_reg_bmap() now always returns -EBUSY for any 'write' of
  the bitmap value after the VM has started running. Documentation is
  adjusted accordingly (Marc).
- kvm_psci_func_id_is_valid() is moved from an inline function to
  kvm/psci.c (Marc).
- Merged ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID into bit-0 of the vendor
  hypervisor firmware register (Gavin).
- Macro optimizations and replace arg0 with arg1 (to comply with KVM
  convention) in hypercalls.c selftest (Gavin).
- Dropped the patch v5 10/10 (Add KVM_REG_ARM_FW_REG(3) to get-reg-list)
  as it was already uploaded by Andrew.
- Fixed typos

v4 -> v5:

Addressed comments by Oliver (thank you!):

- Rebased the series to accommodate ARM_SMCCC_ARCH_WORKAROUND_3
  and PSCI 1.1 changes, and capturing VM's first run.
- Removed the patches related to register scoping (v4 02/13 and
  03/13). I plan to re-introduce them in its own series.
- Dropped the patch that captures VM's first run.
- Moved the bitmap feature firmware registers to its own CORPOC
  space (0x0016).
- Move the KVM_REG_ARM_*_BIT_MAX definitions from uapi header
  to internal header (arm_hypercalls.h).
- Renamed the hypercall descriptor to 'struct kvm_smccc_features',
  and kvm_hvc_call_supported() to kvm_hvc_call_allowed().
- Introduced an allowed-list to hold the function-ids that aren't
  represented by feature-bits.
- Introduced kvm_psci_func_id_is_valid() to check if a given
  function-id is a valid PSCI id, which is used in
  kvm_hvc_call_allowed().
- Introduced KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT as bit-0 of
  KVM_REG_ARM_VENDOR_HYP_BMAP register and
  KVM_REG_ARM_VENDOR_HYP_BIT_PTP is moved to bit-1.
- Updated the arm-smccc.h import to include the definition of
  ARM_SMCCC_ARCH_WORKAROUND_3.
- Introduced the KVM_REG_ARM_FW_FEAT_BMAP COPROC definition to
  get-reg-list selftest.
- Created a new patch to include KVM_REG_ARM_FW_REG(3) in
  get-reg-list.


v3 -> v4

Addressed comments and took suggestions by Reiji, Oliver, Marc,
Sean and Jim:

- Renamed and moved the VM has run once check to arm64.
- Introduced the capability to dynamically modify the register
  encodings to include the scope information.
- Replaced mutex_lock with READ_ONCE and WRITE_ONCE when the
  bitmaps are accessed.
- The hypercalls selftest re-runs with KVM_CAP_ARM_REG_SCOPE
  enabled.

v2 -> v3

Addressed comments by Marc and Andrew:

- Dropped kvm_vcpu_has_run_once() implementation.
- Redifined kvm_vm_has_run_once() as kvm_vm_has_started() in the core
  KVM code that introduces a new field, 'vm_started', to track this.
- KVM_CAP_ARM_HVC_FW_REG_BMAP returns the number of psuedo-firmware
  bitmap registers upon a 'read'. Support for 'write' removed.
- Removed redundant spinlock, 'fw_reg_bmap_enabled' fields from the
  hypercall descriptor structure.
- A separate sub-struct to hold the bitmap info is removed. The bitmap
  info is directly stored in the hypercall descriptor structure
  (struct kvm_hvc_desc).

v1 -> v2

Addressed comments by Oliver (thanks!):

- Introduced kvm_vcpu_has_run_once() and kvm_vm_has_run_once() in the
  core kvm code, rather than relying on ARM specific
  vcpu->arch.has_run_once.
- Writing to KVM_REG_ARM_PSCI_VERSION is done in hypercalls.c itself,
  rather than separating out to psci.c.
- Introduced KVM_CAP_ARM_HVC_FW_REG_BMAP to enable the extension.
- Tracks the register accesses from VMM to decide whether to sanitize
  a register or not, as opposed to sanitizing upon the first 'write'
  in v1.
- kvm_hvc_call_supported() is implemented using a direct switch-case
  statement, instead of looping over all the registers to pick the
  register for the function-id.
- Replaced the register bit definitions with #defines, instead of enums.
- Removed the patch v1-06/08 that imports the firmware register
  definitions as it's not needed.
- Separated out the documentations in its own patch, and the renaming
  of hypercalls.rst to psci.rst into another patch.
- Add the new firmware registers to get-reg-list KVM selftest.

v1: https://lore.kernel.org/kvmarm/20211102002203.1046069-1-rananta@google.com/
v2: https://lore.kernel.org/kvmarm/20211113012234.1443009-1-rananta@google.com/
v3: https://lore.kernel.org/linux-arm-kernel/20220104194918.373612-1-rananta@google.com/
v4: https://lore.kernel.org/lkml/20220224172559.4170192-1-rananta@google.com/
v5: https://lore.kernel.org/lkml/20220407011605.1966778-1-rananta@google.com/

Raghavendra Rao Ananta (9):
  KVM: arm64: Factor out firmware register handling from psci.c
  KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  KVM: arm64: Add standard hypervisor firmware register
  KVM: arm64: Add vendor hypervisor firmware register
  Docs: KVM: Rename psci.rst to hypercalls.rst
  Docs: KVM: Add doc for the bitmap firmware registers
  tools: Import ARM SMCCC definitions
  selftests: KVM: aarch64: Introduce hypercall ABI test
  selftests: KVM: aarch64: Add the bitmap firmware registers to
    get-reg-list

 Documentation/virt/kvm/api.rst                |  16 +
 Documentation/virt/kvm/arm/hypercalls.rst     | 135 +++++++
 Documentation/virt/kvm/arm/psci.rst           |  77 ----
 arch/arm64/include/asm/kvm_host.h             |  16 +
 arch/arm64/include/uapi/asm/kvm.h             |  16 +
 arch/arm64/kvm/arm.c                          |   1 +
 arch/arm64/kvm/guest.c                        |  10 +-
 arch/arm64/kvm/hypercalls.c                   | 313 +++++++++++++++-
 arch/arm64/kvm/psci.c                         | 186 +---------
 include/kvm/arm_hypercalls.h                  |  17 +
 include/kvm/arm_psci.h                        |   9 +-
 tools/include/linux/arm-smccc.h               | 193 ++++++++++
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/aarch64/get-reg-list.c      |   8 +
 .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
 16 files changed, 1065 insertions(+), 269 deletions(-)
 create mode 100644 Documentation/virt/kvm/arm/hypercalls.rst
 delete mode 100644 Documentation/virt/kvm/arm/psci.rst
 create mode 100644 tools/include/linux/arm-smccc.h
 create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c

-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 0/9] KVM: arm64: Add support for hypercall services selection
@ 2022-04-23  0:03 ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Hello,

Continuing the discussion from [1], the series tries to add support
for the userspace to elect the hypercall services that it wishes
to expose to the guest, rather than the guest discovering them
unconditionally. The idea employed by the series was taken from
[1] as suggested by Marc Z.

In a broad sense, the concept is similar to the current implementation
of PSCI interface- create a 'firmware psuedo-register' to handle the
firmware revisions. The series extends this idea to all the other
hypercalls such as TRNG (True Random Number Generator), PV_TIME
(Paravirtualized Time), and PTP (Precision Time protocol).

For better categorization and future scaling, these firmware registers
are categorized based on the service call owners. Also, unlike the
existing firmware psuedo-registers, they hold the features supported
in the form of a bitmap.

During the VM initialization, the registers holds an upper-limit of
the features supported by each one of them. It's expected that the
userspace discover the features provided by each register via GET_ONE_REG,
and writeback the desired values using SET_ONE_REG. KVM allows this
modification only until the VM has started.

Some of the standard function-ids, such as ARM_SMCCC_VERSION_FUNC_ID,
need not be associated with a feature bit. For such ids, the series
introduced an allowed-list (in kvm_hvc_call_default_allowed()), that holds
all such ids. As a result, the functions that are not elected by userspace,
or if they are not a part of this allowed-list, will be denied for when
the guests invoke them.

Older VMMs can simply ignore this interface and the hypercall services
will be exposed unconditionally to the guests, thus ensuring backward
compatibility.

The patches are based off of mainline kernel 5.18-rc3, with the selftest
patches from [2] applied.

Patch-1 factors out the non-PSCI related interface from psci.c to
hypercalls.c, as the series would extend the list in the upcoming
patches.

Patch-2 sets up the framework for the bitmap firmware psuedo-registers.
It includes read/write support for the registers, and a helper to check
if a particular hypercall service is supported for the guest.
It also adds the register KVM_REG_ARM_STD_HYP_BMAP to support ARM's
standard secure services.

Patch-3 introduces the firmware register, KVM_REG_ARM_STD_HYP_BMAP,
which holds the standard hypervisor services (such as PV_TIME).

Patch-4 introduces the firmware register, KVM_REG_ARM_VENDOR_HYP_BMAP,
which holds the vendor specific hypercall services.

Patch-5,6 Add the necessary documentation for the newly added firmware
registers.

Patch-7 imports the SMCCC definitions from linux/arm-smccc.h into tools/
for further use in selftests.

Patch-8 adds the selftest to test the guest (using 'hvc') and userspace
interfaces (SET/GET_ONE_REG).

Patch-9 adds these firmware registers into the get-reg-list selftest.

[1]: https://lore.kernel.org/kvmarm/874kbcpmlq.wl-maz@kernel.org/T/
[2]: https://lore.kernel.org/all/20220409184549.1681189-1-oupton@google.com/

Regards,
Raghavendra

v5 -> v6:

Addressed the comments by Marc and Gavin:

- Bitmaps are represented using 'unsigned long' inctead of 'u64' (Marc).
- Replaced the array holding the allowed-list,
  hvc_func_default_allowed_list[], which looked up the func_id using a
  loop, with a switch-case statement (Marc).
- kvm_arm_set_fw_reg_bmap() now always returns -EBUSY for any 'write' of
  the bitmap value after the VM has started running. Documentation is
  adjusted accordingly (Marc).
- kvm_psci_func_id_is_valid() is moved from an inline function to
  kvm/psci.c (Marc).
- Merged ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID into bit-0 of the vendor
  hypervisor firmware register (Gavin).
- Macro optimizations and replace arg0 with arg1 (to comply with KVM
  convention) in hypercalls.c selftest (Gavin).
- Dropped the patch v5 10/10 (Add KVM_REG_ARM_FW_REG(3) to get-reg-list)
  as it was already uploaded by Andrew.
- Fixed typos

v4 -> v5:

Addressed comments by Oliver (thank you!):

- Rebased the series to accommodate ARM_SMCCC_ARCH_WORKAROUND_3
  and PSCI 1.1 changes, and capturing VM's first run.
- Removed the patches related to register scoping (v4 02/13 and
  03/13). I plan to re-introduce them in its own series.
- Dropped the patch that captures VM's first run.
- Moved the bitmap feature firmware registers to its own CORPOC
  space (0x0016).
- Move the KVM_REG_ARM_*_BIT_MAX definitions from uapi header
  to internal header (arm_hypercalls.h).
- Renamed the hypercall descriptor to 'struct kvm_smccc_features',
  and kvm_hvc_call_supported() to kvm_hvc_call_allowed().
- Introduced an allowed-list to hold the function-ids that aren't
  represented by feature-bits.
- Introduced kvm_psci_func_id_is_valid() to check if a given
  function-id is a valid PSCI id, which is used in
  kvm_hvc_call_allowed().
- Introduced KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT as bit-0 of
  KVM_REG_ARM_VENDOR_HYP_BMAP register and
  KVM_REG_ARM_VENDOR_HYP_BIT_PTP is moved to bit-1.
- Updated the arm-smccc.h import to include the definition of
  ARM_SMCCC_ARCH_WORKAROUND_3.
- Introduced the KVM_REG_ARM_FW_FEAT_BMAP COPROC definition to
  get-reg-list selftest.
- Created a new patch to include KVM_REG_ARM_FW_REG(3) in
  get-reg-list.


v3 -> v4

Addressed comments and took suggestions by Reiji, Oliver, Marc,
Sean and Jim:

- Renamed and moved the VM has run once check to arm64.
- Introduced the capability to dynamically modify the register
  encodings to include the scope information.
- Replaced mutex_lock with READ_ONCE and WRITE_ONCE when the
  bitmaps are accessed.
- The hypercalls selftest re-runs with KVM_CAP_ARM_REG_SCOPE
  enabled.

v2 -> v3

Addressed comments by Marc and Andrew:

- Dropped kvm_vcpu_has_run_once() implementation.
- Redifined kvm_vm_has_run_once() as kvm_vm_has_started() in the core
  KVM code that introduces a new field, 'vm_started', to track this.
- KVM_CAP_ARM_HVC_FW_REG_BMAP returns the number of psuedo-firmware
  bitmap registers upon a 'read'. Support for 'write' removed.
- Removed redundant spinlock, 'fw_reg_bmap_enabled' fields from the
  hypercall descriptor structure.
- A separate sub-struct to hold the bitmap info is removed. The bitmap
  info is directly stored in the hypercall descriptor structure
  (struct kvm_hvc_desc).

v1 -> v2

Addressed comments by Oliver (thanks!):

- Introduced kvm_vcpu_has_run_once() and kvm_vm_has_run_once() in the
  core kvm code, rather than relying on ARM specific
  vcpu->arch.has_run_once.
- Writing to KVM_REG_ARM_PSCI_VERSION is done in hypercalls.c itself,
  rather than separating out to psci.c.
- Introduced KVM_CAP_ARM_HVC_FW_REG_BMAP to enable the extension.
- Tracks the register accesses from VMM to decide whether to sanitize
  a register or not, as opposed to sanitizing upon the first 'write'
  in v1.
- kvm_hvc_call_supported() is implemented using a direct switch-case
  statement, instead of looping over all the registers to pick the
  register for the function-id.
- Replaced the register bit definitions with #defines, instead of enums.
- Removed the patch v1-06/08 that imports the firmware register
  definitions as it's not needed.
- Separated out the documentations in its own patch, and the renaming
  of hypercalls.rst to psci.rst into another patch.
- Add the new firmware registers to get-reg-list KVM selftest.

v1: https://lore.kernel.org/kvmarm/20211102002203.1046069-1-rananta@google.com/
v2: https://lore.kernel.org/kvmarm/20211113012234.1443009-1-rananta@google.com/
v3: https://lore.kernel.org/linux-arm-kernel/20220104194918.373612-1-rananta@google.com/
v4: https://lore.kernel.org/lkml/20220224172559.4170192-1-rananta@google.com/
v5: https://lore.kernel.org/lkml/20220407011605.1966778-1-rananta@google.com/

Raghavendra Rao Ananta (9):
  KVM: arm64: Factor out firmware register handling from psci.c
  KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  KVM: arm64: Add standard hypervisor firmware register
  KVM: arm64: Add vendor hypervisor firmware register
  Docs: KVM: Rename psci.rst to hypercalls.rst
  Docs: KVM: Add doc for the bitmap firmware registers
  tools: Import ARM SMCCC definitions
  selftests: KVM: aarch64: Introduce hypercall ABI test
  selftests: KVM: aarch64: Add the bitmap firmware registers to
    get-reg-list

 Documentation/virt/kvm/api.rst                |  16 +
 Documentation/virt/kvm/arm/hypercalls.rst     | 135 +++++++
 Documentation/virt/kvm/arm/psci.rst           |  77 ----
 arch/arm64/include/asm/kvm_host.h             |  16 +
 arch/arm64/include/uapi/asm/kvm.h             |  16 +
 arch/arm64/kvm/arm.c                          |   1 +
 arch/arm64/kvm/guest.c                        |  10 +-
 arch/arm64/kvm/hypercalls.c                   | 313 +++++++++++++++-
 arch/arm64/kvm/psci.c                         | 186 +---------
 include/kvm/arm_hypercalls.h                  |  17 +
 include/kvm/arm_psci.h                        |   9 +-
 tools/include/linux/arm-smccc.h               | 193 ++++++++++
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/aarch64/get-reg-list.c      |   8 +
 .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
 16 files changed, 1065 insertions(+), 269 deletions(-)
 create mode 100644 Documentation/virt/kvm/arm/hypercalls.rst
 delete mode 100644 Documentation/virt/kvm/arm/psci.rst
 create mode 100644 tools/include/linux/arm-smccc.h
 create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c

-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 0/9] KVM: arm64: Add support for hypercall services selection
@ 2022-04-23  0:03 ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Hello,

Continuing the discussion from [1], the series tries to add support
for the userspace to elect the hypercall services that it wishes
to expose to the guest, rather than the guest discovering them
unconditionally. The idea employed by the series was taken from
[1] as suggested by Marc Z.

In a broad sense, the concept is similar to the current implementation
of PSCI interface- create a 'firmware psuedo-register' to handle the
firmware revisions. The series extends this idea to all the other
hypercalls such as TRNG (True Random Number Generator), PV_TIME
(Paravirtualized Time), and PTP (Precision Time protocol).

For better categorization and future scaling, these firmware registers
are categorized based on the service call owners. Also, unlike the
existing firmware psuedo-registers, they hold the features supported
in the form of a bitmap.

During the VM initialization, the registers holds an upper-limit of
the features supported by each one of them. It's expected that the
userspace discover the features provided by each register via GET_ONE_REG,
and writeback the desired values using SET_ONE_REG. KVM allows this
modification only until the VM has started.

Some of the standard function-ids, such as ARM_SMCCC_VERSION_FUNC_ID,
need not be associated with a feature bit. For such ids, the series
introduced an allowed-list (in kvm_hvc_call_default_allowed()), that holds
all such ids. As a result, the functions that are not elected by userspace,
or if they are not a part of this allowed-list, will be denied for when
the guests invoke them.

Older VMMs can simply ignore this interface and the hypercall services
will be exposed unconditionally to the guests, thus ensuring backward
compatibility.

The patches are based off of mainline kernel 5.18-rc3, with the selftest
patches from [2] applied.

Patch-1 factors out the non-PSCI related interface from psci.c to
hypercalls.c, as the series would extend the list in the upcoming
patches.

Patch-2 sets up the framework for the bitmap firmware psuedo-registers.
It includes read/write support for the registers, and a helper to check
if a particular hypercall service is supported for the guest.
It also adds the register KVM_REG_ARM_STD_HYP_BMAP to support ARM's
standard secure services.

Patch-3 introduces the firmware register, KVM_REG_ARM_STD_HYP_BMAP,
which holds the standard hypervisor services (such as PV_TIME).

Patch-4 introduces the firmware register, KVM_REG_ARM_VENDOR_HYP_BMAP,
which holds the vendor specific hypercall services.

Patch-5,6 Add the necessary documentation for the newly added firmware
registers.

Patch-7 imports the SMCCC definitions from linux/arm-smccc.h into tools/
for further use in selftests.

Patch-8 adds the selftest to test the guest (using 'hvc') and userspace
interfaces (SET/GET_ONE_REG).

Patch-9 adds these firmware registers into the get-reg-list selftest.

[1]: https://lore.kernel.org/kvmarm/874kbcpmlq.wl-maz@kernel.org/T/
[2]: https://lore.kernel.org/all/20220409184549.1681189-1-oupton@google.com/

Regards,
Raghavendra

v5 -> v6:

Addressed the comments by Marc and Gavin:

- Bitmaps are represented using 'unsigned long' inctead of 'u64' (Marc).
- Replaced the array holding the allowed-list,
  hvc_func_default_allowed_list[], which looked up the func_id using a
  loop, with a switch-case statement (Marc).
- kvm_arm_set_fw_reg_bmap() now always returns -EBUSY for any 'write' of
  the bitmap value after the VM has started running. Documentation is
  adjusted accordingly (Marc).
- kvm_psci_func_id_is_valid() is moved from an inline function to
  kvm/psci.c (Marc).
- Merged ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID into bit-0 of the vendor
  hypervisor firmware register (Gavin).
- Macro optimizations and replace arg0 with arg1 (to comply with KVM
  convention) in hypercalls.c selftest (Gavin).
- Dropped the patch v5 10/10 (Add KVM_REG_ARM_FW_REG(3) to get-reg-list)
  as it was already uploaded by Andrew.
- Fixed typos

v4 -> v5:

Addressed comments by Oliver (thank you!):

- Rebased the series to accommodate ARM_SMCCC_ARCH_WORKAROUND_3
  and PSCI 1.1 changes, and capturing VM's first run.
- Removed the patches related to register scoping (v4 02/13 and
  03/13). I plan to re-introduce them in its own series.
- Dropped the patch that captures VM's first run.
- Moved the bitmap feature firmware registers to its own CORPOC
  space (0x0016).
- Move the KVM_REG_ARM_*_BIT_MAX definitions from uapi header
  to internal header (arm_hypercalls.h).
- Renamed the hypercall descriptor to 'struct kvm_smccc_features',
  and kvm_hvc_call_supported() to kvm_hvc_call_allowed().
- Introduced an allowed-list to hold the function-ids that aren't
  represented by feature-bits.
- Introduced kvm_psci_func_id_is_valid() to check if a given
  function-id is a valid PSCI id, which is used in
  kvm_hvc_call_allowed().
- Introduced KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT as bit-0 of
  KVM_REG_ARM_VENDOR_HYP_BMAP register and
  KVM_REG_ARM_VENDOR_HYP_BIT_PTP is moved to bit-1.
- Updated the arm-smccc.h import to include the definition of
  ARM_SMCCC_ARCH_WORKAROUND_3.
- Introduced the KVM_REG_ARM_FW_FEAT_BMAP COPROC definition to
  get-reg-list selftest.
- Created a new patch to include KVM_REG_ARM_FW_REG(3) in
  get-reg-list.


v3 -> v4

Addressed comments and took suggestions by Reiji, Oliver, Marc,
Sean and Jim:

- Renamed and moved the VM has run once check to arm64.
- Introduced the capability to dynamically modify the register
  encodings to include the scope information.
- Replaced mutex_lock with READ_ONCE and WRITE_ONCE when the
  bitmaps are accessed.
- The hypercalls selftest re-runs with KVM_CAP_ARM_REG_SCOPE
  enabled.

v2 -> v3

Addressed comments by Marc and Andrew:

- Dropped kvm_vcpu_has_run_once() implementation.
- Redifined kvm_vm_has_run_once() as kvm_vm_has_started() in the core
  KVM code that introduces a new field, 'vm_started', to track this.
- KVM_CAP_ARM_HVC_FW_REG_BMAP returns the number of psuedo-firmware
  bitmap registers upon a 'read'. Support for 'write' removed.
- Removed redundant spinlock, 'fw_reg_bmap_enabled' fields from the
  hypercall descriptor structure.
- A separate sub-struct to hold the bitmap info is removed. The bitmap
  info is directly stored in the hypercall descriptor structure
  (struct kvm_hvc_desc).

v1 -> v2

Addressed comments by Oliver (thanks!):

- Introduced kvm_vcpu_has_run_once() and kvm_vm_has_run_once() in the
  core kvm code, rather than relying on ARM specific
  vcpu->arch.has_run_once.
- Writing to KVM_REG_ARM_PSCI_VERSION is done in hypercalls.c itself,
  rather than separating out to psci.c.
- Introduced KVM_CAP_ARM_HVC_FW_REG_BMAP to enable the extension.
- Tracks the register accesses from VMM to decide whether to sanitize
  a register or not, as opposed to sanitizing upon the first 'write'
  in v1.
- kvm_hvc_call_supported() is implemented using a direct switch-case
  statement, instead of looping over all the registers to pick the
  register for the function-id.
- Replaced the register bit definitions with #defines, instead of enums.
- Removed the patch v1-06/08 that imports the firmware register
  definitions as it's not needed.
- Separated out the documentations in its own patch, and the renaming
  of hypercalls.rst to psci.rst into another patch.
- Add the new firmware registers to get-reg-list KVM selftest.

v1: https://lore.kernel.org/kvmarm/20211102002203.1046069-1-rananta@google.com/
v2: https://lore.kernel.org/kvmarm/20211113012234.1443009-1-rananta@google.com/
v3: https://lore.kernel.org/linux-arm-kernel/20220104194918.373612-1-rananta@google.com/
v4: https://lore.kernel.org/lkml/20220224172559.4170192-1-rananta@google.com/
v5: https://lore.kernel.org/lkml/20220407011605.1966778-1-rananta@google.com/

Raghavendra Rao Ananta (9):
  KVM: arm64: Factor out firmware register handling from psci.c
  KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  KVM: arm64: Add standard hypervisor firmware register
  KVM: arm64: Add vendor hypervisor firmware register
  Docs: KVM: Rename psci.rst to hypercalls.rst
  Docs: KVM: Add doc for the bitmap firmware registers
  tools: Import ARM SMCCC definitions
  selftests: KVM: aarch64: Introduce hypercall ABI test
  selftests: KVM: aarch64: Add the bitmap firmware registers to
    get-reg-list

 Documentation/virt/kvm/api.rst                |  16 +
 Documentation/virt/kvm/arm/hypercalls.rst     | 135 +++++++
 Documentation/virt/kvm/arm/psci.rst           |  77 ----
 arch/arm64/include/asm/kvm_host.h             |  16 +
 arch/arm64/include/uapi/asm/kvm.h             |  16 +
 arch/arm64/kvm/arm.c                          |   1 +
 arch/arm64/kvm/guest.c                        |  10 +-
 arch/arm64/kvm/hypercalls.c                   | 313 +++++++++++++++-
 arch/arm64/kvm/psci.c                         | 186 +---------
 include/kvm/arm_hypercalls.h                  |  17 +
 include/kvm/arm_psci.h                        |   9 +-
 tools/include/linux/arm-smccc.h               | 193 ++++++++++
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/aarch64/get-reg-list.c      |   8 +
 .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
 16 files changed, 1065 insertions(+), 269 deletions(-)
 create mode 100644 Documentation/virt/kvm/arm/hypercalls.rst
 delete mode 100644 Documentation/virt/kvm/arm/psci.rst
 create mode 100644 tools/include/linux/arm-smccc.h
 create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c

-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
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] 90+ messages in thread

* [PATCH v6 1/9] KVM: arm64: Factor out firmware register handling from psci.c
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm, Gavin Shan

Common hypercall firmware register handing is currently employed
by psci.c. Since the upcoming patches add more of these registers,
it's better to move the generic handling to hypercall.c for a
cleaner presentation.

While we are at it, collect all the firmware registers under
fw_reg_ids[] to help implement kvm_arm_get_fw_num_regs() and
kvm_arm_copy_fw_reg_indices() in a generic way. Also, define
KVM_REG_FEATURE_LEVEL_MASK using a GENMASK instead.

No functional change intended.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
---
 arch/arm64/kvm/guest.c       |   2 +-
 arch/arm64/kvm/hypercalls.c  | 185 +++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/psci.c        | 183 ----------------------------------
 include/kvm/arm_hypercalls.h |   7 ++
 include/kvm/arm_psci.h       |   7 --
 5 files changed, 193 insertions(+), 191 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 7e15b03fbdf8..0d5cca56cbda 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -18,7 +18,7 @@
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
-#include <kvm/arm_psci.h>
+#include <kvm/arm_hypercalls.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/fpsimd.h>
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 202b8c455724..fa6d9378d8e7 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -158,3 +158,188 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
 	return 1;
 }
+
+static const u64 kvm_arm_fw_reg_ids[] = {
+	KVM_REG_ARM_PSCI_VERSION,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
+};
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
+{
+	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
+}
+
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) {
+		if (put_user(kvm_arm_fw_reg_ids[i], uindices++))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+#define KVM_REG_FEATURE_LEVEL_WIDTH	4
+#define KVM_REG_FEATURE_LEVEL_MASK	GENMASK(KVM_REG_FEATURE_LEVEL_WIDTH, 0)
+
+/*
+ * Convert the workaround level into an easy-to-compare number, where higher
+ * values mean better protection.
+ */
+static int get_kernel_wa_level(u64 regid)
+{
+	switch (regid) {
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+		switch (arm64_get_spectre_v2_state()) {
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
+		case SPECTRE_MITIGATED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
+		}
+		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+		switch (arm64_get_spectre_v4_state()) {
+		case SPECTRE_MITIGATED:
+			/*
+			 * As for the hypercall discovery, we pretend we
+			 * don't have any FW mitigation if SSBS is there at
+			 * all times.
+			 */
+			if (cpus_have_final_cap(ARM64_SSBS))
+				return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+			fallthrough;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+		}
+		break;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		switch (arm64_get_spectre_bhb_state()) {
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+		case SPECTRE_MITIGATED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
+		}
+		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+	}
+
+	return -EINVAL;
+}
+
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	void __user *uaddr = (void __user *)(long)reg->addr;
+	u64 val;
+
+	switch (reg->id) {
+	case KVM_REG_ARM_PSCI_VERSION:
+		val = kvm_psci_version(vcpu);
+		break;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
+		return -EFAULT;
+
+	return 0;
+}
+
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	void __user *uaddr = (void __user *)(long)reg->addr;
+	u64 val;
+	int wa_level;
+
+	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
+		return -EFAULT;
+
+	switch (reg->id) {
+	case KVM_REG_ARM_PSCI_VERSION:
+	{
+		bool wants_02;
+
+		wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
+
+		switch (val) {
+		case KVM_ARM_PSCI_0_1:
+			if (wants_02)
+				return -EINVAL;
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		case KVM_ARM_PSCI_0_2:
+		case KVM_ARM_PSCI_1_0:
+		case KVM_ARM_PSCI_1_1:
+			if (!wants_02)
+				return -EINVAL;
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		}
+		break;
+	}
+
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
+			return -EINVAL;
+
+		if (get_kernel_wa_level(reg->id) < val)
+			return -EINVAL;
+
+		return 0;
+
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+		if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
+			    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
+			return -EINVAL;
+
+		/* The enabled bit must not be set unless the level is AVAIL. */
+		if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
+		    (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
+			return -EINVAL;
+
+		/*
+		 * Map all the possible incoming states to the only two we
+		 * really want to deal with.
+		 */
+		switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
+			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+			break;
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
+			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/*
+		 * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
+		 * other way around.
+		 */
+		if (get_kernel_wa_level(reg->id) < wa_level)
+			return -EINVAL;
+
+		return 0;
+	default:
+		return -ENOENT;
+	}
+
+	return -EINVAL;
+}
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index baac2b405f23..346535169faa 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -436,186 +436,3 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 }
-
-int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
-{
-	return 4;		/* PSCI version and three workaround registers */
-}
-
-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;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, uindices++))
-		return -EFAULT;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++))
-		return -EFAULT;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, uindices++))
-		return -EFAULT;
-
-	return 0;
-}
-
-#define KVM_REG_FEATURE_LEVEL_WIDTH	4
-#define KVM_REG_FEATURE_LEVEL_MASK	(BIT(KVM_REG_FEATURE_LEVEL_WIDTH) - 1)
-
-/*
- * Convert the workaround level into an easy-to-compare number, where higher
- * values mean better protection.
- */
-static int get_kernel_wa_level(u64 regid)
-{
-	switch (regid) {
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-		switch (arm64_get_spectre_v2_state()) {
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
-		case SPECTRE_MITIGATED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
-		}
-		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-		switch (arm64_get_spectre_v4_state()) {
-		case SPECTRE_MITIGATED:
-			/*
-			 * As for the hypercall discovery, we pretend we
-			 * don't have any FW mitigation if SSBS is there at
-			 * all times.
-			 */
-			if (cpus_have_final_cap(ARM64_SSBS))
-				return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-			fallthrough;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-		}
-		break;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		switch (arm64_get_spectre_bhb_state()) {
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
-		case SPECTRE_MITIGATED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
-		}
-		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
-	}
-
-	return -EINVAL;
-}
-
-int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
-{
-	void __user *uaddr = (void __user *)(long)reg->addr;
-	u64 val;
-
-	switch (reg->id) {
-	case KVM_REG_ARM_PSCI_VERSION:
-		val = kvm_psci_version(vcpu);
-		break;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
-		break;
-	default:
-		return -ENOENT;
-	}
-
-	if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
-		return -EFAULT;
-
-	return 0;
-}
-
-int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
-{
-	void __user *uaddr = (void __user *)(long)reg->addr;
-	u64 val;
-	int wa_level;
-
-	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
-		return -EFAULT;
-
-	switch (reg->id) {
-	case KVM_REG_ARM_PSCI_VERSION:
-	{
-		bool wants_02;
-
-		wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
-
-		switch (val) {
-		case KVM_ARM_PSCI_0_1:
-			if (wants_02)
-				return -EINVAL;
-			vcpu->kvm->arch.psci_version = val;
-			return 0;
-		case KVM_ARM_PSCI_0_2:
-		case KVM_ARM_PSCI_1_0:
-		case KVM_ARM_PSCI_1_1:
-			if (!wants_02)
-				return -EINVAL;
-			vcpu->kvm->arch.psci_version = val;
-			return 0;
-		}
-		break;
-	}
-
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
-			return -EINVAL;
-
-		if (get_kernel_wa_level(reg->id) < val)
-			return -EINVAL;
-
-		return 0;
-
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-		if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
-			    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
-			return -EINVAL;
-
-		/* The enabled bit must not be set unless the level is AVAIL. */
-		if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
-		    (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
-			return -EINVAL;
-
-		/*
-		 * Map all the possible incoming states to the only two we
-		 * really want to deal with.
-		 */
-		switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
-			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-			break;
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
-			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
-			break;
-		default:
-			return -EINVAL;
-		}
-
-		/*
-		 * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
-		 * other way around.
-		 */
-		if (get_kernel_wa_level(reg->id) < wa_level)
-			return -EINVAL;
-
-		return 0;
-	default:
-		return -ENOENT;
-	}
-
-	return -EINVAL;
-}
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 0e2509d27910..5d38628a8d04 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -40,4 +40,11 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, 3, a3);
 }
 
+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
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 68b96c3826c3..6e55b9283789 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -39,11 +39,4 @@ static inline 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__ */
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 1/9] KVM: arm64: Factor out firmware register handling from psci.c
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Common hypercall firmware register handing is currently employed
by psci.c. Since the upcoming patches add more of these registers,
it's better to move the generic handling to hypercall.c for a
cleaner presentation.

While we are at it, collect all the firmware registers under
fw_reg_ids[] to help implement kvm_arm_get_fw_num_regs() and
kvm_arm_copy_fw_reg_indices() in a generic way. Also, define
KVM_REG_FEATURE_LEVEL_MASK using a GENMASK instead.

No functional change intended.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
---
 arch/arm64/kvm/guest.c       |   2 +-
 arch/arm64/kvm/hypercalls.c  | 185 +++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/psci.c        | 183 ----------------------------------
 include/kvm/arm_hypercalls.h |   7 ++
 include/kvm/arm_psci.h       |   7 --
 5 files changed, 193 insertions(+), 191 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 7e15b03fbdf8..0d5cca56cbda 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -18,7 +18,7 @@
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
-#include <kvm/arm_psci.h>
+#include <kvm/arm_hypercalls.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/fpsimd.h>
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 202b8c455724..fa6d9378d8e7 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -158,3 +158,188 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
 	return 1;
 }
+
+static const u64 kvm_arm_fw_reg_ids[] = {
+	KVM_REG_ARM_PSCI_VERSION,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
+};
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
+{
+	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
+}
+
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) {
+		if (put_user(kvm_arm_fw_reg_ids[i], uindices++))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+#define KVM_REG_FEATURE_LEVEL_WIDTH	4
+#define KVM_REG_FEATURE_LEVEL_MASK	GENMASK(KVM_REG_FEATURE_LEVEL_WIDTH, 0)
+
+/*
+ * Convert the workaround level into an easy-to-compare number, where higher
+ * values mean better protection.
+ */
+static int get_kernel_wa_level(u64 regid)
+{
+	switch (regid) {
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+		switch (arm64_get_spectre_v2_state()) {
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
+		case SPECTRE_MITIGATED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
+		}
+		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+		switch (arm64_get_spectre_v4_state()) {
+		case SPECTRE_MITIGATED:
+			/*
+			 * As for the hypercall discovery, we pretend we
+			 * don't have any FW mitigation if SSBS is there at
+			 * all times.
+			 */
+			if (cpus_have_final_cap(ARM64_SSBS))
+				return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+			fallthrough;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+		}
+		break;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		switch (arm64_get_spectre_bhb_state()) {
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+		case SPECTRE_MITIGATED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
+		}
+		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+	}
+
+	return -EINVAL;
+}
+
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	void __user *uaddr = (void __user *)(long)reg->addr;
+	u64 val;
+
+	switch (reg->id) {
+	case KVM_REG_ARM_PSCI_VERSION:
+		val = kvm_psci_version(vcpu);
+		break;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
+		return -EFAULT;
+
+	return 0;
+}
+
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	void __user *uaddr = (void __user *)(long)reg->addr;
+	u64 val;
+	int wa_level;
+
+	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
+		return -EFAULT;
+
+	switch (reg->id) {
+	case KVM_REG_ARM_PSCI_VERSION:
+	{
+		bool wants_02;
+
+		wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
+
+		switch (val) {
+		case KVM_ARM_PSCI_0_1:
+			if (wants_02)
+				return -EINVAL;
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		case KVM_ARM_PSCI_0_2:
+		case KVM_ARM_PSCI_1_0:
+		case KVM_ARM_PSCI_1_1:
+			if (!wants_02)
+				return -EINVAL;
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		}
+		break;
+	}
+
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
+			return -EINVAL;
+
+		if (get_kernel_wa_level(reg->id) < val)
+			return -EINVAL;
+
+		return 0;
+
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+		if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
+			    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
+			return -EINVAL;
+
+		/* The enabled bit must not be set unless the level is AVAIL. */
+		if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
+		    (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
+			return -EINVAL;
+
+		/*
+		 * Map all the possible incoming states to the only two we
+		 * really want to deal with.
+		 */
+		switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
+			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+			break;
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
+			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/*
+		 * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
+		 * other way around.
+		 */
+		if (get_kernel_wa_level(reg->id) < wa_level)
+			return -EINVAL;
+
+		return 0;
+	default:
+		return -ENOENT;
+	}
+
+	return -EINVAL;
+}
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index baac2b405f23..346535169faa 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -436,186 +436,3 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 }
-
-int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
-{
-	return 4;		/* PSCI version and three workaround registers */
-}
-
-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;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, uindices++))
-		return -EFAULT;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++))
-		return -EFAULT;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, uindices++))
-		return -EFAULT;
-
-	return 0;
-}
-
-#define KVM_REG_FEATURE_LEVEL_WIDTH	4
-#define KVM_REG_FEATURE_LEVEL_MASK	(BIT(KVM_REG_FEATURE_LEVEL_WIDTH) - 1)
-
-/*
- * Convert the workaround level into an easy-to-compare number, where higher
- * values mean better protection.
- */
-static int get_kernel_wa_level(u64 regid)
-{
-	switch (regid) {
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-		switch (arm64_get_spectre_v2_state()) {
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
-		case SPECTRE_MITIGATED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
-		}
-		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-		switch (arm64_get_spectre_v4_state()) {
-		case SPECTRE_MITIGATED:
-			/*
-			 * As for the hypercall discovery, we pretend we
-			 * don't have any FW mitigation if SSBS is there at
-			 * all times.
-			 */
-			if (cpus_have_final_cap(ARM64_SSBS))
-				return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-			fallthrough;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-		}
-		break;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		switch (arm64_get_spectre_bhb_state()) {
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
-		case SPECTRE_MITIGATED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
-		}
-		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
-	}
-
-	return -EINVAL;
-}
-
-int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
-{
-	void __user *uaddr = (void __user *)(long)reg->addr;
-	u64 val;
-
-	switch (reg->id) {
-	case KVM_REG_ARM_PSCI_VERSION:
-		val = kvm_psci_version(vcpu);
-		break;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
-		break;
-	default:
-		return -ENOENT;
-	}
-
-	if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
-		return -EFAULT;
-
-	return 0;
-}
-
-int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
-{
-	void __user *uaddr = (void __user *)(long)reg->addr;
-	u64 val;
-	int wa_level;
-
-	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
-		return -EFAULT;
-
-	switch (reg->id) {
-	case KVM_REG_ARM_PSCI_VERSION:
-	{
-		bool wants_02;
-
-		wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
-
-		switch (val) {
-		case KVM_ARM_PSCI_0_1:
-			if (wants_02)
-				return -EINVAL;
-			vcpu->kvm->arch.psci_version = val;
-			return 0;
-		case KVM_ARM_PSCI_0_2:
-		case KVM_ARM_PSCI_1_0:
-		case KVM_ARM_PSCI_1_1:
-			if (!wants_02)
-				return -EINVAL;
-			vcpu->kvm->arch.psci_version = val;
-			return 0;
-		}
-		break;
-	}
-
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
-			return -EINVAL;
-
-		if (get_kernel_wa_level(reg->id) < val)
-			return -EINVAL;
-
-		return 0;
-
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-		if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
-			    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
-			return -EINVAL;
-
-		/* The enabled bit must not be set unless the level is AVAIL. */
-		if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
-		    (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
-			return -EINVAL;
-
-		/*
-		 * Map all the possible incoming states to the only two we
-		 * really want to deal with.
-		 */
-		switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
-			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-			break;
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
-			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
-			break;
-		default:
-			return -EINVAL;
-		}
-
-		/*
-		 * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
-		 * other way around.
-		 */
-		if (get_kernel_wa_level(reg->id) < wa_level)
-			return -EINVAL;
-
-		return 0;
-	default:
-		return -ENOENT;
-	}
-
-	return -EINVAL;
-}
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 0e2509d27910..5d38628a8d04 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -40,4 +40,11 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, 3, a3);
 }
 
+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
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 68b96c3826c3..6e55b9283789 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -39,11 +39,4 @@ static inline 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__ */
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 1/9] KVM: arm64: Factor out firmware register handling from psci.c
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm, Gavin Shan

Common hypercall firmware register handing is currently employed
by psci.c. Since the upcoming patches add more of these registers,
it's better to move the generic handling to hypercall.c for a
cleaner presentation.

While we are at it, collect all the firmware registers under
fw_reg_ids[] to help implement kvm_arm_get_fw_num_regs() and
kvm_arm_copy_fw_reg_indices() in a generic way. Also, define
KVM_REG_FEATURE_LEVEL_MASK using a GENMASK instead.

No functional change intended.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
---
 arch/arm64/kvm/guest.c       |   2 +-
 arch/arm64/kvm/hypercalls.c  | 185 +++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/psci.c        | 183 ----------------------------------
 include/kvm/arm_hypercalls.h |   7 ++
 include/kvm/arm_psci.h       |   7 --
 5 files changed, 193 insertions(+), 191 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 7e15b03fbdf8..0d5cca56cbda 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -18,7 +18,7 @@
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
-#include <kvm/arm_psci.h>
+#include <kvm/arm_hypercalls.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
 #include <asm/fpsimd.h>
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 202b8c455724..fa6d9378d8e7 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -158,3 +158,188 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
 	return 1;
 }
+
+static const u64 kvm_arm_fw_reg_ids[] = {
+	KVM_REG_ARM_PSCI_VERSION,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
+	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
+};
+
+int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
+{
+	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
+}
+
+int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) {
+		if (put_user(kvm_arm_fw_reg_ids[i], uindices++))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+#define KVM_REG_FEATURE_LEVEL_WIDTH	4
+#define KVM_REG_FEATURE_LEVEL_MASK	GENMASK(KVM_REG_FEATURE_LEVEL_WIDTH, 0)
+
+/*
+ * Convert the workaround level into an easy-to-compare number, where higher
+ * values mean better protection.
+ */
+static int get_kernel_wa_level(u64 regid)
+{
+	switch (regid) {
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+		switch (arm64_get_spectre_v2_state()) {
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
+		case SPECTRE_MITIGATED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
+		}
+		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+		switch (arm64_get_spectre_v4_state()) {
+		case SPECTRE_MITIGATED:
+			/*
+			 * As for the hypercall discovery, we pretend we
+			 * don't have any FW mitigation if SSBS is there at
+			 * all times.
+			 */
+			if (cpus_have_final_cap(ARM64_SSBS))
+				return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+			fallthrough;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+		}
+		break;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		switch (arm64_get_spectre_bhb_state()) {
+		case SPECTRE_VULNERABLE:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+		case SPECTRE_MITIGATED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
+		case SPECTRE_UNAFFECTED:
+			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
+		}
+		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+	}
+
+	return -EINVAL;
+}
+
+int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	void __user *uaddr = (void __user *)(long)reg->addr;
+	u64 val;
+
+	switch (reg->id) {
+	case KVM_REG_ARM_PSCI_VERSION:
+		val = kvm_psci_version(vcpu);
+		break;
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
+		return -EFAULT;
+
+	return 0;
+}
+
+int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	void __user *uaddr = (void __user *)(long)reg->addr;
+	u64 val;
+	int wa_level;
+
+	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
+		return -EFAULT;
+
+	switch (reg->id) {
+	case KVM_REG_ARM_PSCI_VERSION:
+	{
+		bool wants_02;
+
+		wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
+
+		switch (val) {
+		case KVM_ARM_PSCI_0_1:
+			if (wants_02)
+				return -EINVAL;
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		case KVM_ARM_PSCI_0_2:
+		case KVM_ARM_PSCI_1_0:
+		case KVM_ARM_PSCI_1_1:
+			if (!wants_02)
+				return -EINVAL;
+			vcpu->kvm->arch.psci_version = val;
+			return 0;
+		}
+		break;
+	}
+
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+		if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
+			return -EINVAL;
+
+		if (get_kernel_wa_level(reg->id) < val)
+			return -EINVAL;
+
+		return 0;
+
+	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+		if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
+			    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
+			return -EINVAL;
+
+		/* The enabled bit must not be set unless the level is AVAIL. */
+		if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
+		    (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
+			return -EINVAL;
+
+		/*
+		 * Map all the possible incoming states to the only two we
+		 * really want to deal with.
+		 */
+		switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
+			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+			break;
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
+		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
+			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/*
+		 * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
+		 * other way around.
+		 */
+		if (get_kernel_wa_level(reg->id) < wa_level)
+			return -EINVAL;
+
+		return 0;
+	default:
+		return -ENOENT;
+	}
+
+	return -EINVAL;
+}
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index baac2b405f23..346535169faa 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -436,186 +436,3 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 }
-
-int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
-{
-	return 4;		/* PSCI version and three workaround registers */
-}
-
-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;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, uindices++))
-		return -EFAULT;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++))
-		return -EFAULT;
-
-	if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, uindices++))
-		return -EFAULT;
-
-	return 0;
-}
-
-#define KVM_REG_FEATURE_LEVEL_WIDTH	4
-#define KVM_REG_FEATURE_LEVEL_MASK	(BIT(KVM_REG_FEATURE_LEVEL_WIDTH) - 1)
-
-/*
- * Convert the workaround level into an easy-to-compare number, where higher
- * values mean better protection.
- */
-static int get_kernel_wa_level(u64 regid)
-{
-	switch (regid) {
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-		switch (arm64_get_spectre_v2_state()) {
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
-		case SPECTRE_MITIGATED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
-		}
-		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-		switch (arm64_get_spectre_v4_state()) {
-		case SPECTRE_MITIGATED:
-			/*
-			 * As for the hypercall discovery, we pretend we
-			 * don't have any FW mitigation if SSBS is there at
-			 * all times.
-			 */
-			if (cpus_have_final_cap(ARM64_SSBS))
-				return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-			fallthrough;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-		}
-		break;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		switch (arm64_get_spectre_bhb_state()) {
-		case SPECTRE_VULNERABLE:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
-		case SPECTRE_MITIGATED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
-		case SPECTRE_UNAFFECTED:
-			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
-		}
-		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
-	}
-
-	return -EINVAL;
-}
-
-int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
-{
-	void __user *uaddr = (void __user *)(long)reg->addr;
-	u64 val;
-
-	switch (reg->id) {
-	case KVM_REG_ARM_PSCI_VERSION:
-		val = kvm_psci_version(vcpu);
-		break;
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
-		break;
-	default:
-		return -ENOENT;
-	}
-
-	if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
-		return -EFAULT;
-
-	return 0;
-}
-
-int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
-{
-	void __user *uaddr = (void __user *)(long)reg->addr;
-	u64 val;
-	int wa_level;
-
-	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
-		return -EFAULT;
-
-	switch (reg->id) {
-	case KVM_REG_ARM_PSCI_VERSION:
-	{
-		bool wants_02;
-
-		wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
-
-		switch (val) {
-		case KVM_ARM_PSCI_0_1:
-			if (wants_02)
-				return -EINVAL;
-			vcpu->kvm->arch.psci_version = val;
-			return 0;
-		case KVM_ARM_PSCI_0_2:
-		case KVM_ARM_PSCI_1_0:
-		case KVM_ARM_PSCI_1_1:
-			if (!wants_02)
-				return -EINVAL;
-			vcpu->kvm->arch.psci_version = val;
-			return 0;
-		}
-		break;
-	}
-
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
-		if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
-			return -EINVAL;
-
-		if (get_kernel_wa_level(reg->id) < val)
-			return -EINVAL;
-
-		return 0;
-
-	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-		if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
-			    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
-			return -EINVAL;
-
-		/* The enabled bit must not be set unless the level is AVAIL. */
-		if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
-		    (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
-			return -EINVAL;
-
-		/*
-		 * Map all the possible incoming states to the only two we
-		 * really want to deal with.
-		 */
-		switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
-			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-			break;
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
-		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
-			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
-			break;
-		default:
-			return -EINVAL;
-		}
-
-		/*
-		 * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
-		 * other way around.
-		 */
-		if (get_kernel_wa_level(reg->id) < wa_level)
-			return -EINVAL;
-
-		return 0;
-	default:
-		return -ENOENT;
-	}
-
-	return -EINVAL;
-}
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 0e2509d27910..5d38628a8d04 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -40,4 +40,11 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, 3, a3);
 }
 
+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
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 68b96c3826c3..6e55b9283789 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -39,11 +39,4 @@ static inline 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__ */
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

KVM regularly introduces new hypercall services to the guests without
any consent from the userspace. This means, the guests can observe
hypercall services in and out as they migrate across various host
kernel versions. This could be a major problem if the guest
discovered a hypercall, started using it, and after getting migrated
to an older kernel realizes that it's no longer available. Depending
on how the guest handles the change, there's a potential chance that
the guest would just panic.

As a result, there's a need for the userspace to elect the services
that it wishes the guest to discover. It can elect these services
based on the kernels spread across its (migration) fleet. To remedy
this, extend the existing firmware pseudo-registers, such as
KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
for all the hypercall services available.

These firmware registers are categorized based on the service call
owners, but unlike the existing firmware pseudo-registers, they hold
the features supported in the form of a bitmap.

During the VM initialization, the registers are set to upper-limit of
the features supported by the corresponding registers. It's expected
that the VMMs discover the features provided by each register via
GET_ONE_REG, and write back the desired values using SET_ONE_REG.
KVM allows this modification only until the VM has started.

Some of the standard features are not mapped to any bits of the
registers. But since they can recreate the original problem of
making it available without userspace's consent, they need to
be explicitly added to the case-list in
kvm_hvc_call_default_allowed(). Any function-id that's not enabled
via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
be returned as SMCCC_RET_NOT_SUPPORTED to the guest.

Older userspace code can simply ignore the feature and the
hypercall services will be exposed unconditionally to the guests,
thus ensuring backward compatibility.

In this patch, the framework adds the register only for ARM's standard
secure services (owner value 4). Currently, this includes support only
for ARM True Random Number Generator (TRNG) service, with bit-0 of the
register representing mandatory features of v1.0. Other services are
momentarily added in the upcoming patches.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h | 12 ++++
 arch/arm64/include/uapi/asm/kvm.h |  9 +++
 arch/arm64/kvm/arm.c              |  1 +
 arch/arm64/kvm/guest.c            |  8 ++-
 arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
 arch/arm64/kvm/psci.c             | 13 +++++
 include/kvm/arm_hypercalls.h      |  6 ++
 include/kvm/arm_psci.h            |  2 +-
 8 files changed, 142 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 94a27a7520f4..df07f4c10197 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -101,6 +101,15 @@ struct kvm_s2_mmu {
 struct kvm_arch_memory_slot {
 };
 
+/**
+ * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
+ *
+ * @std_bmap: Bitmap of standard secure service calls
+ */
+struct kvm_smccc_features {
+	unsigned long std_bmap;
+};
+
 struct kvm_arch {
 	struct kvm_s2_mmu mmu;
 
@@ -150,6 +159,9 @@ struct kvm_arch {
 
 	u8 pfr0_csv2;
 	u8 pfr0_csv3;
+
+	/* Hypercall features firmware registers' descriptor */
+	struct kvm_smccc_features smccc_feat;
 };
 
 struct kvm_vcpu_fault_info {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index c1b6ddc02d2f..0b79d2dc6ffd 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_ARM64_SVE_VLS_WORDS	\
 	((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
 
+/* Bitmap feature firmware registers */
+#define KVM_REG_ARM_FW_FEAT_BMAP		(0x0016 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+						KVM_REG_ARM_FW_FEAT_BMAP |	\
+						((r) & 0xffff))
+
+#define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
+#define KVM_REG_ARM_STD_BIT_TRNG_V1_0		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/arm.c b/arch/arm64/kvm/arm.c
index 523bc934fe2f..a37fadbd617e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
 
 	set_default_spectre(kvm);
+	kvm_arm_init_hypercalls(kvm);
 
 	return ret;
 out_free_stage2_pgd:
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 0d5cca56cbda..8c607199cad1 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
-	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		return kvm_arm_get_fw_reg(vcpu, reg);
 	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
 	}
 
@@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
-	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		return kvm_arm_set_fw_reg(vcpu, reg);
 	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
 	}
 
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index fa6d9378d8e7..df55a04d2fe8 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
 	val[3] = lower_32_bits(cycles);
 }
 
+static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
+{
+	return test_bit(feat_bit, reg_bmap);
+}
+
+static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	switch (func_id) {
+	/*
+	 * List of function-ids that are not gated with the bitmapped feature
+	 * firmware registers, and are to be allowed for servicing the call by default.
+	 */
+	case ARM_SMCCC_VERSION_FUNC_ID:
+	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
+	case ARM_SMCCC_HV_PV_TIME_FEATURES:
+	case ARM_SMCCC_HV_PV_TIME_ST:
+	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
+		return true;
+	default:
+		return kvm_psci_func_id_is_valid(vcpu, func_id);
+	}
+}
+
+static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
+
+	switch (func_id) {
+	case ARM_SMCCC_TRNG_VERSION:
+	case ARM_SMCCC_TRNG_FEATURES:
+	case ARM_SMCCC_TRNG_GET_UUID:
+	case ARM_SMCCC_TRNG_RND32:
+	case ARM_SMCCC_TRNG_RND64:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
+						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
+	default:
+		return kvm_hvc_call_default_allowed(vcpu, func_id);
+	}
+}
+
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
 	u32 func_id = smccc_get_function(vcpu);
@@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 	u32 feature;
 	gpa_t gpa;
 
+	if (!kvm_hvc_call_allowed(vcpu, func_id))
+		goto out;
+
 	switch (func_id) {
 	case ARM_SMCCC_VERSION_FUNC_ID:
 		val[0] = ARM_SMCCC_VERSION_1_1;
@@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 		return kvm_psci_call(vcpu);
 	}
 
+out:
 	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
 	return 1;
 }
@@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
+	KVM_REG_ARM_STD_BMAP,
 };
 
+void kvm_arm_init_hypercalls(struct kvm *kvm)
+{
+	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
+
+	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
+}
+
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
 	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
@@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
 
 int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
 	void __user *uaddr = (void __user *)(long)reg->addr;
 	u64 val;
 
@@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
 		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
 		break;
+	case KVM_REG_ARM_STD_BMAP:
+		val = READ_ONCE(smccc_feat->std_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return 0;
 }
 
+static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
+{
+	int ret = 0;
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
+	unsigned long *fw_reg_bmap, fw_reg_features;
+
+	switch (reg_id) {
+	case KVM_REG_ARM_STD_BMAP:
+		fw_reg_bmap = &smccc_feat->std_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	/* Check for unsupported bit */
+	if (val & ~fw_reg_features)
+		return -EINVAL;
+
+	mutex_lock(&kvm->lock);
+
+	/* Return -EBUSY if the VM (any vCPU) has already started running. */
+	if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	WRITE_ONCE(*fw_reg_bmap, val);
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	void __user *uaddr = (void __user *)(long)reg->addr;
@@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 			return -EINVAL;
 
 		return 0;
+	case KVM_REG_ARM_STD_BMAP:
+		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
 	}
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index 346535169faa..67d1273e8086 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 }
+
+bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	/* PSCI 0.1 doesn't comply with the standard SMCCC */
+	if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
+		return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
+
+	if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
+		ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
+		return true;
+
+	return false;
+}
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 5d38628a8d04..499b45b607b6 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -6,6 +6,11 @@
 
 #include <asm/kvm_emulate.h>
 
+/* Last valid bits of the bitmapped firmware registers */
+#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+
+#define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
+
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
 static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
@@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
 
 struct kvm_one_reg;
 
+void kvm_arm_init_hypercalls(struct kvm *kvm);
 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);
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 6e55b9283789..c47be3e26965 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
 	return KVM_ARM_PSCI_0_1;
 }
 
-
 int kvm_psci_call(struct kvm_vcpu *vcpu);
+bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
 
 #endif /* __KVM_ARM_PSCI_H__ */
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

KVM regularly introduces new hypercall services to the guests without
any consent from the userspace. This means, the guests can observe
hypercall services in and out as they migrate across various host
kernel versions. This could be a major problem if the guest
discovered a hypercall, started using it, and after getting migrated
to an older kernel realizes that it's no longer available. Depending
on how the guest handles the change, there's a potential chance that
the guest would just panic.

As a result, there's a need for the userspace to elect the services
that it wishes the guest to discover. It can elect these services
based on the kernels spread across its (migration) fleet. To remedy
this, extend the existing firmware pseudo-registers, such as
KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
for all the hypercall services available.

These firmware registers are categorized based on the service call
owners, but unlike the existing firmware pseudo-registers, they hold
the features supported in the form of a bitmap.

During the VM initialization, the registers are set to upper-limit of
the features supported by the corresponding registers. It's expected
that the VMMs discover the features provided by each register via
GET_ONE_REG, and write back the desired values using SET_ONE_REG.
KVM allows this modification only until the VM has started.

Some of the standard features are not mapped to any bits of the
registers. But since they can recreate the original problem of
making it available without userspace's consent, they need to
be explicitly added to the case-list in
kvm_hvc_call_default_allowed(). Any function-id that's not enabled
via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
be returned as SMCCC_RET_NOT_SUPPORTED to the guest.

Older userspace code can simply ignore the feature and the
hypercall services will be exposed unconditionally to the guests,
thus ensuring backward compatibility.

In this patch, the framework adds the register only for ARM's standard
secure services (owner value 4). Currently, this includes support only
for ARM True Random Number Generator (TRNG) service, with bit-0 of the
register representing mandatory features of v1.0. Other services are
momentarily added in the upcoming patches.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h | 12 ++++
 arch/arm64/include/uapi/asm/kvm.h |  9 +++
 arch/arm64/kvm/arm.c              |  1 +
 arch/arm64/kvm/guest.c            |  8 ++-
 arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
 arch/arm64/kvm/psci.c             | 13 +++++
 include/kvm/arm_hypercalls.h      |  6 ++
 include/kvm/arm_psci.h            |  2 +-
 8 files changed, 142 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 94a27a7520f4..df07f4c10197 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -101,6 +101,15 @@ struct kvm_s2_mmu {
 struct kvm_arch_memory_slot {
 };
 
+/**
+ * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
+ *
+ * @std_bmap: Bitmap of standard secure service calls
+ */
+struct kvm_smccc_features {
+	unsigned long std_bmap;
+};
+
 struct kvm_arch {
 	struct kvm_s2_mmu mmu;
 
@@ -150,6 +159,9 @@ struct kvm_arch {
 
 	u8 pfr0_csv2;
 	u8 pfr0_csv3;
+
+	/* Hypercall features firmware registers' descriptor */
+	struct kvm_smccc_features smccc_feat;
 };
 
 struct kvm_vcpu_fault_info {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index c1b6ddc02d2f..0b79d2dc6ffd 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_ARM64_SVE_VLS_WORDS	\
 	((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
 
+/* Bitmap feature firmware registers */
+#define KVM_REG_ARM_FW_FEAT_BMAP		(0x0016 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+						KVM_REG_ARM_FW_FEAT_BMAP |	\
+						((r) & 0xffff))
+
+#define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
+#define KVM_REG_ARM_STD_BIT_TRNG_V1_0		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/arm.c b/arch/arm64/kvm/arm.c
index 523bc934fe2f..a37fadbd617e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
 
 	set_default_spectre(kvm);
+	kvm_arm_init_hypercalls(kvm);
 
 	return ret;
 out_free_stage2_pgd:
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 0d5cca56cbda..8c607199cad1 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
-	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		return kvm_arm_get_fw_reg(vcpu, reg);
 	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
 	}
 
@@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
-	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		return kvm_arm_set_fw_reg(vcpu, reg);
 	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
 	}
 
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index fa6d9378d8e7..df55a04d2fe8 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
 	val[3] = lower_32_bits(cycles);
 }
 
+static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
+{
+	return test_bit(feat_bit, reg_bmap);
+}
+
+static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	switch (func_id) {
+	/*
+	 * List of function-ids that are not gated with the bitmapped feature
+	 * firmware registers, and are to be allowed for servicing the call by default.
+	 */
+	case ARM_SMCCC_VERSION_FUNC_ID:
+	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
+	case ARM_SMCCC_HV_PV_TIME_FEATURES:
+	case ARM_SMCCC_HV_PV_TIME_ST:
+	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
+		return true;
+	default:
+		return kvm_psci_func_id_is_valid(vcpu, func_id);
+	}
+}
+
+static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
+
+	switch (func_id) {
+	case ARM_SMCCC_TRNG_VERSION:
+	case ARM_SMCCC_TRNG_FEATURES:
+	case ARM_SMCCC_TRNG_GET_UUID:
+	case ARM_SMCCC_TRNG_RND32:
+	case ARM_SMCCC_TRNG_RND64:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
+						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
+	default:
+		return kvm_hvc_call_default_allowed(vcpu, func_id);
+	}
+}
+
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
 	u32 func_id = smccc_get_function(vcpu);
@@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 	u32 feature;
 	gpa_t gpa;
 
+	if (!kvm_hvc_call_allowed(vcpu, func_id))
+		goto out;
+
 	switch (func_id) {
 	case ARM_SMCCC_VERSION_FUNC_ID:
 		val[0] = ARM_SMCCC_VERSION_1_1;
@@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 		return kvm_psci_call(vcpu);
 	}
 
+out:
 	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
 	return 1;
 }
@@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
+	KVM_REG_ARM_STD_BMAP,
 };
 
+void kvm_arm_init_hypercalls(struct kvm *kvm)
+{
+	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
+
+	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
+}
+
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
 	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
@@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
 
 int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
 	void __user *uaddr = (void __user *)(long)reg->addr;
 	u64 val;
 
@@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
 		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
 		break;
+	case KVM_REG_ARM_STD_BMAP:
+		val = READ_ONCE(smccc_feat->std_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return 0;
 }
 
+static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
+{
+	int ret = 0;
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
+	unsigned long *fw_reg_bmap, fw_reg_features;
+
+	switch (reg_id) {
+	case KVM_REG_ARM_STD_BMAP:
+		fw_reg_bmap = &smccc_feat->std_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	/* Check for unsupported bit */
+	if (val & ~fw_reg_features)
+		return -EINVAL;
+
+	mutex_lock(&kvm->lock);
+
+	/* Return -EBUSY if the VM (any vCPU) has already started running. */
+	if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	WRITE_ONCE(*fw_reg_bmap, val);
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	void __user *uaddr = (void __user *)(long)reg->addr;
@@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 			return -EINVAL;
 
 		return 0;
+	case KVM_REG_ARM_STD_BMAP:
+		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
 	}
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index 346535169faa..67d1273e8086 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 }
+
+bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	/* PSCI 0.1 doesn't comply with the standard SMCCC */
+	if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
+		return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
+
+	if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
+		ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
+		return true;
+
+	return false;
+}
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 5d38628a8d04..499b45b607b6 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -6,6 +6,11 @@
 
 #include <asm/kvm_emulate.h>
 
+/* Last valid bits of the bitmapped firmware registers */
+#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+
+#define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
+
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
 static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
@@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
 
 struct kvm_one_reg;
 
+void kvm_arm_init_hypercalls(struct kvm *kvm);
 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);
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 6e55b9283789..c47be3e26965 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
 	return KVM_ARM_PSCI_0_1;
 }
 
-
 int kvm_psci_call(struct kvm_vcpu *vcpu);
+bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
 
 #endif /* __KVM_ARM_PSCI_H__ */
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

KVM regularly introduces new hypercall services to the guests without
any consent from the userspace. This means, the guests can observe
hypercall services in and out as they migrate across various host
kernel versions. This could be a major problem if the guest
discovered a hypercall, started using it, and after getting migrated
to an older kernel realizes that it's no longer available. Depending
on how the guest handles the change, there's a potential chance that
the guest would just panic.

As a result, there's a need for the userspace to elect the services
that it wishes the guest to discover. It can elect these services
based on the kernels spread across its (migration) fleet. To remedy
this, extend the existing firmware pseudo-registers, such as
KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
for all the hypercall services available.

These firmware registers are categorized based on the service call
owners, but unlike the existing firmware pseudo-registers, they hold
the features supported in the form of a bitmap.

During the VM initialization, the registers are set to upper-limit of
the features supported by the corresponding registers. It's expected
that the VMMs discover the features provided by each register via
GET_ONE_REG, and write back the desired values using SET_ONE_REG.
KVM allows this modification only until the VM has started.

Some of the standard features are not mapped to any bits of the
registers. But since they can recreate the original problem of
making it available without userspace's consent, they need to
be explicitly added to the case-list in
kvm_hvc_call_default_allowed(). Any function-id that's not enabled
via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
be returned as SMCCC_RET_NOT_SUPPORTED to the guest.

Older userspace code can simply ignore the feature and the
hypercall services will be exposed unconditionally to the guests,
thus ensuring backward compatibility.

In this patch, the framework adds the register only for ARM's standard
secure services (owner value 4). Currently, this includes support only
for ARM True Random Number Generator (TRNG) service, with bit-0 of the
register representing mandatory features of v1.0. Other services are
momentarily added in the upcoming patches.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h | 12 ++++
 arch/arm64/include/uapi/asm/kvm.h |  9 +++
 arch/arm64/kvm/arm.c              |  1 +
 arch/arm64/kvm/guest.c            |  8 ++-
 arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
 arch/arm64/kvm/psci.c             | 13 +++++
 include/kvm/arm_hypercalls.h      |  6 ++
 include/kvm/arm_psci.h            |  2 +-
 8 files changed, 142 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 94a27a7520f4..df07f4c10197 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -101,6 +101,15 @@ struct kvm_s2_mmu {
 struct kvm_arch_memory_slot {
 };
 
+/**
+ * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
+ *
+ * @std_bmap: Bitmap of standard secure service calls
+ */
+struct kvm_smccc_features {
+	unsigned long std_bmap;
+};
+
 struct kvm_arch {
 	struct kvm_s2_mmu mmu;
 
@@ -150,6 +159,9 @@ struct kvm_arch {
 
 	u8 pfr0_csv2;
 	u8 pfr0_csv3;
+
+	/* Hypercall features firmware registers' descriptor */
+	struct kvm_smccc_features smccc_feat;
 };
 
 struct kvm_vcpu_fault_info {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index c1b6ddc02d2f..0b79d2dc6ffd 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_ARM64_SVE_VLS_WORDS	\
 	((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
 
+/* Bitmap feature firmware registers */
+#define KVM_REG_ARM_FW_FEAT_BMAP		(0x0016 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+						KVM_REG_ARM_FW_FEAT_BMAP |	\
+						((r) & 0xffff))
+
+#define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
+#define KVM_REG_ARM_STD_BIT_TRNG_V1_0		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/arm.c b/arch/arm64/kvm/arm.c
index 523bc934fe2f..a37fadbd617e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
 
 	set_default_spectre(kvm);
+	kvm_arm_init_hypercalls(kvm);
 
 	return ret;
 out_free_stage2_pgd:
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 0d5cca56cbda..8c607199cad1 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
-	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		return kvm_arm_get_fw_reg(vcpu, reg);
 	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
 	}
 
@@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
-	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		return kvm_arm_set_fw_reg(vcpu, reg);
 	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
 	}
 
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index fa6d9378d8e7..df55a04d2fe8 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
 	val[3] = lower_32_bits(cycles);
 }
 
+static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
+{
+	return test_bit(feat_bit, reg_bmap);
+}
+
+static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	switch (func_id) {
+	/*
+	 * List of function-ids that are not gated with the bitmapped feature
+	 * firmware registers, and are to be allowed for servicing the call by default.
+	 */
+	case ARM_SMCCC_VERSION_FUNC_ID:
+	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
+	case ARM_SMCCC_HV_PV_TIME_FEATURES:
+	case ARM_SMCCC_HV_PV_TIME_ST:
+	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
+		return true;
+	default:
+		return kvm_psci_func_id_is_valid(vcpu, func_id);
+	}
+}
+
+static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
+
+	switch (func_id) {
+	case ARM_SMCCC_TRNG_VERSION:
+	case ARM_SMCCC_TRNG_FEATURES:
+	case ARM_SMCCC_TRNG_GET_UUID:
+	case ARM_SMCCC_TRNG_RND32:
+	case ARM_SMCCC_TRNG_RND64:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
+						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
+	default:
+		return kvm_hvc_call_default_allowed(vcpu, func_id);
+	}
+}
+
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
 	u32 func_id = smccc_get_function(vcpu);
@@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 	u32 feature;
 	gpa_t gpa;
 
+	if (!kvm_hvc_call_allowed(vcpu, func_id))
+		goto out;
+
 	switch (func_id) {
 	case ARM_SMCCC_VERSION_FUNC_ID:
 		val[0] = ARM_SMCCC_VERSION_1_1;
@@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 		return kvm_psci_call(vcpu);
 	}
 
+out:
 	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
 	return 1;
 }
@@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
+	KVM_REG_ARM_STD_BMAP,
 };
 
+void kvm_arm_init_hypercalls(struct kvm *kvm)
+{
+	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
+
+	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
+}
+
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
 	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
@@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
 
 int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
 	void __user *uaddr = (void __user *)(long)reg->addr;
 	u64 val;
 
@@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
 		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
 		break;
+	case KVM_REG_ARM_STD_BMAP:
+		val = READ_ONCE(smccc_feat->std_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return 0;
 }
 
+static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
+{
+	int ret = 0;
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
+	unsigned long *fw_reg_bmap, fw_reg_features;
+
+	switch (reg_id) {
+	case KVM_REG_ARM_STD_BMAP:
+		fw_reg_bmap = &smccc_feat->std_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	/* Check for unsupported bit */
+	if (val & ~fw_reg_features)
+		return -EINVAL;
+
+	mutex_lock(&kvm->lock);
+
+	/* Return -EBUSY if the VM (any vCPU) has already started running. */
+	if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	WRITE_ONCE(*fw_reg_bmap, val);
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	void __user *uaddr = (void __user *)(long)reg->addr;
@@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 			return -EINVAL;
 
 		return 0;
+	case KVM_REG_ARM_STD_BMAP:
+		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
 	}
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index 346535169faa..67d1273e8086 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 }
+
+bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
+{
+	/* PSCI 0.1 doesn't comply with the standard SMCCC */
+	if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
+		return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
+
+	if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
+		ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
+		return true;
+
+	return false;
+}
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 5d38628a8d04..499b45b607b6 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -6,6 +6,11 @@
 
 #include <asm/kvm_emulate.h>
 
+/* Last valid bits of the bitmapped firmware registers */
+#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+
+#define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
+
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
 static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
@@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
 
 struct kvm_one_reg;
 
+void kvm_arm_init_hypercalls(struct kvm *kvm);
 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);
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
index 6e55b9283789..c47be3e26965 100644
--- a/include/kvm/arm_psci.h
+++ b/include/kvm/arm_psci.h
@@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
 	return KVM_ARM_PSCI_0_1;
 }
 
-
 int kvm_psci_call(struct kvm_vcpu *vcpu);
+bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
 
 #endif /* __KVM_ARM_PSCI_H__ */
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v6 3/9] KVM: arm64: Add standard hypervisor firmware register
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Introduce the firmware register to hold the standard hypervisor
service calls (owner value 5) as a bitmap. The bitmap represents
the features that'll be enabled for the guest, as configured by
the user-space. Currently, this includes support only for
Paravirtualized time, represented by bit-0.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/include/uapi/asm/kvm.h |  3 +++
 arch/arm64/kvm/hypercalls.c       | 21 ++++++++++++++++++---
 include/kvm/arm_hypercalls.h      |  2 ++
 4 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index df07f4c10197..27d4b2a7970e 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -105,9 +105,11 @@ struct kvm_arch_memory_slot {
  * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
  *
  * @std_bmap: Bitmap of standard secure service calls
+ * @std_hyp_bmap: Bitmap of standard hypervisor service calls
  */
 struct kvm_smccc_features {
 	unsigned long std_bmap;
+	unsigned long std_hyp_bmap;
 };
 
 struct kvm_arch {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 0b79d2dc6ffd..9eecc7ee8c14 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -341,6 +341,9 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
 #define KVM_REG_ARM_STD_BIT_TRNG_V1_0		0
 
+#define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
+#define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index df55a04d2fe8..f097bebdad39 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -72,8 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	 */
 	case ARM_SMCCC_VERSION_FUNC_ID:
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-	case ARM_SMCCC_HV_PV_TIME_FEATURES:
-	case ARM_SMCCC_HV_PV_TIME_ST:
 	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
 	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
 	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
@@ -95,6 +93,10 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	case ARM_SMCCC_TRNG_RND64:
 		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
 						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
+	case ARM_SMCCC_HV_PV_TIME_FEATURES:
+	case ARM_SMCCC_HV_PV_TIME_ST:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
+					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
 	default:
 		return kvm_hvc_call_default_allowed(vcpu, func_id);
 	}
@@ -102,6 +104,7 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
 	u32 func_id = smccc_get_function(vcpu);
 	u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
 	u32 feature;
@@ -165,7 +168,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 			}
 			break;
 		case ARM_SMCCC_HV_PV_TIME_FEATURES:
-			val[0] = SMCCC_RET_SUCCESS;
+			if (kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
+					KVM_REG_ARM_STD_HYP_BIT_PV_TIME))
+				val[0] = SMCCC_RET_SUCCESS;
 			break;
 		}
 		break;
@@ -211,6 +216,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
 	KVM_REG_ARM_STD_BMAP,
+	KVM_REG_ARM_STD_HYP_BMAP,
 };
 
 void kvm_arm_init_hypercalls(struct kvm *kvm)
@@ -218,6 +224,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
 	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
 
 	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
+	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
 }
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
@@ -307,6 +314,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_STD_BMAP:
 		val = READ_ONCE(smccc_feat->std_bmap);
 		break;
+	case KVM_REG_ARM_STD_HYP_BMAP:
+		val = READ_ONCE(smccc_feat->std_hyp_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -329,6 +339,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
 		fw_reg_bmap = &smccc_feat->std_bmap;
 		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
 		break;
+	case KVM_REG_ARM_STD_HYP_BMAP:
+		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -430,6 +444,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 		return 0;
 	case KVM_REG_ARM_STD_BMAP:
+	case KVM_REG_ARM_STD_HYP_BMAP:
 		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 499b45b607b6..aadd6ae3ab72 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -8,8 +8,10 @@
 
 /* Last valid bits of the bitmapped firmware registers */
 #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
 
 #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
+#define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 3/9] KVM: arm64: Add standard hypervisor firmware register
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Introduce the firmware register to hold the standard hypervisor
service calls (owner value 5) as a bitmap. The bitmap represents
the features that'll be enabled for the guest, as configured by
the user-space. Currently, this includes support only for
Paravirtualized time, represented by bit-0.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/include/uapi/asm/kvm.h |  3 +++
 arch/arm64/kvm/hypercalls.c       | 21 ++++++++++++++++++---
 include/kvm/arm_hypercalls.h      |  2 ++
 4 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index df07f4c10197..27d4b2a7970e 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -105,9 +105,11 @@ struct kvm_arch_memory_slot {
  * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
  *
  * @std_bmap: Bitmap of standard secure service calls
+ * @std_hyp_bmap: Bitmap of standard hypervisor service calls
  */
 struct kvm_smccc_features {
 	unsigned long std_bmap;
+	unsigned long std_hyp_bmap;
 };
 
 struct kvm_arch {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 0b79d2dc6ffd..9eecc7ee8c14 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -341,6 +341,9 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
 #define KVM_REG_ARM_STD_BIT_TRNG_V1_0		0
 
+#define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
+#define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index df55a04d2fe8..f097bebdad39 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -72,8 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	 */
 	case ARM_SMCCC_VERSION_FUNC_ID:
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-	case ARM_SMCCC_HV_PV_TIME_FEATURES:
-	case ARM_SMCCC_HV_PV_TIME_ST:
 	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
 	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
 	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
@@ -95,6 +93,10 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	case ARM_SMCCC_TRNG_RND64:
 		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
 						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
+	case ARM_SMCCC_HV_PV_TIME_FEATURES:
+	case ARM_SMCCC_HV_PV_TIME_ST:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
+					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
 	default:
 		return kvm_hvc_call_default_allowed(vcpu, func_id);
 	}
@@ -102,6 +104,7 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
 	u32 func_id = smccc_get_function(vcpu);
 	u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
 	u32 feature;
@@ -165,7 +168,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 			}
 			break;
 		case ARM_SMCCC_HV_PV_TIME_FEATURES:
-			val[0] = SMCCC_RET_SUCCESS;
+			if (kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
+					KVM_REG_ARM_STD_HYP_BIT_PV_TIME))
+				val[0] = SMCCC_RET_SUCCESS;
 			break;
 		}
 		break;
@@ -211,6 +216,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
 	KVM_REG_ARM_STD_BMAP,
+	KVM_REG_ARM_STD_HYP_BMAP,
 };
 
 void kvm_arm_init_hypercalls(struct kvm *kvm)
@@ -218,6 +224,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
 	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
 
 	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
+	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
 }
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
@@ -307,6 +314,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_STD_BMAP:
 		val = READ_ONCE(smccc_feat->std_bmap);
 		break;
+	case KVM_REG_ARM_STD_HYP_BMAP:
+		val = READ_ONCE(smccc_feat->std_hyp_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -329,6 +339,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
 		fw_reg_bmap = &smccc_feat->std_bmap;
 		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
 		break;
+	case KVM_REG_ARM_STD_HYP_BMAP:
+		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -430,6 +444,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 		return 0;
 	case KVM_REG_ARM_STD_BMAP:
+	case KVM_REG_ARM_STD_HYP_BMAP:
 		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 499b45b607b6..aadd6ae3ab72 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -8,8 +8,10 @@
 
 /* Last valid bits of the bitmapped firmware registers */
 #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
 
 #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
+#define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 3/9] KVM: arm64: Add standard hypervisor firmware register
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Introduce the firmware register to hold the standard hypervisor
service calls (owner value 5) as a bitmap. The bitmap represents
the features that'll be enabled for the guest, as configured by
the user-space. Currently, this includes support only for
Paravirtualized time, represented by bit-0.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/include/uapi/asm/kvm.h |  3 +++
 arch/arm64/kvm/hypercalls.c       | 21 ++++++++++++++++++---
 include/kvm/arm_hypercalls.h      |  2 ++
 4 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index df07f4c10197..27d4b2a7970e 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -105,9 +105,11 @@ struct kvm_arch_memory_slot {
  * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
  *
  * @std_bmap: Bitmap of standard secure service calls
+ * @std_hyp_bmap: Bitmap of standard hypervisor service calls
  */
 struct kvm_smccc_features {
 	unsigned long std_bmap;
+	unsigned long std_hyp_bmap;
 };
 
 struct kvm_arch {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 0b79d2dc6ffd..9eecc7ee8c14 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -341,6 +341,9 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
 #define KVM_REG_ARM_STD_BIT_TRNG_V1_0		0
 
+#define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
+#define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index df55a04d2fe8..f097bebdad39 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -72,8 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	 */
 	case ARM_SMCCC_VERSION_FUNC_ID:
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-	case ARM_SMCCC_HV_PV_TIME_FEATURES:
-	case ARM_SMCCC_HV_PV_TIME_ST:
 	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
 	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
 	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
@@ -95,6 +93,10 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	case ARM_SMCCC_TRNG_RND64:
 		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
 						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
+	case ARM_SMCCC_HV_PV_TIME_FEATURES:
+	case ARM_SMCCC_HV_PV_TIME_ST:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
+					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
 	default:
 		return kvm_hvc_call_default_allowed(vcpu, func_id);
 	}
@@ -102,6 +104,7 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 {
+	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
 	u32 func_id = smccc_get_function(vcpu);
 	u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
 	u32 feature;
@@ -165,7 +168,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 			}
 			break;
 		case ARM_SMCCC_HV_PV_TIME_FEATURES:
-			val[0] = SMCCC_RET_SUCCESS;
+			if (kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
+					KVM_REG_ARM_STD_HYP_BIT_PV_TIME))
+				val[0] = SMCCC_RET_SUCCESS;
 			break;
 		}
 		break;
@@ -211,6 +216,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
 	KVM_REG_ARM_STD_BMAP,
+	KVM_REG_ARM_STD_HYP_BMAP,
 };
 
 void kvm_arm_init_hypercalls(struct kvm *kvm)
@@ -218,6 +224,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
 	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
 
 	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
+	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
 }
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
@@ -307,6 +314,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_STD_BMAP:
 		val = READ_ONCE(smccc_feat->std_bmap);
 		break;
+	case KVM_REG_ARM_STD_HYP_BMAP:
+		val = READ_ONCE(smccc_feat->std_hyp_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -329,6 +339,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
 		fw_reg_bmap = &smccc_feat->std_bmap;
 		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
 		break;
+	case KVM_REG_ARM_STD_HYP_BMAP:
+		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -430,6 +444,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 
 		return 0;
 	case KVM_REG_ARM_STD_BMAP:
+	case KVM_REG_ARM_STD_HYP_BMAP:
 		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index 499b45b607b6..aadd6ae3ab72 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -8,8 +8,10 @@
 
 /* Last valid bits of the bitmapped firmware registers */
 #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
 
 #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
+#define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Introduce the firmware register to hold the vendor specific
hypervisor service calls (owner value 6) as a bitmap. The
bitmap represents the features that'll be enabled for the
guest, as configured by the user-space. Currently, this
includes support for KVM-vendor features along with
reading the UID, represented by bit-0, and Precision Time
Protocol (PTP), represented by bit-1.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/include/uapi/asm/kvm.h |  4 ++++
 arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
 include/kvm/arm_hypercalls.h      |  2 ++
 4 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 27d4b2a7970e..a025c2ba012a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
  *
  * @std_bmap: Bitmap of standard secure service calls
  * @std_hyp_bmap: Bitmap of standard hypervisor service calls
+ * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
  */
 struct kvm_smccc_features {
 	unsigned long std_bmap;
 	unsigned long std_hyp_bmap;
+	unsigned long vendor_hyp_bmap;
 };
 
 struct kvm_arch {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9eecc7ee8c14..e7d5ae222684 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
 #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		0
 
+#define KVM_REG_ARM_VENDOR_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
+#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT	0
+#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP		1
+
 /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index f097bebdad39..76e626d0e699 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	 */
 	case ARM_SMCCC_VERSION_FUNC_ID:
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
 		return true;
 	default:
 		return kvm_psci_func_id_is_valid(vcpu, func_id);
@@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	case ARM_SMCCC_HV_PV_TIME_ST:
 		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
 					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
+	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
+					KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
+	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
+					KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
 	default:
 		return kvm_hvc_call_default_allowed(vcpu, func_id);
 	}
@@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 		val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
 		break;
 	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
-		val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
-		val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
+		val[0] = smccc_feat->vendor_hyp_bmap;
 		break;
 	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
 		kvm_ptp_get_time(vcpu, val);
@@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
 	KVM_REG_ARM_STD_BMAP,
 	KVM_REG_ARM_STD_HYP_BMAP,
+	KVM_REG_ARM_VENDOR_HYP_BMAP,
 };
 
 void kvm_arm_init_hypercalls(struct kvm *kvm)
@@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
 
 	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
 	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
+	smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
 }
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
@@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_STD_HYP_BMAP:
 		val = READ_ONCE(smccc_feat->std_hyp_bmap);
 		break;
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
+		val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
 		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
 		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
 		break;
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
+		fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 		return 0;
 	case KVM_REG_ARM_STD_BMAP:
 	case KVM_REG_ARM_STD_HYP_BMAP:
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
 		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index aadd6ae3ab72..4ebfdd26e486 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -9,9 +9,11 @@
 /* Last valid bits of the bitmapped firmware registers */
 #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
 #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
+#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
 
 #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
 #define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
+#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES	GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Introduce the firmware register to hold the vendor specific
hypervisor service calls (owner value 6) as a bitmap. The
bitmap represents the features that'll be enabled for the
guest, as configured by the user-space. Currently, this
includes support for KVM-vendor features along with
reading the UID, represented by bit-0, and Precision Time
Protocol (PTP), represented by bit-1.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/include/uapi/asm/kvm.h |  4 ++++
 arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
 include/kvm/arm_hypercalls.h      |  2 ++
 4 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 27d4b2a7970e..a025c2ba012a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
  *
  * @std_bmap: Bitmap of standard secure service calls
  * @std_hyp_bmap: Bitmap of standard hypervisor service calls
+ * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
  */
 struct kvm_smccc_features {
 	unsigned long std_bmap;
 	unsigned long std_hyp_bmap;
+	unsigned long vendor_hyp_bmap;
 };
 
 struct kvm_arch {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9eecc7ee8c14..e7d5ae222684 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
 #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		0
 
+#define KVM_REG_ARM_VENDOR_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
+#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT	0
+#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP		1
+
 /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index f097bebdad39..76e626d0e699 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	 */
 	case ARM_SMCCC_VERSION_FUNC_ID:
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
 		return true;
 	default:
 		return kvm_psci_func_id_is_valid(vcpu, func_id);
@@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	case ARM_SMCCC_HV_PV_TIME_ST:
 		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
 					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
+	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
+					KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
+	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
+					KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
 	default:
 		return kvm_hvc_call_default_allowed(vcpu, func_id);
 	}
@@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 		val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
 		break;
 	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
-		val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
-		val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
+		val[0] = smccc_feat->vendor_hyp_bmap;
 		break;
 	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
 		kvm_ptp_get_time(vcpu, val);
@@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
 	KVM_REG_ARM_STD_BMAP,
 	KVM_REG_ARM_STD_HYP_BMAP,
+	KVM_REG_ARM_VENDOR_HYP_BMAP,
 };
 
 void kvm_arm_init_hypercalls(struct kvm *kvm)
@@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
 
 	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
 	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
+	smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
 }
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
@@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_STD_HYP_BMAP:
 		val = READ_ONCE(smccc_feat->std_hyp_bmap);
 		break;
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
+		val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
 		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
 		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
 		break;
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
+		fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 		return 0;
 	case KVM_REG_ARM_STD_BMAP:
 	case KVM_REG_ARM_STD_HYP_BMAP:
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
 		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index aadd6ae3ab72..4ebfdd26e486 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -9,9 +9,11 @@
 /* Last valid bits of the bitmapped firmware registers */
 #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
 #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
+#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
 
 #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
 #define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
+#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES	GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Introduce the firmware register to hold the vendor specific
hypervisor service calls (owner value 6) as a bitmap. The
bitmap represents the features that'll be enabled for the
guest, as configured by the user-space. Currently, this
includes support for KVM-vendor features along with
reading the UID, represented by bit-0, and Precision Time
Protocol (PTP), represented by bit-1.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/include/uapi/asm/kvm.h |  4 ++++
 arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
 include/kvm/arm_hypercalls.h      |  2 ++
 4 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 27d4b2a7970e..a025c2ba012a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
  *
  * @std_bmap: Bitmap of standard secure service calls
  * @std_hyp_bmap: Bitmap of standard hypervisor service calls
+ * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
  */
 struct kvm_smccc_features {
 	unsigned long std_bmap;
 	unsigned long std_hyp_bmap;
+	unsigned long vendor_hyp_bmap;
 };
 
 struct kvm_arch {
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9eecc7ee8c14..e7d5ae222684 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
 #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		0
 
+#define KVM_REG_ARM_VENDOR_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
+#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT	0
+#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP		1
+
 /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index f097bebdad39..76e626d0e699 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	 */
 	case ARM_SMCCC_VERSION_FUNC_ID:
 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
-	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
 		return true;
 	default:
 		return kvm_psci_func_id_is_valid(vcpu, func_id);
@@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
 	case ARM_SMCCC_HV_PV_TIME_ST:
 		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
 					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
+	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
+	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
+					KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
+	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
+		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
+					KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
 	default:
 		return kvm_hvc_call_default_allowed(vcpu, func_id);
 	}
@@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 		val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
 		break;
 	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
-		val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
-		val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
+		val[0] = smccc_feat->vendor_hyp_bmap;
 		break;
 	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
 		kvm_ptp_get_time(vcpu, val);
@@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
 	KVM_REG_ARM_STD_BMAP,
 	KVM_REG_ARM_STD_HYP_BMAP,
+	KVM_REG_ARM_VENDOR_HYP_BMAP,
 };
 
 void kvm_arm_init_hypercalls(struct kvm *kvm)
@@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
 
 	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
 	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
+	smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
 }
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
@@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	case KVM_REG_ARM_STD_HYP_BMAP:
 		val = READ_ONCE(smccc_feat->std_hyp_bmap);
 		break;
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
+		val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
 		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
 		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
 		break;
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
+		fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
+		fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
+		break;
 	default:
 		return -ENOENT;
 	}
@@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 		return 0;
 	case KVM_REG_ARM_STD_BMAP:
 	case KVM_REG_ARM_STD_HYP_BMAP:
+	case KVM_REG_ARM_VENDOR_HYP_BMAP:
 		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
 	default:
 		return -ENOENT;
diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
index aadd6ae3ab72..4ebfdd26e486 100644
--- a/include/kvm/arm_hypercalls.h
+++ b/include/kvm/arm_hypercalls.h
@@ -9,9 +9,11 @@
 /* Last valid bits of the bitmapped firmware registers */
 #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
 #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
+#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
 
 #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
 #define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
+#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES	GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
 
 int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
 
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v6 5/9] Docs: KVM: Rename psci.rst to hypercalls.rst
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Since the doc also covers general hypercalls' details,
rather than just PSCI, and the fact that the bitmap firmware
registers' details will be added to this doc, rename the file
to a more appropriate name- hypercalls.rst.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
---
 Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} (100%)

diff --git a/Documentation/virt/kvm/arm/psci.rst b/Documentation/virt/kvm/arm/hypercalls.rst
similarity index 100%
rename from Documentation/virt/kvm/arm/psci.rst
rename to Documentation/virt/kvm/arm/hypercalls.rst
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 5/9] Docs: KVM: Rename psci.rst to hypercalls.rst
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Since the doc also covers general hypercalls' details,
rather than just PSCI, and the fact that the bitmap firmware
registers' details will be added to this doc, rename the file
to a more appropriate name- hypercalls.rst.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
---
 Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} (100%)

diff --git a/Documentation/virt/kvm/arm/psci.rst b/Documentation/virt/kvm/arm/hypercalls.rst
similarity index 100%
rename from Documentation/virt/kvm/arm/psci.rst
rename to Documentation/virt/kvm/arm/hypercalls.rst
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 5/9] Docs: KVM: Rename psci.rst to hypercalls.rst
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Since the doc also covers general hypercalls' details,
rather than just PSCI, and the fact that the bitmap firmware
registers' details will be added to this doc, rename the file
to a more appropriate name- hypercalls.rst.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
---
 Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} (100%)

diff --git a/Documentation/virt/kvm/arm/psci.rst b/Documentation/virt/kvm/arm/hypercalls.rst
similarity index 100%
rename from Documentation/virt/kvm/arm/psci.rst
rename to Documentation/virt/kvm/arm/hypercalls.rst
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
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] 90+ messages in thread

* [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Add the documentation for the bitmap firmware registers in
hypercalls.rst and api.rst. This includes the details for
KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
KVM_REG_ARM_VENDOR_HYP_BMAP registers.

Since the document is growing to carry other hypercall related
information, make necessary adjustments to present the document
in a generic sense, rather than being PSCI focused.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 Documentation/virt/kvm/api.rst            | 16 ++++
 Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
 2 files changed, 92 insertions(+), 18 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 85c7abc51af5..ac489191d0a9 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
 
   0x6030 0000 0014 <regno:16>
 
+arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
+
+  0x6030 0000 0016 <regno:16>
+
+The bitmap feature firmware registers exposes the hypercall services that are
+available for userspace to configure. The set bits corresponds to the services
+that are available for the guests to access. By default, KVM sets all the
+supported bits during VM initialization. The userspace can discover the
+available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
+to the features that it wishes guests to see via KVM_SET_ONE_REG.
+
+Note: These registers are immutable once any of the vCPUs of the VM has run at
+least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
+
+(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
+
 arm64 SVE registers have the following bit patterns::
 
   0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
index d52c2e83b5b8..6327c504b2fb 100644
--- a/Documentation/virt/kvm/arm/hypercalls.rst
+++ b/Documentation/virt/kvm/arm/hypercalls.rst
@@ -1,32 +1,32 @@
 .. SPDX-License-Identifier: GPL-2.0
 
-=========================================
-Power State Coordination Interface (PSCI)
-=========================================
+=======================
+ARM Hypercall Interface
+=======================
 
-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.
+KVM handles the hypercall services as requested by the guests. New hypercall
+services are regularly made available by the ARM specification or by KVM (as
+vendor services) if they make sense from a virtualization point of view.
 
-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.
+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 version of a hypercall service, or if a migration
+causes a different version to be exposed out of the blue to an unsuspecting
+guest.
 
 In order to remedy this situation, KVM exposes a set of "firmware
 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.
+to a convenient value as required.
 
-The following register is defined:
+The following registers are defined:
 
 * KVM_REG_ARM_PSCI_VERSION:
 
+  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.
+
   - 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
@@ -74,4 +74,62 @@ The following register is defined:
     KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
       The workaround is always active on this vCPU or it is not needed.
 
-.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
+
+Bitmap Feature Firmware Registers
+---------------------------------
+
+Contrary to the above registers, the following registers exposes the hypercall
+services in the form of a feature-bitmap to the userspace. This bitmap is
+translated to the services that are available to the guest. There is a register
+defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
+
+By default, these registers are set with the upper limit of the features that
+are supported. This way userspace can discover all the electable hypercall services
+via GET_ONE_REG. The user-space can write-back the desired bitmap back via
+SET_ONE_REG. The features for the registers that are untouched, probably because
+userspace isn't aware of them, will be exposed as is to the guest.
+
+Note that KVM would't allow the userspace to configure the registers anymore once
+any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
+
+The psuedo-firmware bitmap register are as follows:
+
+* KVM_REG_ARM_STD_BMAP:
+    Controls the bitmap of the ARM Standard Secure Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
+      The bit represents the services offered under v1.0 of ARM True Random
+      Number Generator (TRNG) specification, ARM DEN0098.
+
+* KVM_REG_ARM_STD_HYP_BMAP:
+    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
+      The bit represents the Paravirtualized Time service as represented by
+      ARM DEN0057A.
+
+* KVM_REG_ARM_VENDOR_HYP_BMAP:
+    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
+      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
+      function-id
+
+    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
+      The bit represents the Precision Time Protocol KVM service.
+
+Errors:
+
+    =======  =============================================================
+    -ENOENT   Unknown register accessed.
+    -EBUSY    Attempt a 'write' to the register after the VM has started.
+    -EINVAL   Invalid bitmap written to the register.
+    =======  =============================================================
+
+.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
\ No newline at end of file
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Add the documentation for the bitmap firmware registers in
hypercalls.rst and api.rst. This includes the details for
KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
KVM_REG_ARM_VENDOR_HYP_BMAP registers.

Since the document is growing to carry other hypercall related
information, make necessary adjustments to present the document
in a generic sense, rather than being PSCI focused.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 Documentation/virt/kvm/api.rst            | 16 ++++
 Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
 2 files changed, 92 insertions(+), 18 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 85c7abc51af5..ac489191d0a9 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
 
   0x6030 0000 0014 <regno:16>
 
+arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
+
+  0x6030 0000 0016 <regno:16>
+
+The bitmap feature firmware registers exposes the hypercall services that are
+available for userspace to configure. The set bits corresponds to the services
+that are available for the guests to access. By default, KVM sets all the
+supported bits during VM initialization. The userspace can discover the
+available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
+to the features that it wishes guests to see via KVM_SET_ONE_REG.
+
+Note: These registers are immutable once any of the vCPUs of the VM has run at
+least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
+
+(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
+
 arm64 SVE registers have the following bit patterns::
 
   0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
index d52c2e83b5b8..6327c504b2fb 100644
--- a/Documentation/virt/kvm/arm/hypercalls.rst
+++ b/Documentation/virt/kvm/arm/hypercalls.rst
@@ -1,32 +1,32 @@
 .. SPDX-License-Identifier: GPL-2.0
 
-=========================================
-Power State Coordination Interface (PSCI)
-=========================================
+=======================
+ARM Hypercall Interface
+=======================
 
-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.
+KVM handles the hypercall services as requested by the guests. New hypercall
+services are regularly made available by the ARM specification or by KVM (as
+vendor services) if they make sense from a virtualization point of view.
 
-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.
+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 version of a hypercall service, or if a migration
+causes a different version to be exposed out of the blue to an unsuspecting
+guest.
 
 In order to remedy this situation, KVM exposes a set of "firmware
 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.
+to a convenient value as required.
 
-The following register is defined:
+The following registers are defined:
 
 * KVM_REG_ARM_PSCI_VERSION:
 
+  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.
+
   - 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
@@ -74,4 +74,62 @@ The following register is defined:
     KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
       The workaround is always active on this vCPU or it is not needed.
 
-.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
+
+Bitmap Feature Firmware Registers
+---------------------------------
+
+Contrary to the above registers, the following registers exposes the hypercall
+services in the form of a feature-bitmap to the userspace. This bitmap is
+translated to the services that are available to the guest. There is a register
+defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
+
+By default, these registers are set with the upper limit of the features that
+are supported. This way userspace can discover all the electable hypercall services
+via GET_ONE_REG. The user-space can write-back the desired bitmap back via
+SET_ONE_REG. The features for the registers that are untouched, probably because
+userspace isn't aware of them, will be exposed as is to the guest.
+
+Note that KVM would't allow the userspace to configure the registers anymore once
+any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
+
+The psuedo-firmware bitmap register are as follows:
+
+* KVM_REG_ARM_STD_BMAP:
+    Controls the bitmap of the ARM Standard Secure Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
+      The bit represents the services offered under v1.0 of ARM True Random
+      Number Generator (TRNG) specification, ARM DEN0098.
+
+* KVM_REG_ARM_STD_HYP_BMAP:
+    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
+      The bit represents the Paravirtualized Time service as represented by
+      ARM DEN0057A.
+
+* KVM_REG_ARM_VENDOR_HYP_BMAP:
+    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
+      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
+      function-id
+
+    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
+      The bit represents the Precision Time Protocol KVM service.
+
+Errors:
+
+    =======  =============================================================
+    -ENOENT   Unknown register accessed.
+    -EBUSY    Attempt a 'write' to the register after the VM has started.
+    -EINVAL   Invalid bitmap written to the register.
+    =======  =============================================================
+
+.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
\ No newline at end of file
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Add the documentation for the bitmap firmware registers in
hypercalls.rst and api.rst. This includes the details for
KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
KVM_REG_ARM_VENDOR_HYP_BMAP registers.

Since the document is growing to carry other hypercall related
information, make necessary adjustments to present the document
in a generic sense, rather than being PSCI focused.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 Documentation/virt/kvm/api.rst            | 16 ++++
 Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
 2 files changed, 92 insertions(+), 18 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 85c7abc51af5..ac489191d0a9 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
 
   0x6030 0000 0014 <regno:16>
 
+arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
+
+  0x6030 0000 0016 <regno:16>
+
+The bitmap feature firmware registers exposes the hypercall services that are
+available for userspace to configure. The set bits corresponds to the services
+that are available for the guests to access. By default, KVM sets all the
+supported bits during VM initialization. The userspace can discover the
+available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
+to the features that it wishes guests to see via KVM_SET_ONE_REG.
+
+Note: These registers are immutable once any of the vCPUs of the VM has run at
+least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
+
+(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
+
 arm64 SVE registers have the following bit patterns::
 
   0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
index d52c2e83b5b8..6327c504b2fb 100644
--- a/Documentation/virt/kvm/arm/hypercalls.rst
+++ b/Documentation/virt/kvm/arm/hypercalls.rst
@@ -1,32 +1,32 @@
 .. SPDX-License-Identifier: GPL-2.0
 
-=========================================
-Power State Coordination Interface (PSCI)
-=========================================
+=======================
+ARM Hypercall Interface
+=======================
 
-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.
+KVM handles the hypercall services as requested by the guests. New hypercall
+services are regularly made available by the ARM specification or by KVM (as
+vendor services) if they make sense from a virtualization point of view.
 
-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.
+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 version of a hypercall service, or if a migration
+causes a different version to be exposed out of the blue to an unsuspecting
+guest.
 
 In order to remedy this situation, KVM exposes a set of "firmware
 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.
+to a convenient value as required.
 
-The following register is defined:
+The following registers are defined:
 
 * KVM_REG_ARM_PSCI_VERSION:
 
+  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.
+
   - 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
@@ -74,4 +74,62 @@ The following register is defined:
     KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
       The workaround is always active on this vCPU or it is not needed.
 
-.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
+
+Bitmap Feature Firmware Registers
+---------------------------------
+
+Contrary to the above registers, the following registers exposes the hypercall
+services in the form of a feature-bitmap to the userspace. This bitmap is
+translated to the services that are available to the guest. There is a register
+defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
+
+By default, these registers are set with the upper limit of the features that
+are supported. This way userspace can discover all the electable hypercall services
+via GET_ONE_REG. The user-space can write-back the desired bitmap back via
+SET_ONE_REG. The features for the registers that are untouched, probably because
+userspace isn't aware of them, will be exposed as is to the guest.
+
+Note that KVM would't allow the userspace to configure the registers anymore once
+any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
+
+The psuedo-firmware bitmap register are as follows:
+
+* KVM_REG_ARM_STD_BMAP:
+    Controls the bitmap of the ARM Standard Secure Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
+      The bit represents the services offered under v1.0 of ARM True Random
+      Number Generator (TRNG) specification, ARM DEN0098.
+
+* KVM_REG_ARM_STD_HYP_BMAP:
+    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
+      The bit represents the Paravirtualized Time service as represented by
+      ARM DEN0057A.
+
+* KVM_REG_ARM_VENDOR_HYP_BMAP:
+    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
+
+  The following bits are accepted:
+
+    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
+      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
+      function-id
+
+    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
+      The bit represents the Precision Time Protocol KVM service.
+
+Errors:
+
+    =======  =============================================================
+    -ENOENT   Unknown register accessed.
+    -EBUSY    Attempt a 'write' to the register after the VM has started.
+    -EINVAL   Invalid bitmap written to the register.
+    =======  =============================================================
+
+.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
\ No newline at end of file
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v6 7/9] tools: Import ARM SMCCC definitions
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Import the standard SMCCC definitions from include/linux/arm-smccc.h.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/include/linux/arm-smccc.h | 193 ++++++++++++++++++++++++++++++++
 1 file changed, 193 insertions(+)
 create mode 100644 tools/include/linux/arm-smccc.h

diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h
new file mode 100644
index 000000000000..63ce9bebccd3
--- /dev/null
+++ b/tools/include/linux/arm-smccc.h
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2015, Linaro Limited
+ */
+#ifndef __LINUX_ARM_SMCCC_H
+#define __LINUX_ARM_SMCCC_H
+
+#include <linux/const.h>
+
+/*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * https://developer.arm.com/docs/den0028/latest
+ *
+ * This code is up-to-date with version DEN 0028 C
+ */
+
+#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
+#define ARM_SMCCC_SMC_64		1
+#define ARM_SMCCC_CALL_CONV_SHIFT	30
+
+#define ARM_SMCCC_OWNER_MASK		0x3F
+#define ARM_SMCCC_OWNER_SHIFT		24
+
+#define ARM_SMCCC_FUNC_MASK		0xFFFF
+
+#define ARM_SMCCC_IS_FAST_CALL(smc_val)	\
+	((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
+#define ARM_SMCCC_IS_64(smc_val) \
+	((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
+#define ARM_SMCCC_FUNC_NUM(smc_val)	((smc_val) & ARM_SMCCC_FUNC_MASK)
+#define ARM_SMCCC_OWNER_NUM(smc_val) \
+	(((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+	(((type) << ARM_SMCCC_TYPE_SHIFT) | \
+	((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+	(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+	((func_num) & ARM_SMCCC_FUNC_MASK))
+
+#define ARM_SMCCC_OWNER_ARCH		0
+#define ARM_SMCCC_OWNER_CPU		1
+#define ARM_SMCCC_OWNER_SIP		2
+#define ARM_SMCCC_OWNER_OEM		3
+#define ARM_SMCCC_OWNER_STANDARD	4
+#define ARM_SMCCC_OWNER_STANDARD_HYP	5
+#define ARM_SMCCC_OWNER_VENDOR_HYP	6
+#define ARM_SMCCC_OWNER_TRUSTED_APP	48
+#define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
+#define ARM_SMCCC_OWNER_TRUSTED_OS	50
+#define ARM_SMCCC_OWNER_TRUSTED_OS_END	63
+
+#define ARM_SMCCC_FUNC_QUERY_CALL_UID  0xff01
+
+#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_1_2		0x10002
+#define ARM_SMCCC_VERSION_1_3		0x10003
+
+#define ARM_SMCCC_1_3_SVE_HINT		0x10000
+
+#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)
+
+#define ARM_SMCCC_ARCH_SOC_ID						\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 2)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_1					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x8000)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_2					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x7fff)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_3					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x3fff)
+
+#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_FUNC_QUERY_CALL_UID)
+
+/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0	0xb66fb428U
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1	0xe911c52eU
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2	0x564bcaa9U
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3	0x743a004dU
+
+/* KVM "vendor specific" services */
+#define ARM_SMCCC_KVM_FUNC_FEATURES		0
+#define ARM_SMCCC_KVM_FUNC_PTP			1
+#define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
+#define ARM_SMCCC_KVM_NUM_FUNCS			128
+
+#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID			\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_KVM_FUNC_FEATURES)
+
+#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED	1
+
+/*
+ * ptp_kvm is a feature used for time sync between vm and host.
+ * ptp_kvm module in guest kernel will get service from host using
+ * this hypercall ID.
+ */
+#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_KVM_FUNC_PTP)
+
+/* ptp_kvm counter type ID */
+#define KVM_PTP_VIRT_COUNTER			0
+#define KVM_PTP_PHYS_COUNTER			1
+
+/* Paravirtualised time calls (defined by ARM DEN0057A) */
+#define ARM_SMCCC_HV_PV_TIME_FEATURES				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
+			   0x20)
+
+#define ARM_SMCCC_HV_PV_TIME_ST					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
+			   0x21)
+
+/* TRNG entropy source calls (defined by ARM DEN0098) */
+#define ARM_SMCCC_TRNG_VERSION					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x50)
+
+#define ARM_SMCCC_TRNG_FEATURES					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x51)
+
+#define ARM_SMCCC_TRNG_GET_UUID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x52)
+
+#define ARM_SMCCC_TRNG_RND32					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x53)
+
+#define ARM_SMCCC_TRNG_RND64					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x53)
+
+/*
+ * Return codes defined in ARM DEN 0070A
+ * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
+ */
+#define SMCCC_RET_SUCCESS			0
+#define SMCCC_RET_NOT_SUPPORTED			-1
+#define SMCCC_RET_NOT_REQUIRED			-2
+#define SMCCC_RET_INVALID_PARAMETER		-3
+
+#endif /*__LINUX_ARM_SMCCC_H*/
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 7/9] tools: Import ARM SMCCC definitions
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Import the standard SMCCC definitions from include/linux/arm-smccc.h.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/include/linux/arm-smccc.h | 193 ++++++++++++++++++++++++++++++++
 1 file changed, 193 insertions(+)
 create mode 100644 tools/include/linux/arm-smccc.h

diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h
new file mode 100644
index 000000000000..63ce9bebccd3
--- /dev/null
+++ b/tools/include/linux/arm-smccc.h
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2015, Linaro Limited
+ */
+#ifndef __LINUX_ARM_SMCCC_H
+#define __LINUX_ARM_SMCCC_H
+
+#include <linux/const.h>
+
+/*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * https://developer.arm.com/docs/den0028/latest
+ *
+ * This code is up-to-date with version DEN 0028 C
+ */
+
+#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
+#define ARM_SMCCC_SMC_64		1
+#define ARM_SMCCC_CALL_CONV_SHIFT	30
+
+#define ARM_SMCCC_OWNER_MASK		0x3F
+#define ARM_SMCCC_OWNER_SHIFT		24
+
+#define ARM_SMCCC_FUNC_MASK		0xFFFF
+
+#define ARM_SMCCC_IS_FAST_CALL(smc_val)	\
+	((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
+#define ARM_SMCCC_IS_64(smc_val) \
+	((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
+#define ARM_SMCCC_FUNC_NUM(smc_val)	((smc_val) & ARM_SMCCC_FUNC_MASK)
+#define ARM_SMCCC_OWNER_NUM(smc_val) \
+	(((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+	(((type) << ARM_SMCCC_TYPE_SHIFT) | \
+	((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+	(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+	((func_num) & ARM_SMCCC_FUNC_MASK))
+
+#define ARM_SMCCC_OWNER_ARCH		0
+#define ARM_SMCCC_OWNER_CPU		1
+#define ARM_SMCCC_OWNER_SIP		2
+#define ARM_SMCCC_OWNER_OEM		3
+#define ARM_SMCCC_OWNER_STANDARD	4
+#define ARM_SMCCC_OWNER_STANDARD_HYP	5
+#define ARM_SMCCC_OWNER_VENDOR_HYP	6
+#define ARM_SMCCC_OWNER_TRUSTED_APP	48
+#define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
+#define ARM_SMCCC_OWNER_TRUSTED_OS	50
+#define ARM_SMCCC_OWNER_TRUSTED_OS_END	63
+
+#define ARM_SMCCC_FUNC_QUERY_CALL_UID  0xff01
+
+#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_1_2		0x10002
+#define ARM_SMCCC_VERSION_1_3		0x10003
+
+#define ARM_SMCCC_1_3_SVE_HINT		0x10000
+
+#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)
+
+#define ARM_SMCCC_ARCH_SOC_ID						\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 2)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_1					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x8000)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_2					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x7fff)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_3					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x3fff)
+
+#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_FUNC_QUERY_CALL_UID)
+
+/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0	0xb66fb428U
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1	0xe911c52eU
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2	0x564bcaa9U
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3	0x743a004dU
+
+/* KVM "vendor specific" services */
+#define ARM_SMCCC_KVM_FUNC_FEATURES		0
+#define ARM_SMCCC_KVM_FUNC_PTP			1
+#define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
+#define ARM_SMCCC_KVM_NUM_FUNCS			128
+
+#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID			\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_KVM_FUNC_FEATURES)
+
+#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED	1
+
+/*
+ * ptp_kvm is a feature used for time sync between vm and host.
+ * ptp_kvm module in guest kernel will get service from host using
+ * this hypercall ID.
+ */
+#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_KVM_FUNC_PTP)
+
+/* ptp_kvm counter type ID */
+#define KVM_PTP_VIRT_COUNTER			0
+#define KVM_PTP_PHYS_COUNTER			1
+
+/* Paravirtualised time calls (defined by ARM DEN0057A) */
+#define ARM_SMCCC_HV_PV_TIME_FEATURES				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
+			   0x20)
+
+#define ARM_SMCCC_HV_PV_TIME_ST					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
+			   0x21)
+
+/* TRNG entropy source calls (defined by ARM DEN0098) */
+#define ARM_SMCCC_TRNG_VERSION					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x50)
+
+#define ARM_SMCCC_TRNG_FEATURES					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x51)
+
+#define ARM_SMCCC_TRNG_GET_UUID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x52)
+
+#define ARM_SMCCC_TRNG_RND32					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x53)
+
+#define ARM_SMCCC_TRNG_RND64					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x53)
+
+/*
+ * Return codes defined in ARM DEN 0070A
+ * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
+ */
+#define SMCCC_RET_SUCCESS			0
+#define SMCCC_RET_NOT_SUPPORTED			-1
+#define SMCCC_RET_NOT_REQUIRED			-2
+#define SMCCC_RET_INVALID_PARAMETER		-3
+
+#endif /*__LINUX_ARM_SMCCC_H*/
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 7/9] tools: Import ARM SMCCC definitions
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Import the standard SMCCC definitions from include/linux/arm-smccc.h.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/include/linux/arm-smccc.h | 193 ++++++++++++++++++++++++++++++++
 1 file changed, 193 insertions(+)
 create mode 100644 tools/include/linux/arm-smccc.h

diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h
new file mode 100644
index 000000000000..63ce9bebccd3
--- /dev/null
+++ b/tools/include/linux/arm-smccc.h
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2015, Linaro Limited
+ */
+#ifndef __LINUX_ARM_SMCCC_H
+#define __LINUX_ARM_SMCCC_H
+
+#include <linux/const.h>
+
+/*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * https://developer.arm.com/docs/den0028/latest
+ *
+ * This code is up-to-date with version DEN 0028 C
+ */
+
+#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
+#define ARM_SMCCC_SMC_64		1
+#define ARM_SMCCC_CALL_CONV_SHIFT	30
+
+#define ARM_SMCCC_OWNER_MASK		0x3F
+#define ARM_SMCCC_OWNER_SHIFT		24
+
+#define ARM_SMCCC_FUNC_MASK		0xFFFF
+
+#define ARM_SMCCC_IS_FAST_CALL(smc_val)	\
+	((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
+#define ARM_SMCCC_IS_64(smc_val) \
+	((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
+#define ARM_SMCCC_FUNC_NUM(smc_val)	((smc_val) & ARM_SMCCC_FUNC_MASK)
+#define ARM_SMCCC_OWNER_NUM(smc_val) \
+	(((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+	(((type) << ARM_SMCCC_TYPE_SHIFT) | \
+	((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+	(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+	((func_num) & ARM_SMCCC_FUNC_MASK))
+
+#define ARM_SMCCC_OWNER_ARCH		0
+#define ARM_SMCCC_OWNER_CPU		1
+#define ARM_SMCCC_OWNER_SIP		2
+#define ARM_SMCCC_OWNER_OEM		3
+#define ARM_SMCCC_OWNER_STANDARD	4
+#define ARM_SMCCC_OWNER_STANDARD_HYP	5
+#define ARM_SMCCC_OWNER_VENDOR_HYP	6
+#define ARM_SMCCC_OWNER_TRUSTED_APP	48
+#define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
+#define ARM_SMCCC_OWNER_TRUSTED_OS	50
+#define ARM_SMCCC_OWNER_TRUSTED_OS_END	63
+
+#define ARM_SMCCC_FUNC_QUERY_CALL_UID  0xff01
+
+#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_1_2		0x10002
+#define ARM_SMCCC_VERSION_1_3		0x10003
+
+#define ARM_SMCCC_1_3_SVE_HINT		0x10000
+
+#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)
+
+#define ARM_SMCCC_ARCH_SOC_ID						\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 2)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_1					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x8000)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_2					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x7fff)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_3					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x3fff)
+
+#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_FUNC_QUERY_CALL_UID)
+
+/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0	0xb66fb428U
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1	0xe911c52eU
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2	0x564bcaa9U
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3	0x743a004dU
+
+/* KVM "vendor specific" services */
+#define ARM_SMCCC_KVM_FUNC_FEATURES		0
+#define ARM_SMCCC_KVM_FUNC_PTP			1
+#define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
+#define ARM_SMCCC_KVM_NUM_FUNCS			128
+
+#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID			\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_KVM_FUNC_FEATURES)
+
+#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED	1
+
+/*
+ * ptp_kvm is a feature used for time sync between vm and host.
+ * ptp_kvm module in guest kernel will get service from host using
+ * this hypercall ID.
+ */
+#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_KVM_FUNC_PTP)
+
+/* ptp_kvm counter type ID */
+#define KVM_PTP_VIRT_COUNTER			0
+#define KVM_PTP_PHYS_COUNTER			1
+
+/* Paravirtualised time calls (defined by ARM DEN0057A) */
+#define ARM_SMCCC_HV_PV_TIME_FEATURES				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
+			   0x20)
+
+#define ARM_SMCCC_HV_PV_TIME_ST					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
+			   0x21)
+
+/* TRNG entropy source calls (defined by ARM DEN0098) */
+#define ARM_SMCCC_TRNG_VERSION					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x50)
+
+#define ARM_SMCCC_TRNG_FEATURES					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x51)
+
+#define ARM_SMCCC_TRNG_GET_UUID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x52)
+
+#define ARM_SMCCC_TRNG_RND32					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_32,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x53)
+
+#define ARM_SMCCC_TRNG_RND64					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
+			   ARM_SMCCC_SMC_64,			\
+			   ARM_SMCCC_OWNER_STANDARD,		\
+			   0x53)
+
+/*
+ * Return codes defined in ARM DEN 0070A
+ * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
+ */
+#define SMCCC_RET_SUCCESS			0
+#define SMCCC_RET_NOT_SUPPORTED			-1
+#define SMCCC_RET_NOT_REQUIRED			-2
+#define SMCCC_RET_INVALID_PARAMETER		-3
+
+#endif /*__LINUX_ARM_SMCCC_H*/
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Introduce a KVM selftest to check the hypercall interface
for arm64 platforms. The test validates the user-space'
[GET|SET]_ONE_REG interface to read/write the psuedo-firmware
registers as well as its effects on the guest upon certain
configurations.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
 3 files changed, 337 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c

diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
index 1bb575dfc42e..b17e464ec661 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -2,6 +2,7 @@
 /aarch64/arch_timer
 /aarch64/debug-exceptions
 /aarch64/get-reg-list
+/aarch64/hypercalls
 /aarch64/psci_test
 /aarch64/vcpu_width_config
 /aarch64/vgic_init
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index c2cf4d318296..97eef0c03d3b 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
 TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
 TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
 TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
+TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
 TEST_GEN_PROGS_aarch64 += aarch64/psci_test
 TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
 TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
new file mode 100644
index 000000000000..f404343a0ae3
--- /dev/null
+++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
+ *
+ * The test validates the basic hypercall functionalities that are exposed
+ * via the psuedo-firmware bitmap register. This includes the registers'
+ * read/write behavior before and after the VM has started, and if the
+ * hypercalls are properly masked or unmasked to the guest when disabled or
+ * enabled from the KVM userspace, respectively.
+ */
+
+#include <errno.h>
+#include <linux/arm-smccc.h>
+#include <asm/kvm.h>
+#include <kvm_util.h>
+
+#include "processor.h"
+
+#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
+
+/* Last valid bits of the bitmapped firmware registers */
+#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
+#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
+
+struct kvm_fw_reg_info {
+	uint64_t reg;		/* Register definition */
+	uint64_t max_feat_bit;	/* Bit that represents the upper limit of the feature-map */
+};
+
+#define FW_REG_INFO(r)			\
+	{					\
+		.reg = r,			\
+		.max_feat_bit = r##_BIT_MAX,	\
+	}
+
+static const struct kvm_fw_reg_info fw_reg_info[] = {
+	FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
+	FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
+	FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
+};
+
+enum test_stage {
+	TEST_STAGE_REG_IFACE,
+	TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
+	TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
+	TEST_STAGE_HVC_IFACE_FALSE_INFO,
+	TEST_STAGE_END,
+};
+
+static int stage = TEST_STAGE_REG_IFACE;
+
+struct test_hvc_info {
+	uint32_t func_id;
+	uint64_t arg1;
+};
+
+#define TEST_HVC_INFO(f, a1)	\
+	{			\
+		.func_id = f,	\
+		.arg1 = a1,	\
+	}
+
+static const struct test_hvc_info hvc_info[] = {
+	/* KVM_REG_ARM_STD_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
+
+	/* KVM_REG_ARM_STD_HYP_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
+
+	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
+			ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
+};
+
+/* Feed false hypercall info to test the KVM behavior */
+static const struct test_hvc_info false_hvc_info[] = {
+	/* Feature support check against a different family of hypercalls */
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
+	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
+};
+
+static void guest_test_hvc(const struct test_hvc_info *hc_info)
+{
+	unsigned int i;
+	struct arm_smccc_res res;
+	unsigned int hvc_info_arr_sz;
+
+	hvc_info_arr_sz =
+	hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
+
+	for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
+		memset(&res, 0, sizeof(res));
+		smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
+
+		switch (stage) {
+		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+			GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
+					res.a0, hc_info->func_id, hc_info->arg1);
+			break;
+		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+			GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
+					res.a0, hc_info->func_id, hc_info->arg1);
+			break;
+		default:
+			GUEST_ASSERT_1(0, stage);
+		}
+	}
+}
+
+static void guest_code(void)
+{
+	while (stage != TEST_STAGE_END) {
+		switch (stage) {
+		case TEST_STAGE_REG_IFACE:
+			break;
+		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+			guest_test_hvc(hvc_info);
+			break;
+		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+			guest_test_hvc(false_hvc_info);
+			break;
+		default:
+			GUEST_ASSERT_1(0, stage);
+		}
+
+		GUEST_SYNC(stage);
+	}
+
+	GUEST_DONE();
+}
+
+static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
+{
+	struct kvm_one_reg reg = {
+		.id = id,
+		.addr = (uint64_t)&val,
+	};
+
+	return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
+}
+
+static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
+{
+	struct kvm_one_reg reg = {
+		.id = id,
+		.addr = (uint64_t)addr,
+	};
+
+	vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
+}
+
+struct st_time {
+	uint32_t rev;
+	uint32_t attr;
+	uint64_t st_time;
+};
+
+#define STEAL_TIME_SIZE		((sizeof(struct st_time) + 63) & ~63)
+#define ST_GPA_BASE		(1 << 30)
+
+static void steal_time_init(struct kvm_vm *vm)
+{
+	uint64_t st_ipa = (ulong)ST_GPA_BASE;
+	unsigned int gpages;
+	struct kvm_device_attr dev = {
+		.group = KVM_ARM_VCPU_PVTIME_CTRL,
+		.attr = KVM_ARM_VCPU_PVTIME_IPA,
+		.addr = (uint64_t)&st_ipa,
+	};
+
+	gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
+
+	vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
+}
+
+static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
+{
+	uint64_t val;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
+		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
+
+		/* First 'read' should be an upper limit of the features supported */
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
+			"Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
+			reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
+
+		/* Test a 'write' by disabling all the features of the register map */
+		ret = set_fw_reg(vm, reg_info->reg, 0);
+		TEST_ASSERT(ret == 0,
+			"Failed to clear all the features of reg: 0x%lx; ret: %d\n",
+			reg_info->reg, errno);
+
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == 0,
+			"Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
+
+		/*
+		 * Test enabling a feature that's not supported.
+		 * Avoid this check if all the bits are occupied.
+		 */
+		if (reg_info->max_feat_bit < 63) {
+			ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
+			TEST_ASSERT(ret != 0 && errno == EINVAL,
+			"Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
+			errno, reg_info->reg);
+		}
+	}
+}
+
+static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
+{
+	uint64_t val;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
+		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
+
+		/*
+		 * Before starting the VM, the test clears all the bits.
+		 * Check if that's still the case.
+		 */
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == 0,
+			"Expected all the features to be cleared for reg: 0x%lx\n",
+			reg_info->reg);
+
+		/*
+		 * Set all the features for this register again. KVM shouldn't
+		 * allow this as the VM is running.
+		 */
+		ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
+		TEST_ASSERT(ret != 0 && errno == EBUSY,
+		"Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
+		errno, reg_info->reg);
+	}
+}
+
+static struct kvm_vm *test_vm_create(void)
+{
+	struct kvm_vm *vm;
+
+	vm = vm_create_default(0, 0, guest_code);
+
+	ucall_init(vm, NULL);
+	steal_time_init(vm);
+
+	return vm;
+}
+
+static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
+{
+	struct kvm_vm *ret_vm = vm;
+
+	pr_debug("Stage: %d\n", stage);
+
+	switch (stage) {
+	case TEST_STAGE_REG_IFACE:
+		test_fw_regs_after_vm_start(vm);
+		break;
+	case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		/* Start a new VM so that all the features are now enabled by default */
+		kvm_vm_free(vm);
+		ret_vm = test_vm_create();
+		break;
+	case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+	case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+		break;
+	default:
+		TEST_FAIL("Unknown test stage: %d\n", stage);
+	}
+
+	stage++;
+	sync_global_to_guest(vm, stage);
+
+	return ret_vm;
+}
+
+static void test_run(void)
+{
+	struct kvm_vm *vm;
+	struct ucall uc;
+	bool guest_done = false;
+
+	vm = test_vm_create();
+
+	test_fw_regs_before_vm_start(vm);
+
+	while (!guest_done) {
+		vcpu_run(vm, 0);
+
+		switch (get_ucall(vm, 0, &uc)) {
+		case UCALL_SYNC:
+			vm = test_guest_stage(vm);
+			break;
+		case UCALL_DONE:
+			guest_done = true;
+			break;
+		case UCALL_ABORT:
+			TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
+			(const char *)uc.args[0], __FILE__, uc.args[1],
+			uc.args[2], uc.args[3], uc.args[4], stage);
+			break;
+		default:
+			TEST_FAIL("Unexpected guest exit\n");
+		}
+	}
+
+	kvm_vm_free(vm);
+}
+
+int main(void)
+{
+	setbuf(stdout, NULL);
+
+	test_run();
+	return 0;
+}
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Introduce a KVM selftest to check the hypercall interface
for arm64 platforms. The test validates the user-space'
[GET|SET]_ONE_REG interface to read/write the psuedo-firmware
registers as well as its effects on the guest upon certain
configurations.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
 3 files changed, 337 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c

diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
index 1bb575dfc42e..b17e464ec661 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -2,6 +2,7 @@
 /aarch64/arch_timer
 /aarch64/debug-exceptions
 /aarch64/get-reg-list
+/aarch64/hypercalls
 /aarch64/psci_test
 /aarch64/vcpu_width_config
 /aarch64/vgic_init
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index c2cf4d318296..97eef0c03d3b 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
 TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
 TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
 TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
+TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
 TEST_GEN_PROGS_aarch64 += aarch64/psci_test
 TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
 TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
new file mode 100644
index 000000000000..f404343a0ae3
--- /dev/null
+++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
+ *
+ * The test validates the basic hypercall functionalities that are exposed
+ * via the psuedo-firmware bitmap register. This includes the registers'
+ * read/write behavior before and after the VM has started, and if the
+ * hypercalls are properly masked or unmasked to the guest when disabled or
+ * enabled from the KVM userspace, respectively.
+ */
+
+#include <errno.h>
+#include <linux/arm-smccc.h>
+#include <asm/kvm.h>
+#include <kvm_util.h>
+
+#include "processor.h"
+
+#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
+
+/* Last valid bits of the bitmapped firmware registers */
+#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
+#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
+
+struct kvm_fw_reg_info {
+	uint64_t reg;		/* Register definition */
+	uint64_t max_feat_bit;	/* Bit that represents the upper limit of the feature-map */
+};
+
+#define FW_REG_INFO(r)			\
+	{					\
+		.reg = r,			\
+		.max_feat_bit = r##_BIT_MAX,	\
+	}
+
+static const struct kvm_fw_reg_info fw_reg_info[] = {
+	FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
+	FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
+	FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
+};
+
+enum test_stage {
+	TEST_STAGE_REG_IFACE,
+	TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
+	TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
+	TEST_STAGE_HVC_IFACE_FALSE_INFO,
+	TEST_STAGE_END,
+};
+
+static int stage = TEST_STAGE_REG_IFACE;
+
+struct test_hvc_info {
+	uint32_t func_id;
+	uint64_t arg1;
+};
+
+#define TEST_HVC_INFO(f, a1)	\
+	{			\
+		.func_id = f,	\
+		.arg1 = a1,	\
+	}
+
+static const struct test_hvc_info hvc_info[] = {
+	/* KVM_REG_ARM_STD_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
+
+	/* KVM_REG_ARM_STD_HYP_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
+
+	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
+			ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
+};
+
+/* Feed false hypercall info to test the KVM behavior */
+static const struct test_hvc_info false_hvc_info[] = {
+	/* Feature support check against a different family of hypercalls */
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
+	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
+};
+
+static void guest_test_hvc(const struct test_hvc_info *hc_info)
+{
+	unsigned int i;
+	struct arm_smccc_res res;
+	unsigned int hvc_info_arr_sz;
+
+	hvc_info_arr_sz =
+	hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
+
+	for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
+		memset(&res, 0, sizeof(res));
+		smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
+
+		switch (stage) {
+		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+			GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
+					res.a0, hc_info->func_id, hc_info->arg1);
+			break;
+		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+			GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
+					res.a0, hc_info->func_id, hc_info->arg1);
+			break;
+		default:
+			GUEST_ASSERT_1(0, stage);
+		}
+	}
+}
+
+static void guest_code(void)
+{
+	while (stage != TEST_STAGE_END) {
+		switch (stage) {
+		case TEST_STAGE_REG_IFACE:
+			break;
+		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+			guest_test_hvc(hvc_info);
+			break;
+		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+			guest_test_hvc(false_hvc_info);
+			break;
+		default:
+			GUEST_ASSERT_1(0, stage);
+		}
+
+		GUEST_SYNC(stage);
+	}
+
+	GUEST_DONE();
+}
+
+static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
+{
+	struct kvm_one_reg reg = {
+		.id = id,
+		.addr = (uint64_t)&val,
+	};
+
+	return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
+}
+
+static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
+{
+	struct kvm_one_reg reg = {
+		.id = id,
+		.addr = (uint64_t)addr,
+	};
+
+	vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
+}
+
+struct st_time {
+	uint32_t rev;
+	uint32_t attr;
+	uint64_t st_time;
+};
+
+#define STEAL_TIME_SIZE		((sizeof(struct st_time) + 63) & ~63)
+#define ST_GPA_BASE		(1 << 30)
+
+static void steal_time_init(struct kvm_vm *vm)
+{
+	uint64_t st_ipa = (ulong)ST_GPA_BASE;
+	unsigned int gpages;
+	struct kvm_device_attr dev = {
+		.group = KVM_ARM_VCPU_PVTIME_CTRL,
+		.attr = KVM_ARM_VCPU_PVTIME_IPA,
+		.addr = (uint64_t)&st_ipa,
+	};
+
+	gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
+
+	vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
+}
+
+static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
+{
+	uint64_t val;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
+		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
+
+		/* First 'read' should be an upper limit of the features supported */
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
+			"Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
+			reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
+
+		/* Test a 'write' by disabling all the features of the register map */
+		ret = set_fw_reg(vm, reg_info->reg, 0);
+		TEST_ASSERT(ret == 0,
+			"Failed to clear all the features of reg: 0x%lx; ret: %d\n",
+			reg_info->reg, errno);
+
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == 0,
+			"Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
+
+		/*
+		 * Test enabling a feature that's not supported.
+		 * Avoid this check if all the bits are occupied.
+		 */
+		if (reg_info->max_feat_bit < 63) {
+			ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
+			TEST_ASSERT(ret != 0 && errno == EINVAL,
+			"Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
+			errno, reg_info->reg);
+		}
+	}
+}
+
+static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
+{
+	uint64_t val;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
+		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
+
+		/*
+		 * Before starting the VM, the test clears all the bits.
+		 * Check if that's still the case.
+		 */
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == 0,
+			"Expected all the features to be cleared for reg: 0x%lx\n",
+			reg_info->reg);
+
+		/*
+		 * Set all the features for this register again. KVM shouldn't
+		 * allow this as the VM is running.
+		 */
+		ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
+		TEST_ASSERT(ret != 0 && errno == EBUSY,
+		"Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
+		errno, reg_info->reg);
+	}
+}
+
+static struct kvm_vm *test_vm_create(void)
+{
+	struct kvm_vm *vm;
+
+	vm = vm_create_default(0, 0, guest_code);
+
+	ucall_init(vm, NULL);
+	steal_time_init(vm);
+
+	return vm;
+}
+
+static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
+{
+	struct kvm_vm *ret_vm = vm;
+
+	pr_debug("Stage: %d\n", stage);
+
+	switch (stage) {
+	case TEST_STAGE_REG_IFACE:
+		test_fw_regs_after_vm_start(vm);
+		break;
+	case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		/* Start a new VM so that all the features are now enabled by default */
+		kvm_vm_free(vm);
+		ret_vm = test_vm_create();
+		break;
+	case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+	case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+		break;
+	default:
+		TEST_FAIL("Unknown test stage: %d\n", stage);
+	}
+
+	stage++;
+	sync_global_to_guest(vm, stage);
+
+	return ret_vm;
+}
+
+static void test_run(void)
+{
+	struct kvm_vm *vm;
+	struct ucall uc;
+	bool guest_done = false;
+
+	vm = test_vm_create();
+
+	test_fw_regs_before_vm_start(vm);
+
+	while (!guest_done) {
+		vcpu_run(vm, 0);
+
+		switch (get_ucall(vm, 0, &uc)) {
+		case UCALL_SYNC:
+			vm = test_guest_stage(vm);
+			break;
+		case UCALL_DONE:
+			guest_done = true;
+			break;
+		case UCALL_ABORT:
+			TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
+			(const char *)uc.args[0], __FILE__, uc.args[1],
+			uc.args[2], uc.args[3], uc.args[4], stage);
+			break;
+		default:
+			TEST_FAIL("Unexpected guest exit\n");
+		}
+	}
+
+	kvm_vm_free(vm);
+}
+
+int main(void)
+{
+	setbuf(stdout, NULL);
+
+	test_run();
+	return 0;
+}
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Introduce a KVM selftest to check the hypercall interface
for arm64 platforms. The test validates the user-space'
[GET|SET]_ONE_REG interface to read/write the psuedo-firmware
registers as well as its effects on the guest upon certain
configurations.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
 3 files changed, 337 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c

diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
index 1bb575dfc42e..b17e464ec661 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -2,6 +2,7 @@
 /aarch64/arch_timer
 /aarch64/debug-exceptions
 /aarch64/get-reg-list
+/aarch64/hypercalls
 /aarch64/psci_test
 /aarch64/vcpu_width_config
 /aarch64/vgic_init
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index c2cf4d318296..97eef0c03d3b 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
 TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
 TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
 TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
+TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
 TEST_GEN_PROGS_aarch64 += aarch64/psci_test
 TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
 TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
new file mode 100644
index 000000000000..f404343a0ae3
--- /dev/null
+++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
+ *
+ * The test validates the basic hypercall functionalities that are exposed
+ * via the psuedo-firmware bitmap register. This includes the registers'
+ * read/write behavior before and after the VM has started, and if the
+ * hypercalls are properly masked or unmasked to the guest when disabled or
+ * enabled from the KVM userspace, respectively.
+ */
+
+#include <errno.h>
+#include <linux/arm-smccc.h>
+#include <asm/kvm.h>
+#include <kvm_util.h>
+
+#include "processor.h"
+
+#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
+
+/* Last valid bits of the bitmapped firmware registers */
+#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
+#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
+#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
+
+struct kvm_fw_reg_info {
+	uint64_t reg;		/* Register definition */
+	uint64_t max_feat_bit;	/* Bit that represents the upper limit of the feature-map */
+};
+
+#define FW_REG_INFO(r)			\
+	{					\
+		.reg = r,			\
+		.max_feat_bit = r##_BIT_MAX,	\
+	}
+
+static const struct kvm_fw_reg_info fw_reg_info[] = {
+	FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
+	FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
+	FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
+};
+
+enum test_stage {
+	TEST_STAGE_REG_IFACE,
+	TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
+	TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
+	TEST_STAGE_HVC_IFACE_FALSE_INFO,
+	TEST_STAGE_END,
+};
+
+static int stage = TEST_STAGE_REG_IFACE;
+
+struct test_hvc_info {
+	uint32_t func_id;
+	uint64_t arg1;
+};
+
+#define TEST_HVC_INFO(f, a1)	\
+	{			\
+		.func_id = f,	\
+		.arg1 = a1,	\
+	}
+
+static const struct test_hvc_info hvc_info[] = {
+	/* KVM_REG_ARM_STD_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
+
+	/* KVM_REG_ARM_STD_HYP_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
+
+	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
+			ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
+	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
+};
+
+/* Feed false hypercall info to test the KVM behavior */
+static const struct test_hvc_info false_hvc_info[] = {
+	/* Feature support check against a different family of hypercalls */
+	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
+	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
+	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
+};
+
+static void guest_test_hvc(const struct test_hvc_info *hc_info)
+{
+	unsigned int i;
+	struct arm_smccc_res res;
+	unsigned int hvc_info_arr_sz;
+
+	hvc_info_arr_sz =
+	hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
+
+	for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
+		memset(&res, 0, sizeof(res));
+		smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
+
+		switch (stage) {
+		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+			GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
+					res.a0, hc_info->func_id, hc_info->arg1);
+			break;
+		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+			GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
+					res.a0, hc_info->func_id, hc_info->arg1);
+			break;
+		default:
+			GUEST_ASSERT_1(0, stage);
+		}
+	}
+}
+
+static void guest_code(void)
+{
+	while (stage != TEST_STAGE_END) {
+		switch (stage) {
+		case TEST_STAGE_REG_IFACE:
+			break;
+		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+			guest_test_hvc(hvc_info);
+			break;
+		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+			guest_test_hvc(false_hvc_info);
+			break;
+		default:
+			GUEST_ASSERT_1(0, stage);
+		}
+
+		GUEST_SYNC(stage);
+	}
+
+	GUEST_DONE();
+}
+
+static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
+{
+	struct kvm_one_reg reg = {
+		.id = id,
+		.addr = (uint64_t)&val,
+	};
+
+	return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
+}
+
+static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
+{
+	struct kvm_one_reg reg = {
+		.id = id,
+		.addr = (uint64_t)addr,
+	};
+
+	vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
+}
+
+struct st_time {
+	uint32_t rev;
+	uint32_t attr;
+	uint64_t st_time;
+};
+
+#define STEAL_TIME_SIZE		((sizeof(struct st_time) + 63) & ~63)
+#define ST_GPA_BASE		(1 << 30)
+
+static void steal_time_init(struct kvm_vm *vm)
+{
+	uint64_t st_ipa = (ulong)ST_GPA_BASE;
+	unsigned int gpages;
+	struct kvm_device_attr dev = {
+		.group = KVM_ARM_VCPU_PVTIME_CTRL,
+		.attr = KVM_ARM_VCPU_PVTIME_IPA,
+		.addr = (uint64_t)&st_ipa,
+	};
+
+	gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
+
+	vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
+}
+
+static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
+{
+	uint64_t val;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
+		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
+
+		/* First 'read' should be an upper limit of the features supported */
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
+			"Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
+			reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
+
+		/* Test a 'write' by disabling all the features of the register map */
+		ret = set_fw_reg(vm, reg_info->reg, 0);
+		TEST_ASSERT(ret == 0,
+			"Failed to clear all the features of reg: 0x%lx; ret: %d\n",
+			reg_info->reg, errno);
+
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == 0,
+			"Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
+
+		/*
+		 * Test enabling a feature that's not supported.
+		 * Avoid this check if all the bits are occupied.
+		 */
+		if (reg_info->max_feat_bit < 63) {
+			ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
+			TEST_ASSERT(ret != 0 && errno == EINVAL,
+			"Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
+			errno, reg_info->reg);
+		}
+	}
+}
+
+static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
+{
+	uint64_t val;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
+		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
+
+		/*
+		 * Before starting the VM, the test clears all the bits.
+		 * Check if that's still the case.
+		 */
+		get_fw_reg(vm, reg_info->reg, &val);
+		TEST_ASSERT(val == 0,
+			"Expected all the features to be cleared for reg: 0x%lx\n",
+			reg_info->reg);
+
+		/*
+		 * Set all the features for this register again. KVM shouldn't
+		 * allow this as the VM is running.
+		 */
+		ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
+		TEST_ASSERT(ret != 0 && errno == EBUSY,
+		"Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
+		errno, reg_info->reg);
+	}
+}
+
+static struct kvm_vm *test_vm_create(void)
+{
+	struct kvm_vm *vm;
+
+	vm = vm_create_default(0, 0, guest_code);
+
+	ucall_init(vm, NULL);
+	steal_time_init(vm);
+
+	return vm;
+}
+
+static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
+{
+	struct kvm_vm *ret_vm = vm;
+
+	pr_debug("Stage: %d\n", stage);
+
+	switch (stage) {
+	case TEST_STAGE_REG_IFACE:
+		test_fw_regs_after_vm_start(vm);
+		break;
+	case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
+		/* Start a new VM so that all the features are now enabled by default */
+		kvm_vm_free(vm);
+		ret_vm = test_vm_create();
+		break;
+	case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
+	case TEST_STAGE_HVC_IFACE_FALSE_INFO:
+		break;
+	default:
+		TEST_FAIL("Unknown test stage: %d\n", stage);
+	}
+
+	stage++;
+	sync_global_to_guest(vm, stage);
+
+	return ret_vm;
+}
+
+static void test_run(void)
+{
+	struct kvm_vm *vm;
+	struct ucall uc;
+	bool guest_done = false;
+
+	vm = test_vm_create();
+
+	test_fw_regs_before_vm_start(vm);
+
+	while (!guest_done) {
+		vcpu_run(vm, 0);
+
+		switch (get_ucall(vm, 0, &uc)) {
+		case UCALL_SYNC:
+			vm = test_guest_stage(vm);
+			break;
+		case UCALL_DONE:
+			guest_done = true;
+			break;
+		case UCALL_ABORT:
+			TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
+			(const char *)uc.args[0], __FILE__, uc.args[1],
+			uc.args[2], uc.args[3], uc.args[4], stage);
+			break;
+		default:
+			TEST_FAIL("Unexpected guest exit\n");
+		}
+	}
+
+	kvm_vm_free(vm);
+}
+
+int main(void)
+{
+	setbuf(stdout, NULL);
+
+	test_run();
+	return 0;
+}
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v6 9/9] selftests: KVM: aarch64: Add the bitmap firmware registers to get-reg-list
  2022-04-23  0:03 ` Raghavendra Rao Ananta
  (?)
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Add the psuedo-firmware registers KVM_REG_ARM_STD_BMAP,
KVM_REG_ARM_STD_HYP_BMAP, and KVM_REG_ARM_VENDOR_HYP_BMAP to
the base_regs[] list.

Also, add the COPROC support for KVM_REG_ARM_FW_FEAT_BMAP.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/testing/selftests/kvm/aarch64/get-reg-list.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c
index 0b571f3fe64c..d3a7dbfcbb3d 100644
--- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c
+++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c
@@ -294,6 +294,11 @@ static void print_reg(struct vcpu_config *c, __u64 id)
 			    "%s: Unexpected bits set in FW reg id: 0x%llx", config_name(c), id);
 		printf("\tKVM_REG_ARM_FW_REG(%lld),\n", id & 0xffff);
 		break;
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		TEST_ASSERT(id == KVM_REG_ARM_FW_FEAT_BMAP_REG(id & 0xffff),
+			    "%s: Unexpected bits set in the bitmap feature FW reg id: 0x%llx", config_name(c), id);
+		printf("\tKVM_REG_ARM_FW_FEAT_BMAP_REG(%lld),\n", id & 0xffff);
+		break;
 	case KVM_REG_ARM64_SVE:
 		if (has_cap(c, KVM_CAP_ARM_SVE))
 			printf("\t%s,\n", sve_id_to_str(c, id));
@@ -692,6 +697,9 @@ static __u64 base_regs[] = {
 	KVM_REG_ARM_FW_REG(1),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 */
 	KVM_REG_ARM_FW_REG(2),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 */
 	KVM_REG_ARM_FW_REG(3),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(0),	/* KVM_REG_ARM_STD_BMAP */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(1),	/* KVM_REG_ARM_STD_HYP_BMAP */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(2),	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
 	ARM64_SYS_REG(3, 3, 14, 3, 1),	/* CNTV_CTL_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 3, 2),	/* CNTV_CVAL_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 0, 2),
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


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

* [PATCH v6 9/9] selftests: KVM: aarch64: Add the bitmap firmware registers to get-reg-list
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Add the psuedo-firmware registers KVM_REG_ARM_STD_BMAP,
KVM_REG_ARM_STD_HYP_BMAP, and KVM_REG_ARM_VENDOR_HYP_BMAP to
the base_regs[] list.

Also, add the COPROC support for KVM_REG_ARM_FW_FEAT_BMAP.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/testing/selftests/kvm/aarch64/get-reg-list.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c
index 0b571f3fe64c..d3a7dbfcbb3d 100644
--- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c
+++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c
@@ -294,6 +294,11 @@ static void print_reg(struct vcpu_config *c, __u64 id)
 			    "%s: Unexpected bits set in FW reg id: 0x%llx", config_name(c), id);
 		printf("\tKVM_REG_ARM_FW_REG(%lld),\n", id & 0xffff);
 		break;
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		TEST_ASSERT(id == KVM_REG_ARM_FW_FEAT_BMAP_REG(id & 0xffff),
+			    "%s: Unexpected bits set in the bitmap feature FW reg id: 0x%llx", config_name(c), id);
+		printf("\tKVM_REG_ARM_FW_FEAT_BMAP_REG(%lld),\n", id & 0xffff);
+		break;
 	case KVM_REG_ARM64_SVE:
 		if (has_cap(c, KVM_CAP_ARM_SVE))
 			printf("\t%s,\n", sve_id_to_str(c, id));
@@ -692,6 +697,9 @@ static __u64 base_regs[] = {
 	KVM_REG_ARM_FW_REG(1),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 */
 	KVM_REG_ARM_FW_REG(2),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 */
 	KVM_REG_ARM_FW_REG(3),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(0),	/* KVM_REG_ARM_STD_BMAP */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(1),	/* KVM_REG_ARM_STD_HYP_BMAP */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(2),	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
 	ARM64_SYS_REG(3, 3, 14, 3, 1),	/* CNTV_CTL_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 3, 2),	/* CNTV_CVAL_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 0, 2),
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v6 9/9] selftests: KVM: aarch64: Add the bitmap firmware registers to get-reg-list
@ 2022-04-23  0:03   ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-23  0:03 UTC (permalink / raw)
  To: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose
  Cc: Paolo Bonzini, Catalin Marinas, Will Deacon, Peter Shier,
	Ricardo Koller, Oliver Upton, Reiji Watanabe, Jing Zhang,
	Raghavendra Rao Anata, linux-arm-kernel, kvmarm, linux-kernel,
	kvm

Add the psuedo-firmware registers KVM_REG_ARM_STD_BMAP,
KVM_REG_ARM_STD_HYP_BMAP, and KVM_REG_ARM_VENDOR_HYP_BMAP to
the base_regs[] list.

Also, add the COPROC support for KVM_REG_ARM_FW_FEAT_BMAP.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
 tools/testing/selftests/kvm/aarch64/get-reg-list.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c
index 0b571f3fe64c..d3a7dbfcbb3d 100644
--- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c
+++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c
@@ -294,6 +294,11 @@ static void print_reg(struct vcpu_config *c, __u64 id)
 			    "%s: Unexpected bits set in FW reg id: 0x%llx", config_name(c), id);
 		printf("\tKVM_REG_ARM_FW_REG(%lld),\n", id & 0xffff);
 		break;
+	case KVM_REG_ARM_FW_FEAT_BMAP:
+		TEST_ASSERT(id == KVM_REG_ARM_FW_FEAT_BMAP_REG(id & 0xffff),
+			    "%s: Unexpected bits set in the bitmap feature FW reg id: 0x%llx", config_name(c), id);
+		printf("\tKVM_REG_ARM_FW_FEAT_BMAP_REG(%lld),\n", id & 0xffff);
+		break;
 	case KVM_REG_ARM64_SVE:
 		if (has_cap(c, KVM_CAP_ARM_SVE))
 			printf("\t%s,\n", sve_id_to_str(c, id));
@@ -692,6 +697,9 @@ static __u64 base_regs[] = {
 	KVM_REG_ARM_FW_REG(1),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 */
 	KVM_REG_ARM_FW_REG(2),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 */
 	KVM_REG_ARM_FW_REG(3),		/* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(0),	/* KVM_REG_ARM_STD_BMAP */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(1),	/* KVM_REG_ARM_STD_HYP_BMAP */
+	KVM_REG_ARM_FW_FEAT_BMAP_REG(2),	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
 	ARM64_SYS_REG(3, 3, 14, 3, 1),	/* CNTV_CTL_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 3, 2),	/* CNTV_CVAL_EL0 */
 	ARM64_SYS_REG(3, 3, 14, 0, 2),
-- 
2.36.0.rc2.479.g8af0fa9b8e-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-25  4:52     ` Reiji Watanabe
  -1 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  4:52 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> KVM regularly introduces new hypercall services to the guests without
> any consent from the userspace. This means, the guests can observe
> hypercall services in and out as they migrate across various host
> kernel versions. This could be a major problem if the guest
> discovered a hypercall, started using it, and after getting migrated
> to an older kernel realizes that it's no longer available. Depending
> on how the guest handles the change, there's a potential chance that
> the guest would just panic.
>
> As a result, there's a need for the userspace to elect the services
> that it wishes the guest to discover. It can elect these services
> based on the kernels spread across its (migration) fleet. To remedy
> this, extend the existing firmware pseudo-registers, such as
> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> for all the hypercall services available.
>
> These firmware registers are categorized based on the service call
> owners, but unlike the existing firmware pseudo-registers, they hold
> the features supported in the form of a bitmap.
>
> During the VM initialization, the registers are set to upper-limit of
> the features supported by the corresponding registers. It's expected
> that the VMMs discover the features provided by each register via
> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> KVM allows this modification only until the VM has started.
>
> Some of the standard features are not mapped to any bits of the
> registers. But since they can recreate the original problem of
> making it available without userspace's consent, they need to
> be explicitly added to the case-list in
> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
>
> Older userspace code can simply ignore the feature and the
> hypercall services will be exposed unconditionally to the guests,
> thus ensuring backward compatibility.
>
> In this patch, the framework adds the register only for ARM's standard
> secure services (owner value 4). Currently, this includes support only
> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> register representing mandatory features of v1.0. Other services are
> momentarily added in the upcoming patches.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 12 ++++
>  arch/arm64/include/uapi/asm/kvm.h |  9 +++
>  arch/arm64/kvm/arm.c              |  1 +
>  arch/arm64/kvm/guest.c            |  8 ++-
>  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>  arch/arm64/kvm/psci.c             | 13 +++++
>  include/kvm/arm_hypercalls.h      |  6 ++
>  include/kvm/arm_psci.h            |  2 +-
>  8 files changed, 142 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 94a27a7520f4..df07f4c10197 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>  struct kvm_arch_memory_slot {
>  };
>
> +/**
> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> + *
> + * @std_bmap: Bitmap of standard secure service calls
> + */
> +struct kvm_smccc_features {
> +       unsigned long std_bmap;
> +};
> +
>  struct kvm_arch {
>         struct kvm_s2_mmu mmu;
>
> @@ -150,6 +159,9 @@ struct kvm_arch {
>
>         u8 pfr0_csv2;
>         u8 pfr0_csv3;
> +
> +       /* Hypercall features firmware registers' descriptor */
> +       struct kvm_smccc_features smccc_feat;
>  };
>
>  struct kvm_vcpu_fault_info {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index c1b6ddc02d2f..0b79d2dc6ffd 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>  #define KVM_ARM64_SVE_VLS_WORDS        \
>         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>
> +/* Bitmap feature firmware registers */
> +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> +                                               ((r) & 0xffff))
> +
> +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> index 523bc934fe2f..a37fadbd617e 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>
>         set_default_spectre(kvm);
> +       kvm_arm_init_hypercalls(kvm);
>
>         return ret;
>  out_free_stage2_pgd:
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 0d5cca56cbda..8c607199cad1 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>
>         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> +       case KVM_REG_ARM_FW:
> +       case KVM_REG_ARM_FW_FEAT_BMAP:
> +               return kvm_arm_get_fw_reg(vcpu, reg);
>         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
>         }
>
> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>
>         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> +       case KVM_REG_ARM_FW:
> +       case KVM_REG_ARM_FW_FEAT_BMAP:
> +               return kvm_arm_set_fw_reg(vcpu, reg);
>         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
>         }
>
> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index fa6d9378d8e7..df55a04d2fe8 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>         val[3] = lower_32_bits(cycles);
>  }
>
> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> +{
> +       return test_bit(feat_bit, reg_bmap);
> +}
> +
> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       switch (func_id) {
> +       /*
> +        * List of function-ids that are not gated with the bitmapped feature
> +        * firmware registers, and are to be allowed for servicing the call by default.
> +        */
> +       case ARM_SMCCC_VERSION_FUNC_ID:
> +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +       case ARM_SMCCC_HV_PV_TIME_ST:
> +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +               return true;
> +       default:
> +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> +       }
> +}
> +
> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> +
> +       switch (func_id) {
> +       case ARM_SMCCC_TRNG_VERSION:
> +       case ARM_SMCCC_TRNG_FEATURES:
> +       case ARM_SMCCC_TRNG_GET_UUID:
> +       case ARM_SMCCC_TRNG_RND32:
> +       case ARM_SMCCC_TRNG_RND64:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +       default:
> +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> +       }
> +}
> +
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>  {
>         u32 func_id = smccc_get_function(vcpu);
> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>         u32 feature;
>         gpa_t gpa;
>
> +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> +               goto out;
> +
>         switch (func_id) {
>         case ARM_SMCCC_VERSION_FUNC_ID:
>                 val[0] = ARM_SMCCC_VERSION_1_1;
> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>                 return kvm_psci_call(vcpu);
>         }
>
> +out:
>         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>         return 1;
>  }
> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> +       KVM_REG_ARM_STD_BMAP,
>  };
>
> +void kvm_arm_init_hypercalls(struct kvm *kvm)
> +{
> +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +
> +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +}
> +
>  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>  {
>         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>
>  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  {
> +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>         void __user *uaddr = (void __user *)(long)reg->addr;
>         u64 val;
>
> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>                 break;
> +       case KVM_REG_ARM_STD_BMAP:
> +               val = READ_ONCE(smccc_feat->std_bmap);
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         return 0;
>  }
>
> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> +{
> +       int ret = 0;
> +       struct kvm *kvm = vcpu->kvm;
> +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +       unsigned long *fw_reg_bmap, fw_reg_features;
> +
> +       switch (reg_id) {
> +       case KVM_REG_ARM_STD_BMAP:
> +               fw_reg_bmap = &smccc_feat->std_bmap;
> +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> +               break;
> +       default:
> +               return -ENOENT;
> +       }
> +
> +       /* Check for unsupported bit */
> +       if (val & ~fw_reg_features)
> +               return -EINVAL;
> +
> +       mutex_lock(&kvm->lock);

Why don't you check if the register value will be modified before
getting the lock ? (then there is nothing to do)
It would help reduce unnecessary serialization for live migration
(even without the vm-scoped register capability).



> +
> +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> +               ret = -EBUSY;
> +               goto out;
> +       }

I just would like to make sure that you are sure that existing
userspace you know will not run KVM_RUN for any vCPUs until
KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
correct ?


> +
> +       WRITE_ONCE(*fw_reg_bmap, val);
> +out:
> +       mutex_unlock(&kvm->lock);
> +       return ret;
> +}
> +
>  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  {
>         void __user *uaddr = (void __user *)(long)reg->addr;
> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>                         return -EINVAL;
>
>                 return 0;
> +       case KVM_REG_ARM_STD_BMAP:
> +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>         default:
>                 return -ENOENT;
>         }
> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> index 346535169faa..67d1273e8086 100644
> --- a/arch/arm64/kvm/psci.c
> +++ b/arch/arm64/kvm/psci.c
> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>                 return -EINVAL;
>         }
>  }
> +
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> +
> +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> +               return true;

For PSCI 0.1, the function checks if the funct_id is valid for
the vCPU (according to the vCPU's PSCI version).
For other version of PSCI, the function doesn't care the vCPU's
PSCI version (although supported functions depend on the PSCI
version and not all of them are defined yet, the code returns
true as long as the function id is within the reserved PSCI
function id range).
So, the behavior appears to be inconsistent.
Shouldn't it return the validity of the function id according
to the vCPU's psci version for non-PSCI 0.1 case as well ?
(Otherwise, shouldn't it return true if the function id is valid
for any of the PSCI versions ?)

Thanks,
Reiji



> +
> +       return false;
> +}
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 5d38628a8d04..499b45b607b6 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -6,6 +6,11 @@
>
>  #include <asm/kvm_emulate.h>
>
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> +
> +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>
>  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>
>  struct kvm_one_reg;
>
> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>  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);
> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> index 6e55b9283789..c47be3e26965 100644
> --- a/include/kvm/arm_psci.h
> +++ b/include/kvm/arm_psci.h
> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>         return KVM_ARM_PSCI_0_1;
>  }
>
> -
>  int kvm_psci_call(struct kvm_vcpu *vcpu);
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>
>  #endif /* __KVM_ARM_PSCI_H__ */
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-25  4:52     ` Reiji Watanabe
  0 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  4:52 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> KVM regularly introduces new hypercall services to the guests without
> any consent from the userspace. This means, the guests can observe
> hypercall services in and out as they migrate across various host
> kernel versions. This could be a major problem if the guest
> discovered a hypercall, started using it, and after getting migrated
> to an older kernel realizes that it's no longer available. Depending
> on how the guest handles the change, there's a potential chance that
> the guest would just panic.
>
> As a result, there's a need for the userspace to elect the services
> that it wishes the guest to discover. It can elect these services
> based on the kernels spread across its (migration) fleet. To remedy
> this, extend the existing firmware pseudo-registers, such as
> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> for all the hypercall services available.
>
> These firmware registers are categorized based on the service call
> owners, but unlike the existing firmware pseudo-registers, they hold
> the features supported in the form of a bitmap.
>
> During the VM initialization, the registers are set to upper-limit of
> the features supported by the corresponding registers. It's expected
> that the VMMs discover the features provided by each register via
> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> KVM allows this modification only until the VM has started.
>
> Some of the standard features are not mapped to any bits of the
> registers. But since they can recreate the original problem of
> making it available without userspace's consent, they need to
> be explicitly added to the case-list in
> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
>
> Older userspace code can simply ignore the feature and the
> hypercall services will be exposed unconditionally to the guests,
> thus ensuring backward compatibility.
>
> In this patch, the framework adds the register only for ARM's standard
> secure services (owner value 4). Currently, this includes support only
> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> register representing mandatory features of v1.0. Other services are
> momentarily added in the upcoming patches.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 12 ++++
>  arch/arm64/include/uapi/asm/kvm.h |  9 +++
>  arch/arm64/kvm/arm.c              |  1 +
>  arch/arm64/kvm/guest.c            |  8 ++-
>  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>  arch/arm64/kvm/psci.c             | 13 +++++
>  include/kvm/arm_hypercalls.h      |  6 ++
>  include/kvm/arm_psci.h            |  2 +-
>  8 files changed, 142 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 94a27a7520f4..df07f4c10197 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>  struct kvm_arch_memory_slot {
>  };
>
> +/**
> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> + *
> + * @std_bmap: Bitmap of standard secure service calls
> + */
> +struct kvm_smccc_features {
> +       unsigned long std_bmap;
> +};
> +
>  struct kvm_arch {
>         struct kvm_s2_mmu mmu;
>
> @@ -150,6 +159,9 @@ struct kvm_arch {
>
>         u8 pfr0_csv2;
>         u8 pfr0_csv3;
> +
> +       /* Hypercall features firmware registers' descriptor */
> +       struct kvm_smccc_features smccc_feat;
>  };
>
>  struct kvm_vcpu_fault_info {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index c1b6ddc02d2f..0b79d2dc6ffd 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>  #define KVM_ARM64_SVE_VLS_WORDS        \
>         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>
> +/* Bitmap feature firmware registers */
> +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> +                                               ((r) & 0xffff))
> +
> +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> index 523bc934fe2f..a37fadbd617e 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>
>         set_default_spectre(kvm);
> +       kvm_arm_init_hypercalls(kvm);
>
>         return ret;
>  out_free_stage2_pgd:
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 0d5cca56cbda..8c607199cad1 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>
>         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> +       case KVM_REG_ARM_FW:
> +       case KVM_REG_ARM_FW_FEAT_BMAP:
> +               return kvm_arm_get_fw_reg(vcpu, reg);
>         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
>         }
>
> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>
>         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> +       case KVM_REG_ARM_FW:
> +       case KVM_REG_ARM_FW_FEAT_BMAP:
> +               return kvm_arm_set_fw_reg(vcpu, reg);
>         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
>         }
>
> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index fa6d9378d8e7..df55a04d2fe8 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>         val[3] = lower_32_bits(cycles);
>  }
>
> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> +{
> +       return test_bit(feat_bit, reg_bmap);
> +}
> +
> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       switch (func_id) {
> +       /*
> +        * List of function-ids that are not gated with the bitmapped feature
> +        * firmware registers, and are to be allowed for servicing the call by default.
> +        */
> +       case ARM_SMCCC_VERSION_FUNC_ID:
> +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +       case ARM_SMCCC_HV_PV_TIME_ST:
> +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +               return true;
> +       default:
> +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> +       }
> +}
> +
> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> +
> +       switch (func_id) {
> +       case ARM_SMCCC_TRNG_VERSION:
> +       case ARM_SMCCC_TRNG_FEATURES:
> +       case ARM_SMCCC_TRNG_GET_UUID:
> +       case ARM_SMCCC_TRNG_RND32:
> +       case ARM_SMCCC_TRNG_RND64:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +       default:
> +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> +       }
> +}
> +
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>  {
>         u32 func_id = smccc_get_function(vcpu);
> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>         u32 feature;
>         gpa_t gpa;
>
> +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> +               goto out;
> +
>         switch (func_id) {
>         case ARM_SMCCC_VERSION_FUNC_ID:
>                 val[0] = ARM_SMCCC_VERSION_1_1;
> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>                 return kvm_psci_call(vcpu);
>         }
>
> +out:
>         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>         return 1;
>  }
> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> +       KVM_REG_ARM_STD_BMAP,
>  };
>
> +void kvm_arm_init_hypercalls(struct kvm *kvm)
> +{
> +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +
> +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +}
> +
>  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>  {
>         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>
>  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  {
> +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>         void __user *uaddr = (void __user *)(long)reg->addr;
>         u64 val;
>
> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>                 break;
> +       case KVM_REG_ARM_STD_BMAP:
> +               val = READ_ONCE(smccc_feat->std_bmap);
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         return 0;
>  }
>
> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> +{
> +       int ret = 0;
> +       struct kvm *kvm = vcpu->kvm;
> +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +       unsigned long *fw_reg_bmap, fw_reg_features;
> +
> +       switch (reg_id) {
> +       case KVM_REG_ARM_STD_BMAP:
> +               fw_reg_bmap = &smccc_feat->std_bmap;
> +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> +               break;
> +       default:
> +               return -ENOENT;
> +       }
> +
> +       /* Check for unsupported bit */
> +       if (val & ~fw_reg_features)
> +               return -EINVAL;
> +
> +       mutex_lock(&kvm->lock);

Why don't you check if the register value will be modified before
getting the lock ? (then there is nothing to do)
It would help reduce unnecessary serialization for live migration
(even without the vm-scoped register capability).



> +
> +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> +               ret = -EBUSY;
> +               goto out;
> +       }

I just would like to make sure that you are sure that existing
userspace you know will not run KVM_RUN for any vCPUs until
KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
correct ?


> +
> +       WRITE_ONCE(*fw_reg_bmap, val);
> +out:
> +       mutex_unlock(&kvm->lock);
> +       return ret;
> +}
> +
>  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  {
>         void __user *uaddr = (void __user *)(long)reg->addr;
> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>                         return -EINVAL;
>
>                 return 0;
> +       case KVM_REG_ARM_STD_BMAP:
> +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>         default:
>                 return -ENOENT;
>         }
> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> index 346535169faa..67d1273e8086 100644
> --- a/arch/arm64/kvm/psci.c
> +++ b/arch/arm64/kvm/psci.c
> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>                 return -EINVAL;
>         }
>  }
> +
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> +
> +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> +               return true;

For PSCI 0.1, the function checks if the funct_id is valid for
the vCPU (according to the vCPU's PSCI version).
For other version of PSCI, the function doesn't care the vCPU's
PSCI version (although supported functions depend on the PSCI
version and not all of them are defined yet, the code returns
true as long as the function id is within the reserved PSCI
function id range).
So, the behavior appears to be inconsistent.
Shouldn't it return the validity of the function id according
to the vCPU's psci version for non-PSCI 0.1 case as well ?
(Otherwise, shouldn't it return true if the function id is valid
for any of the PSCI versions ?)

Thanks,
Reiji



> +
> +       return false;
> +}
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 5d38628a8d04..499b45b607b6 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -6,6 +6,11 @@
>
>  #include <asm/kvm_emulate.h>
>
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> +
> +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>
>  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>
>  struct kvm_one_reg;
>
> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>  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);
> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> index 6e55b9283789..c47be3e26965 100644
> --- a/include/kvm/arm_psci.h
> +++ b/include/kvm/arm_psci.h
> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>         return KVM_ARM_PSCI_0_1;
>  }
>
> -
>  int kvm_psci_call(struct kvm_vcpu *vcpu);
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>
>  #endif /* __KVM_ARM_PSCI_H__ */
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-25  4:52     ` Reiji Watanabe
  0 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  4:52 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> KVM regularly introduces new hypercall services to the guests without
> any consent from the userspace. This means, the guests can observe
> hypercall services in and out as they migrate across various host
> kernel versions. This could be a major problem if the guest
> discovered a hypercall, started using it, and after getting migrated
> to an older kernel realizes that it's no longer available. Depending
> on how the guest handles the change, there's a potential chance that
> the guest would just panic.
>
> As a result, there's a need for the userspace to elect the services
> that it wishes the guest to discover. It can elect these services
> based on the kernels spread across its (migration) fleet. To remedy
> this, extend the existing firmware pseudo-registers, such as
> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> for all the hypercall services available.
>
> These firmware registers are categorized based on the service call
> owners, but unlike the existing firmware pseudo-registers, they hold
> the features supported in the form of a bitmap.
>
> During the VM initialization, the registers are set to upper-limit of
> the features supported by the corresponding registers. It's expected
> that the VMMs discover the features provided by each register via
> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> KVM allows this modification only until the VM has started.
>
> Some of the standard features are not mapped to any bits of the
> registers. But since they can recreate the original problem of
> making it available without userspace's consent, they need to
> be explicitly added to the case-list in
> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
>
> Older userspace code can simply ignore the feature and the
> hypercall services will be exposed unconditionally to the guests,
> thus ensuring backward compatibility.
>
> In this patch, the framework adds the register only for ARM's standard
> secure services (owner value 4). Currently, this includes support only
> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> register representing mandatory features of v1.0. Other services are
> momentarily added in the upcoming patches.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 12 ++++
>  arch/arm64/include/uapi/asm/kvm.h |  9 +++
>  arch/arm64/kvm/arm.c              |  1 +
>  arch/arm64/kvm/guest.c            |  8 ++-
>  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>  arch/arm64/kvm/psci.c             | 13 +++++
>  include/kvm/arm_hypercalls.h      |  6 ++
>  include/kvm/arm_psci.h            |  2 +-
>  8 files changed, 142 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 94a27a7520f4..df07f4c10197 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>  struct kvm_arch_memory_slot {
>  };
>
> +/**
> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> + *
> + * @std_bmap: Bitmap of standard secure service calls
> + */
> +struct kvm_smccc_features {
> +       unsigned long std_bmap;
> +};
> +
>  struct kvm_arch {
>         struct kvm_s2_mmu mmu;
>
> @@ -150,6 +159,9 @@ struct kvm_arch {
>
>         u8 pfr0_csv2;
>         u8 pfr0_csv3;
> +
> +       /* Hypercall features firmware registers' descriptor */
> +       struct kvm_smccc_features smccc_feat;
>  };
>
>  struct kvm_vcpu_fault_info {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index c1b6ddc02d2f..0b79d2dc6ffd 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>  #define KVM_ARM64_SVE_VLS_WORDS        \
>         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>
> +/* Bitmap feature firmware registers */
> +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> +                                               ((r) & 0xffff))
> +
> +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> index 523bc934fe2f..a37fadbd617e 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>
>         set_default_spectre(kvm);
> +       kvm_arm_init_hypercalls(kvm);
>
>         return ret;
>  out_free_stage2_pgd:
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 0d5cca56cbda..8c607199cad1 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>
>         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> +       case KVM_REG_ARM_FW:
> +       case KVM_REG_ARM_FW_FEAT_BMAP:
> +               return kvm_arm_get_fw_reg(vcpu, reg);
>         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
>         }
>
> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>
>         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> +       case KVM_REG_ARM_FW:
> +       case KVM_REG_ARM_FW_FEAT_BMAP:
> +               return kvm_arm_set_fw_reg(vcpu, reg);
>         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
>         }
>
> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index fa6d9378d8e7..df55a04d2fe8 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>         val[3] = lower_32_bits(cycles);
>  }
>
> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> +{
> +       return test_bit(feat_bit, reg_bmap);
> +}
> +
> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       switch (func_id) {
> +       /*
> +        * List of function-ids that are not gated with the bitmapped feature
> +        * firmware registers, and are to be allowed for servicing the call by default.
> +        */
> +       case ARM_SMCCC_VERSION_FUNC_ID:
> +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +       case ARM_SMCCC_HV_PV_TIME_ST:
> +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +               return true;
> +       default:
> +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> +       }
> +}
> +
> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> +
> +       switch (func_id) {
> +       case ARM_SMCCC_TRNG_VERSION:
> +       case ARM_SMCCC_TRNG_FEATURES:
> +       case ARM_SMCCC_TRNG_GET_UUID:
> +       case ARM_SMCCC_TRNG_RND32:
> +       case ARM_SMCCC_TRNG_RND64:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +       default:
> +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> +       }
> +}
> +
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>  {
>         u32 func_id = smccc_get_function(vcpu);
> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>         u32 feature;
>         gpa_t gpa;
>
> +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> +               goto out;
> +
>         switch (func_id) {
>         case ARM_SMCCC_VERSION_FUNC_ID:
>                 val[0] = ARM_SMCCC_VERSION_1_1;
> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>                 return kvm_psci_call(vcpu);
>         }
>
> +out:
>         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>         return 1;
>  }
> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> +       KVM_REG_ARM_STD_BMAP,
>  };
>
> +void kvm_arm_init_hypercalls(struct kvm *kvm)
> +{
> +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +
> +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +}
> +
>  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>  {
>         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>
>  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  {
> +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>         void __user *uaddr = (void __user *)(long)reg->addr;
>         u64 val;
>
> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>                 break;
> +       case KVM_REG_ARM_STD_BMAP:
> +               val = READ_ONCE(smccc_feat->std_bmap);
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         return 0;
>  }
>
> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> +{
> +       int ret = 0;
> +       struct kvm *kvm = vcpu->kvm;
> +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +       unsigned long *fw_reg_bmap, fw_reg_features;
> +
> +       switch (reg_id) {
> +       case KVM_REG_ARM_STD_BMAP:
> +               fw_reg_bmap = &smccc_feat->std_bmap;
> +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> +               break;
> +       default:
> +               return -ENOENT;
> +       }
> +
> +       /* Check for unsupported bit */
> +       if (val & ~fw_reg_features)
> +               return -EINVAL;
> +
> +       mutex_lock(&kvm->lock);

Why don't you check if the register value will be modified before
getting the lock ? (then there is nothing to do)
It would help reduce unnecessary serialization for live migration
(even without the vm-scoped register capability).



> +
> +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> +               ret = -EBUSY;
> +               goto out;
> +       }

I just would like to make sure that you are sure that existing
userspace you know will not run KVM_RUN for any vCPUs until
KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
correct ?


> +
> +       WRITE_ONCE(*fw_reg_bmap, val);
> +out:
> +       mutex_unlock(&kvm->lock);
> +       return ret;
> +}
> +
>  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  {
>         void __user *uaddr = (void __user *)(long)reg->addr;
> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>                         return -EINVAL;
>
>                 return 0;
> +       case KVM_REG_ARM_STD_BMAP:
> +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>         default:
>                 return -ENOENT;
>         }
> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> index 346535169faa..67d1273e8086 100644
> --- a/arch/arm64/kvm/psci.c
> +++ b/arch/arm64/kvm/psci.c
> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>                 return -EINVAL;
>         }
>  }
> +
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> +
> +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> +               return true;

For PSCI 0.1, the function checks if the funct_id is valid for
the vCPU (according to the vCPU's PSCI version).
For other version of PSCI, the function doesn't care the vCPU's
PSCI version (although supported functions depend on the PSCI
version and not all of them are defined yet, the code returns
true as long as the function id is within the reserved PSCI
function id range).
So, the behavior appears to be inconsistent.
Shouldn't it return the validity of the function id according
to the vCPU's psci version for non-PSCI 0.1 case as well ?
(Otherwise, shouldn't it return true if the function id is valid
for any of the PSCI versions ?)

Thanks,
Reiji



> +
> +       return false;
> +}
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 5d38628a8d04..499b45b607b6 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -6,6 +6,11 @@
>
>  #include <asm/kvm_emulate.h>
>
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> +
> +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>
>  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>
>  struct kvm_one_reg;
>
> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>  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);
> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> index 6e55b9283789..c47be3e26965 100644
> --- a/include/kvm/arm_psci.h
> +++ b/include/kvm/arm_psci.h
> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>         return KVM_ARM_PSCI_0_1;
>  }
>
> -
>  int kvm_psci_call(struct kvm_vcpu *vcpu);
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>
>  #endif /* __KVM_ARM_PSCI_H__ */
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-25  6:22     ` Reiji Watanabe
  -1 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  6:22 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Introduce the firmware register to hold the vendor specific
> hypervisor service calls (owner value 6) as a bitmap. The
> bitmap represents the features that'll be enabled for the
> guest, as configured by the user-space. Currently, this
> includes support for KVM-vendor features along with
> reading the UID, represented by bit-0, and Precision Time
> Protocol (PTP), represented by bit-1.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  arch/arm64/include/asm/kvm_host.h |  2 ++
>  arch/arm64/include/uapi/asm/kvm.h |  4 ++++
>  arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
>  include/kvm/arm_hypercalls.h      |  2 ++
>  4 files changed, 26 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 27d4b2a7970e..a025c2ba012a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
>   *
>   * @std_bmap: Bitmap of standard secure service calls
>   * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
>   */
>  struct kvm_smccc_features {
>         unsigned long std_bmap;
>         unsigned long std_hyp_bmap;
> +       unsigned long vendor_hyp_bmap;
>  };
>
>  struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 9eecc7ee8c14..e7d5ae222684 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
>  #define KVM_REG_ARM_STD_HYP_BMAP               KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
>  #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME                0
>
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP            KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT   0
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP         1
> +
>  /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index f097bebdad39..76e626d0e699 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>          */
>         case ARM_SMCCC_VERSION_FUNC_ID:
>         case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>                 return true;
>         default:
>                 return kvm_psci_func_id_is_valid(vcpu, func_id);
> @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>         case ARM_SMCCC_HV_PV_TIME_ST:
>                 return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
>                                         KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +                                       KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +                                       KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
>         default:
>                 return kvm_hvc_call_default_allowed(vcpu, func_id);
>         }
> @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>                 val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
>                 break;
>         case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -               val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> -               val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> +               val[0] = smccc_feat->vendor_hyp_bmap;
>                 break;
>         case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>                 kvm_ptp_get_time(vcpu, val);
> @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>         KVM_REG_ARM_STD_BMAP,
>         KVM_REG_ARM_STD_HYP_BMAP,
> +       KVM_REG_ARM_VENDOR_HYP_BMAP,
>  };
>
>  void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>
>         smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>         smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +       smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
>  }
>
>  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         case KVM_REG_ARM_STD_HYP_BMAP:
>                 val = READ_ONCE(smccc_feat->std_hyp_bmap);
>                 break;
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +               val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>                 fw_reg_bmap = &smccc_feat->std_hyp_bmap;
>                 fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>                 break;
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +               fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> +               fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>                 return 0;
>         case KVM_REG_ARM_STD_BMAP:
>         case KVM_REG_ARM_STD_HYP_BMAP:
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
>                 return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>         default:
>                 return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index aadd6ae3ab72..4ebfdd26e486 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -9,9 +9,11 @@
>  /* Last valid bits of the bitmapped firmware registers */
>  #define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
>  #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX       0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1

Nit: IMHO perhaps it might be more convenient to define the MAX macro
in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
(The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)

#define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP

Thanks,
Reiji


>
>  #define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>  #define KVM_ARM_SMCCC_STD_HYP_FEATURES         GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES      GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
>
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>

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

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-25  6:22     ` Reiji Watanabe
  0 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  6:22 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Introduce the firmware register to hold the vendor specific
> hypervisor service calls (owner value 6) as a bitmap. The
> bitmap represents the features that'll be enabled for the
> guest, as configured by the user-space. Currently, this
> includes support for KVM-vendor features along with
> reading the UID, represented by bit-0, and Precision Time
> Protocol (PTP), represented by bit-1.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  arch/arm64/include/asm/kvm_host.h |  2 ++
>  arch/arm64/include/uapi/asm/kvm.h |  4 ++++
>  arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
>  include/kvm/arm_hypercalls.h      |  2 ++
>  4 files changed, 26 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 27d4b2a7970e..a025c2ba012a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
>   *
>   * @std_bmap: Bitmap of standard secure service calls
>   * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
>   */
>  struct kvm_smccc_features {
>         unsigned long std_bmap;
>         unsigned long std_hyp_bmap;
> +       unsigned long vendor_hyp_bmap;
>  };
>
>  struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 9eecc7ee8c14..e7d5ae222684 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
>  #define KVM_REG_ARM_STD_HYP_BMAP               KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
>  #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME                0
>
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP            KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT   0
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP         1
> +
>  /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index f097bebdad39..76e626d0e699 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>          */
>         case ARM_SMCCC_VERSION_FUNC_ID:
>         case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>                 return true;
>         default:
>                 return kvm_psci_func_id_is_valid(vcpu, func_id);
> @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>         case ARM_SMCCC_HV_PV_TIME_ST:
>                 return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
>                                         KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +                                       KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +                                       KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
>         default:
>                 return kvm_hvc_call_default_allowed(vcpu, func_id);
>         }
> @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>                 val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
>                 break;
>         case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -               val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> -               val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> +               val[0] = smccc_feat->vendor_hyp_bmap;
>                 break;
>         case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>                 kvm_ptp_get_time(vcpu, val);
> @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>         KVM_REG_ARM_STD_BMAP,
>         KVM_REG_ARM_STD_HYP_BMAP,
> +       KVM_REG_ARM_VENDOR_HYP_BMAP,
>  };
>
>  void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>
>         smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>         smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +       smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
>  }
>
>  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         case KVM_REG_ARM_STD_HYP_BMAP:
>                 val = READ_ONCE(smccc_feat->std_hyp_bmap);
>                 break;
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +               val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>                 fw_reg_bmap = &smccc_feat->std_hyp_bmap;
>                 fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>                 break;
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +               fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> +               fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>                 return 0;
>         case KVM_REG_ARM_STD_BMAP:
>         case KVM_REG_ARM_STD_HYP_BMAP:
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
>                 return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>         default:
>                 return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index aadd6ae3ab72..4ebfdd26e486 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -9,9 +9,11 @@
>  /* Last valid bits of the bitmapped firmware registers */
>  #define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
>  #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX       0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1

Nit: IMHO perhaps it might be more convenient to define the MAX macro
in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
(The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)

#define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP

Thanks,
Reiji


>
>  #define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>  #define KVM_ARM_SMCCC_STD_HYP_FEATURES         GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES      GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
>
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-25  6:22     ` Reiji Watanabe
  0 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  6:22 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Introduce the firmware register to hold the vendor specific
> hypervisor service calls (owner value 6) as a bitmap. The
> bitmap represents the features that'll be enabled for the
> guest, as configured by the user-space. Currently, this
> includes support for KVM-vendor features along with
> reading the UID, represented by bit-0, and Precision Time
> Protocol (PTP), represented by bit-1.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  arch/arm64/include/asm/kvm_host.h |  2 ++
>  arch/arm64/include/uapi/asm/kvm.h |  4 ++++
>  arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
>  include/kvm/arm_hypercalls.h      |  2 ++
>  4 files changed, 26 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 27d4b2a7970e..a025c2ba012a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
>   *
>   * @std_bmap: Bitmap of standard secure service calls
>   * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
>   */
>  struct kvm_smccc_features {
>         unsigned long std_bmap;
>         unsigned long std_hyp_bmap;
> +       unsigned long vendor_hyp_bmap;
>  };
>
>  struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 9eecc7ee8c14..e7d5ae222684 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
>  #define KVM_REG_ARM_STD_HYP_BMAP               KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
>  #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME                0
>
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP            KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT   0
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP         1
> +
>  /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index f097bebdad39..76e626d0e699 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>          */
>         case ARM_SMCCC_VERSION_FUNC_ID:
>         case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>                 return true;
>         default:
>                 return kvm_psci_func_id_is_valid(vcpu, func_id);
> @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>         case ARM_SMCCC_HV_PV_TIME_ST:
>                 return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
>                                         KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +                                       KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +                                       KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
>         default:
>                 return kvm_hvc_call_default_allowed(vcpu, func_id);
>         }
> @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>                 val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
>                 break;
>         case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -               val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> -               val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> +               val[0] = smccc_feat->vendor_hyp_bmap;
>                 break;
>         case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>                 kvm_ptp_get_time(vcpu, val);
> @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>         KVM_REG_ARM_STD_BMAP,
>         KVM_REG_ARM_STD_HYP_BMAP,
> +       KVM_REG_ARM_VENDOR_HYP_BMAP,
>  };
>
>  void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>
>         smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>         smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +       smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
>  }
>
>  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>         case KVM_REG_ARM_STD_HYP_BMAP:
>                 val = READ_ONCE(smccc_feat->std_hyp_bmap);
>                 break;
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +               val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>                 fw_reg_bmap = &smccc_feat->std_hyp_bmap;
>                 fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>                 break;
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +               fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> +               fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> +               break;
>         default:
>                 return -ENOENT;
>         }
> @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>                 return 0;
>         case KVM_REG_ARM_STD_BMAP:
>         case KVM_REG_ARM_STD_HYP_BMAP:
> +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
>                 return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>         default:
>                 return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index aadd6ae3ab72..4ebfdd26e486 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -9,9 +9,11 @@
>  /* Last valid bits of the bitmapped firmware registers */
>  #define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
>  #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX       0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1

Nit: IMHO perhaps it might be more convenient to define the MAX macro
in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
(The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)

#define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP

Thanks,
Reiji


>
>  #define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>  #define KVM_ARM_SMCCC_STD_HYP_FEATURES         GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES      GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
>
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-25  6:31     ` Reiji Watanabe
  -1 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  6:31 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Add the documentation for the bitmap firmware registers in
> hypercalls.rst and api.rst. This includes the details for
> KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> KVM_REG_ARM_VENDOR_HYP_BMAP registers.
>
> Since the document is growing to carry other hypercall related
> information, make necessary adjustments to present the document
> in a generic sense, rather than being PSCI focused.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  Documentation/virt/kvm/api.rst            | 16 ++++
>  Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
>  2 files changed, 92 insertions(+), 18 deletions(-)
>
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index 85c7abc51af5..ac489191d0a9 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
>
>    0x6030 0000 0014 <regno:16>
>
> +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> +
> +  0x6030 0000 0016 <regno:16>
> +
> +The bitmap feature firmware registers exposes the hypercall services that are
> +available for userspace to configure. The set bits corresponds to the services
> +that are available for the guests to access. By default, KVM sets all the
> +supported bits during VM initialization. The userspace can discover the
> +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> +
> +Note: These registers are immutable once any of the vCPUs of the VM has run at
> +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> +
> +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> +
>  arm64 SVE registers have the following bit patterns::
>
>    0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> index d52c2e83b5b8..6327c504b2fb 100644
> --- a/Documentation/virt/kvm/arm/hypercalls.rst
> +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> @@ -1,32 +1,32 @@
>  .. SPDX-License-Identifier: GPL-2.0
>
> -=========================================
> -Power State Coordination Interface (PSCI)
> -=========================================
> +=======================
> +ARM Hypercall Interface
> +=======================
>
> -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.
> +KVM handles the hypercall services as requested by the guests. New hypercall
> +services are regularly made available by the ARM specification or by KVM (as
> +vendor services) if they make sense from a virtualization point of view.
>
> -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.
> +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 version of a hypercall service, or if a migration
> +causes a different version to be exposed out of the blue to an unsuspecting
> +guest.
>
>  In order to remedy this situation, KVM exposes a set of "firmware
>  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.
> +to a convenient value as required.
>
> -The following register is defined:
> +The following registers are defined:
>
>  * KVM_REG_ARM_PSCI_VERSION:
>
> +  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.
> +
>    - 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
> @@ -74,4 +74,62 @@ The following register is defined:
>      KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
>        The workaround is always active on this vCPU or it is not needed.
>
> -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> +
> +Bitmap Feature Firmware Registers
> +---------------------------------
> +
> +Contrary to the above registers, the following registers exposes the hypercall
> +services in the form of a feature-bitmap to the userspace. This bitmap is
> +translated to the services that are available to the guest. There is a register
> +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> +
> +By default, these registers are set with the upper limit of the features that
> +are supported. This way userspace can discover all the electable hypercall services
> +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> +SET_ONE_REG. The features for the registers that are untouched, probably because
> +userspace isn't aware of them, will be exposed as is to the guest.
> +
> +Note that KVM would't allow the userspace to configure the registers anymore once
> +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> +
> +The psuedo-firmware bitmap register are as follows:
> +
> +* KVM_REG_ARM_STD_BMAP:
> +    Controls the bitmap of the ARM Standard Secure Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> +      The bit represents the services offered under v1.0 of ARM True Random
> +      Number Generator (TRNG) specification, ARM DEN0098.
> +
> +* KVM_REG_ARM_STD_HYP_BMAP:
> +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> +      The bit represents the Paravirtualized Time service as represented by
> +      ARM DEN0057A.
> +
> +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> +      function-id

Looking at the code,
the bit also represents ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID.

Thanks,
Reiji


> +
> +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> +      The bit represents the Precision Time Protocol KVM service.
> +
> +Errors:
> +
> +    =======  =============================================================
> +    -ENOENT   Unknown register accessed.
> +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> +    -EINVAL   Invalid bitmap written to the register.
> +    =======  =============================================================
> +
> +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> \ No newline at end of file
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>

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

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
@ 2022-04-25  6:31     ` Reiji Watanabe
  0 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  6:31 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Add the documentation for the bitmap firmware registers in
> hypercalls.rst and api.rst. This includes the details for
> KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> KVM_REG_ARM_VENDOR_HYP_BMAP registers.
>
> Since the document is growing to carry other hypercall related
> information, make necessary adjustments to present the document
> in a generic sense, rather than being PSCI focused.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  Documentation/virt/kvm/api.rst            | 16 ++++
>  Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
>  2 files changed, 92 insertions(+), 18 deletions(-)
>
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index 85c7abc51af5..ac489191d0a9 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
>
>    0x6030 0000 0014 <regno:16>
>
> +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> +
> +  0x6030 0000 0016 <regno:16>
> +
> +The bitmap feature firmware registers exposes the hypercall services that are
> +available for userspace to configure. The set bits corresponds to the services
> +that are available for the guests to access. By default, KVM sets all the
> +supported bits during VM initialization. The userspace can discover the
> +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> +
> +Note: These registers are immutable once any of the vCPUs of the VM has run at
> +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> +
> +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> +
>  arm64 SVE registers have the following bit patterns::
>
>    0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> index d52c2e83b5b8..6327c504b2fb 100644
> --- a/Documentation/virt/kvm/arm/hypercalls.rst
> +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> @@ -1,32 +1,32 @@
>  .. SPDX-License-Identifier: GPL-2.0
>
> -=========================================
> -Power State Coordination Interface (PSCI)
> -=========================================
> +=======================
> +ARM Hypercall Interface
> +=======================
>
> -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.
> +KVM handles the hypercall services as requested by the guests. New hypercall
> +services are regularly made available by the ARM specification or by KVM (as
> +vendor services) if they make sense from a virtualization point of view.
>
> -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.
> +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 version of a hypercall service, or if a migration
> +causes a different version to be exposed out of the blue to an unsuspecting
> +guest.
>
>  In order to remedy this situation, KVM exposes a set of "firmware
>  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.
> +to a convenient value as required.
>
> -The following register is defined:
> +The following registers are defined:
>
>  * KVM_REG_ARM_PSCI_VERSION:
>
> +  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.
> +
>    - 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
> @@ -74,4 +74,62 @@ The following register is defined:
>      KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
>        The workaround is always active on this vCPU or it is not needed.
>
> -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> +
> +Bitmap Feature Firmware Registers
> +---------------------------------
> +
> +Contrary to the above registers, the following registers exposes the hypercall
> +services in the form of a feature-bitmap to the userspace. This bitmap is
> +translated to the services that are available to the guest. There is a register
> +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> +
> +By default, these registers are set with the upper limit of the features that
> +are supported. This way userspace can discover all the electable hypercall services
> +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> +SET_ONE_REG. The features for the registers that are untouched, probably because
> +userspace isn't aware of them, will be exposed as is to the guest.
> +
> +Note that KVM would't allow the userspace to configure the registers anymore once
> +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> +
> +The psuedo-firmware bitmap register are as follows:
> +
> +* KVM_REG_ARM_STD_BMAP:
> +    Controls the bitmap of the ARM Standard Secure Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> +      The bit represents the services offered under v1.0 of ARM True Random
> +      Number Generator (TRNG) specification, ARM DEN0098.
> +
> +* KVM_REG_ARM_STD_HYP_BMAP:
> +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> +      The bit represents the Paravirtualized Time service as represented by
> +      ARM DEN0057A.
> +
> +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> +      function-id

Looking at the code,
the bit also represents ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID.

Thanks,
Reiji


> +
> +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> +      The bit represents the Precision Time Protocol KVM service.
> +
> +Errors:
> +
> +    =======  =============================================================
> +    -ENOENT   Unknown register accessed.
> +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> +    -EINVAL   Invalid bitmap written to the register.
> +    =======  =============================================================
> +
> +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> \ No newline at end of file
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
@ 2022-04-25  6:31     ` Reiji Watanabe
  0 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-25  6:31 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Raghu,

On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Add the documentation for the bitmap firmware registers in
> hypercalls.rst and api.rst. This includes the details for
> KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> KVM_REG_ARM_VENDOR_HYP_BMAP registers.
>
> Since the document is growing to carry other hypercall related
> information, make necessary adjustments to present the document
> in a generic sense, rather than being PSCI focused.
>
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>  Documentation/virt/kvm/api.rst            | 16 ++++
>  Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
>  2 files changed, 92 insertions(+), 18 deletions(-)
>
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index 85c7abc51af5..ac489191d0a9 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
>
>    0x6030 0000 0014 <regno:16>
>
> +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> +
> +  0x6030 0000 0016 <regno:16>
> +
> +The bitmap feature firmware registers exposes the hypercall services that are
> +available for userspace to configure. The set bits corresponds to the services
> +that are available for the guests to access. By default, KVM sets all the
> +supported bits during VM initialization. The userspace can discover the
> +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> +
> +Note: These registers are immutable once any of the vCPUs of the VM has run at
> +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> +
> +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> +
>  arm64 SVE registers have the following bit patterns::
>
>    0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> index d52c2e83b5b8..6327c504b2fb 100644
> --- a/Documentation/virt/kvm/arm/hypercalls.rst
> +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> @@ -1,32 +1,32 @@
>  .. SPDX-License-Identifier: GPL-2.0
>
> -=========================================
> -Power State Coordination Interface (PSCI)
> -=========================================
> +=======================
> +ARM Hypercall Interface
> +=======================
>
> -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.
> +KVM handles the hypercall services as requested by the guests. New hypercall
> +services are regularly made available by the ARM specification or by KVM (as
> +vendor services) if they make sense from a virtualization point of view.
>
> -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.
> +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 version of a hypercall service, or if a migration
> +causes a different version to be exposed out of the blue to an unsuspecting
> +guest.
>
>  In order to remedy this situation, KVM exposes a set of "firmware
>  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.
> +to a convenient value as required.
>
> -The following register is defined:
> +The following registers are defined:
>
>  * KVM_REG_ARM_PSCI_VERSION:
>
> +  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.
> +
>    - 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
> @@ -74,4 +74,62 @@ The following register is defined:
>      KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
>        The workaround is always active on this vCPU or it is not needed.
>
> -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> +
> +Bitmap Feature Firmware Registers
> +---------------------------------
> +
> +Contrary to the above registers, the following registers exposes the hypercall
> +services in the form of a feature-bitmap to the userspace. This bitmap is
> +translated to the services that are available to the guest. There is a register
> +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> +
> +By default, these registers are set with the upper limit of the features that
> +are supported. This way userspace can discover all the electable hypercall services
> +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> +SET_ONE_REG. The features for the registers that are untouched, probably because
> +userspace isn't aware of them, will be exposed as is to the guest.
> +
> +Note that KVM would't allow the userspace to configure the registers anymore once
> +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> +
> +The psuedo-firmware bitmap register are as follows:
> +
> +* KVM_REG_ARM_STD_BMAP:
> +    Controls the bitmap of the ARM Standard Secure Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> +      The bit represents the services offered under v1.0 of ARM True Random
> +      Number Generator (TRNG) specification, ARM DEN0098.
> +
> +* KVM_REG_ARM_STD_HYP_BMAP:
> +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> +      The bit represents the Paravirtualized Time service as represented by
> +      ARM DEN0057A.
> +
> +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> +      function-id

Looking at the code,
the bit also represents ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID.

Thanks,
Reiji


> +
> +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> +      The bit represents the Precision Time Protocol KVM service.
> +
> +Errors:
> +
> +    =======  =============================================================
> +    -ENOENT   Unknown register accessed.
> +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> +    -EINVAL   Invalid bitmap written to the register.
> +    =======  =============================================================
> +
> +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> \ No newline at end of file
> --
> 2.36.0.rc2.479.g8af0fa9b8e-goog
>

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  2022-04-25  4:52     ` Reiji Watanabe
  (?)
@ 2022-04-25 16:46       ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:46 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Reiji,

On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > KVM regularly introduces new hypercall services to the guests without
> > any consent from the userspace. This means, the guests can observe
> > hypercall services in and out as they migrate across various host
> > kernel versions. This could be a major problem if the guest
> > discovered a hypercall, started using it, and after getting migrated
> > to an older kernel realizes that it's no longer available. Depending
> > on how the guest handles the change, there's a potential chance that
> > the guest would just panic.
> >
> > As a result, there's a need for the userspace to elect the services
> > that it wishes the guest to discover. It can elect these services
> > based on the kernels spread across its (migration) fleet. To remedy
> > this, extend the existing firmware pseudo-registers, such as
> > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > for all the hypercall services available.
> >
> > These firmware registers are categorized based on the service call
> > owners, but unlike the existing firmware pseudo-registers, they hold
> > the features supported in the form of a bitmap.
> >
> > During the VM initialization, the registers are set to upper-limit of
> > the features supported by the corresponding registers. It's expected
> > that the VMMs discover the features provided by each register via
> > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > KVM allows this modification only until the VM has started.
> >
> > Some of the standard features are not mapped to any bits of the
> > registers. But since they can recreate the original problem of
> > making it available without userspace's consent, they need to
> > be explicitly added to the case-list in
> > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> >
> > Older userspace code can simply ignore the feature and the
> > hypercall services will be exposed unconditionally to the guests,
> > thus ensuring backward compatibility.
> >
> > In this patch, the framework adds the register only for ARM's standard
> > secure services (owner value 4). Currently, this includes support only
> > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > register representing mandatory features of v1.0. Other services are
> > momentarily added in the upcoming patches.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> >  arch/arm64/kvm/arm.c              |  1 +
> >  arch/arm64/kvm/guest.c            |  8 ++-
> >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> >  arch/arm64/kvm/psci.c             | 13 +++++
> >  include/kvm/arm_hypercalls.h      |  6 ++
> >  include/kvm/arm_psci.h            |  2 +-
> >  8 files changed, 142 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 94a27a7520f4..df07f4c10197 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> >  struct kvm_arch_memory_slot {
> >  };
> >
> > +/**
> > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > + *
> > + * @std_bmap: Bitmap of standard secure service calls
> > + */
> > +struct kvm_smccc_features {
> > +       unsigned long std_bmap;
> > +};
> > +
> >  struct kvm_arch {
> >         struct kvm_s2_mmu mmu;
> >
> > @@ -150,6 +159,9 @@ struct kvm_arch {
> >
> >         u8 pfr0_csv2;
> >         u8 pfr0_csv3;
> > +
> > +       /* Hypercall features firmware registers' descriptor */
> > +       struct kvm_smccc_features smccc_feat;
> >  };
> >
> >  struct kvm_vcpu_fault_info {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> >  #define KVM_ARM64_SVE_VLS_WORDS        \
> >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> >
> > +/* Bitmap feature firmware registers */
> > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > +                                               ((r) & 0xffff))
> > +
> > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > index 523bc934fe2f..a37fadbd617e 100644
> > --- a/arch/arm64/kvm/arm.c
> > +++ b/arch/arm64/kvm/arm.c
> > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> >
> >         set_default_spectre(kvm);
> > +       kvm_arm_init_hypercalls(kvm);
> >
> >         return ret;
> >  out_free_stage2_pgd:
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 0d5cca56cbda..8c607199cad1 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > +       case KVM_REG_ARM_FW:
> > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > +               return kvm_arm_get_fw_reg(vcpu, reg);
> >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> >         }
> >
> > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > +       case KVM_REG_ARM_FW:
> > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > +               return kvm_arm_set_fw_reg(vcpu, reg);
> >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> >         }
> >
> > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index fa6d9378d8e7..df55a04d2fe8 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> >         val[3] = lower_32_bits(cycles);
> >  }
> >
> > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > +{
> > +       return test_bit(feat_bit, reg_bmap);
> > +}
> > +
> > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       switch (func_id) {
> > +       /*
> > +        * List of function-ids that are not gated with the bitmapped feature
> > +        * firmware registers, and are to be allowed for servicing the call by default.
> > +        */
> > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +               return true;
> > +       default:
> > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > +       }
> > +}
> > +
> > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > +
> > +       switch (func_id) {
> > +       case ARM_SMCCC_TRNG_VERSION:
> > +       case ARM_SMCCC_TRNG_FEATURES:
> > +       case ARM_SMCCC_TRNG_GET_UUID:
> > +       case ARM_SMCCC_TRNG_RND32:
> > +       case ARM_SMCCC_TRNG_RND64:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > +       default:
> > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > +       }
> > +}
> > +
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >  {
> >         u32 func_id = smccc_get_function(vcpu);
> > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >         u32 feature;
> >         gpa_t gpa;
> >
> > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > +               goto out;
> > +
> >         switch (func_id) {
> >         case ARM_SMCCC_VERSION_FUNC_ID:
> >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >                 return kvm_psci_call(vcpu);
> >         }
> >
> > +out:
> >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> >         return 1;
> >  }
> > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > +       KVM_REG_ARM_STD_BMAP,
> >  };
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > +{
> > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +
> > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > +}
> > +
> >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> >  {
> >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> >
> >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  {
> > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> >         void __user *uaddr = (void __user *)(long)reg->addr;
> >         u64 val;
> >
> > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> >                 break;
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               val = READ_ONCE(smccc_feat->std_bmap);
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         return 0;
> >  }
> >
> > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > +{
> > +       int ret = 0;
> > +       struct kvm *kvm = vcpu->kvm;
> > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > +
> > +       switch (reg_id) {
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > +               break;
> > +       default:
> > +               return -ENOENT;
> > +       }
> > +
> > +       /* Check for unsupported bit */
> > +       if (val & ~fw_reg_features)
> > +               return -EINVAL;
> > +
> > +       mutex_lock(&kvm->lock);
>
> Why don't you check if the register value will be modified before
> getting the lock ? (then there is nothing to do)
> It would help reduce unnecessary serialization for live migration
> (even without the vm-scoped register capability).
>
That was the case until v5. Since v6, we return -EBUSY unconditionally
regardless of the incoming value. See Marc's comments in [1].
>
>
> > +
> > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > +               ret = -EBUSY;
> > +               goto out;
> > +       }
>
> I just would like to make sure that you are sure that existing
> userspace you know will not run KVM_RUN for any vCPUs until
> KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> correct ?
>
Since v6, that is something that we are leaving with the userspace to
synchronize. See [1].
>
> > +
> > +       WRITE_ONCE(*fw_reg_bmap, val);
> > +out:
> > +       mutex_unlock(&kvm->lock);
> > +       return ret;
> > +}
> > +
> >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  {
> >         void __user *uaddr = (void __user *)(long)reg->addr;
> > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                         return -EINVAL;
> >
> >                 return 0;
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >         default:
> >                 return -ENOENT;
> >         }
> > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > index 346535169faa..67d1273e8086 100644
> > --- a/arch/arm64/kvm/psci.c
> > +++ b/arch/arm64/kvm/psci.c
> > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> >                 return -EINVAL;
> >         }
> >  }
> > +
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > +
> > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > +               return true;
>
> For PSCI 0.1, the function checks if the funct_id is valid for
> the vCPU (according to the vCPU's PSCI version).
> For other version of PSCI, the function doesn't care the vCPU's
> PSCI version (although supported functions depend on the PSCI
> version and not all of them are defined yet, the code returns
> true as long as the function id is within the reserved PSCI
> function id range).
> So, the behavior appears to be inconsistent.
> Shouldn't it return the validity of the function id according
> to the vCPU's psci version for non-PSCI 0.1 case as well ?
> (Otherwise, shouldn't it return true if the function id is valid
> for any of the PSCI versions ?)
>
Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
with the SMCCC, hence needed some special handling. Only two func_ids
are currently supported by KVM, and we just check for each. The second
'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
specification defines a range of acceptable PSCI func_ids.

If it's confusing, I can add a comment above the second 'if' that it's
for all PSCI versions >= 0.2.
> Thanks,
> Reiji
>
Thank you.
Raghavendra

[1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
>
>
> > +
> > +       return false;
> > +}
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index 5d38628a8d04..499b45b607b6 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -6,6 +6,11 @@
> >
> >  #include <asm/kvm_emulate.h>
> >
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > +
> > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > +
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> >
> >  struct kvm_one_reg;
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> >  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);
> > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > index 6e55b9283789..c47be3e26965 100644
> > --- a/include/kvm/arm_psci.h
> > +++ b/include/kvm/arm_psci.h
> > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> >         return KVM_ARM_PSCI_0_1;
> >  }
> >
> > -
> >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> >
> >  #endif /* __KVM_ARM_PSCI_H__ */
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-25 16:46       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:46 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

Hi Reiji,

On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > KVM regularly introduces new hypercall services to the guests without
> > any consent from the userspace. This means, the guests can observe
> > hypercall services in and out as they migrate across various host
> > kernel versions. This could be a major problem if the guest
> > discovered a hypercall, started using it, and after getting migrated
> > to an older kernel realizes that it's no longer available. Depending
> > on how the guest handles the change, there's a potential chance that
> > the guest would just panic.
> >
> > As a result, there's a need for the userspace to elect the services
> > that it wishes the guest to discover. It can elect these services
> > based on the kernels spread across its (migration) fleet. To remedy
> > this, extend the existing firmware pseudo-registers, such as
> > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > for all the hypercall services available.
> >
> > These firmware registers are categorized based on the service call
> > owners, but unlike the existing firmware pseudo-registers, they hold
> > the features supported in the form of a bitmap.
> >
> > During the VM initialization, the registers are set to upper-limit of
> > the features supported by the corresponding registers. It's expected
> > that the VMMs discover the features provided by each register via
> > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > KVM allows this modification only until the VM has started.
> >
> > Some of the standard features are not mapped to any bits of the
> > registers. But since they can recreate the original problem of
> > making it available without userspace's consent, they need to
> > be explicitly added to the case-list in
> > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> >
> > Older userspace code can simply ignore the feature and the
> > hypercall services will be exposed unconditionally to the guests,
> > thus ensuring backward compatibility.
> >
> > In this patch, the framework adds the register only for ARM's standard
> > secure services (owner value 4). Currently, this includes support only
> > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > register representing mandatory features of v1.0. Other services are
> > momentarily added in the upcoming patches.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> >  arch/arm64/kvm/arm.c              |  1 +
> >  arch/arm64/kvm/guest.c            |  8 ++-
> >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> >  arch/arm64/kvm/psci.c             | 13 +++++
> >  include/kvm/arm_hypercalls.h      |  6 ++
> >  include/kvm/arm_psci.h            |  2 +-
> >  8 files changed, 142 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 94a27a7520f4..df07f4c10197 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> >  struct kvm_arch_memory_slot {
> >  };
> >
> > +/**
> > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > + *
> > + * @std_bmap: Bitmap of standard secure service calls
> > + */
> > +struct kvm_smccc_features {
> > +       unsigned long std_bmap;
> > +};
> > +
> >  struct kvm_arch {
> >         struct kvm_s2_mmu mmu;
> >
> > @@ -150,6 +159,9 @@ struct kvm_arch {
> >
> >         u8 pfr0_csv2;
> >         u8 pfr0_csv3;
> > +
> > +       /* Hypercall features firmware registers' descriptor */
> > +       struct kvm_smccc_features smccc_feat;
> >  };
> >
> >  struct kvm_vcpu_fault_info {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> >  #define KVM_ARM64_SVE_VLS_WORDS        \
> >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> >
> > +/* Bitmap feature firmware registers */
> > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > +                                               ((r) & 0xffff))
> > +
> > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > index 523bc934fe2f..a37fadbd617e 100644
> > --- a/arch/arm64/kvm/arm.c
> > +++ b/arch/arm64/kvm/arm.c
> > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> >
> >         set_default_spectre(kvm);
> > +       kvm_arm_init_hypercalls(kvm);
> >
> >         return ret;
> >  out_free_stage2_pgd:
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 0d5cca56cbda..8c607199cad1 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > +       case KVM_REG_ARM_FW:
> > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > +               return kvm_arm_get_fw_reg(vcpu, reg);
> >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> >         }
> >
> > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > +       case KVM_REG_ARM_FW:
> > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > +               return kvm_arm_set_fw_reg(vcpu, reg);
> >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> >         }
> >
> > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index fa6d9378d8e7..df55a04d2fe8 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> >         val[3] = lower_32_bits(cycles);
> >  }
> >
> > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > +{
> > +       return test_bit(feat_bit, reg_bmap);
> > +}
> > +
> > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       switch (func_id) {
> > +       /*
> > +        * List of function-ids that are not gated with the bitmapped feature
> > +        * firmware registers, and are to be allowed for servicing the call by default.
> > +        */
> > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +               return true;
> > +       default:
> > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > +       }
> > +}
> > +
> > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > +
> > +       switch (func_id) {
> > +       case ARM_SMCCC_TRNG_VERSION:
> > +       case ARM_SMCCC_TRNG_FEATURES:
> > +       case ARM_SMCCC_TRNG_GET_UUID:
> > +       case ARM_SMCCC_TRNG_RND32:
> > +       case ARM_SMCCC_TRNG_RND64:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > +       default:
> > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > +       }
> > +}
> > +
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >  {
> >         u32 func_id = smccc_get_function(vcpu);
> > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >         u32 feature;
> >         gpa_t gpa;
> >
> > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > +               goto out;
> > +
> >         switch (func_id) {
> >         case ARM_SMCCC_VERSION_FUNC_ID:
> >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >                 return kvm_psci_call(vcpu);
> >         }
> >
> > +out:
> >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> >         return 1;
> >  }
> > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > +       KVM_REG_ARM_STD_BMAP,
> >  };
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > +{
> > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +
> > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > +}
> > +
> >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> >  {
> >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> >
> >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  {
> > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> >         void __user *uaddr = (void __user *)(long)reg->addr;
> >         u64 val;
> >
> > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> >                 break;
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               val = READ_ONCE(smccc_feat->std_bmap);
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         return 0;
> >  }
> >
> > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > +{
> > +       int ret = 0;
> > +       struct kvm *kvm = vcpu->kvm;
> > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > +
> > +       switch (reg_id) {
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > +               break;
> > +       default:
> > +               return -ENOENT;
> > +       }
> > +
> > +       /* Check for unsupported bit */
> > +       if (val & ~fw_reg_features)
> > +               return -EINVAL;
> > +
> > +       mutex_lock(&kvm->lock);
>
> Why don't you check if the register value will be modified before
> getting the lock ? (then there is nothing to do)
> It would help reduce unnecessary serialization for live migration
> (even without the vm-scoped register capability).
>
That was the case until v5. Since v6, we return -EBUSY unconditionally
regardless of the incoming value. See Marc's comments in [1].
>
>
> > +
> > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > +               ret = -EBUSY;
> > +               goto out;
> > +       }
>
> I just would like to make sure that you are sure that existing
> userspace you know will not run KVM_RUN for any vCPUs until
> KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> correct ?
>
Since v6, that is something that we are leaving with the userspace to
synchronize. See [1].
>
> > +
> > +       WRITE_ONCE(*fw_reg_bmap, val);
> > +out:
> > +       mutex_unlock(&kvm->lock);
> > +       return ret;
> > +}
> > +
> >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  {
> >         void __user *uaddr = (void __user *)(long)reg->addr;
> > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                         return -EINVAL;
> >
> >                 return 0;
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >         default:
> >                 return -ENOENT;
> >         }
> > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > index 346535169faa..67d1273e8086 100644
> > --- a/arch/arm64/kvm/psci.c
> > +++ b/arch/arm64/kvm/psci.c
> > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> >                 return -EINVAL;
> >         }
> >  }
> > +
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > +
> > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > +               return true;
>
> For PSCI 0.1, the function checks if the funct_id is valid for
> the vCPU (according to the vCPU's PSCI version).
> For other version of PSCI, the function doesn't care the vCPU's
> PSCI version (although supported functions depend on the PSCI
> version and not all of them are defined yet, the code returns
> true as long as the function id is within the reserved PSCI
> function id range).
> So, the behavior appears to be inconsistent.
> Shouldn't it return the validity of the function id according
> to the vCPU's psci version for non-PSCI 0.1 case as well ?
> (Otherwise, shouldn't it return true if the function id is valid
> for any of the PSCI versions ?)
>
Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
with the SMCCC, hence needed some special handling. Only two func_ids
are currently supported by KVM, and we just check for each. The second
'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
specification defines a range of acceptable PSCI func_ids.

If it's confusing, I can add a comment above the second 'if' that it's
for all PSCI versions >= 0.2.
> Thanks,
> Reiji
>
Thank you.
Raghavendra

[1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
>
>
> > +
> > +       return false;
> > +}
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index 5d38628a8d04..499b45b607b6 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -6,6 +6,11 @@
> >
> >  #include <asm/kvm_emulate.h>
> >
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > +
> > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > +
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> >
> >  struct kvm_one_reg;
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> >  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);
> > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > index 6e55b9283789..c47be3e26965 100644
> > --- a/include/kvm/arm_psci.h
> > +++ b/include/kvm/arm_psci.h
> > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> >         return KVM_ARM_PSCI_0_1;
> >  }
> >
> > -
> >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> >
> >  #endif /* __KVM_ARM_PSCI_H__ */
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-25 16:46       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:46 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Reiji,

On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > KVM regularly introduces new hypercall services to the guests without
> > any consent from the userspace. This means, the guests can observe
> > hypercall services in and out as they migrate across various host
> > kernel versions. This could be a major problem if the guest
> > discovered a hypercall, started using it, and after getting migrated
> > to an older kernel realizes that it's no longer available. Depending
> > on how the guest handles the change, there's a potential chance that
> > the guest would just panic.
> >
> > As a result, there's a need for the userspace to elect the services
> > that it wishes the guest to discover. It can elect these services
> > based on the kernels spread across its (migration) fleet. To remedy
> > this, extend the existing firmware pseudo-registers, such as
> > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > for all the hypercall services available.
> >
> > These firmware registers are categorized based on the service call
> > owners, but unlike the existing firmware pseudo-registers, they hold
> > the features supported in the form of a bitmap.
> >
> > During the VM initialization, the registers are set to upper-limit of
> > the features supported by the corresponding registers. It's expected
> > that the VMMs discover the features provided by each register via
> > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > KVM allows this modification only until the VM has started.
> >
> > Some of the standard features are not mapped to any bits of the
> > registers. But since they can recreate the original problem of
> > making it available without userspace's consent, they need to
> > be explicitly added to the case-list in
> > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> >
> > Older userspace code can simply ignore the feature and the
> > hypercall services will be exposed unconditionally to the guests,
> > thus ensuring backward compatibility.
> >
> > In this patch, the framework adds the register only for ARM's standard
> > secure services (owner value 4). Currently, this includes support only
> > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > register representing mandatory features of v1.0. Other services are
> > momentarily added in the upcoming patches.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> >  arch/arm64/kvm/arm.c              |  1 +
> >  arch/arm64/kvm/guest.c            |  8 ++-
> >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> >  arch/arm64/kvm/psci.c             | 13 +++++
> >  include/kvm/arm_hypercalls.h      |  6 ++
> >  include/kvm/arm_psci.h            |  2 +-
> >  8 files changed, 142 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 94a27a7520f4..df07f4c10197 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> >  struct kvm_arch_memory_slot {
> >  };
> >
> > +/**
> > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > + *
> > + * @std_bmap: Bitmap of standard secure service calls
> > + */
> > +struct kvm_smccc_features {
> > +       unsigned long std_bmap;
> > +};
> > +
> >  struct kvm_arch {
> >         struct kvm_s2_mmu mmu;
> >
> > @@ -150,6 +159,9 @@ struct kvm_arch {
> >
> >         u8 pfr0_csv2;
> >         u8 pfr0_csv3;
> > +
> > +       /* Hypercall features firmware registers' descriptor */
> > +       struct kvm_smccc_features smccc_feat;
> >  };
> >
> >  struct kvm_vcpu_fault_info {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> >  #define KVM_ARM64_SVE_VLS_WORDS        \
> >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> >
> > +/* Bitmap feature firmware registers */
> > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > +                                               ((r) & 0xffff))
> > +
> > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > index 523bc934fe2f..a37fadbd617e 100644
> > --- a/arch/arm64/kvm/arm.c
> > +++ b/arch/arm64/kvm/arm.c
> > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> >
> >         set_default_spectre(kvm);
> > +       kvm_arm_init_hypercalls(kvm);
> >
> >         return ret;
> >  out_free_stage2_pgd:
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 0d5cca56cbda..8c607199cad1 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > +       case KVM_REG_ARM_FW:
> > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > +               return kvm_arm_get_fw_reg(vcpu, reg);
> >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> >         }
> >
> > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > +       case KVM_REG_ARM_FW:
> > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > +               return kvm_arm_set_fw_reg(vcpu, reg);
> >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> >         }
> >
> > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index fa6d9378d8e7..df55a04d2fe8 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> >         val[3] = lower_32_bits(cycles);
> >  }
> >
> > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > +{
> > +       return test_bit(feat_bit, reg_bmap);
> > +}
> > +
> > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       switch (func_id) {
> > +       /*
> > +        * List of function-ids that are not gated with the bitmapped feature
> > +        * firmware registers, and are to be allowed for servicing the call by default.
> > +        */
> > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +               return true;
> > +       default:
> > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > +       }
> > +}
> > +
> > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > +
> > +       switch (func_id) {
> > +       case ARM_SMCCC_TRNG_VERSION:
> > +       case ARM_SMCCC_TRNG_FEATURES:
> > +       case ARM_SMCCC_TRNG_GET_UUID:
> > +       case ARM_SMCCC_TRNG_RND32:
> > +       case ARM_SMCCC_TRNG_RND64:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > +       default:
> > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > +       }
> > +}
> > +
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >  {
> >         u32 func_id = smccc_get_function(vcpu);
> > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >         u32 feature;
> >         gpa_t gpa;
> >
> > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > +               goto out;
> > +
> >         switch (func_id) {
> >         case ARM_SMCCC_VERSION_FUNC_ID:
> >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >                 return kvm_psci_call(vcpu);
> >         }
> >
> > +out:
> >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> >         return 1;
> >  }
> > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > +       KVM_REG_ARM_STD_BMAP,
> >  };
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > +{
> > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +
> > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > +}
> > +
> >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> >  {
> >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> >
> >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  {
> > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> >         void __user *uaddr = (void __user *)(long)reg->addr;
> >         u64 val;
> >
> > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> >                 break;
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               val = READ_ONCE(smccc_feat->std_bmap);
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         return 0;
> >  }
> >
> > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > +{
> > +       int ret = 0;
> > +       struct kvm *kvm = vcpu->kvm;
> > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > +
> > +       switch (reg_id) {
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > +               break;
> > +       default:
> > +               return -ENOENT;
> > +       }
> > +
> > +       /* Check for unsupported bit */
> > +       if (val & ~fw_reg_features)
> > +               return -EINVAL;
> > +
> > +       mutex_lock(&kvm->lock);
>
> Why don't you check if the register value will be modified before
> getting the lock ? (then there is nothing to do)
> It would help reduce unnecessary serialization for live migration
> (even without the vm-scoped register capability).
>
That was the case until v5. Since v6, we return -EBUSY unconditionally
regardless of the incoming value. See Marc's comments in [1].
>
>
> > +
> > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > +               ret = -EBUSY;
> > +               goto out;
> > +       }
>
> I just would like to make sure that you are sure that existing
> userspace you know will not run KVM_RUN for any vCPUs until
> KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> correct ?
>
Since v6, that is something that we are leaving with the userspace to
synchronize. See [1].
>
> > +
> > +       WRITE_ONCE(*fw_reg_bmap, val);
> > +out:
> > +       mutex_unlock(&kvm->lock);
> > +       return ret;
> > +}
> > +
> >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  {
> >         void __user *uaddr = (void __user *)(long)reg->addr;
> > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                         return -EINVAL;
> >
> >                 return 0;
> > +       case KVM_REG_ARM_STD_BMAP:
> > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >         default:
> >                 return -ENOENT;
> >         }
> > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > index 346535169faa..67d1273e8086 100644
> > --- a/arch/arm64/kvm/psci.c
> > +++ b/arch/arm64/kvm/psci.c
> > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> >                 return -EINVAL;
> >         }
> >  }
> > +
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > +
> > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > +               return true;
>
> For PSCI 0.1, the function checks if the funct_id is valid for
> the vCPU (according to the vCPU's PSCI version).
> For other version of PSCI, the function doesn't care the vCPU's
> PSCI version (although supported functions depend on the PSCI
> version and not all of them are defined yet, the code returns
> true as long as the function id is within the reserved PSCI
> function id range).
> So, the behavior appears to be inconsistent.
> Shouldn't it return the validity of the function id according
> to the vCPU's psci version for non-PSCI 0.1 case as well ?
> (Otherwise, shouldn't it return true if the function id is valid
> for any of the PSCI versions ?)
>
Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
with the SMCCC, hence needed some special handling. Only two func_ids
are currently supported by KVM, and we just check for each. The second
'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
specification defines a range of acceptable PSCI func_ids.

If it's confusing, I can add a comment above the second 'if' that it's
for all PSCI versions >= 0.2.
> Thanks,
> Reiji
>
Thank you.
Raghavendra

[1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
>
>
> > +
> > +       return false;
> > +}
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index 5d38628a8d04..499b45b607b6 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -6,6 +6,11 @@
> >
> >  #include <asm/kvm_emulate.h>
> >
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > +
> > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > +
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> >
> >  struct kvm_one_reg;
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> >  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);
> > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > index 6e55b9283789..c47be3e26965 100644
> > --- a/include/kvm/arm_psci.h
> > +++ b/include/kvm/arm_psci.h
> > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> >         return KVM_ARM_PSCI_0_1;
> >  }
> >
> > -
> >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> >
> >  #endif /* __KVM_ARM_PSCI_H__ */
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
  2022-04-25  6:22     ` Reiji Watanabe
  (?)
@ 2022-04-25 16:51       ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:51 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Reiji,

On Sun, Apr 24, 2022 at 11:22 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Introduce the firmware register to hold the vendor specific
> > hypervisor service calls (owner value 6) as a bitmap. The
> > bitmap represents the features that'll be enabled for the
> > guest, as configured by the user-space. Currently, this
> > includes support for KVM-vendor features along with
> > reading the UID, represented by bit-0, and Precision Time
> > Protocol (PTP), represented by bit-1.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h |  2 ++
> >  arch/arm64/include/uapi/asm/kvm.h |  4 ++++
> >  arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
> >  include/kvm/arm_hypercalls.h      |  2 ++
> >  4 files changed, 26 insertions(+), 5 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 27d4b2a7970e..a025c2ba012a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
> >   *
> >   * @std_bmap: Bitmap of standard secure service calls
> >   * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> > + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
> >   */
> >  struct kvm_smccc_features {
> >         unsigned long std_bmap;
> >         unsigned long std_hyp_bmap;
> > +       unsigned long vendor_hyp_bmap;
> >  };
> >
> >  struct kvm_arch {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index 9eecc7ee8c14..e7d5ae222684 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
> >  #define KVM_REG_ARM_STD_HYP_BMAP               KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
> >  #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME                0
> >
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP            KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> > +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT   0
> > +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP         1
> > +
> >  /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index f097bebdad39..76e626d0e699 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> >          */
> >         case ARM_SMCCC_VERSION_FUNC_ID:
> >         case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> >                 return true;
> >         default:
> >                 return kvm_psci_func_id_is_valid(vcpu, func_id);
> > @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> >         case ARM_SMCCC_HV_PV_TIME_ST:
> >                 return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> >                                         KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> > +                                       KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> > +                                       KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
> >         default:
> >                 return kvm_hvc_call_default_allowed(vcpu, func_id);
> >         }
> > @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >                 val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
> >                 break;
> >         case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > -               val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> > -               val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> > +               val[0] = smccc_feat->vendor_hyp_bmap;
> >                 break;
> >         case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> >                 kvm_ptp_get_time(vcpu, val);
> > @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> >         KVM_REG_ARM_STD_BMAP,
> >         KVM_REG_ARM_STD_HYP_BMAP,
> > +       KVM_REG_ARM_VENDOR_HYP_BMAP,
> >  };
> >
> >  void kvm_arm_init_hypercalls(struct kvm *kvm)
> > @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
> >
> >         smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> >         smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> > +       smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> >  }
> >
> >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         case KVM_REG_ARM_STD_HYP_BMAP:
> >                 val = READ_ONCE(smccc_feat->std_hyp_bmap);
> >                 break;
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +               val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> >                 fw_reg_bmap = &smccc_feat->std_hyp_bmap;
> >                 fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> >                 break;
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +               fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> > +               fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                 return 0;
> >         case KVM_REG_ARM_STD_BMAP:
> >         case KVM_REG_ARM_STD_HYP_BMAP:
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> >                 return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >         default:
> >                 return -ENOENT;
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index aadd6ae3ab72..4ebfdd26e486 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -9,9 +9,11 @@
> >  /* Last valid bits of the bitmapped firmware registers */
> >  #define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> >  #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX       0
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1
>
> Nit: IMHO perhaps it might be more convenient to define the MAX macro
> in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
> (The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)
>
> #define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP
>
We have been going back and forth on this :)
It made sense for me to keep it in uapi as well, but I took Oliver's
suggestion of keeping it outside of uapi since this is something that
could be constantly changing [1].

Thank you.
Raghavendra

[1]: https://lore.kernel.org/lkml/CAJHc60wz5WsZWTn66i41+G4-dsjCFuFkthXU_Vf6QeXHkgzrZg@mail.gmail.com/

> Thanks,
> Reiji
>
>
> >
> >  #define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> >  #define KVM_ARM_SMCCC_STD_HYP_FEATURES         GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> > +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES      GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
> >
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >

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

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-25 16:51       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:51 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

Hi Reiji,

On Sun, Apr 24, 2022 at 11:22 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Introduce the firmware register to hold the vendor specific
> > hypervisor service calls (owner value 6) as a bitmap. The
> > bitmap represents the features that'll be enabled for the
> > guest, as configured by the user-space. Currently, this
> > includes support for KVM-vendor features along with
> > reading the UID, represented by bit-0, and Precision Time
> > Protocol (PTP), represented by bit-1.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h |  2 ++
> >  arch/arm64/include/uapi/asm/kvm.h |  4 ++++
> >  arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
> >  include/kvm/arm_hypercalls.h      |  2 ++
> >  4 files changed, 26 insertions(+), 5 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 27d4b2a7970e..a025c2ba012a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
> >   *
> >   * @std_bmap: Bitmap of standard secure service calls
> >   * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> > + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
> >   */
> >  struct kvm_smccc_features {
> >         unsigned long std_bmap;
> >         unsigned long std_hyp_bmap;
> > +       unsigned long vendor_hyp_bmap;
> >  };
> >
> >  struct kvm_arch {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index 9eecc7ee8c14..e7d5ae222684 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
> >  #define KVM_REG_ARM_STD_HYP_BMAP               KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
> >  #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME                0
> >
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP            KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> > +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT   0
> > +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP         1
> > +
> >  /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index f097bebdad39..76e626d0e699 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> >          */
> >         case ARM_SMCCC_VERSION_FUNC_ID:
> >         case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> >                 return true;
> >         default:
> >                 return kvm_psci_func_id_is_valid(vcpu, func_id);
> > @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> >         case ARM_SMCCC_HV_PV_TIME_ST:
> >                 return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> >                                         KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> > +                                       KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> > +                                       KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
> >         default:
> >                 return kvm_hvc_call_default_allowed(vcpu, func_id);
> >         }
> > @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >                 val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
> >                 break;
> >         case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > -               val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> > -               val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> > +               val[0] = smccc_feat->vendor_hyp_bmap;
> >                 break;
> >         case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> >                 kvm_ptp_get_time(vcpu, val);
> > @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> >         KVM_REG_ARM_STD_BMAP,
> >         KVM_REG_ARM_STD_HYP_BMAP,
> > +       KVM_REG_ARM_VENDOR_HYP_BMAP,
> >  };
> >
> >  void kvm_arm_init_hypercalls(struct kvm *kvm)
> > @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
> >
> >         smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> >         smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> > +       smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> >  }
> >
> >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         case KVM_REG_ARM_STD_HYP_BMAP:
> >                 val = READ_ONCE(smccc_feat->std_hyp_bmap);
> >                 break;
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +               val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> >                 fw_reg_bmap = &smccc_feat->std_hyp_bmap;
> >                 fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> >                 break;
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +               fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> > +               fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                 return 0;
> >         case KVM_REG_ARM_STD_BMAP:
> >         case KVM_REG_ARM_STD_HYP_BMAP:
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> >                 return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >         default:
> >                 return -ENOENT;
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index aadd6ae3ab72..4ebfdd26e486 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -9,9 +9,11 @@
> >  /* Last valid bits of the bitmapped firmware registers */
> >  #define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> >  #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX       0
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1
>
> Nit: IMHO perhaps it might be more convenient to define the MAX macro
> in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
> (The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)
>
> #define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP
>
We have been going back and forth on this :)
It made sense for me to keep it in uapi as well, but I took Oliver's
suggestion of keeping it outside of uapi since this is something that
could be constantly changing [1].

Thank you.
Raghavendra

[1]: https://lore.kernel.org/lkml/CAJHc60wz5WsZWTn66i41+G4-dsjCFuFkthXU_Vf6QeXHkgzrZg@mail.gmail.com/

> Thanks,
> Reiji
>
>
> >
> >  #define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> >  #define KVM_ARM_SMCCC_STD_HYP_FEATURES         GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> > +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES      GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
> >
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-25 16:51       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:51 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Reiji,

On Sun, Apr 24, 2022 at 11:22 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Introduce the firmware register to hold the vendor specific
> > hypervisor service calls (owner value 6) as a bitmap. The
> > bitmap represents the features that'll be enabled for the
> > guest, as configured by the user-space. Currently, this
> > includes support for KVM-vendor features along with
> > reading the UID, represented by bit-0, and Precision Time
> > Protocol (PTP), represented by bit-1.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h |  2 ++
> >  arch/arm64/include/uapi/asm/kvm.h |  4 ++++
> >  arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
> >  include/kvm/arm_hypercalls.h      |  2 ++
> >  4 files changed, 26 insertions(+), 5 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 27d4b2a7970e..a025c2ba012a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
> >   *
> >   * @std_bmap: Bitmap of standard secure service calls
> >   * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> > + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
> >   */
> >  struct kvm_smccc_features {
> >         unsigned long std_bmap;
> >         unsigned long std_hyp_bmap;
> > +       unsigned long vendor_hyp_bmap;
> >  };
> >
> >  struct kvm_arch {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index 9eecc7ee8c14..e7d5ae222684 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
> >  #define KVM_REG_ARM_STD_HYP_BMAP               KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
> >  #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME                0
> >
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP            KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> > +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT   0
> > +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP         1
> > +
> >  /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index f097bebdad39..76e626d0e699 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> >          */
> >         case ARM_SMCCC_VERSION_FUNC_ID:
> >         case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > -       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> >                 return true;
> >         default:
> >                 return kvm_psci_func_id_is_valid(vcpu, func_id);
> > @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> >         case ARM_SMCCC_HV_PV_TIME_ST:
> >                 return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> >                                         KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> > +                                       KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> > +                                       KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
> >         default:
> >                 return kvm_hvc_call_default_allowed(vcpu, func_id);
> >         }
> > @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >                 val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
> >                 break;
> >         case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > -               val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> > -               val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> > +               val[0] = smccc_feat->vendor_hyp_bmap;
> >                 break;
> >         case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> >                 kvm_ptp_get_time(vcpu, val);
> > @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> >         KVM_REG_ARM_STD_BMAP,
> >         KVM_REG_ARM_STD_HYP_BMAP,
> > +       KVM_REG_ARM_VENDOR_HYP_BMAP,
> >  };
> >
> >  void kvm_arm_init_hypercalls(struct kvm *kvm)
> > @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
> >
> >         smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> >         smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> > +       smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> >  }
> >
> >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >         case KVM_REG_ARM_STD_HYP_BMAP:
> >                 val = READ_ONCE(smccc_feat->std_hyp_bmap);
> >                 break;
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +               val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> >                 fw_reg_bmap = &smccc_feat->std_hyp_bmap;
> >                 fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> >                 break;
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +               fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> > +               fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> > +               break;
> >         default:
> >                 return -ENOENT;
> >         }
> > @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                 return 0;
> >         case KVM_REG_ARM_STD_BMAP:
> >         case KVM_REG_ARM_STD_HYP_BMAP:
> > +       case KVM_REG_ARM_VENDOR_HYP_BMAP:
> >                 return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >         default:
> >                 return -ENOENT;
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index aadd6ae3ab72..4ebfdd26e486 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -9,9 +9,11 @@
> >  /* Last valid bits of the bitmapped firmware registers */
> >  #define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> >  #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX       0
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1
>
> Nit: IMHO perhaps it might be more convenient to define the MAX macro
> in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
> (The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)
>
> #define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP
>
We have been going back and forth on this :)
It made sense for me to keep it in uapi as well, but I took Oliver's
suggestion of keeping it outside of uapi since this is something that
could be constantly changing [1].

Thank you.
Raghavendra

[1]: https://lore.kernel.org/lkml/CAJHc60wz5WsZWTn66i41+G4-dsjCFuFkthXU_Vf6QeXHkgzrZg@mail.gmail.com/

> Thanks,
> Reiji
>
>
> >
> >  #define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> >  #define KVM_ARM_SMCCC_STD_HYP_FEATURES         GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> > +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES      GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
> >
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
  2022-04-25  6:31     ` Reiji Watanabe
  (?)
@ 2022-04-25 16:52       ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:52 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

On Sun, Apr 24, 2022 at 11:31 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Add the documentation for the bitmap firmware registers in
> > hypercalls.rst and api.rst. This includes the details for
> > KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> > KVM_REG_ARM_VENDOR_HYP_BMAP registers.
> >
> > Since the document is growing to carry other hypercall related
> > information, make necessary adjustments to present the document
> > in a generic sense, rather than being PSCI focused.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  Documentation/virt/kvm/api.rst            | 16 ++++
> >  Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
> >  2 files changed, 92 insertions(+), 18 deletions(-)
> >
> > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> > index 85c7abc51af5..ac489191d0a9 100644
> > --- a/Documentation/virt/kvm/api.rst
> > +++ b/Documentation/virt/kvm/api.rst
> > @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
> >
> >    0x6030 0000 0014 <regno:16>
> >
> > +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> > +
> > +  0x6030 0000 0016 <regno:16>
> > +
> > +The bitmap feature firmware registers exposes the hypercall services that are
> > +available for userspace to configure. The set bits corresponds to the services
> > +that are available for the guests to access. By default, KVM sets all the
> > +supported bits during VM initialization. The userspace can discover the
> > +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> > +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> > +
> > +Note: These registers are immutable once any of the vCPUs of the VM has run at
> > +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> > +
> > +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> > +
> >  arm64 SVE registers have the following bit patterns::
> >
> >    0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> > index d52c2e83b5b8..6327c504b2fb 100644
> > --- a/Documentation/virt/kvm/arm/hypercalls.rst
> > +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> > @@ -1,32 +1,32 @@
> >  .. SPDX-License-Identifier: GPL-2.0
> >
> > -=========================================
> > -Power State Coordination Interface (PSCI)
> > -=========================================
> > +=======================
> > +ARM Hypercall Interface
> > +=======================
> >
> > -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.
> > +KVM handles the hypercall services as requested by the guests. New hypercall
> > +services are regularly made available by the ARM specification or by KVM (as
> > +vendor services) if they make sense from a virtualization point of view.
> >
> > -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.
> > +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 version of a hypercall service, or if a migration
> > +causes a different version to be exposed out of the blue to an unsuspecting
> > +guest.
> >
> >  In order to remedy this situation, KVM exposes a set of "firmware
> >  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.
> > +to a convenient value as required.
> >
> > -The following register is defined:
> > +The following registers are defined:
> >
> >  * KVM_REG_ARM_PSCI_VERSION:
> >
> > +  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.
> > +
> >    - 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
> > @@ -74,4 +74,62 @@ The following register is defined:
> >      KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
> >        The workaround is always active on this vCPU or it is not needed.
> >
> > -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> > +
> > +Bitmap Feature Firmware Registers
> > +---------------------------------
> > +
> > +Contrary to the above registers, the following registers exposes the hypercall
> > +services in the form of a feature-bitmap to the userspace. This bitmap is
> > +translated to the services that are available to the guest. There is a register
> > +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> > +
> > +By default, these registers are set with the upper limit of the features that
> > +are supported. This way userspace can discover all the electable hypercall services
> > +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> > +SET_ONE_REG. The features for the registers that are untouched, probably because
> > +userspace isn't aware of them, will be exposed as is to the guest.
> > +
> > +Note that KVM would't allow the userspace to configure the registers anymore once
> > +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> > +
> > +The psuedo-firmware bitmap register are as follows:
> > +
> > +* KVM_REG_ARM_STD_BMAP:
> > +    Controls the bitmap of the ARM Standard Secure Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> > +      The bit represents the services offered under v1.0 of ARM True Random
> > +      Number Generator (TRNG) specification, ARM DEN0098.
> > +
> > +* KVM_REG_ARM_STD_HYP_BMAP:
> > +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> > +      The bit represents the Paravirtualized Time service as represented by
> > +      ARM DEN0057A.
> > +
> > +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> > +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> > +      function-id
>
> Looking at the code,
> the bit also represents ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID.
>
You are right, I missed it here in the doc. I'll fix this.

Regards,
Raghavendra

> Thanks,
> Reiji
>
>
> > +
> > +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> > +      The bit represents the Precision Time Protocol KVM service.
> > +
> > +Errors:
> > +
> > +    =======  =============================================================
> > +    -ENOENT   Unknown register accessed.
> > +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> > +    -EINVAL   Invalid bitmap written to the register.
> > +    =======  =============================================================
> > +
> > +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> > \ No newline at end of file
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >

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

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
@ 2022-04-25 16:52       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:52 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

On Sun, Apr 24, 2022 at 11:31 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Add the documentation for the bitmap firmware registers in
> > hypercalls.rst and api.rst. This includes the details for
> > KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> > KVM_REG_ARM_VENDOR_HYP_BMAP registers.
> >
> > Since the document is growing to carry other hypercall related
> > information, make necessary adjustments to present the document
> > in a generic sense, rather than being PSCI focused.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  Documentation/virt/kvm/api.rst            | 16 ++++
> >  Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
> >  2 files changed, 92 insertions(+), 18 deletions(-)
> >
> > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> > index 85c7abc51af5..ac489191d0a9 100644
> > --- a/Documentation/virt/kvm/api.rst
> > +++ b/Documentation/virt/kvm/api.rst
> > @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
> >
> >    0x6030 0000 0014 <regno:16>
> >
> > +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> > +
> > +  0x6030 0000 0016 <regno:16>
> > +
> > +The bitmap feature firmware registers exposes the hypercall services that are
> > +available for userspace to configure. The set bits corresponds to the services
> > +that are available for the guests to access. By default, KVM sets all the
> > +supported bits during VM initialization. The userspace can discover the
> > +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> > +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> > +
> > +Note: These registers are immutable once any of the vCPUs of the VM has run at
> > +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> > +
> > +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> > +
> >  arm64 SVE registers have the following bit patterns::
> >
> >    0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> > index d52c2e83b5b8..6327c504b2fb 100644
> > --- a/Documentation/virt/kvm/arm/hypercalls.rst
> > +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> > @@ -1,32 +1,32 @@
> >  .. SPDX-License-Identifier: GPL-2.0
> >
> > -=========================================
> > -Power State Coordination Interface (PSCI)
> > -=========================================
> > +=======================
> > +ARM Hypercall Interface
> > +=======================
> >
> > -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.
> > +KVM handles the hypercall services as requested by the guests. New hypercall
> > +services are regularly made available by the ARM specification or by KVM (as
> > +vendor services) if they make sense from a virtualization point of view.
> >
> > -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.
> > +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 version of a hypercall service, or if a migration
> > +causes a different version to be exposed out of the blue to an unsuspecting
> > +guest.
> >
> >  In order to remedy this situation, KVM exposes a set of "firmware
> >  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.
> > +to a convenient value as required.
> >
> > -The following register is defined:
> > +The following registers are defined:
> >
> >  * KVM_REG_ARM_PSCI_VERSION:
> >
> > +  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.
> > +
> >    - 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
> > @@ -74,4 +74,62 @@ The following register is defined:
> >      KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
> >        The workaround is always active on this vCPU or it is not needed.
> >
> > -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> > +
> > +Bitmap Feature Firmware Registers
> > +---------------------------------
> > +
> > +Contrary to the above registers, the following registers exposes the hypercall
> > +services in the form of a feature-bitmap to the userspace. This bitmap is
> > +translated to the services that are available to the guest. There is a register
> > +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> > +
> > +By default, these registers are set with the upper limit of the features that
> > +are supported. This way userspace can discover all the electable hypercall services
> > +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> > +SET_ONE_REG. The features for the registers that are untouched, probably because
> > +userspace isn't aware of them, will be exposed as is to the guest.
> > +
> > +Note that KVM would't allow the userspace to configure the registers anymore once
> > +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> > +
> > +The psuedo-firmware bitmap register are as follows:
> > +
> > +* KVM_REG_ARM_STD_BMAP:
> > +    Controls the bitmap of the ARM Standard Secure Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> > +      The bit represents the services offered under v1.0 of ARM True Random
> > +      Number Generator (TRNG) specification, ARM DEN0098.
> > +
> > +* KVM_REG_ARM_STD_HYP_BMAP:
> > +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> > +      The bit represents the Paravirtualized Time service as represented by
> > +      ARM DEN0057A.
> > +
> > +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> > +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> > +      function-id
>
> Looking at the code,
> the bit also represents ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID.
>
You are right, I missed it here in the doc. I'll fix this.

Regards,
Raghavendra

> Thanks,
> Reiji
>
>
> > +
> > +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> > +      The bit represents the Precision Time Protocol KVM service.
> > +
> > +Errors:
> > +
> > +    =======  =============================================================
> > +    -ENOENT   Unknown register accessed.
> > +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> > +    -EINVAL   Invalid bitmap written to the register.
> > +    =======  =============================================================
> > +
> > +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> > \ No newline at end of file
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
@ 2022-04-25 16:52       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-25 16:52 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

On Sun, Apr 24, 2022 at 11:31 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Add the documentation for the bitmap firmware registers in
> > hypercalls.rst and api.rst. This includes the details for
> > KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> > KVM_REG_ARM_VENDOR_HYP_BMAP registers.
> >
> > Since the document is growing to carry other hypercall related
> > information, make necessary adjustments to present the document
> > in a generic sense, rather than being PSCI focused.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >  Documentation/virt/kvm/api.rst            | 16 ++++
> >  Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
> >  2 files changed, 92 insertions(+), 18 deletions(-)
> >
> > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> > index 85c7abc51af5..ac489191d0a9 100644
> > --- a/Documentation/virt/kvm/api.rst
> > +++ b/Documentation/virt/kvm/api.rst
> > @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
> >
> >    0x6030 0000 0014 <regno:16>
> >
> > +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> > +
> > +  0x6030 0000 0016 <regno:16>
> > +
> > +The bitmap feature firmware registers exposes the hypercall services that are
> > +available for userspace to configure. The set bits corresponds to the services
> > +that are available for the guests to access. By default, KVM sets all the
> > +supported bits during VM initialization. The userspace can discover the
> > +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> > +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> > +
> > +Note: These registers are immutable once any of the vCPUs of the VM has run at
> > +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> > +
> > +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> > +
> >  arm64 SVE registers have the following bit patterns::
> >
> >    0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> > index d52c2e83b5b8..6327c504b2fb 100644
> > --- a/Documentation/virt/kvm/arm/hypercalls.rst
> > +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> > @@ -1,32 +1,32 @@
> >  .. SPDX-License-Identifier: GPL-2.0
> >
> > -=========================================
> > -Power State Coordination Interface (PSCI)
> > -=========================================
> > +=======================
> > +ARM Hypercall Interface
> > +=======================
> >
> > -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.
> > +KVM handles the hypercall services as requested by the guests. New hypercall
> > +services are regularly made available by the ARM specification or by KVM (as
> > +vendor services) if they make sense from a virtualization point of view.
> >
> > -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.
> > +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 version of a hypercall service, or if a migration
> > +causes a different version to be exposed out of the blue to an unsuspecting
> > +guest.
> >
> >  In order to remedy this situation, KVM exposes a set of "firmware
> >  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.
> > +to a convenient value as required.
> >
> > -The following register is defined:
> > +The following registers are defined:
> >
> >  * KVM_REG_ARM_PSCI_VERSION:
> >
> > +  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.
> > +
> >    - 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
> > @@ -74,4 +74,62 @@ The following register is defined:
> >      KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
> >        The workaround is always active on this vCPU or it is not needed.
> >
> > -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> > +
> > +Bitmap Feature Firmware Registers
> > +---------------------------------
> > +
> > +Contrary to the above registers, the following registers exposes the hypercall
> > +services in the form of a feature-bitmap to the userspace. This bitmap is
> > +translated to the services that are available to the guest. There is a register
> > +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> > +
> > +By default, these registers are set with the upper limit of the features that
> > +are supported. This way userspace can discover all the electable hypercall services
> > +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> > +SET_ONE_REG. The features for the registers that are untouched, probably because
> > +userspace isn't aware of them, will be exposed as is to the guest.
> > +
> > +Note that KVM would't allow the userspace to configure the registers anymore once
> > +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> > +
> > +The psuedo-firmware bitmap register are as follows:
> > +
> > +* KVM_REG_ARM_STD_BMAP:
> > +    Controls the bitmap of the ARM Standard Secure Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> > +      The bit represents the services offered under v1.0 of ARM True Random
> > +      Number Generator (TRNG) specification, ARM DEN0098.
> > +
> > +* KVM_REG_ARM_STD_HYP_BMAP:
> > +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> > +      The bit represents the Paravirtualized Time service as represented by
> > +      ARM DEN0057A.
> > +
> > +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> > +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> > +
> > +  The following bits are accepted:
> > +
> > +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> > +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> > +      function-id
>
> Looking at the code,
> the bit also represents ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID.
>
You are right, I missed it here in the doc. I'll fix this.

Regards,
Raghavendra

> Thanks,
> Reiji
>
>
> > +
> > +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> > +      The bit represents the Precision Time Protocol KVM service.
> > +
> > +Errors:
> > +
> > +    =======  =============================================================
> > +    -ENOENT   Unknown register accessed.
> > +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> > +    -EINVAL   Invalid bitmap written to the register.
> > +    =======  =============================================================
> > +
> > +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> > \ No newline at end of file
> > --
> > 2.36.0.rc2.479.g8af0fa9b8e-goog
> >

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
  2022-04-25 16:51       ` Raghavendra Rao Ananta
  (?)
@ 2022-04-25 17:12         ` Oliver Upton
  -1 siblings, 0 replies; 90+ messages in thread
From: Oliver Upton @ 2022-04-25 17:12 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Reiji Watanabe, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose, Paolo Bonzini,
	Catalin Marinas, Will Deacon, Peter Shier, Ricardo Koller,
	Jing Zhang, Linux ARM, kvmarm, linux-kernel, kvm

On Mon, Apr 25, 2022 at 9:52 AM Raghavendra Rao Ananta
<rananta@google.com> wrote:

[...]

> > > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1
> >
> > Nit: IMHO perhaps it might be more convenient to define the MAX macro
> > in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
> > (The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)
> >
> > #define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP
> >
> We have been going back and forth on this :)
> It made sense for me to keep it in uapi as well, but I took Oliver's
> suggestion of keeping it outside of uapi since this is something that
> could be constantly changing [1].

The maximum set of features in a given bitmap register is a property
of the running system, not the headers chosen at compile time. There
is an illusion of ABI breakage when adding new bits to the registers
if we've declared the max bit in UAPI. We also define
KVM_VCPU_MAX_FEATURES outside of UAPI, even though it is related to
the KVM_ARM_VCPU_INIT ioctl.

--
Thanks,
Oliver

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

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-25 17:12         ` Oliver Upton
  0 siblings, 0 replies; 90+ messages in thread
From: Oliver Upton @ 2022-04-25 17:12 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

On Mon, Apr 25, 2022 at 9:52 AM Raghavendra Rao Ananta
<rananta@google.com> wrote:

[...]

> > > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1
> >
> > Nit: IMHO perhaps it might be more convenient to define the MAX macro
> > in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
> > (The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)
> >
> > #define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP
> >
> We have been going back and forth on this :)
> It made sense for me to keep it in uapi as well, but I took Oliver's
> suggestion of keeping it outside of uapi since this is something that
> could be constantly changing [1].

The maximum set of features in a given bitmap register is a property
of the running system, not the headers chosen at compile time. There
is an illusion of ABI breakage when adding new bits to the registers
if we've declared the max bit in UAPI. We also define
KVM_VCPU_MAX_FEATURES outside of UAPI, even though it is related to
the KVM_ARM_VCPU_INIT ioctl.

--
Thanks,
Oliver
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-25 17:12         ` Oliver Upton
  0 siblings, 0 replies; 90+ messages in thread
From: Oliver Upton @ 2022-04-25 17:12 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Reiji Watanabe, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose, Paolo Bonzini,
	Catalin Marinas, Will Deacon, Peter Shier, Ricardo Koller,
	Jing Zhang, Linux ARM, kvmarm, linux-kernel, kvm

On Mon, Apr 25, 2022 at 9:52 AM Raghavendra Rao Ananta
<rananta@google.com> wrote:

[...]

> > > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX    1
> >
> > Nit: IMHO perhaps it might be more convenient to define the MAX macro
> > in arch/arm64/include/uapi/asm/kvm.h like below for maintenance ?
> > (The same comments are applied to other KVM_REG_ARM_*_BMAP_BIT_MAX)
> >
> > #define KVM_REG_ARM_VENDOR_HYP_BIT_MAX KVM_REG_ARM_VENDOR_HYP_BIT_PTP
> >
> We have been going back and forth on this :)
> It made sense for me to keep it in uapi as well, but I took Oliver's
> suggestion of keeping it outside of uapi since this is something that
> could be constantly changing [1].

The maximum set of features in a given bitmap register is a property
of the running system, not the headers chosen at compile time. There
is an illusion of ABI breakage when adding new bits to the registers
if we've declared the max bit in UAPI. We also define
KVM_VCPU_MAX_FEATURES outside of UAPI, even though it is related to
the KVM_ARM_VCPU_INIT ioctl.

--
Thanks,
Oliver

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-26  6:33     ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:33 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Hi Raghavendra,

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> KVM regularly introduces new hypercall services to the guests without
> any consent from the userspace. This means, the guests can observe
> hypercall services in and out as they migrate across various host
> kernel versions. This could be a major problem if the guest
> discovered a hypercall, started using it, and after getting migrated
> to an older kernel realizes that it's no longer available. Depending
> on how the guest handles the change, there's a potential chance that
> the guest would just panic.
> 
> As a result, there's a need for the userspace to elect the services
> that it wishes the guest to discover. It can elect these services
> based on the kernels spread across its (migration) fleet. To remedy
> this, extend the existing firmware pseudo-registers, such as
> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> for all the hypercall services available.
> 
> These firmware registers are categorized based on the service call
> owners, but unlike the existing firmware pseudo-registers, they hold
> the features supported in the form of a bitmap.
> 
> During the VM initialization, the registers are set to upper-limit of
> the features supported by the corresponding registers. It's expected
> that the VMMs discover the features provided by each register via
> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> KVM allows this modification only until the VM has started.
> 
> Some of the standard features are not mapped to any bits of the
> registers. But since they can recreate the original problem of
> making it available without userspace's consent, they need to
> be explicitly added to the case-list in
> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> 
> Older userspace code can simply ignore the feature and the
> hypercall services will be exposed unconditionally to the guests,
> thus ensuring backward compatibility.
> 
> In this patch, the framework adds the register only for ARM's standard
> secure services (owner value 4). Currently, this includes support only
> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> register representing mandatory features of v1.0. Other services are
> momentarily added in the upcoming patches.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h | 12 ++++
>   arch/arm64/include/uapi/asm/kvm.h |  9 +++
>   arch/arm64/kvm/arm.c              |  1 +
>   arch/arm64/kvm/guest.c            |  8 ++-
>   arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>   arch/arm64/kvm/psci.c             | 13 +++++
>   include/kvm/arm_hypercalls.h      |  6 ++
>   include/kvm/arm_psci.h            |  2 +-
>   8 files changed, 142 insertions(+), 3 deletions(-)
> 

Some nits as below, please consider to improve if you need another
respin.

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 94a27a7520f4..df07f4c10197 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>   struct kvm_arch_memory_slot {
>   };
>   
> +/**
> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> + *
> + * @std_bmap: Bitmap of standard secure service calls
> + */
> +struct kvm_smccc_features {
> +	unsigned long std_bmap;
> +};
> +

s/Descriptor/Descriptor of

>   struct kvm_arch {
>   	struct kvm_s2_mmu mmu;
>   
> @@ -150,6 +159,9 @@ struct kvm_arch {
>   
>   	u8 pfr0_csv2;
>   	u8 pfr0_csv3;
> +
> +	/* Hypercall features firmware registers' descriptor */
> +	struct kvm_smccc_features smccc_feat;
>   };
>   
>   struct kvm_vcpu_fault_info {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index c1b6ddc02d2f..0b79d2dc6ffd 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_ARM64_SVE_VLS_WORDS	\
>   	((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>   
> +/* Bitmap feature firmware registers */
> +#define KVM_REG_ARM_FW_FEAT_BMAP		(0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> +						KVM_REG_ARM_FW_FEAT_BMAP |	\
> +						((r) & 0xffff))
> +
> +#define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0		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/arm.c b/arch/arm64/kvm/arm.c
> index 523bc934fe2f..a37fadbd617e 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>   	kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>   
>   	set_default_spectre(kvm);
> +	kvm_arm_init_hypercalls(kvm);
>   
>   	return ret;
>   out_free_stage2_pgd:
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 0d5cca56cbda..8c607199cad1 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>   	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> -	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:
> +	case KVM_REG_ARM_FW_FEAT_BMAP:
> +		return kvm_arm_get_fw_reg(vcpu, reg);
>   	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
>   	}
>   
> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>   	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> -	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:
> +	case KVM_REG_ARM_FW_FEAT_BMAP:
> +		return kvm_arm_set_fw_reg(vcpu, reg);
>   	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
>   	}
>   
> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index fa6d9378d8e7..df55a04d2fe8 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>   	val[3] = lower_32_bits(cycles);
>   }
>   
> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> +{
> +	return test_bit(feat_bit, reg_bmap);
> +}
> +

Might be worhty to be 'inline'. This function would be called
frequently.

> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	switch (func_id) {
> +	/*
> +	 * List of function-ids that are not gated with the bitmapped feature
> +	 * firmware registers, and are to be allowed for servicing the call by default.
> +	 */
> +	case ARM_SMCCC_VERSION_FUNC_ID:
> +	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +	case ARM_SMCCC_HV_PV_TIME_ST:
> +	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +		return true;
> +	default:
> +		return kvm_psci_func_id_is_valid(vcpu, func_id);
> +	}
> +}
> +
> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> +
> +	switch (func_id) {
> +	case ARM_SMCCC_TRNG_VERSION:
> +	case ARM_SMCCC_TRNG_FEATURES:
> +	case ARM_SMCCC_TRNG_GET_UUID:
> +	case ARM_SMCCC_TRNG_RND32:
> +	case ARM_SMCCC_TRNG_RND64:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> +						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +	default:
> +		return kvm_hvc_call_default_allowed(vcpu, func_id);
> +	}
> +}
> +
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   {
>   	u32 func_id = smccc_get_function(vcpu);
> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   	u32 feature;
>   	gpa_t gpa;
>   
> +	if (!kvm_hvc_call_allowed(vcpu, func_id))
> +		goto out;
> +
>   	switch (func_id) {
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   		val[0] = ARM_SMCCC_VERSION_1_1;
> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   		return kvm_psci_call(vcpu);
>   	}
>   
> +out:
>   	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>   	return 1;
>   }
> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> +	KVM_REG_ARM_STD_BMAP,
>   };
>   
> +void kvm_arm_init_hypercalls(struct kvm *kvm)
> +{
> +	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +
> +	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +}
> +
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>   {
>   	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>   
>   int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   {
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>   	void __user *uaddr = (void __user *)(long)reg->addr;
>   	u64 val;
>   
> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>   		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>   		break;
> +	case KVM_REG_ARM_STD_BMAP:
> +		val = READ_ONCE(smccc_feat->std_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	return 0;
>   }
>   
> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> +{
> +	int ret = 0;
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +	unsigned long *fw_reg_bmap, fw_reg_features;
> +
> +	switch (reg_id) {
> +	case KVM_REG_ARM_STD_BMAP:
> +		fw_reg_bmap = &smccc_feat->std_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> +		break;
> +	default:
> +		return -ENOENT;
> +	}
> +
> +	/* Check for unsupported bit */
> +	if (val & ~fw_reg_features)
> +		return -EINVAL;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	/* Return -EBUSY if the VM (any vCPU) has already started running. */
> +	if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	WRITE_ONCE(*fw_reg_bmap, val);
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return ret;
> +}
> +
>   int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   {
>   	void __user *uaddr = (void __user *)(long)reg->addr;
> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   			return -EINVAL;
>   
>   		return 0;
> +	case KVM_REG_ARM_STD_BMAP:
> +		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
>   	}
> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> index 346535169faa..67d1273e8086 100644
> --- a/arch/arm64/kvm/psci.c
> +++ b/arch/arm64/kvm/psci.c
> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>   		return -EINVAL;
>   	}
>   }
> +
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	/* PSCI 0.1 doesn't comply with the standard SMCCC */
> +	if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> +		return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> +
> +	if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> +		ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> +		return true;
> +
> +	return false;
> +}
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 5d38628a8d04..499b45b607b6 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -6,6 +6,11 @@
>   
>   #include <asm/kvm_emulate.h>
>   
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +
> +#define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +

s/bits of/bit of

>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
>   static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>   
>   struct kvm_one_reg;
>   
> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>   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);
> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> index 6e55b9283789..c47be3e26965 100644
> --- a/include/kvm/arm_psci.h
> +++ b/include/kvm/arm_psci.h
> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>   	return KVM_ARM_PSCI_0_1;
>   }
>   
> -
>   int kvm_psci_call(struct kvm_vcpu *vcpu);
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>   
>   #endif /* __KVM_ARM_PSCI_H__ */
> 

Thanks,
Gavin


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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-26  6:33     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:33 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Hi Raghavendra,

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> KVM regularly introduces new hypercall services to the guests without
> any consent from the userspace. This means, the guests can observe
> hypercall services in and out as they migrate across various host
> kernel versions. This could be a major problem if the guest
> discovered a hypercall, started using it, and after getting migrated
> to an older kernel realizes that it's no longer available. Depending
> on how the guest handles the change, there's a potential chance that
> the guest would just panic.
> 
> As a result, there's a need for the userspace to elect the services
> that it wishes the guest to discover. It can elect these services
> based on the kernels spread across its (migration) fleet. To remedy
> this, extend the existing firmware pseudo-registers, such as
> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> for all the hypercall services available.
> 
> These firmware registers are categorized based on the service call
> owners, but unlike the existing firmware pseudo-registers, they hold
> the features supported in the form of a bitmap.
> 
> During the VM initialization, the registers are set to upper-limit of
> the features supported by the corresponding registers. It's expected
> that the VMMs discover the features provided by each register via
> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> KVM allows this modification only until the VM has started.
> 
> Some of the standard features are not mapped to any bits of the
> registers. But since they can recreate the original problem of
> making it available without userspace's consent, they need to
> be explicitly added to the case-list in
> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> 
> Older userspace code can simply ignore the feature and the
> hypercall services will be exposed unconditionally to the guests,
> thus ensuring backward compatibility.
> 
> In this patch, the framework adds the register only for ARM's standard
> secure services (owner value 4). Currently, this includes support only
> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> register representing mandatory features of v1.0. Other services are
> momentarily added in the upcoming patches.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h | 12 ++++
>   arch/arm64/include/uapi/asm/kvm.h |  9 +++
>   arch/arm64/kvm/arm.c              |  1 +
>   arch/arm64/kvm/guest.c            |  8 ++-
>   arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>   arch/arm64/kvm/psci.c             | 13 +++++
>   include/kvm/arm_hypercalls.h      |  6 ++
>   include/kvm/arm_psci.h            |  2 +-
>   8 files changed, 142 insertions(+), 3 deletions(-)
> 

Some nits as below, please consider to improve if you need another
respin.

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 94a27a7520f4..df07f4c10197 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>   struct kvm_arch_memory_slot {
>   };
>   
> +/**
> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> + *
> + * @std_bmap: Bitmap of standard secure service calls
> + */
> +struct kvm_smccc_features {
> +	unsigned long std_bmap;
> +};
> +

s/Descriptor/Descriptor of

>   struct kvm_arch {
>   	struct kvm_s2_mmu mmu;
>   
> @@ -150,6 +159,9 @@ struct kvm_arch {
>   
>   	u8 pfr0_csv2;
>   	u8 pfr0_csv3;
> +
> +	/* Hypercall features firmware registers' descriptor */
> +	struct kvm_smccc_features smccc_feat;
>   };
>   
>   struct kvm_vcpu_fault_info {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index c1b6ddc02d2f..0b79d2dc6ffd 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_ARM64_SVE_VLS_WORDS	\
>   	((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>   
> +/* Bitmap feature firmware registers */
> +#define KVM_REG_ARM_FW_FEAT_BMAP		(0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> +						KVM_REG_ARM_FW_FEAT_BMAP |	\
> +						((r) & 0xffff))
> +
> +#define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0		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/arm.c b/arch/arm64/kvm/arm.c
> index 523bc934fe2f..a37fadbd617e 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>   	kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>   
>   	set_default_spectre(kvm);
> +	kvm_arm_init_hypercalls(kvm);
>   
>   	return ret;
>   out_free_stage2_pgd:
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 0d5cca56cbda..8c607199cad1 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>   	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> -	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:
> +	case KVM_REG_ARM_FW_FEAT_BMAP:
> +		return kvm_arm_get_fw_reg(vcpu, reg);
>   	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
>   	}
>   
> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>   	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> -	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:
> +	case KVM_REG_ARM_FW_FEAT_BMAP:
> +		return kvm_arm_set_fw_reg(vcpu, reg);
>   	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
>   	}
>   
> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index fa6d9378d8e7..df55a04d2fe8 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>   	val[3] = lower_32_bits(cycles);
>   }
>   
> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> +{
> +	return test_bit(feat_bit, reg_bmap);
> +}
> +

Might be worhty to be 'inline'. This function would be called
frequently.

> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	switch (func_id) {
> +	/*
> +	 * List of function-ids that are not gated with the bitmapped feature
> +	 * firmware registers, and are to be allowed for servicing the call by default.
> +	 */
> +	case ARM_SMCCC_VERSION_FUNC_ID:
> +	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +	case ARM_SMCCC_HV_PV_TIME_ST:
> +	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +		return true;
> +	default:
> +		return kvm_psci_func_id_is_valid(vcpu, func_id);
> +	}
> +}
> +
> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> +
> +	switch (func_id) {
> +	case ARM_SMCCC_TRNG_VERSION:
> +	case ARM_SMCCC_TRNG_FEATURES:
> +	case ARM_SMCCC_TRNG_GET_UUID:
> +	case ARM_SMCCC_TRNG_RND32:
> +	case ARM_SMCCC_TRNG_RND64:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> +						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +	default:
> +		return kvm_hvc_call_default_allowed(vcpu, func_id);
> +	}
> +}
> +
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   {
>   	u32 func_id = smccc_get_function(vcpu);
> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   	u32 feature;
>   	gpa_t gpa;
>   
> +	if (!kvm_hvc_call_allowed(vcpu, func_id))
> +		goto out;
> +
>   	switch (func_id) {
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   		val[0] = ARM_SMCCC_VERSION_1_1;
> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   		return kvm_psci_call(vcpu);
>   	}
>   
> +out:
>   	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>   	return 1;
>   }
> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> +	KVM_REG_ARM_STD_BMAP,
>   };
>   
> +void kvm_arm_init_hypercalls(struct kvm *kvm)
> +{
> +	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +
> +	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +}
> +
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>   {
>   	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>   
>   int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   {
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>   	void __user *uaddr = (void __user *)(long)reg->addr;
>   	u64 val;
>   
> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>   		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>   		break;
> +	case KVM_REG_ARM_STD_BMAP:
> +		val = READ_ONCE(smccc_feat->std_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	return 0;
>   }
>   
> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> +{
> +	int ret = 0;
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +	unsigned long *fw_reg_bmap, fw_reg_features;
> +
> +	switch (reg_id) {
> +	case KVM_REG_ARM_STD_BMAP:
> +		fw_reg_bmap = &smccc_feat->std_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> +		break;
> +	default:
> +		return -ENOENT;
> +	}
> +
> +	/* Check for unsupported bit */
> +	if (val & ~fw_reg_features)
> +		return -EINVAL;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	/* Return -EBUSY if the VM (any vCPU) has already started running. */
> +	if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	WRITE_ONCE(*fw_reg_bmap, val);
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return ret;
> +}
> +
>   int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   {
>   	void __user *uaddr = (void __user *)(long)reg->addr;
> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   			return -EINVAL;
>   
>   		return 0;
> +	case KVM_REG_ARM_STD_BMAP:
> +		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
>   	}
> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> index 346535169faa..67d1273e8086 100644
> --- a/arch/arm64/kvm/psci.c
> +++ b/arch/arm64/kvm/psci.c
> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>   		return -EINVAL;
>   	}
>   }
> +
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	/* PSCI 0.1 doesn't comply with the standard SMCCC */
> +	if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> +		return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> +
> +	if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> +		ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> +		return true;
> +
> +	return false;
> +}
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 5d38628a8d04..499b45b607b6 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -6,6 +6,11 @@
>   
>   #include <asm/kvm_emulate.h>
>   
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +
> +#define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +

s/bits of/bit of

>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
>   static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>   
>   struct kvm_one_reg;
>   
> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>   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);
> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> index 6e55b9283789..c47be3e26965 100644
> --- a/include/kvm/arm_psci.h
> +++ b/include/kvm/arm_psci.h
> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>   	return KVM_ARM_PSCI_0_1;
>   }
>   
> -
>   int kvm_psci_call(struct kvm_vcpu *vcpu);
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>   
>   #endif /* __KVM_ARM_PSCI_H__ */
> 

Thanks,
Gavin

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-26  6:33     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:33 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Hi Raghavendra,

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> KVM regularly introduces new hypercall services to the guests without
> any consent from the userspace. This means, the guests can observe
> hypercall services in and out as they migrate across various host
> kernel versions. This could be a major problem if the guest
> discovered a hypercall, started using it, and after getting migrated
> to an older kernel realizes that it's no longer available. Depending
> on how the guest handles the change, there's a potential chance that
> the guest would just panic.
> 
> As a result, there's a need for the userspace to elect the services
> that it wishes the guest to discover. It can elect these services
> based on the kernels spread across its (migration) fleet. To remedy
> this, extend the existing firmware pseudo-registers, such as
> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> for all the hypercall services available.
> 
> These firmware registers are categorized based on the service call
> owners, but unlike the existing firmware pseudo-registers, they hold
> the features supported in the form of a bitmap.
> 
> During the VM initialization, the registers are set to upper-limit of
> the features supported by the corresponding registers. It's expected
> that the VMMs discover the features provided by each register via
> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> KVM allows this modification only until the VM has started.
> 
> Some of the standard features are not mapped to any bits of the
> registers. But since they can recreate the original problem of
> making it available without userspace's consent, they need to
> be explicitly added to the case-list in
> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> 
> Older userspace code can simply ignore the feature and the
> hypercall services will be exposed unconditionally to the guests,
> thus ensuring backward compatibility.
> 
> In this patch, the framework adds the register only for ARM's standard
> secure services (owner value 4). Currently, this includes support only
> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> register representing mandatory features of v1.0. Other services are
> momentarily added in the upcoming patches.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h | 12 ++++
>   arch/arm64/include/uapi/asm/kvm.h |  9 +++
>   arch/arm64/kvm/arm.c              |  1 +
>   arch/arm64/kvm/guest.c            |  8 ++-
>   arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>   arch/arm64/kvm/psci.c             | 13 +++++
>   include/kvm/arm_hypercalls.h      |  6 ++
>   include/kvm/arm_psci.h            |  2 +-
>   8 files changed, 142 insertions(+), 3 deletions(-)
> 

Some nits as below, please consider to improve if you need another
respin.

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 94a27a7520f4..df07f4c10197 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>   struct kvm_arch_memory_slot {
>   };
>   
> +/**
> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> + *
> + * @std_bmap: Bitmap of standard secure service calls
> + */
> +struct kvm_smccc_features {
> +	unsigned long std_bmap;
> +};
> +

s/Descriptor/Descriptor of

>   struct kvm_arch {
>   	struct kvm_s2_mmu mmu;
>   
> @@ -150,6 +159,9 @@ struct kvm_arch {
>   
>   	u8 pfr0_csv2;
>   	u8 pfr0_csv3;
> +
> +	/* Hypercall features firmware registers' descriptor */
> +	struct kvm_smccc_features smccc_feat;
>   };
>   
>   struct kvm_vcpu_fault_info {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index c1b6ddc02d2f..0b79d2dc6ffd 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_ARM64_SVE_VLS_WORDS	\
>   	((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>   
> +/* Bitmap feature firmware registers */
> +#define KVM_REG_ARM_FW_FEAT_BMAP		(0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)		(KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> +						KVM_REG_ARM_FW_FEAT_BMAP |	\
> +						((r) & 0xffff))
> +
> +#define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0		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/arm.c b/arch/arm64/kvm/arm.c
> index 523bc934fe2f..a37fadbd617e 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>   	kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>   
>   	set_default_spectre(kvm);
> +	kvm_arm_init_hypercalls(kvm);
>   
>   	return ret;
>   out_free_stage2_pgd:
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 0d5cca56cbda..8c607199cad1 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>   	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> -	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:
> +	case KVM_REG_ARM_FW_FEAT_BMAP:
> +		return kvm_arm_get_fw_reg(vcpu, reg);
>   	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
>   	}
>   
> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>   	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> -	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:
> +	case KVM_REG_ARM_FW_FEAT_BMAP:
> +		return kvm_arm_set_fw_reg(vcpu, reg);
>   	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
>   	}
>   
> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index fa6d9378d8e7..df55a04d2fe8 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>   	val[3] = lower_32_bits(cycles);
>   }
>   
> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> +{
> +	return test_bit(feat_bit, reg_bmap);
> +}
> +

Might be worhty to be 'inline'. This function would be called
frequently.

> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	switch (func_id) {
> +	/*
> +	 * List of function-ids that are not gated with the bitmapped feature
> +	 * firmware registers, and are to be allowed for servicing the call by default.
> +	 */
> +	case ARM_SMCCC_VERSION_FUNC_ID:
> +	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +	case ARM_SMCCC_HV_PV_TIME_ST:
> +	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +		return true;
> +	default:
> +		return kvm_psci_func_id_is_valid(vcpu, func_id);
> +	}
> +}
> +
> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> +
> +	switch (func_id) {
> +	case ARM_SMCCC_TRNG_VERSION:
> +	case ARM_SMCCC_TRNG_FEATURES:
> +	case ARM_SMCCC_TRNG_GET_UUID:
> +	case ARM_SMCCC_TRNG_RND32:
> +	case ARM_SMCCC_TRNG_RND64:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> +						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +	default:
> +		return kvm_hvc_call_default_allowed(vcpu, func_id);
> +	}
> +}
> +
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   {
>   	u32 func_id = smccc_get_function(vcpu);
> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   	u32 feature;
>   	gpa_t gpa;
>   
> +	if (!kvm_hvc_call_allowed(vcpu, func_id))
> +		goto out;
> +
>   	switch (func_id) {
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   		val[0] = ARM_SMCCC_VERSION_1_1;
> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   		return kvm_psci_call(vcpu);
>   	}
>   
> +out:
>   	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>   	return 1;
>   }
> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> +	KVM_REG_ARM_STD_BMAP,
>   };
>   
> +void kvm_arm_init_hypercalls(struct kvm *kvm)
> +{
> +	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +
> +	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +}
> +
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>   {
>   	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>   
>   int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   {
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>   	void __user *uaddr = (void __user *)(long)reg->addr;
>   	u64 val;
>   
> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>   		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>   		break;
> +	case KVM_REG_ARM_STD_BMAP:
> +		val = READ_ONCE(smccc_feat->std_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	return 0;
>   }
>   
> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> +{
> +	int ret = 0;
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> +	unsigned long *fw_reg_bmap, fw_reg_features;
> +
> +	switch (reg_id) {
> +	case KVM_REG_ARM_STD_BMAP:
> +		fw_reg_bmap = &smccc_feat->std_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> +		break;
> +	default:
> +		return -ENOENT;
> +	}
> +
> +	/* Check for unsupported bit */
> +	if (val & ~fw_reg_features)
> +		return -EINVAL;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	/* Return -EBUSY if the VM (any vCPU) has already started running. */
> +	if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	WRITE_ONCE(*fw_reg_bmap, val);
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return ret;
> +}
> +
>   int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   {
>   	void __user *uaddr = (void __user *)(long)reg->addr;
> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   			return -EINVAL;
>   
>   		return 0;
> +	case KVM_REG_ARM_STD_BMAP:
> +		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
>   	}
> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> index 346535169faa..67d1273e8086 100644
> --- a/arch/arm64/kvm/psci.c
> +++ b/arch/arm64/kvm/psci.c
> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>   		return -EINVAL;
>   	}
>   }
> +
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> +{
> +	/* PSCI 0.1 doesn't comply with the standard SMCCC */
> +	if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> +		return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> +
> +	if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> +		ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> +		return true;
> +
> +	return false;
> +}
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 5d38628a8d04..499b45b607b6 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -6,6 +6,11 @@
>   
>   #include <asm/kvm_emulate.h>
>   
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +
> +#define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +

s/bits of/bit of

>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
>   static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>   
>   struct kvm_one_reg;
>   
> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>   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);
> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> index 6e55b9283789..c47be3e26965 100644
> --- a/include/kvm/arm_psci.h
> +++ b/include/kvm/arm_psci.h
> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>   	return KVM_ARM_PSCI_0_1;
>   }
>   
> -
>   int kvm_psci_call(struct kvm_vcpu *vcpu);
> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>   
>   #endif /* __KVM_ARM_PSCI_H__ */
> 

Thanks,
Gavin


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 3/9] KVM: arm64: Add standard hypervisor firmware register
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-26  6:37     ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:37 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce the firmware register to hold the standard hypervisor
> service calls (owner value 5) as a bitmap. The bitmap represents
> the features that'll be enabled for the guest, as configured by
> the user-space. Currently, this includes support only for
> Paravirtualized time, represented by bit-0.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h |  2 ++
>   arch/arm64/include/uapi/asm/kvm.h |  3 +++
>   arch/arm64/kvm/hypercalls.c       | 21 ++++++++++++++++++---
>   include/kvm/arm_hypercalls.h      |  2 ++
>   4 files changed, 25 insertions(+), 3 deletions(-)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index df07f4c10197..27d4b2a7970e 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -105,9 +105,11 @@ struct kvm_arch_memory_slot {
>    * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
>    *
>    * @std_bmap: Bitmap of standard secure service calls
> + * @std_hyp_bmap: Bitmap of standard hypervisor service calls
>    */
>   struct kvm_smccc_features {
>   	unsigned long std_bmap;
> +	unsigned long std_hyp_bmap;
>   };
>   
>   struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 0b79d2dc6ffd..9eecc7ee8c14 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -341,6 +341,9 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
>   #define KVM_REG_ARM_STD_BIT_TRNG_V1_0		0
>   
> +#define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
> +#define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index df55a04d2fe8..f097bebdad39 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,8 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	 */
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> -	case ARM_SMCCC_HV_PV_TIME_ST:
>   	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
>   	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
>   	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> @@ -95,6 +93,10 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	case ARM_SMCCC_TRNG_RND64:
>   		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
>   						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +	case ARM_SMCCC_HV_PV_TIME_ST:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> +					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
>   	default:
>   		return kvm_hvc_call_default_allowed(vcpu, func_id);
>   	}
> @@ -102,6 +104,7 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   {
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>   	u32 func_id = smccc_get_function(vcpu);
>   	u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
>   	u32 feature;
> @@ -165,7 +168,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   			}
>   			break;
>   		case ARM_SMCCC_HV_PV_TIME_FEATURES:
> -			val[0] = SMCCC_RET_SUCCESS;
> +			if (kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> +					KVM_REG_ARM_STD_HYP_BIT_PV_TIME))
> +				val[0] = SMCCC_RET_SUCCESS;
>   			break;
>   		}
>   		break;
> @@ -211,6 +216,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>   	KVM_REG_ARM_STD_BMAP,
> +	KVM_REG_ARM_STD_HYP_BMAP,
>   };
>   
>   void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -218,6 +224,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>   	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>   
>   	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>   }
>   
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -307,6 +314,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_STD_BMAP:
>   		val = READ_ONCE(smccc_feat->std_bmap);
>   		break;
> +	case KVM_REG_ARM_STD_HYP_BMAP:
> +		val = READ_ONCE(smccc_feat->std_hyp_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -329,6 +339,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>   		fw_reg_bmap = &smccc_feat->std_bmap;
>   		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
>   		break;
> +	case KVM_REG_ARM_STD_HYP_BMAP:
> +		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -430,6 +444,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   		return 0;
>   	case KVM_REG_ARM_STD_BMAP:
> +	case KVM_REG_ARM_STD_HYP_BMAP:
>   		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 499b45b607b6..aadd6ae3ab72 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -8,8 +8,10 @@
>   
>   /* Last valid bits of the bitmapped firmware registers */
>   #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
>   
>   #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
> 


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

* Re: [PATCH v6 3/9] KVM: arm64: Add standard hypervisor firmware register
@ 2022-04-26  6:37     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:37 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce the firmware register to hold the standard hypervisor
> service calls (owner value 5) as a bitmap. The bitmap represents
> the features that'll be enabled for the guest, as configured by
> the user-space. Currently, this includes support only for
> Paravirtualized time, represented by bit-0.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h |  2 ++
>   arch/arm64/include/uapi/asm/kvm.h |  3 +++
>   arch/arm64/kvm/hypercalls.c       | 21 ++++++++++++++++++---
>   include/kvm/arm_hypercalls.h      |  2 ++
>   4 files changed, 25 insertions(+), 3 deletions(-)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index df07f4c10197..27d4b2a7970e 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -105,9 +105,11 @@ struct kvm_arch_memory_slot {
>    * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
>    *
>    * @std_bmap: Bitmap of standard secure service calls
> + * @std_hyp_bmap: Bitmap of standard hypervisor service calls
>    */
>   struct kvm_smccc_features {
>   	unsigned long std_bmap;
> +	unsigned long std_hyp_bmap;
>   };
>   
>   struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 0b79d2dc6ffd..9eecc7ee8c14 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -341,6 +341,9 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
>   #define KVM_REG_ARM_STD_BIT_TRNG_V1_0		0
>   
> +#define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
> +#define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index df55a04d2fe8..f097bebdad39 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,8 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	 */
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> -	case ARM_SMCCC_HV_PV_TIME_ST:
>   	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
>   	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
>   	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> @@ -95,6 +93,10 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	case ARM_SMCCC_TRNG_RND64:
>   		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
>   						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +	case ARM_SMCCC_HV_PV_TIME_ST:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> +					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
>   	default:
>   		return kvm_hvc_call_default_allowed(vcpu, func_id);
>   	}
> @@ -102,6 +104,7 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   {
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>   	u32 func_id = smccc_get_function(vcpu);
>   	u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
>   	u32 feature;
> @@ -165,7 +168,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   			}
>   			break;
>   		case ARM_SMCCC_HV_PV_TIME_FEATURES:
> -			val[0] = SMCCC_RET_SUCCESS;
> +			if (kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> +					KVM_REG_ARM_STD_HYP_BIT_PV_TIME))
> +				val[0] = SMCCC_RET_SUCCESS;
>   			break;
>   		}
>   		break;
> @@ -211,6 +216,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>   	KVM_REG_ARM_STD_BMAP,
> +	KVM_REG_ARM_STD_HYP_BMAP,
>   };
>   
>   void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -218,6 +224,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>   	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>   
>   	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>   }
>   
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -307,6 +314,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_STD_BMAP:
>   		val = READ_ONCE(smccc_feat->std_bmap);
>   		break;
> +	case KVM_REG_ARM_STD_HYP_BMAP:
> +		val = READ_ONCE(smccc_feat->std_hyp_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -329,6 +339,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>   		fw_reg_bmap = &smccc_feat->std_bmap;
>   		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
>   		break;
> +	case KVM_REG_ARM_STD_HYP_BMAP:
> +		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -430,6 +444,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   		return 0;
>   	case KVM_REG_ARM_STD_BMAP:
> +	case KVM_REG_ARM_STD_HYP_BMAP:
>   		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 499b45b607b6..aadd6ae3ab72 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -8,8 +8,10 @@
>   
>   /* Last valid bits of the bitmapped firmware registers */
>   #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
>   
>   #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
> 

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 3/9] KVM: arm64: Add standard hypervisor firmware register
@ 2022-04-26  6:37     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:37 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce the firmware register to hold the standard hypervisor
> service calls (owner value 5) as a bitmap. The bitmap represents
> the features that'll be enabled for the guest, as configured by
> the user-space. Currently, this includes support only for
> Paravirtualized time, represented by bit-0.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h |  2 ++
>   arch/arm64/include/uapi/asm/kvm.h |  3 +++
>   arch/arm64/kvm/hypercalls.c       | 21 ++++++++++++++++++---
>   include/kvm/arm_hypercalls.h      |  2 ++
>   4 files changed, 25 insertions(+), 3 deletions(-)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index df07f4c10197..27d4b2a7970e 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -105,9 +105,11 @@ struct kvm_arch_memory_slot {
>    * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
>    *
>    * @std_bmap: Bitmap of standard secure service calls
> + * @std_hyp_bmap: Bitmap of standard hypervisor service calls
>    */
>   struct kvm_smccc_features {
>   	unsigned long std_bmap;
> +	unsigned long std_hyp_bmap;
>   };
>   
>   struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 0b79d2dc6ffd..9eecc7ee8c14 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -341,6 +341,9 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_REG_ARM_STD_BMAP			KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
>   #define KVM_REG_ARM_STD_BIT_TRNG_V1_0		0
>   
> +#define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
> +#define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index df55a04d2fe8..f097bebdad39 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,8 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	 */
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> -	case ARM_SMCCC_HV_PV_TIME_ST:
>   	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
>   	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
>   	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> @@ -95,6 +93,10 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	case ARM_SMCCC_TRNG_RND64:
>   		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
>   						KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> +	case ARM_SMCCC_HV_PV_TIME_FEATURES:
> +	case ARM_SMCCC_HV_PV_TIME_ST:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> +					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
>   	default:
>   		return kvm_hvc_call_default_allowed(vcpu, func_id);
>   	}
> @@ -102,6 +104,7 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   {
> +	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>   	u32 func_id = smccc_get_function(vcpu);
>   	u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
>   	u32 feature;
> @@ -165,7 +168,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   			}
>   			break;
>   		case ARM_SMCCC_HV_PV_TIME_FEATURES:
> -			val[0] = SMCCC_RET_SUCCESS;
> +			if (kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
> +					KVM_REG_ARM_STD_HYP_BIT_PV_TIME))
> +				val[0] = SMCCC_RET_SUCCESS;
>   			break;
>   		}
>   		break;
> @@ -211,6 +216,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>   	KVM_REG_ARM_STD_BMAP,
> +	KVM_REG_ARM_STD_HYP_BMAP,
>   };
>   
>   void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -218,6 +224,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>   	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>   
>   	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> +	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>   }
>   
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -307,6 +314,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_STD_BMAP:
>   		val = READ_ONCE(smccc_feat->std_bmap);
>   		break;
> +	case KVM_REG_ARM_STD_HYP_BMAP:
> +		val = READ_ONCE(smccc_feat->std_hyp_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -329,6 +339,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>   		fw_reg_bmap = &smccc_feat->std_bmap;
>   		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
>   		break;
> +	case KVM_REG_ARM_STD_HYP_BMAP:
> +		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -430,6 +444,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   
>   		return 0;
>   	case KVM_REG_ARM_STD_BMAP:
> +	case KVM_REG_ARM_STD_HYP_BMAP:
>   		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 499b45b607b6..aadd6ae3ab72 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -8,8 +8,10 @@
>   
>   /* Last valid bits of the bitmapped firmware registers */
>   #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
>   
>   #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
> 


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-26  6:40     ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:40 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce the firmware register to hold the vendor specific
> hypervisor service calls (owner value 6) as a bitmap. The
> bitmap represents the features that'll be enabled for the
> guest, as configured by the user-space. Currently, this
> includes support for KVM-vendor features along with
> reading the UID, represented by bit-0, and Precision Time
> Protocol (PTP), represented by bit-1.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h |  2 ++
>   arch/arm64/include/uapi/asm/kvm.h |  4 ++++
>   arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
>   include/kvm/arm_hypercalls.h      |  2 ++
>   4 files changed, 26 insertions(+), 5 deletions(-)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 27d4b2a7970e..a025c2ba012a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
>    *
>    * @std_bmap: Bitmap of standard secure service calls
>    * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
>    */
>   struct kvm_smccc_features {
>   	unsigned long std_bmap;
>   	unsigned long std_hyp_bmap;
> +	unsigned long vendor_hyp_bmap;
>   };
>   
>   struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 9eecc7ee8c14..e7d5ae222684 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
>   #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		0
>   
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT	0
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP		1
> +
>   /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index f097bebdad39..76e626d0e699 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	 */
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>   		return true;
>   	default:
>   		return kvm_psci_func_id_is_valid(vcpu, func_id);
> @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	case ARM_SMCCC_HV_PV_TIME_ST:
>   		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
>   					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> +	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +					KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> +	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +					KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
>   	default:
>   		return kvm_hvc_call_default_allowed(vcpu, func_id);
>   	}
> @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   		val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
>   		break;
>   	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -		val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> -		val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> +		val[0] = smccc_feat->vendor_hyp_bmap;
>   		break;
>   	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>   		kvm_ptp_get_time(vcpu, val);
> @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>   	KVM_REG_ARM_STD_BMAP,
>   	KVM_REG_ARM_STD_HYP_BMAP,
> +	KVM_REG_ARM_VENDOR_HYP_BMAP,
>   };
>   
>   void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>   
>   	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>   	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +	smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
>   }
>   
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_STD_HYP_BMAP:
>   		val = READ_ONCE(smccc_feat->std_hyp_bmap);
>   		break;
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +		val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>   		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
>   		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>   		break;
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +		fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   		return 0;
>   	case KVM_REG_ARM_STD_BMAP:
>   	case KVM_REG_ARM_STD_HYP_BMAP:
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
>   		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index aadd6ae3ab72..4ebfdd26e486 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -9,9 +9,11 @@
>   /* Last valid bits of the bitmapped firmware registers */
>   #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
>   #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
>   
>   #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>   #define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES	GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
> 

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-26  6:40     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:40 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce the firmware register to hold the vendor specific
> hypervisor service calls (owner value 6) as a bitmap. The
> bitmap represents the features that'll be enabled for the
> guest, as configured by the user-space. Currently, this
> includes support for KVM-vendor features along with
> reading the UID, represented by bit-0, and Precision Time
> Protocol (PTP), represented by bit-1.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h |  2 ++
>   arch/arm64/include/uapi/asm/kvm.h |  4 ++++
>   arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
>   include/kvm/arm_hypercalls.h      |  2 ++
>   4 files changed, 26 insertions(+), 5 deletions(-)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 27d4b2a7970e..a025c2ba012a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
>    *
>    * @std_bmap: Bitmap of standard secure service calls
>    * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
>    */
>   struct kvm_smccc_features {
>   	unsigned long std_bmap;
>   	unsigned long std_hyp_bmap;
> +	unsigned long vendor_hyp_bmap;
>   };
>   
>   struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 9eecc7ee8c14..e7d5ae222684 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
>   #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		0
>   
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT	0
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP		1
> +
>   /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index f097bebdad39..76e626d0e699 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	 */
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>   		return true;
>   	default:
>   		return kvm_psci_func_id_is_valid(vcpu, func_id);
> @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	case ARM_SMCCC_HV_PV_TIME_ST:
>   		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
>   					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> +	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +					KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> +	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +					KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
>   	default:
>   		return kvm_hvc_call_default_allowed(vcpu, func_id);
>   	}
> @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   		val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
>   		break;
>   	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -		val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> -		val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> +		val[0] = smccc_feat->vendor_hyp_bmap;
>   		break;
>   	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>   		kvm_ptp_get_time(vcpu, val);
> @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>   	KVM_REG_ARM_STD_BMAP,
>   	KVM_REG_ARM_STD_HYP_BMAP,
> +	KVM_REG_ARM_VENDOR_HYP_BMAP,
>   };
>   
>   void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>   
>   	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>   	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +	smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
>   }
>   
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_STD_HYP_BMAP:
>   		val = READ_ONCE(smccc_feat->std_hyp_bmap);
>   		break;
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +		val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>   		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
>   		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>   		break;
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +		fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   		return 0;
>   	case KVM_REG_ARM_STD_BMAP:
>   	case KVM_REG_ARM_STD_HYP_BMAP:
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
>   		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index aadd6ae3ab72..4ebfdd26e486 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -9,9 +9,11 @@
>   /* Last valid bits of the bitmapped firmware registers */
>   #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
>   #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
>   
>   #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>   #define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES	GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
> 


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

* Re: [PATCH v6 4/9] KVM: arm64: Add vendor hypervisor firmware register
@ 2022-04-26  6:40     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:40 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce the firmware register to hold the vendor specific
> hypervisor service calls (owner value 6) as a bitmap. The
> bitmap represents the features that'll be enabled for the
> guest, as configured by the user-space. Currently, this
> includes support for KVM-vendor features along with
> reading the UID, represented by bit-0, and Precision Time
> Protocol (PTP), represented by bit-1.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   arch/arm64/include/asm/kvm_host.h |  2 ++
>   arch/arm64/include/uapi/asm/kvm.h |  4 ++++
>   arch/arm64/kvm/hypercalls.c       | 23 ++++++++++++++++++-----
>   include/kvm/arm_hypercalls.h      |  2 ++
>   4 files changed, 26 insertions(+), 5 deletions(-)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 27d4b2a7970e..a025c2ba012a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -106,10 +106,12 @@ struct kvm_arch_memory_slot {
>    *
>    * @std_bmap: Bitmap of standard secure service calls
>    * @std_hyp_bmap: Bitmap of standard hypervisor service calls
> + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls
>    */
>   struct kvm_smccc_features {
>   	unsigned long std_bmap;
>   	unsigned long std_hyp_bmap;
> +	unsigned long vendor_hyp_bmap;
>   };
>   
>   struct kvm_arch {
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 9eecc7ee8c14..e7d5ae222684 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -344,6 +344,10 @@ struct kvm_arm_copy_mte_tags {
>   #define KVM_REG_ARM_STD_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
>   #define KVM_REG_ARM_STD_HYP_BIT_PV_TIME		0
>   
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP		KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT	0
> +#define KVM_REG_ARM_VENDOR_HYP_BIT_PTP		1
> +
>   /* 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/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index f097bebdad39..76e626d0e699 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -72,9 +72,6 @@ static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	 */
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>   		return true;
>   	default:
>   		return kvm_psci_func_id_is_valid(vcpu, func_id);
> @@ -97,6 +94,13 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>   	case ARM_SMCCC_HV_PV_TIME_ST:
>   		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_hyp_bmap,
>   					KVM_REG_ARM_STD_HYP_BIT_PV_TIME);
> +	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> +	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +					KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT);
> +	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> +		return kvm_arm_fw_reg_feat_enabled(&smccc_feat->vendor_hyp_bmap,
> +					KVM_REG_ARM_VENDOR_HYP_BIT_PTP);
>   	default:
>   		return kvm_hvc_call_default_allowed(vcpu, func_id);
>   	}
> @@ -189,8 +193,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>   		val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
>   		break;
>   	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> -		val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> -		val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
> +		val[0] = smccc_feat->vendor_hyp_bmap;
>   		break;
>   	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>   		kvm_ptp_get_time(vcpu, val);
> @@ -217,6 +220,7 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>   	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>   	KVM_REG_ARM_STD_BMAP,
>   	KVM_REG_ARM_STD_HYP_BMAP,
> +	KVM_REG_ARM_VENDOR_HYP_BMAP,
>   };
>   
>   void kvm_arm_init_hypercalls(struct kvm *kvm)
> @@ -225,6 +229,7 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
>   
>   	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>   	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
> +	smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
>   }
>   
>   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> @@ -317,6 +322,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   	case KVM_REG_ARM_STD_HYP_BMAP:
>   		val = READ_ONCE(smccc_feat->std_hyp_bmap);
>   		break;
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +		val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -343,6 +351,10 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>   		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
>   		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
>   		break;
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
> +		fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
> +		fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
> +		break;
>   	default:
>   		return -ENOENT;
>   	}
> @@ -445,6 +457,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>   		return 0;
>   	case KVM_REG_ARM_STD_BMAP:
>   	case KVM_REG_ARM_STD_HYP_BMAP:
> +	case KVM_REG_ARM_VENDOR_HYP_BMAP:
>   		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>   	default:
>   		return -ENOENT;
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index aadd6ae3ab72..4ebfdd26e486 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -9,9 +9,11 @@
>   /* Last valid bits of the bitmapped firmware registers */
>   #define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
>   #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
>   
>   #define KVM_ARM_SMCCC_STD_FEATURES		GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>   #define KVM_ARM_SMCCC_STD_HYP_FEATURES		GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX, 0)
> +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES	GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX, 0)
>   
>   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>   
> 


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 5/9] Docs: KVM: Rename psci.rst to hypercalls.rst
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-26  6:41     ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:41 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Since the doc also covers general hypercalls' details,
> rather than just PSCI, and the fact that the bitmap firmware
> registers' details will be added to this doc, rename the file
> to a more appropriate name- hypercalls.rst.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> Reviewed-by: Oliver Upton <oupton@google.com>
> ---
>   Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} | 0
>   1 file changed, 0 insertions(+), 0 deletions(-)
>   rename Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} (100%)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/Documentation/virt/kvm/arm/psci.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> similarity index 100%
> rename from Documentation/virt/kvm/arm/psci.rst
> rename to Documentation/virt/kvm/arm/hypercalls.rst
> 


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

* Re: [PATCH v6 5/9] Docs: KVM: Rename psci.rst to hypercalls.rst
@ 2022-04-26  6:41     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:41 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Since the doc also covers general hypercalls' details,
> rather than just PSCI, and the fact that the bitmap firmware
> registers' details will be added to this doc, rename the file
> to a more appropriate name- hypercalls.rst.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> Reviewed-by: Oliver Upton <oupton@google.com>
> ---
>   Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} | 0
>   1 file changed, 0 insertions(+), 0 deletions(-)
>   rename Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} (100%)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/Documentation/virt/kvm/arm/psci.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> similarity index 100%
> rename from Documentation/virt/kvm/arm/psci.rst
> rename to Documentation/virt/kvm/arm/hypercalls.rst
> 

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 5/9] Docs: KVM: Rename psci.rst to hypercalls.rst
@ 2022-04-26  6:41     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:41 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Since the doc also covers general hypercalls' details,
> rather than just PSCI, and the fact that the bitmap firmware
> registers' details will be added to this doc, rename the file
> to a more appropriate name- hypercalls.rst.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> Reviewed-by: Oliver Upton <oupton@google.com>
> ---
>   Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} | 0
>   1 file changed, 0 insertions(+), 0 deletions(-)
>   rename Documentation/virt/kvm/arm/{psci.rst => hypercalls.rst} (100%)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/Documentation/virt/kvm/arm/psci.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> similarity index 100%
> rename from Documentation/virt/kvm/arm/psci.rst
> rename to Documentation/virt/kvm/arm/hypercalls.rst
> 


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-26  6:42     ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:42 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Add the documentation for the bitmap firmware registers in
> hypercalls.rst and api.rst. This includes the details for
> KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> KVM_REG_ARM_VENDOR_HYP_BMAP registers.
> 
> Since the document is growing to carry other hypercall related
> information, make necessary adjustments to present the document
> in a generic sense, rather than being PSCI focused.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   Documentation/virt/kvm/api.rst            | 16 ++++
>   Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
>   2 files changed, 92 insertions(+), 18 deletions(-)
> 

With Reiji's comment fixed:

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index 85c7abc51af5..ac489191d0a9 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
>   
>     0x6030 0000 0014 <regno:16>
>   
> +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> +
> +  0x6030 0000 0016 <regno:16>
> +
> +The bitmap feature firmware registers exposes the hypercall services that are
> +available for userspace to configure. The set bits corresponds to the services
> +that are available for the guests to access. By default, KVM sets all the
> +supported bits during VM initialization. The userspace can discover the
> +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> +
> +Note: These registers are immutable once any of the vCPUs of the VM has run at
> +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> +
> +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> +
>   arm64 SVE registers have the following bit patterns::
>   
>     0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> index d52c2e83b5b8..6327c504b2fb 100644
> --- a/Documentation/virt/kvm/arm/hypercalls.rst
> +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> @@ -1,32 +1,32 @@
>   .. SPDX-License-Identifier: GPL-2.0
>   
> -=========================================
> -Power State Coordination Interface (PSCI)
> -=========================================
> +=======================
> +ARM Hypercall Interface
> +=======================
>   
> -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.
> +KVM handles the hypercall services as requested by the guests. New hypercall
> +services are regularly made available by the ARM specification or by KVM (as
> +vendor services) if they make sense from a virtualization point of view.
>   
> -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.
> +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 version of a hypercall service, or if a migration
> +causes a different version to be exposed out of the blue to an unsuspecting
> +guest.
>   
>   In order to remedy this situation, KVM exposes a set of "firmware
>   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.
> +to a convenient value as required.
>   
> -The following register is defined:
> +The following registers are defined:
>   
>   * KVM_REG_ARM_PSCI_VERSION:
>   
> +  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.
> +
>     - 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
> @@ -74,4 +74,62 @@ The following register is defined:
>       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
>         The workaround is always active on this vCPU or it is not needed.
>   
> -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> +
> +Bitmap Feature Firmware Registers
> +---------------------------------
> +
> +Contrary to the above registers, the following registers exposes the hypercall
> +services in the form of a feature-bitmap to the userspace. This bitmap is
> +translated to the services that are available to the guest. There is a register
> +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> +
> +By default, these registers are set with the upper limit of the features that
> +are supported. This way userspace can discover all the electable hypercall services
> +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> +SET_ONE_REG. The features for the registers that are untouched, probably because
> +userspace isn't aware of them, will be exposed as is to the guest.
> +
> +Note that KVM would't allow the userspace to configure the registers anymore once
> +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> +
> +The psuedo-firmware bitmap register are as follows:
> +
> +* KVM_REG_ARM_STD_BMAP:
> +    Controls the bitmap of the ARM Standard Secure Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> +      The bit represents the services offered under v1.0 of ARM True Random
> +      Number Generator (TRNG) specification, ARM DEN0098.
> +
> +* KVM_REG_ARM_STD_HYP_BMAP:
> +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> +      The bit represents the Paravirtualized Time service as represented by
> +      ARM DEN0057A.
> +
> +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> +      function-id
> +
> +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> +      The bit represents the Precision Time Protocol KVM service.
> +
> +Errors:
> +
> +    =======  =============================================================
> +    -ENOENT   Unknown register accessed.
> +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> +    -EINVAL   Invalid bitmap written to the register.
> +    =======  =============================================================
> +
> +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> \ No newline at end of file
> 


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

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
@ 2022-04-26  6:42     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:42 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Add the documentation for the bitmap firmware registers in
> hypercalls.rst and api.rst. This includes the details for
> KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> KVM_REG_ARM_VENDOR_HYP_BMAP registers.
> 
> Since the document is growing to carry other hypercall related
> information, make necessary adjustments to present the document
> in a generic sense, rather than being PSCI focused.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   Documentation/virt/kvm/api.rst            | 16 ++++
>   Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
>   2 files changed, 92 insertions(+), 18 deletions(-)
> 

With Reiji's comment fixed:

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index 85c7abc51af5..ac489191d0a9 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
>   
>     0x6030 0000 0014 <regno:16>
>   
> +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> +
> +  0x6030 0000 0016 <regno:16>
> +
> +The bitmap feature firmware registers exposes the hypercall services that are
> +available for userspace to configure. The set bits corresponds to the services
> +that are available for the guests to access. By default, KVM sets all the
> +supported bits during VM initialization. The userspace can discover the
> +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> +
> +Note: These registers are immutable once any of the vCPUs of the VM has run at
> +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> +
> +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> +
>   arm64 SVE registers have the following bit patterns::
>   
>     0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> index d52c2e83b5b8..6327c504b2fb 100644
> --- a/Documentation/virt/kvm/arm/hypercalls.rst
> +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> @@ -1,32 +1,32 @@
>   .. SPDX-License-Identifier: GPL-2.0
>   
> -=========================================
> -Power State Coordination Interface (PSCI)
> -=========================================
> +=======================
> +ARM Hypercall Interface
> +=======================
>   
> -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.
> +KVM handles the hypercall services as requested by the guests. New hypercall
> +services are regularly made available by the ARM specification or by KVM (as
> +vendor services) if they make sense from a virtualization point of view.
>   
> -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.
> +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 version of a hypercall service, or if a migration
> +causes a different version to be exposed out of the blue to an unsuspecting
> +guest.
>   
>   In order to remedy this situation, KVM exposes a set of "firmware
>   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.
> +to a convenient value as required.
>   
> -The following register is defined:
> +The following registers are defined:
>   
>   * KVM_REG_ARM_PSCI_VERSION:
>   
> +  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.
> +
>     - 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
> @@ -74,4 +74,62 @@ The following register is defined:
>       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
>         The workaround is always active on this vCPU or it is not needed.
>   
> -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> +
> +Bitmap Feature Firmware Registers
> +---------------------------------
> +
> +Contrary to the above registers, the following registers exposes the hypercall
> +services in the form of a feature-bitmap to the userspace. This bitmap is
> +translated to the services that are available to the guest. There is a register
> +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> +
> +By default, these registers are set with the upper limit of the features that
> +are supported. This way userspace can discover all the electable hypercall services
> +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> +SET_ONE_REG. The features for the registers that are untouched, probably because
> +userspace isn't aware of them, will be exposed as is to the guest.
> +
> +Note that KVM would't allow the userspace to configure the registers anymore once
> +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> +
> +The psuedo-firmware bitmap register are as follows:
> +
> +* KVM_REG_ARM_STD_BMAP:
> +    Controls the bitmap of the ARM Standard Secure Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> +      The bit represents the services offered under v1.0 of ARM True Random
> +      Number Generator (TRNG) specification, ARM DEN0098.
> +
> +* KVM_REG_ARM_STD_HYP_BMAP:
> +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> +      The bit represents the Paravirtualized Time service as represented by
> +      ARM DEN0057A.
> +
> +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> +      function-id
> +
> +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> +      The bit represents the Precision Time Protocol KVM service.
> +
> +Errors:
> +
> +    =======  =============================================================
> +    -ENOENT   Unknown register accessed.
> +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> +    -EINVAL   Invalid bitmap written to the register.
> +    =======  =============================================================
> +
> +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> \ No newline at end of file
> 

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers
@ 2022-04-26  6:42     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  6:42 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Add the documentation for the bitmap firmware registers in
> hypercalls.rst and api.rst. This includes the details for
> KVM_REG_ARM_STD_BMAP, KVM_REG_ARM_STD_HYP_BMAP, and
> KVM_REG_ARM_VENDOR_HYP_BMAP registers.
> 
> Since the document is growing to carry other hypercall related
> information, make necessary adjustments to present the document
> in a generic sense, rather than being PSCI focused.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   Documentation/virt/kvm/api.rst            | 16 ++++
>   Documentation/virt/kvm/arm/hypercalls.rst | 94 ++++++++++++++++++-----
>   2 files changed, 92 insertions(+), 18 deletions(-)
> 

With Reiji's comment fixed:

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index 85c7abc51af5..ac489191d0a9 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -2542,6 +2542,22 @@ arm64 firmware pseudo-registers have the following bit pattern::
>   
>     0x6030 0000 0014 <regno:16>
>   
> +arm64 bitmap feature firmware pseudo-registers have the following bit pattern::
> +
> +  0x6030 0000 0016 <regno:16>
> +
> +The bitmap feature firmware registers exposes the hypercall services that are
> +available for userspace to configure. The set bits corresponds to the services
> +that are available for the guests to access. By default, KVM sets all the
> +supported bits during VM initialization. The userspace can discover the
> +available services via KVM_GET_ONE_REG, and write back the bitmap corresponding
> +to the features that it wishes guests to see via KVM_SET_ONE_REG.
> +
> +Note: These registers are immutable once any of the vCPUs of the VM has run at
> +least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.
> +
> +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.)
> +
>   arm64 SVE registers have the following bit patterns::
>   
>     0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
> index d52c2e83b5b8..6327c504b2fb 100644
> --- a/Documentation/virt/kvm/arm/hypercalls.rst
> +++ b/Documentation/virt/kvm/arm/hypercalls.rst
> @@ -1,32 +1,32 @@
>   .. SPDX-License-Identifier: GPL-2.0
>   
> -=========================================
> -Power State Coordination Interface (PSCI)
> -=========================================
> +=======================
> +ARM Hypercall Interface
> +=======================
>   
> -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.
> +KVM handles the hypercall services as requested by the guests. New hypercall
> +services are regularly made available by the ARM specification or by KVM (as
> +vendor services) if they make sense from a virtualization point of view.
>   
> -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.
> +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 version of a hypercall service, or if a migration
> +causes a different version to be exposed out of the blue to an unsuspecting
> +guest.
>   
>   In order to remedy this situation, KVM exposes a set of "firmware
>   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.
> +to a convenient value as required.
>   
> -The following register is defined:
> +The following registers are defined:
>   
>   * KVM_REG_ARM_PSCI_VERSION:
>   
> +  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.
> +
>     - 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
> @@ -74,4 +74,62 @@ The following register is defined:
>       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
>         The workaround is always active on this vCPU or it is not needed.
>   
> -.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> +
> +Bitmap Feature Firmware Registers
> +---------------------------------
> +
> +Contrary to the above registers, the following registers exposes the hypercall
> +services in the form of a feature-bitmap to the userspace. This bitmap is
> +translated to the services that are available to the guest. There is a register
> +defined per service call owner and can be accessed via GET/SET_ONE_REG interface.
> +
> +By default, these registers are set with the upper limit of the features that
> +are supported. This way userspace can discover all the electable hypercall services
> +via GET_ONE_REG. The user-space can write-back the desired bitmap back via
> +SET_ONE_REG. The features for the registers that are untouched, probably because
> +userspace isn't aware of them, will be exposed as is to the guest.
> +
> +Note that KVM would't allow the userspace to configure the registers anymore once
> +any of the vCPUs has run at least once. Instead, it will return a -EBUSY.
> +
> +The psuedo-firmware bitmap register are as follows:
> +
> +* KVM_REG_ARM_STD_BMAP:
> +    Controls the bitmap of the ARM Standard Secure Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0:
> +      The bit represents the services offered under v1.0 of ARM True Random
> +      Number Generator (TRNG) specification, ARM DEN0098.
> +
> +* KVM_REG_ARM_STD_HYP_BMAP:
> +    Controls the bitmap of the ARM Standard Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME:
> +      The bit represents the Paravirtualized Time service as represented by
> +      ARM DEN0057A.
> +
> +* KVM_REG_ARM_VENDOR_HYP_BMAP:
> +    Controls the bitmap of the Vendor specific Hypervisor Service Calls.
> +
> +  The following bits are accepted:
> +
> +    Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT
> +      The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID
> +      function-id
> +
> +    Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
> +      The bit represents the Precision Time Protocol KVM service.
> +
> +Errors:
> +
> +    =======  =============================================================
> +    -ENOENT   Unknown register accessed.
> +    -EBUSY    Attempt a 'write' to the register after the VM has started.
> +    -EINVAL   Invalid bitmap written to the register.
> +    =======  =============================================================
> +
> +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf
> \ No newline at end of file
> 


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 7/9] tools: Import ARM SMCCC definitions
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-26  7:24     ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  7:24 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Import the standard SMCCC definitions from include/linux/arm-smccc.h.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   tools/include/linux/arm-smccc.h | 193 ++++++++++++++++++++++++++++++++
>   1 file changed, 193 insertions(+)
>   create mode 100644 tools/include/linux/arm-smccc.h
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h
> new file mode 100644
> index 000000000000..63ce9bebccd3
> --- /dev/null
> +++ b/tools/include/linux/arm-smccc.h
> @@ -0,0 +1,193 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2015, Linaro Limited
> + */
> +#ifndef __LINUX_ARM_SMCCC_H
> +#define __LINUX_ARM_SMCCC_H
> +
> +#include <linux/const.h>
> +
> +/*
> + * This file provides common defines for ARM SMC Calling Convention as
> + * specified in
> + * https://developer.arm.com/docs/den0028/latest
> + *
> + * This code is up-to-date with version DEN 0028 C
> + */
> +
> +#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
> +#define ARM_SMCCC_SMC_64		1
> +#define ARM_SMCCC_CALL_CONV_SHIFT	30
> +
> +#define ARM_SMCCC_OWNER_MASK		0x3F
> +#define ARM_SMCCC_OWNER_SHIFT		24
> +
> +#define ARM_SMCCC_FUNC_MASK		0xFFFF
> +
> +#define ARM_SMCCC_IS_FAST_CALL(smc_val)	\
> +	((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
> +#define ARM_SMCCC_IS_64(smc_val) \
> +	((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
> +#define ARM_SMCCC_FUNC_NUM(smc_val)	((smc_val) & ARM_SMCCC_FUNC_MASK)
> +#define ARM_SMCCC_OWNER_NUM(smc_val) \
> +	(((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
> +
> +#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
> +	(((type) << ARM_SMCCC_TYPE_SHIFT) | \
> +	((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
> +	(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
> +	((func_num) & ARM_SMCCC_FUNC_MASK))
> +
> +#define ARM_SMCCC_OWNER_ARCH		0
> +#define ARM_SMCCC_OWNER_CPU		1
> +#define ARM_SMCCC_OWNER_SIP		2
> +#define ARM_SMCCC_OWNER_OEM		3
> +#define ARM_SMCCC_OWNER_STANDARD	4
> +#define ARM_SMCCC_OWNER_STANDARD_HYP	5
> +#define ARM_SMCCC_OWNER_VENDOR_HYP	6
> +#define ARM_SMCCC_OWNER_TRUSTED_APP	48
> +#define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
> +#define ARM_SMCCC_OWNER_TRUSTED_OS	50
> +#define ARM_SMCCC_OWNER_TRUSTED_OS_END	63
> +
> +#define ARM_SMCCC_FUNC_QUERY_CALL_UID  0xff01
> +
> +#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_1_2		0x10002
> +#define ARM_SMCCC_VERSION_1_3		0x10003
> +
> +#define ARM_SMCCC_1_3_SVE_HINT		0x10000
> +
> +#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)
> +
> +#define ARM_SMCCC_ARCH_SOC_ID						\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 2)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_1					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x8000)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_2					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x7fff)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_3					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x3fff)
> +
> +#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_FUNC_QUERY_CALL_UID)
> +
> +/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0	0xb66fb428U
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1	0xe911c52eU
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2	0x564bcaa9U
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3	0x743a004dU
> +
> +/* KVM "vendor specific" services */
> +#define ARM_SMCCC_KVM_FUNC_FEATURES		0
> +#define ARM_SMCCC_KVM_FUNC_PTP			1
> +#define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
> +#define ARM_SMCCC_KVM_NUM_FUNCS			128
> +
> +#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID			\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_KVM_FUNC_FEATURES)
> +
> +#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED	1
> +
> +/*
> + * ptp_kvm is a feature used for time sync between vm and host.
> + * ptp_kvm module in guest kernel will get service from host using
> + * this hypercall ID.
> + */
> +#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_KVM_FUNC_PTP)
> +
> +/* ptp_kvm counter type ID */
> +#define KVM_PTP_VIRT_COUNTER			0
> +#define KVM_PTP_PHYS_COUNTER			1
> +
> +/* Paravirtualised time calls (defined by ARM DEN0057A) */
> +#define ARM_SMCCC_HV_PV_TIME_FEATURES				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
> +			   0x20)
> +
> +#define ARM_SMCCC_HV_PV_TIME_ST					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
> +			   0x21)
> +
> +/* TRNG entropy source calls (defined by ARM DEN0098) */
> +#define ARM_SMCCC_TRNG_VERSION					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x50)
> +
> +#define ARM_SMCCC_TRNG_FEATURES					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x51)
> +
> +#define ARM_SMCCC_TRNG_GET_UUID					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x52)
> +
> +#define ARM_SMCCC_TRNG_RND32					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x53)
> +
> +#define ARM_SMCCC_TRNG_RND64					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x53)
> +
> +/*
> + * Return codes defined in ARM DEN 0070A
> + * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
> + */
> +#define SMCCC_RET_SUCCESS			0
> +#define SMCCC_RET_NOT_SUPPORTED			-1
> +#define SMCCC_RET_NOT_REQUIRED			-2
> +#define SMCCC_RET_INVALID_PARAMETER		-3
> +
> +#endif /*__LINUX_ARM_SMCCC_H*/
> 


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

* Re: [PATCH v6 7/9] tools: Import ARM SMCCC definitions
@ 2022-04-26  7:24     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  7:24 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Import the standard SMCCC definitions from include/linux/arm-smccc.h.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   tools/include/linux/arm-smccc.h | 193 ++++++++++++++++++++++++++++++++
>   1 file changed, 193 insertions(+)
>   create mode 100644 tools/include/linux/arm-smccc.h
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h
> new file mode 100644
> index 000000000000..63ce9bebccd3
> --- /dev/null
> +++ b/tools/include/linux/arm-smccc.h
> @@ -0,0 +1,193 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2015, Linaro Limited
> + */
> +#ifndef __LINUX_ARM_SMCCC_H
> +#define __LINUX_ARM_SMCCC_H
> +
> +#include <linux/const.h>
> +
> +/*
> + * This file provides common defines for ARM SMC Calling Convention as
> + * specified in
> + * https://developer.arm.com/docs/den0028/latest
> + *
> + * This code is up-to-date with version DEN 0028 C
> + */
> +
> +#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
> +#define ARM_SMCCC_SMC_64		1
> +#define ARM_SMCCC_CALL_CONV_SHIFT	30
> +
> +#define ARM_SMCCC_OWNER_MASK		0x3F
> +#define ARM_SMCCC_OWNER_SHIFT		24
> +
> +#define ARM_SMCCC_FUNC_MASK		0xFFFF
> +
> +#define ARM_SMCCC_IS_FAST_CALL(smc_val)	\
> +	((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
> +#define ARM_SMCCC_IS_64(smc_val) \
> +	((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
> +#define ARM_SMCCC_FUNC_NUM(smc_val)	((smc_val) & ARM_SMCCC_FUNC_MASK)
> +#define ARM_SMCCC_OWNER_NUM(smc_val) \
> +	(((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
> +
> +#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
> +	(((type) << ARM_SMCCC_TYPE_SHIFT) | \
> +	((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
> +	(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
> +	((func_num) & ARM_SMCCC_FUNC_MASK))
> +
> +#define ARM_SMCCC_OWNER_ARCH		0
> +#define ARM_SMCCC_OWNER_CPU		1
> +#define ARM_SMCCC_OWNER_SIP		2
> +#define ARM_SMCCC_OWNER_OEM		3
> +#define ARM_SMCCC_OWNER_STANDARD	4
> +#define ARM_SMCCC_OWNER_STANDARD_HYP	5
> +#define ARM_SMCCC_OWNER_VENDOR_HYP	6
> +#define ARM_SMCCC_OWNER_TRUSTED_APP	48
> +#define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
> +#define ARM_SMCCC_OWNER_TRUSTED_OS	50
> +#define ARM_SMCCC_OWNER_TRUSTED_OS_END	63
> +
> +#define ARM_SMCCC_FUNC_QUERY_CALL_UID  0xff01
> +
> +#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_1_2		0x10002
> +#define ARM_SMCCC_VERSION_1_3		0x10003
> +
> +#define ARM_SMCCC_1_3_SVE_HINT		0x10000
> +
> +#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)
> +
> +#define ARM_SMCCC_ARCH_SOC_ID						\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 2)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_1					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x8000)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_2					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x7fff)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_3					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x3fff)
> +
> +#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_FUNC_QUERY_CALL_UID)
> +
> +/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0	0xb66fb428U
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1	0xe911c52eU
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2	0x564bcaa9U
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3	0x743a004dU
> +
> +/* KVM "vendor specific" services */
> +#define ARM_SMCCC_KVM_FUNC_FEATURES		0
> +#define ARM_SMCCC_KVM_FUNC_PTP			1
> +#define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
> +#define ARM_SMCCC_KVM_NUM_FUNCS			128
> +
> +#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID			\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_KVM_FUNC_FEATURES)
> +
> +#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED	1
> +
> +/*
> + * ptp_kvm is a feature used for time sync between vm and host.
> + * ptp_kvm module in guest kernel will get service from host using
> + * this hypercall ID.
> + */
> +#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_KVM_FUNC_PTP)
> +
> +/* ptp_kvm counter type ID */
> +#define KVM_PTP_VIRT_COUNTER			0
> +#define KVM_PTP_PHYS_COUNTER			1
> +
> +/* Paravirtualised time calls (defined by ARM DEN0057A) */
> +#define ARM_SMCCC_HV_PV_TIME_FEATURES				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
> +			   0x20)
> +
> +#define ARM_SMCCC_HV_PV_TIME_ST					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
> +			   0x21)
> +
> +/* TRNG entropy source calls (defined by ARM DEN0098) */
> +#define ARM_SMCCC_TRNG_VERSION					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x50)
> +
> +#define ARM_SMCCC_TRNG_FEATURES					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x51)
> +
> +#define ARM_SMCCC_TRNG_GET_UUID					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x52)
> +
> +#define ARM_SMCCC_TRNG_RND32					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x53)
> +
> +#define ARM_SMCCC_TRNG_RND64					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x53)
> +
> +/*
> + * Return codes defined in ARM DEN 0070A
> + * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
> + */
> +#define SMCCC_RET_SUCCESS			0
> +#define SMCCC_RET_NOT_SUPPORTED			-1
> +#define SMCCC_RET_NOT_REQUIRED			-2
> +#define SMCCC_RET_INVALID_PARAMETER		-3
> +
> +#endif /*__LINUX_ARM_SMCCC_H*/
> 

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 7/9] tools: Import ARM SMCCC definitions
@ 2022-04-26  7:24     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  7:24 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Import the standard SMCCC definitions from include/linux/arm-smccc.h.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   tools/include/linux/arm-smccc.h | 193 ++++++++++++++++++++++++++++++++
>   1 file changed, 193 insertions(+)
>   create mode 100644 tools/include/linux/arm-smccc.h
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h
> new file mode 100644
> index 000000000000..63ce9bebccd3
> --- /dev/null
> +++ b/tools/include/linux/arm-smccc.h
> @@ -0,0 +1,193 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2015, Linaro Limited
> + */
> +#ifndef __LINUX_ARM_SMCCC_H
> +#define __LINUX_ARM_SMCCC_H
> +
> +#include <linux/const.h>
> +
> +/*
> + * This file provides common defines for ARM SMC Calling Convention as
> + * specified in
> + * https://developer.arm.com/docs/den0028/latest
> + *
> + * This code is up-to-date with version DEN 0028 C
> + */
> +
> +#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
> +#define ARM_SMCCC_SMC_64		1
> +#define ARM_SMCCC_CALL_CONV_SHIFT	30
> +
> +#define ARM_SMCCC_OWNER_MASK		0x3F
> +#define ARM_SMCCC_OWNER_SHIFT		24
> +
> +#define ARM_SMCCC_FUNC_MASK		0xFFFF
> +
> +#define ARM_SMCCC_IS_FAST_CALL(smc_val)	\
> +	((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
> +#define ARM_SMCCC_IS_64(smc_val) \
> +	((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
> +#define ARM_SMCCC_FUNC_NUM(smc_val)	((smc_val) & ARM_SMCCC_FUNC_MASK)
> +#define ARM_SMCCC_OWNER_NUM(smc_val) \
> +	(((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
> +
> +#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
> +	(((type) << ARM_SMCCC_TYPE_SHIFT) | \
> +	((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
> +	(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
> +	((func_num) & ARM_SMCCC_FUNC_MASK))
> +
> +#define ARM_SMCCC_OWNER_ARCH		0
> +#define ARM_SMCCC_OWNER_CPU		1
> +#define ARM_SMCCC_OWNER_SIP		2
> +#define ARM_SMCCC_OWNER_OEM		3
> +#define ARM_SMCCC_OWNER_STANDARD	4
> +#define ARM_SMCCC_OWNER_STANDARD_HYP	5
> +#define ARM_SMCCC_OWNER_VENDOR_HYP	6
> +#define ARM_SMCCC_OWNER_TRUSTED_APP	48
> +#define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
> +#define ARM_SMCCC_OWNER_TRUSTED_OS	50
> +#define ARM_SMCCC_OWNER_TRUSTED_OS_END	63
> +
> +#define ARM_SMCCC_FUNC_QUERY_CALL_UID  0xff01
> +
> +#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_1_2		0x10002
> +#define ARM_SMCCC_VERSION_1_3		0x10003
> +
> +#define ARM_SMCCC_1_3_SVE_HINT		0x10000
> +
> +#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)
> +
> +#define ARM_SMCCC_ARCH_SOC_ID						\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 2)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_1					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x8000)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_2					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x7fff)
> +
> +#define ARM_SMCCC_ARCH_WORKAROUND_3					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   0, 0x3fff)
> +
> +#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_FUNC_QUERY_CALL_UID)
> +
> +/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0	0xb66fb428U
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1	0xe911c52eU
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2	0x564bcaa9U
> +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3	0x743a004dU
> +
> +/* KVM "vendor specific" services */
> +#define ARM_SMCCC_KVM_FUNC_FEATURES		0
> +#define ARM_SMCCC_KVM_FUNC_PTP			1
> +#define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
> +#define ARM_SMCCC_KVM_NUM_FUNCS			128
> +
> +#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID			\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_KVM_FUNC_FEATURES)
> +
> +#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED	1
> +
> +/*
> + * ptp_kvm is a feature used for time sync between vm and host.
> + * ptp_kvm module in guest kernel will get service from host using
> + * this hypercall ID.
> + */
> +#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
> +			   ARM_SMCCC_SMC_32,				\
> +			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
> +			   ARM_SMCCC_KVM_FUNC_PTP)
> +
> +/* ptp_kvm counter type ID */
> +#define KVM_PTP_VIRT_COUNTER			0
> +#define KVM_PTP_PHYS_COUNTER			1
> +
> +/* Paravirtualised time calls (defined by ARM DEN0057A) */
> +#define ARM_SMCCC_HV_PV_TIME_FEATURES				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
> +			   0x20)
> +
> +#define ARM_SMCCC_HV_PV_TIME_ST					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
> +			   0x21)
> +
> +/* TRNG entropy source calls (defined by ARM DEN0098) */
> +#define ARM_SMCCC_TRNG_VERSION					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x50)
> +
> +#define ARM_SMCCC_TRNG_FEATURES					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x51)
> +
> +#define ARM_SMCCC_TRNG_GET_UUID					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x52)
> +
> +#define ARM_SMCCC_TRNG_RND32					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_32,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x53)
> +
> +#define ARM_SMCCC_TRNG_RND64					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD,		\
> +			   0x53)
> +
> +/*
> + * Return codes defined in ARM DEN 0070A
> + * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
> + */
> +#define SMCCC_RET_SUCCESS			0
> +#define SMCCC_RET_NOT_SUPPORTED			-1
> +#define SMCCC_RET_NOT_REQUIRED			-2
> +#define SMCCC_RET_INVALID_PARAMETER		-3
> +
> +#endif /*__LINUX_ARM_SMCCC_H*/
> 


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
  2022-04-23  0:03   ` Raghavendra Rao Ananta
  (?)
@ 2022-04-26  7:49     ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  7:49 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Hi Raghavendra,

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce a KVM selftest to check the hypercall interface
> for arm64 platforms. The test validates the user-space'
> [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
> registers as well as its effects on the guest upon certain
> configurations.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   tools/testing/selftests/kvm/.gitignore        |   1 +
>   tools/testing/selftests/kvm/Makefile          |   1 +
>   .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
>   3 files changed, 337 insertions(+)
>   create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
> 

There are comments about @false_hvc_info[] and some nits, as below.
Please evaluate and improve if it makes sense to you. Otherwise, it
looks good to me:

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
> index 1bb575dfc42e..b17e464ec661 100644
> --- a/tools/testing/selftests/kvm/.gitignore
> +++ b/tools/testing/selftests/kvm/.gitignore
> @@ -2,6 +2,7 @@
>   /aarch64/arch_timer
>   /aarch64/debug-exceptions
>   /aarch64/get-reg-list
> +/aarch64/hypercalls
>   /aarch64/psci_test
>   /aarch64/vcpu_width_config
>   /aarch64/vgic_init
> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> index c2cf4d318296..97eef0c03d3b 100644
> --- a/tools/testing/selftests/kvm/Makefile
> +++ b/tools/testing/selftests/kvm/Makefile
> @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
>   TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
>   TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
>   TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
> +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
>   TEST_GEN_PROGS_aarch64 += aarch64/psci_test
>   TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
>   TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
> diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> new file mode 100644
> index 000000000000..f404343a0ae3
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> @@ -0,0 +1,335 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
> + *
> + * The test validates the basic hypercall functionalities that are exposed
> + * via the psuedo-firmware bitmap register. This includes the registers'
> + * read/write behavior before and after the VM has started, and if the
> + * hypercalls are properly masked or unmasked to the guest when disabled or
> + * enabled from the KVM userspace, respectively.
> + */
> +
> +#include <errno.h>
> +#include <linux/arm-smccc.h>
> +#include <asm/kvm.h>
> +#include <kvm_util.h>
> +
> +#include "processor.h"
> +
> +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
> +
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
> +
> +struct kvm_fw_reg_info {
> +	uint64_t reg;		/* Register definition */
> +	uint64_t max_feat_bit;	/* Bit that represents the upper limit of the feature-map */
> +};
> +
> +#define FW_REG_INFO(r)			\
> +	{					\
> +		.reg = r,			\
> +		.max_feat_bit = r##_BIT_MAX,	\
> +	}
> +
> +static const struct kvm_fw_reg_info fw_reg_info[] = {
> +	FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
> +	FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
> +	FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
> +};
> +
> +enum test_stage {
> +	TEST_STAGE_REG_IFACE,
> +	TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
> +	TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
> +	TEST_STAGE_HVC_IFACE_FALSE_INFO,
> +	TEST_STAGE_END,
> +};
> +
> +static int stage = TEST_STAGE_REG_IFACE;
> +
> +struct test_hvc_info {
> +	uint32_t func_id;
> +	uint64_t arg1;
> +};
> +
> +#define TEST_HVC_INFO(f, a1)	\
> +	{			\
> +		.func_id = f,	\
> +		.arg1 = a1,	\
> +	}
> +
> +static const struct test_hvc_info hvc_info[] = {
> +	/* KVM_REG_ARM_STD_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
> +
> +	/* KVM_REG_ARM_STD_HYP_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
> +
> +	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
> +			ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
> +};
> +
> +/* Feed false hypercall info to test the KVM behavior */
> +static const struct test_hvc_info false_hvc_info[] = {
> +	/* Feature support check against a different family of hypercalls */
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> +	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
> +};
> +

I don't see too much benefits of @false_hvc_info[] because
NOT_SUPPORTED is always returned from its test case. I think
it and its test case can be removed if you agree. I'm not
sure if it was suggested by somebody else.

> +static void guest_test_hvc(const struct test_hvc_info *hc_info)
> +{
> +	unsigned int i;
> +	struct arm_smccc_res res;
> +	unsigned int hvc_info_arr_sz;
> +
> +	hvc_info_arr_sz =
> +	hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
> +
> +	for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
> +		memset(&res, 0, sizeof(res));
> +		smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
> +
> +		switch (stage) {
> +		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +			GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
> +					res.a0, hc_info->func_id, hc_info->arg1);
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +			GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
> +					res.a0, hc_info->func_id, hc_info->arg1);
> +			break;
> +		default:
> +			GUEST_ASSERT_1(0, stage);
> +		}
> +	}
> +}
> +
> +static void guest_code(void)
> +{
> +	while (stage != TEST_STAGE_END) {
> +		switch (stage) {
> +		case TEST_STAGE_REG_IFACE:
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +			guest_test_hvc(hvc_info);
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +			guest_test_hvc(false_hvc_info);
> +			break;
> +		default:
> +			GUEST_ASSERT_1(0, stage);
> +		}
> +
> +		GUEST_SYNC(stage);
> +	}
> +
> +	GUEST_DONE();
> +}
> +
> +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
> +{
> +	struct kvm_one_reg reg = {
> +		.id = id,
> +		.addr = (uint64_t)&val,
> +	};
> +
> +	return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
> +}
> +
> +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
> +{
> +	struct kvm_one_reg reg = {
> +		.id = id,
> +		.addr = (uint64_t)addr,
> +	};
> +
> +	vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
> +}
> +
> +struct st_time {
> +	uint32_t rev;
> +	uint32_t attr;
> +	uint64_t st_time;
> +};
> +
> +#define STEAL_TIME_SIZE		((sizeof(struct st_time) + 63) & ~63)
> +#define ST_GPA_BASE		(1 << 30)
> +
> +static void steal_time_init(struct kvm_vm *vm)
> +{
> +	uint64_t st_ipa = (ulong)ST_GPA_BASE;
> +	unsigned int gpages;
> +	struct kvm_device_attr dev = {
> +		.group = KVM_ARM_VCPU_PVTIME_CTRL,
> +		.attr = KVM_ARM_VCPU_PVTIME_IPA,
> +		.addr = (uint64_t)&st_ipa,
> +	};
> +
> +	gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
> +	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
> +
> +	vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
> +}
> +
> +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
> +{
> +	uint64_t val;
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> +		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> +
> +		/* First 'read' should be an upper limit of the features supported */
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
> +			"Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
> +			reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
> +
> +		/* Test a 'write' by disabling all the features of the register map */
> +		ret = set_fw_reg(vm, reg_info->reg, 0);
> +		TEST_ASSERT(ret == 0,
> +			"Failed to clear all the features of reg: 0x%lx; ret: %d\n",
> +			reg_info->reg, errno);
> +
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == 0,
> +			"Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
> +
> +		/*
> +		 * Test enabling a feature that's not supported.
> +		 * Avoid this check if all the bits are occupied.
> +		 */
> +		if (reg_info->max_feat_bit < 63) {
> +			ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
> +			TEST_ASSERT(ret != 0 && errno == EINVAL,
> +			"Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
> +			errno, reg_info->reg);
> +		}
> +	}
> +}

Just in case :)

      ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));


> +
> +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
> +{
> +	uint64_t val;
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> +		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> +
> +		/*
> +		 * Before starting the VM, the test clears all the bits.
> +		 * Check if that's still the case.
> +		 */
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == 0,
> +			"Expected all the features to be cleared for reg: 0x%lx\n",
> +			reg_info->reg);
> +
> +		/*
> +		 * Set all the features for this register again. KVM shouldn't
> +		 * allow this as the VM is running.
> +		 */
> +		ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
> +		TEST_ASSERT(ret != 0 && errno == EBUSY,
> +		"Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
> +		errno, reg_info->reg);
> +	}
> +}
> +

I guess you want to check -EBUSY is returned. In that case,
the comments here could be clearer, something like below
to emphasize '-EBUSY'.

         /*
          * After VM runs for once, -EBUSY should be returned on attempt
          * to set features. Check if the correct errno is returned.
          */

> +static struct kvm_vm *test_vm_create(void)
> +{
> +	struct kvm_vm *vm;
> +
> +	vm = vm_create_default(0, 0, guest_code);
> +
> +	ucall_init(vm, NULL);
> +	steal_time_init(vm);
> +
> +	return vm;
> +}
> +
> +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
> +{
> +	struct kvm_vm *ret_vm = vm;
> +
> +	pr_debug("Stage: %d\n", stage);
> +
> +	switch (stage) {
> +	case TEST_STAGE_REG_IFACE:
> +		test_fw_regs_after_vm_start(vm);
> +		break;
> +	case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		/* Start a new VM so that all the features are now enabled by default */
> +		kvm_vm_free(vm);
> +		ret_vm = test_vm_create();
> +		break;
> +	case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +	case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +		break;
> +	default:
> +		TEST_FAIL("Unknown test stage: %d\n", stage);
> +	}
> +
> +	stage++;
> +	sync_global_to_guest(vm, stage);
> +
> +	return ret_vm;
> +}
> +
> +static void test_run(void)
> +{
> +	struct kvm_vm *vm;
> +	struct ucall uc;
> +	bool guest_done = false;
> +
> +	vm = test_vm_create();
> +
> +	test_fw_regs_before_vm_start(vm);
> +
> +	while (!guest_done) {
> +		vcpu_run(vm, 0);
> +
> +		switch (get_ucall(vm, 0, &uc)) {
> +		case UCALL_SYNC:
> +			vm = test_guest_stage(vm);
> +			break;
> +		case UCALL_DONE:
> +			guest_done = true;
> +			break;
> +		case UCALL_ABORT:
> +			TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
> +			(const char *)uc.args[0], __FILE__, uc.args[1],
> +			uc.args[2], uc.args[3], uc.args[4], stage);
> +			break;
> +		default:
> +			TEST_FAIL("Unexpected guest exit\n");
> +		}
> +	}
> +
> +	kvm_vm_free(vm);
> +}
> +
> +int main(void)
> +{
> +	setbuf(stdout, NULL);
> +
> +	test_run();
> +	return 0;
> +}
> 

Thanks,
Gavin


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

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
@ 2022-04-26  7:49     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  7:49 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Hi Raghavendra,

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce a KVM selftest to check the hypercall interface
> for arm64 platforms. The test validates the user-space'
> [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
> registers as well as its effects on the guest upon certain
> configurations.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   tools/testing/selftests/kvm/.gitignore        |   1 +
>   tools/testing/selftests/kvm/Makefile          |   1 +
>   .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
>   3 files changed, 337 insertions(+)
>   create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
> 

There are comments about @false_hvc_info[] and some nits, as below.
Please evaluate and improve if it makes sense to you. Otherwise, it
looks good to me:

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
> index 1bb575dfc42e..b17e464ec661 100644
> --- a/tools/testing/selftests/kvm/.gitignore
> +++ b/tools/testing/selftests/kvm/.gitignore
> @@ -2,6 +2,7 @@
>   /aarch64/arch_timer
>   /aarch64/debug-exceptions
>   /aarch64/get-reg-list
> +/aarch64/hypercalls
>   /aarch64/psci_test
>   /aarch64/vcpu_width_config
>   /aarch64/vgic_init
> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> index c2cf4d318296..97eef0c03d3b 100644
> --- a/tools/testing/selftests/kvm/Makefile
> +++ b/tools/testing/selftests/kvm/Makefile
> @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
>   TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
>   TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
>   TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
> +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
>   TEST_GEN_PROGS_aarch64 += aarch64/psci_test
>   TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
>   TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
> diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> new file mode 100644
> index 000000000000..f404343a0ae3
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> @@ -0,0 +1,335 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
> + *
> + * The test validates the basic hypercall functionalities that are exposed
> + * via the psuedo-firmware bitmap register. This includes the registers'
> + * read/write behavior before and after the VM has started, and if the
> + * hypercalls are properly masked or unmasked to the guest when disabled or
> + * enabled from the KVM userspace, respectively.
> + */
> +
> +#include <errno.h>
> +#include <linux/arm-smccc.h>
> +#include <asm/kvm.h>
> +#include <kvm_util.h>
> +
> +#include "processor.h"
> +
> +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
> +
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
> +
> +struct kvm_fw_reg_info {
> +	uint64_t reg;		/* Register definition */
> +	uint64_t max_feat_bit;	/* Bit that represents the upper limit of the feature-map */
> +};
> +
> +#define FW_REG_INFO(r)			\
> +	{					\
> +		.reg = r,			\
> +		.max_feat_bit = r##_BIT_MAX,	\
> +	}
> +
> +static const struct kvm_fw_reg_info fw_reg_info[] = {
> +	FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
> +	FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
> +	FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
> +};
> +
> +enum test_stage {
> +	TEST_STAGE_REG_IFACE,
> +	TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
> +	TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
> +	TEST_STAGE_HVC_IFACE_FALSE_INFO,
> +	TEST_STAGE_END,
> +};
> +
> +static int stage = TEST_STAGE_REG_IFACE;
> +
> +struct test_hvc_info {
> +	uint32_t func_id;
> +	uint64_t arg1;
> +};
> +
> +#define TEST_HVC_INFO(f, a1)	\
> +	{			\
> +		.func_id = f,	\
> +		.arg1 = a1,	\
> +	}
> +
> +static const struct test_hvc_info hvc_info[] = {
> +	/* KVM_REG_ARM_STD_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
> +
> +	/* KVM_REG_ARM_STD_HYP_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
> +
> +	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
> +			ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
> +};
> +
> +/* Feed false hypercall info to test the KVM behavior */
> +static const struct test_hvc_info false_hvc_info[] = {
> +	/* Feature support check against a different family of hypercalls */
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> +	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
> +};
> +

I don't see too much benefits of @false_hvc_info[] because
NOT_SUPPORTED is always returned from its test case. I think
it and its test case can be removed if you agree. I'm not
sure if it was suggested by somebody else.

> +static void guest_test_hvc(const struct test_hvc_info *hc_info)
> +{
> +	unsigned int i;
> +	struct arm_smccc_res res;
> +	unsigned int hvc_info_arr_sz;
> +
> +	hvc_info_arr_sz =
> +	hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
> +
> +	for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
> +		memset(&res, 0, sizeof(res));
> +		smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
> +
> +		switch (stage) {
> +		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +			GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
> +					res.a0, hc_info->func_id, hc_info->arg1);
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +			GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
> +					res.a0, hc_info->func_id, hc_info->arg1);
> +			break;
> +		default:
> +			GUEST_ASSERT_1(0, stage);
> +		}
> +	}
> +}
> +
> +static void guest_code(void)
> +{
> +	while (stage != TEST_STAGE_END) {
> +		switch (stage) {
> +		case TEST_STAGE_REG_IFACE:
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +			guest_test_hvc(hvc_info);
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +			guest_test_hvc(false_hvc_info);
> +			break;
> +		default:
> +			GUEST_ASSERT_1(0, stage);
> +		}
> +
> +		GUEST_SYNC(stage);
> +	}
> +
> +	GUEST_DONE();
> +}
> +
> +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
> +{
> +	struct kvm_one_reg reg = {
> +		.id = id,
> +		.addr = (uint64_t)&val,
> +	};
> +
> +	return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
> +}
> +
> +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
> +{
> +	struct kvm_one_reg reg = {
> +		.id = id,
> +		.addr = (uint64_t)addr,
> +	};
> +
> +	vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
> +}
> +
> +struct st_time {
> +	uint32_t rev;
> +	uint32_t attr;
> +	uint64_t st_time;
> +};
> +
> +#define STEAL_TIME_SIZE		((sizeof(struct st_time) + 63) & ~63)
> +#define ST_GPA_BASE		(1 << 30)
> +
> +static void steal_time_init(struct kvm_vm *vm)
> +{
> +	uint64_t st_ipa = (ulong)ST_GPA_BASE;
> +	unsigned int gpages;
> +	struct kvm_device_attr dev = {
> +		.group = KVM_ARM_VCPU_PVTIME_CTRL,
> +		.attr = KVM_ARM_VCPU_PVTIME_IPA,
> +		.addr = (uint64_t)&st_ipa,
> +	};
> +
> +	gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
> +	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
> +
> +	vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
> +}
> +
> +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
> +{
> +	uint64_t val;
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> +		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> +
> +		/* First 'read' should be an upper limit of the features supported */
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
> +			"Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
> +			reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
> +
> +		/* Test a 'write' by disabling all the features of the register map */
> +		ret = set_fw_reg(vm, reg_info->reg, 0);
> +		TEST_ASSERT(ret == 0,
> +			"Failed to clear all the features of reg: 0x%lx; ret: %d\n",
> +			reg_info->reg, errno);
> +
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == 0,
> +			"Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
> +
> +		/*
> +		 * Test enabling a feature that's not supported.
> +		 * Avoid this check if all the bits are occupied.
> +		 */
> +		if (reg_info->max_feat_bit < 63) {
> +			ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
> +			TEST_ASSERT(ret != 0 && errno == EINVAL,
> +			"Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
> +			errno, reg_info->reg);
> +		}
> +	}
> +}

Just in case :)

      ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));


> +
> +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
> +{
> +	uint64_t val;
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> +		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> +
> +		/*
> +		 * Before starting the VM, the test clears all the bits.
> +		 * Check if that's still the case.
> +		 */
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == 0,
> +			"Expected all the features to be cleared for reg: 0x%lx\n",
> +			reg_info->reg);
> +
> +		/*
> +		 * Set all the features for this register again. KVM shouldn't
> +		 * allow this as the VM is running.
> +		 */
> +		ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
> +		TEST_ASSERT(ret != 0 && errno == EBUSY,
> +		"Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
> +		errno, reg_info->reg);
> +	}
> +}
> +

I guess you want to check -EBUSY is returned. In that case,
the comments here could be clearer, something like below
to emphasize '-EBUSY'.

         /*
          * After VM runs for once, -EBUSY should be returned on attempt
          * to set features. Check if the correct errno is returned.
          */

> +static struct kvm_vm *test_vm_create(void)
> +{
> +	struct kvm_vm *vm;
> +
> +	vm = vm_create_default(0, 0, guest_code);
> +
> +	ucall_init(vm, NULL);
> +	steal_time_init(vm);
> +
> +	return vm;
> +}
> +
> +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
> +{
> +	struct kvm_vm *ret_vm = vm;
> +
> +	pr_debug("Stage: %d\n", stage);
> +
> +	switch (stage) {
> +	case TEST_STAGE_REG_IFACE:
> +		test_fw_regs_after_vm_start(vm);
> +		break;
> +	case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		/* Start a new VM so that all the features are now enabled by default */
> +		kvm_vm_free(vm);
> +		ret_vm = test_vm_create();
> +		break;
> +	case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +	case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +		break;
> +	default:
> +		TEST_FAIL("Unknown test stage: %d\n", stage);
> +	}
> +
> +	stage++;
> +	sync_global_to_guest(vm, stage);
> +
> +	return ret_vm;
> +}
> +
> +static void test_run(void)
> +{
> +	struct kvm_vm *vm;
> +	struct ucall uc;
> +	bool guest_done = false;
> +
> +	vm = test_vm_create();
> +
> +	test_fw_regs_before_vm_start(vm);
> +
> +	while (!guest_done) {
> +		vcpu_run(vm, 0);
> +
> +		switch (get_ucall(vm, 0, &uc)) {
> +		case UCALL_SYNC:
> +			vm = test_guest_stage(vm);
> +			break;
> +		case UCALL_DONE:
> +			guest_done = true;
> +			break;
> +		case UCALL_ABORT:
> +			TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
> +			(const char *)uc.args[0], __FILE__, uc.args[1],
> +			uc.args[2], uc.args[3], uc.args[4], stage);
> +			break;
> +		default:
> +			TEST_FAIL("Unexpected guest exit\n");
> +		}
> +	}
> +
> +	kvm_vm_free(vm);
> +}
> +
> +int main(void)
> +{
> +	setbuf(stdout, NULL);
> +
> +	test_run();
> +	return 0;
> +}
> 

Thanks,
Gavin

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
@ 2022-04-26  7:49     ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-26  7:49 UTC (permalink / raw)
  To: Raghavendra Rao Ananta, Marc Zyngier, Andrew Jones, James Morse,
	Alexandru Elisei, Suzuki K Poulose
  Cc: kvm, Catalin Marinas, Peter Shier, linux-kernel, Paolo Bonzini,
	Will Deacon, kvmarm, linux-arm-kernel

Hi Raghavendra,

On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> Introduce a KVM selftest to check the hypercall interface
> for arm64 platforms. The test validates the user-space'
> [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
> registers as well as its effects on the guest upon certain
> configurations.
> 
> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> ---
>   tools/testing/selftests/kvm/.gitignore        |   1 +
>   tools/testing/selftests/kvm/Makefile          |   1 +
>   .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
>   3 files changed, 337 insertions(+)
>   create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
> 

There are comments about @false_hvc_info[] and some nits, as below.
Please evaluate and improve if it makes sense to you. Otherwise, it
looks good to me:

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
> index 1bb575dfc42e..b17e464ec661 100644
> --- a/tools/testing/selftests/kvm/.gitignore
> +++ b/tools/testing/selftests/kvm/.gitignore
> @@ -2,6 +2,7 @@
>   /aarch64/arch_timer
>   /aarch64/debug-exceptions
>   /aarch64/get-reg-list
> +/aarch64/hypercalls
>   /aarch64/psci_test
>   /aarch64/vcpu_width_config
>   /aarch64/vgic_init
> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> index c2cf4d318296..97eef0c03d3b 100644
> --- a/tools/testing/selftests/kvm/Makefile
> +++ b/tools/testing/selftests/kvm/Makefile
> @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
>   TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
>   TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
>   TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
> +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
>   TEST_GEN_PROGS_aarch64 += aarch64/psci_test
>   TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
>   TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
> diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> new file mode 100644
> index 000000000000..f404343a0ae3
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> @@ -0,0 +1,335 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
> + *
> + * The test validates the basic hypercall functionalities that are exposed
> + * via the psuedo-firmware bitmap register. This includes the registers'
> + * read/write behavior before and after the VM has started, and if the
> + * hypercalls are properly masked or unmasked to the guest when disabled or
> + * enabled from the KVM userspace, respectively.
> + */
> +
> +#include <errno.h>
> +#include <linux/arm-smccc.h>
> +#include <asm/kvm.h>
> +#include <kvm_util.h>
> +
> +#include "processor.h"
> +
> +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
> +
> +/* Last valid bits of the bitmapped firmware registers */
> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX		0
> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX	0
> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX	1
> +
> +struct kvm_fw_reg_info {
> +	uint64_t reg;		/* Register definition */
> +	uint64_t max_feat_bit;	/* Bit that represents the upper limit of the feature-map */
> +};
> +
> +#define FW_REG_INFO(r)			\
> +	{					\
> +		.reg = r,			\
> +		.max_feat_bit = r##_BIT_MAX,	\
> +	}
> +
> +static const struct kvm_fw_reg_info fw_reg_info[] = {
> +	FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
> +	FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
> +	FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
> +};
> +
> +enum test_stage {
> +	TEST_STAGE_REG_IFACE,
> +	TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
> +	TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
> +	TEST_STAGE_HVC_IFACE_FALSE_INFO,
> +	TEST_STAGE_END,
> +};
> +
> +static int stage = TEST_STAGE_REG_IFACE;
> +
> +struct test_hvc_info {
> +	uint32_t func_id;
> +	uint64_t arg1;
> +};
> +
> +#define TEST_HVC_INFO(f, a1)	\
> +	{			\
> +		.func_id = f,	\
> +		.arg1 = a1,	\
> +	}
> +
> +static const struct test_hvc_info hvc_info[] = {
> +	/* KVM_REG_ARM_STD_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
> +
> +	/* KVM_REG_ARM_STD_HYP_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
> +
> +	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
> +			ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
> +	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
> +};
> +
> +/* Feed false hypercall info to test the KVM behavior */
> +static const struct test_hvc_info false_hvc_info[] = {
> +	/* Feature support check against a different family of hypercalls */
> +	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> +	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
> +	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
> +};
> +

I don't see too much benefits of @false_hvc_info[] because
NOT_SUPPORTED is always returned from its test case. I think
it and its test case can be removed if you agree. I'm not
sure if it was suggested by somebody else.

> +static void guest_test_hvc(const struct test_hvc_info *hc_info)
> +{
> +	unsigned int i;
> +	struct arm_smccc_res res;
> +	unsigned int hvc_info_arr_sz;
> +
> +	hvc_info_arr_sz =
> +	hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
> +
> +	for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
> +		memset(&res, 0, sizeof(res));
> +		smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
> +
> +		switch (stage) {
> +		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +			GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
> +					res.a0, hc_info->func_id, hc_info->arg1);
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +			GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
> +					res.a0, hc_info->func_id, hc_info->arg1);
> +			break;
> +		default:
> +			GUEST_ASSERT_1(0, stage);
> +		}
> +	}
> +}
> +
> +static void guest_code(void)
> +{
> +	while (stage != TEST_STAGE_END) {
> +		switch (stage) {
> +		case TEST_STAGE_REG_IFACE:
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +			guest_test_hvc(hvc_info);
> +			break;
> +		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +			guest_test_hvc(false_hvc_info);
> +			break;
> +		default:
> +			GUEST_ASSERT_1(0, stage);
> +		}
> +
> +		GUEST_SYNC(stage);
> +	}
> +
> +	GUEST_DONE();
> +}
> +
> +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
> +{
> +	struct kvm_one_reg reg = {
> +		.id = id,
> +		.addr = (uint64_t)&val,
> +	};
> +
> +	return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
> +}
> +
> +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
> +{
> +	struct kvm_one_reg reg = {
> +		.id = id,
> +		.addr = (uint64_t)addr,
> +	};
> +
> +	vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
> +}
> +
> +struct st_time {
> +	uint32_t rev;
> +	uint32_t attr;
> +	uint64_t st_time;
> +};
> +
> +#define STEAL_TIME_SIZE		((sizeof(struct st_time) + 63) & ~63)
> +#define ST_GPA_BASE		(1 << 30)
> +
> +static void steal_time_init(struct kvm_vm *vm)
> +{
> +	uint64_t st_ipa = (ulong)ST_GPA_BASE;
> +	unsigned int gpages;
> +	struct kvm_device_attr dev = {
> +		.group = KVM_ARM_VCPU_PVTIME_CTRL,
> +		.attr = KVM_ARM_VCPU_PVTIME_IPA,
> +		.addr = (uint64_t)&st_ipa,
> +	};
> +
> +	gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
> +	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
> +
> +	vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
> +}
> +
> +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
> +{
> +	uint64_t val;
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> +		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> +
> +		/* First 'read' should be an upper limit of the features supported */
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
> +			"Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
> +			reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
> +
> +		/* Test a 'write' by disabling all the features of the register map */
> +		ret = set_fw_reg(vm, reg_info->reg, 0);
> +		TEST_ASSERT(ret == 0,
> +			"Failed to clear all the features of reg: 0x%lx; ret: %d\n",
> +			reg_info->reg, errno);
> +
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == 0,
> +			"Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
> +
> +		/*
> +		 * Test enabling a feature that's not supported.
> +		 * Avoid this check if all the bits are occupied.
> +		 */
> +		if (reg_info->max_feat_bit < 63) {
> +			ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
> +			TEST_ASSERT(ret != 0 && errno == EINVAL,
> +			"Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
> +			errno, reg_info->reg);
> +		}
> +	}
> +}

Just in case :)

      ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));


> +
> +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
> +{
> +	uint64_t val;
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> +		const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> +
> +		/*
> +		 * Before starting the VM, the test clears all the bits.
> +		 * Check if that's still the case.
> +		 */
> +		get_fw_reg(vm, reg_info->reg, &val);
> +		TEST_ASSERT(val == 0,
> +			"Expected all the features to be cleared for reg: 0x%lx\n",
> +			reg_info->reg);
> +
> +		/*
> +		 * Set all the features for this register again. KVM shouldn't
> +		 * allow this as the VM is running.
> +		 */
> +		ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
> +		TEST_ASSERT(ret != 0 && errno == EBUSY,
> +		"Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
> +		errno, reg_info->reg);
> +	}
> +}
> +

I guess you want to check -EBUSY is returned. In that case,
the comments here could be clearer, something like below
to emphasize '-EBUSY'.

         /*
          * After VM runs for once, -EBUSY should be returned on attempt
          * to set features. Check if the correct errno is returned.
          */

> +static struct kvm_vm *test_vm_create(void)
> +{
> +	struct kvm_vm *vm;
> +
> +	vm = vm_create_default(0, 0, guest_code);
> +
> +	ucall_init(vm, NULL);
> +	steal_time_init(vm);
> +
> +	return vm;
> +}
> +
> +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
> +{
> +	struct kvm_vm *ret_vm = vm;
> +
> +	pr_debug("Stage: %d\n", stage);
> +
> +	switch (stage) {
> +	case TEST_STAGE_REG_IFACE:
> +		test_fw_regs_after_vm_start(vm);
> +		break;
> +	case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> +		/* Start a new VM so that all the features are now enabled by default */
> +		kvm_vm_free(vm);
> +		ret_vm = test_vm_create();
> +		break;
> +	case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> +	case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> +		break;
> +	default:
> +		TEST_FAIL("Unknown test stage: %d\n", stage);
> +	}
> +
> +	stage++;
> +	sync_global_to_guest(vm, stage);
> +
> +	return ret_vm;
> +}
> +
> +static void test_run(void)
> +{
> +	struct kvm_vm *vm;
> +	struct ucall uc;
> +	bool guest_done = false;
> +
> +	vm = test_vm_create();
> +
> +	test_fw_regs_before_vm_start(vm);
> +
> +	while (!guest_done) {
> +		vcpu_run(vm, 0);
> +
> +		switch (get_ucall(vm, 0, &uc)) {
> +		case UCALL_SYNC:
> +			vm = test_guest_stage(vm);
> +			break;
> +		case UCALL_DONE:
> +			guest_done = true;
> +			break;
> +		case UCALL_ABORT:
> +			TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
> +			(const char *)uc.args[0], __FILE__, uc.args[1],
> +			uc.args[2], uc.args[3], uc.args[4], stage);
> +			break;
> +		default:
> +			TEST_FAIL("Unexpected guest exit\n");
> +		}
> +	}
> +
> +	kvm_vm_free(vm);
> +}
> +
> +int main(void)
> +{
> +	setbuf(stdout, NULL);
> +
> +	test_run();
> +	return 0;
> +}
> 

Thanks,
Gavin


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  2022-04-26  6:33     ` Gavin Shan
  (?)
@ 2022-04-26 16:44       ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-26 16:44 UTC (permalink / raw)
  To: Gavin Shan
  Cc: kvm, Marc Zyngier, Peter Shier, linux-kernel, Will Deacon,
	Catalin Marinas, Paolo Bonzini, kvmarm, linux-arm-kernel

Hi Gavin,

On Mon, Apr 25, 2022 at 11:34 PM Gavin Shan <gshan@redhat.com> wrote:
>
> Hi Raghavendra,
>
> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> > KVM regularly introduces new hypercall services to the guests without
> > any consent from the userspace. This means, the guests can observe
> > hypercall services in and out as they migrate across various host
> > kernel versions. This could be a major problem if the guest
> > discovered a hypercall, started using it, and after getting migrated
> > to an older kernel realizes that it's no longer available. Depending
> > on how the guest handles the change, there's a potential chance that
> > the guest would just panic.
> >
> > As a result, there's a need for the userspace to elect the services
> > that it wishes the guest to discover. It can elect these services
> > based on the kernels spread across its (migration) fleet. To remedy
> > this, extend the existing firmware pseudo-registers, such as
> > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > for all the hypercall services available.
> >
> > These firmware registers are categorized based on the service call
> > owners, but unlike the existing firmware pseudo-registers, they hold
> > the features supported in the form of a bitmap.
> >
> > During the VM initialization, the registers are set to upper-limit of
> > the features supported by the corresponding registers. It's expected
> > that the VMMs discover the features provided by each register via
> > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > KVM allows this modification only until the VM has started.
> >
> > Some of the standard features are not mapped to any bits of the
> > registers. But since they can recreate the original problem of
> > making it available without userspace's consent, they need to
> > be explicitly added to the case-list in
> > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> >
> > Older userspace code can simply ignore the feature and the
> > hypercall services will be exposed unconditionally to the guests,
> > thus ensuring backward compatibility.
> >
> > In this patch, the framework adds the register only for ARM's standard
> > secure services (owner value 4). Currently, this includes support only
> > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > register representing mandatory features of v1.0. Other services are
> > momentarily added in the upcoming patches.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >   arch/arm64/include/asm/kvm_host.h | 12 ++++
> >   arch/arm64/include/uapi/asm/kvm.h |  9 +++
> >   arch/arm64/kvm/arm.c              |  1 +
> >   arch/arm64/kvm/guest.c            |  8 ++-
> >   arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> >   arch/arm64/kvm/psci.c             | 13 +++++
> >   include/kvm/arm_hypercalls.h      |  6 ++
> >   include/kvm/arm_psci.h            |  2 +-
> >   8 files changed, 142 insertions(+), 3 deletions(-)
> >
>
> Some nits as below, please consider to improve if you need another
> respin.
>
> Reviewed-by: Gavin Shan <gshan@redhat.com>
>
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 94a27a7520f4..df07f4c10197 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> >   struct kvm_arch_memory_slot {
> >   };
> >
> > +/**
> > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > + *
> > + * @std_bmap: Bitmap of standard secure service calls
> > + */
> > +struct kvm_smccc_features {
> > +     unsigned long std_bmap;
> > +};
> > +
>
> s/Descriptor/Descriptor of
>
Nice catch!

> >   struct kvm_arch {
> >       struct kvm_s2_mmu mmu;
> >
> > @@ -150,6 +159,9 @@ struct kvm_arch {
> >
> >       u8 pfr0_csv2;
> >       u8 pfr0_csv3;
> > +
> > +     /* Hypercall features firmware registers' descriptor */
> > +     struct kvm_smccc_features smccc_feat;
> >   };
> >
> >   struct kvm_vcpu_fault_info {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> >   #define KVM_ARM64_SVE_VLS_WORDS     \
> >       ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> >
> > +/* Bitmap feature firmware registers */
> > +#define KVM_REG_ARM_FW_FEAT_BMAP             (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)              (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > +                                             KVM_REG_ARM_FW_FEAT_BMAP |      \
> > +                                             ((r) & 0xffff))
> > +
> > +#define KVM_REG_ARM_STD_BMAP                 KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0                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/arm.c b/arch/arm64/kvm/arm.c
> > index 523bc934fe2f..a37fadbd617e 100644
> > --- a/arch/arm64/kvm/arm.c
> > +++ b/arch/arm64/kvm/arm.c
> > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> >       kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> >
> >       set_default_spectre(kvm);
> > +     kvm_arm_init_hypercalls(kvm);
> >
> >       return ret;
> >   out_free_stage2_pgd:
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 0d5cca56cbda..8c607199cad1 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >       switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >       case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > -     case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > +     case KVM_REG_ARM_FW:
> > +     case KVM_REG_ARM_FW_FEAT_BMAP:
> > +             return kvm_arm_get_fw_reg(vcpu, reg);
> >       case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> >       }
> >
> > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >       switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >       case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > -     case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > +     case KVM_REG_ARM_FW:
> > +     case KVM_REG_ARM_FW_FEAT_BMAP:
> > +             return kvm_arm_set_fw_reg(vcpu, reg);
> >       case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> >       }
> >
> > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index fa6d9378d8e7..df55a04d2fe8 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> >       val[3] = lower_32_bits(cycles);
> >   }
> >
> > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > +{
> > +     return test_bit(feat_bit, reg_bmap);
> > +}
> > +
>
> Might be worhty to be 'inline'. This function would be called
> frequently.
>
I was hoping the compiler would optimize it for us as needed.

> > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     switch (func_id) {
> > +     /*
> > +      * List of function-ids that are not gated with the bitmapped feature
> > +      * firmware registers, and are to be allowed for servicing the call by default.
> > +      */
> > +     case ARM_SMCCC_VERSION_FUNC_ID:
> > +     case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > +     case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > +     case ARM_SMCCC_HV_PV_TIME_ST:
> > +     case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +     case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +     case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +             return true;
> > +     default:
> > +             return kvm_psci_func_id_is_valid(vcpu, func_id);
> > +     }
> > +}
> > +
> > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > +
> > +     switch (func_id) {
> > +     case ARM_SMCCC_TRNG_VERSION:
> > +     case ARM_SMCCC_TRNG_FEATURES:
> > +     case ARM_SMCCC_TRNG_GET_UUID:
> > +     case ARM_SMCCC_TRNG_RND32:
> > +     case ARM_SMCCC_TRNG_RND64:
> > +             return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > +                                             KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > +     default:
> > +             return kvm_hvc_call_default_allowed(vcpu, func_id);
> > +     }
> > +}
> > +
> >   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >   {
> >       u32 func_id = smccc_get_function(vcpu);
> > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >       u32 feature;
> >       gpa_t gpa;
> >
> > +     if (!kvm_hvc_call_allowed(vcpu, func_id))
> > +             goto out;
> > +
> >       switch (func_id) {
> >       case ARM_SMCCC_VERSION_FUNC_ID:
> >               val[0] = ARM_SMCCC_VERSION_1_1;
> > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >               return kvm_psci_call(vcpu);
> >       }
> >
> > +out:
> >       smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> >       return 1;
> >   }
> > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > +     KVM_REG_ARM_STD_BMAP,
> >   };
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > +{
> > +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +
> > +     smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > +}
> > +
> >   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> >   {
> >       return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> >
> >   int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >   {
> > +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> >       void __user *uaddr = (void __user *)(long)reg->addr;
> >       u64 val;
> >
> > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> >               val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> >               break;
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             val = READ_ONCE(smccc_feat->std_bmap);
> > +             break;
> >       default:
> >               return -ENOENT;
> >       }
> > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >       return 0;
> >   }
> >
> > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > +{
> > +     int ret = 0;
> > +     struct kvm *kvm = vcpu->kvm;
> > +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +     unsigned long *fw_reg_bmap, fw_reg_features;
> > +
> > +     switch (reg_id) {
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             fw_reg_bmap = &smccc_feat->std_bmap;
> > +             fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > +             break;
> > +     default:
> > +             return -ENOENT;
> > +     }
> > +
> > +     /* Check for unsupported bit */
> > +     if (val & ~fw_reg_features)
> > +             return -EINVAL;
> > +
> > +     mutex_lock(&kvm->lock);
> > +
> > +     /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > +     if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > +             ret = -EBUSY;
> > +             goto out;
> > +     }
> > +
> > +     WRITE_ONCE(*fw_reg_bmap, val);
> > +out:
> > +     mutex_unlock(&kvm->lock);
> > +     return ret;
> > +}
> > +
> >   int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >   {
> >       void __user *uaddr = (void __user *)(long)reg->addr;
> > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                       return -EINVAL;
> >
> >               return 0;
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >       default:
> >               return -ENOENT;
> >       }
> > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > index 346535169faa..67d1273e8086 100644
> > --- a/arch/arm64/kvm/psci.c
> > +++ b/arch/arm64/kvm/psci.c
> > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> >               return -EINVAL;
> >       }
> >   }
> > +
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > +     if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > +             return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > +
> > +     if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > +             ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > +             return true;
> > +
> > +     return false;
> > +}
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index 5d38628a8d04..499b45b607b6 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -6,6 +6,11 @@
> >
> >   #include <asm/kvm_emulate.h>
> >
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
> > +
> > +#define KVM_ARM_SMCCC_STD_FEATURES           GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > +
>
> s/bits of/bit of
>
Great catch again!

> >   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> >   static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> >
> >   struct kvm_one_reg;
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> >   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);
> > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > index 6e55b9283789..c47be3e26965 100644
> > --- a/include/kvm/arm_psci.h
> > +++ b/include/kvm/arm_psci.h
> > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> >       return KVM_ARM_PSCI_0_1;
> >   }
> >
> > -
> >   int kvm_psci_call(struct kvm_vcpu *vcpu);
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> >
> >   #endif /* __KVM_ARM_PSCI_H__ */
> >
>
> Thanks,
> Gavin
>

Thanks for the review, Gavin.

- Raghavendra
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-26 16:44       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-26 16:44 UTC (permalink / raw)
  To: Gavin Shan
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, kvm, Catalin Marinas, Peter Shier,
	linux-kernel, Paolo Bonzini, Will Deacon, kvmarm,
	linux-arm-kernel

Hi Gavin,

On Mon, Apr 25, 2022 at 11:34 PM Gavin Shan <gshan@redhat.com> wrote:
>
> Hi Raghavendra,
>
> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> > KVM regularly introduces new hypercall services to the guests without
> > any consent from the userspace. This means, the guests can observe
> > hypercall services in and out as they migrate across various host
> > kernel versions. This could be a major problem if the guest
> > discovered a hypercall, started using it, and after getting migrated
> > to an older kernel realizes that it's no longer available. Depending
> > on how the guest handles the change, there's a potential chance that
> > the guest would just panic.
> >
> > As a result, there's a need for the userspace to elect the services
> > that it wishes the guest to discover. It can elect these services
> > based on the kernels spread across its (migration) fleet. To remedy
> > this, extend the existing firmware pseudo-registers, such as
> > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > for all the hypercall services available.
> >
> > These firmware registers are categorized based on the service call
> > owners, but unlike the existing firmware pseudo-registers, they hold
> > the features supported in the form of a bitmap.
> >
> > During the VM initialization, the registers are set to upper-limit of
> > the features supported by the corresponding registers. It's expected
> > that the VMMs discover the features provided by each register via
> > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > KVM allows this modification only until the VM has started.
> >
> > Some of the standard features are not mapped to any bits of the
> > registers. But since they can recreate the original problem of
> > making it available without userspace's consent, they need to
> > be explicitly added to the case-list in
> > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> >
> > Older userspace code can simply ignore the feature and the
> > hypercall services will be exposed unconditionally to the guests,
> > thus ensuring backward compatibility.
> >
> > In this patch, the framework adds the register only for ARM's standard
> > secure services (owner value 4). Currently, this includes support only
> > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > register representing mandatory features of v1.0. Other services are
> > momentarily added in the upcoming patches.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >   arch/arm64/include/asm/kvm_host.h | 12 ++++
> >   arch/arm64/include/uapi/asm/kvm.h |  9 +++
> >   arch/arm64/kvm/arm.c              |  1 +
> >   arch/arm64/kvm/guest.c            |  8 ++-
> >   arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> >   arch/arm64/kvm/psci.c             | 13 +++++
> >   include/kvm/arm_hypercalls.h      |  6 ++
> >   include/kvm/arm_psci.h            |  2 +-
> >   8 files changed, 142 insertions(+), 3 deletions(-)
> >
>
> Some nits as below, please consider to improve if you need another
> respin.
>
> Reviewed-by: Gavin Shan <gshan@redhat.com>
>
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 94a27a7520f4..df07f4c10197 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> >   struct kvm_arch_memory_slot {
> >   };
> >
> > +/**
> > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > + *
> > + * @std_bmap: Bitmap of standard secure service calls
> > + */
> > +struct kvm_smccc_features {
> > +     unsigned long std_bmap;
> > +};
> > +
>
> s/Descriptor/Descriptor of
>
Nice catch!

> >   struct kvm_arch {
> >       struct kvm_s2_mmu mmu;
> >
> > @@ -150,6 +159,9 @@ struct kvm_arch {
> >
> >       u8 pfr0_csv2;
> >       u8 pfr0_csv3;
> > +
> > +     /* Hypercall features firmware registers' descriptor */
> > +     struct kvm_smccc_features smccc_feat;
> >   };
> >
> >   struct kvm_vcpu_fault_info {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> >   #define KVM_ARM64_SVE_VLS_WORDS     \
> >       ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> >
> > +/* Bitmap feature firmware registers */
> > +#define KVM_REG_ARM_FW_FEAT_BMAP             (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)              (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > +                                             KVM_REG_ARM_FW_FEAT_BMAP |      \
> > +                                             ((r) & 0xffff))
> > +
> > +#define KVM_REG_ARM_STD_BMAP                 KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0                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/arm.c b/arch/arm64/kvm/arm.c
> > index 523bc934fe2f..a37fadbd617e 100644
> > --- a/arch/arm64/kvm/arm.c
> > +++ b/arch/arm64/kvm/arm.c
> > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> >       kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> >
> >       set_default_spectre(kvm);
> > +     kvm_arm_init_hypercalls(kvm);
> >
> >       return ret;
> >   out_free_stage2_pgd:
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 0d5cca56cbda..8c607199cad1 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >       switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >       case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > -     case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > +     case KVM_REG_ARM_FW:
> > +     case KVM_REG_ARM_FW_FEAT_BMAP:
> > +             return kvm_arm_get_fw_reg(vcpu, reg);
> >       case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> >       }
> >
> > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >       switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >       case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > -     case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > +     case KVM_REG_ARM_FW:
> > +     case KVM_REG_ARM_FW_FEAT_BMAP:
> > +             return kvm_arm_set_fw_reg(vcpu, reg);
> >       case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> >       }
> >
> > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index fa6d9378d8e7..df55a04d2fe8 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> >       val[3] = lower_32_bits(cycles);
> >   }
> >
> > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > +{
> > +     return test_bit(feat_bit, reg_bmap);
> > +}
> > +
>
> Might be worhty to be 'inline'. This function would be called
> frequently.
>
I was hoping the compiler would optimize it for us as needed.

> > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     switch (func_id) {
> > +     /*
> > +      * List of function-ids that are not gated with the bitmapped feature
> > +      * firmware registers, and are to be allowed for servicing the call by default.
> > +      */
> > +     case ARM_SMCCC_VERSION_FUNC_ID:
> > +     case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > +     case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > +     case ARM_SMCCC_HV_PV_TIME_ST:
> > +     case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +     case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +     case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +             return true;
> > +     default:
> > +             return kvm_psci_func_id_is_valid(vcpu, func_id);
> > +     }
> > +}
> > +
> > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > +
> > +     switch (func_id) {
> > +     case ARM_SMCCC_TRNG_VERSION:
> > +     case ARM_SMCCC_TRNG_FEATURES:
> > +     case ARM_SMCCC_TRNG_GET_UUID:
> > +     case ARM_SMCCC_TRNG_RND32:
> > +     case ARM_SMCCC_TRNG_RND64:
> > +             return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > +                                             KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > +     default:
> > +             return kvm_hvc_call_default_allowed(vcpu, func_id);
> > +     }
> > +}
> > +
> >   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >   {
> >       u32 func_id = smccc_get_function(vcpu);
> > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >       u32 feature;
> >       gpa_t gpa;
> >
> > +     if (!kvm_hvc_call_allowed(vcpu, func_id))
> > +             goto out;
> > +
> >       switch (func_id) {
> >       case ARM_SMCCC_VERSION_FUNC_ID:
> >               val[0] = ARM_SMCCC_VERSION_1_1;
> > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >               return kvm_psci_call(vcpu);
> >       }
> >
> > +out:
> >       smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> >       return 1;
> >   }
> > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > +     KVM_REG_ARM_STD_BMAP,
> >   };
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > +{
> > +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +
> > +     smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > +}
> > +
> >   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> >   {
> >       return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> >
> >   int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >   {
> > +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> >       void __user *uaddr = (void __user *)(long)reg->addr;
> >       u64 val;
> >
> > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> >               val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> >               break;
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             val = READ_ONCE(smccc_feat->std_bmap);
> > +             break;
> >       default:
> >               return -ENOENT;
> >       }
> > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >       return 0;
> >   }
> >
> > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > +{
> > +     int ret = 0;
> > +     struct kvm *kvm = vcpu->kvm;
> > +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +     unsigned long *fw_reg_bmap, fw_reg_features;
> > +
> > +     switch (reg_id) {
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             fw_reg_bmap = &smccc_feat->std_bmap;
> > +             fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > +             break;
> > +     default:
> > +             return -ENOENT;
> > +     }
> > +
> > +     /* Check for unsupported bit */
> > +     if (val & ~fw_reg_features)
> > +             return -EINVAL;
> > +
> > +     mutex_lock(&kvm->lock);
> > +
> > +     /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > +     if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > +             ret = -EBUSY;
> > +             goto out;
> > +     }
> > +
> > +     WRITE_ONCE(*fw_reg_bmap, val);
> > +out:
> > +     mutex_unlock(&kvm->lock);
> > +     return ret;
> > +}
> > +
> >   int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >   {
> >       void __user *uaddr = (void __user *)(long)reg->addr;
> > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                       return -EINVAL;
> >
> >               return 0;
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >       default:
> >               return -ENOENT;
> >       }
> > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > index 346535169faa..67d1273e8086 100644
> > --- a/arch/arm64/kvm/psci.c
> > +++ b/arch/arm64/kvm/psci.c
> > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> >               return -EINVAL;
> >       }
> >   }
> > +
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > +     if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > +             return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > +
> > +     if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > +             ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > +             return true;
> > +
> > +     return false;
> > +}
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index 5d38628a8d04..499b45b607b6 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -6,6 +6,11 @@
> >
> >   #include <asm/kvm_emulate.h>
> >
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
> > +
> > +#define KVM_ARM_SMCCC_STD_FEATURES           GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > +
>
> s/bits of/bit of
>
Great catch again!

> >   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> >   static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> >
> >   struct kvm_one_reg;
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> >   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);
> > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > index 6e55b9283789..c47be3e26965 100644
> > --- a/include/kvm/arm_psci.h
> > +++ b/include/kvm/arm_psci.h
> > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> >       return KVM_ARM_PSCI_0_1;
> >   }
> >
> > -
> >   int kvm_psci_call(struct kvm_vcpu *vcpu);
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> >
> >   #endif /* __KVM_ARM_PSCI_H__ */
> >
>
> Thanks,
> Gavin
>

Thanks for the review, Gavin.

- Raghavendra

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-26 16:44       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-26 16:44 UTC (permalink / raw)
  To: Gavin Shan
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, kvm, Catalin Marinas, Peter Shier,
	linux-kernel, Paolo Bonzini, Will Deacon, kvmarm,
	linux-arm-kernel

Hi Gavin,

On Mon, Apr 25, 2022 at 11:34 PM Gavin Shan <gshan@redhat.com> wrote:
>
> Hi Raghavendra,
>
> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> > KVM regularly introduces new hypercall services to the guests without
> > any consent from the userspace. This means, the guests can observe
> > hypercall services in and out as they migrate across various host
> > kernel versions. This could be a major problem if the guest
> > discovered a hypercall, started using it, and after getting migrated
> > to an older kernel realizes that it's no longer available. Depending
> > on how the guest handles the change, there's a potential chance that
> > the guest would just panic.
> >
> > As a result, there's a need for the userspace to elect the services
> > that it wishes the guest to discover. It can elect these services
> > based on the kernels spread across its (migration) fleet. To remedy
> > this, extend the existing firmware pseudo-registers, such as
> > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > for all the hypercall services available.
> >
> > These firmware registers are categorized based on the service call
> > owners, but unlike the existing firmware pseudo-registers, they hold
> > the features supported in the form of a bitmap.
> >
> > During the VM initialization, the registers are set to upper-limit of
> > the features supported by the corresponding registers. It's expected
> > that the VMMs discover the features provided by each register via
> > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > KVM allows this modification only until the VM has started.
> >
> > Some of the standard features are not mapped to any bits of the
> > registers. But since they can recreate the original problem of
> > making it available without userspace's consent, they need to
> > be explicitly added to the case-list in
> > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> >
> > Older userspace code can simply ignore the feature and the
> > hypercall services will be exposed unconditionally to the guests,
> > thus ensuring backward compatibility.
> >
> > In this patch, the framework adds the register only for ARM's standard
> > secure services (owner value 4). Currently, this includes support only
> > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > register representing mandatory features of v1.0. Other services are
> > momentarily added in the upcoming patches.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >   arch/arm64/include/asm/kvm_host.h | 12 ++++
> >   arch/arm64/include/uapi/asm/kvm.h |  9 +++
> >   arch/arm64/kvm/arm.c              |  1 +
> >   arch/arm64/kvm/guest.c            |  8 ++-
> >   arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> >   arch/arm64/kvm/psci.c             | 13 +++++
> >   include/kvm/arm_hypercalls.h      |  6 ++
> >   include/kvm/arm_psci.h            |  2 +-
> >   8 files changed, 142 insertions(+), 3 deletions(-)
> >
>
> Some nits as below, please consider to improve if you need another
> respin.
>
> Reviewed-by: Gavin Shan <gshan@redhat.com>
>
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 94a27a7520f4..df07f4c10197 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> >   struct kvm_arch_memory_slot {
> >   };
> >
> > +/**
> > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > + *
> > + * @std_bmap: Bitmap of standard secure service calls
> > + */
> > +struct kvm_smccc_features {
> > +     unsigned long std_bmap;
> > +};
> > +
>
> s/Descriptor/Descriptor of
>
Nice catch!

> >   struct kvm_arch {
> >       struct kvm_s2_mmu mmu;
> >
> > @@ -150,6 +159,9 @@ struct kvm_arch {
> >
> >       u8 pfr0_csv2;
> >       u8 pfr0_csv3;
> > +
> > +     /* Hypercall features firmware registers' descriptor */
> > +     struct kvm_smccc_features smccc_feat;
> >   };
> >
> >   struct kvm_vcpu_fault_info {
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> >   #define KVM_ARM64_SVE_VLS_WORDS     \
> >       ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> >
> > +/* Bitmap feature firmware registers */
> > +#define KVM_REG_ARM_FW_FEAT_BMAP             (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)              (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > +                                             KVM_REG_ARM_FW_FEAT_BMAP |      \
> > +                                             ((r) & 0xffff))
> > +
> > +#define KVM_REG_ARM_STD_BMAP                 KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0                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/arm.c b/arch/arm64/kvm/arm.c
> > index 523bc934fe2f..a37fadbd617e 100644
> > --- a/arch/arm64/kvm/arm.c
> > +++ b/arch/arm64/kvm/arm.c
> > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> >       kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> >
> >       set_default_spectre(kvm);
> > +     kvm_arm_init_hypercalls(kvm);
> >
> >       return ret;
> >   out_free_stage2_pgd:
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 0d5cca56cbda..8c607199cad1 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >       switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >       case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > -     case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > +     case KVM_REG_ARM_FW:
> > +     case KVM_REG_ARM_FW_FEAT_BMAP:
> > +             return kvm_arm_get_fw_reg(vcpu, reg);
> >       case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> >       }
> >
> > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >
> >       switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> >       case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > -     case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > +     case KVM_REG_ARM_FW:
> > +     case KVM_REG_ARM_FW_FEAT_BMAP:
> > +             return kvm_arm_set_fw_reg(vcpu, reg);
> >       case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> >       }
> >
> > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > index fa6d9378d8e7..df55a04d2fe8 100644
> > --- a/arch/arm64/kvm/hypercalls.c
> > +++ b/arch/arm64/kvm/hypercalls.c
> > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> >       val[3] = lower_32_bits(cycles);
> >   }
> >
> > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > +{
> > +     return test_bit(feat_bit, reg_bmap);
> > +}
> > +
>
> Might be worhty to be 'inline'. This function would be called
> frequently.
>
I was hoping the compiler would optimize it for us as needed.

> > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     switch (func_id) {
> > +     /*
> > +      * List of function-ids that are not gated with the bitmapped feature
> > +      * firmware registers, and are to be allowed for servicing the call by default.
> > +      */
> > +     case ARM_SMCCC_VERSION_FUNC_ID:
> > +     case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > +     case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > +     case ARM_SMCCC_HV_PV_TIME_ST:
> > +     case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +     case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > +     case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > +             return true;
> > +     default:
> > +             return kvm_psci_func_id_is_valid(vcpu, func_id);
> > +     }
> > +}
> > +
> > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > +
> > +     switch (func_id) {
> > +     case ARM_SMCCC_TRNG_VERSION:
> > +     case ARM_SMCCC_TRNG_FEATURES:
> > +     case ARM_SMCCC_TRNG_GET_UUID:
> > +     case ARM_SMCCC_TRNG_RND32:
> > +     case ARM_SMCCC_TRNG_RND64:
> > +             return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > +                                             KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > +     default:
> > +             return kvm_hvc_call_default_allowed(vcpu, func_id);
> > +     }
> > +}
> > +
> >   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >   {
> >       u32 func_id = smccc_get_function(vcpu);
> > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >       u32 feature;
> >       gpa_t gpa;
> >
> > +     if (!kvm_hvc_call_allowed(vcpu, func_id))
> > +             goto out;
> > +
> >       switch (func_id) {
> >       case ARM_SMCCC_VERSION_FUNC_ID:
> >               val[0] = ARM_SMCCC_VERSION_1_1;
> > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> >               return kvm_psci_call(vcpu);
> >       }
> >
> > +out:
> >       smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> >       return 1;
> >   }
> > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> >       KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > +     KVM_REG_ARM_STD_BMAP,
> >   };
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > +{
> > +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +
> > +     smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > +}
> > +
> >   int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> >   {
> >       return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> >
> >   int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >   {
> > +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> >       void __user *uaddr = (void __user *)(long)reg->addr;
> >       u64 val;
> >
> > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> >               val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> >               break;
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             val = READ_ONCE(smccc_feat->std_bmap);
> > +             break;
> >       default:
> >               return -ENOENT;
> >       }
> > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >       return 0;
> >   }
> >
> > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > +{
> > +     int ret = 0;
> > +     struct kvm *kvm = vcpu->kvm;
> > +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > +     unsigned long *fw_reg_bmap, fw_reg_features;
> > +
> > +     switch (reg_id) {
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             fw_reg_bmap = &smccc_feat->std_bmap;
> > +             fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > +             break;
> > +     default:
> > +             return -ENOENT;
> > +     }
> > +
> > +     /* Check for unsupported bit */
> > +     if (val & ~fw_reg_features)
> > +             return -EINVAL;
> > +
> > +     mutex_lock(&kvm->lock);
> > +
> > +     /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > +     if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > +             ret = -EBUSY;
> > +             goto out;
> > +     }
> > +
> > +     WRITE_ONCE(*fw_reg_bmap, val);
> > +out:
> > +     mutex_unlock(&kvm->lock);
> > +     return ret;
> > +}
> > +
> >   int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >   {
> >       void __user *uaddr = (void __user *)(long)reg->addr;
> > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >                       return -EINVAL;
> >
> >               return 0;
> > +     case KVM_REG_ARM_STD_BMAP:
> > +             return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> >       default:
> >               return -ENOENT;
> >       }
> > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > index 346535169faa..67d1273e8086 100644
> > --- a/arch/arm64/kvm/psci.c
> > +++ b/arch/arm64/kvm/psci.c
> > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> >               return -EINVAL;
> >       }
> >   }
> > +
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > +{
> > +     /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > +     if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > +             return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > +
> > +     if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > +             ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > +             return true;
> > +
> > +     return false;
> > +}
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index 5d38628a8d04..499b45b607b6 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -6,6 +6,11 @@
> >
> >   #include <asm/kvm_emulate.h>
> >
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
> > +
> > +#define KVM_ARM_SMCCC_STD_FEATURES           GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > +
>
> s/bits of/bit of
>
Great catch again!

> >   int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> >
> >   static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> >
> >   struct kvm_one_reg;
> >
> > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> >   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);
> > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > index 6e55b9283789..c47be3e26965 100644
> > --- a/include/kvm/arm_psci.h
> > +++ b/include/kvm/arm_psci.h
> > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> >       return KVM_ARM_PSCI_0_1;
> >   }
> >
> > -
> >   int kvm_psci_call(struct kvm_vcpu *vcpu);
> > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> >
> >   #endif /* __KVM_ARM_PSCI_H__ */
> >
>
> Thanks,
> Gavin
>

Thanks for the review, Gavin.

- Raghavendra

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
  2022-04-26  7:49     ` Gavin Shan
  (?)
@ 2022-04-26 16:59       ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-26 16:59 UTC (permalink / raw)
  To: Gavin Shan
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, kvm, Catalin Marinas, Peter Shier,
	linux-kernel, Paolo Bonzini, Will Deacon, kvmarm,
	linux-arm-kernel

Hi Gavin,

On Tue, Apr 26, 2022 at 12:50 AM Gavin Shan <gshan@redhat.com> wrote:
>
> Hi Raghavendra,
>
> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> > Introduce a KVM selftest to check the hypercall interface
> > for arm64 platforms. The test validates the user-space'
> > [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
> > registers as well as its effects on the guest upon certain
> > configurations.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >   tools/testing/selftests/kvm/.gitignore        |   1 +
> >   tools/testing/selftests/kvm/Makefile          |   1 +
> >   .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
> >   3 files changed, 337 insertions(+)
> >   create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
> >
>
> There are comments about @false_hvc_info[] and some nits, as below.
> Please evaluate and improve if it makes sense to you. Otherwise, it
> looks good to me:
>
> Reviewed-by: Gavin Shan <gshan@redhat.com>
>
> > diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
> > index 1bb575dfc42e..b17e464ec661 100644
> > --- a/tools/testing/selftests/kvm/.gitignore
> > +++ b/tools/testing/selftests/kvm/.gitignore
> > @@ -2,6 +2,7 @@
> >   /aarch64/arch_timer
> >   /aarch64/debug-exceptions
> >   /aarch64/get-reg-list
> > +/aarch64/hypercalls
> >   /aarch64/psci_test
> >   /aarch64/vcpu_width_config
> >   /aarch64/vgic_init
> > diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> > index c2cf4d318296..97eef0c03d3b 100644
> > --- a/tools/testing/selftests/kvm/Makefile
> > +++ b/tools/testing/selftests/kvm/Makefile
> > @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
> >   TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
> >   TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
> >   TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
> > +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
> >   TEST_GEN_PROGS_aarch64 += aarch64/psci_test
> >   TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
> >   TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
> > diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> > new file mode 100644
> > index 000000000000..f404343a0ae3
> > --- /dev/null
> > +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> > @@ -0,0 +1,335 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
> > + *
> > + * The test validates the basic hypercall functionalities that are exposed
> > + * via the psuedo-firmware bitmap register. This includes the registers'
> > + * read/write behavior before and after the VM has started, and if the
> > + * hypercalls are properly masked or unmasked to the guest when disabled or
> > + * enabled from the KVM userspace, respectively.
> > + */
> > +
> > +#include <errno.h>
> > +#include <linux/arm-smccc.h>
> > +#include <asm/kvm.h>
> > +#include <kvm_util.h>
> > +
> > +#include "processor.h"
> > +
> > +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
> > +
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
> > +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX     0
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX  1
> > +
> > +struct kvm_fw_reg_info {
> > +     uint64_t reg;           /* Register definition */
> > +     uint64_t max_feat_bit;  /* Bit that represents the upper limit of the feature-map */
> > +};
> > +
> > +#define FW_REG_INFO(r)                       \
> > +     {                                       \
> > +             .reg = r,                       \
> > +             .max_feat_bit = r##_BIT_MAX,    \
> > +     }
> > +
> > +static const struct kvm_fw_reg_info fw_reg_info[] = {
> > +     FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
> > +     FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
> > +     FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
> > +};
> > +
> > +enum test_stage {
> > +     TEST_STAGE_REG_IFACE,
> > +     TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
> > +     TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
> > +     TEST_STAGE_HVC_IFACE_FALSE_INFO,
> > +     TEST_STAGE_END,
> > +};
> > +
> > +static int stage = TEST_STAGE_REG_IFACE;
> > +
> > +struct test_hvc_info {
> > +     uint32_t func_id;
> > +     uint64_t arg1;
> > +};
> > +
> > +#define TEST_HVC_INFO(f, a1) \
> > +     {                       \
> > +             .func_id = f,   \
> > +             .arg1 = a1,     \
> > +     }
> > +
> > +static const struct test_hvc_info hvc_info[] = {
> > +     /* KVM_REG_ARM_STD_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
> > +
> > +     /* KVM_REG_ARM_STD_HYP_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
> > +
> > +     /* KVM_REG_ARM_VENDOR_HYP_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
> > +                     ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
> > +};
> > +
> > +/* Feed false hypercall info to test the KVM behavior */
> > +static const struct test_hvc_info false_hvc_info[] = {
> > +     /* Feature support check against a different family of hypercalls */
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> > +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
> > +};
> > +
>
> I don't see too much benefits of @false_hvc_info[] because
> NOT_SUPPORTED is always returned from its test case. I think
> it and its test case can be removed if you agree. I'm not
> sure if it was suggested by somebody else.
>
While this is not exactly testing the bitmap firmware registers, the
idea behind introducing false_hvc_info[] was to introduce some
negative tests and see if KVM handles it well. Especially with
*_FEATURES func_ids, we can accidentally introduce functional bugs in
KVM, and these would act as our safety net. I was planning to also
test with some reserved hypercall numbers, just to test if the kernel
doesn't panic for some reason.

> > +static void guest_test_hvc(const struct test_hvc_info *hc_info)
> > +{
> > +     unsigned int i;
> > +     struct arm_smccc_res res;
> > +     unsigned int hvc_info_arr_sz;
> > +
> > +     hvc_info_arr_sz =
> > +     hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
> > +
> > +     for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
> > +             memset(&res, 0, sizeof(res));
> > +             smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
> > +
> > +             switch (stage) {
> > +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +                     GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
> > +                                     res.a0, hc_info->func_id, hc_info->arg1);
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +                     GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
> > +                                     res.a0, hc_info->func_id, hc_info->arg1);
> > +                     break;
> > +             default:
> > +                     GUEST_ASSERT_1(0, stage);
> > +             }
> > +     }
> > +}
> > +
> > +static void guest_code(void)
> > +{
> > +     while (stage != TEST_STAGE_END) {
> > +             switch (stage) {
> > +             case TEST_STAGE_REG_IFACE:
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +                     guest_test_hvc(hvc_info);
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +                     guest_test_hvc(false_hvc_info);
> > +                     break;
> > +             default:
> > +                     GUEST_ASSERT_1(0, stage);
> > +             }
> > +
> > +             GUEST_SYNC(stage);
> > +     }
> > +
> > +     GUEST_DONE();
> > +}
> > +
> > +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
> > +{
> > +     struct kvm_one_reg reg = {
> > +             .id = id,
> > +             .addr = (uint64_t)&val,
> > +     };
> > +
> > +     return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
> > +}
> > +
> > +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
> > +{
> > +     struct kvm_one_reg reg = {
> > +             .id = id,
> > +             .addr = (uint64_t)addr,
> > +     };
> > +
> > +     vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
> > +}
> > +
> > +struct st_time {
> > +     uint32_t rev;
> > +     uint32_t attr;
> > +     uint64_t st_time;
> > +};
> > +
> > +#define STEAL_TIME_SIZE              ((sizeof(struct st_time) + 63) & ~63)
> > +#define ST_GPA_BASE          (1 << 30)
> > +
> > +static void steal_time_init(struct kvm_vm *vm)
> > +{
> > +     uint64_t st_ipa = (ulong)ST_GPA_BASE;
> > +     unsigned int gpages;
> > +     struct kvm_device_attr dev = {
> > +             .group = KVM_ARM_VCPU_PVTIME_CTRL,
> > +             .attr = KVM_ARM_VCPU_PVTIME_IPA,
> > +             .addr = (uint64_t)&st_ipa,
> > +     };
> > +
> > +     gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
> > +     vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
> > +
> > +     vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
> > +}
> > +
> > +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
> > +{
> > +     uint64_t val;
> > +     unsigned int i;
> > +     int ret;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> > +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> > +
> > +             /* First 'read' should be an upper limit of the features supported */
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
> > +                     "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
> > +                     reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
> > +
> > +             /* Test a 'write' by disabling all the features of the register map */
> > +             ret = set_fw_reg(vm, reg_info->reg, 0);
> > +             TEST_ASSERT(ret == 0,
> > +                     "Failed to clear all the features of reg: 0x%lx; ret: %d\n",
> > +                     reg_info->reg, errno);
> > +
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == 0,
> > +                     "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
> > +
> > +             /*
> > +              * Test enabling a feature that's not supported.
> > +              * Avoid this check if all the bits are occupied.
> > +              */
> > +             if (reg_info->max_feat_bit < 63) {
> > +                     ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
> > +                     TEST_ASSERT(ret != 0 && errno == EINVAL,
> > +                     "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
> > +                     errno, reg_info->reg);
> > +             }
> > +     }
> > +}
>
> Just in case :)
>
>       ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));
>
It may be better to cover the entire range, but to test only the
(max_feat_bit + 1) gives us the advantage of checking if there's any
discrepancy between the kernel and the test, now that *_BIT_MAX are
not a part of UAPI headers.

Probably also include your test along with the existing one?
>
> > +
> > +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
> > +{
> > +     uint64_t val;
> > +     unsigned int i;
> > +     int ret;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> > +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> > +
> > +             /*
> > +              * Before starting the VM, the test clears all the bits.
> > +              * Check if that's still the case.
> > +              */
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == 0,
> > +                     "Expected all the features to be cleared for reg: 0x%lx\n",
> > +                     reg_info->reg);
> > +
> > +             /*
> > +              * Set all the features for this register again. KVM shouldn't
> > +              * allow this as the VM is running.
> > +              */
> > +             ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
> > +             TEST_ASSERT(ret != 0 && errno == EBUSY,
> > +             "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
> > +             errno, reg_info->reg);
> > +     }
> > +}
> > +
>
> I guess you want to check -EBUSY is returned. In that case,
> the comments here could be clearer, something like below
> to emphasize '-EBUSY'.
>
>          /*
>           * After VM runs for once, -EBUSY should be returned on attempt
>           * to set features. Check if the correct errno is returned.
>           */
>
Sounds good.

> > +static struct kvm_vm *test_vm_create(void)
> > +{
> > +     struct kvm_vm *vm;
> > +
> > +     vm = vm_create_default(0, 0, guest_code);
> > +
> > +     ucall_init(vm, NULL);
> > +     steal_time_init(vm);
> > +
> > +     return vm;
> > +}
> > +
> > +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
> > +{
> > +     struct kvm_vm *ret_vm = vm;
> > +
> > +     pr_debug("Stage: %d\n", stage);
> > +
> > +     switch (stage) {
> > +     case TEST_STAGE_REG_IFACE:
> > +             test_fw_regs_after_vm_start(vm);
> > +             break;
> > +     case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             /* Start a new VM so that all the features are now enabled by default */
> > +             kvm_vm_free(vm);
> > +             ret_vm = test_vm_create();
> > +             break;
> > +     case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +     case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +             break;
> > +     default:
> > +             TEST_FAIL("Unknown test stage: %d\n", stage);
> > +     }
> > +
> > +     stage++;
> > +     sync_global_to_guest(vm, stage);
> > +
> > +     return ret_vm;
> > +}
> > +
> > +static void test_run(void)
> > +{
> > +     struct kvm_vm *vm;
> > +     struct ucall uc;
> > +     bool guest_done = false;
> > +
> > +     vm = test_vm_create();
> > +
> > +     test_fw_regs_before_vm_start(vm);
> > +
> > +     while (!guest_done) {
> > +             vcpu_run(vm, 0);
> > +
> > +             switch (get_ucall(vm, 0, &uc)) {
> > +             case UCALL_SYNC:
> > +                     vm = test_guest_stage(vm);
> > +                     break;
> > +             case UCALL_DONE:
> > +                     guest_done = true;
> > +                     break;
> > +             case UCALL_ABORT:
> > +                     TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
> > +                     (const char *)uc.args[0], __FILE__, uc.args[1],
> > +                     uc.args[2], uc.args[3], uc.args[4], stage);
> > +                     break;
> > +             default:
> > +                     TEST_FAIL("Unexpected guest exit\n");
> > +             }
> > +     }
> > +
> > +     kvm_vm_free(vm);
> > +}
> > +
> > +int main(void)
> > +{
> > +     setbuf(stdout, NULL);
> > +
> > +     test_run();
> > +     return 0;
> > +}
> >
>
> Thanks,
> Gavin
>
Thanks for the reviews on all the patches, Gavin.

Regards,
Raghavendra

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

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
@ 2022-04-26 16:59       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-26 16:59 UTC (permalink / raw)
  To: Gavin Shan
  Cc: kvm, Marc Zyngier, Peter Shier, linux-kernel, Will Deacon,
	Catalin Marinas, Paolo Bonzini, kvmarm, linux-arm-kernel

Hi Gavin,

On Tue, Apr 26, 2022 at 12:50 AM Gavin Shan <gshan@redhat.com> wrote:
>
> Hi Raghavendra,
>
> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> > Introduce a KVM selftest to check the hypercall interface
> > for arm64 platforms. The test validates the user-space'
> > [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
> > registers as well as its effects on the guest upon certain
> > configurations.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >   tools/testing/selftests/kvm/.gitignore        |   1 +
> >   tools/testing/selftests/kvm/Makefile          |   1 +
> >   .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
> >   3 files changed, 337 insertions(+)
> >   create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
> >
>
> There are comments about @false_hvc_info[] and some nits, as below.
> Please evaluate and improve if it makes sense to you. Otherwise, it
> looks good to me:
>
> Reviewed-by: Gavin Shan <gshan@redhat.com>
>
> > diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
> > index 1bb575dfc42e..b17e464ec661 100644
> > --- a/tools/testing/selftests/kvm/.gitignore
> > +++ b/tools/testing/selftests/kvm/.gitignore
> > @@ -2,6 +2,7 @@
> >   /aarch64/arch_timer
> >   /aarch64/debug-exceptions
> >   /aarch64/get-reg-list
> > +/aarch64/hypercalls
> >   /aarch64/psci_test
> >   /aarch64/vcpu_width_config
> >   /aarch64/vgic_init
> > diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> > index c2cf4d318296..97eef0c03d3b 100644
> > --- a/tools/testing/selftests/kvm/Makefile
> > +++ b/tools/testing/selftests/kvm/Makefile
> > @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
> >   TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
> >   TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
> >   TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
> > +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
> >   TEST_GEN_PROGS_aarch64 += aarch64/psci_test
> >   TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
> >   TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
> > diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> > new file mode 100644
> > index 000000000000..f404343a0ae3
> > --- /dev/null
> > +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> > @@ -0,0 +1,335 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
> > + *
> > + * The test validates the basic hypercall functionalities that are exposed
> > + * via the psuedo-firmware bitmap register. This includes the registers'
> > + * read/write behavior before and after the VM has started, and if the
> > + * hypercalls are properly masked or unmasked to the guest when disabled or
> > + * enabled from the KVM userspace, respectively.
> > + */
> > +
> > +#include <errno.h>
> > +#include <linux/arm-smccc.h>
> > +#include <asm/kvm.h>
> > +#include <kvm_util.h>
> > +
> > +#include "processor.h"
> > +
> > +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
> > +
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
> > +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX     0
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX  1
> > +
> > +struct kvm_fw_reg_info {
> > +     uint64_t reg;           /* Register definition */
> > +     uint64_t max_feat_bit;  /* Bit that represents the upper limit of the feature-map */
> > +};
> > +
> > +#define FW_REG_INFO(r)                       \
> > +     {                                       \
> > +             .reg = r,                       \
> > +             .max_feat_bit = r##_BIT_MAX,    \
> > +     }
> > +
> > +static const struct kvm_fw_reg_info fw_reg_info[] = {
> > +     FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
> > +     FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
> > +     FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
> > +};
> > +
> > +enum test_stage {
> > +     TEST_STAGE_REG_IFACE,
> > +     TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
> > +     TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
> > +     TEST_STAGE_HVC_IFACE_FALSE_INFO,
> > +     TEST_STAGE_END,
> > +};
> > +
> > +static int stage = TEST_STAGE_REG_IFACE;
> > +
> > +struct test_hvc_info {
> > +     uint32_t func_id;
> > +     uint64_t arg1;
> > +};
> > +
> > +#define TEST_HVC_INFO(f, a1) \
> > +     {                       \
> > +             .func_id = f,   \
> > +             .arg1 = a1,     \
> > +     }
> > +
> > +static const struct test_hvc_info hvc_info[] = {
> > +     /* KVM_REG_ARM_STD_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
> > +
> > +     /* KVM_REG_ARM_STD_HYP_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
> > +
> > +     /* KVM_REG_ARM_VENDOR_HYP_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
> > +                     ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
> > +};
> > +
> > +/* Feed false hypercall info to test the KVM behavior */
> > +static const struct test_hvc_info false_hvc_info[] = {
> > +     /* Feature support check against a different family of hypercalls */
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> > +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
> > +};
> > +
>
> I don't see too much benefits of @false_hvc_info[] because
> NOT_SUPPORTED is always returned from its test case. I think
> it and its test case can be removed if you agree. I'm not
> sure if it was suggested by somebody else.
>
While this is not exactly testing the bitmap firmware registers, the
idea behind introducing false_hvc_info[] was to introduce some
negative tests and see if KVM handles it well. Especially with
*_FEATURES func_ids, we can accidentally introduce functional bugs in
KVM, and these would act as our safety net. I was planning to also
test with some reserved hypercall numbers, just to test if the kernel
doesn't panic for some reason.

> > +static void guest_test_hvc(const struct test_hvc_info *hc_info)
> > +{
> > +     unsigned int i;
> > +     struct arm_smccc_res res;
> > +     unsigned int hvc_info_arr_sz;
> > +
> > +     hvc_info_arr_sz =
> > +     hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
> > +
> > +     for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
> > +             memset(&res, 0, sizeof(res));
> > +             smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
> > +
> > +             switch (stage) {
> > +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +                     GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
> > +                                     res.a0, hc_info->func_id, hc_info->arg1);
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +                     GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
> > +                                     res.a0, hc_info->func_id, hc_info->arg1);
> > +                     break;
> > +             default:
> > +                     GUEST_ASSERT_1(0, stage);
> > +             }
> > +     }
> > +}
> > +
> > +static void guest_code(void)
> > +{
> > +     while (stage != TEST_STAGE_END) {
> > +             switch (stage) {
> > +             case TEST_STAGE_REG_IFACE:
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +                     guest_test_hvc(hvc_info);
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +                     guest_test_hvc(false_hvc_info);
> > +                     break;
> > +             default:
> > +                     GUEST_ASSERT_1(0, stage);
> > +             }
> > +
> > +             GUEST_SYNC(stage);
> > +     }
> > +
> > +     GUEST_DONE();
> > +}
> > +
> > +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
> > +{
> > +     struct kvm_one_reg reg = {
> > +             .id = id,
> > +             .addr = (uint64_t)&val,
> > +     };
> > +
> > +     return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
> > +}
> > +
> > +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
> > +{
> > +     struct kvm_one_reg reg = {
> > +             .id = id,
> > +             .addr = (uint64_t)addr,
> > +     };
> > +
> > +     vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
> > +}
> > +
> > +struct st_time {
> > +     uint32_t rev;
> > +     uint32_t attr;
> > +     uint64_t st_time;
> > +};
> > +
> > +#define STEAL_TIME_SIZE              ((sizeof(struct st_time) + 63) & ~63)
> > +#define ST_GPA_BASE          (1 << 30)
> > +
> > +static void steal_time_init(struct kvm_vm *vm)
> > +{
> > +     uint64_t st_ipa = (ulong)ST_GPA_BASE;
> > +     unsigned int gpages;
> > +     struct kvm_device_attr dev = {
> > +             .group = KVM_ARM_VCPU_PVTIME_CTRL,
> > +             .attr = KVM_ARM_VCPU_PVTIME_IPA,
> > +             .addr = (uint64_t)&st_ipa,
> > +     };
> > +
> > +     gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
> > +     vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
> > +
> > +     vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
> > +}
> > +
> > +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
> > +{
> > +     uint64_t val;
> > +     unsigned int i;
> > +     int ret;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> > +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> > +
> > +             /* First 'read' should be an upper limit of the features supported */
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
> > +                     "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
> > +                     reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
> > +
> > +             /* Test a 'write' by disabling all the features of the register map */
> > +             ret = set_fw_reg(vm, reg_info->reg, 0);
> > +             TEST_ASSERT(ret == 0,
> > +                     "Failed to clear all the features of reg: 0x%lx; ret: %d\n",
> > +                     reg_info->reg, errno);
> > +
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == 0,
> > +                     "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
> > +
> > +             /*
> > +              * Test enabling a feature that's not supported.
> > +              * Avoid this check if all the bits are occupied.
> > +              */
> > +             if (reg_info->max_feat_bit < 63) {
> > +                     ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
> > +                     TEST_ASSERT(ret != 0 && errno == EINVAL,
> > +                     "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
> > +                     errno, reg_info->reg);
> > +             }
> > +     }
> > +}
>
> Just in case :)
>
>       ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));
>
It may be better to cover the entire range, but to test only the
(max_feat_bit + 1) gives us the advantage of checking if there's any
discrepancy between the kernel and the test, now that *_BIT_MAX are
not a part of UAPI headers.

Probably also include your test along with the existing one?
>
> > +
> > +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
> > +{
> > +     uint64_t val;
> > +     unsigned int i;
> > +     int ret;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> > +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> > +
> > +             /*
> > +              * Before starting the VM, the test clears all the bits.
> > +              * Check if that's still the case.
> > +              */
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == 0,
> > +                     "Expected all the features to be cleared for reg: 0x%lx\n",
> > +                     reg_info->reg);
> > +
> > +             /*
> > +              * Set all the features for this register again. KVM shouldn't
> > +              * allow this as the VM is running.
> > +              */
> > +             ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
> > +             TEST_ASSERT(ret != 0 && errno == EBUSY,
> > +             "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
> > +             errno, reg_info->reg);
> > +     }
> > +}
> > +
>
> I guess you want to check -EBUSY is returned. In that case,
> the comments here could be clearer, something like below
> to emphasize '-EBUSY'.
>
>          /*
>           * After VM runs for once, -EBUSY should be returned on attempt
>           * to set features. Check if the correct errno is returned.
>           */
>
Sounds good.

> > +static struct kvm_vm *test_vm_create(void)
> > +{
> > +     struct kvm_vm *vm;
> > +
> > +     vm = vm_create_default(0, 0, guest_code);
> > +
> > +     ucall_init(vm, NULL);
> > +     steal_time_init(vm);
> > +
> > +     return vm;
> > +}
> > +
> > +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
> > +{
> > +     struct kvm_vm *ret_vm = vm;
> > +
> > +     pr_debug("Stage: %d\n", stage);
> > +
> > +     switch (stage) {
> > +     case TEST_STAGE_REG_IFACE:
> > +             test_fw_regs_after_vm_start(vm);
> > +             break;
> > +     case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             /* Start a new VM so that all the features are now enabled by default */
> > +             kvm_vm_free(vm);
> > +             ret_vm = test_vm_create();
> > +             break;
> > +     case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +     case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +             break;
> > +     default:
> > +             TEST_FAIL("Unknown test stage: %d\n", stage);
> > +     }
> > +
> > +     stage++;
> > +     sync_global_to_guest(vm, stage);
> > +
> > +     return ret_vm;
> > +}
> > +
> > +static void test_run(void)
> > +{
> > +     struct kvm_vm *vm;
> > +     struct ucall uc;
> > +     bool guest_done = false;
> > +
> > +     vm = test_vm_create();
> > +
> > +     test_fw_regs_before_vm_start(vm);
> > +
> > +     while (!guest_done) {
> > +             vcpu_run(vm, 0);
> > +
> > +             switch (get_ucall(vm, 0, &uc)) {
> > +             case UCALL_SYNC:
> > +                     vm = test_guest_stage(vm);
> > +                     break;
> > +             case UCALL_DONE:
> > +                     guest_done = true;
> > +                     break;
> > +             case UCALL_ABORT:
> > +                     TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
> > +                     (const char *)uc.args[0], __FILE__, uc.args[1],
> > +                     uc.args[2], uc.args[3], uc.args[4], stage);
> > +                     break;
> > +             default:
> > +                     TEST_FAIL("Unexpected guest exit\n");
> > +             }
> > +     }
> > +
> > +     kvm_vm_free(vm);
> > +}
> > +
> > +int main(void)
> > +{
> > +     setbuf(stdout, NULL);
> > +
> > +     test_run();
> > +     return 0;
> > +}
> >
>
> Thanks,
> Gavin
>
Thanks for the reviews on all the patches, Gavin.

Regards,
Raghavendra
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
@ 2022-04-26 16:59       ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-26 16:59 UTC (permalink / raw)
  To: Gavin Shan
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, kvm, Catalin Marinas, Peter Shier,
	linux-kernel, Paolo Bonzini, Will Deacon, kvmarm,
	linux-arm-kernel

Hi Gavin,

On Tue, Apr 26, 2022 at 12:50 AM Gavin Shan <gshan@redhat.com> wrote:
>
> Hi Raghavendra,
>
> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
> > Introduce a KVM selftest to check the hypercall interface
> > for arm64 platforms. The test validates the user-space'
> > [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
> > registers as well as its effects on the guest upon certain
> > configurations.
> >
> > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > ---
> >   tools/testing/selftests/kvm/.gitignore        |   1 +
> >   tools/testing/selftests/kvm/Makefile          |   1 +
> >   .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
> >   3 files changed, 337 insertions(+)
> >   create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
> >
>
> There are comments about @false_hvc_info[] and some nits, as below.
> Please evaluate and improve if it makes sense to you. Otherwise, it
> looks good to me:
>
> Reviewed-by: Gavin Shan <gshan@redhat.com>
>
> > diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
> > index 1bb575dfc42e..b17e464ec661 100644
> > --- a/tools/testing/selftests/kvm/.gitignore
> > +++ b/tools/testing/selftests/kvm/.gitignore
> > @@ -2,6 +2,7 @@
> >   /aarch64/arch_timer
> >   /aarch64/debug-exceptions
> >   /aarch64/get-reg-list
> > +/aarch64/hypercalls
> >   /aarch64/psci_test
> >   /aarch64/vcpu_width_config
> >   /aarch64/vgic_init
> > diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> > index c2cf4d318296..97eef0c03d3b 100644
> > --- a/tools/testing/selftests/kvm/Makefile
> > +++ b/tools/testing/selftests/kvm/Makefile
> > @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
> >   TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
> >   TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
> >   TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
> > +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
> >   TEST_GEN_PROGS_aarch64 += aarch64/psci_test
> >   TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
> >   TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
> > diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> > new file mode 100644
> > index 000000000000..f404343a0ae3
> > --- /dev/null
> > +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
> > @@ -0,0 +1,335 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
> > + *
> > + * The test validates the basic hypercall functionalities that are exposed
> > + * via the psuedo-firmware bitmap register. This includes the registers'
> > + * read/write behavior before and after the VM has started, and if the
> > + * hypercalls are properly masked or unmasked to the guest when disabled or
> > + * enabled from the KVM userspace, respectively.
> > + */
> > +
> > +#include <errno.h>
> > +#include <linux/arm-smccc.h>
> > +#include <asm/kvm.h>
> > +#include <kvm_util.h>
> > +
> > +#include "processor.h"
> > +
> > +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
> > +
> > +/* Last valid bits of the bitmapped firmware registers */
> > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
> > +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX     0
> > +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX  1
> > +
> > +struct kvm_fw_reg_info {
> > +     uint64_t reg;           /* Register definition */
> > +     uint64_t max_feat_bit;  /* Bit that represents the upper limit of the feature-map */
> > +};
> > +
> > +#define FW_REG_INFO(r)                       \
> > +     {                                       \
> > +             .reg = r,                       \
> > +             .max_feat_bit = r##_BIT_MAX,    \
> > +     }
> > +
> > +static const struct kvm_fw_reg_info fw_reg_info[] = {
> > +     FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
> > +     FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
> > +     FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
> > +};
> > +
> > +enum test_stage {
> > +     TEST_STAGE_REG_IFACE,
> > +     TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
> > +     TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
> > +     TEST_STAGE_HVC_IFACE_FALSE_INFO,
> > +     TEST_STAGE_END,
> > +};
> > +
> > +static int stage = TEST_STAGE_REG_IFACE;
> > +
> > +struct test_hvc_info {
> > +     uint32_t func_id;
> > +     uint64_t arg1;
> > +};
> > +
> > +#define TEST_HVC_INFO(f, a1) \
> > +     {                       \
> > +             .func_id = f,   \
> > +             .arg1 = a1,     \
> > +     }
> > +
> > +static const struct test_hvc_info hvc_info[] = {
> > +     /* KVM_REG_ARM_STD_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
> > +
> > +     /* KVM_REG_ARM_STD_HYP_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
> > +
> > +     /* KVM_REG_ARM_VENDOR_HYP_BMAP */
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
> > +                     ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
> > +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
> > +};
> > +
> > +/* Feed false hypercall info to test the KVM behavior */
> > +static const struct test_hvc_info false_hvc_info[] = {
> > +     /* Feature support check against a different family of hypercalls */
> > +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
> > +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
> > +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
> > +};
> > +
>
> I don't see too much benefits of @false_hvc_info[] because
> NOT_SUPPORTED is always returned from its test case. I think
> it and its test case can be removed if you agree. I'm not
> sure if it was suggested by somebody else.
>
While this is not exactly testing the bitmap firmware registers, the
idea behind introducing false_hvc_info[] was to introduce some
negative tests and see if KVM handles it well. Especially with
*_FEATURES func_ids, we can accidentally introduce functional bugs in
KVM, and these would act as our safety net. I was planning to also
test with some reserved hypercall numbers, just to test if the kernel
doesn't panic for some reason.

> > +static void guest_test_hvc(const struct test_hvc_info *hc_info)
> > +{
> > +     unsigned int i;
> > +     struct arm_smccc_res res;
> > +     unsigned int hvc_info_arr_sz;
> > +
> > +     hvc_info_arr_sz =
> > +     hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
> > +
> > +     for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
> > +             memset(&res, 0, sizeof(res));
> > +             smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
> > +
> > +             switch (stage) {
> > +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +                     GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
> > +                                     res.a0, hc_info->func_id, hc_info->arg1);
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +                     GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
> > +                                     res.a0, hc_info->func_id, hc_info->arg1);
> > +                     break;
> > +             default:
> > +                     GUEST_ASSERT_1(0, stage);
> > +             }
> > +     }
> > +}
> > +
> > +static void guest_code(void)
> > +{
> > +     while (stage != TEST_STAGE_END) {
> > +             switch (stage) {
> > +             case TEST_STAGE_REG_IFACE:
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +                     guest_test_hvc(hvc_info);
> > +                     break;
> > +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +                     guest_test_hvc(false_hvc_info);
> > +                     break;
> > +             default:
> > +                     GUEST_ASSERT_1(0, stage);
> > +             }
> > +
> > +             GUEST_SYNC(stage);
> > +     }
> > +
> > +     GUEST_DONE();
> > +}
> > +
> > +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
> > +{
> > +     struct kvm_one_reg reg = {
> > +             .id = id,
> > +             .addr = (uint64_t)&val,
> > +     };
> > +
> > +     return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
> > +}
> > +
> > +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
> > +{
> > +     struct kvm_one_reg reg = {
> > +             .id = id,
> > +             .addr = (uint64_t)addr,
> > +     };
> > +
> > +     vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
> > +}
> > +
> > +struct st_time {
> > +     uint32_t rev;
> > +     uint32_t attr;
> > +     uint64_t st_time;
> > +};
> > +
> > +#define STEAL_TIME_SIZE              ((sizeof(struct st_time) + 63) & ~63)
> > +#define ST_GPA_BASE          (1 << 30)
> > +
> > +static void steal_time_init(struct kvm_vm *vm)
> > +{
> > +     uint64_t st_ipa = (ulong)ST_GPA_BASE;
> > +     unsigned int gpages;
> > +     struct kvm_device_attr dev = {
> > +             .group = KVM_ARM_VCPU_PVTIME_CTRL,
> > +             .attr = KVM_ARM_VCPU_PVTIME_IPA,
> > +             .addr = (uint64_t)&st_ipa,
> > +     };
> > +
> > +     gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
> > +     vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
> > +
> > +     vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
> > +}
> > +
> > +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
> > +{
> > +     uint64_t val;
> > +     unsigned int i;
> > +     int ret;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> > +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> > +
> > +             /* First 'read' should be an upper limit of the features supported */
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
> > +                     "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
> > +                     reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
> > +
> > +             /* Test a 'write' by disabling all the features of the register map */
> > +             ret = set_fw_reg(vm, reg_info->reg, 0);
> > +             TEST_ASSERT(ret == 0,
> > +                     "Failed to clear all the features of reg: 0x%lx; ret: %d\n",
> > +                     reg_info->reg, errno);
> > +
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == 0,
> > +                     "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
> > +
> > +             /*
> > +              * Test enabling a feature that's not supported.
> > +              * Avoid this check if all the bits are occupied.
> > +              */
> > +             if (reg_info->max_feat_bit < 63) {
> > +                     ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
> > +                     TEST_ASSERT(ret != 0 && errno == EINVAL,
> > +                     "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
> > +                     errno, reg_info->reg);
> > +             }
> > +     }
> > +}
>
> Just in case :)
>
>       ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));
>
It may be better to cover the entire range, but to test only the
(max_feat_bit + 1) gives us the advantage of checking if there's any
discrepancy between the kernel and the test, now that *_BIT_MAX are
not a part of UAPI headers.

Probably also include your test along with the existing one?
>
> > +
> > +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
> > +{
> > +     uint64_t val;
> > +     unsigned int i;
> > +     int ret;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
> > +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
> > +
> > +             /*
> > +              * Before starting the VM, the test clears all the bits.
> > +              * Check if that's still the case.
> > +              */
> > +             get_fw_reg(vm, reg_info->reg, &val);
> > +             TEST_ASSERT(val == 0,
> > +                     "Expected all the features to be cleared for reg: 0x%lx\n",
> > +                     reg_info->reg);
> > +
> > +             /*
> > +              * Set all the features for this register again. KVM shouldn't
> > +              * allow this as the VM is running.
> > +              */
> > +             ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
> > +             TEST_ASSERT(ret != 0 && errno == EBUSY,
> > +             "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
> > +             errno, reg_info->reg);
> > +     }
> > +}
> > +
>
> I guess you want to check -EBUSY is returned. In that case,
> the comments here could be clearer, something like below
> to emphasize '-EBUSY'.
>
>          /*
>           * After VM runs for once, -EBUSY should be returned on attempt
>           * to set features. Check if the correct errno is returned.
>           */
>
Sounds good.

> > +static struct kvm_vm *test_vm_create(void)
> > +{
> > +     struct kvm_vm *vm;
> > +
> > +     vm = vm_create_default(0, 0, guest_code);
> > +
> > +     ucall_init(vm, NULL);
> > +     steal_time_init(vm);
> > +
> > +     return vm;
> > +}
> > +
> > +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
> > +{
> > +     struct kvm_vm *ret_vm = vm;
> > +
> > +     pr_debug("Stage: %d\n", stage);
> > +
> > +     switch (stage) {
> > +     case TEST_STAGE_REG_IFACE:
> > +             test_fw_regs_after_vm_start(vm);
> > +             break;
> > +     case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
> > +             /* Start a new VM so that all the features are now enabled by default */
> > +             kvm_vm_free(vm);
> > +             ret_vm = test_vm_create();
> > +             break;
> > +     case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
> > +     case TEST_STAGE_HVC_IFACE_FALSE_INFO:
> > +             break;
> > +     default:
> > +             TEST_FAIL("Unknown test stage: %d\n", stage);
> > +     }
> > +
> > +     stage++;
> > +     sync_global_to_guest(vm, stage);
> > +
> > +     return ret_vm;
> > +}
> > +
> > +static void test_run(void)
> > +{
> > +     struct kvm_vm *vm;
> > +     struct ucall uc;
> > +     bool guest_done = false;
> > +
> > +     vm = test_vm_create();
> > +
> > +     test_fw_regs_before_vm_start(vm);
> > +
> > +     while (!guest_done) {
> > +             vcpu_run(vm, 0);
> > +
> > +             switch (get_ucall(vm, 0, &uc)) {
> > +             case UCALL_SYNC:
> > +                     vm = test_guest_stage(vm);
> > +                     break;
> > +             case UCALL_DONE:
> > +                     guest_done = true;
> > +                     break;
> > +             case UCALL_ABORT:
> > +                     TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
> > +                     (const char *)uc.args[0], __FILE__, uc.args[1],
> > +                     uc.args[2], uc.args[3], uc.args[4], stage);
> > +                     break;
> > +             default:
> > +                     TEST_FAIL("Unexpected guest exit\n");
> > +             }
> > +     }
> > +
> > +     kvm_vm_free(vm);
> > +}
> > +
> > +int main(void)
> > +{
> > +     setbuf(stdout, NULL);
> > +
> > +     test_run();
> > +     return 0;
> > +}
> >
>
> Thanks,
> Gavin
>
Thanks for the reviews on all the patches, Gavin.

Regards,
Raghavendra

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  2022-04-26 16:44       ` Raghavendra Rao Ananta
  (?)
@ 2022-04-27  1:38         ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-27  1:38 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, kvm, Catalin Marinas, Peter Shier,
	linux-kernel, Paolo Bonzini, Will Deacon, kvmarm,
	linux-arm-kernel

Hi Raghavendra,

On 4/27/22 12:44 AM, Raghavendra Rao Ananta wrote:
> On Mon, Apr 25, 2022 at 11:34 PM Gavin Shan <gshan@redhat.com> wrote:
>> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
>>> KVM regularly introduces new hypercall services to the guests without
>>> any consent from the userspace. This means, the guests can observe
>>> hypercall services in and out as they migrate across various host
>>> kernel versions. This could be a major problem if the guest
>>> discovered a hypercall, started using it, and after getting migrated
>>> to an older kernel realizes that it's no longer available. Depending
>>> on how the guest handles the change, there's a potential chance that
>>> the guest would just panic.
>>>
>>> As a result, there's a need for the userspace to elect the services
>>> that it wishes the guest to discover. It can elect these services
>>> based on the kernels spread across its (migration) fleet. To remedy
>>> this, extend the existing firmware pseudo-registers, such as
>>> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
>>> for all the hypercall services available.
>>>
>>> These firmware registers are categorized based on the service call
>>> owners, but unlike the existing firmware pseudo-registers, they hold
>>> the features supported in the form of a bitmap.
>>>
>>> During the VM initialization, the registers are set to upper-limit of
>>> the features supported by the corresponding registers. It's expected
>>> that the VMMs discover the features provided by each register via
>>> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
>>> KVM allows this modification only until the VM has started.
>>>
>>> Some of the standard features are not mapped to any bits of the
>>> registers. But since they can recreate the original problem of
>>> making it available without userspace's consent, they need to
>>> be explicitly added to the case-list in
>>> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
>>> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
>>> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
>>>
>>> Older userspace code can simply ignore the feature and the
>>> hypercall services will be exposed unconditionally to the guests,
>>> thus ensuring backward compatibility.
>>>
>>> In this patch, the framework adds the register only for ARM's standard
>>> secure services (owner value 4). Currently, this includes support only
>>> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
>>> register representing mandatory features of v1.0. Other services are
>>> momentarily added in the upcoming patches.
>>>
>>> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
>>> ---
>>>    arch/arm64/include/asm/kvm_host.h | 12 ++++
>>>    arch/arm64/include/uapi/asm/kvm.h |  9 +++
>>>    arch/arm64/kvm/arm.c              |  1 +
>>>    arch/arm64/kvm/guest.c            |  8 ++-
>>>    arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>>>    arch/arm64/kvm/psci.c             | 13 +++++
>>>    include/kvm/arm_hypercalls.h      |  6 ++
>>>    include/kvm/arm_psci.h            |  2 +-
>>>    8 files changed, 142 insertions(+), 3 deletions(-)
>>>
>>
>> Some nits as below, please consider to improve if you need another
>> respin.
>>
>> Reviewed-by: Gavin Shan <gshan@redhat.com>
>>
>>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>>> index 94a27a7520f4..df07f4c10197 100644
>>> --- a/arch/arm64/include/asm/kvm_host.h
>>> +++ b/arch/arm64/include/asm/kvm_host.h
>>> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>>>    struct kvm_arch_memory_slot {
>>>    };
>>>
>>> +/**
>>> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
>>> + *
>>> + * @std_bmap: Bitmap of standard secure service calls
>>> + */
>>> +struct kvm_smccc_features {
>>> +     unsigned long std_bmap;
>>> +};
>>> +
>>
>> s/Descriptor/Descriptor of
>>
> Nice catch!
> 
>>>    struct kvm_arch {
>>>        struct kvm_s2_mmu mmu;
>>>
>>> @@ -150,6 +159,9 @@ struct kvm_arch {
>>>
>>>        u8 pfr0_csv2;
>>>        u8 pfr0_csv3;
>>> +
>>> +     /* Hypercall features firmware registers' descriptor */
>>> +     struct kvm_smccc_features smccc_feat;
>>>    };
>>>
>>>    struct kvm_vcpu_fault_info {
>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>>> index c1b6ddc02d2f..0b79d2dc6ffd 100644
>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>>>    #define KVM_ARM64_SVE_VLS_WORDS     \
>>>        ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>>>
>>> +/* Bitmap feature firmware registers */
>>> +#define KVM_REG_ARM_FW_FEAT_BMAP             (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
>>> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)              (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
>>> +                                             KVM_REG_ARM_FW_FEAT_BMAP |      \
>>> +                                             ((r) & 0xffff))
>>> +
>>> +#define KVM_REG_ARM_STD_BMAP                 KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
>>> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0                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/arm.c b/arch/arm64/kvm/arm.c
>>> index 523bc934fe2f..a37fadbd617e 100644
>>> --- a/arch/arm64/kvm/arm.c
>>> +++ b/arch/arm64/kvm/arm.c
>>> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>>>        kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>>>
>>>        set_default_spectre(kvm);
>>> +     kvm_arm_init_hypercalls(kvm);
>>>
>>>        return ret;
>>>    out_free_stage2_pgd:
>>> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
>>> index 0d5cca56cbda..8c607199cad1 100644
>>> --- a/arch/arm64/kvm/guest.c
>>> +++ b/arch/arm64/kvm/guest.c
>>> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>
>>>        switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>>>        case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
>>> -     case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
>>> +     case KVM_REG_ARM_FW:
>>> +     case KVM_REG_ARM_FW_FEAT_BMAP:
>>> +             return kvm_arm_get_fw_reg(vcpu, reg);
>>>        case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
>>>        }
>>>
>>> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>
>>>        switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>>>        case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
>>> -     case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
>>> +     case KVM_REG_ARM_FW:
>>> +     case KVM_REG_ARM_FW_FEAT_BMAP:
>>> +             return kvm_arm_set_fw_reg(vcpu, reg);
>>>        case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
>>>        }
>>>
>>> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
>>> index fa6d9378d8e7..df55a04d2fe8 100644
>>> --- a/arch/arm64/kvm/hypercalls.c
>>> +++ b/arch/arm64/kvm/hypercalls.c
>>> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>>>        val[3] = lower_32_bits(cycles);
>>>    }
>>>
>>> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
>>> +{
>>> +     return test_bit(feat_bit, reg_bmap);
>>> +}
>>> +
>>
>> Might be worhty to be 'inline'. This function would be called
>> frequently.
>>
> I was hoping the compiler would optimize it for us as needed.
> 

Yeah, GCC is smart enough. It could be compiled to inline function
even it's not specified explicitly. I guess __always_inline can be
used here. However, it seems __always_inline isn't used broadly in
kvm/arm64 scope. Anyway, it's not a big deal in this specific case :)

>>> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     switch (func_id) {
>>> +     /*
>>> +      * List of function-ids that are not gated with the bitmapped feature
>>> +      * firmware registers, and are to be allowed for servicing the call by default.
>>> +      */
>>> +     case ARM_SMCCC_VERSION_FUNC_ID:
>>> +     case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
>>> +     case ARM_SMCCC_HV_PV_TIME_FEATURES:
>>> +     case ARM_SMCCC_HV_PV_TIME_ST:
>>> +     case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
>>> +     case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
>>> +     case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>>> +             return true;
>>> +     default:
>>> +             return kvm_psci_func_id_is_valid(vcpu, func_id);
>>> +     }
>>> +}
>>> +
>>> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>>> +
>>> +     switch (func_id) {
>>> +     case ARM_SMCCC_TRNG_VERSION:
>>> +     case ARM_SMCCC_TRNG_FEATURES:
>>> +     case ARM_SMCCC_TRNG_GET_UUID:
>>> +     case ARM_SMCCC_TRNG_RND32:
>>> +     case ARM_SMCCC_TRNG_RND64:
>>> +             return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
>>> +                                             KVM_REG_ARM_STD_BIT_TRNG_V1_0);
>>> +     default:
>>> +             return kvm_hvc_call_default_allowed(vcpu, func_id);
>>> +     }
>>> +}
>>> +
>>>    int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>    {
>>>        u32 func_id = smccc_get_function(vcpu);
>>> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>        u32 feature;
>>>        gpa_t gpa;
>>>
>>> +     if (!kvm_hvc_call_allowed(vcpu, func_id))
>>> +             goto out;
>>> +
>>>        switch (func_id) {
>>>        case ARM_SMCCC_VERSION_FUNC_ID:
>>>                val[0] = ARM_SMCCC_VERSION_1_1;
>>> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>                return kvm_psci_call(vcpu);
>>>        }
>>>
>>> +out:
>>>        smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>>>        return 1;
>>>    }
>>> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>>> +     KVM_REG_ARM_STD_BMAP,
>>>    };
>>>
>>> +void kvm_arm_init_hypercalls(struct kvm *kvm)
>>> +{
>>> +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>>> +
>>> +     smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>>> +}
>>> +
>>>    int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>>>    {
>>>        return ARRAY_SIZE(kvm_arm_fw_reg_ids);
>>> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>>>
>>>    int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>    {
>>> +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>>>        void __user *uaddr = (void __user *)(long)reg->addr;
>>>        u64 val;
>>>
>>> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>>>                val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>>>                break;
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             val = READ_ONCE(smccc_feat->std_bmap);
>>> +             break;
>>>        default:
>>>                return -ENOENT;
>>>        }
>>> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>        return 0;
>>>    }
>>>
>>> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>>> +{
>>> +     int ret = 0;
>>> +     struct kvm *kvm = vcpu->kvm;
>>> +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>>> +     unsigned long *fw_reg_bmap, fw_reg_features;
>>> +
>>> +     switch (reg_id) {
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             fw_reg_bmap = &smccc_feat->std_bmap;
>>> +             fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
>>> +             break;
>>> +     default:
>>> +             return -ENOENT;
>>> +     }
>>> +
>>> +     /* Check for unsupported bit */
>>> +     if (val & ~fw_reg_features)
>>> +             return -EINVAL;
>>> +
>>> +     mutex_lock(&kvm->lock);
>>> +
>>> +     /* Return -EBUSY if the VM (any vCPU) has already started running. */
>>> +     if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
>>> +             ret = -EBUSY;
>>> +             goto out;
>>> +     }
>>> +
>>> +     WRITE_ONCE(*fw_reg_bmap, val);
>>> +out:
>>> +     mutex_unlock(&kvm->lock);
>>> +     return ret;
>>> +}
>>> +
>>>    int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>    {
>>>        void __user *uaddr = (void __user *)(long)reg->addr;
>>> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>                        return -EINVAL;
>>>
>>>                return 0;
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>>>        default:
>>>                return -ENOENT;
>>>        }
>>> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
>>> index 346535169faa..67d1273e8086 100644
>>> --- a/arch/arm64/kvm/psci.c
>>> +++ b/arch/arm64/kvm/psci.c
>>> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>>>                return -EINVAL;
>>>        }
>>>    }
>>> +
>>> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     /* PSCI 0.1 doesn't comply with the standard SMCCC */
>>> +     if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
>>> +             return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
>>> +
>>> +     if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
>>> +             ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
>>> +             return true;
>>> +
>>> +     return false;
>>> +}
>>> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
>>> index 5d38628a8d04..499b45b607b6 100644
>>> --- a/include/kvm/arm_hypercalls.h
>>> +++ b/include/kvm/arm_hypercalls.h
>>> @@ -6,6 +6,11 @@
>>>
>>>    #include <asm/kvm_emulate.h>
>>>
>>> +/* Last valid bits of the bitmapped firmware registers */
>>> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
>>> +
>>> +#define KVM_ARM_SMCCC_STD_FEATURES           GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>>> +
>>
>> s/bits of/bit of
>>
> Great catch again!
> 
>>>    int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>>>
>>>    static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
>>> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>>>
>>>    struct kvm_one_reg;
>>>
>>> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>>>    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);
>>> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
>>> index 6e55b9283789..c47be3e26965 100644
>>> --- a/include/kvm/arm_psci.h
>>> +++ b/include/kvm/arm_psci.h
>>> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>>>        return KVM_ARM_PSCI_0_1;
>>>    }
>>>
>>> -
>>>    int kvm_psci_call(struct kvm_vcpu *vcpu);
>>> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>>>
>>>    #endif /* __KVM_ARM_PSCI_H__ */
>>>
>>
>> Thanks,
>> Gavin
>>
> 
> Thanks for the review, Gavin.
> 

No worries :)

Thanks,
Gavin


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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-27  1:38         ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-27  1:38 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: kvm, Marc Zyngier, Peter Shier, linux-kernel, Will Deacon,
	Catalin Marinas, Paolo Bonzini, kvmarm, linux-arm-kernel

Hi Raghavendra,

On 4/27/22 12:44 AM, Raghavendra Rao Ananta wrote:
> On Mon, Apr 25, 2022 at 11:34 PM Gavin Shan <gshan@redhat.com> wrote:
>> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
>>> KVM regularly introduces new hypercall services to the guests without
>>> any consent from the userspace. This means, the guests can observe
>>> hypercall services in and out as they migrate across various host
>>> kernel versions. This could be a major problem if the guest
>>> discovered a hypercall, started using it, and after getting migrated
>>> to an older kernel realizes that it's no longer available. Depending
>>> on how the guest handles the change, there's a potential chance that
>>> the guest would just panic.
>>>
>>> As a result, there's a need for the userspace to elect the services
>>> that it wishes the guest to discover. It can elect these services
>>> based on the kernels spread across its (migration) fleet. To remedy
>>> this, extend the existing firmware pseudo-registers, such as
>>> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
>>> for all the hypercall services available.
>>>
>>> These firmware registers are categorized based on the service call
>>> owners, but unlike the existing firmware pseudo-registers, they hold
>>> the features supported in the form of a bitmap.
>>>
>>> During the VM initialization, the registers are set to upper-limit of
>>> the features supported by the corresponding registers. It's expected
>>> that the VMMs discover the features provided by each register via
>>> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
>>> KVM allows this modification only until the VM has started.
>>>
>>> Some of the standard features are not mapped to any bits of the
>>> registers. But since they can recreate the original problem of
>>> making it available without userspace's consent, they need to
>>> be explicitly added to the case-list in
>>> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
>>> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
>>> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
>>>
>>> Older userspace code can simply ignore the feature and the
>>> hypercall services will be exposed unconditionally to the guests,
>>> thus ensuring backward compatibility.
>>>
>>> In this patch, the framework adds the register only for ARM's standard
>>> secure services (owner value 4). Currently, this includes support only
>>> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
>>> register representing mandatory features of v1.0. Other services are
>>> momentarily added in the upcoming patches.
>>>
>>> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
>>> ---
>>>    arch/arm64/include/asm/kvm_host.h | 12 ++++
>>>    arch/arm64/include/uapi/asm/kvm.h |  9 +++
>>>    arch/arm64/kvm/arm.c              |  1 +
>>>    arch/arm64/kvm/guest.c            |  8 ++-
>>>    arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>>>    arch/arm64/kvm/psci.c             | 13 +++++
>>>    include/kvm/arm_hypercalls.h      |  6 ++
>>>    include/kvm/arm_psci.h            |  2 +-
>>>    8 files changed, 142 insertions(+), 3 deletions(-)
>>>
>>
>> Some nits as below, please consider to improve if you need another
>> respin.
>>
>> Reviewed-by: Gavin Shan <gshan@redhat.com>
>>
>>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>>> index 94a27a7520f4..df07f4c10197 100644
>>> --- a/arch/arm64/include/asm/kvm_host.h
>>> +++ b/arch/arm64/include/asm/kvm_host.h
>>> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>>>    struct kvm_arch_memory_slot {
>>>    };
>>>
>>> +/**
>>> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
>>> + *
>>> + * @std_bmap: Bitmap of standard secure service calls
>>> + */
>>> +struct kvm_smccc_features {
>>> +     unsigned long std_bmap;
>>> +};
>>> +
>>
>> s/Descriptor/Descriptor of
>>
> Nice catch!
> 
>>>    struct kvm_arch {
>>>        struct kvm_s2_mmu mmu;
>>>
>>> @@ -150,6 +159,9 @@ struct kvm_arch {
>>>
>>>        u8 pfr0_csv2;
>>>        u8 pfr0_csv3;
>>> +
>>> +     /* Hypercall features firmware registers' descriptor */
>>> +     struct kvm_smccc_features smccc_feat;
>>>    };
>>>
>>>    struct kvm_vcpu_fault_info {
>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>>> index c1b6ddc02d2f..0b79d2dc6ffd 100644
>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>>>    #define KVM_ARM64_SVE_VLS_WORDS     \
>>>        ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>>>
>>> +/* Bitmap feature firmware registers */
>>> +#define KVM_REG_ARM_FW_FEAT_BMAP             (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
>>> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)              (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
>>> +                                             KVM_REG_ARM_FW_FEAT_BMAP |      \
>>> +                                             ((r) & 0xffff))
>>> +
>>> +#define KVM_REG_ARM_STD_BMAP                 KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
>>> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0                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/arm.c b/arch/arm64/kvm/arm.c
>>> index 523bc934fe2f..a37fadbd617e 100644
>>> --- a/arch/arm64/kvm/arm.c
>>> +++ b/arch/arm64/kvm/arm.c
>>> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>>>        kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>>>
>>>        set_default_spectre(kvm);
>>> +     kvm_arm_init_hypercalls(kvm);
>>>
>>>        return ret;
>>>    out_free_stage2_pgd:
>>> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
>>> index 0d5cca56cbda..8c607199cad1 100644
>>> --- a/arch/arm64/kvm/guest.c
>>> +++ b/arch/arm64/kvm/guest.c
>>> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>
>>>        switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>>>        case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
>>> -     case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
>>> +     case KVM_REG_ARM_FW:
>>> +     case KVM_REG_ARM_FW_FEAT_BMAP:
>>> +             return kvm_arm_get_fw_reg(vcpu, reg);
>>>        case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
>>>        }
>>>
>>> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>
>>>        switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>>>        case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
>>> -     case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
>>> +     case KVM_REG_ARM_FW:
>>> +     case KVM_REG_ARM_FW_FEAT_BMAP:
>>> +             return kvm_arm_set_fw_reg(vcpu, reg);
>>>        case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
>>>        }
>>>
>>> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
>>> index fa6d9378d8e7..df55a04d2fe8 100644
>>> --- a/arch/arm64/kvm/hypercalls.c
>>> +++ b/arch/arm64/kvm/hypercalls.c
>>> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>>>        val[3] = lower_32_bits(cycles);
>>>    }
>>>
>>> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
>>> +{
>>> +     return test_bit(feat_bit, reg_bmap);
>>> +}
>>> +
>>
>> Might be worhty to be 'inline'. This function would be called
>> frequently.
>>
> I was hoping the compiler would optimize it for us as needed.
> 

Yeah, GCC is smart enough. It could be compiled to inline function
even it's not specified explicitly. I guess __always_inline can be
used here. However, it seems __always_inline isn't used broadly in
kvm/arm64 scope. Anyway, it's not a big deal in this specific case :)

>>> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     switch (func_id) {
>>> +     /*
>>> +      * List of function-ids that are not gated with the bitmapped feature
>>> +      * firmware registers, and are to be allowed for servicing the call by default.
>>> +      */
>>> +     case ARM_SMCCC_VERSION_FUNC_ID:
>>> +     case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
>>> +     case ARM_SMCCC_HV_PV_TIME_FEATURES:
>>> +     case ARM_SMCCC_HV_PV_TIME_ST:
>>> +     case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
>>> +     case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
>>> +     case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>>> +             return true;
>>> +     default:
>>> +             return kvm_psci_func_id_is_valid(vcpu, func_id);
>>> +     }
>>> +}
>>> +
>>> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>>> +
>>> +     switch (func_id) {
>>> +     case ARM_SMCCC_TRNG_VERSION:
>>> +     case ARM_SMCCC_TRNG_FEATURES:
>>> +     case ARM_SMCCC_TRNG_GET_UUID:
>>> +     case ARM_SMCCC_TRNG_RND32:
>>> +     case ARM_SMCCC_TRNG_RND64:
>>> +             return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
>>> +                                             KVM_REG_ARM_STD_BIT_TRNG_V1_0);
>>> +     default:
>>> +             return kvm_hvc_call_default_allowed(vcpu, func_id);
>>> +     }
>>> +}
>>> +
>>>    int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>    {
>>>        u32 func_id = smccc_get_function(vcpu);
>>> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>        u32 feature;
>>>        gpa_t gpa;
>>>
>>> +     if (!kvm_hvc_call_allowed(vcpu, func_id))
>>> +             goto out;
>>> +
>>>        switch (func_id) {
>>>        case ARM_SMCCC_VERSION_FUNC_ID:
>>>                val[0] = ARM_SMCCC_VERSION_1_1;
>>> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>                return kvm_psci_call(vcpu);
>>>        }
>>>
>>> +out:
>>>        smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>>>        return 1;
>>>    }
>>> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>>> +     KVM_REG_ARM_STD_BMAP,
>>>    };
>>>
>>> +void kvm_arm_init_hypercalls(struct kvm *kvm)
>>> +{
>>> +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>>> +
>>> +     smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>>> +}
>>> +
>>>    int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>>>    {
>>>        return ARRAY_SIZE(kvm_arm_fw_reg_ids);
>>> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>>>
>>>    int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>    {
>>> +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>>>        void __user *uaddr = (void __user *)(long)reg->addr;
>>>        u64 val;
>>>
>>> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>>>                val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>>>                break;
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             val = READ_ONCE(smccc_feat->std_bmap);
>>> +             break;
>>>        default:
>>>                return -ENOENT;
>>>        }
>>> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>        return 0;
>>>    }
>>>
>>> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>>> +{
>>> +     int ret = 0;
>>> +     struct kvm *kvm = vcpu->kvm;
>>> +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>>> +     unsigned long *fw_reg_bmap, fw_reg_features;
>>> +
>>> +     switch (reg_id) {
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             fw_reg_bmap = &smccc_feat->std_bmap;
>>> +             fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
>>> +             break;
>>> +     default:
>>> +             return -ENOENT;
>>> +     }
>>> +
>>> +     /* Check for unsupported bit */
>>> +     if (val & ~fw_reg_features)
>>> +             return -EINVAL;
>>> +
>>> +     mutex_lock(&kvm->lock);
>>> +
>>> +     /* Return -EBUSY if the VM (any vCPU) has already started running. */
>>> +     if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
>>> +             ret = -EBUSY;
>>> +             goto out;
>>> +     }
>>> +
>>> +     WRITE_ONCE(*fw_reg_bmap, val);
>>> +out:
>>> +     mutex_unlock(&kvm->lock);
>>> +     return ret;
>>> +}
>>> +
>>>    int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>    {
>>>        void __user *uaddr = (void __user *)(long)reg->addr;
>>> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>                        return -EINVAL;
>>>
>>>                return 0;
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>>>        default:
>>>                return -ENOENT;
>>>        }
>>> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
>>> index 346535169faa..67d1273e8086 100644
>>> --- a/arch/arm64/kvm/psci.c
>>> +++ b/arch/arm64/kvm/psci.c
>>> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>>>                return -EINVAL;
>>>        }
>>>    }
>>> +
>>> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     /* PSCI 0.1 doesn't comply with the standard SMCCC */
>>> +     if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
>>> +             return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
>>> +
>>> +     if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
>>> +             ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
>>> +             return true;
>>> +
>>> +     return false;
>>> +}
>>> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
>>> index 5d38628a8d04..499b45b607b6 100644
>>> --- a/include/kvm/arm_hypercalls.h
>>> +++ b/include/kvm/arm_hypercalls.h
>>> @@ -6,6 +6,11 @@
>>>
>>>    #include <asm/kvm_emulate.h>
>>>
>>> +/* Last valid bits of the bitmapped firmware registers */
>>> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
>>> +
>>> +#define KVM_ARM_SMCCC_STD_FEATURES           GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>>> +
>>
>> s/bits of/bit of
>>
> Great catch again!
> 
>>>    int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>>>
>>>    static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
>>> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>>>
>>>    struct kvm_one_reg;
>>>
>>> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>>>    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);
>>> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
>>> index 6e55b9283789..c47be3e26965 100644
>>> --- a/include/kvm/arm_psci.h
>>> +++ b/include/kvm/arm_psci.h
>>> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>>>        return KVM_ARM_PSCI_0_1;
>>>    }
>>>
>>> -
>>>    int kvm_psci_call(struct kvm_vcpu *vcpu);
>>> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>>>
>>>    #endif /* __KVM_ARM_PSCI_H__ */
>>>
>>
>> Thanks,
>> Gavin
>>
> 
> Thanks for the review, Gavin.
> 

No worries :)

Thanks,
Gavin

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-27  1:38         ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-27  1:38 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, kvm, Catalin Marinas, Peter Shier,
	linux-kernel, Paolo Bonzini, Will Deacon, kvmarm,
	linux-arm-kernel

Hi Raghavendra,

On 4/27/22 12:44 AM, Raghavendra Rao Ananta wrote:
> On Mon, Apr 25, 2022 at 11:34 PM Gavin Shan <gshan@redhat.com> wrote:
>> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
>>> KVM regularly introduces new hypercall services to the guests without
>>> any consent from the userspace. This means, the guests can observe
>>> hypercall services in and out as they migrate across various host
>>> kernel versions. This could be a major problem if the guest
>>> discovered a hypercall, started using it, and after getting migrated
>>> to an older kernel realizes that it's no longer available. Depending
>>> on how the guest handles the change, there's a potential chance that
>>> the guest would just panic.
>>>
>>> As a result, there's a need for the userspace to elect the services
>>> that it wishes the guest to discover. It can elect these services
>>> based on the kernels spread across its (migration) fleet. To remedy
>>> this, extend the existing firmware pseudo-registers, such as
>>> KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
>>> for all the hypercall services available.
>>>
>>> These firmware registers are categorized based on the service call
>>> owners, but unlike the existing firmware pseudo-registers, they hold
>>> the features supported in the form of a bitmap.
>>>
>>> During the VM initialization, the registers are set to upper-limit of
>>> the features supported by the corresponding registers. It's expected
>>> that the VMMs discover the features provided by each register via
>>> GET_ONE_REG, and write back the desired values using SET_ONE_REG.
>>> KVM allows this modification only until the VM has started.
>>>
>>> Some of the standard features are not mapped to any bits of the
>>> registers. But since they can recreate the original problem of
>>> making it available without userspace's consent, they need to
>>> be explicitly added to the case-list in
>>> kvm_hvc_call_default_allowed(). Any function-id that's not enabled
>>> via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
>>> be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
>>>
>>> Older userspace code can simply ignore the feature and the
>>> hypercall services will be exposed unconditionally to the guests,
>>> thus ensuring backward compatibility.
>>>
>>> In this patch, the framework adds the register only for ARM's standard
>>> secure services (owner value 4). Currently, this includes support only
>>> for ARM True Random Number Generator (TRNG) service, with bit-0 of the
>>> register representing mandatory features of v1.0. Other services are
>>> momentarily added in the upcoming patches.
>>>
>>> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
>>> ---
>>>    arch/arm64/include/asm/kvm_host.h | 12 ++++
>>>    arch/arm64/include/uapi/asm/kvm.h |  9 +++
>>>    arch/arm64/kvm/arm.c              |  1 +
>>>    arch/arm64/kvm/guest.c            |  8 ++-
>>>    arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
>>>    arch/arm64/kvm/psci.c             | 13 +++++
>>>    include/kvm/arm_hypercalls.h      |  6 ++
>>>    include/kvm/arm_psci.h            |  2 +-
>>>    8 files changed, 142 insertions(+), 3 deletions(-)
>>>
>>
>> Some nits as below, please consider to improve if you need another
>> respin.
>>
>> Reviewed-by: Gavin Shan <gshan@redhat.com>
>>
>>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>>> index 94a27a7520f4..df07f4c10197 100644
>>> --- a/arch/arm64/include/asm/kvm_host.h
>>> +++ b/arch/arm64/include/asm/kvm_host.h
>>> @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
>>>    struct kvm_arch_memory_slot {
>>>    };
>>>
>>> +/**
>>> + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
>>> + *
>>> + * @std_bmap: Bitmap of standard secure service calls
>>> + */
>>> +struct kvm_smccc_features {
>>> +     unsigned long std_bmap;
>>> +};
>>> +
>>
>> s/Descriptor/Descriptor of
>>
> Nice catch!
> 
>>>    struct kvm_arch {
>>>        struct kvm_s2_mmu mmu;
>>>
>>> @@ -150,6 +159,9 @@ struct kvm_arch {
>>>
>>>        u8 pfr0_csv2;
>>>        u8 pfr0_csv3;
>>> +
>>> +     /* Hypercall features firmware registers' descriptor */
>>> +     struct kvm_smccc_features smccc_feat;
>>>    };
>>>
>>>    struct kvm_vcpu_fault_info {
>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>>> index c1b6ddc02d2f..0b79d2dc6ffd 100644
>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>> @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
>>>    #define KVM_ARM64_SVE_VLS_WORDS     \
>>>        ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
>>>
>>> +/* Bitmap feature firmware registers */
>>> +#define KVM_REG_ARM_FW_FEAT_BMAP             (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
>>> +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)              (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
>>> +                                             KVM_REG_ARM_FW_FEAT_BMAP |      \
>>> +                                             ((r) & 0xffff))
>>> +
>>> +#define KVM_REG_ARM_STD_BMAP                 KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
>>> +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0                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/arm.c b/arch/arm64/kvm/arm.c
>>> index 523bc934fe2f..a37fadbd617e 100644
>>> --- a/arch/arm64/kvm/arm.c
>>> +++ b/arch/arm64/kvm/arm.c
>>> @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>>>        kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
>>>
>>>        set_default_spectre(kvm);
>>> +     kvm_arm_init_hypercalls(kvm);
>>>
>>>        return ret;
>>>    out_free_stage2_pgd:
>>> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
>>> index 0d5cca56cbda..8c607199cad1 100644
>>> --- a/arch/arm64/kvm/guest.c
>>> +++ b/arch/arm64/kvm/guest.c
>>> @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>
>>>        switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>>>        case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
>>> -     case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
>>> +     case KVM_REG_ARM_FW:
>>> +     case KVM_REG_ARM_FW_FEAT_BMAP:
>>> +             return kvm_arm_get_fw_reg(vcpu, reg);
>>>        case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
>>>        }
>>>
>>> @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>
>>>        switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
>>>        case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
>>> -     case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
>>> +     case KVM_REG_ARM_FW:
>>> +     case KVM_REG_ARM_FW_FEAT_BMAP:
>>> +             return kvm_arm_set_fw_reg(vcpu, reg);
>>>        case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
>>>        }
>>>
>>> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
>>> index fa6d9378d8e7..df55a04d2fe8 100644
>>> --- a/arch/arm64/kvm/hypercalls.c
>>> +++ b/arch/arm64/kvm/hypercalls.c
>>> @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
>>>        val[3] = lower_32_bits(cycles);
>>>    }
>>>
>>> +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
>>> +{
>>> +     return test_bit(feat_bit, reg_bmap);
>>> +}
>>> +
>>
>> Might be worhty to be 'inline'. This function would be called
>> frequently.
>>
> I was hoping the compiler would optimize it for us as needed.
> 

Yeah, GCC is smart enough. It could be compiled to inline function
even it's not specified explicitly. I guess __always_inline can be
used here. However, it seems __always_inline isn't used broadly in
kvm/arm64 scope. Anyway, it's not a big deal in this specific case :)

>>> +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     switch (func_id) {
>>> +     /*
>>> +      * List of function-ids that are not gated with the bitmapped feature
>>> +      * firmware registers, and are to be allowed for servicing the call by default.
>>> +      */
>>> +     case ARM_SMCCC_VERSION_FUNC_ID:
>>> +     case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
>>> +     case ARM_SMCCC_HV_PV_TIME_FEATURES:
>>> +     case ARM_SMCCC_HV_PV_TIME_ST:
>>> +     case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
>>> +     case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
>>> +     case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>>> +             return true;
>>> +     default:
>>> +             return kvm_psci_func_id_is_valid(vcpu, func_id);
>>> +     }
>>> +}
>>> +
>>> +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>>> +
>>> +     switch (func_id) {
>>> +     case ARM_SMCCC_TRNG_VERSION:
>>> +     case ARM_SMCCC_TRNG_FEATURES:
>>> +     case ARM_SMCCC_TRNG_GET_UUID:
>>> +     case ARM_SMCCC_TRNG_RND32:
>>> +     case ARM_SMCCC_TRNG_RND64:
>>> +             return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
>>> +                                             KVM_REG_ARM_STD_BIT_TRNG_V1_0);
>>> +     default:
>>> +             return kvm_hvc_call_default_allowed(vcpu, func_id);
>>> +     }
>>> +}
>>> +
>>>    int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>    {
>>>        u32 func_id = smccc_get_function(vcpu);
>>> @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>        u32 feature;
>>>        gpa_t gpa;
>>>
>>> +     if (!kvm_hvc_call_allowed(vcpu, func_id))
>>> +             goto out;
>>> +
>>>        switch (func_id) {
>>>        case ARM_SMCCC_VERSION_FUNC_ID:
>>>                val[0] = ARM_SMCCC_VERSION_1_1;
>>> @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>>>                return kvm_psci_call(vcpu);
>>>        }
>>>
>>> +out:
>>>        smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
>>>        return 1;
>>>    }
>>> @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
>>>        KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
>>> +     KVM_REG_ARM_STD_BMAP,
>>>    };
>>>
>>> +void kvm_arm_init_hypercalls(struct kvm *kvm)
>>> +{
>>> +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>>> +
>>> +     smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
>>> +}
>>> +
>>>    int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
>>>    {
>>>        return ARRAY_SIZE(kvm_arm_fw_reg_ids);
>>> @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
>>>
>>>    int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>    {
>>> +     struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
>>>        void __user *uaddr = (void __user *)(long)reg->addr;
>>>        u64 val;
>>>
>>> @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
>>>                val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
>>>                break;
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             val = READ_ONCE(smccc_feat->std_bmap);
>>> +             break;
>>>        default:
>>>                return -ENOENT;
>>>        }
>>> @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>        return 0;
>>>    }
>>>
>>> +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
>>> +{
>>> +     int ret = 0;
>>> +     struct kvm *kvm = vcpu->kvm;
>>> +     struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
>>> +     unsigned long *fw_reg_bmap, fw_reg_features;
>>> +
>>> +     switch (reg_id) {
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             fw_reg_bmap = &smccc_feat->std_bmap;
>>> +             fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
>>> +             break;
>>> +     default:
>>> +             return -ENOENT;
>>> +     }
>>> +
>>> +     /* Check for unsupported bit */
>>> +     if (val & ~fw_reg_features)
>>> +             return -EINVAL;
>>> +
>>> +     mutex_lock(&kvm->lock);
>>> +
>>> +     /* Return -EBUSY if the VM (any vCPU) has already started running. */
>>> +     if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
>>> +             ret = -EBUSY;
>>> +             goto out;
>>> +     }
>>> +
>>> +     WRITE_ONCE(*fw_reg_bmap, val);
>>> +out:
>>> +     mutex_unlock(&kvm->lock);
>>> +     return ret;
>>> +}
>>> +
>>>    int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>    {
>>>        void __user *uaddr = (void __user *)(long)reg->addr;
>>> @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>>>                        return -EINVAL;
>>>
>>>                return 0;
>>> +     case KVM_REG_ARM_STD_BMAP:
>>> +             return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
>>>        default:
>>>                return -ENOENT;
>>>        }
>>> diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
>>> index 346535169faa..67d1273e8086 100644
>>> --- a/arch/arm64/kvm/psci.c
>>> +++ b/arch/arm64/kvm/psci.c
>>> @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
>>>                return -EINVAL;
>>>        }
>>>    }
>>> +
>>> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
>>> +{
>>> +     /* PSCI 0.1 doesn't comply with the standard SMCCC */
>>> +     if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
>>> +             return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
>>> +
>>> +     if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
>>> +             ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
>>> +             return true;
>>> +
>>> +     return false;
>>> +}
>>> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
>>> index 5d38628a8d04..499b45b607b6 100644
>>> --- a/include/kvm/arm_hypercalls.h
>>> +++ b/include/kvm/arm_hypercalls.h
>>> @@ -6,6 +6,11 @@
>>>
>>>    #include <asm/kvm_emulate.h>
>>>
>>> +/* Last valid bits of the bitmapped firmware registers */
>>> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
>>> +
>>> +#define KVM_ARM_SMCCC_STD_FEATURES           GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
>>> +
>>
>> s/bits of/bit of
>>
> Great catch again!
> 
>>>    int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
>>>
>>>    static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
>>> @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
>>>
>>>    struct kvm_one_reg;
>>>
>>> +void kvm_arm_init_hypercalls(struct kvm *kvm);
>>>    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);
>>> diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
>>> index 6e55b9283789..c47be3e26965 100644
>>> --- a/include/kvm/arm_psci.h
>>> +++ b/include/kvm/arm_psci.h
>>> @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
>>>        return KVM_ARM_PSCI_0_1;
>>>    }
>>>
>>> -
>>>    int kvm_psci_call(struct kvm_vcpu *vcpu);
>>> +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
>>>
>>>    #endif /* __KVM_ARM_PSCI_H__ */
>>>
>>
>> Thanks,
>> Gavin
>>
> 
> Thanks for the review, Gavin.
> 

No worries :)

Thanks,
Gavin


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  2022-04-25 16:46       ` Raghavendra Rao Ananta
  (?)
@ 2022-04-27  1:46         ` Reiji Watanabe
  -1 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-27  1:46 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Raghu,

On Mon, Apr 25, 2022 at 9:46 AM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Hi Reiji,
>
> On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
> >
> > Hi Raghu,
> >
> > On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> > <rananta@google.com> wrote:
> > >
> > > KVM regularly introduces new hypercall services to the guests without
> > > any consent from the userspace. This means, the guests can observe
> > > hypercall services in and out as they migrate across various host
> > > kernel versions. This could be a major problem if the guest
> > > discovered a hypercall, started using it, and after getting migrated
> > > to an older kernel realizes that it's no longer available. Depending
> > > on how the guest handles the change, there's a potential chance that
> > > the guest would just panic.
> > >
> > > As a result, there's a need for the userspace to elect the services
> > > that it wishes the guest to discover. It can elect these services
> > > based on the kernels spread across its (migration) fleet. To remedy
> > > this, extend the existing firmware pseudo-registers, such as
> > > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > > for all the hypercall services available.
> > >
> > > These firmware registers are categorized based on the service call
> > > owners, but unlike the existing firmware pseudo-registers, they hold
> > > the features supported in the form of a bitmap.
> > >
> > > During the VM initialization, the registers are set to upper-limit of
> > > the features supported by the corresponding registers. It's expected
> > > that the VMMs discover the features provided by each register via
> > > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > > KVM allows this modification only until the VM has started.
> > >
> > > Some of the standard features are not mapped to any bits of the
> > > registers. But since they can recreate the original problem of
> > > making it available without userspace's consent, they need to
> > > be explicitly added to the case-list in
> > > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> > >
> > > Older userspace code can simply ignore the feature and the
> > > hypercall services will be exposed unconditionally to the guests,
> > > thus ensuring backward compatibility.
> > >
> > > In this patch, the framework adds the register only for ARM's standard
> > > secure services (owner value 4). Currently, this includes support only
> > > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > > register representing mandatory features of v1.0. Other services are
> > > momentarily added in the upcoming patches.
> > >
> > > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> > >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> > >  arch/arm64/kvm/arm.c              |  1 +
> > >  arch/arm64/kvm/guest.c            |  8 ++-
> > >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> > >  arch/arm64/kvm/psci.c             | 13 +++++
> > >  include/kvm/arm_hypercalls.h      |  6 ++
> > >  include/kvm/arm_psci.h            |  2 +-
> > >  8 files changed, 142 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 94a27a7520f4..df07f4c10197 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> > >  struct kvm_arch_memory_slot {
> > >  };
> > >
> > > +/**
> > > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > > + *
> > > + * @std_bmap: Bitmap of standard secure service calls
> > > + */
> > > +struct kvm_smccc_features {
> > > +       unsigned long std_bmap;
> > > +};
> > > +
> > >  struct kvm_arch {
> > >         struct kvm_s2_mmu mmu;
> > >
> > > @@ -150,6 +159,9 @@ struct kvm_arch {
> > >
> > >         u8 pfr0_csv2;
> > >         u8 pfr0_csv3;
> > > +
> > > +       /* Hypercall features firmware registers' descriptor */
> > > +       struct kvm_smccc_features smccc_feat;
> > >  };
> > >
> > >  struct kvm_vcpu_fault_info {
> > > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > > --- a/arch/arm64/include/uapi/asm/kvm.h
> > > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> > >  #define KVM_ARM64_SVE_VLS_WORDS        \
> > >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> > >
> > > +/* Bitmap feature firmware registers */
> > > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > > +                                               ((r) & 0xffff))
> > > +
> > > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > > index 523bc934fe2f..a37fadbd617e 100644
> > > --- a/arch/arm64/kvm/arm.c
> > > +++ b/arch/arm64/kvm/arm.c
> > > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> > >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> > >
> > >         set_default_spectre(kvm);
> > > +       kvm_arm_init_hypercalls(kvm);
> > >
> > >         return ret;
> > >  out_free_stage2_pgd:
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 0d5cca56cbda..8c607199cad1 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >
> > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > > +       case KVM_REG_ARM_FW:
> > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > +               return kvm_arm_get_fw_reg(vcpu, reg);
> > >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> > >         }
> > >
> > > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >
> > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > > +       case KVM_REG_ARM_FW:
> > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > +               return kvm_arm_set_fw_reg(vcpu, reg);
> > >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> > >         }
> > >
> > > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > > index fa6d9378d8e7..df55a04d2fe8 100644
> > > --- a/arch/arm64/kvm/hypercalls.c
> > > +++ b/arch/arm64/kvm/hypercalls.c
> > > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> > >         val[3] = lower_32_bits(cycles);
> > >  }
> > >
> > > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > > +{
> > > +       return test_bit(feat_bit, reg_bmap);
> > > +}
> > > +
> > > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       switch (func_id) {
> > > +       /*
> > > +        * List of function-ids that are not gated with the bitmapped feature
> > > +        * firmware registers, and are to be allowed for servicing the call by default.
> > > +        */
> > > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > > +               return true;
> > > +       default:
> > > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > > +       }
> > > +}
> > > +
> > > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > +
> > > +       switch (func_id) {
> > > +       case ARM_SMCCC_TRNG_VERSION:
> > > +       case ARM_SMCCC_TRNG_FEATURES:
> > > +       case ARM_SMCCC_TRNG_GET_UUID:
> > > +       case ARM_SMCCC_TRNG_RND32:
> > > +       case ARM_SMCCC_TRNG_RND64:
> > > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > > +       default:
> > > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > > +       }
> > > +}
> > > +
> > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >  {
> > >         u32 func_id = smccc_get_function(vcpu);
> > > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >         u32 feature;
> > >         gpa_t gpa;
> > >
> > > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > > +               goto out;
> > > +
> > >         switch (func_id) {
> > >         case ARM_SMCCC_VERSION_FUNC_ID:
> > >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >                 return kvm_psci_call(vcpu);
> > >         }
> > >
> > > +out:
> > >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> > >         return 1;
> > >  }
> > > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > > +       KVM_REG_ARM_STD_BMAP,
> > >  };
> > >
> > > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > > +{
> > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > +
> > > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > > +}
> > > +
> > >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > >  {
> > >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> > >
> > >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  {
> > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > >         u64 val;
> > >
> > > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> > >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> > >                 break;
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               val = READ_ONCE(smccc_feat->std_bmap);
> > > +               break;
> > >         default:
> > >                 return -ENOENT;
> > >         }
> > > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >         return 0;
> > >  }
> > >
> > > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > > +{
> > > +       int ret = 0;
> > > +       struct kvm *kvm = vcpu->kvm;
> > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > > +
> > > +       switch (reg_id) {
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > > +               break;
> > > +       default:
> > > +               return -ENOENT;
> > > +       }
> > > +
> > > +       /* Check for unsupported bit */
> > > +       if (val & ~fw_reg_features)
> > > +               return -EINVAL;
> > > +
> > > +       mutex_lock(&kvm->lock);
> >
> > Why don't you check if the register value will be modified before
> > getting the lock ? (then there is nothing to do)
> > It would help reduce unnecessary serialization for live migration
> > (even without the vm-scoped register capability).
> >
> That was the case until v5. Since v6, we return -EBUSY unconditionally
> regardless of the incoming value. See Marc's comments in [1].

> That was the case until v5. Since v6, we return -EBUSY unconditionally
> regardless of the incoming value. See Marc's comments in [1].

Even with that, the function could do below to avoid
the unnecessary serialization.
(I would expect mostly the function returns before getting the lock)

        if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags))
              return -EBUSY;

        if (val == *fw_reg_bmap)
              return 0;

        mutex_lock(&kvm->lock);

        <...>

> >
> >
> > > +
> > > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > > +               ret = -EBUSY;
> > > +               goto out;
> > > +       }
> >
> > I just would like to make sure that you are sure that existing
> > userspace you know will not run KVM_RUN for any vCPUs until
> > KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> > correct ?
> >
> Since v6, that is something that we are leaving with the userspace to
> synchronize. See [1].

Understood.


> > > +o
> > > +       WRITE_ONCE(*fw_reg_bmap, val);
> > > +out:
> > > +       mutex_unlock(&kvm->lock);
> > > +       return ret;
> > > +}
> > > +
> > >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  {
> > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >                         return -EINVAL;
> > >
> > >                 return 0;
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> > >         default:
> > >                 return -ENOENT;
> > >         }
> > > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > > index 346535169faa..67d1273e8086 100644
> > > --- a/arch/arm64/kvm/psci.c
> > > +++ b/arch/arm64/kvm/psci.c
> > > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> > >                 return -EINVAL;
> > >         }
> > >  }
> > > +
> > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > > +
> > > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > > +               return true;
> >
> > For PSCI 0.1, the function checks if the funct_id is valid for
> > the vCPU (according to the vCPU's PSCI version).
> > For other version of PSCI, the function doesn't care the vCPU's
> > PSCI version (although supported functions depend on the PSCI
> > version and not all of them are defined yet, the code returns
> > true as long as the function id is within the reserved PSCI
> > function id range).
> > So, the behavior appears to be inconsistent.
> > Shouldn't it return the validity of the function id according
> > to the vCPU's psci version for non-PSCI 0.1 case as well ?
> > (Otherwise, shouldn't it return true if the function id is valid
> > for any of the PSCI versions ?)
> >
> Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
> with the SMCCC, hence needed some special handling. Only two func_ids> are currently supported by KVM, and we just check for each. The second
> 'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
> specification defines a range of acceptable PSCI func_ids.

I understand PSCI 0.1 is different from PSCI 0.2 or newer versions.
But, my question is: What would you consider "valid" psci function id ?
It seems that the function checks whether or not the func_id is valid
on the vCPU for PSCI 0.1, and checks whether or not the func_id is a
PSCI function id for vCPU with PSCI 0.2 or newer.

I understand either one works for your purpose, but I would think
the behavior should be consistent.

Thanks,
Reiji


>
> If it's confusing, I can add a comment above the second 'if' that it's
> for all PSCI versions >= 0.2.
> > Thanks,
> > Reiji
> >
> Thank you.
> Raghavendra
>
> [1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
> >
> >
> > > +
> > > +       return false;
> > > +}
> > > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > > index 5d38628a8d04..499b45b607b6 100644
> > > --- a/include/kvm/arm_hypercalls.h
> > > +++ b/include/kvm/arm_hypercalls.h
> > > @@ -6,6 +6,11 @@
> > >
> > >  #include <asm/kvm_emulate.h>
> > >
> > > +/* Last valid bits of the bitmapped firmware registers */
> > > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > > +
> > > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > > +
> > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> > >
> > >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> > >
> > >  struct kvm_one_reg;
> > >
> > > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> > >  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);
> > > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > > index 6e55b9283789..c47be3e26965 100644
> > > --- a/include/kvm/arm_psci.h
> > > +++ b/include/kvm/arm_psci.h
> > > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> > >         return KVM_ARM_PSCI_0_1;
> > >  }
> > >
> > > -
> > >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> > >
> > >  #endif /* __KVM_ARM_PSCI_H__ */
> > > --
> > > 2.36.0.rc2.479.g8af0fa9b8e-goog
> > >

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-27  1:46         ` Reiji Watanabe
  0 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-27  1:46 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

Hi Raghu,

On Mon, Apr 25, 2022 at 9:46 AM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Hi Reiji,
>
> On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
> >
> > Hi Raghu,
> >
> > On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> > <rananta@google.com> wrote:
> > >
> > > KVM regularly introduces new hypercall services to the guests without
> > > any consent from the userspace. This means, the guests can observe
> > > hypercall services in and out as they migrate across various host
> > > kernel versions. This could be a major problem if the guest
> > > discovered a hypercall, started using it, and after getting migrated
> > > to an older kernel realizes that it's no longer available. Depending
> > > on how the guest handles the change, there's a potential chance that
> > > the guest would just panic.
> > >
> > > As a result, there's a need for the userspace to elect the services
> > > that it wishes the guest to discover. It can elect these services
> > > based on the kernels spread across its (migration) fleet. To remedy
> > > this, extend the existing firmware pseudo-registers, such as
> > > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > > for all the hypercall services available.
> > >
> > > These firmware registers are categorized based on the service call
> > > owners, but unlike the existing firmware pseudo-registers, they hold
> > > the features supported in the form of a bitmap.
> > >
> > > During the VM initialization, the registers are set to upper-limit of
> > > the features supported by the corresponding registers. It's expected
> > > that the VMMs discover the features provided by each register via
> > > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > > KVM allows this modification only until the VM has started.
> > >
> > > Some of the standard features are not mapped to any bits of the
> > > registers. But since they can recreate the original problem of
> > > making it available without userspace's consent, they need to
> > > be explicitly added to the case-list in
> > > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> > >
> > > Older userspace code can simply ignore the feature and the
> > > hypercall services will be exposed unconditionally to the guests,
> > > thus ensuring backward compatibility.
> > >
> > > In this patch, the framework adds the register only for ARM's standard
> > > secure services (owner value 4). Currently, this includes support only
> > > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > > register representing mandatory features of v1.0. Other services are
> > > momentarily added in the upcoming patches.
> > >
> > > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> > >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> > >  arch/arm64/kvm/arm.c              |  1 +
> > >  arch/arm64/kvm/guest.c            |  8 ++-
> > >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> > >  arch/arm64/kvm/psci.c             | 13 +++++
> > >  include/kvm/arm_hypercalls.h      |  6 ++
> > >  include/kvm/arm_psci.h            |  2 +-
> > >  8 files changed, 142 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 94a27a7520f4..df07f4c10197 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> > >  struct kvm_arch_memory_slot {
> > >  };
> > >
> > > +/**
> > > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > > + *
> > > + * @std_bmap: Bitmap of standard secure service calls
> > > + */
> > > +struct kvm_smccc_features {
> > > +       unsigned long std_bmap;
> > > +};
> > > +
> > >  struct kvm_arch {
> > >         struct kvm_s2_mmu mmu;
> > >
> > > @@ -150,6 +159,9 @@ struct kvm_arch {
> > >
> > >         u8 pfr0_csv2;
> > >         u8 pfr0_csv3;
> > > +
> > > +       /* Hypercall features firmware registers' descriptor */
> > > +       struct kvm_smccc_features smccc_feat;
> > >  };
> > >
> > >  struct kvm_vcpu_fault_info {
> > > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > > --- a/arch/arm64/include/uapi/asm/kvm.h
> > > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> > >  #define KVM_ARM64_SVE_VLS_WORDS        \
> > >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> > >
> > > +/* Bitmap feature firmware registers */
> > > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > > +                                               ((r) & 0xffff))
> > > +
> > > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > > index 523bc934fe2f..a37fadbd617e 100644
> > > --- a/arch/arm64/kvm/arm.c
> > > +++ b/arch/arm64/kvm/arm.c
> > > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> > >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> > >
> > >         set_default_spectre(kvm);
> > > +       kvm_arm_init_hypercalls(kvm);
> > >
> > >         return ret;
> > >  out_free_stage2_pgd:
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 0d5cca56cbda..8c607199cad1 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >
> > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > > +       case KVM_REG_ARM_FW:
> > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > +               return kvm_arm_get_fw_reg(vcpu, reg);
> > >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> > >         }
> > >
> > > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >
> > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > > +       case KVM_REG_ARM_FW:
> > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > +               return kvm_arm_set_fw_reg(vcpu, reg);
> > >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> > >         }
> > >
> > > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > > index fa6d9378d8e7..df55a04d2fe8 100644
> > > --- a/arch/arm64/kvm/hypercalls.c
> > > +++ b/arch/arm64/kvm/hypercalls.c
> > > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> > >         val[3] = lower_32_bits(cycles);
> > >  }
> > >
> > > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > > +{
> > > +       return test_bit(feat_bit, reg_bmap);
> > > +}
> > > +
> > > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       switch (func_id) {
> > > +       /*
> > > +        * List of function-ids that are not gated with the bitmapped feature
> > > +        * firmware registers, and are to be allowed for servicing the call by default.
> > > +        */
> > > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > > +               return true;
> > > +       default:
> > > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > > +       }
> > > +}
> > > +
> > > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > +
> > > +       switch (func_id) {
> > > +       case ARM_SMCCC_TRNG_VERSION:
> > > +       case ARM_SMCCC_TRNG_FEATURES:
> > > +       case ARM_SMCCC_TRNG_GET_UUID:
> > > +       case ARM_SMCCC_TRNG_RND32:
> > > +       case ARM_SMCCC_TRNG_RND64:
> > > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > > +       default:
> > > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > > +       }
> > > +}
> > > +
> > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >  {
> > >         u32 func_id = smccc_get_function(vcpu);
> > > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >         u32 feature;
> > >         gpa_t gpa;
> > >
> > > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > > +               goto out;
> > > +
> > >         switch (func_id) {
> > >         case ARM_SMCCC_VERSION_FUNC_ID:
> > >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >                 return kvm_psci_call(vcpu);
> > >         }
> > >
> > > +out:
> > >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> > >         return 1;
> > >  }
> > > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > > +       KVM_REG_ARM_STD_BMAP,
> > >  };
> > >
> > > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > > +{
> > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > +
> > > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > > +}
> > > +
> > >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > >  {
> > >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> > >
> > >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  {
> > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > >         u64 val;
> > >
> > > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> > >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> > >                 break;
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               val = READ_ONCE(smccc_feat->std_bmap);
> > > +               break;
> > >         default:
> > >                 return -ENOENT;
> > >         }
> > > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >         return 0;
> > >  }
> > >
> > > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > > +{
> > > +       int ret = 0;
> > > +       struct kvm *kvm = vcpu->kvm;
> > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > > +
> > > +       switch (reg_id) {
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > > +               break;
> > > +       default:
> > > +               return -ENOENT;
> > > +       }
> > > +
> > > +       /* Check for unsupported bit */
> > > +       if (val & ~fw_reg_features)
> > > +               return -EINVAL;
> > > +
> > > +       mutex_lock(&kvm->lock);
> >
> > Why don't you check if the register value will be modified before
> > getting the lock ? (then there is nothing to do)
> > It would help reduce unnecessary serialization for live migration
> > (even without the vm-scoped register capability).
> >
> That was the case until v5. Since v6, we return -EBUSY unconditionally
> regardless of the incoming value. See Marc's comments in [1].

> That was the case until v5. Since v6, we return -EBUSY unconditionally
> regardless of the incoming value. See Marc's comments in [1].

Even with that, the function could do below to avoid
the unnecessary serialization.
(I would expect mostly the function returns before getting the lock)

        if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags))
              return -EBUSY;

        if (val == *fw_reg_bmap)
              return 0;

        mutex_lock(&kvm->lock);

        <...>

> >
> >
> > > +
> > > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > > +               ret = -EBUSY;
> > > +               goto out;
> > > +       }
> >
> > I just would like to make sure that you are sure that existing
> > userspace you know will not run KVM_RUN for any vCPUs until
> > KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> > correct ?
> >
> Since v6, that is something that we are leaving with the userspace to
> synchronize. See [1].

Understood.


> > > +o
> > > +       WRITE_ONCE(*fw_reg_bmap, val);
> > > +out:
> > > +       mutex_unlock(&kvm->lock);
> > > +       return ret;
> > > +}
> > > +
> > >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  {
> > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >                         return -EINVAL;
> > >
> > >                 return 0;
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> > >         default:
> > >                 return -ENOENT;
> > >         }
> > > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > > index 346535169faa..67d1273e8086 100644
> > > --- a/arch/arm64/kvm/psci.c
> > > +++ b/arch/arm64/kvm/psci.c
> > > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> > >                 return -EINVAL;
> > >         }
> > >  }
> > > +
> > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > > +
> > > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > > +               return true;
> >
> > For PSCI 0.1, the function checks if the funct_id is valid for
> > the vCPU (according to the vCPU's PSCI version).
> > For other version of PSCI, the function doesn't care the vCPU's
> > PSCI version (although supported functions depend on the PSCI
> > version and not all of them are defined yet, the code returns
> > true as long as the function id is within the reserved PSCI
> > function id range).
> > So, the behavior appears to be inconsistent.
> > Shouldn't it return the validity of the function id according
> > to the vCPU's psci version for non-PSCI 0.1 case as well ?
> > (Otherwise, shouldn't it return true if the function id is valid
> > for any of the PSCI versions ?)
> >
> Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
> with the SMCCC, hence needed some special handling. Only two func_ids> are currently supported by KVM, and we just check for each. The second
> 'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
> specification defines a range of acceptable PSCI func_ids.

I understand PSCI 0.1 is different from PSCI 0.2 or newer versions.
But, my question is: What would you consider "valid" psci function id ?
It seems that the function checks whether or not the func_id is valid
on the vCPU for PSCI 0.1, and checks whether or not the func_id is a
PSCI function id for vCPU with PSCI 0.2 or newer.

I understand either one works for your purpose, but I would think
the behavior should be consistent.

Thanks,
Reiji


>
> If it's confusing, I can add a comment above the second 'if' that it's
> for all PSCI versions >= 0.2.
> > Thanks,
> > Reiji
> >
> Thank you.
> Raghavendra
>
> [1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
> >
> >
> > > +
> > > +       return false;
> > > +}
> > > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > > index 5d38628a8d04..499b45b607b6 100644
> > > --- a/include/kvm/arm_hypercalls.h
> > > +++ b/include/kvm/arm_hypercalls.h
> > > @@ -6,6 +6,11 @@
> > >
> > >  #include <asm/kvm_emulate.h>
> > >
> > > +/* Last valid bits of the bitmapped firmware registers */
> > > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > > +
> > > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > > +
> > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> > >
> > >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> > >
> > >  struct kvm_one_reg;
> > >
> > > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> > >  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);
> > > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > > index 6e55b9283789..c47be3e26965 100644
> > > --- a/include/kvm/arm_psci.h
> > > +++ b/include/kvm/arm_psci.h
> > > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> > >         return KVM_ARM_PSCI_0_1;
> > >  }
> > >
> > > -
> > >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> > >
> > >  #endif /* __KVM_ARM_PSCI_H__ */
> > > --
> > > 2.36.0.rc2.479.g8af0fa9b8e-goog
> > >
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-27  1:46         ` Reiji Watanabe
  0 siblings, 0 replies; 90+ messages in thread
From: Reiji Watanabe @ 2022-04-27  1:46 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

Hi Raghu,

On Mon, Apr 25, 2022 at 9:46 AM Raghavendra Rao Ananta
<rananta@google.com> wrote:
>
> Hi Reiji,
>
> On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
> >
> > Hi Raghu,
> >
> > On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> > <rananta@google.com> wrote:
> > >
> > > KVM regularly introduces new hypercall services to the guests without
> > > any consent from the userspace. This means, the guests can observe
> > > hypercall services in and out as they migrate across various host
> > > kernel versions. This could be a major problem if the guest
> > > discovered a hypercall, started using it, and after getting migrated
> > > to an older kernel realizes that it's no longer available. Depending
> > > on how the guest handles the change, there's a potential chance that
> > > the guest would just panic.
> > >
> > > As a result, there's a need for the userspace to elect the services
> > > that it wishes the guest to discover. It can elect these services
> > > based on the kernels spread across its (migration) fleet. To remedy
> > > this, extend the existing firmware pseudo-registers, such as
> > > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > > for all the hypercall services available.
> > >
> > > These firmware registers are categorized based on the service call
> > > owners, but unlike the existing firmware pseudo-registers, they hold
> > > the features supported in the form of a bitmap.
> > >
> > > During the VM initialization, the registers are set to upper-limit of
> > > the features supported by the corresponding registers. It's expected
> > > that the VMMs discover the features provided by each register via
> > > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > > KVM allows this modification only until the VM has started.
> > >
> > > Some of the standard features are not mapped to any bits of the
> > > registers. But since they can recreate the original problem of
> > > making it available without userspace's consent, they need to
> > > be explicitly added to the case-list in
> > > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> > >
> > > Older userspace code can simply ignore the feature and the
> > > hypercall services will be exposed unconditionally to the guests,
> > > thus ensuring backward compatibility.
> > >
> > > In this patch, the framework adds the register only for ARM's standard
> > > secure services (owner value 4). Currently, this includes support only
> > > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > > register representing mandatory features of v1.0. Other services are
> > > momentarily added in the upcoming patches.
> > >
> > > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> > >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> > >  arch/arm64/kvm/arm.c              |  1 +
> > >  arch/arm64/kvm/guest.c            |  8 ++-
> > >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> > >  arch/arm64/kvm/psci.c             | 13 +++++
> > >  include/kvm/arm_hypercalls.h      |  6 ++
> > >  include/kvm/arm_psci.h            |  2 +-
> > >  8 files changed, 142 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 94a27a7520f4..df07f4c10197 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> > >  struct kvm_arch_memory_slot {
> > >  };
> > >
> > > +/**
> > > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > > + *
> > > + * @std_bmap: Bitmap of standard secure service calls
> > > + */
> > > +struct kvm_smccc_features {
> > > +       unsigned long std_bmap;
> > > +};
> > > +
> > >  struct kvm_arch {
> > >         struct kvm_s2_mmu mmu;
> > >
> > > @@ -150,6 +159,9 @@ struct kvm_arch {
> > >
> > >         u8 pfr0_csv2;
> > >         u8 pfr0_csv3;
> > > +
> > > +       /* Hypercall features firmware registers' descriptor */
> > > +       struct kvm_smccc_features smccc_feat;
> > >  };
> > >
> > >  struct kvm_vcpu_fault_info {
> > > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > > --- a/arch/arm64/include/uapi/asm/kvm.h
> > > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> > >  #define KVM_ARM64_SVE_VLS_WORDS        \
> > >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> > >
> > > +/* Bitmap feature firmware registers */
> > > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > > +                                               ((r) & 0xffff))
> > > +
> > > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > > index 523bc934fe2f..a37fadbd617e 100644
> > > --- a/arch/arm64/kvm/arm.c
> > > +++ b/arch/arm64/kvm/arm.c
> > > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> > >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> > >
> > >         set_default_spectre(kvm);
> > > +       kvm_arm_init_hypercalls(kvm);
> > >
> > >         return ret;
> > >  out_free_stage2_pgd:
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 0d5cca56cbda..8c607199cad1 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >
> > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > > +       case KVM_REG_ARM_FW:
> > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > +               return kvm_arm_get_fw_reg(vcpu, reg);
> > >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> > >         }
> > >
> > > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >
> > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > > +       case KVM_REG_ARM_FW:
> > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > +               return kvm_arm_set_fw_reg(vcpu, reg);
> > >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> > >         }
> > >
> > > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > > index fa6d9378d8e7..df55a04d2fe8 100644
> > > --- a/arch/arm64/kvm/hypercalls.c
> > > +++ b/arch/arm64/kvm/hypercalls.c
> > > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> > >         val[3] = lower_32_bits(cycles);
> > >  }
> > >
> > > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > > +{
> > > +       return test_bit(feat_bit, reg_bmap);
> > > +}
> > > +
> > > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       switch (func_id) {
> > > +       /*
> > > +        * List of function-ids that are not gated with the bitmapped feature
> > > +        * firmware registers, and are to be allowed for servicing the call by default.
> > > +        */
> > > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > > +               return true;
> > > +       default:
> > > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > > +       }
> > > +}
> > > +
> > > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > +
> > > +       switch (func_id) {
> > > +       case ARM_SMCCC_TRNG_VERSION:
> > > +       case ARM_SMCCC_TRNG_FEATURES:
> > > +       case ARM_SMCCC_TRNG_GET_UUID:
> > > +       case ARM_SMCCC_TRNG_RND32:
> > > +       case ARM_SMCCC_TRNG_RND64:
> > > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > > +       default:
> > > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > > +       }
> > > +}
> > > +
> > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >  {
> > >         u32 func_id = smccc_get_function(vcpu);
> > > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >         u32 feature;
> > >         gpa_t gpa;
> > >
> > > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > > +               goto out;
> > > +
> > >         switch (func_id) {
> > >         case ARM_SMCCC_VERSION_FUNC_ID:
> > >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > >                 return kvm_psci_call(vcpu);
> > >         }
> > >
> > > +out:
> > >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> > >         return 1;
> > >  }
> > > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > > +       KVM_REG_ARM_STD_BMAP,
> > >  };
> > >
> > > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > > +{
> > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > +
> > > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > > +}
> > > +
> > >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > >  {
> > >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> > >
> > >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  {
> > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > >         u64 val;
> > >
> > > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> > >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> > >                 break;
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               val = READ_ONCE(smccc_feat->std_bmap);
> > > +               break;
> > >         default:
> > >                 return -ENOENT;
> > >         }
> > > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >         return 0;
> > >  }
> > >
> > > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > > +{
> > > +       int ret = 0;
> > > +       struct kvm *kvm = vcpu->kvm;
> > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > > +
> > > +       switch (reg_id) {
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > > +               break;
> > > +       default:
> > > +               return -ENOENT;
> > > +       }
> > > +
> > > +       /* Check for unsupported bit */
> > > +       if (val & ~fw_reg_features)
> > > +               return -EINVAL;
> > > +
> > > +       mutex_lock(&kvm->lock);
> >
> > Why don't you check if the register value will be modified before
> > getting the lock ? (then there is nothing to do)
> > It would help reduce unnecessary serialization for live migration
> > (even without the vm-scoped register capability).
> >
> That was the case until v5. Since v6, we return -EBUSY unconditionally
> regardless of the incoming value. See Marc's comments in [1].

> That was the case until v5. Since v6, we return -EBUSY unconditionally
> regardless of the incoming value. See Marc's comments in [1].

Even with that, the function could do below to avoid
the unnecessary serialization.
(I would expect mostly the function returns before getting the lock)

        if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags))
              return -EBUSY;

        if (val == *fw_reg_bmap)
              return 0;

        mutex_lock(&kvm->lock);

        <...>

> >
> >
> > > +
> > > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > > +               ret = -EBUSY;
> > > +               goto out;
> > > +       }
> >
> > I just would like to make sure that you are sure that existing
> > userspace you know will not run KVM_RUN for any vCPUs until
> > KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> > correct ?
> >
> Since v6, that is something that we are leaving with the userspace to
> synchronize. See [1].

Understood.


> > > +o
> > > +       WRITE_ONCE(*fw_reg_bmap, val);
> > > +out:
> > > +       mutex_unlock(&kvm->lock);
> > > +       return ret;
> > > +}
> > > +
> > >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  {
> > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >                         return -EINVAL;
> > >
> > >                 return 0;
> > > +       case KVM_REG_ARM_STD_BMAP:
> > > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> > >         default:
> > >                 return -ENOENT;
> > >         }
> > > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > > index 346535169faa..67d1273e8086 100644
> > > --- a/arch/arm64/kvm/psci.c
> > > +++ b/arch/arm64/kvm/psci.c
> > > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> > >                 return -EINVAL;
> > >         }
> > >  }
> > > +
> > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > > +{
> > > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > > +
> > > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > > +               return true;
> >
> > For PSCI 0.1, the function checks if the funct_id is valid for
> > the vCPU (according to the vCPU's PSCI version).
> > For other version of PSCI, the function doesn't care the vCPU's
> > PSCI version (although supported functions depend on the PSCI
> > version and not all of them are defined yet, the code returns
> > true as long as the function id is within the reserved PSCI
> > function id range).
> > So, the behavior appears to be inconsistent.
> > Shouldn't it return the validity of the function id according
> > to the vCPU's psci version for non-PSCI 0.1 case as well ?
> > (Otherwise, shouldn't it return true if the function id is valid
> > for any of the PSCI versions ?)
> >
> Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
> with the SMCCC, hence needed some special handling. Only two func_ids> are currently supported by KVM, and we just check for each. The second
> 'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
> specification defines a range of acceptable PSCI func_ids.

I understand PSCI 0.1 is different from PSCI 0.2 or newer versions.
But, my question is: What would you consider "valid" psci function id ?
It seems that the function checks whether or not the func_id is valid
on the vCPU for PSCI 0.1, and checks whether or not the func_id is a
PSCI function id for vCPU with PSCI 0.2 or newer.

I understand either one works for your purpose, but I would think
the behavior should be consistent.

Thanks,
Reiji


>
> If it's confusing, I can add a comment above the second 'if' that it's
> for all PSCI versions >= 0.2.
> > Thanks,
> > Reiji
> >
> Thank you.
> Raghavendra
>
> [1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
> >
> >
> > > +
> > > +       return false;
> > > +}
> > > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > > index 5d38628a8d04..499b45b607b6 100644
> > > --- a/include/kvm/arm_hypercalls.h
> > > +++ b/include/kvm/arm_hypercalls.h
> > > @@ -6,6 +6,11 @@
> > >
> > >  #include <asm/kvm_emulate.h>
> > >
> > > +/* Last valid bits of the bitmapped firmware registers */
> > > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > > +
> > > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > > +
> > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> > >
> > >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> > >
> > >  struct kvm_one_reg;
> > >
> > > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> > >  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);
> > > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > > index 6e55b9283789..c47be3e26965 100644
> > > --- a/include/kvm/arm_psci.h
> > > +++ b/include/kvm/arm_psci.h
> > > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> > >         return KVM_ARM_PSCI_0_1;
> > >  }
> > >
> > > -
> > >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> > >
> > >  #endif /* __KVM_ARM_PSCI_H__ */
> > > --
> > > 2.36.0.rc2.479.g8af0fa9b8e-goog
> > >

_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
  2022-04-26 16:59       ` Raghavendra Rao Ananta
  (?)
@ 2022-04-27  2:09         ` Gavin Shan
  -1 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-27  2:09 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, kvm, Catalin Marinas, Peter Shier,
	linux-kernel, Paolo Bonzini, Will Deacon, kvmarm,
	linux-arm-kernel

Hi Raghavendra,

On 4/27/22 12:59 AM, Raghavendra Rao Ananta wrote:
> On Tue, Apr 26, 2022 at 12:50 AM Gavin Shan <gshan@redhat.com> wrote:
>> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
>>> Introduce a KVM selftest to check the hypercall interface
>>> for arm64 platforms. The test validates the user-space'
>>> [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
>>> registers as well as its effects on the guest upon certain
>>> configurations.
>>>
>>> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
>>> ---
>>>    tools/testing/selftests/kvm/.gitignore        |   1 +
>>>    tools/testing/selftests/kvm/Makefile          |   1 +
>>>    .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
>>>    3 files changed, 337 insertions(+)
>>>    create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
>>>
>>
>> There are comments about @false_hvc_info[] and some nits, as below.
>> Please evaluate and improve if it makes sense to you. Otherwise, it
>> looks good to me:
>>
>> Reviewed-by: Gavin Shan <gshan@redhat.com>
>>
>>> diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
>>> index 1bb575dfc42e..b17e464ec661 100644
>>> --- a/tools/testing/selftests/kvm/.gitignore
>>> +++ b/tools/testing/selftests/kvm/.gitignore
>>> @@ -2,6 +2,7 @@
>>>    /aarch64/arch_timer
>>>    /aarch64/debug-exceptions
>>>    /aarch64/get-reg-list
>>> +/aarch64/hypercalls
>>>    /aarch64/psci_test
>>>    /aarch64/vcpu_width_config
>>>    /aarch64/vgic_init
>>> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
>>> index c2cf4d318296..97eef0c03d3b 100644
>>> --- a/tools/testing/selftests/kvm/Makefile
>>> +++ b/tools/testing/selftests/kvm/Makefile
>>> @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
>>>    TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
>>>    TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
>>>    TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
>>> +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
>>>    TEST_GEN_PROGS_aarch64 += aarch64/psci_test
>>>    TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
>>>    TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
>>> diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
>>> new file mode 100644
>>> index 000000000000..f404343a0ae3
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
>>> @@ -0,0 +1,335 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +
>>> +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
>>> + *
>>> + * The test validates the basic hypercall functionalities that are exposed
>>> + * via the psuedo-firmware bitmap register. This includes the registers'
>>> + * read/write behavior before and after the VM has started, and if the
>>> + * hypercalls are properly masked or unmasked to the guest when disabled or
>>> + * enabled from the KVM userspace, respectively.
>>> + */
>>> +
>>> +#include <errno.h>
>>> +#include <linux/arm-smccc.h>
>>> +#include <asm/kvm.h>
>>> +#include <kvm_util.h>
>>> +
>>> +#include "processor.h"
>>> +
>>> +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
>>> +
>>> +/* Last valid bits of the bitmapped firmware registers */
>>> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
>>> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX     0
>>> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX  1
>>> +
>>> +struct kvm_fw_reg_info {
>>> +     uint64_t reg;           /* Register definition */
>>> +     uint64_t max_feat_bit;  /* Bit that represents the upper limit of the feature-map */
>>> +};
>>> +
>>> +#define FW_REG_INFO(r)                       \
>>> +     {                                       \
>>> +             .reg = r,                       \
>>> +             .max_feat_bit = r##_BIT_MAX,    \
>>> +     }
>>> +
>>> +static const struct kvm_fw_reg_info fw_reg_info[] = {
>>> +     FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
>>> +     FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
>>> +     FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
>>> +};
>>> +
>>> +enum test_stage {
>>> +     TEST_STAGE_REG_IFACE,
>>> +     TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
>>> +     TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
>>> +     TEST_STAGE_HVC_IFACE_FALSE_INFO,
>>> +     TEST_STAGE_END,
>>> +};
>>> +
>>> +static int stage = TEST_STAGE_REG_IFACE;
>>> +
>>> +struct test_hvc_info {
>>> +     uint32_t func_id;
>>> +     uint64_t arg1;
>>> +};
>>> +
>>> +#define TEST_HVC_INFO(f, a1) \
>>> +     {                       \
>>> +             .func_id = f,   \
>>> +             .arg1 = a1,     \
>>> +     }
>>> +
>>> +static const struct test_hvc_info hvc_info[] = {
>>> +     /* KVM_REG_ARM_STD_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
>>> +
>>> +     /* KVM_REG_ARM_STD_HYP_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
>>> +
>>> +     /* KVM_REG_ARM_VENDOR_HYP_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
>>> +                     ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
>>> +};
>>> +
>>> +/* Feed false hypercall info to test the KVM behavior */
>>> +static const struct test_hvc_info false_hvc_info[] = {
>>> +     /* Feature support check against a different family of hypercalls */
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
>>> +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
>>> +};
>>> +
>>
>> I don't see too much benefits of @false_hvc_info[] because
>> NOT_SUPPORTED is always returned from its test case. I think
>> it and its test case can be removed if you agree. I'm not
>> sure if it was suggested by somebody else.
>>
> While this is not exactly testing the bitmap firmware registers, the
> idea behind introducing false_hvc_info[] was to introduce some
> negative tests and see if KVM handles it well. Especially with
> *_FEATURES func_ids, we can accidentally introduce functional bugs in
> KVM, and these would act as our safety net. I was planning to also
> test with some reserved hypercall numbers, just to test if the kernel
> doesn't panic for some reason.
> 

Ok, thanks for the explanation. It makes sense to me.

>>> +static void guest_test_hvc(const struct test_hvc_info *hc_info)
>>> +{
>>> +     unsigned int i;
>>> +     struct arm_smccc_res res;
>>> +     unsigned int hvc_info_arr_sz;
>>> +
>>> +     hvc_info_arr_sz =
>>> +     hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
>>> +
>>> +     for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
>>> +             memset(&res, 0, sizeof(res));
>>> +             smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
>>> +
>>> +             switch (stage) {
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +                     GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
>>> +                                     res.a0, hc_info->func_id, hc_info->arg1);
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +                     GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
>>> +                                     res.a0, hc_info->func_id, hc_info->arg1);
>>> +                     break;
>>> +             default:
>>> +                     GUEST_ASSERT_1(0, stage);
>>> +             }
>>> +     }
>>> +}
>>> +
>>> +static void guest_code(void)
>>> +{
>>> +     while (stage != TEST_STAGE_END) {
>>> +             switch (stage) {
>>> +             case TEST_STAGE_REG_IFACE:
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +                     guest_test_hvc(hvc_info);
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +                     guest_test_hvc(false_hvc_info);
>>> +                     break;
>>> +             default:
>>> +                     GUEST_ASSERT_1(0, stage);
>>> +             }
>>> +
>>> +             GUEST_SYNC(stage);
>>> +     }
>>> +
>>> +     GUEST_DONE();
>>> +}
>>> +
>>> +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
>>> +{
>>> +     struct kvm_one_reg reg = {
>>> +             .id = id,
>>> +             .addr = (uint64_t)&val,
>>> +     };
>>> +
>>> +     return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
>>> +}
>>> +
>>> +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
>>> +{
>>> +     struct kvm_one_reg reg = {
>>> +             .id = id,
>>> +             .addr = (uint64_t)addr,
>>> +     };
>>> +
>>> +     vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
>>> +}
>>> +
>>> +struct st_time {
>>> +     uint32_t rev;
>>> +     uint32_t attr;
>>> +     uint64_t st_time;
>>> +};
>>> +
>>> +#define STEAL_TIME_SIZE              ((sizeof(struct st_time) + 63) & ~63)
>>> +#define ST_GPA_BASE          (1 << 30)
>>> +
>>> +static void steal_time_init(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t st_ipa = (ulong)ST_GPA_BASE;
>>> +     unsigned int gpages;
>>> +     struct kvm_device_attr dev = {
>>> +             .group = KVM_ARM_VCPU_PVTIME_CTRL,
>>> +             .attr = KVM_ARM_VCPU_PVTIME_IPA,
>>> +             .addr = (uint64_t)&st_ipa,
>>> +     };
>>> +
>>> +     gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
>>> +     vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
>>> +
>>> +     vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
>>> +}
>>> +
>>> +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t val;
>>> +     unsigned int i;
>>> +     int ret;
>>> +
>>> +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
>>> +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
>>> +
>>> +             /* First 'read' should be an upper limit of the features supported */
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
>>> +                     "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
>>> +                     reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
>>> +
>>> +             /* Test a 'write' by disabling all the features of the register map */
>>> +             ret = set_fw_reg(vm, reg_info->reg, 0);
>>> +             TEST_ASSERT(ret == 0,
>>> +                     "Failed to clear all the features of reg: 0x%lx; ret: %d\n",
>>> +                     reg_info->reg, errno);
>>> +
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == 0,
>>> +                     "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
>>> +
>>> +             /*
>>> +              * Test enabling a feature that's not supported.
>>> +              * Avoid this check if all the bits are occupied.
>>> +              */
>>> +             if (reg_info->max_feat_bit < 63) {
>>> +                     ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
>>> +                     TEST_ASSERT(ret != 0 && errno == EINVAL,
>>> +                     "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
>>> +                     errno, reg_info->reg);
>>> +             }
>>> +     }
>>> +}
>>
>> Just in case :)
>>
>>        ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));
>>
> It may be better to cover the entire range, but to test only the
> (max_feat_bit + 1) gives us the advantage of checking if there's any
> discrepancy between the kernel and the test, now that *_BIT_MAX are
> not a part of UAPI headers.
> 
> Probably also include your test along with the existing one?

Thanks for your explanation again. Lets keep it as it is then.

>>
>>> +
>>> +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t val;
>>> +     unsigned int i;
>>> +     int ret;
>>> +
>>> +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
>>> +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
>>> +
>>> +             /*
>>> +              * Before starting the VM, the test clears all the bits.
>>> +              * Check if that's still the case.
>>> +              */
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == 0,
>>> +                     "Expected all the features to be cleared for reg: 0x%lx\n",
>>> +                     reg_info->reg);
>>> +
>>> +             /*
>>> +              * Set all the features for this register again. KVM shouldn't
>>> +              * allow this as the VM is running.
>>> +              */
>>> +             ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
>>> +             TEST_ASSERT(ret != 0 && errno == EBUSY,
>>> +             "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
>>> +             errno, reg_info->reg);
>>> +     }
>>> +}
>>> +
>>
>> I guess you want to check -EBUSY is returned. In that case,
>> the comments here could be clearer, something like below
>> to emphasize '-EBUSY'.
>>
>>           /*
>>            * After VM runs for once, -EBUSY should be returned on attempt
>>            * to set features. Check if the correct errno is returned.
>>            */
>>
> Sounds good.
> 
>>> +static struct kvm_vm *test_vm_create(void)
>>> +{
>>> +     struct kvm_vm *vm;
>>> +
>>> +     vm = vm_create_default(0, 0, guest_code);
>>> +
>>> +     ucall_init(vm, NULL);
>>> +     steal_time_init(vm);
>>> +
>>> +     return vm;
>>> +}
>>> +
>>> +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
>>> +{
>>> +     struct kvm_vm *ret_vm = vm;
>>> +
>>> +     pr_debug("Stage: %d\n", stage);
>>> +
>>> +     switch (stage) {
>>> +     case TEST_STAGE_REG_IFACE:
>>> +             test_fw_regs_after_vm_start(vm);
>>> +             break;
>>> +     case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             /* Start a new VM so that all the features are now enabled by default */
>>> +             kvm_vm_free(vm);
>>> +             ret_vm = test_vm_create();
>>> +             break;
>>> +     case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +     case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +             break;
>>> +     default:
>>> +             TEST_FAIL("Unknown test stage: %d\n", stage);
>>> +     }
>>> +
>>> +     stage++;
>>> +     sync_global_to_guest(vm, stage);
>>> +
>>> +     return ret_vm;
>>> +}
>>> +
>>> +static void test_run(void)
>>> +{
>>> +     struct kvm_vm *vm;
>>> +     struct ucall uc;
>>> +     bool guest_done = false;
>>> +
>>> +     vm = test_vm_create();
>>> +
>>> +     test_fw_regs_before_vm_start(vm);
>>> +
>>> +     while (!guest_done) {
>>> +             vcpu_run(vm, 0);
>>> +
>>> +             switch (get_ucall(vm, 0, &uc)) {
>>> +             case UCALL_SYNC:
>>> +                     vm = test_guest_stage(vm);
>>> +                     break;
>>> +             case UCALL_DONE:
>>> +                     guest_done = true;
>>> +                     break;
>>> +             case UCALL_ABORT:
>>> +                     TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
>>> +                     (const char *)uc.args[0], __FILE__, uc.args[1],
>>> +                     uc.args[2], uc.args[3], uc.args[4], stage);
>>> +                     break;
>>> +             default:
>>> +                     TEST_FAIL("Unexpected guest exit\n");
>>> +             }
>>> +     }
>>> +
>>> +     kvm_vm_free(vm);
>>> +}
>>> +
>>> +int main(void)
>>> +{
>>> +     setbuf(stdout, NULL);
>>> +
>>> +     test_run();
>>> +     return 0;
>>> +}
>>>

[...]

Thanks,
Gavin


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

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
@ 2022-04-27  2:09         ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-27  2:09 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: kvm, Marc Zyngier, Peter Shier, linux-kernel, Will Deacon,
	Catalin Marinas, Paolo Bonzini, kvmarm, linux-arm-kernel

Hi Raghavendra,

On 4/27/22 12:59 AM, Raghavendra Rao Ananta wrote:
> On Tue, Apr 26, 2022 at 12:50 AM Gavin Shan <gshan@redhat.com> wrote:
>> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
>>> Introduce a KVM selftest to check the hypercall interface
>>> for arm64 platforms. The test validates the user-space'
>>> [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
>>> registers as well as its effects on the guest upon certain
>>> configurations.
>>>
>>> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
>>> ---
>>>    tools/testing/selftests/kvm/.gitignore        |   1 +
>>>    tools/testing/selftests/kvm/Makefile          |   1 +
>>>    .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
>>>    3 files changed, 337 insertions(+)
>>>    create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
>>>
>>
>> There are comments about @false_hvc_info[] and some nits, as below.
>> Please evaluate and improve if it makes sense to you. Otherwise, it
>> looks good to me:
>>
>> Reviewed-by: Gavin Shan <gshan@redhat.com>
>>
>>> diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
>>> index 1bb575dfc42e..b17e464ec661 100644
>>> --- a/tools/testing/selftests/kvm/.gitignore
>>> +++ b/tools/testing/selftests/kvm/.gitignore
>>> @@ -2,6 +2,7 @@
>>>    /aarch64/arch_timer
>>>    /aarch64/debug-exceptions
>>>    /aarch64/get-reg-list
>>> +/aarch64/hypercalls
>>>    /aarch64/psci_test
>>>    /aarch64/vcpu_width_config
>>>    /aarch64/vgic_init
>>> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
>>> index c2cf4d318296..97eef0c03d3b 100644
>>> --- a/tools/testing/selftests/kvm/Makefile
>>> +++ b/tools/testing/selftests/kvm/Makefile
>>> @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
>>>    TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
>>>    TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
>>>    TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
>>> +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
>>>    TEST_GEN_PROGS_aarch64 += aarch64/psci_test
>>>    TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
>>>    TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
>>> diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
>>> new file mode 100644
>>> index 000000000000..f404343a0ae3
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
>>> @@ -0,0 +1,335 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +
>>> +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
>>> + *
>>> + * The test validates the basic hypercall functionalities that are exposed
>>> + * via the psuedo-firmware bitmap register. This includes the registers'
>>> + * read/write behavior before and after the VM has started, and if the
>>> + * hypercalls are properly masked or unmasked to the guest when disabled or
>>> + * enabled from the KVM userspace, respectively.
>>> + */
>>> +
>>> +#include <errno.h>
>>> +#include <linux/arm-smccc.h>
>>> +#include <asm/kvm.h>
>>> +#include <kvm_util.h>
>>> +
>>> +#include "processor.h"
>>> +
>>> +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
>>> +
>>> +/* Last valid bits of the bitmapped firmware registers */
>>> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
>>> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX     0
>>> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX  1
>>> +
>>> +struct kvm_fw_reg_info {
>>> +     uint64_t reg;           /* Register definition */
>>> +     uint64_t max_feat_bit;  /* Bit that represents the upper limit of the feature-map */
>>> +};
>>> +
>>> +#define FW_REG_INFO(r)                       \
>>> +     {                                       \
>>> +             .reg = r,                       \
>>> +             .max_feat_bit = r##_BIT_MAX,    \
>>> +     }
>>> +
>>> +static const struct kvm_fw_reg_info fw_reg_info[] = {
>>> +     FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
>>> +     FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
>>> +     FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
>>> +};
>>> +
>>> +enum test_stage {
>>> +     TEST_STAGE_REG_IFACE,
>>> +     TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
>>> +     TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
>>> +     TEST_STAGE_HVC_IFACE_FALSE_INFO,
>>> +     TEST_STAGE_END,
>>> +};
>>> +
>>> +static int stage = TEST_STAGE_REG_IFACE;
>>> +
>>> +struct test_hvc_info {
>>> +     uint32_t func_id;
>>> +     uint64_t arg1;
>>> +};
>>> +
>>> +#define TEST_HVC_INFO(f, a1) \
>>> +     {                       \
>>> +             .func_id = f,   \
>>> +             .arg1 = a1,     \
>>> +     }
>>> +
>>> +static const struct test_hvc_info hvc_info[] = {
>>> +     /* KVM_REG_ARM_STD_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
>>> +
>>> +     /* KVM_REG_ARM_STD_HYP_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
>>> +
>>> +     /* KVM_REG_ARM_VENDOR_HYP_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
>>> +                     ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
>>> +};
>>> +
>>> +/* Feed false hypercall info to test the KVM behavior */
>>> +static const struct test_hvc_info false_hvc_info[] = {
>>> +     /* Feature support check against a different family of hypercalls */
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
>>> +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
>>> +};
>>> +
>>
>> I don't see too much benefits of @false_hvc_info[] because
>> NOT_SUPPORTED is always returned from its test case. I think
>> it and its test case can be removed if you agree. I'm not
>> sure if it was suggested by somebody else.
>>
> While this is not exactly testing the bitmap firmware registers, the
> idea behind introducing false_hvc_info[] was to introduce some
> negative tests and see if KVM handles it well. Especially with
> *_FEATURES func_ids, we can accidentally introduce functional bugs in
> KVM, and these would act as our safety net. I was planning to also
> test with some reserved hypercall numbers, just to test if the kernel
> doesn't panic for some reason.
> 

Ok, thanks for the explanation. It makes sense to me.

>>> +static void guest_test_hvc(const struct test_hvc_info *hc_info)
>>> +{
>>> +     unsigned int i;
>>> +     struct arm_smccc_res res;
>>> +     unsigned int hvc_info_arr_sz;
>>> +
>>> +     hvc_info_arr_sz =
>>> +     hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
>>> +
>>> +     for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
>>> +             memset(&res, 0, sizeof(res));
>>> +             smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
>>> +
>>> +             switch (stage) {
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +                     GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
>>> +                                     res.a0, hc_info->func_id, hc_info->arg1);
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +                     GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
>>> +                                     res.a0, hc_info->func_id, hc_info->arg1);
>>> +                     break;
>>> +             default:
>>> +                     GUEST_ASSERT_1(0, stage);
>>> +             }
>>> +     }
>>> +}
>>> +
>>> +static void guest_code(void)
>>> +{
>>> +     while (stage != TEST_STAGE_END) {
>>> +             switch (stage) {
>>> +             case TEST_STAGE_REG_IFACE:
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +                     guest_test_hvc(hvc_info);
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +                     guest_test_hvc(false_hvc_info);
>>> +                     break;
>>> +             default:
>>> +                     GUEST_ASSERT_1(0, stage);
>>> +             }
>>> +
>>> +             GUEST_SYNC(stage);
>>> +     }
>>> +
>>> +     GUEST_DONE();
>>> +}
>>> +
>>> +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
>>> +{
>>> +     struct kvm_one_reg reg = {
>>> +             .id = id,
>>> +             .addr = (uint64_t)&val,
>>> +     };
>>> +
>>> +     return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
>>> +}
>>> +
>>> +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
>>> +{
>>> +     struct kvm_one_reg reg = {
>>> +             .id = id,
>>> +             .addr = (uint64_t)addr,
>>> +     };
>>> +
>>> +     vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
>>> +}
>>> +
>>> +struct st_time {
>>> +     uint32_t rev;
>>> +     uint32_t attr;
>>> +     uint64_t st_time;
>>> +};
>>> +
>>> +#define STEAL_TIME_SIZE              ((sizeof(struct st_time) + 63) & ~63)
>>> +#define ST_GPA_BASE          (1 << 30)
>>> +
>>> +static void steal_time_init(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t st_ipa = (ulong)ST_GPA_BASE;
>>> +     unsigned int gpages;
>>> +     struct kvm_device_attr dev = {
>>> +             .group = KVM_ARM_VCPU_PVTIME_CTRL,
>>> +             .attr = KVM_ARM_VCPU_PVTIME_IPA,
>>> +             .addr = (uint64_t)&st_ipa,
>>> +     };
>>> +
>>> +     gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
>>> +     vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
>>> +
>>> +     vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
>>> +}
>>> +
>>> +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t val;
>>> +     unsigned int i;
>>> +     int ret;
>>> +
>>> +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
>>> +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
>>> +
>>> +             /* First 'read' should be an upper limit of the features supported */
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
>>> +                     "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
>>> +                     reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
>>> +
>>> +             /* Test a 'write' by disabling all the features of the register map */
>>> +             ret = set_fw_reg(vm, reg_info->reg, 0);
>>> +             TEST_ASSERT(ret == 0,
>>> +                     "Failed to clear all the features of reg: 0x%lx; ret: %d\n",
>>> +                     reg_info->reg, errno);
>>> +
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == 0,
>>> +                     "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
>>> +
>>> +             /*
>>> +              * Test enabling a feature that's not supported.
>>> +              * Avoid this check if all the bits are occupied.
>>> +              */
>>> +             if (reg_info->max_feat_bit < 63) {
>>> +                     ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
>>> +                     TEST_ASSERT(ret != 0 && errno == EINVAL,
>>> +                     "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
>>> +                     errno, reg_info->reg);
>>> +             }
>>> +     }
>>> +}
>>
>> Just in case :)
>>
>>        ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));
>>
> It may be better to cover the entire range, but to test only the
> (max_feat_bit + 1) gives us the advantage of checking if there's any
> discrepancy between the kernel and the test, now that *_BIT_MAX are
> not a part of UAPI headers.
> 
> Probably also include your test along with the existing one?

Thanks for your explanation again. Lets keep it as it is then.

>>
>>> +
>>> +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t val;
>>> +     unsigned int i;
>>> +     int ret;
>>> +
>>> +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
>>> +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
>>> +
>>> +             /*
>>> +              * Before starting the VM, the test clears all the bits.
>>> +              * Check if that's still the case.
>>> +              */
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == 0,
>>> +                     "Expected all the features to be cleared for reg: 0x%lx\n",
>>> +                     reg_info->reg);
>>> +
>>> +             /*
>>> +              * Set all the features for this register again. KVM shouldn't
>>> +              * allow this as the VM is running.
>>> +              */
>>> +             ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
>>> +             TEST_ASSERT(ret != 0 && errno == EBUSY,
>>> +             "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
>>> +             errno, reg_info->reg);
>>> +     }
>>> +}
>>> +
>>
>> I guess you want to check -EBUSY is returned. In that case,
>> the comments here could be clearer, something like below
>> to emphasize '-EBUSY'.
>>
>>           /*
>>            * After VM runs for once, -EBUSY should be returned on attempt
>>            * to set features. Check if the correct errno is returned.
>>            */
>>
> Sounds good.
> 
>>> +static struct kvm_vm *test_vm_create(void)
>>> +{
>>> +     struct kvm_vm *vm;
>>> +
>>> +     vm = vm_create_default(0, 0, guest_code);
>>> +
>>> +     ucall_init(vm, NULL);
>>> +     steal_time_init(vm);
>>> +
>>> +     return vm;
>>> +}
>>> +
>>> +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
>>> +{
>>> +     struct kvm_vm *ret_vm = vm;
>>> +
>>> +     pr_debug("Stage: %d\n", stage);
>>> +
>>> +     switch (stage) {
>>> +     case TEST_STAGE_REG_IFACE:
>>> +             test_fw_regs_after_vm_start(vm);
>>> +             break;
>>> +     case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             /* Start a new VM so that all the features are now enabled by default */
>>> +             kvm_vm_free(vm);
>>> +             ret_vm = test_vm_create();
>>> +             break;
>>> +     case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +     case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +             break;
>>> +     default:
>>> +             TEST_FAIL("Unknown test stage: %d\n", stage);
>>> +     }
>>> +
>>> +     stage++;
>>> +     sync_global_to_guest(vm, stage);
>>> +
>>> +     return ret_vm;
>>> +}
>>> +
>>> +static void test_run(void)
>>> +{
>>> +     struct kvm_vm *vm;
>>> +     struct ucall uc;
>>> +     bool guest_done = false;
>>> +
>>> +     vm = test_vm_create();
>>> +
>>> +     test_fw_regs_before_vm_start(vm);
>>> +
>>> +     while (!guest_done) {
>>> +             vcpu_run(vm, 0);
>>> +
>>> +             switch (get_ucall(vm, 0, &uc)) {
>>> +             case UCALL_SYNC:
>>> +                     vm = test_guest_stage(vm);
>>> +                     break;
>>> +             case UCALL_DONE:
>>> +                     guest_done = true;
>>> +                     break;
>>> +             case UCALL_ABORT:
>>> +                     TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
>>> +                     (const char *)uc.args[0], __FILE__, uc.args[1],
>>> +                     uc.args[2], uc.args[3], uc.args[4], stage);
>>> +                     break;
>>> +             default:
>>> +                     TEST_FAIL("Unexpected guest exit\n");
>>> +             }
>>> +     }
>>> +
>>> +     kvm_vm_free(vm);
>>> +}
>>> +
>>> +int main(void)
>>> +{
>>> +     setbuf(stdout, NULL);
>>> +
>>> +     test_run();
>>> +     return 0;
>>> +}
>>>

[...]

Thanks,
Gavin

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test
@ 2022-04-27  2:09         ` Gavin Shan
  0 siblings, 0 replies; 90+ messages in thread
From: Gavin Shan @ 2022-04-27  2:09 UTC (permalink / raw)
  To: Raghavendra Rao Ananta
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, kvm, Catalin Marinas, Peter Shier,
	linux-kernel, Paolo Bonzini, Will Deacon, kvmarm,
	linux-arm-kernel

Hi Raghavendra,

On 4/27/22 12:59 AM, Raghavendra Rao Ananta wrote:
> On Tue, Apr 26, 2022 at 12:50 AM Gavin Shan <gshan@redhat.com> wrote:
>> On 4/23/22 8:03 AM, Raghavendra Rao Ananta wrote:
>>> Introduce a KVM selftest to check the hypercall interface
>>> for arm64 platforms. The test validates the user-space'
>>> [GET|SET]_ONE_REG interface to read/write the psuedo-firmware
>>> registers as well as its effects on the guest upon certain
>>> configurations.
>>>
>>> Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
>>> ---
>>>    tools/testing/selftests/kvm/.gitignore        |   1 +
>>>    tools/testing/selftests/kvm/Makefile          |   1 +
>>>    .../selftests/kvm/aarch64/hypercalls.c        | 335 ++++++++++++++++++
>>>    3 files changed, 337 insertions(+)
>>>    create mode 100644 tools/testing/selftests/kvm/aarch64/hypercalls.c
>>>
>>
>> There are comments about @false_hvc_info[] and some nits, as below.
>> Please evaluate and improve if it makes sense to you. Otherwise, it
>> looks good to me:
>>
>> Reviewed-by: Gavin Shan <gshan@redhat.com>
>>
>>> diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
>>> index 1bb575dfc42e..b17e464ec661 100644
>>> --- a/tools/testing/selftests/kvm/.gitignore
>>> +++ b/tools/testing/selftests/kvm/.gitignore
>>> @@ -2,6 +2,7 @@
>>>    /aarch64/arch_timer
>>>    /aarch64/debug-exceptions
>>>    /aarch64/get-reg-list
>>> +/aarch64/hypercalls
>>>    /aarch64/psci_test
>>>    /aarch64/vcpu_width_config
>>>    /aarch64/vgic_init
>>> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
>>> index c2cf4d318296..97eef0c03d3b 100644
>>> --- a/tools/testing/selftests/kvm/Makefile
>>> +++ b/tools/testing/selftests/kvm/Makefile
>>> @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
>>>    TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
>>>    TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
>>>    TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
>>> +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
>>>    TEST_GEN_PROGS_aarch64 += aarch64/psci_test
>>>    TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
>>>    TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
>>> diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c
>>> new file mode 100644
>>> index 000000000000..f404343a0ae3
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c
>>> @@ -0,0 +1,335 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +
>>> +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface.
>>> + *
>>> + * The test validates the basic hypercall functionalities that are exposed
>>> + * via the psuedo-firmware bitmap register. This includes the registers'
>>> + * read/write behavior before and after the VM has started, and if the
>>> + * hypercalls are properly masked or unmasked to the guest when disabled or
>>> + * enabled from the KVM userspace, respectively.
>>> + */
>>> +
>>> +#include <errno.h>
>>> +#include <linux/arm-smccc.h>
>>> +#include <asm/kvm.h>
>>> +#include <kvm_util.h>
>>> +
>>> +#include "processor.h"
>>> +
>>> +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0))
>>> +
>>> +/* Last valid bits of the bitmapped firmware registers */
>>> +#define KVM_REG_ARM_STD_BMAP_BIT_MAX         0
>>> +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX     0
>>> +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX  1
>>> +
>>> +struct kvm_fw_reg_info {
>>> +     uint64_t reg;           /* Register definition */
>>> +     uint64_t max_feat_bit;  /* Bit that represents the upper limit of the feature-map */
>>> +};
>>> +
>>> +#define FW_REG_INFO(r)                       \
>>> +     {                                       \
>>> +             .reg = r,                       \
>>> +             .max_feat_bit = r##_BIT_MAX,    \
>>> +     }
>>> +
>>> +static const struct kvm_fw_reg_info fw_reg_info[] = {
>>> +     FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
>>> +     FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
>>> +     FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
>>> +};
>>> +
>>> +enum test_stage {
>>> +     TEST_STAGE_REG_IFACE,
>>> +     TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
>>> +     TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
>>> +     TEST_STAGE_HVC_IFACE_FALSE_INFO,
>>> +     TEST_STAGE_END,
>>> +};
>>> +
>>> +static int stage = TEST_STAGE_REG_IFACE;
>>> +
>>> +struct test_hvc_info {
>>> +     uint32_t func_id;
>>> +     uint64_t arg1;
>>> +};
>>> +
>>> +#define TEST_HVC_INFO(f, a1) \
>>> +     {                       \
>>> +             .func_id = f,   \
>>> +             .arg1 = a1,     \
>>> +     }
>>> +
>>> +static const struct test_hvc_info hvc_info[] = {
>>> +     /* KVM_REG_ARM_STD_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),
>>> +
>>> +     /* KVM_REG_ARM_STD_HYP_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),
>>> +
>>> +     /* KVM_REG_ARM_VENDOR_HYP_BMAP */
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
>>> +                     ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
>>> +     TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
>>> +};
>>> +
>>> +/* Feed false hypercall info to test the KVM behavior */
>>> +static const struct test_hvc_info false_hvc_info[] = {
>>> +     /* Feature support check against a different family of hypercalls */
>>> +     TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
>>> +     TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
>>> +     TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
>>> +};
>>> +
>>
>> I don't see too much benefits of @false_hvc_info[] because
>> NOT_SUPPORTED is always returned from its test case. I think
>> it and its test case can be removed if you agree. I'm not
>> sure if it was suggested by somebody else.
>>
> While this is not exactly testing the bitmap firmware registers, the
> idea behind introducing false_hvc_info[] was to introduce some
> negative tests and see if KVM handles it well. Especially with
> *_FEATURES func_ids, we can accidentally introduce functional bugs in
> KVM, and these would act as our safety net. I was planning to also
> test with some reserved hypercall numbers, just to test if the kernel
> doesn't panic for some reason.
> 

Ok, thanks for the explanation. It makes sense to me.

>>> +static void guest_test_hvc(const struct test_hvc_info *hc_info)
>>> +{
>>> +     unsigned int i;
>>> +     struct arm_smccc_res res;
>>> +     unsigned int hvc_info_arr_sz;
>>> +
>>> +     hvc_info_arr_sz =
>>> +     hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);
>>> +
>>> +     for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
>>> +             memset(&res, 0, sizeof(res));
>>> +             smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
>>> +
>>> +             switch (stage) {
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +                     GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED,
>>> +                                     res.a0, hc_info->func_id, hc_info->arg1);
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +                     GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED,
>>> +                                     res.a0, hc_info->func_id, hc_info->arg1);
>>> +                     break;
>>> +             default:
>>> +                     GUEST_ASSERT_1(0, stage);
>>> +             }
>>> +     }
>>> +}
>>> +
>>> +static void guest_code(void)
>>> +{
>>> +     while (stage != TEST_STAGE_END) {
>>> +             switch (stage) {
>>> +             case TEST_STAGE_REG_IFACE:
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +                     guest_test_hvc(hvc_info);
>>> +                     break;
>>> +             case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +                     guest_test_hvc(false_hvc_info);
>>> +                     break;
>>> +             default:
>>> +                     GUEST_ASSERT_1(0, stage);
>>> +             }
>>> +
>>> +             GUEST_SYNC(stage);
>>> +     }
>>> +
>>> +     GUEST_DONE();
>>> +}
>>> +
>>> +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val)
>>> +{
>>> +     struct kvm_one_reg reg = {
>>> +             .id = id,
>>> +             .addr = (uint64_t)&val,
>>> +     };
>>> +
>>> +     return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
>>> +}
>>> +
>>> +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr)
>>> +{
>>> +     struct kvm_one_reg reg = {
>>> +             .id = id,
>>> +             .addr = (uint64_t)addr,
>>> +     };
>>> +
>>> +     vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
>>> +}
>>> +
>>> +struct st_time {
>>> +     uint32_t rev;
>>> +     uint32_t attr;
>>> +     uint64_t st_time;
>>> +};
>>> +
>>> +#define STEAL_TIME_SIZE              ((sizeof(struct st_time) + 63) & ~63)
>>> +#define ST_GPA_BASE          (1 << 30)
>>> +
>>> +static void steal_time_init(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t st_ipa = (ulong)ST_GPA_BASE;
>>> +     unsigned int gpages;
>>> +     struct kvm_device_attr dev = {
>>> +             .group = KVM_ARM_VCPU_PVTIME_CTRL,
>>> +             .attr = KVM_ARM_VCPU_PVTIME_IPA,
>>> +             .addr = (uint64_t)&st_ipa,
>>> +     };
>>> +
>>> +     gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
>>> +     vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
>>> +
>>> +     vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev);
>>> +}
>>> +
>>> +static void test_fw_regs_before_vm_start(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t val;
>>> +     unsigned int i;
>>> +     int ret;
>>> +
>>> +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
>>> +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
>>> +
>>> +             /* First 'read' should be an upper limit of the features supported */
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
>>> +                     "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
>>> +                     reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
>>> +
>>> +             /* Test a 'write' by disabling all the features of the register map */
>>> +             ret = set_fw_reg(vm, reg_info->reg, 0);
>>> +             TEST_ASSERT(ret == 0,
>>> +                     "Failed to clear all the features of reg: 0x%lx; ret: %d\n",
>>> +                     reg_info->reg, errno);
>>> +
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == 0,
>>> +                     "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
>>> +
>>> +             /*
>>> +              * Test enabling a feature that's not supported.
>>> +              * Avoid this check if all the bits are occupied.
>>> +              */
>>> +             if (reg_info->max_feat_bit < 63) {
>>> +                     ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
>>> +                     TEST_ASSERT(ret != 0 && errno == EINVAL,
>>> +                     "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
>>> +                     errno, reg_info->reg);
>>> +             }
>>> +     }
>>> +}
>>
>> Just in case :)
>>
>>        ret = set_fw_reg(vm, reg_info->reg, GENMASK(63, reg_info->max_feat_bit + 1));
>>
> It may be better to cover the entire range, but to test only the
> (max_feat_bit + 1) gives us the advantage of checking if there's any
> discrepancy between the kernel and the test, now that *_BIT_MAX are
> not a part of UAPI headers.
> 
> Probably also include your test along with the existing one?

Thanks for your explanation again. Lets keep it as it is then.

>>
>>> +
>>> +static void test_fw_regs_after_vm_start(struct kvm_vm *vm)
>>> +{
>>> +     uint64_t val;
>>> +     unsigned int i;
>>> +     int ret;
>>> +
>>> +     for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) {
>>> +             const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i];
>>> +
>>> +             /*
>>> +              * Before starting the VM, the test clears all the bits.
>>> +              * Check if that's still the case.
>>> +              */
>>> +             get_fw_reg(vm, reg_info->reg, &val);
>>> +             TEST_ASSERT(val == 0,
>>> +                     "Expected all the features to be cleared for reg: 0x%lx\n",
>>> +                     reg_info->reg);
>>> +
>>> +             /*
>>> +              * Set all the features for this register again. KVM shouldn't
>>> +              * allow this as the VM is running.
>>> +              */
>>> +             ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
>>> +             TEST_ASSERT(ret != 0 && errno == EBUSY,
>>> +             "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
>>> +             errno, reg_info->reg);
>>> +     }
>>> +}
>>> +
>>
>> I guess you want to check -EBUSY is returned. In that case,
>> the comments here could be clearer, something like below
>> to emphasize '-EBUSY'.
>>
>>           /*
>>            * After VM runs for once, -EBUSY should be returned on attempt
>>            * to set features. Check if the correct errno is returned.
>>            */
>>
> Sounds good.
> 
>>> +static struct kvm_vm *test_vm_create(void)
>>> +{
>>> +     struct kvm_vm *vm;
>>> +
>>> +     vm = vm_create_default(0, 0, guest_code);
>>> +
>>> +     ucall_init(vm, NULL);
>>> +     steal_time_init(vm);
>>> +
>>> +     return vm;
>>> +}
>>> +
>>> +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm)
>>> +{
>>> +     struct kvm_vm *ret_vm = vm;
>>> +
>>> +     pr_debug("Stage: %d\n", stage);
>>> +
>>> +     switch (stage) {
>>> +     case TEST_STAGE_REG_IFACE:
>>> +             test_fw_regs_after_vm_start(vm);
>>> +             break;
>>> +     case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
>>> +             /* Start a new VM so that all the features are now enabled by default */
>>> +             kvm_vm_free(vm);
>>> +             ret_vm = test_vm_create();
>>> +             break;
>>> +     case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:
>>> +     case TEST_STAGE_HVC_IFACE_FALSE_INFO:
>>> +             break;
>>> +     default:
>>> +             TEST_FAIL("Unknown test stage: %d\n", stage);
>>> +     }
>>> +
>>> +     stage++;
>>> +     sync_global_to_guest(vm, stage);
>>> +
>>> +     return ret_vm;
>>> +}
>>> +
>>> +static void test_run(void)
>>> +{
>>> +     struct kvm_vm *vm;
>>> +     struct ucall uc;
>>> +     bool guest_done = false;
>>> +
>>> +     vm = test_vm_create();
>>> +
>>> +     test_fw_regs_before_vm_start(vm);
>>> +
>>> +     while (!guest_done) {
>>> +             vcpu_run(vm, 0);
>>> +
>>> +             switch (get_ucall(vm, 0, &uc)) {
>>> +             case UCALL_SYNC:
>>> +                     vm = test_guest_stage(vm);
>>> +                     break;
>>> +             case UCALL_DONE:
>>> +                     guest_done = true;
>>> +                     break;
>>> +             case UCALL_ABORT:
>>> +                     TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u",
>>> +                     (const char *)uc.args[0], __FILE__, uc.args[1],
>>> +                     uc.args[2], uc.args[3], uc.args[4], stage);
>>> +                     break;
>>> +             default:
>>> +                     TEST_FAIL("Unexpected guest exit\n");
>>> +             }
>>> +     }
>>> +
>>> +     kvm_vm_free(vm);
>>> +}
>>> +
>>> +int main(void)
>>> +{
>>> +     setbuf(stdout, NULL);
>>> +
>>> +     test_run();
>>> +     return 0;
>>> +}
>>>

[...]

Thanks,
Gavin


_______________________________________________
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] 90+ messages in thread

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
  2022-04-27  1:46         ` Reiji Watanabe
  (?)
@ 2022-04-27 17:57           ` Raghavendra Rao Ananta
  -1 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-27 17:57 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

On Tue, Apr 26, 2022 at 6:46 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Mon, Apr 25, 2022 at 9:46 AM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Hi Reiji,
> >
> > On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
> > >
> > > Hi Raghu,
> > >
> > > On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> > > <rananta@google.com> wrote:
> > > >
> > > > KVM regularly introduces new hypercall services to the guests without
> > > > any consent from the userspace. This means, the guests can observe
> > > > hypercall services in and out as they migrate across various host
> > > > kernel versions. This could be a major problem if the guest
> > > > discovered a hypercall, started using it, and after getting migrated
> > > > to an older kernel realizes that it's no longer available. Depending
> > > > on how the guest handles the change, there's a potential chance that
> > > > the guest would just panic.
> > > >
> > > > As a result, there's a need for the userspace to elect the services
> > > > that it wishes the guest to discover. It can elect these services
> > > > based on the kernels spread across its (migration) fleet. To remedy
> > > > this, extend the existing firmware pseudo-registers, such as
> > > > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > > > for all the hypercall services available.
> > > >
> > > > These firmware registers are categorized based on the service call
> > > > owners, but unlike the existing firmware pseudo-registers, they hold
> > > > the features supported in the form of a bitmap.
> > > >
> > > > During the VM initialization, the registers are set to upper-limit of
> > > > the features supported by the corresponding registers. It's expected
> > > > that the VMMs discover the features provided by each register via
> > > > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > > > KVM allows this modification only until the VM has started.
> > > >
> > > > Some of the standard features are not mapped to any bits of the
> > > > registers. But since they can recreate the original problem of
> > > > making it available without userspace's consent, they need to
> > > > be explicitly added to the case-list in
> > > > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > > > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > > > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> > > >
> > > > Older userspace code can simply ignore the feature and the
> > > > hypercall services will be exposed unconditionally to the guests,
> > > > thus ensuring backward compatibility.
> > > >
> > > > In this patch, the framework adds the register only for ARM's standard
> > > > secure services (owner value 4). Currently, this includes support only
> > > > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > > > register representing mandatory features of v1.0. Other services are
> > > > momentarily added in the upcoming patches.
> > > >
> > > > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > > > ---
> > > >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> > > >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> > > >  arch/arm64/kvm/arm.c              |  1 +
> > > >  arch/arm64/kvm/guest.c            |  8 ++-
> > > >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> > > >  arch/arm64/kvm/psci.c             | 13 +++++
> > > >  include/kvm/arm_hypercalls.h      |  6 ++
> > > >  include/kvm/arm_psci.h            |  2 +-
> > > >  8 files changed, 142 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > > index 94a27a7520f4..df07f4c10197 100644
> > > > --- a/arch/arm64/include/asm/kvm_host.h
> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> > > >  struct kvm_arch_memory_slot {
> > > >  };
> > > >
> > > > +/**
> > > > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > > > + *
> > > > + * @std_bmap: Bitmap of standard secure service calls
> > > > + */
> > > > +struct kvm_smccc_features {
> > > > +       unsigned long std_bmap;
> > > > +};
> > > > +
> > > >  struct kvm_arch {
> > > >         struct kvm_s2_mmu mmu;
> > > >
> > > > @@ -150,6 +159,9 @@ struct kvm_arch {
> > > >
> > > >         u8 pfr0_csv2;
> > > >         u8 pfr0_csv3;
> > > > +
> > > > +       /* Hypercall features firmware registers' descriptor */
> > > > +       struct kvm_smccc_features smccc_feat;
> > > >  };
> > > >
> > > >  struct kvm_vcpu_fault_info {
> > > > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > > > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > > > --- a/arch/arm64/include/uapi/asm/kvm.h
> > > > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > > > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> > > >  #define KVM_ARM64_SVE_VLS_WORDS        \
> > > >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> > > >
> > > > +/* Bitmap feature firmware registers */
> > > > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > > > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > > > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > > > +                                               ((r) & 0xffff))
> > > > +
> > > > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > > > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > > > index 523bc934fe2f..a37fadbd617e 100644
> > > > --- a/arch/arm64/kvm/arm.c
> > > > +++ b/arch/arm64/kvm/arm.c
> > > > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> > > >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> > > >
> > > >         set_default_spectre(kvm);
> > > > +       kvm_arm_init_hypercalls(kvm);
> > > >
> > > >         return ret;
> > > >  out_free_stage2_pgd:
> > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > > index 0d5cca56cbda..8c607199cad1 100644
> > > > --- a/arch/arm64/kvm/guest.c
> > > > +++ b/arch/arm64/kvm/guest.c
> > > > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >
> > > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > > > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > > > +       case KVM_REG_ARM_FW:
> > > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > > +               return kvm_arm_get_fw_reg(vcpu, reg);
> > > >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> > > >         }
> > > >
> > > > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >
> > > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > > > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > > > +       case KVM_REG_ARM_FW:
> > > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > > +               return kvm_arm_set_fw_reg(vcpu, reg);
> > > >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> > > >         }
> > > >
> > > > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > > > index fa6d9378d8e7..df55a04d2fe8 100644
> > > > --- a/arch/arm64/kvm/hypercalls.c
> > > > +++ b/arch/arm64/kvm/hypercalls.c
> > > > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> > > >         val[3] = lower_32_bits(cycles);
> > > >  }
> > > >
> > > > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > > > +{
> > > > +       return test_bit(feat_bit, reg_bmap);
> > > > +}
> > > > +
> > > > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       switch (func_id) {
> > > > +       /*
> > > > +        * List of function-ids that are not gated with the bitmapped feature
> > > > +        * firmware registers, and are to be allowed for servicing the call by default.
> > > > +        */
> > > > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > > > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > > > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > > > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > > > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > > > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > > > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > > > +               return true;
> > > > +       default:
> > > > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > > > +       }
> > > > +}
> > > > +
> > > > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > > +
> > > > +       switch (func_id) {
> > > > +       case ARM_SMCCC_TRNG_VERSION:
> > > > +       case ARM_SMCCC_TRNG_FEATURES:
> > > > +       case ARM_SMCCC_TRNG_GET_UUID:
> > > > +       case ARM_SMCCC_TRNG_RND32:
> > > > +       case ARM_SMCCC_TRNG_RND64:
> > > > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > > > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > > > +       default:
> > > > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > > > +       }
> > > > +}
> > > > +
> > > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >  {
> > > >         u32 func_id = smccc_get_function(vcpu);
> > > > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >         u32 feature;
> > > >         gpa_t gpa;
> > > >
> > > > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > > > +               goto out;
> > > > +
> > > >         switch (func_id) {
> > > >         case ARM_SMCCC_VERSION_FUNC_ID:
> > > >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > > > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >                 return kvm_psci_call(vcpu);
> > > >         }
> > > >
> > > > +out:
> > > >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> > > >         return 1;
> > > >  }
> > > > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > > > +       KVM_REG_ARM_STD_BMAP,
> > > >  };
> > > >
> > > > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > > > +{
> > > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > > +
> > > > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > > > +}
> > > > +
> > > >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > > >  {
> > > >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > > > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> > > >
> > > >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  {
> > > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > >         u64 val;
> > > >
> > > > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> > > >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> > > >                 break;
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               val = READ_ONCE(smccc_feat->std_bmap);
> > > > +               break;
> > > >         default:
> > > >                 return -ENOENT;
> > > >         }
> > > > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >         return 0;
> > > >  }
> > > >
> > > > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > > > +{
> > > > +       int ret = 0;
> > > > +       struct kvm *kvm = vcpu->kvm;
> > > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > > > +
> > > > +       switch (reg_id) {
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > > > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > > > +               break;
> > > > +       default:
> > > > +               return -ENOENT;
> > > > +       }
> > > > +
> > > > +       /* Check for unsupported bit */
> > > > +       if (val & ~fw_reg_features)
> > > > +               return -EINVAL;
> > > > +
> > > > +       mutex_lock(&kvm->lock);
> > >
> > > Why don't you check if the register value will be modified before
> > > getting the lock ? (then there is nothing to do)
> > > It would help reduce unnecessary serialization for live migration
> > > (even without the vm-scoped register capability).
> > >
> > That was the case until v5. Since v6, we return -EBUSY unconditionally
> > regardless of the incoming value. See Marc's comments in [1].
>
> > That was the case until v5. Since v6, we return -EBUSY unconditionally
> > regardless of the incoming value. See Marc's comments in [1].
>
> Even with that, the function could do below to avoid
> the unnecessary serialization.
> (I would expect mostly the function returns before getting the lock)
>
>         if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags))
>               return -EBUSY;
>
>         if (val == *fw_reg_bmap)
>               return 0;
>
>         mutex_lock(&kvm->lock);
>
>         <...>
>
Great idea! I can try this out. Thanks for the suggestion.

> > >
> > >
> > > > +
> > > > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > > > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > > > +               ret = -EBUSY;
> > > > +               goto out;
> > > > +       }
> > >
> > > I just would like to make sure that you are sure that existing
> > > userspace you know will not run KVM_RUN for any vCPUs until
> > > KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> > > correct ?
> > >
> > Since v6, that is something that we are leaving with the userspace to
> > synchronize. See [1].
>
> Understood.
>
>
> > > > +o
> > > > +       WRITE_ONCE(*fw_reg_bmap, val);
> > > > +out:
> > > > +       mutex_unlock(&kvm->lock);
> > > > +       return ret;
> > > > +}
> > > > +
> > > >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  {
> > > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >                         return -EINVAL;
> > > >
> > > >                 return 0;
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> > > >         default:
> > > >                 return -ENOENT;
> > > >         }
> > > > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > > > index 346535169faa..67d1273e8086 100644
> > > > --- a/arch/arm64/kvm/psci.c
> > > > +++ b/arch/arm64/kvm/psci.c
> > > > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> > > >                 return -EINVAL;
> > > >         }
> > > >  }
> > > > +
> > > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > > > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > > > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > > > +
> > > > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > > > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > > > +               return true;
> > >
> > > For PSCI 0.1, the function checks if the funct_id is valid for
> > > the vCPU (according to the vCPU's PSCI version).
> > > For other version of PSCI, the function doesn't care the vCPU's
> > > PSCI version (although supported functions depend on the PSCI
> > > version and not all of them are defined yet, the code returns
> > > true as long as the function id is within the reserved PSCI
> > > function id range).
> > > So, the behavior appears to be inconsistent.
> > > Shouldn't it return the validity of the function id according
> > > to the vCPU's psci version for non-PSCI 0.1 case as well ?
> > > (Otherwise, shouldn't it return true if the function id is valid
> > > for any of the PSCI versions ?)
> > >
> > Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
> > with the SMCCC, hence needed some special handling. Only two func_ids> are currently supported by KVM, and we just check for each. The second
> > 'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
> > specification defines a range of acceptable PSCI func_ids.
>
> I understand PSCI 0.1 is different from PSCI 0.2 or newer versions.
> But, my question is: What would you consider "valid" psci function id ?
> It seems that the function checks whether or not the func_id is valid
> on the vCPU for PSCI 0.1, and checks whether or not the func_id is a
> PSCI function id for vCPU with PSCI 0.2 or newer.
>
> I understand either one works for your purpose, but I would think
> the behavior should be consistent.
>
I guess checking for the version caused the confusion here, but that
was done since there isn't a standard way to check the 0.1's range of
func_ids. Alternatively, instead of version, since the base of the
0.1's range is different as well, I can just check for that to avoid
the confusion (no functional change though).

Thank you.
Raghavendra
> Thanks,
> Reiji
>
>
> >
> > If it's confusing, I can add a comment above the second 'if' that it's
> > for all PSCI versions >= 0.2.
> > > Thanks,
> > > Reiji
> > >
> > Thank you.
> > Raghavendra
> >
> > [1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
> > >
> > >
> > > > +
> > > > +       return false;
> > > > +}
> > > > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > > > index 5d38628a8d04..499b45b607b6 100644
> > > > --- a/include/kvm/arm_hypercalls.h
> > > > +++ b/include/kvm/arm_hypercalls.h
> > > > @@ -6,6 +6,11 @@
> > > >
> > > >  #include <asm/kvm_emulate.h>
> > > >
> > > > +/* Last valid bits of the bitmapped firmware registers */
> > > > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > > > +
> > > > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > > > +
> > > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> > > >
> > > >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > > > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> > > >
> > > >  struct kvm_one_reg;
> > > >
> > > > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> > > >  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);
> > > > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > > > index 6e55b9283789..c47be3e26965 100644
> > > > --- a/include/kvm/arm_psci.h
> > > > +++ b/include/kvm/arm_psci.h
> > > > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> > > >         return KVM_ARM_PSCI_0_1;
> > > >  }
> > > >
> > > > -
> > > >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> > > >
> > > >  #endif /* __KVM_ARM_PSCI_H__ */
> > > > --
> > > > 2.36.0.rc2.479.g8af0fa9b8e-goog
> > > >

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-27 17:57           ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-27 17:57 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: kvm, Will Deacon, Marc Zyngier, Peter Shier, linux-kernel,
	Catalin Marinas, Paolo Bonzini, kvmarm, Linux ARM

On Tue, Apr 26, 2022 at 6:46 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Mon, Apr 25, 2022 at 9:46 AM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Hi Reiji,
> >
> > On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
> > >
> > > Hi Raghu,
> > >
> > > On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> > > <rananta@google.com> wrote:
> > > >
> > > > KVM regularly introduces new hypercall services to the guests without
> > > > any consent from the userspace. This means, the guests can observe
> > > > hypercall services in and out as they migrate across various host
> > > > kernel versions. This could be a major problem if the guest
> > > > discovered a hypercall, started using it, and after getting migrated
> > > > to an older kernel realizes that it's no longer available. Depending
> > > > on how the guest handles the change, there's a potential chance that
> > > > the guest would just panic.
> > > >
> > > > As a result, there's a need for the userspace to elect the services
> > > > that it wishes the guest to discover. It can elect these services
> > > > based on the kernels spread across its (migration) fleet. To remedy
> > > > this, extend the existing firmware pseudo-registers, such as
> > > > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > > > for all the hypercall services available.
> > > >
> > > > These firmware registers are categorized based on the service call
> > > > owners, but unlike the existing firmware pseudo-registers, they hold
> > > > the features supported in the form of a bitmap.
> > > >
> > > > During the VM initialization, the registers are set to upper-limit of
> > > > the features supported by the corresponding registers. It's expected
> > > > that the VMMs discover the features provided by each register via
> > > > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > > > KVM allows this modification only until the VM has started.
> > > >
> > > > Some of the standard features are not mapped to any bits of the
> > > > registers. But since they can recreate the original problem of
> > > > making it available without userspace's consent, they need to
> > > > be explicitly added to the case-list in
> > > > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > > > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > > > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> > > >
> > > > Older userspace code can simply ignore the feature and the
> > > > hypercall services will be exposed unconditionally to the guests,
> > > > thus ensuring backward compatibility.
> > > >
> > > > In this patch, the framework adds the register only for ARM's standard
> > > > secure services (owner value 4). Currently, this includes support only
> > > > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > > > register representing mandatory features of v1.0. Other services are
> > > > momentarily added in the upcoming patches.
> > > >
> > > > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > > > ---
> > > >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> > > >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> > > >  arch/arm64/kvm/arm.c              |  1 +
> > > >  arch/arm64/kvm/guest.c            |  8 ++-
> > > >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> > > >  arch/arm64/kvm/psci.c             | 13 +++++
> > > >  include/kvm/arm_hypercalls.h      |  6 ++
> > > >  include/kvm/arm_psci.h            |  2 +-
> > > >  8 files changed, 142 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > > index 94a27a7520f4..df07f4c10197 100644
> > > > --- a/arch/arm64/include/asm/kvm_host.h
> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> > > >  struct kvm_arch_memory_slot {
> > > >  };
> > > >
> > > > +/**
> > > > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > > > + *
> > > > + * @std_bmap: Bitmap of standard secure service calls
> > > > + */
> > > > +struct kvm_smccc_features {
> > > > +       unsigned long std_bmap;
> > > > +};
> > > > +
> > > >  struct kvm_arch {
> > > >         struct kvm_s2_mmu mmu;
> > > >
> > > > @@ -150,6 +159,9 @@ struct kvm_arch {
> > > >
> > > >         u8 pfr0_csv2;
> > > >         u8 pfr0_csv3;
> > > > +
> > > > +       /* Hypercall features firmware registers' descriptor */
> > > > +       struct kvm_smccc_features smccc_feat;
> > > >  };
> > > >
> > > >  struct kvm_vcpu_fault_info {
> > > > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > > > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > > > --- a/arch/arm64/include/uapi/asm/kvm.h
> > > > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > > > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> > > >  #define KVM_ARM64_SVE_VLS_WORDS        \
> > > >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> > > >
> > > > +/* Bitmap feature firmware registers */
> > > > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > > > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > > > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > > > +                                               ((r) & 0xffff))
> > > > +
> > > > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > > > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > > > index 523bc934fe2f..a37fadbd617e 100644
> > > > --- a/arch/arm64/kvm/arm.c
> > > > +++ b/arch/arm64/kvm/arm.c
> > > > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> > > >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> > > >
> > > >         set_default_spectre(kvm);
> > > > +       kvm_arm_init_hypercalls(kvm);
> > > >
> > > >         return ret;
> > > >  out_free_stage2_pgd:
> > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > > index 0d5cca56cbda..8c607199cad1 100644
> > > > --- a/arch/arm64/kvm/guest.c
> > > > +++ b/arch/arm64/kvm/guest.c
> > > > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >
> > > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > > > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > > > +       case KVM_REG_ARM_FW:
> > > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > > +               return kvm_arm_get_fw_reg(vcpu, reg);
> > > >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> > > >         }
> > > >
> > > > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >
> > > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > > > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > > > +       case KVM_REG_ARM_FW:
> > > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > > +               return kvm_arm_set_fw_reg(vcpu, reg);
> > > >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> > > >         }
> > > >
> > > > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > > > index fa6d9378d8e7..df55a04d2fe8 100644
> > > > --- a/arch/arm64/kvm/hypercalls.c
> > > > +++ b/arch/arm64/kvm/hypercalls.c
> > > > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> > > >         val[3] = lower_32_bits(cycles);
> > > >  }
> > > >
> > > > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > > > +{
> > > > +       return test_bit(feat_bit, reg_bmap);
> > > > +}
> > > > +
> > > > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       switch (func_id) {
> > > > +       /*
> > > > +        * List of function-ids that are not gated with the bitmapped feature
> > > > +        * firmware registers, and are to be allowed for servicing the call by default.
> > > > +        */
> > > > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > > > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > > > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > > > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > > > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > > > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > > > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > > > +               return true;
> > > > +       default:
> > > > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > > > +       }
> > > > +}
> > > > +
> > > > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > > +
> > > > +       switch (func_id) {
> > > > +       case ARM_SMCCC_TRNG_VERSION:
> > > > +       case ARM_SMCCC_TRNG_FEATURES:
> > > > +       case ARM_SMCCC_TRNG_GET_UUID:
> > > > +       case ARM_SMCCC_TRNG_RND32:
> > > > +       case ARM_SMCCC_TRNG_RND64:
> > > > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > > > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > > > +       default:
> > > > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > > > +       }
> > > > +}
> > > > +
> > > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >  {
> > > >         u32 func_id = smccc_get_function(vcpu);
> > > > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >         u32 feature;
> > > >         gpa_t gpa;
> > > >
> > > > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > > > +               goto out;
> > > > +
> > > >         switch (func_id) {
> > > >         case ARM_SMCCC_VERSION_FUNC_ID:
> > > >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > > > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >                 return kvm_psci_call(vcpu);
> > > >         }
> > > >
> > > > +out:
> > > >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> > > >         return 1;
> > > >  }
> > > > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > > > +       KVM_REG_ARM_STD_BMAP,
> > > >  };
> > > >
> > > > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > > > +{
> > > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > > +
> > > > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > > > +}
> > > > +
> > > >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > > >  {
> > > >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > > > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> > > >
> > > >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  {
> > > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > >         u64 val;
> > > >
> > > > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> > > >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> > > >                 break;
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               val = READ_ONCE(smccc_feat->std_bmap);
> > > > +               break;
> > > >         default:
> > > >                 return -ENOENT;
> > > >         }
> > > > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >         return 0;
> > > >  }
> > > >
> > > > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > > > +{
> > > > +       int ret = 0;
> > > > +       struct kvm *kvm = vcpu->kvm;
> > > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > > > +
> > > > +       switch (reg_id) {
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > > > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > > > +               break;
> > > > +       default:
> > > > +               return -ENOENT;
> > > > +       }
> > > > +
> > > > +       /* Check for unsupported bit */
> > > > +       if (val & ~fw_reg_features)
> > > > +               return -EINVAL;
> > > > +
> > > > +       mutex_lock(&kvm->lock);
> > >
> > > Why don't you check if the register value will be modified before
> > > getting the lock ? (then there is nothing to do)
> > > It would help reduce unnecessary serialization for live migration
> > > (even without the vm-scoped register capability).
> > >
> > That was the case until v5. Since v6, we return -EBUSY unconditionally
> > regardless of the incoming value. See Marc's comments in [1].
>
> > That was the case until v5. Since v6, we return -EBUSY unconditionally
> > regardless of the incoming value. See Marc's comments in [1].
>
> Even with that, the function could do below to avoid
> the unnecessary serialization.
> (I would expect mostly the function returns before getting the lock)
>
>         if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags))
>               return -EBUSY;
>
>         if (val == *fw_reg_bmap)
>               return 0;
>
>         mutex_lock(&kvm->lock);
>
>         <...>
>
Great idea! I can try this out. Thanks for the suggestion.

> > >
> > >
> > > > +
> > > > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > > > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > > > +               ret = -EBUSY;
> > > > +               goto out;
> > > > +       }
> > >
> > > I just would like to make sure that you are sure that existing
> > > userspace you know will not run KVM_RUN for any vCPUs until
> > > KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> > > correct ?
> > >
> > Since v6, that is something that we are leaving with the userspace to
> > synchronize. See [1].
>
> Understood.
>
>
> > > > +o
> > > > +       WRITE_ONCE(*fw_reg_bmap, val);
> > > > +out:
> > > > +       mutex_unlock(&kvm->lock);
> > > > +       return ret;
> > > > +}
> > > > +
> > > >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  {
> > > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >                         return -EINVAL;
> > > >
> > > >                 return 0;
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> > > >         default:
> > > >                 return -ENOENT;
> > > >         }
> > > > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > > > index 346535169faa..67d1273e8086 100644
> > > > --- a/arch/arm64/kvm/psci.c
> > > > +++ b/arch/arm64/kvm/psci.c
> > > > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> > > >                 return -EINVAL;
> > > >         }
> > > >  }
> > > > +
> > > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > > > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > > > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > > > +
> > > > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > > > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > > > +               return true;
> > >
> > > For PSCI 0.1, the function checks if the funct_id is valid for
> > > the vCPU (according to the vCPU's PSCI version).
> > > For other version of PSCI, the function doesn't care the vCPU's
> > > PSCI version (although supported functions depend on the PSCI
> > > version and not all of them are defined yet, the code returns
> > > true as long as the function id is within the reserved PSCI
> > > function id range).
> > > So, the behavior appears to be inconsistent.
> > > Shouldn't it return the validity of the function id according
> > > to the vCPU's psci version for non-PSCI 0.1 case as well ?
> > > (Otherwise, shouldn't it return true if the function id is valid
> > > for any of the PSCI versions ?)
> > >
> > Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
> > with the SMCCC, hence needed some special handling. Only two func_ids> are currently supported by KVM, and we just check for each. The second
> > 'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
> > specification defines a range of acceptable PSCI func_ids.
>
> I understand PSCI 0.1 is different from PSCI 0.2 or newer versions.
> But, my question is: What would you consider "valid" psci function id ?
> It seems that the function checks whether or not the func_id is valid
> on the vCPU for PSCI 0.1, and checks whether or not the func_id is a
> PSCI function id for vCPU with PSCI 0.2 or newer.
>
> I understand either one works for your purpose, but I would think
> the behavior should be consistent.
>
I guess checking for the version caused the confusion here, but that
was done since there isn't a standard way to check the 0.1's range of
func_ids. Alternatively, instead of version, since the base of the
0.1's range is different as well, I can just check for that to avoid
the confusion (no functional change though).

Thank you.
Raghavendra
> Thanks,
> Reiji
>
>
> >
> > If it's confusing, I can add a comment above the second 'if' that it's
> > for all PSCI versions >= 0.2.
> > > Thanks,
> > > Reiji
> > >
> > Thank you.
> > Raghavendra
> >
> > [1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
> > >
> > >
> > > > +
> > > > +       return false;
> > > > +}
> > > > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > > > index 5d38628a8d04..499b45b607b6 100644
> > > > --- a/include/kvm/arm_hypercalls.h
> > > > +++ b/include/kvm/arm_hypercalls.h
> > > > @@ -6,6 +6,11 @@
> > > >
> > > >  #include <asm/kvm_emulate.h>
> > > >
> > > > +/* Last valid bits of the bitmapped firmware registers */
> > > > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > > > +
> > > > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > > > +
> > > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> > > >
> > > >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > > > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> > > >
> > > >  struct kvm_one_reg;
> > > >
> > > > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> > > >  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);
> > > > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > > > index 6e55b9283789..c47be3e26965 100644
> > > > --- a/include/kvm/arm_psci.h
> > > > +++ b/include/kvm/arm_psci.h
> > > > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> > > >         return KVM_ARM_PSCI_0_1;
> > > >  }
> > > >
> > > > -
> > > >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> > > >
> > > >  #endif /* __KVM_ARM_PSCI_H__ */
> > > > --
> > > > 2.36.0.rc2.479.g8af0fa9b8e-goog
> > > >
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers
@ 2022-04-27 17:57           ` Raghavendra Rao Ananta
  0 siblings, 0 replies; 90+ messages in thread
From: Raghavendra Rao Ananta @ 2022-04-27 17:57 UTC (permalink / raw)
  To: Reiji Watanabe
  Cc: Marc Zyngier, Andrew Jones, James Morse, Alexandru Elisei,
	Suzuki K Poulose, Paolo Bonzini, Catalin Marinas, Will Deacon,
	Peter Shier, Ricardo Koller, Oliver Upton, Jing Zhang, Linux ARM,
	kvmarm, linux-kernel, kvm

On Tue, Apr 26, 2022 at 6:46 PM Reiji Watanabe <reijiw@google.com> wrote:
>
> Hi Raghu,
>
> On Mon, Apr 25, 2022 at 9:46 AM Raghavendra Rao Ananta
> <rananta@google.com> wrote:
> >
> > Hi Reiji,
> >
> > On Sun, Apr 24, 2022 at 9:52 PM Reiji Watanabe <reijiw@google.com> wrote:
> > >
> > > Hi Raghu,
> > >
> > > On Fri, Apr 22, 2022 at 5:03 PM Raghavendra Rao Ananta
> > > <rananta@google.com> wrote:
> > > >
> > > > KVM regularly introduces new hypercall services to the guests without
> > > > any consent from the userspace. This means, the guests can observe
> > > > hypercall services in and out as they migrate across various host
> > > > kernel versions. This could be a major problem if the guest
> > > > discovered a hypercall, started using it, and after getting migrated
> > > > to an older kernel realizes that it's no longer available. Depending
> > > > on how the guest handles the change, there's a potential chance that
> > > > the guest would just panic.
> > > >
> > > > As a result, there's a need for the userspace to elect the services
> > > > that it wishes the guest to discover. It can elect these services
> > > > based on the kernels spread across its (migration) fleet. To remedy
> > > > this, extend the existing firmware pseudo-registers, such as
> > > > KVM_REG_ARM_PSCI_VERSION, but by creating a new COPROC register space
> > > > for all the hypercall services available.
> > > >
> > > > These firmware registers are categorized based on the service call
> > > > owners, but unlike the existing firmware pseudo-registers, they hold
> > > > the features supported in the form of a bitmap.
> > > >
> > > > During the VM initialization, the registers are set to upper-limit of
> > > > the features supported by the corresponding registers. It's expected
> > > > that the VMMs discover the features provided by each register via
> > > > GET_ONE_REG, and write back the desired values using SET_ONE_REG.
> > > > KVM allows this modification only until the VM has started.
> > > >
> > > > Some of the standard features are not mapped to any bits of the
> > > > registers. But since they can recreate the original problem of
> > > > making it available without userspace's consent, they need to
> > > > be explicitly added to the case-list in
> > > > kvm_hvc_call_default_allowed(). Any function-id that's not enabled
> > > > via the bitmap, or not listed in kvm_hvc_call_default_allowed, will
> > > > be returned as SMCCC_RET_NOT_SUPPORTED to the guest.
> > > >
> > > > Older userspace code can simply ignore the feature and the
> > > > hypercall services will be exposed unconditionally to the guests,
> > > > thus ensuring backward compatibility.
> > > >
> > > > In this patch, the framework adds the register only for ARM's standard
> > > > secure services (owner value 4). Currently, this includes support only
> > > > for ARM True Random Number Generator (TRNG) service, with bit-0 of the
> > > > register representing mandatory features of v1.0. Other services are
> > > > momentarily added in the upcoming patches.
> > > >
> > > > Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
> > > > ---
> > > >  arch/arm64/include/asm/kvm_host.h | 12 ++++
> > > >  arch/arm64/include/uapi/asm/kvm.h |  9 +++
> > > >  arch/arm64/kvm/arm.c              |  1 +
> > > >  arch/arm64/kvm/guest.c            |  8 ++-
> > > >  arch/arm64/kvm/hypercalls.c       | 94 +++++++++++++++++++++++++++++++
> > > >  arch/arm64/kvm/psci.c             | 13 +++++
> > > >  include/kvm/arm_hypercalls.h      |  6 ++
> > > >  include/kvm/arm_psci.h            |  2 +-
> > > >  8 files changed, 142 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > > index 94a27a7520f4..df07f4c10197 100644
> > > > --- a/arch/arm64/include/asm/kvm_host.h
> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > > @@ -101,6 +101,15 @@ struct kvm_s2_mmu {
> > > >  struct kvm_arch_memory_slot {
> > > >  };
> > > >
> > > > +/**
> > > > + * struct kvm_smccc_features: Descriptor the hypercall services exposed to the guests
> > > > + *
> > > > + * @std_bmap: Bitmap of standard secure service calls
> > > > + */
> > > > +struct kvm_smccc_features {
> > > > +       unsigned long std_bmap;
> > > > +};
> > > > +
> > > >  struct kvm_arch {
> > > >         struct kvm_s2_mmu mmu;
> > > >
> > > > @@ -150,6 +159,9 @@ struct kvm_arch {
> > > >
> > > >         u8 pfr0_csv2;
> > > >         u8 pfr0_csv3;
> > > > +
> > > > +       /* Hypercall features firmware registers' descriptor */
> > > > +       struct kvm_smccc_features smccc_feat;
> > > >  };
> > > >
> > > >  struct kvm_vcpu_fault_info {
> > > > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > > > index c1b6ddc02d2f..0b79d2dc6ffd 100644
> > > > --- a/arch/arm64/include/uapi/asm/kvm.h
> > > > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > > > @@ -332,6 +332,15 @@ struct kvm_arm_copy_mte_tags {
> > > >  #define KVM_ARM64_SVE_VLS_WORDS        \
> > > >         ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
> > > >
> > > > +/* Bitmap feature firmware registers */
> > > > +#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
> > > > +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> > > > +                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
> > > > +                                               ((r) & 0xffff))
> > > > +
> > > > +#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
> > > > +#define KVM_REG_ARM_STD_BIT_TRNG_V1_0          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/arm.c b/arch/arm64/kvm/arm.c
> > > > index 523bc934fe2f..a37fadbd617e 100644
> > > > --- a/arch/arm64/kvm/arm.c
> > > > +++ b/arch/arm64/kvm/arm.c
> > > > @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> > > >         kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
> > > >
> > > >         set_default_spectre(kvm);
> > > > +       kvm_arm_init_hypercalls(kvm);
> > > >
> > > >         return ret;
> > > >  out_free_stage2_pgd:
> > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > > index 0d5cca56cbda..8c607199cad1 100644
> > > > --- a/arch/arm64/kvm/guest.c
> > > > +++ b/arch/arm64/kvm/guest.c
> > > > @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >
> > > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > >         case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
> > > > -       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
> > > > +       case KVM_REG_ARM_FW:
> > > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > > +               return kvm_arm_get_fw_reg(vcpu, reg);
> > > >         case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
> > > >         }
> > > >
> > > > @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >
> > > >         switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > >         case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
> > > > -       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
> > > > +       case KVM_REG_ARM_FW:
> > > > +       case KVM_REG_ARM_FW_FEAT_BMAP:
> > > > +               return kvm_arm_set_fw_reg(vcpu, reg);
> > > >         case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
> > > >         }
> > > >
> > > > diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> > > > index fa6d9378d8e7..df55a04d2fe8 100644
> > > > --- a/arch/arm64/kvm/hypercalls.c
> > > > +++ b/arch/arm64/kvm/hypercalls.c
> > > > @@ -58,6 +58,48 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
> > > >         val[3] = lower_32_bits(cycles);
> > > >  }
> > > >
> > > > +static bool kvm_arm_fw_reg_feat_enabled(unsigned long *reg_bmap, unsigned long feat_bit)
> > > > +{
> > > > +       return test_bit(feat_bit, reg_bmap);
> > > > +}
> > > > +
> > > > +static bool kvm_hvc_call_default_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       switch (func_id) {
> > > > +       /*
> > > > +        * List of function-ids that are not gated with the bitmapped feature
> > > > +        * firmware registers, and are to be allowed for servicing the call by default.
> > > > +        */
> > > > +       case ARM_SMCCC_VERSION_FUNC_ID:
> > > > +       case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > > > +       case ARM_SMCCC_HV_PV_TIME_FEATURES:
> > > > +       case ARM_SMCCC_HV_PV_TIME_ST:
> > > > +       case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > > > +       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> > > > +       case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
> > > > +               return true;
> > > > +       default:
> > > > +               return kvm_psci_func_id_is_valid(vcpu, func_id);
> > > > +       }
> > > > +}
> > > > +
> > > > +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > > +
> > > > +       switch (func_id) {
> > > > +       case ARM_SMCCC_TRNG_VERSION:
> > > > +       case ARM_SMCCC_TRNG_FEATURES:
> > > > +       case ARM_SMCCC_TRNG_GET_UUID:
> > > > +       case ARM_SMCCC_TRNG_RND32:
> > > > +       case ARM_SMCCC_TRNG_RND64:
> > > > +               return kvm_arm_fw_reg_feat_enabled(&smccc_feat->std_bmap,
> > > > +                                               KVM_REG_ARM_STD_BIT_TRNG_V1_0);
> > > > +       default:
> > > > +               return kvm_hvc_call_default_allowed(vcpu, func_id);
> > > > +       }
> > > > +}
> > > > +
> > > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >  {
> > > >         u32 func_id = smccc_get_function(vcpu);
> > > > @@ -65,6 +107,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >         u32 feature;
> > > >         gpa_t gpa;
> > > >
> > > > +       if (!kvm_hvc_call_allowed(vcpu, func_id))
> > > > +               goto out;
> > > > +
> > > >         switch (func_id) {
> > > >         case ARM_SMCCC_VERSION_FUNC_ID:
> > > >                 val[0] = ARM_SMCCC_VERSION_1_1;
> > > > @@ -155,6 +200,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
> > > >                 return kvm_psci_call(vcpu);
> > > >         }
> > > >
> > > > +out:
> > > >         smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> > > >         return 1;
> > > >  }
> > > > @@ -164,8 +210,16 @@ static const u64 kvm_arm_fw_reg_ids[] = {
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
> > > >         KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
> > > > +       KVM_REG_ARM_STD_BMAP,
> > > >  };
> > > >
> > > > +void kvm_arm_init_hypercalls(struct kvm *kvm)
> > > > +{
> > > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > > +
> > > > +       smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
> > > > +}
> > > > +
> > > >  int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
> > > >  {
> > > >         return ARRAY_SIZE(kvm_arm_fw_reg_ids);
> > > > @@ -237,6 +291,7 @@ static int get_kernel_wa_level(u64 regid)
> > > >
> > > >  int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  {
> > > > +       struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
> > > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > >         u64 val;
> > > >
> > > > @@ -249,6 +304,9 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >         case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
> > > >                 val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
> > > >                 break;
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               val = READ_ONCE(smccc_feat->std_bmap);
> > > > +               break;
> > > >         default:
> > > >                 return -ENOENT;
> > > >         }
> > > > @@ -259,6 +317,40 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >         return 0;
> > > >  }
> > > >
> > > > +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
> > > > +{
> > > > +       int ret = 0;
> > > > +       struct kvm *kvm = vcpu->kvm;
> > > > +       struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
> > > > +       unsigned long *fw_reg_bmap, fw_reg_features;
> > > > +
> > > > +       switch (reg_id) {
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               fw_reg_bmap = &smccc_feat->std_bmap;
> > > > +               fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
> > > > +               break;
> > > > +       default:
> > > > +               return -ENOENT;
> > > > +       }
> > > > +
> > > > +       /* Check for unsupported bit */
> > > > +       if (val & ~fw_reg_features)
> > > > +               return -EINVAL;
> > > > +
> > > > +       mutex_lock(&kvm->lock);
> > >
> > > Why don't you check if the register value will be modified before
> > > getting the lock ? (then there is nothing to do)
> > > It would help reduce unnecessary serialization for live migration
> > > (even without the vm-scoped register capability).
> > >
> > That was the case until v5. Since v6, we return -EBUSY unconditionally
> > regardless of the incoming value. See Marc's comments in [1].
>
> > That was the case until v5. Since v6, we return -EBUSY unconditionally
> > regardless of the incoming value. See Marc's comments in [1].
>
> Even with that, the function could do below to avoid
> the unnecessary serialization.
> (I would expect mostly the function returns before getting the lock)
>
>         if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags))
>               return -EBUSY;
>
>         if (val == *fw_reg_bmap)
>               return 0;
>
>         mutex_lock(&kvm->lock);
>
>         <...>
>
Great idea! I can try this out. Thanks for the suggestion.

> > >
> > >
> > > > +
> > > > +       /* Return -EBUSY if the VM (any vCPU) has already started running. */
> > > > +       if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) {
> > > > +               ret = -EBUSY;
> > > > +               goto out;
> > > > +       }
> > >
> > > I just would like to make sure that you are sure that existing
> > > userspace you know will not run KVM_RUN for any vCPUs until
> > > KVM_SET_ONE_REG is complete for all vCPUs (even for migration),
> > > correct ?
> > >
> > Since v6, that is something that we are leaving with the userspace to
> > synchronize. See [1].
>
> Understood.
>
>
> > > > +o
> > > > +       WRITE_ONCE(*fw_reg_bmap, val);
> > > > +out:
> > > > +       mutex_unlock(&kvm->lock);
> > > > +       return ret;
> > > > +}
> > > > +
> > > >  int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  {
> > > >         void __user *uaddr = (void __user *)(long)reg->addr;
> > > > @@ -337,6 +429,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >                         return -EINVAL;
> > > >
> > > >                 return 0;
> > > > +       case KVM_REG_ARM_STD_BMAP:
> > > > +               return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
> > > >         default:
> > > >                 return -ENOENT;
> > > >         }
> > > > diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
> > > > index 346535169faa..67d1273e8086 100644
> > > > --- a/arch/arm64/kvm/psci.c
> > > > +++ b/arch/arm64/kvm/psci.c
> > > > @@ -436,3 +436,16 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
> > > >                 return -EINVAL;
> > > >         }
> > > >  }
> > > > +
> > > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id)
> > > > +{
> > > > +       /* PSCI 0.1 doesn't comply with the standard SMCCC */
> > > > +       if (kvm_psci_version(vcpu) == KVM_ARM_PSCI_0_1)
> > > > +               return (func_id == KVM_PSCI_FN_CPU_OFF || func_id == KVM_PSCI_FN_CPU_ON);
> > > > +
> > > > +       if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
> > > > +               ARM_SMCCC_FUNC_NUM(func_id) >= 0 && ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
> > > > +               return true;
> > >
> > > For PSCI 0.1, the function checks if the funct_id is valid for
> > > the vCPU (according to the vCPU's PSCI version).
> > > For other version of PSCI, the function doesn't care the vCPU's
> > > PSCI version (although supported functions depend on the PSCI
> > > version and not all of them are defined yet, the code returns
> > > true as long as the function id is within the reserved PSCI
> > > function id range).
> > > So, the behavior appears to be inconsistent.
> > > Shouldn't it return the validity of the function id according
> > > to the vCPU's psci version for non-PSCI 0.1 case as well ?
> > > (Otherwise, shouldn't it return true if the function id is valid
> > > for any of the PSCI versions ?)
> > >
> > Well, PSCI 1.0 is somewhat of an odd implementation. It doesn't comply
> > with the SMCCC, hence needed some special handling. Only two func_ids> are currently supported by KVM, and we just check for each. The second
> > 'if' statement is for all the PSCI versions >= 0.2. Thankfully, the
> > specification defines a range of acceptable PSCI func_ids.
>
> I understand PSCI 0.1 is different from PSCI 0.2 or newer versions.
> But, my question is: What would you consider "valid" psci function id ?
> It seems that the function checks whether or not the func_id is valid
> on the vCPU for PSCI 0.1, and checks whether or not the func_id is a
> PSCI function id for vCPU with PSCI 0.2 or newer.
>
> I understand either one works for your purpose, but I would think
> the behavior should be consistent.
>
I guess checking for the version caused the confusion here, but that
was done since there isn't a standard way to check the 0.1's range of
func_ids. Alternatively, instead of version, since the base of the
0.1's range is different as well, I can just check for that to avoid
the confusion (no functional change though).

Thank you.
Raghavendra
> Thanks,
> Reiji
>
>
> >
> > If it's confusing, I can add a comment above the second 'if' that it's
> > for all PSCI versions >= 0.2.
> > > Thanks,
> > > Reiji
> > >
> > Thank you.
> > Raghavendra
> >
> > [1]: https://lore.kernel.org/lkml/87ilrlb6un.wl-maz@kernel.org/
> > >
> > >
> > > > +
> > > > +       return false;
> > > > +}
> > > > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > > > index 5d38628a8d04..499b45b607b6 100644
> > > > --- a/include/kvm/arm_hypercalls.h
> > > > +++ b/include/kvm/arm_hypercalls.h
> > > > @@ -6,6 +6,11 @@
> > > >
> > > >  #include <asm/kvm_emulate.h>
> > > >
> > > > +/* Last valid bits of the bitmapped firmware registers */
> > > > +#define KVM_REG_ARM_STD_BMAP_BIT_MAX           0
> > > > +
> > > > +#define KVM_ARM_SMCCC_STD_FEATURES             GENMASK(KVM_REG_ARM_STD_BMAP_BIT_MAX, 0)
> > > > +
> > > >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> > > >
> > > >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> > > > @@ -42,6 +47,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
> > > >
> > > >  struct kvm_one_reg;
> > > >
> > > > +void kvm_arm_init_hypercalls(struct kvm *kvm);
> > > >  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);
> > > > diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
> > > > index 6e55b9283789..c47be3e26965 100644
> > > > --- a/include/kvm/arm_psci.h
> > > > +++ b/include/kvm/arm_psci.h
> > > > @@ -36,7 +36,7 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
> > > >         return KVM_ARM_PSCI_0_1;
> > > >  }
> > > >
> > > > -
> > > >  int kvm_psci_call(struct kvm_vcpu *vcpu);
> > > > +bool kvm_psci_func_id_is_valid(struct kvm_vcpu *vcpu, u32 func_id);
> > > >
> > > >  #endif /* __KVM_ARM_PSCI_H__ */
> > > > --
> > > > 2.36.0.rc2.479.g8af0fa9b8e-goog
> > > >

_______________________________________________
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] 90+ messages in thread

end of thread, other threads:[~2022-04-27 17:59 UTC | newest]

Thread overview: 90+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-23  0:03 [PATCH v6 0/9] KVM: arm64: Add support for hypercall services selection Raghavendra Rao Ananta
2022-04-23  0:03 ` Raghavendra Rao Ananta
2022-04-23  0:03 ` Raghavendra Rao Ananta
2022-04-23  0:03 ` [PATCH v6 1/9] KVM: arm64: Factor out firmware register handling from psci.c Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03 ` [PATCH v6 2/9] KVM: arm64: Setup a framework for hypercall bitmap firmware registers Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-25  4:52   ` Reiji Watanabe
2022-04-25  4:52     ` Reiji Watanabe
2022-04-25  4:52     ` Reiji Watanabe
2022-04-25 16:46     ` Raghavendra Rao Ananta
2022-04-25 16:46       ` Raghavendra Rao Ananta
2022-04-25 16:46       ` Raghavendra Rao Ananta
2022-04-27  1:46       ` Reiji Watanabe
2022-04-27  1:46         ` Reiji Watanabe
2022-04-27  1:46         ` Reiji Watanabe
2022-04-27 17:57         ` Raghavendra Rao Ananta
2022-04-27 17:57           ` Raghavendra Rao Ananta
2022-04-27 17:57           ` Raghavendra Rao Ananta
2022-04-26  6:33   ` Gavin Shan
2022-04-26  6:33     ` Gavin Shan
2022-04-26  6:33     ` Gavin Shan
2022-04-26 16:44     ` Raghavendra Rao Ananta
2022-04-26 16:44       ` Raghavendra Rao Ananta
2022-04-26 16:44       ` Raghavendra Rao Ananta
2022-04-27  1:38       ` Gavin Shan
2022-04-27  1:38         ` Gavin Shan
2022-04-27  1:38         ` Gavin Shan
2022-04-23  0:03 ` [PATCH v6 3/9] KVM: arm64: Add standard hypervisor firmware register Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-26  6:37   ` Gavin Shan
2022-04-26  6:37     ` Gavin Shan
2022-04-26  6:37     ` Gavin Shan
2022-04-23  0:03 ` [PATCH v6 4/9] KVM: arm64: Add vendor " Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-25  6:22   ` Reiji Watanabe
2022-04-25  6:22     ` Reiji Watanabe
2022-04-25  6:22     ` Reiji Watanabe
2022-04-25 16:51     ` Raghavendra Rao Ananta
2022-04-25 16:51       ` Raghavendra Rao Ananta
2022-04-25 16:51       ` Raghavendra Rao Ananta
2022-04-25 17:12       ` Oliver Upton
2022-04-25 17:12         ` Oliver Upton
2022-04-25 17:12         ` Oliver Upton
2022-04-26  6:40   ` Gavin Shan
2022-04-26  6:40     ` Gavin Shan
2022-04-26  6:40     ` Gavin Shan
2022-04-23  0:03 ` [PATCH v6 5/9] Docs: KVM: Rename psci.rst to hypercalls.rst Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-26  6:41   ` Gavin Shan
2022-04-26  6:41     ` Gavin Shan
2022-04-26  6:41     ` Gavin Shan
2022-04-23  0:03 ` [PATCH v6 6/9] Docs: KVM: Add doc for the bitmap firmware registers Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-25  6:31   ` Reiji Watanabe
2022-04-25  6:31     ` Reiji Watanabe
2022-04-25  6:31     ` Reiji Watanabe
2022-04-25 16:52     ` Raghavendra Rao Ananta
2022-04-25 16:52       ` Raghavendra Rao Ananta
2022-04-25 16:52       ` Raghavendra Rao Ananta
2022-04-26  6:42   ` Gavin Shan
2022-04-26  6:42     ` Gavin Shan
2022-04-26  6:42     ` Gavin Shan
2022-04-23  0:03 ` [PATCH v6 7/9] tools: Import ARM SMCCC definitions Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-26  7:24   ` Gavin Shan
2022-04-26  7:24     ` Gavin Shan
2022-04-26  7:24     ` Gavin Shan
2022-04-23  0:03 ` [PATCH v6 8/9] selftests: KVM: aarch64: Introduce hypercall ABI test Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-26  7:49   ` Gavin Shan
2022-04-26  7:49     ` Gavin Shan
2022-04-26  7:49     ` Gavin Shan
2022-04-26 16:59     ` Raghavendra Rao Ananta
2022-04-26 16:59       ` Raghavendra Rao Ananta
2022-04-26 16:59       ` Raghavendra Rao Ananta
2022-04-27  2:09       ` Gavin Shan
2022-04-27  2:09         ` Gavin Shan
2022-04-27  2:09         ` Gavin Shan
2022-04-23  0:03 ` [PATCH v6 9/9] selftests: KVM: aarch64: Add the bitmap firmware registers to get-reg-list Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta
2022-04-23  0:03   ` Raghavendra Rao Ananta

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.