All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] Support for Arm CCA VMs on Linux
@ 2023-01-27 11:22 ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:22 UTC (permalink / raw)
  To: linux-coco, linux-kernel, kvm, kvmarm, linux-arm-kernel
  Cc: Alexandru Elisei, Andrew Jones, Catalin Marinas, Chao Peng,
	Christoffer Dall, Fuad Tabba, James Morse, Jean-Philippe Brucker,
	Joey Gouly, Marc Zyngier, Mark Rutland, Oliver Upton,
	Paolo Bonzini, Quentin Perret, Sean Christopherson, Steven Price,
	Thomas Huth, Will Deacon, Zenghui Yu, kvmarm

We are happy to announce the early RFC version of the Arm
Confidential Compute Architecture (CCA) support for the Linux
stack. The intention is to seek early feedback in the following areas:
 * KVM integration of the Arm CCA
 * KVM UABI for managing the Realms, seeking to generalise the operations
   wherever possible with other Confidential Compute solutions.
   Note: This version doesn't support Guest Private memory, which will be added
   later (see below).
 * Linux Guest support for Realms

Arm CCA Introduction
=====================

The Arm CCA is a reference software architecture and implementation that builds
on the Realm Management Extension (RME), enabling the execution of Virtual
machines, while preventing access by more privileged software, such as hypervisor.
The Arm CCA allows the hypervisor to control the VM, but removes the right for
access to the code, register state or data that is used by VM.
More information on the architecture is available here[0].

    Arm CCA Reference Software Architecture

        Realm World    ||    Normal World   ||  Secure World  ||
                       ||        |          ||                ||
 EL0 x-------x         || x----x | x------x ||                ||
     | Realm |         || |    | | |      | ||                ||
     |       |         || | VM | | |      | ||                ||
 ----|  VM*  |---------||-|    |---|      |-||----------------||
     |       |         || |    | | |  H   | ||                ||
 EL1 x-------x         || x----x | |      | ||                ||
         ^             ||        | |  o   | ||                ||
         |             ||        | |      | ||                ||
 ------- R*------------------------|  s  -|---------------------
         S             ||          |      | ||                ||
         I             ||          |  t   | ||                ||
         |             ||          |      | ||                || 
         v             ||          x------x ||                ||
 EL2    RMM*           ||              ^    ||                ||
         ^             ||              |    ||                ||
 ========|=============================|========================
         |                             | SMC
         x--------- *RMI* -------------x

 EL3                   Root World
                       EL3 Firmware
 ===============================================================
Where :
 RMM - Realm Management Monitor
 RMI - Realm Management Interface
 RSI - Realm Service Interface
 SMC - Secure Monitor Call

RME introduces a new security state "Realm world", in addition to the
traditional Secure and Non-Secure states. The Arm CCA defines a new component,
Realm Management Monitor (RMM) that runs at R-EL2. This is a standard piece of
firmware, verified, installed and loaded by the EL3 firmware (e.g, TF-A), at
system boot.

The RMM provides standard interfaces - Realm Management Interface (RMI) - to the
Normal world hypervisor to manage the VMs running in the Realm world (also called
Realms in short). These are exposed via SMC and are routed through the EL3
firmwre.
The RMI interface includes:
  - Move a physical page from the Normal world to the Realm world
  - Creating a Realm with requested parameters, tracked via Realm Descriptor (RD)
  - Creating VCPUs aka Realm Execution Context (REC), with initial register state.
  - Create stage2 translation table at any level.
  - Load initial images into Realm Memory from normal world memory
  - Schedule RECs (vCPUs) and handle exits
  - Inject virtual interrupts into the Realm
  - Service stage2 runtime faults with pages (provided by host, scrubbed by RMM).
  - Create "shared" mappings that can be accessed by VMM/Hyp.
  - Reclaim the memory allocated for the RAM and RTTs (Realm Translation Tables)

However v1.0 of RMM specifications doesn't support:
 - Paging protected memory of a Realm VM. Thus the pages backing the protected
   memory region must be pinned.
 - Live migration of Realms.
 - Trusted Device assignment.
 - Physical interrupt backed Virtual interrupts for Realms

RMM also provides certain services to the Realms via SMC, called Realm Service
Interface (RSI). These include:
 - Realm Guest Configuration.
 - Attestation & Measurement services
 - Managing the state of an Intermediate Physical Address (IPA aka GPA) page.
 - Host Call service (Communication with the Normal world Hypervisor)

The specifications for the RMM software is currently at *v1.0-Beta2* and the
latest version is available here [1].

The Trusted Firmware foundation has an implementation of the RMM - TF-RMM -
available here [3].

Implementation
=================

This version of the stack is based on the RMM specification v1.0-Beta0[2], with
following exceptions :
  - TF-RMM/KVM currently doesn't support the optional features of PMU,
     SVE and Self-hosted debug (coming soon).
  - The RSI_HOST_CALL structure alignment requirement is reduced to match
     RMM v1.0 Beta1
  - RMI/RSI version numbers do not match the RMM spec. This will be
    resolved once the spec/implementation is complete, across TF-RMM+Linux stack.

We plan to update the stack to support the latest version of the RMMv1.0 spec
in the coming revisions.

This release includes the following components :

 a) Linux Kernel
     i) Host / KVM support - Support for driving the Realms via RMI. This is
     dependent on running in the Kernel at EL2 (aka VHE mode). Also provides
     UABI for VMMs to manage the Realm VMs. The support is restricted to 4K page
     size, matching the Stage2 granule supported by RMM. The VMM is responsible
     for making sure the guest memory is locked.

       TODO: Guest Private memory[10] integration - We have been following the
       series and support will be added once it is merged upstream.
     
     ii) Guest support - Support for a Linux Kernel to run in the Realm VM at
     Realm-EL1, using RSI services. This includes virtio support (virtio-v1.0
     only). All I/O are treated as non-secure/shared.
 
 c) kvmtool - VMM changes required to manage Realm VMs. No guest private memory
    as mentioned above.
 d) kvm-unit-tests - Support for running in Realms along with additional tests
    for RSI ABI.

Running the stack
====================

To run/test the stack, you would need the following components :

1) FVP Base AEM RevC model with FEAT_RME support [4]
2) TF-A firmware for EL3 [5]
3) TF-A RMM for R-EL2 [3]
4) Linux Kernel [6]
5) kvmtool [7]
6) kvm-unit-tests [8]

Instructions for building the firmware components and running the model are
available here [9]. Once, the host kernel is booted, a Realm can be launched by
invoking the `lkvm` commad as follows:

 $ lkvm run --realm 				 \
	 --measurement-algo=["sha256", "sha512"] \
	 --disable-sve				 \
	 <normal-vm-options>

Where:
 * --measurement-algo (Optional) specifies the algorithm selected for creating the
   initial measurements by the RMM for this Realm (defaults to sha256).
 * GICv3 is mandatory for the Realms.
 * SVE is not yet supported in the TF-RMM, and thus must be disabled using
   --disable-sve

You may also run the kvm-unit-tests inside the Realm world, using the similar
options as above.


Links
============

[0] Arm CCA Landing page (See Key Resources section for various documentations)
    https://www.arm.com/architecture/security-features/arm-confidential-compute-architecture

[1] RMM Specification Latest
    https://developer.arm.com/documentation/den0137/latest

[2] RMM v1.0-Beta0 specification
    https://developer.arm.com/documentation/den0137/1-0bet0/

[3] Trusted Firmware RMM - TF-RMM
    https://www.trustedfirmware.org/projects/tf-rmm/
    GIT: https://git.trustedfirmware.org/TF-RMM/tf-rmm.git

[4] FVP Base RevC AEM Model (available on x86_64 / Arm64 Linux)
    https://developer.arm.com/Tools%20and%20Software/Fixed%20Virtual%20Platforms

[5] Trusted Firmware for A class
    https://www.trustedfirmware.org/projects/tf-a/

[6] Linux kernel support for Arm-CCA
    https://gitlab.arm.com/linux-arm/linux-cca
    Host Support branch:	cca-host/rfc-v1
    Guest Support branch:	cca-guest/rfc-v1

[7] kvmtool support for Arm CCA
    https://gitlab.arm.com/linux-arm/kvmtool-cca cca/rfc-v1

[8] kvm-unit-tests support for Arm CCA
    https://gitlab.arm.com/linux-arm/kvm-unit-tests-cca  cca/rfc-v1

[9] Instructions for Building Firmware components and running the model, see
    section 4.19.2 "Building and running TF-A with RME"
    https://trustedfirmware-a.readthedocs.io/en/latest/components/realm-management-extension.html#building-and-running-tf-a-with-rme

[10] fd based Guest Private memory for KVM
   https://lkml.kernel.org/r/20221202061347.1070246-1-chao.p.peng@linux.intel.com

Cc: Alexandru Elisei <alexandru.elisei@arm.com>
Cc: Andrew Jones <andrew.jones@linux.dev>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chao Peng <chao.p.peng@linux.intel.com>
Cc: Christoffer Dall <christoffer.dall@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Cc: James Morse <james.morse@arm.com>
Cc: Jean-Philippe Brucker <jean-philippe@linaro.org>
Cc: Joey Gouly <Joey.Gouly@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Quentin Perret <qperret@google.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Steven Price <steven.price@arm.com>
Cc: Thomas Huth <thuth@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Zenghui Yu <yuzenghui@huawei.com>
To: linux-coco@lists.linux.dev
To: kvmarm@lists.linux.dev
Cc: kvmarm@lists.cs.columbia.edu
Cc: linux-arm-kernel@lists.infradead.org
To: linux-kernel@vger.kernel.org
To: kvm@vger.kernel.org

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

* [RFC] Support for Arm CCA VMs on Linux
@ 2023-01-27 11:22 ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:22 UTC (permalink / raw)
  To: linux-coco, linux-kernel, kvm, kvmarm, linux-arm-kernel
  Cc: Alexandru Elisei, Andrew Jones, Catalin Marinas, Chao Peng,
	Christoffer Dall, Fuad Tabba, James Morse, Jean-Philippe Brucker,
	Joey Gouly, Marc Zyngier, Mark Rutland, Oliver Upton,
	Paolo Bonzini, Quentin Perret, Sean Christopherson, Steven Price,
	Thomas Huth, Will Deacon, Zenghui Yu, kvmarm

We are happy to announce the early RFC version of the Arm
Confidential Compute Architecture (CCA) support for the Linux
stack. The intention is to seek early feedback in the following areas:
 * KVM integration of the Arm CCA
 * KVM UABI for managing the Realms, seeking to generalise the operations
   wherever possible with other Confidential Compute solutions.
   Note: This version doesn't support Guest Private memory, which will be added
   later (see below).
 * Linux Guest support for Realms

Arm CCA Introduction
=====================

The Arm CCA is a reference software architecture and implementation that builds
on the Realm Management Extension (RME), enabling the execution of Virtual
machines, while preventing access by more privileged software, such as hypervisor.
The Arm CCA allows the hypervisor to control the VM, but removes the right for
access to the code, register state or data that is used by VM.
More information on the architecture is available here[0].

    Arm CCA Reference Software Architecture

        Realm World    ||    Normal World   ||  Secure World  ||
                       ||        |          ||                ||
 EL0 x-------x         || x----x | x------x ||                ||
     | Realm |         || |    | | |      | ||                ||
     |       |         || | VM | | |      | ||                ||
 ----|  VM*  |---------||-|    |---|      |-||----------------||
     |       |         || |    | | |  H   | ||                ||
 EL1 x-------x         || x----x | |      | ||                ||
         ^             ||        | |  o   | ||                ||
         |             ||        | |      | ||                ||
 ------- R*------------------------|  s  -|---------------------
         S             ||          |      | ||                ||
         I             ||          |  t   | ||                ||
         |             ||          |      | ||                || 
         v             ||          x------x ||                ||
 EL2    RMM*           ||              ^    ||                ||
         ^             ||              |    ||                ||
 ========|=============================|========================
         |                             | SMC
         x--------- *RMI* -------------x

 EL3                   Root World
                       EL3 Firmware
 ===============================================================
Where :
 RMM - Realm Management Monitor
 RMI - Realm Management Interface
 RSI - Realm Service Interface
 SMC - Secure Monitor Call

RME introduces a new security state "Realm world", in addition to the
traditional Secure and Non-Secure states. The Arm CCA defines a new component,
Realm Management Monitor (RMM) that runs at R-EL2. This is a standard piece of
firmware, verified, installed and loaded by the EL3 firmware (e.g, TF-A), at
system boot.

The RMM provides standard interfaces - Realm Management Interface (RMI) - to the
Normal world hypervisor to manage the VMs running in the Realm world (also called
Realms in short). These are exposed via SMC and are routed through the EL3
firmwre.
The RMI interface includes:
  - Move a physical page from the Normal world to the Realm world
  - Creating a Realm with requested parameters, tracked via Realm Descriptor (RD)
  - Creating VCPUs aka Realm Execution Context (REC), with initial register state.
  - Create stage2 translation table at any level.
  - Load initial images into Realm Memory from normal world memory
  - Schedule RECs (vCPUs) and handle exits
  - Inject virtual interrupts into the Realm
  - Service stage2 runtime faults with pages (provided by host, scrubbed by RMM).
  - Create "shared" mappings that can be accessed by VMM/Hyp.
  - Reclaim the memory allocated for the RAM and RTTs (Realm Translation Tables)

However v1.0 of RMM specifications doesn't support:
 - Paging protected memory of a Realm VM. Thus the pages backing the protected
   memory region must be pinned.
 - Live migration of Realms.
 - Trusted Device assignment.
 - Physical interrupt backed Virtual interrupts for Realms

RMM also provides certain services to the Realms via SMC, called Realm Service
Interface (RSI). These include:
 - Realm Guest Configuration.
 - Attestation & Measurement services
 - Managing the state of an Intermediate Physical Address (IPA aka GPA) page.
 - Host Call service (Communication with the Normal world Hypervisor)

The specifications for the RMM software is currently at *v1.0-Beta2* and the
latest version is available here [1].

The Trusted Firmware foundation has an implementation of the RMM - TF-RMM -
available here [3].

Implementation
=================

This version of the stack is based on the RMM specification v1.0-Beta0[2], with
following exceptions :
  - TF-RMM/KVM currently doesn't support the optional features of PMU,
     SVE and Self-hosted debug (coming soon).
  - The RSI_HOST_CALL structure alignment requirement is reduced to match
     RMM v1.0 Beta1
  - RMI/RSI version numbers do not match the RMM spec. This will be
    resolved once the spec/implementation is complete, across TF-RMM+Linux stack.

We plan to update the stack to support the latest version of the RMMv1.0 spec
in the coming revisions.

This release includes the following components :

 a) Linux Kernel
     i) Host / KVM support - Support for driving the Realms via RMI. This is
     dependent on running in the Kernel at EL2 (aka VHE mode). Also provides
     UABI for VMMs to manage the Realm VMs. The support is restricted to 4K page
     size, matching the Stage2 granule supported by RMM. The VMM is responsible
     for making sure the guest memory is locked.

       TODO: Guest Private memory[10] integration - We have been following the
       series and support will be added once it is merged upstream.
     
     ii) Guest support - Support for a Linux Kernel to run in the Realm VM at
     Realm-EL1, using RSI services. This includes virtio support (virtio-v1.0
     only). All I/O are treated as non-secure/shared.
 
 c) kvmtool - VMM changes required to manage Realm VMs. No guest private memory
    as mentioned above.
 d) kvm-unit-tests - Support for running in Realms along with additional tests
    for RSI ABI.

Running the stack
====================

To run/test the stack, you would need the following components :

1) FVP Base AEM RevC model with FEAT_RME support [4]
2) TF-A firmware for EL3 [5]
3) TF-A RMM for R-EL2 [3]
4) Linux Kernel [6]
5) kvmtool [7]
6) kvm-unit-tests [8]

Instructions for building the firmware components and running the model are
available here [9]. Once, the host kernel is booted, a Realm can be launched by
invoking the `lkvm` commad as follows:

 $ lkvm run --realm 				 \
	 --measurement-algo=["sha256", "sha512"] \
	 --disable-sve				 \
	 <normal-vm-options>

Where:
 * --measurement-algo (Optional) specifies the algorithm selected for creating the
   initial measurements by the RMM for this Realm (defaults to sha256).
 * GICv3 is mandatory for the Realms.
 * SVE is not yet supported in the TF-RMM, and thus must be disabled using
   --disable-sve

You may also run the kvm-unit-tests inside the Realm world, using the similar
options as above.


Links
============

[0] Arm CCA Landing page (See Key Resources section for various documentations)
    https://www.arm.com/architecture/security-features/arm-confidential-compute-architecture

[1] RMM Specification Latest
    https://developer.arm.com/documentation/den0137/latest

[2] RMM v1.0-Beta0 specification
    https://developer.arm.com/documentation/den0137/1-0bet0/

[3] Trusted Firmware RMM - TF-RMM
    https://www.trustedfirmware.org/projects/tf-rmm/
    GIT: https://git.trustedfirmware.org/TF-RMM/tf-rmm.git

[4] FVP Base RevC AEM Model (available on x86_64 / Arm64 Linux)
    https://developer.arm.com/Tools%20and%20Software/Fixed%20Virtual%20Platforms

[5] Trusted Firmware for A class
    https://www.trustedfirmware.org/projects/tf-a/

[6] Linux kernel support for Arm-CCA
    https://gitlab.arm.com/linux-arm/linux-cca
    Host Support branch:	cca-host/rfc-v1
    Guest Support branch:	cca-guest/rfc-v1

[7] kvmtool support for Arm CCA
    https://gitlab.arm.com/linux-arm/kvmtool-cca cca/rfc-v1

[8] kvm-unit-tests support for Arm CCA
    https://gitlab.arm.com/linux-arm/kvm-unit-tests-cca  cca/rfc-v1

[9] Instructions for Building Firmware components and running the model, see
    section 4.19.2 "Building and running TF-A with RME"
    https://trustedfirmware-a.readthedocs.io/en/latest/components/realm-management-extension.html#building-and-running-tf-a-with-rme

[10] fd based Guest Private memory for KVM
   https://lkml.kernel.org/r/20221202061347.1070246-1-chao.p.peng@linux.intel.com

Cc: Alexandru Elisei <alexandru.elisei@arm.com>
Cc: Andrew Jones <andrew.jones@linux.dev>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chao Peng <chao.p.peng@linux.intel.com>
Cc: Christoffer Dall <christoffer.dall@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Cc: James Morse <james.morse@arm.com>
Cc: Jean-Philippe Brucker <jean-philippe@linaro.org>
Cc: Joey Gouly <Joey.Gouly@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Quentin Perret <qperret@google.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Steven Price <steven.price@arm.com>
Cc: Thomas Huth <thuth@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Zenghui Yu <yuzenghui@huawei.com>
To: linux-coco@lists.linux.dev
To: kvmarm@lists.linux.dev
Cc: kvmarm@lists.cs.columbia.edu
Cc: linux-arm-kernel@lists.infradead.org
To: linux-kernel@vger.kernel.org
To: kvm@vger.kernel.org

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

* [RFC PATCH 00/14] arm64: Support for running as a guest in Arm CCA
  2023-01-27 11:22 ` Suzuki K Poulose
@ 2023-01-27 11:27   ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

This series is an RFC adding support for running Linux in a protected
VM under the new Arm Confidential Compute Architecture (CCA). The
purpose of this series is to gather feedback on the proposed changes to
the architecture code for CCA.

The ABI to the RMM from a realm (the RSI) is based on the Beta 0
specification[2] and will be updated in the future when a final version
of the specification is published.

This series is based on v6.2-rc1. It is also available as a git
repository:

https://gitlab.arm.com/linux-arm/linux-cca cca-guest/rfc-v1

Introduction
============
A more general introduction to Arm CCA is available on the Arm
website[3], and links to the other components involved are available in
the overall cover letter[4].

Arm Confidential Compute Architecture adds two new 'worlds' to the
architecture: Root and Realm. A new software component known as the RMM
(Realm Management Monitor) runs in Realm EL2 and is trusted by both the
Normal World and VMs running within Realms. This enables mutual
distrust between the Realm VMs and the Normal World.

Virtual machines running within a Realm can decide on a (4k)
page-by-page granularity whether to share a page with the (Normal World)
host or to keep it private (protected). This protection is provided by
the hardware and attempts to access a page which isn't shared by the
Normal World will trigger a Granule Protection Fault.

Realm VMs can communicate with the RMM via another SMC interface known
as RSI (Realm Services Interface). This series adds wrappers for the
full set of RSI commands and uses them to manage the Realm IPA State
(RIPAS) and to discover the configuration of the realm.

The VM running within the Realm needs to ensure that memory that is
going to use is marked as 'RIPAS_RAM' (i.e. protected memory accessible
only to the guest). This could be provided by the VMM (and subject to
measurement to ensure it is setup correctly) or the VM can set it
itself.  This series includes a patch which will iterate over all
described RAM and set the RIPAS. An alternative would be to update
booting.rst and state this as a requirement, but this would reduce the
flexibility of the VMM to manage the available memory to the guest (as
the initial RIPAS state is part of the guest's measurement).

Within the Realm the most-significant active bit of the IPA is used to
select whether the access is to protected memory or to memory shared
with the host. This series treats this bit as if it is attribute bit in
the page tables and will modify it when sharing/unsharing memory with
the host.

This top bit usage also necessitates that the IPA width is made more
dynamic in the guest. The VMM will choose a width (and therefore which
bit controls the shared flag) and the guest must be able to identify
this bit to mask it out when necessary. PHYS_MASK_SHIFT/PHYS_MASK are
therefore made dynamic.

To allow virtio to communicate with the host the shared buffers must be
placed in memory which has this top IPA bit set. This is achieved by
implementating the set_memory_{encrypted,decrypted} APIs for arm64 and
forcing the use of bounce buffers. For now all device access is
considered to required the memory to be shared, at this stage there is
no support for real devices to be assigned to a realm guest - obviously
if device assignment is added this will have to change.

Finally the GIC is (largely) emulated by the (untrusted) host. The RMM
provides some management (including register save/restore) but the
ITS buffers must be placed into shared memory for the host to emulate.
There is likely to be future work to harden the GIC driver against a
malicious host (along with any other drivers used within a Realm guest).

[1] https://lore.kernel.org/r/20221202061347.1070246-1-chao.p.peng%40linux.intel.com
[2] https://developer.arm.com/documentation/den0137/1-0bet0/
[3] https://www.arm.com/architecture/security-features/arm-confidential-compute-architecture
[4] https://lore.kernel.org/r/20230127112248.136810-1-suzuki.poulose%40arm.com

Steven Price (9):
  arm64: remove redundant 'extern'
  arm64: Detect if in a realm and set RIPAS RAM
  arm64: realm: Query IPA size from the RMM
  arm64: Mark all I/O as non-secure shared
  arm64: Make the PHYS_MASK_SHIFT dynamic
  arm64: Enforce bounce buffers for realm DMA
  arm64: Enable memory encrypt for Realms
  arm64: realm: Support nonsecure ITS emulation shared
  HACK: Accept prototype RSI version

Suzuki K Poulose (5):
  arm64: rsi: Add RSI definitions
  fixmap: Allow architecture overriding set_fixmap_io
  arm64: Override set_fixmap_io
  arm64: Force device mappings to be non-secure shared
  efi: arm64: Map Device with Prot Shared

 arch/arm64/Kconfig                     |   3 +
 arch/arm64/include/asm/fixmap.h        |   4 +-
 arch/arm64/include/asm/io.h            |   6 +-
 arch/arm64/include/asm/kvm_arm.h       |   2 +-
 arch/arm64/include/asm/mem_encrypt.h   |  19 ++++
 arch/arm64/include/asm/pgtable-hwdef.h |   4 +-
 arch/arm64/include/asm/pgtable-prot.h  |   2 +
 arch/arm64/include/asm/pgtable.h       |   7 +-
 arch/arm64/include/asm/rsi.h           |  46 +++++++++
 arch/arm64/include/asm/rsi_cmds.h      |  71 +++++++++++++
 arch/arm64/include/asm/rsi_smc.h       | 132 +++++++++++++++++++++++++
 arch/arm64/kernel/Makefile             |   2 +-
 arch/arm64/kernel/efi.c                |   2 +-
 arch/arm64/kernel/head.S               |   2 +-
 arch/arm64/kernel/rsi.c                |  82 +++++++++++++++
 arch/arm64/kernel/setup.c              |   3 +
 arch/arm64/kvm/Kconfig                 |   8 ++
 arch/arm64/mm/init.c                   |  10 +-
 arch/arm64/mm/mmu.c                    |  13 +++
 arch/arm64/mm/pageattr.c               |  48 ++++++++-
 drivers/irqchip/irq-gic-v3-its.c       |  95 +++++++++++++-----
 include/asm-generic/fixmap.h           |   2 +
 22 files changed, 523 insertions(+), 40 deletions(-)
 create mode 100644 arch/arm64/include/asm/mem_encrypt.h
 create mode 100644 arch/arm64/include/asm/rsi.h
 create mode 100644 arch/arm64/include/asm/rsi_cmds.h
 create mode 100644 arch/arm64/include/asm/rsi_smc.h
 create mode 100644 arch/arm64/kernel/rsi.c

-- 
2.34.1


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

* [RFC PATCH 00/14] arm64: Support for running as a guest in Arm CCA
@ 2023-01-27 11:27   ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

This series is an RFC adding support for running Linux in a protected
VM under the new Arm Confidential Compute Architecture (CCA). The
purpose of this series is to gather feedback on the proposed changes to
the architecture code for CCA.

The ABI to the RMM from a realm (the RSI) is based on the Beta 0
specification[2] and will be updated in the future when a final version
of the specification is published.

This series is based on v6.2-rc1. It is also available as a git
repository:

https://gitlab.arm.com/linux-arm/linux-cca cca-guest/rfc-v1

Introduction
============
A more general introduction to Arm CCA is available on the Arm
website[3], and links to the other components involved are available in
the overall cover letter[4].

Arm Confidential Compute Architecture adds two new 'worlds' to the
architecture: Root and Realm. A new software component known as the RMM
(Realm Management Monitor) runs in Realm EL2 and is trusted by both the
Normal World and VMs running within Realms. This enables mutual
distrust between the Realm VMs and the Normal World.

Virtual machines running within a Realm can decide on a (4k)
page-by-page granularity whether to share a page with the (Normal World)
host or to keep it private (protected). This protection is provided by
the hardware and attempts to access a page which isn't shared by the
Normal World will trigger a Granule Protection Fault.

Realm VMs can communicate with the RMM via another SMC interface known
as RSI (Realm Services Interface). This series adds wrappers for the
full set of RSI commands and uses them to manage the Realm IPA State
(RIPAS) and to discover the configuration of the realm.

The VM running within the Realm needs to ensure that memory that is
going to use is marked as 'RIPAS_RAM' (i.e. protected memory accessible
only to the guest). This could be provided by the VMM (and subject to
measurement to ensure it is setup correctly) or the VM can set it
itself.  This series includes a patch which will iterate over all
described RAM and set the RIPAS. An alternative would be to update
booting.rst and state this as a requirement, but this would reduce the
flexibility of the VMM to manage the available memory to the guest (as
the initial RIPAS state is part of the guest's measurement).

Within the Realm the most-significant active bit of the IPA is used to
select whether the access is to protected memory or to memory shared
with the host. This series treats this bit as if it is attribute bit in
the page tables and will modify it when sharing/unsharing memory with
the host.

This top bit usage also necessitates that the IPA width is made more
dynamic in the guest. The VMM will choose a width (and therefore which
bit controls the shared flag) and the guest must be able to identify
this bit to mask it out when necessary. PHYS_MASK_SHIFT/PHYS_MASK are
therefore made dynamic.

To allow virtio to communicate with the host the shared buffers must be
placed in memory which has this top IPA bit set. This is achieved by
implementating the set_memory_{encrypted,decrypted} APIs for arm64 and
forcing the use of bounce buffers. For now all device access is
considered to required the memory to be shared, at this stage there is
no support for real devices to be assigned to a realm guest - obviously
if device assignment is added this will have to change.

Finally the GIC is (largely) emulated by the (untrusted) host. The RMM
provides some management (including register save/restore) but the
ITS buffers must be placed into shared memory for the host to emulate.
There is likely to be future work to harden the GIC driver against a
malicious host (along with any other drivers used within a Realm guest).

[1] https://lore.kernel.org/r/20221202061347.1070246-1-chao.p.peng%40linux.intel.com
[2] https://developer.arm.com/documentation/den0137/1-0bet0/
[3] https://www.arm.com/architecture/security-features/arm-confidential-compute-architecture
[4] https://lore.kernel.org/r/20230127112248.136810-1-suzuki.poulose%40arm.com

Steven Price (9):
  arm64: remove redundant 'extern'
  arm64: Detect if in a realm and set RIPAS RAM
  arm64: realm: Query IPA size from the RMM
  arm64: Mark all I/O as non-secure shared
  arm64: Make the PHYS_MASK_SHIFT dynamic
  arm64: Enforce bounce buffers for realm DMA
  arm64: Enable memory encrypt for Realms
  arm64: realm: Support nonsecure ITS emulation shared
  HACK: Accept prototype RSI version

Suzuki K Poulose (5):
  arm64: rsi: Add RSI definitions
  fixmap: Allow architecture overriding set_fixmap_io
  arm64: Override set_fixmap_io
  arm64: Force device mappings to be non-secure shared
  efi: arm64: Map Device with Prot Shared

 arch/arm64/Kconfig                     |   3 +
 arch/arm64/include/asm/fixmap.h        |   4 +-
 arch/arm64/include/asm/io.h            |   6 +-
 arch/arm64/include/asm/kvm_arm.h       |   2 +-
 arch/arm64/include/asm/mem_encrypt.h   |  19 ++++
 arch/arm64/include/asm/pgtable-hwdef.h |   4 +-
 arch/arm64/include/asm/pgtable-prot.h  |   2 +
 arch/arm64/include/asm/pgtable.h       |   7 +-
 arch/arm64/include/asm/rsi.h           |  46 +++++++++
 arch/arm64/include/asm/rsi_cmds.h      |  71 +++++++++++++
 arch/arm64/include/asm/rsi_smc.h       | 132 +++++++++++++++++++++++++
 arch/arm64/kernel/Makefile             |   2 +-
 arch/arm64/kernel/efi.c                |   2 +-
 arch/arm64/kernel/head.S               |   2 +-
 arch/arm64/kernel/rsi.c                |  82 +++++++++++++++
 arch/arm64/kernel/setup.c              |   3 +
 arch/arm64/kvm/Kconfig                 |   8 ++
 arch/arm64/mm/init.c                   |  10 +-
 arch/arm64/mm/mmu.c                    |  13 +++
 arch/arm64/mm/pageattr.c               |  48 ++++++++-
 drivers/irqchip/irq-gic-v3-its.c       |  95 +++++++++++++-----
 include/asm-generic/fixmap.h           |   2 +
 22 files changed, 523 insertions(+), 40 deletions(-)
 create mode 100644 arch/arm64/include/asm/mem_encrypt.h
 create mode 100644 arch/arm64/include/asm/rsi.h
 create mode 100644 arch/arm64/include/asm/rsi_cmds.h
 create mode 100644 arch/arm64/include/asm/rsi_smc.h
 create mode 100644 arch/arm64/kernel/rsi.c

-- 
2.34.1


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

* [RFC PATCH 01/14] arm64: remove redundant 'extern'
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

It isn't necessary to mark function definitions extern and goes against
the kernel coding style. Remove the redundant extern keyword.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/fixmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 71ed5fdf718b..09ba9fe3b02c 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -107,7 +107,7 @@ void __init early_fixmap_init(void);
 #define __late_set_fixmap __set_fixmap
 #define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
 
-extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
+void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
 
 #include <asm-generic/fixmap.h>
 
-- 
2.34.1


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

* [RFC PATCH 01/14] arm64: remove redundant 'extern'
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

It isn't necessary to mark function definitions extern and goes against
the kernel coding style. Remove the redundant extern keyword.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/fixmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 71ed5fdf718b..09ba9fe3b02c 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -107,7 +107,7 @@ void __init early_fixmap_init(void);
 #define __late_set_fixmap __set_fixmap
 #define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
 
-extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
+void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
 
 #include <asm-generic/fixmap.h>
 
-- 
2.34.1


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

* [RFC PATCH 02/14] arm64: rsi: Add RSI definitions
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

The RMM (Realm Management Monitor) provides functionality that can be
accessed by a realm guest through SMC (Realm Services Interface) calls.

The SMC definitions are based on DEN0137[1] version A-bet0.

[1] https://developer.arm.com/documentation/den0137/latest

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rsi_cmds.h |  57 +++++++++++++
 arch/arm64/include/asm/rsi_smc.h  | 130 ++++++++++++++++++++++++++++++
 2 files changed, 187 insertions(+)
 create mode 100644 arch/arm64/include/asm/rsi_cmds.h
 create mode 100644 arch/arm64/include/asm/rsi_smc.h

diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
new file mode 100644
index 000000000000..a0b3c1bd786a
--- /dev/null
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RSI_CMDS_H
+#define __ASM_RSI_CMDS_H
+
+#include <linux/arm-smccc.h>
+
+#include <asm/rsi_smc.h>
+
+enum ripas {
+	RSI_RIPAS_EMPTY,
+	RSI_RIPAS_RAM,
+};
+
+static inline unsigned long rsi_get_version(void)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(SMC_RSI_ABI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
+
+	return res.a0;
+}
+
+static inline unsigned long invoke_rsi_fn_smc(unsigned long function_id,
+					      unsigned long arg0,
+					      unsigned long arg1,
+					      unsigned long arg2,
+					      unsigned long arg3)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, 0, 0, 0, &res);
+	return res.a0;
+}
+
+static inline void invoke_rsi_fn_smc_with_res(unsigned long function_id,
+					      unsigned long arg0,
+					      unsigned long arg1,
+					      unsigned long arg2,
+					      unsigned long arg3,
+					      struct arm_smccc_res *res)
+{
+	arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, 0, 0, 0, res);
+}
+
+static inline unsigned long rsi_set_addr_range_state(phys_addr_t start,
+						     phys_addr_t end,
+						     enum ripas state)
+{
+	return invoke_rsi_fn_smc(SMC_RSI_IPA_STATE_SET,
+				 start, (end - start), state, 0);
+}
+
+#endif
diff --git a/arch/arm64/include/asm/rsi_smc.h b/arch/arm64/include/asm/rsi_smc.h
new file mode 100644
index 000000000000..bc0cdd83f164
--- /dev/null
+++ b/arch/arm64/include/asm/rsi_smc.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __SMC_RSI_H_
+#define __SMC_RSI_H_
+
+/*
+ * This file describes the Realm Services Interface (RSI) Application Binary
+ * Interface (ABI) for SMC calls made from within the Realm to the RMM and
+ * serviced by the RMM.
+ */
+
+#define SMC_RSI_CALL_BASE		0xC4000000
+
+/*
+ * The major version number of the RSI implementation.  Increase this whenever
+ * the binary format or semantics of the SMC calls change.
+ */
+#define RSI_ABI_VERSION_MAJOR		1
+
+/*
+ * The minor version number of the RSI implementation.  Increase this when
+ * a bug is fixed, or a feature is added without breaking binary compatibility.
+ */
+#define RSI_ABI_VERSION_MINOR		0
+
+#define RSI_ABI_VERSION			((RSI_ABI_VERSION_MAJOR << 16) | \
+					 RSI_ABI_VERSION_MINOR)
+
+#define RSI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
+#define RSI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
+
+#define RSI_SUCCESS			0
+#define RSI_ERROR_INPUT			1
+#define RSI_ERROR_STATE			2
+#define RSI_INCOMPLETE			3
+
+#define SMC_RSI_FID(_x)			(SMC_RSI_CALL_BASE + (_x))
+
+#define SMC_RSI_ABI_VERSION			SMC_RSI_FID(0x190)
+
+/*
+ * arg1 == The IPA of token buffer
+ * arg2 == Challenge value, bytes:  0 -  7
+ * arg3 == Challenge value, bytes:  7 - 15
+ * arg4 == Challenge value, bytes: 16 - 23
+ * arg5 == Challenge value, bytes: 24 - 31
+ * arg6 == Challenge value, bytes: 32 - 39
+ * arg7 == Challenge value, bytes: 40 - 47
+ * arg8 == Challenge value, bytes: 48 - 55
+ * arg9 == Challenge value, bytes: 56 - 63
+ * ret0 == Status / error
+ */
+#define SMC_RSI_ATTESTATION_TOKEN_INIT		SMC_RSI_FID(0x194)
+
+/*
+ * arg1 == The IPA of token buffer
+ * ret0 == Status / error
+ * ret1 == Size of completed token in bytes
+ */
+#define SMC_RSI_ATTESTATION_TOKEN_CONTINUE	SMC_RSI_FID(0x195)
+
+/*
+ * arg1  == Index, which measurements slot to extend
+ * arg2  == Size of realm measurement in bytes, max 64 bytes
+ * arg3  == Measurement value, bytes:  0 -  7
+ * arg4  == Measurement value, bytes:  7 - 15
+ * arg5  == Measurement value, bytes: 16 - 23
+ * arg6  == Measurement value, bytes: 24 - 31
+ * arg7  == Measurement value, bytes: 32 - 39
+ * arg8  == Measurement value, bytes: 40 - 47
+ * arg9  == Measurement value, bytes: 48 - 55
+ * arg10 == Measurement value, bytes: 56 - 63
+ * ret0  == Status / error
+ */
+#define SMC_RSI_MEASUREMENT_EXTEND		SMC_RSI_FID(0x193)
+
+/*
+ * arg1 == Index, which measurements slot to read
+ * ret0 == Status / error
+ * ret1 == Measurement value, bytes:  0 -  7
+ * ret2 == Measurement value, bytes:  7 - 15
+ * ret3 == Measurement value, bytes: 16 - 23
+ * ret4 == Measurement value, bytes: 24 - 31
+ * ret5 == Measurement value, bytes: 32 - 39
+ * ret6 == Measurement value, bytes: 40 - 47
+ * ret7 == Measurement value, bytes: 48 - 55
+ * ret8 == Measurement value, bytes: 56 - 63
+ */
+#define SMC_RSI_MEASUREMENT_READ		SMC_RSI_FID(0x192)
+
+#ifndef __ASSEMBLY__
+
+struct realm_config {
+	unsigned long ipa_bits; /* Width of IPA in bits */
+};
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * arg1 == struct realm_config addr
+ * ret0 == Status / error
+ */
+#define SMC_RSI_REALM_CONFIG			SMC_RSI_FID(0x196)
+
+/*
+ * arg1 == IPA address of target region
+ * arg2 == size of target region in bytes
+ * arg3 == RIPAS value
+ * ret0 == Status / error
+ * ret1 == Top of modified IPA range
+ */
+#define SMC_RSI_IPA_STATE_SET			SMC_RSI_FID(0x197)
+
+/*
+ * arg1 == IPA of target page
+ * ret0 == Status / error
+ * ret1 == RIPAS value
+ */
+#define SMC_RSI_IPA_STATE_GET			SMC_RSI_FID(0x198)
+
+/*
+ * arg1 == IPA of host call structure
+ * ret0 == Status / error
+ */
+#define SMC_RSI_HOST_CALL			SMC_RSI_FID(0x199)
+
+#endif /* __SMC_RSI_H_ */
-- 
2.34.1


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

* [RFC PATCH 02/14] arm64: rsi: Add RSI definitions
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

The RMM (Realm Management Monitor) provides functionality that can be
accessed by a realm guest through SMC (Realm Services Interface) calls.

The SMC definitions are based on DEN0137[1] version A-bet0.

[1] https://developer.arm.com/documentation/den0137/latest

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rsi_cmds.h |  57 +++++++++++++
 arch/arm64/include/asm/rsi_smc.h  | 130 ++++++++++++++++++++++++++++++
 2 files changed, 187 insertions(+)
 create mode 100644 arch/arm64/include/asm/rsi_cmds.h
 create mode 100644 arch/arm64/include/asm/rsi_smc.h

diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
new file mode 100644
index 000000000000..a0b3c1bd786a
--- /dev/null
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RSI_CMDS_H
+#define __ASM_RSI_CMDS_H
+
+#include <linux/arm-smccc.h>
+
+#include <asm/rsi_smc.h>
+
+enum ripas {
+	RSI_RIPAS_EMPTY,
+	RSI_RIPAS_RAM,
+};
+
+static inline unsigned long rsi_get_version(void)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(SMC_RSI_ABI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
+
+	return res.a0;
+}
+
+static inline unsigned long invoke_rsi_fn_smc(unsigned long function_id,
+					      unsigned long arg0,
+					      unsigned long arg1,
+					      unsigned long arg2,
+					      unsigned long arg3)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, 0, 0, 0, &res);
+	return res.a0;
+}
+
+static inline void invoke_rsi_fn_smc_with_res(unsigned long function_id,
+					      unsigned long arg0,
+					      unsigned long arg1,
+					      unsigned long arg2,
+					      unsigned long arg3,
+					      struct arm_smccc_res *res)
+{
+	arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, 0, 0, 0, res);
+}
+
+static inline unsigned long rsi_set_addr_range_state(phys_addr_t start,
+						     phys_addr_t end,
+						     enum ripas state)
+{
+	return invoke_rsi_fn_smc(SMC_RSI_IPA_STATE_SET,
+				 start, (end - start), state, 0);
+}
+
+#endif
diff --git a/arch/arm64/include/asm/rsi_smc.h b/arch/arm64/include/asm/rsi_smc.h
new file mode 100644
index 000000000000..bc0cdd83f164
--- /dev/null
+++ b/arch/arm64/include/asm/rsi_smc.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __SMC_RSI_H_
+#define __SMC_RSI_H_
+
+/*
+ * This file describes the Realm Services Interface (RSI) Application Binary
+ * Interface (ABI) for SMC calls made from within the Realm to the RMM and
+ * serviced by the RMM.
+ */
+
+#define SMC_RSI_CALL_BASE		0xC4000000
+
+/*
+ * The major version number of the RSI implementation.  Increase this whenever
+ * the binary format or semantics of the SMC calls change.
+ */
+#define RSI_ABI_VERSION_MAJOR		1
+
+/*
+ * The minor version number of the RSI implementation.  Increase this when
+ * a bug is fixed, or a feature is added without breaking binary compatibility.
+ */
+#define RSI_ABI_VERSION_MINOR		0
+
+#define RSI_ABI_VERSION			((RSI_ABI_VERSION_MAJOR << 16) | \
+					 RSI_ABI_VERSION_MINOR)
+
+#define RSI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
+#define RSI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
+
+#define RSI_SUCCESS			0
+#define RSI_ERROR_INPUT			1
+#define RSI_ERROR_STATE			2
+#define RSI_INCOMPLETE			3
+
+#define SMC_RSI_FID(_x)			(SMC_RSI_CALL_BASE + (_x))
+
+#define SMC_RSI_ABI_VERSION			SMC_RSI_FID(0x190)
+
+/*
+ * arg1 == The IPA of token buffer
+ * arg2 == Challenge value, bytes:  0 -  7
+ * arg3 == Challenge value, bytes:  7 - 15
+ * arg4 == Challenge value, bytes: 16 - 23
+ * arg5 == Challenge value, bytes: 24 - 31
+ * arg6 == Challenge value, bytes: 32 - 39
+ * arg7 == Challenge value, bytes: 40 - 47
+ * arg8 == Challenge value, bytes: 48 - 55
+ * arg9 == Challenge value, bytes: 56 - 63
+ * ret0 == Status / error
+ */
+#define SMC_RSI_ATTESTATION_TOKEN_INIT		SMC_RSI_FID(0x194)
+
+/*
+ * arg1 == The IPA of token buffer
+ * ret0 == Status / error
+ * ret1 == Size of completed token in bytes
+ */
+#define SMC_RSI_ATTESTATION_TOKEN_CONTINUE	SMC_RSI_FID(0x195)
+
+/*
+ * arg1  == Index, which measurements slot to extend
+ * arg2  == Size of realm measurement in bytes, max 64 bytes
+ * arg3  == Measurement value, bytes:  0 -  7
+ * arg4  == Measurement value, bytes:  7 - 15
+ * arg5  == Measurement value, bytes: 16 - 23
+ * arg6  == Measurement value, bytes: 24 - 31
+ * arg7  == Measurement value, bytes: 32 - 39
+ * arg8  == Measurement value, bytes: 40 - 47
+ * arg9  == Measurement value, bytes: 48 - 55
+ * arg10 == Measurement value, bytes: 56 - 63
+ * ret0  == Status / error
+ */
+#define SMC_RSI_MEASUREMENT_EXTEND		SMC_RSI_FID(0x193)
+
+/*
+ * arg1 == Index, which measurements slot to read
+ * ret0 == Status / error
+ * ret1 == Measurement value, bytes:  0 -  7
+ * ret2 == Measurement value, bytes:  7 - 15
+ * ret3 == Measurement value, bytes: 16 - 23
+ * ret4 == Measurement value, bytes: 24 - 31
+ * ret5 == Measurement value, bytes: 32 - 39
+ * ret6 == Measurement value, bytes: 40 - 47
+ * ret7 == Measurement value, bytes: 48 - 55
+ * ret8 == Measurement value, bytes: 56 - 63
+ */
+#define SMC_RSI_MEASUREMENT_READ		SMC_RSI_FID(0x192)
+
+#ifndef __ASSEMBLY__
+
+struct realm_config {
+	unsigned long ipa_bits; /* Width of IPA in bits */
+};
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * arg1 == struct realm_config addr
+ * ret0 == Status / error
+ */
+#define SMC_RSI_REALM_CONFIG			SMC_RSI_FID(0x196)
+
+/*
+ * arg1 == IPA address of target region
+ * arg2 == size of target region in bytes
+ * arg3 == RIPAS value
+ * ret0 == Status / error
+ * ret1 == Top of modified IPA range
+ */
+#define SMC_RSI_IPA_STATE_SET			SMC_RSI_FID(0x197)
+
+/*
+ * arg1 == IPA of target page
+ * ret0 == Status / error
+ * ret1 == RIPAS value
+ */
+#define SMC_RSI_IPA_STATE_GET			SMC_RSI_FID(0x198)
+
+/*
+ * arg1 == IPA of host call structure
+ * ret0 == Status / error
+ */
+#define SMC_RSI_HOST_CALL			SMC_RSI_FID(0x199)
+
+#endif /* __SMC_RSI_H_ */
-- 
2.34.1


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

* [RFC PATCH 03/14] arm64: Detect if in a realm and set RIPAS RAM
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Detect that the VM is a realm guest by the presence of the RSI
interface.

If in a realm then all memory needs to be marked as RIPAS RAM initially,
the loader may or may not have done this for us. To be sure iterate over
all RAM and mark it as such. Any failure is fatal as that implies the
RAM regions passed to Linux are incorrect - which would mean failing
later when attempting to access non-existent RAM.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rsi.h      | 46 ++++++++++++++++++++++++++++
 arch/arm64/include/asm/rsi_cmds.h | 12 ++++++--
 arch/arm64/kernel/Makefile        |  2 +-
 arch/arm64/kernel/rsi.c           | 50 +++++++++++++++++++++++++++++++
 arch/arm64/kernel/setup.c         |  3 ++
 arch/arm64/mm/init.c              |  2 ++
 6 files changed, 111 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/rsi.h
 create mode 100644 arch/arm64/kernel/rsi.c

diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
new file mode 100644
index 000000000000..3b56aac5dc43
--- /dev/null
+++ b/arch/arm64/include/asm/rsi.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RSI_H_
+#define __ASM_RSI_H_
+
+#include <linux/jump_label.h>
+#include <asm/rsi_cmds.h>
+
+extern struct static_key_false rsi_present;
+
+void arm64_setup_memory(void);
+
+void __init arm64_rsi_init(void);
+static inline bool is_realm_world(void)
+{
+	return static_branch_unlikely(&rsi_present);
+}
+
+static inline void set_memory_range(phys_addr_t start, phys_addr_t end,
+				    enum ripas state)
+{
+	unsigned long ret;
+	phys_addr_t top;
+
+	while (start != end) {
+		ret = rsi_set_addr_range_state(start, end, state, &top);
+		BUG_ON(ret);
+		BUG_ON(top < start);
+		BUG_ON(top > end);
+		start = top;
+	}
+}
+
+static inline void set_memory_range_protected(phys_addr_t start, phys_addr_t end)
+{
+	set_memory_range(start, end, RSI_RIPAS_RAM);
+}
+
+static inline void set_memory_range_shared(phys_addr_t start, phys_addr_t end)
+{
+	set_memory_range(start, end, RSI_RIPAS_EMPTY);
+}
+#endif
diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
index a0b3c1bd786a..ee0df00efd87 100644
--- a/arch/arm64/include/asm/rsi_cmds.h
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -48,10 +48,16 @@ static inline void invoke_rsi_fn_smc_with_res(unsigned long function_id,
 
 static inline unsigned long rsi_set_addr_range_state(phys_addr_t start,
 						     phys_addr_t end,
-						     enum ripas state)
+						     enum ripas state,
+						     phys_addr_t *top)
 {
-	return invoke_rsi_fn_smc(SMC_RSI_IPA_STATE_SET,
-				 start, (end - start), state, 0);
+	struct arm_smccc_res res;
+
+	invoke_rsi_fn_smc_with_res(SMC_RSI_IPA_STATE_SET,
+				   start, (end - start), state, 0, &res);
+
+	*top = res.a1;
+	return res.a0;
 }
 
 #endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index ceba6792f5b3..f301c2ad2fa7 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -34,7 +34,7 @@ obj-y			:= debug-monitors.o entry.o irq.o fpsimd.o		\
 			   cpufeature.o alternative.o cacheinfo.o		\
 			   smp.o smp_spin_table.o topology.o smccc-call.o	\
 			   syscall.o proton-pack.o idreg-override.o idle.o	\
-			   patching.o
+			   patching.o rsi.o
 
 obj-$(CONFIG_COMPAT)			+= sys32.o signal32.o			\
 					   sys_compat.o
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
new file mode 100644
index 000000000000..b354ac661c9d
--- /dev/null
+++ b/arch/arm64/kernel/rsi.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#include <linux/jump_label.h>
+#include <linux/memblock.h>
+#include <asm/rsi.h>
+
+DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
+
+static bool rsi_version_matches(void)
+{
+	unsigned long ver = rsi_get_version();
+
+	if (ver == SMCCC_RET_NOT_SUPPORTED)
+		return false;
+
+	pr_info("RME: RSI version %lu.%lu advertised\n",
+		RSI_ABI_VERSION_GET_MAJOR(ver),
+		RSI_ABI_VERSION_GET_MINOR(ver));
+
+	return (ver >= RSI_ABI_VERSION &&
+		RSI_ABI_VERSION_GET_MAJOR(ver) == RSI_ABI_VERSION_MAJOR);
+}
+
+void arm64_setup_memory(void)
+{
+	u64 i;
+	phys_addr_t start, end;
+
+	if (!static_branch_unlikely(&rsi_present))
+		return;
+
+	/*
+	 * Iterate over the available memory ranges
+	 * and convert the state to protected memory.
+	 */
+	for_each_mem_range(i, &start, &end) {
+		set_memory_range_protected(start, end);
+	}
+}
+
+void __init arm64_rsi_init(void)
+{
+	if (!rsi_version_matches())
+		return;
+
+	static_branch_enable(&rsi_present);
+}
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 12cfe9d0d3fa..ea89ee563135 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -43,6 +43,7 @@
 #include <asm/cpu_ops.h>
 #include <asm/kasan.h>
 #include <asm/numa.h>
+#include <asm/rsi.h>
 #include <asm/scs.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
@@ -312,6 +313,8 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
 	 * cpufeature code and early parameters.
 	 */
 	jump_label_init();
+	/* Init RSI after jump_labels are active */
+	arm64_rsi_init();
 	parse_early_param();
 
 	dynamic_scs_init();
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 58a0bb2c17f1..fa9088add624 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -39,6 +39,7 @@
 #include <asm/kvm_host.h>
 #include <asm/memory.h>
 #include <asm/numa.h>
+#include <asm/rsi.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <linux/sizes.h>
@@ -412,6 +413,7 @@ void __init arm64_memblock_init(void)
 		reserve_crashkernel();
 
 	high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
+	arm64_setup_memory();
 }
 
 void __init bootmem_init(void)
-- 
2.34.1


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

* [RFC PATCH 03/14] arm64: Detect if in a realm and set RIPAS RAM
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Detect that the VM is a realm guest by the presence of the RSI
interface.

If in a realm then all memory needs to be marked as RIPAS RAM initially,
the loader may or may not have done this for us. To be sure iterate over
all RAM and mark it as such. Any failure is fatal as that implies the
RAM regions passed to Linux are incorrect - which would mean failing
later when attempting to access non-existent RAM.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rsi.h      | 46 ++++++++++++++++++++++++++++
 arch/arm64/include/asm/rsi_cmds.h | 12 ++++++--
 arch/arm64/kernel/Makefile        |  2 +-
 arch/arm64/kernel/rsi.c           | 50 +++++++++++++++++++++++++++++++
 arch/arm64/kernel/setup.c         |  3 ++
 arch/arm64/mm/init.c              |  2 ++
 6 files changed, 111 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/rsi.h
 create mode 100644 arch/arm64/kernel/rsi.c

diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
new file mode 100644
index 000000000000..3b56aac5dc43
--- /dev/null
+++ b/arch/arm64/include/asm/rsi.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RSI_H_
+#define __ASM_RSI_H_
+
+#include <linux/jump_label.h>
+#include <asm/rsi_cmds.h>
+
+extern struct static_key_false rsi_present;
+
+void arm64_setup_memory(void);
+
+void __init arm64_rsi_init(void);
+static inline bool is_realm_world(void)
+{
+	return static_branch_unlikely(&rsi_present);
+}
+
+static inline void set_memory_range(phys_addr_t start, phys_addr_t end,
+				    enum ripas state)
+{
+	unsigned long ret;
+	phys_addr_t top;
+
+	while (start != end) {
+		ret = rsi_set_addr_range_state(start, end, state, &top);
+		BUG_ON(ret);
+		BUG_ON(top < start);
+		BUG_ON(top > end);
+		start = top;
+	}
+}
+
+static inline void set_memory_range_protected(phys_addr_t start, phys_addr_t end)
+{
+	set_memory_range(start, end, RSI_RIPAS_RAM);
+}
+
+static inline void set_memory_range_shared(phys_addr_t start, phys_addr_t end)
+{
+	set_memory_range(start, end, RSI_RIPAS_EMPTY);
+}
+#endif
diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
index a0b3c1bd786a..ee0df00efd87 100644
--- a/arch/arm64/include/asm/rsi_cmds.h
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -48,10 +48,16 @@ static inline void invoke_rsi_fn_smc_with_res(unsigned long function_id,
 
 static inline unsigned long rsi_set_addr_range_state(phys_addr_t start,
 						     phys_addr_t end,
-						     enum ripas state)
+						     enum ripas state,
+						     phys_addr_t *top)
 {
-	return invoke_rsi_fn_smc(SMC_RSI_IPA_STATE_SET,
-				 start, (end - start), state, 0);
+	struct arm_smccc_res res;
+
+	invoke_rsi_fn_smc_with_res(SMC_RSI_IPA_STATE_SET,
+				   start, (end - start), state, 0, &res);
+
+	*top = res.a1;
+	return res.a0;
 }
 
 #endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index ceba6792f5b3..f301c2ad2fa7 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -34,7 +34,7 @@ obj-y			:= debug-monitors.o entry.o irq.o fpsimd.o		\
 			   cpufeature.o alternative.o cacheinfo.o		\
 			   smp.o smp_spin_table.o topology.o smccc-call.o	\
 			   syscall.o proton-pack.o idreg-override.o idle.o	\
-			   patching.o
+			   patching.o rsi.o
 
 obj-$(CONFIG_COMPAT)			+= sys32.o signal32.o			\
 					   sys_compat.o
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
new file mode 100644
index 000000000000..b354ac661c9d
--- /dev/null
+++ b/arch/arm64/kernel/rsi.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#include <linux/jump_label.h>
+#include <linux/memblock.h>
+#include <asm/rsi.h>
+
+DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
+
+static bool rsi_version_matches(void)
+{
+	unsigned long ver = rsi_get_version();
+
+	if (ver == SMCCC_RET_NOT_SUPPORTED)
+		return false;
+
+	pr_info("RME: RSI version %lu.%lu advertised\n",
+		RSI_ABI_VERSION_GET_MAJOR(ver),
+		RSI_ABI_VERSION_GET_MINOR(ver));
+
+	return (ver >= RSI_ABI_VERSION &&
+		RSI_ABI_VERSION_GET_MAJOR(ver) == RSI_ABI_VERSION_MAJOR);
+}
+
+void arm64_setup_memory(void)
+{
+	u64 i;
+	phys_addr_t start, end;
+
+	if (!static_branch_unlikely(&rsi_present))
+		return;
+
+	/*
+	 * Iterate over the available memory ranges
+	 * and convert the state to protected memory.
+	 */
+	for_each_mem_range(i, &start, &end) {
+		set_memory_range_protected(start, end);
+	}
+}
+
+void __init arm64_rsi_init(void)
+{
+	if (!rsi_version_matches())
+		return;
+
+	static_branch_enable(&rsi_present);
+}
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 12cfe9d0d3fa..ea89ee563135 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -43,6 +43,7 @@
 #include <asm/cpu_ops.h>
 #include <asm/kasan.h>
 #include <asm/numa.h>
+#include <asm/rsi.h>
 #include <asm/scs.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
@@ -312,6 +313,8 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
 	 * cpufeature code and early parameters.
 	 */
 	jump_label_init();
+	/* Init RSI after jump_labels are active */
+	arm64_rsi_init();
 	parse_early_param();
 
 	dynamic_scs_init();
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 58a0bb2c17f1..fa9088add624 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -39,6 +39,7 @@
 #include <asm/kvm_host.h>
 #include <asm/memory.h>
 #include <asm/numa.h>
+#include <asm/rsi.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <linux/sizes.h>
@@ -412,6 +413,7 @@ void __init arm64_memblock_init(void)
 		reserve_crashkernel();
 
 	high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
+	arm64_setup_memory();
 }
 
 void __init bootmem_init(void)
-- 
2.34.1


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

* [RFC PATCH 04/14] arm64: realm: Query IPA size from the RMM
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The top bit of the configured IPA size is used as an attribute to
control whether the address is protected or shared. Query the
configuration from the RMM to assertain which bit this is.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/pgtable-prot.h | 2 ++
 arch/arm64/include/asm/rsi_cmds.h     | 8 ++++++++
 arch/arm64/kernel/rsi.c               | 8 ++++++++
 3 files changed, 18 insertions(+)

diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 9b165117a454..3f24080d6cc9 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -33,7 +33,9 @@
 #include <asm/pgtable-types.h>
 
 extern bool arm64_use_ng_mappings;
+extern unsigned long prot_ns_shared;
 
+#define PROT_NS_SHARED		((prot_ns_shared))
 #define _PROT_DEFAULT		(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
 #define _PROT_SECT_DEFAULT	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
index ee0df00efd87..e13f702de6c2 100644
--- a/arch/arm64/include/asm/rsi_cmds.h
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -46,6 +46,14 @@ static inline void invoke_rsi_fn_smc_with_res(unsigned long function_id,
 	arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, 0, 0, 0, res);
 }
 
+static inline unsigned long rsi_get_realm_config(struct realm_config *cfg)
+{
+	struct arm_smccc_res res;
+
+	invoke_rsi_fn_smc_with_res(SMC_RSI_REALM_CONFIG, virt_to_phys(cfg), 0, 0, 0, &res);
+	return res.a0;
+}
+
 static inline unsigned long rsi_set_addr_range_state(phys_addr_t start,
 						     phys_addr_t end,
 						     enum ripas state,
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index b354ac661c9d..9c63ee1c6979 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -7,6 +7,11 @@
 #include <linux/memblock.h>
 #include <asm/rsi.h>
 
+struct realm_config __attribute((aligned(PAGE_SIZE))) config;
+
+unsigned long prot_ns_shared;
+EXPORT_SYMBOL(prot_ns_shared);
+
 DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
 
 static bool rsi_version_matches(void)
@@ -45,6 +50,9 @@ void __init arm64_rsi_init(void)
 {
 	if (!rsi_version_matches())
 		return;
+	if (rsi_get_realm_config(&config))
+		return;
+	prot_ns_shared = BIT(config.ipa_bits - 1);
 
 	static_branch_enable(&rsi_present);
 }
-- 
2.34.1


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

* [RFC PATCH 04/14] arm64: realm: Query IPA size from the RMM
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The top bit of the configured IPA size is used as an attribute to
control whether the address is protected or shared. Query the
configuration from the RMM to assertain which bit this is.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/pgtable-prot.h | 2 ++
 arch/arm64/include/asm/rsi_cmds.h     | 8 ++++++++
 arch/arm64/kernel/rsi.c               | 8 ++++++++
 3 files changed, 18 insertions(+)

diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 9b165117a454..3f24080d6cc9 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -33,7 +33,9 @@
 #include <asm/pgtable-types.h>
 
 extern bool arm64_use_ng_mappings;
+extern unsigned long prot_ns_shared;
 
+#define PROT_NS_SHARED		((prot_ns_shared))
 #define _PROT_DEFAULT		(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
 #define _PROT_SECT_DEFAULT	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
index ee0df00efd87..e13f702de6c2 100644
--- a/arch/arm64/include/asm/rsi_cmds.h
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -46,6 +46,14 @@ static inline void invoke_rsi_fn_smc_with_res(unsigned long function_id,
 	arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, 0, 0, 0, res);
 }
 
+static inline unsigned long rsi_get_realm_config(struct realm_config *cfg)
+{
+	struct arm_smccc_res res;
+
+	invoke_rsi_fn_smc_with_res(SMC_RSI_REALM_CONFIG, virt_to_phys(cfg), 0, 0, 0, &res);
+	return res.a0;
+}
+
 static inline unsigned long rsi_set_addr_range_state(phys_addr_t start,
 						     phys_addr_t end,
 						     enum ripas state,
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index b354ac661c9d..9c63ee1c6979 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -7,6 +7,11 @@
 #include <linux/memblock.h>
 #include <asm/rsi.h>
 
+struct realm_config __attribute((aligned(PAGE_SIZE))) config;
+
+unsigned long prot_ns_shared;
+EXPORT_SYMBOL(prot_ns_shared);
+
 DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
 
 static bool rsi_version_matches(void)
@@ -45,6 +50,9 @@ void __init arm64_rsi_init(void)
 {
 	if (!rsi_version_matches())
 		return;
+	if (rsi_get_realm_config(&config))
+		return;
+	prot_ns_shared = BIT(config.ipa_bits - 1);
 
 	static_branch_enable(&rsi_present);
 }
-- 
2.34.1


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

* [RFC PATCH 05/14] arm64: Mark all I/O as non-secure shared
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

All I/O is by default considered non-secure for realms. As such
mark them as shared with the host.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/io.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 877495a0fd0c..b1a9c22aed72 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -142,12 +142,12 @@ extern void __memset_io(volatile void __iomem *, int, size_t);
 bool ioremap_allowed(phys_addr_t phys_addr, size_t size, unsigned long prot);
 #define ioremap_allowed ioremap_allowed
 
-#define _PAGE_IOREMAP PROT_DEVICE_nGnRE
+#define _PAGE_IOREMAP (PROT_DEVICE_nGnRE | PROT_NS_SHARED)
 
 #define ioremap_wc(addr, size)	\
-	ioremap_prot((addr), (size), PROT_NORMAL_NC)
+	ioremap_prot((addr), (size), (PROT_NORMAL_NC | PROT_NS_SHARED))
 #define ioremap_np(addr, size)	\
-	ioremap_prot((addr), (size), PROT_DEVICE_nGnRnE)
+	ioremap_prot((addr), (size), (PROT_DEVICE_nGnRnE | PROT_NS_SHARED))
 
 /*
  * io{read,write}{16,32,64}be() macros
-- 
2.34.1


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

* [RFC PATCH 05/14] arm64: Mark all I/O as non-secure shared
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

All I/O is by default considered non-secure for realms. As such
mark them as shared with the host.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/io.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 877495a0fd0c..b1a9c22aed72 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -142,12 +142,12 @@ extern void __memset_io(volatile void __iomem *, int, size_t);
 bool ioremap_allowed(phys_addr_t phys_addr, size_t size, unsigned long prot);
 #define ioremap_allowed ioremap_allowed
 
-#define _PAGE_IOREMAP PROT_DEVICE_nGnRE
+#define _PAGE_IOREMAP (PROT_DEVICE_nGnRE | PROT_NS_SHARED)
 
 #define ioremap_wc(addr, size)	\
-	ioremap_prot((addr), (size), PROT_NORMAL_NC)
+	ioremap_prot((addr), (size), (PROT_NORMAL_NC | PROT_NS_SHARED))
 #define ioremap_np(addr, size)	\
-	ioremap_prot((addr), (size), PROT_DEVICE_nGnRnE)
+	ioremap_prot((addr), (size), (PROT_DEVICE_nGnRnE | PROT_NS_SHARED))
 
 /*
  * io{read,write}{16,32,64}be() macros
-- 
2.34.1


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

* [RFC PATCH 06/14] fixmap: Allow architecture overriding set_fixmap_io
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

For a realm guest it will be necessary to ensure IO mappings are shared
so that the VMM can emulate the device. The following patch will provide
an implementation of set_fixmap_io for arm64 setting the shared bit (if
in a realm).

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 include/asm-generic/fixmap.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/asm-generic/fixmap.h b/include/asm-generic/fixmap.h
index 8cc7b09c1bc7..c5ce0368c1ee 100644
--- a/include/asm-generic/fixmap.h
+++ b/include/asm-generic/fixmap.h
@@ -94,8 +94,10 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
 /*
  * Some fixmaps are for IO
  */
+#ifndef set_fixmap_io
 #define set_fixmap_io(idx, phys) \
 	__set_fixmap(idx, phys, FIXMAP_PAGE_IO)
+#endif
 
 #define set_fixmap_offset_io(idx, phys) \
 	__set_fixmap_offset(idx, phys, FIXMAP_PAGE_IO)
-- 
2.34.1


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

* [RFC PATCH 06/14] fixmap: Allow architecture overriding set_fixmap_io
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

For a realm guest it will be necessary to ensure IO mappings are shared
so that the VMM can emulate the device. The following patch will provide
an implementation of set_fixmap_io for arm64 setting the shared bit (if
in a realm).

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 include/asm-generic/fixmap.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/asm-generic/fixmap.h b/include/asm-generic/fixmap.h
index 8cc7b09c1bc7..c5ce0368c1ee 100644
--- a/include/asm-generic/fixmap.h
+++ b/include/asm-generic/fixmap.h
@@ -94,8 +94,10 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
 /*
  * Some fixmaps are for IO
  */
+#ifndef set_fixmap_io
 #define set_fixmap_io(idx, phys) \
 	__set_fixmap(idx, phys, FIXMAP_PAGE_IO)
+#endif
 
 #define set_fixmap_offset_io(idx, phys) \
 	__set_fixmap_offset(idx, phys, FIXMAP_PAGE_IO)
-- 
2.34.1


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

* [RFC PATCH 07/14] arm64: Override set_fixmap_io
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

Override the set_fixmap_io to set shared permission for the host
in case of a CC guest. For now we mark it shared unconditionally.
Future changes could filter the physical address and make the
decision accordingly.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/fixmap.h |  2 ++
 arch/arm64/mm/mmu.c             | 13 +++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 09ba9fe3b02c..1acafc1c7fae 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -107,6 +107,8 @@ void __init early_fixmap_init(void);
 #define __late_set_fixmap __set_fixmap
 #define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
 
+#define set_fixmap_io set_fixmap_io
+void set_fixmap_io(enum fixed_addresses idx, phys_addr_t phys);
 void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
 
 #include <asm-generic/fixmap.h>
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 14c87e8d69d8..33fda73c669b 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1279,6 +1279,19 @@ void __set_fixmap(enum fixed_addresses idx,
 	}
 }
 
+void set_fixmap_io(enum fixed_addresses idx, phys_addr_t phys)
+{
+	pgprot_t prot = FIXMAP_PAGE_IO;
+
+	/*
+	 * For now we consider all I/O as non-secure. For future
+	 * filter the I/O base for setting appropriate permissions.
+	 */
+	prot = __pgprot(pgprot_val(prot) | PROT_NS_SHARED);
+
+	return __set_fixmap(idx, phys, prot);
+}
+
 void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
 {
 	const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
-- 
2.34.1


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

* [RFC PATCH 07/14] arm64: Override set_fixmap_io
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

Override the set_fixmap_io to set shared permission for the host
in case of a CC guest. For now we mark it shared unconditionally.
Future changes could filter the physical address and make the
decision accordingly.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/fixmap.h |  2 ++
 arch/arm64/mm/mmu.c             | 13 +++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 09ba9fe3b02c..1acafc1c7fae 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -107,6 +107,8 @@ void __init early_fixmap_init(void);
 #define __late_set_fixmap __set_fixmap
 #define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
 
+#define set_fixmap_io set_fixmap_io
+void set_fixmap_io(enum fixed_addresses idx, phys_addr_t phys);
 void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
 
 #include <asm-generic/fixmap.h>
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 14c87e8d69d8..33fda73c669b 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1279,6 +1279,19 @@ void __set_fixmap(enum fixed_addresses idx,
 	}
 }
 
+void set_fixmap_io(enum fixed_addresses idx, phys_addr_t phys)
+{
+	pgprot_t prot = FIXMAP_PAGE_IO;
+
+	/*
+	 * For now we consider all I/O as non-secure. For future
+	 * filter the I/O base for setting appropriate permissions.
+	 */
+	prot = __pgprot(pgprot_val(prot) | PROT_NS_SHARED);
+
+	return __set_fixmap(idx, phys, prot);
+}
+
 void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
 {
 	const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
-- 
2.34.1


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

* [RFC PATCH 08/14] arm64: Make the PHYS_MASK_SHIFT dynamic
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Make the PHYS_MASK_SHIFT dynamic for Realms. This is only is required
for masking the PFN from a pte entry. Elsewhere, we could still use the
PA bits configured by the kernel. So, this patch:

 -> renames PHYS_MASK_SHIFT -> MAX_PHYS_SHIFT as supported by the kernel
 -> Makes PHYS_MASK_SHIFT -> Dynamic value of the (I)PA bit width
 -> For a realm: reduces phys_mask_shift if the RMM reports a smaller
    configured size for the guest.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_arm.h       | 2 +-
 arch/arm64/include/asm/pgtable-hwdef.h | 4 ++--
 arch/arm64/include/asm/pgtable.h       | 5 +++++
 arch/arm64/kernel/head.S               | 2 +-
 arch/arm64/kernel/rsi.c                | 5 +++++
 5 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 0df3fc3a0173..924f84024009 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -346,7 +346,7 @@
  * bits in PAR are res0.
  */
 #define PAR_TO_HPFAR(par)		\
-	(((par) & GENMASK_ULL(52 - 1, 12)) >> 8)
+	(((par) & GENMASK_ULL(MAX_PHYS_MASK_SHIFT - 1, 12)) >> 8)
 
 #define ECN(x) { ESR_ELx_EC_##x, #x }
 
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index f658aafc47df..677bf7a91616 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -178,8 +178,8 @@
 /*
  * Highest possible physical address supported.
  */
-#define PHYS_MASK_SHIFT		(CONFIG_ARM64_PA_BITS)
-#define PHYS_MASK		((UL(1) << PHYS_MASK_SHIFT) - 1)
+#define MAX_PHYS_MASK_SHIFT	(CONFIG_ARM64_PA_BITS)
+#define MAX_PHYS_MASK		((UL(1) << PHYS_MASK_SHIFT) - 1)
 
 #define TTBR_CNP_BIT		(UL(1) << 0)
 
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index b4bbeed80fb6..a1319a743b38 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -35,6 +35,11 @@
 #include <linux/sched.h>
 #include <linux/page_table_check.h>
 
+extern unsigned int phys_mask_shift;
+
+#define PHYS_MASK_SHIFT		(phys_mask_shift)
+#define PHYS_MASK		((1UL << PHYS_MASK_SHIFT) - 1)
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
 
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 952e17bd1c0b..a05504667b69 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -321,7 +321,7 @@ SYM_FUNC_START_LOCAL(create_idmap)
 #error "Mismatch between VA_BITS and page size/number of translation levels"
 #endif
 #else
-#define IDMAP_PGD_ORDER	(PHYS_MASK_SHIFT - PGDIR_SHIFT)
+#define IDMAP_PGD_ORDER	(MAX_PHYS_MASK_SHIFT - PGDIR_SHIFT)
 #define EXTRA_SHIFT
 	/*
 	 * If VA_BITS == 48, we don't have to configure an additional
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 9c63ee1c6979..49d36dfe0064 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -12,6 +12,8 @@ struct realm_config __attribute((aligned(PAGE_SIZE))) config;
 unsigned long prot_ns_shared;
 EXPORT_SYMBOL(prot_ns_shared);
 
+unsigned int phys_mask_shift = CONFIG_ARM64_PA_BITS;
+
 DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
 
 static bool rsi_version_matches(void)
@@ -54,5 +56,8 @@ void __init arm64_rsi_init(void)
 		return;
 	prot_ns_shared = BIT(config.ipa_bits - 1);
 
+	if (config.ipa_bits - 1 < phys_mask_shift)
+		phys_mask_shift = config.ipa_bits - 1;
+
 	static_branch_enable(&rsi_present);
 }
-- 
2.34.1


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

* [RFC PATCH 08/14] arm64: Make the PHYS_MASK_SHIFT dynamic
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Make the PHYS_MASK_SHIFT dynamic for Realms. This is only is required
for masking the PFN from a pte entry. Elsewhere, we could still use the
PA bits configured by the kernel. So, this patch:

 -> renames PHYS_MASK_SHIFT -> MAX_PHYS_SHIFT as supported by the kernel
 -> Makes PHYS_MASK_SHIFT -> Dynamic value of the (I)PA bit width
 -> For a realm: reduces phys_mask_shift if the RMM reports a smaller
    configured size for the guest.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_arm.h       | 2 +-
 arch/arm64/include/asm/pgtable-hwdef.h | 4 ++--
 arch/arm64/include/asm/pgtable.h       | 5 +++++
 arch/arm64/kernel/head.S               | 2 +-
 arch/arm64/kernel/rsi.c                | 5 +++++
 5 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 0df3fc3a0173..924f84024009 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -346,7 +346,7 @@
  * bits in PAR are res0.
  */
 #define PAR_TO_HPFAR(par)		\
-	(((par) & GENMASK_ULL(52 - 1, 12)) >> 8)
+	(((par) & GENMASK_ULL(MAX_PHYS_MASK_SHIFT - 1, 12)) >> 8)
 
 #define ECN(x) { ESR_ELx_EC_##x, #x }
 
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index f658aafc47df..677bf7a91616 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -178,8 +178,8 @@
 /*
  * Highest possible physical address supported.
  */
-#define PHYS_MASK_SHIFT		(CONFIG_ARM64_PA_BITS)
-#define PHYS_MASK		((UL(1) << PHYS_MASK_SHIFT) - 1)
+#define MAX_PHYS_MASK_SHIFT	(CONFIG_ARM64_PA_BITS)
+#define MAX_PHYS_MASK		((UL(1) << PHYS_MASK_SHIFT) - 1)
 
 #define TTBR_CNP_BIT		(UL(1) << 0)
 
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index b4bbeed80fb6..a1319a743b38 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -35,6 +35,11 @@
 #include <linux/sched.h>
 #include <linux/page_table_check.h>
 
+extern unsigned int phys_mask_shift;
+
+#define PHYS_MASK_SHIFT		(phys_mask_shift)
+#define PHYS_MASK		((1UL << PHYS_MASK_SHIFT) - 1)
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
 
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 952e17bd1c0b..a05504667b69 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -321,7 +321,7 @@ SYM_FUNC_START_LOCAL(create_idmap)
 #error "Mismatch between VA_BITS and page size/number of translation levels"
 #endif
 #else
-#define IDMAP_PGD_ORDER	(PHYS_MASK_SHIFT - PGDIR_SHIFT)
+#define IDMAP_PGD_ORDER	(MAX_PHYS_MASK_SHIFT - PGDIR_SHIFT)
 #define EXTRA_SHIFT
 	/*
 	 * If VA_BITS == 48, we don't have to configure an additional
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 9c63ee1c6979..49d36dfe0064 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -12,6 +12,8 @@ struct realm_config __attribute((aligned(PAGE_SIZE))) config;
 unsigned long prot_ns_shared;
 EXPORT_SYMBOL(prot_ns_shared);
 
+unsigned int phys_mask_shift = CONFIG_ARM64_PA_BITS;
+
 DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
 
 static bool rsi_version_matches(void)
@@ -54,5 +56,8 @@ void __init arm64_rsi_init(void)
 		return;
 	prot_ns_shared = BIT(config.ipa_bits - 1);
 
+	if (config.ipa_bits - 1 < phys_mask_shift)
+		phys_mask_shift = config.ipa_bits - 1;
+
 	static_branch_enable(&rsi_present);
 }
-- 
2.34.1


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

* [RFC PATCH 09/14] arm64: Enforce bounce buffers for realm DMA
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Within a realm guest it's not possible for a device emulated by the VMM
to access arbitrary guest memory. So force the use of bounce buffers to
ensure that the memory the emulated devices are accessing is in memory
which is explicitly shared with the host.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kernel/rsi.c | 2 ++
 arch/arm64/mm/init.c    | 8 +++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 49d36dfe0064..1a07eefdd2e9 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -5,6 +5,8 @@
 
 #include <linux/jump_label.h>
 #include <linux/memblock.h>
+#include <linux/swiotlb.h>
+
 #include <asm/rsi.h>
 
 struct realm_config __attribute((aligned(PAGE_SIZE))) config;
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index fa9088add624..32a4710ad861 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -472,7 +472,13 @@ void __init bootmem_init(void)
  */
 void __init mem_init(void)
 {
-	swiotlb_init(max_pfn > PFN_DOWN(arm64_dma_phys_limit), SWIOTLB_VERBOSE);
+	if (is_realm_world()) {
+		swiotlb_init(true, SWIOTLB_VERBOSE | SWIOTLB_FORCE);
+		swiotlb_update_mem_attributes();
+	} else {
+		swiotlb_init(max_pfn > PFN_DOWN(arm64_dma_phys_limit),
+			     SWIOTLB_VERBOSE);
+	}
 
 	/* this will put all unused low memory onto the freelists */
 	memblock_free_all();
-- 
2.34.1


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

* [RFC PATCH 09/14] arm64: Enforce bounce buffers for realm DMA
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Within a realm guest it's not possible for a device emulated by the VMM
to access arbitrary guest memory. So force the use of bounce buffers to
ensure that the memory the emulated devices are accessing is in memory
which is explicitly shared with the host.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kernel/rsi.c | 2 ++
 arch/arm64/mm/init.c    | 8 +++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 49d36dfe0064..1a07eefdd2e9 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -5,6 +5,8 @@
 
 #include <linux/jump_label.h>
 #include <linux/memblock.h>
+#include <linux/swiotlb.h>
+
 #include <asm/rsi.h>
 
 struct realm_config __attribute((aligned(PAGE_SIZE))) config;
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index fa9088add624..32a4710ad861 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -472,7 +472,13 @@ void __init bootmem_init(void)
  */
 void __init mem_init(void)
 {
-	swiotlb_init(max_pfn > PFN_DOWN(arm64_dma_phys_limit), SWIOTLB_VERBOSE);
+	if (is_realm_world()) {
+		swiotlb_init(true, SWIOTLB_VERBOSE | SWIOTLB_FORCE);
+		swiotlb_update_mem_attributes();
+	} else {
+		swiotlb_init(max_pfn > PFN_DOWN(arm64_dma_phys_limit),
+			     SWIOTLB_VERBOSE);
+	}
 
 	/* this will put all unused low memory onto the freelists */
 	memblock_free_all();
-- 
2.34.1


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

* [RFC PATCH 10/14] arm64: Enable memory encrypt for Realms
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Use the memory encryption APIs to trigger a RSI call to request a
transition between protected memory and shared memory (or vice versa)
and updating the kernel's linear map of modified pages to flip the top
bit of the IPA. This requires that block mappings are not used in the
direct map for realm guests.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/Kconfig                   |  3 ++
 arch/arm64/include/asm/mem_encrypt.h | 19 +++++++++++
 arch/arm64/kernel/rsi.c              | 12 +++++++
 arch/arm64/mm/pageattr.c             | 48 +++++++++++++++++++++++++---
 4 files changed, 78 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/mem_encrypt.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 03934808b2ed..0aac44a993ac 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -20,6 +20,7 @@ config ARM64
 	select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
 	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
 	select ARCH_HAS_CACHE_LINE_SIZE
+	select ARCH_HAS_CC_PLATFORM
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DEBUG_VIRTUAL
 	select ARCH_HAS_DEBUG_VM_PGTABLE
@@ -39,6 +40,8 @@ config ARM64
 	select ARCH_HAS_SETUP_DMA_OPS
 	select ARCH_HAS_SET_DIRECT_MAP
 	select ARCH_HAS_SET_MEMORY
+	select ARCH_HAS_MEM_ENCRYPT
+	select ARCH_HAS_FORCE_DMA_UNENCRYPTED
 	select ARCH_STACKWALK
 	select ARCH_HAS_STRICT_KERNEL_RWX
 	select ARCH_HAS_STRICT_MODULE_RWX
diff --git a/arch/arm64/include/asm/mem_encrypt.h b/arch/arm64/include/asm/mem_encrypt.h
new file mode 100644
index 000000000000..7381f9585321
--- /dev/null
+++ b/arch/arm64/include/asm/mem_encrypt.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_MEM_ENCRYPT_H
+#define __ASM_MEM_ENCRYPT_H
+
+#include <asm/rsi.h>
+
+/* All DMA must be to non-secure memory for now */
+static inline bool force_dma_unencrypted(struct device *dev)
+{
+	return is_realm_world();
+}
+
+int set_memory_encrypted(unsigned long addr, int numpages);
+int set_memory_decrypted(unsigned long addr, int numpages);
+#endif
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 1a07eefdd2e9..1cc292826f2b 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -6,6 +6,7 @@
 #include <linux/jump_label.h>
 #include <linux/memblock.h>
 #include <linux/swiotlb.h>
+#include <linux/cc_platform.h>
 
 #include <asm/rsi.h>
 
@@ -18,6 +19,17 @@ unsigned int phys_mask_shift = CONFIG_ARM64_PA_BITS;
 
 DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
 
+bool cc_platform_has(enum cc_attr attr)
+{
+	switch (attr) {
+	case CC_ATTR_MEM_ENCRYPT:
+		return is_realm_world();
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL_GPL(cc_platform_has);
+
 static bool rsi_version_matches(void)
 {
 	unsigned long ver = rsi_get_version();
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index 79dd201c59d8..bbd7364dd9a8 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -5,10 +5,12 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/mem_encrypt.h>
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
 
 #include <asm/cacheflush.h>
+#include <asm/pgtable-prot.h>
 #include <asm/set_memory.h>
 #include <asm/tlbflush.h>
 
@@ -22,12 +24,12 @@ bool rodata_full __ro_after_init = IS_ENABLED(CONFIG_RODATA_FULL_DEFAULT_ENABLED
 bool can_set_direct_map(void)
 {
 	/*
-	 * rodata_full, DEBUG_PAGEALLOC and KFENCE require linear map to be
-	 * mapped at page granularity, so that it is possible to
-	 * protect/unprotect single pages.
+	 * rodata_full, DEBUG_PAGEALLOC, KFENCE and a Realm guest all require
+	 * linear map to be mapped at page granularity, so that it is possible
+	 * to protect/unprotect single pages.
 	 */
 	return (rodata_enabled && rodata_full) || debug_pagealloc_enabled() ||
-		IS_ENABLED(CONFIG_KFENCE);
+		IS_ENABLED(CONFIG_KFENCE) || is_realm_world();
 }
 
 static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
@@ -38,6 +40,7 @@ static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
 	pte = clear_pte_bit(pte, cdata->clear_mask);
 	pte = set_pte_bit(pte, cdata->set_mask);
 
+	/* TODO: Break before make for PROT_NS_SHARED updates */
 	set_pte(ptep, pte);
 	return 0;
 }
@@ -190,6 +193,43 @@ int set_direct_map_default_noflush(struct page *page)
 				   PAGE_SIZE, change_page_range, &data);
 }
 
+static int __set_memory_encrypted(unsigned long addr,
+				  int numpages,
+				  bool encrypt)
+{
+	unsigned long set_prot = 0, clear_prot = 0;
+	phys_addr_t start, end;
+
+	if (!is_realm_world())
+		return 0;
+
+	WARN_ON(!__is_lm_address(addr));
+	start = __virt_to_phys(addr);
+	end = start + numpages * PAGE_SIZE;
+
+	if (encrypt) {
+		clear_prot = PROT_NS_SHARED;
+		set_memory_range_protected(start, end);
+	} else {
+		set_prot = PROT_NS_SHARED;
+		set_memory_range_shared(start, end);
+	}
+
+	return __change_memory_common(addr, PAGE_SIZE * numpages,
+				      __pgprot(set_prot),
+				      __pgprot(clear_prot));
+}
+
+int set_memory_encrypted(unsigned long addr, int numpages)
+{
+	return __set_memory_encrypted(addr, numpages, true);
+}
+
+int set_memory_decrypted(unsigned long addr, int numpages)
+{
+	return __set_memory_encrypted(addr, numpages, false);
+}
+
 #ifdef CONFIG_DEBUG_PAGEALLOC
 void __kernel_map_pages(struct page *page, int numpages, int enable)
 {
-- 
2.34.1


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

* [RFC PATCH 10/14] arm64: Enable memory encrypt for Realms
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Use the memory encryption APIs to trigger a RSI call to request a
transition between protected memory and shared memory (or vice versa)
and updating the kernel's linear map of modified pages to flip the top
bit of the IPA. This requires that block mappings are not used in the
direct map for realm guests.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/Kconfig                   |  3 ++
 arch/arm64/include/asm/mem_encrypt.h | 19 +++++++++++
 arch/arm64/kernel/rsi.c              | 12 +++++++
 arch/arm64/mm/pageattr.c             | 48 +++++++++++++++++++++++++---
 4 files changed, 78 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/mem_encrypt.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 03934808b2ed..0aac44a993ac 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -20,6 +20,7 @@ config ARM64
 	select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
 	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
 	select ARCH_HAS_CACHE_LINE_SIZE
+	select ARCH_HAS_CC_PLATFORM
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DEBUG_VIRTUAL
 	select ARCH_HAS_DEBUG_VM_PGTABLE
@@ -39,6 +40,8 @@ config ARM64
 	select ARCH_HAS_SETUP_DMA_OPS
 	select ARCH_HAS_SET_DIRECT_MAP
 	select ARCH_HAS_SET_MEMORY
+	select ARCH_HAS_MEM_ENCRYPT
+	select ARCH_HAS_FORCE_DMA_UNENCRYPTED
 	select ARCH_STACKWALK
 	select ARCH_HAS_STRICT_KERNEL_RWX
 	select ARCH_HAS_STRICT_MODULE_RWX
diff --git a/arch/arm64/include/asm/mem_encrypt.h b/arch/arm64/include/asm/mem_encrypt.h
new file mode 100644
index 000000000000..7381f9585321
--- /dev/null
+++ b/arch/arm64/include/asm/mem_encrypt.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_MEM_ENCRYPT_H
+#define __ASM_MEM_ENCRYPT_H
+
+#include <asm/rsi.h>
+
+/* All DMA must be to non-secure memory for now */
+static inline bool force_dma_unencrypted(struct device *dev)
+{
+	return is_realm_world();
+}
+
+int set_memory_encrypted(unsigned long addr, int numpages);
+int set_memory_decrypted(unsigned long addr, int numpages);
+#endif
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 1a07eefdd2e9..1cc292826f2b 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -6,6 +6,7 @@
 #include <linux/jump_label.h>
 #include <linux/memblock.h>
 #include <linux/swiotlb.h>
+#include <linux/cc_platform.h>
 
 #include <asm/rsi.h>
 
@@ -18,6 +19,17 @@ unsigned int phys_mask_shift = CONFIG_ARM64_PA_BITS;
 
 DEFINE_STATIC_KEY_FALSE_RO(rsi_present);
 
+bool cc_platform_has(enum cc_attr attr)
+{
+	switch (attr) {
+	case CC_ATTR_MEM_ENCRYPT:
+		return is_realm_world();
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL_GPL(cc_platform_has);
+
 static bool rsi_version_matches(void)
 {
 	unsigned long ver = rsi_get_version();
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index 79dd201c59d8..bbd7364dd9a8 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -5,10 +5,12 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/mem_encrypt.h>
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
 
 #include <asm/cacheflush.h>
+#include <asm/pgtable-prot.h>
 #include <asm/set_memory.h>
 #include <asm/tlbflush.h>
 
@@ -22,12 +24,12 @@ bool rodata_full __ro_after_init = IS_ENABLED(CONFIG_RODATA_FULL_DEFAULT_ENABLED
 bool can_set_direct_map(void)
 {
 	/*
-	 * rodata_full, DEBUG_PAGEALLOC and KFENCE require linear map to be
-	 * mapped at page granularity, so that it is possible to
-	 * protect/unprotect single pages.
+	 * rodata_full, DEBUG_PAGEALLOC, KFENCE and a Realm guest all require
+	 * linear map to be mapped at page granularity, so that it is possible
+	 * to protect/unprotect single pages.
 	 */
 	return (rodata_enabled && rodata_full) || debug_pagealloc_enabled() ||
-		IS_ENABLED(CONFIG_KFENCE);
+		IS_ENABLED(CONFIG_KFENCE) || is_realm_world();
 }
 
 static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
@@ -38,6 +40,7 @@ static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
 	pte = clear_pte_bit(pte, cdata->clear_mask);
 	pte = set_pte_bit(pte, cdata->set_mask);
 
+	/* TODO: Break before make for PROT_NS_SHARED updates */
 	set_pte(ptep, pte);
 	return 0;
 }
@@ -190,6 +193,43 @@ int set_direct_map_default_noflush(struct page *page)
 				   PAGE_SIZE, change_page_range, &data);
 }
 
+static int __set_memory_encrypted(unsigned long addr,
+				  int numpages,
+				  bool encrypt)
+{
+	unsigned long set_prot = 0, clear_prot = 0;
+	phys_addr_t start, end;
+
+	if (!is_realm_world())
+		return 0;
+
+	WARN_ON(!__is_lm_address(addr));
+	start = __virt_to_phys(addr);
+	end = start + numpages * PAGE_SIZE;
+
+	if (encrypt) {
+		clear_prot = PROT_NS_SHARED;
+		set_memory_range_protected(start, end);
+	} else {
+		set_prot = PROT_NS_SHARED;
+		set_memory_range_shared(start, end);
+	}
+
+	return __change_memory_common(addr, PAGE_SIZE * numpages,
+				      __pgprot(set_prot),
+				      __pgprot(clear_prot));
+}
+
+int set_memory_encrypted(unsigned long addr, int numpages)
+{
+	return __set_memory_encrypted(addr, numpages, true);
+}
+
+int set_memory_decrypted(unsigned long addr, int numpages)
+{
+	return __set_memory_encrypted(addr, numpages, false);
+}
+
 #ifdef CONFIG_DEBUG_PAGEALLOC
 void __kernel_map_pages(struct page *page, int numpages, int enable)
 {
-- 
2.34.1


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

* [RFC PATCH 11/14] arm64: Force device mappings to be non-secure shared
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

Device mappings (currently) need to be emulated by the VMM so must be
mapped shared with the host.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/pgtable.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index a1319a743b38..f283ac3fb905 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -567,7 +567,7 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
 #define pgprot_writecombine(prot) \
 	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
 #define pgprot_device(prot) \
-	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
+	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN | PROT_NS_SHARED)
 #define pgprot_tagged(prot) \
 	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_TAGGED))
 #define pgprot_mhp	pgprot_tagged
-- 
2.34.1


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

* [RFC PATCH 11/14] arm64: Force device mappings to be non-secure shared
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

Device mappings (currently) need to be emulated by the VMM so must be
mapped shared with the host.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/pgtable.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index a1319a743b38..f283ac3fb905 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -567,7 +567,7 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
 #define pgprot_writecombine(prot) \
 	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
 #define pgprot_device(prot) \
-	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
+	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN | PROT_NS_SHARED)
 #define pgprot_tagged(prot) \
 	__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_TAGGED))
 #define pgprot_mhp	pgprot_tagged
-- 
2.34.1


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

* [RFC PATCH 12/14] efi: arm64: Map Device with Prot Shared
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

Device mappings need to be emualted by the VMM so must be mapped shared
with the host.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kernel/efi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index fab05de2e12d..03a876707fc5 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -31,7 +31,7 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md)
 	u32 type = md->type;
 
 	if (type == EFI_MEMORY_MAPPED_IO)
-		return PROT_DEVICE_nGnRE;
+		return PROT_NS_SHARED | PROT_DEVICE_nGnRE;
 
 	if (region_is_misaligned(md)) {
 		static bool __initdata code_is_misaligned;
-- 
2.34.1


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

* [RFC PATCH 12/14] efi: arm64: Map Device with Prot Shared
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

Device mappings need to be emualted by the VMM so must be mapped shared
with the host.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kernel/efi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index fab05de2e12d..03a876707fc5 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -31,7 +31,7 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md)
 	u32 type = md->type;
 
 	if (type == EFI_MEMORY_MAPPED_IO)
-		return PROT_DEVICE_nGnRE;
+		return PROT_NS_SHARED | PROT_DEVICE_nGnRE;
 
 	if (region_is_misaligned(md)) {
 		static bool __initdata code_is_misaligned;
-- 
2.34.1


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

* [RFC PATCH 13/14] arm64: realm: Support nonsecure ITS emulation shared
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Within a realm guest the ITS is emulated by the host. This means the
allocations must have been made available to the host by a call to
set_memory_decrypted(). Introduce an allocation function which performs
this extra call.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 drivers/irqchip/irq-gic-v3-its.c | 95 ++++++++++++++++++++++++--------
 1 file changed, 71 insertions(+), 24 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 973ede0197e3..5f9829376f6c 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -18,6 +18,7 @@
 #include <linux/irqdomain.h>
 #include <linux/list.h>
 #include <linux/log2.h>
+#include <linux/mem_encrypt.h>
 #include <linux/memblock.h>
 #include <linux/mm.h>
 #include <linux/msi.h>
@@ -27,6 +28,7 @@
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
 #include <linux/percpu.h>
+#include <linux/set_memory.h>
 #include <linux/slab.h>
 #include <linux/syscore_ops.h>
 
@@ -165,6 +167,7 @@ struct its_device {
 	struct its_node		*its;
 	struct event_lpi_map	event_map;
 	void			*itt;
+	u32			itt_order;
 	u32			nr_ites;
 	u32			device_id;
 	bool			shared;
@@ -200,6 +203,33 @@ static DEFINE_IDA(its_vpeid_ida);
 #define gic_data_rdist_rd_base()	(gic_data_rdist()->rd_base)
 #define gic_data_rdist_vlpi_base()	(gic_data_rdist_rd_base() + SZ_128K)
 
+static struct page *its_alloc_shared_pages_node(int node, gfp_t gfp,
+						unsigned int order)
+{
+	struct page *page;
+
+	if (node == NUMA_NO_NODE)
+		page = alloc_pages(gfp, order);
+	else
+		page = alloc_pages_node(node, gfp, order);
+
+	if (page)
+		set_memory_decrypted((unsigned long)page_address(page),
+				     1 << order);
+	return page;
+}
+
+static struct page *its_alloc_shared_pages(gfp_t gfp, unsigned int order)
+{
+	return its_alloc_shared_pages_node(NUMA_NO_NODE, gfp, order);
+}
+
+static void its_free_shared_pages(void *addr, unsigned int order)
+{
+	set_memory_encrypted((unsigned long)addr, 1 << order);
+	free_pages((unsigned long)addr, order);
+}
+
 /*
  * Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we
  * always have vSGIs mapped.
@@ -2178,7 +2208,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
 {
 	struct page *prop_page;
 
-	prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ));
+	prop_page = its_alloc_shared_pages(gfp_flags,
+					   get_order(LPI_PROPBASE_SZ));
 	if (!prop_page)
 		return NULL;
 
@@ -2189,8 +2220,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
 
 static void its_free_prop_table(struct page *prop_page)
 {
-	free_pages((unsigned long)page_address(prop_page),
-		   get_order(LPI_PROPBASE_SZ));
+	its_free_shared_pages(page_address(prop_page),
+			      get_order(LPI_PROPBASE_SZ));
 }
 
 static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size)
@@ -2312,10 +2343,10 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
 		order = get_order(GITS_BASER_PAGES_MAX * psz);
 	}
 
-	page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
+	page = its_alloc_shared_pages_node(its->numa_node,
+					   GFP_KERNEL | __GFP_ZERO, order);
 	if (!page)
 		return -ENOMEM;
-
 	base = (void *)page_address(page);
 	baser_phys = virt_to_phys(base);
 
@@ -2325,7 +2356,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
 		/* 52bit PA is supported only when PageSize=64K */
 		if (psz != SZ_64K) {
 			pr_err("ITS: no 52bit PA support when psz=%d\n", psz);
-			free_pages((unsigned long)base, order);
+			its_free_shared_pages(base, order);
 			return -ENXIO;
 		}
 
@@ -2379,7 +2410,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
 		pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n",
 		       &its->phys_base, its_base_type_string[type],
 		       val, tmp);
-		free_pages((unsigned long)base, order);
+		its_free_shared_pages(base, order);
 		return -ENXIO;
 	}
 
@@ -2518,8 +2549,8 @@ static void its_free_tables(struct its_node *its)
 
 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
 		if (its->tables[i].base) {
-			free_pages((unsigned long)its->tables[i].base,
-				   its->tables[i].order);
+			its_free_shared_pages(its->tables[i].base,
+					      its->tables[i].order);
 			its->tables[i].base = NULL;
 		}
 	}
@@ -2778,7 +2809,8 @@ static bool allocate_vpe_l2_table(int cpu, u32 id)
 
 	/* Allocate memory for 2nd level table */
 	if (!table[idx]) {
-		page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
+		page = its_alloc_shared_pages(GFP_KERNEL | __GFP_ZERO,
+					      get_order(psz));
 		if (!page)
 			return false;
 
@@ -2897,7 +2929,8 @@ static int allocate_vpe_l1_table(void)
 
 	pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n",
 		 np, npg, psz, epp, esz);
-	page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE));
+	page = its_alloc_shared_pages(GFP_ATOMIC | __GFP_ZERO,
+				      get_order(np * PAGE_SIZE));
 	if (!page)
 		return -ENOMEM;
 
@@ -2941,8 +2974,8 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
 {
 	struct page *pend_page;
 
-	pend_page = alloc_pages(gfp_flags | __GFP_ZERO,
-				get_order(LPI_PENDBASE_SZ));
+	pend_page = its_alloc_shared_pages(gfp_flags | __GFP_ZERO,
+					   get_order(LPI_PENDBASE_SZ));
 	if (!pend_page)
 		return NULL;
 
@@ -2954,7 +2987,8 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
 
 static void its_free_pending_table(struct page *pt)
 {
-	free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ));
+	its_free_shared_pages(page_address(pt),
+			      get_order(LPI_PENDBASE_SZ));
 }
 
 /*
@@ -3283,8 +3317,9 @@ static bool its_alloc_table_entry(struct its_node *its,
 
 	/* Allocate memory for 2nd level table */
 	if (!table[idx]) {
-		page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
-					get_order(baser->psz));
+		page = its_alloc_shared_pages_node(its->numa_node,
+						   GFP_KERNEL | __GFP_ZERO,
+						   get_order(baser->psz));
 		if (!page)
 			return false;
 
@@ -3367,7 +3402,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 	unsigned long *lpi_map = NULL;
 	unsigned long flags;
 	u16 *col_map = NULL;
+	struct page *page;
 	void *itt;
+	int itt_order;
 	int lpi_base;
 	int nr_lpis;
 	int nr_ites;
@@ -3379,7 +3416,6 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 	if (WARN_ON(!is_power_of_2(nvecs)))
 		nvecs = roundup_pow_of_two(nvecs);
 
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	/*
 	 * Even if the device wants a single LPI, the ITT must be
 	 * sized as a power of two (and you need at least one bit...).
@@ -3387,7 +3423,16 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 	nr_ites = max(2, nvecs);
 	sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
 	sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
-	itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node);
+	itt_order = get_order(sz);
+	page = its_alloc_shared_pages_node(its->numa_node,
+					   GFP_KERNEL | __GFP_ZERO,
+					   itt_order);
+	if (!page)
+		return NULL;
+	itt = (void *)page_address(page);
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
 	if (alloc_lpis) {
 		lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis);
 		if (lpi_map)
@@ -3399,9 +3444,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 		lpi_base = 0;
 	}
 
-	if (!dev || !itt ||  !col_map || (!lpi_map && alloc_lpis)) {
+	if (!dev || !col_map || (!lpi_map && alloc_lpis)) {
 		kfree(dev);
-		kfree(itt);
+		its_free_shared_pages(itt, itt_order);
 		bitmap_free(lpi_map);
 		kfree(col_map);
 		return NULL;
@@ -3411,6 +3456,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 
 	dev->its = its;
 	dev->itt = itt;
+	dev->itt_order = itt_order;
 	dev->nr_ites = nr_ites;
 	dev->event_map.lpi_map = lpi_map;
 	dev->event_map.col_map = col_map;
@@ -3438,7 +3484,7 @@ static void its_free_device(struct its_device *its_dev)
 	list_del(&its_dev->entry);
 	raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
 	kfree(its_dev->event_map.col_map);
-	kfree(its_dev->itt);
+	its_free_shared_pages(its_dev->itt, its_dev->itt_order);
 	kfree(its_dev);
 }
 
@@ -5064,8 +5110,9 @@ static int __init its_probe_one(struct resource *res,
 
 	its->numa_node = numa_node;
 
-	page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
-				get_order(ITS_CMD_QUEUE_SZ));
+	page = its_alloc_shared_pages_node(its->numa_node,
+					   GFP_KERNEL | __GFP_ZERO,
+					   get_order(ITS_CMD_QUEUE_SZ));
 	if (!page) {
 		err = -ENOMEM;
 		goto out_unmap_sgir;
@@ -5131,7 +5178,7 @@ static int __init its_probe_one(struct resource *res,
 out_free_tables:
 	its_free_tables(its);
 out_free_cmd:
-	free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
+	its_free_shared_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
 out_unmap_sgir:
 	if (its->sgir_base)
 		iounmap(its->sgir_base);
-- 
2.34.1


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

* [RFC PATCH 13/14] arm64: realm: Support nonsecure ITS emulation shared
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Within a realm guest the ITS is emulated by the host. This means the
allocations must have been made available to the host by a call to
set_memory_decrypted(). Introduce an allocation function which performs
this extra call.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 drivers/irqchip/irq-gic-v3-its.c | 95 ++++++++++++++++++++++++--------
 1 file changed, 71 insertions(+), 24 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 973ede0197e3..5f9829376f6c 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -18,6 +18,7 @@
 #include <linux/irqdomain.h>
 #include <linux/list.h>
 #include <linux/log2.h>
+#include <linux/mem_encrypt.h>
 #include <linux/memblock.h>
 #include <linux/mm.h>
 #include <linux/msi.h>
@@ -27,6 +28,7 @@
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
 #include <linux/percpu.h>
+#include <linux/set_memory.h>
 #include <linux/slab.h>
 #include <linux/syscore_ops.h>
 
@@ -165,6 +167,7 @@ struct its_device {
 	struct its_node		*its;
 	struct event_lpi_map	event_map;
 	void			*itt;
+	u32			itt_order;
 	u32			nr_ites;
 	u32			device_id;
 	bool			shared;
@@ -200,6 +203,33 @@ static DEFINE_IDA(its_vpeid_ida);
 #define gic_data_rdist_rd_base()	(gic_data_rdist()->rd_base)
 #define gic_data_rdist_vlpi_base()	(gic_data_rdist_rd_base() + SZ_128K)
 
+static struct page *its_alloc_shared_pages_node(int node, gfp_t gfp,
+						unsigned int order)
+{
+	struct page *page;
+
+	if (node == NUMA_NO_NODE)
+		page = alloc_pages(gfp, order);
+	else
+		page = alloc_pages_node(node, gfp, order);
+
+	if (page)
+		set_memory_decrypted((unsigned long)page_address(page),
+				     1 << order);
+	return page;
+}
+
+static struct page *its_alloc_shared_pages(gfp_t gfp, unsigned int order)
+{
+	return its_alloc_shared_pages_node(NUMA_NO_NODE, gfp, order);
+}
+
+static void its_free_shared_pages(void *addr, unsigned int order)
+{
+	set_memory_encrypted((unsigned long)addr, 1 << order);
+	free_pages((unsigned long)addr, order);
+}
+
 /*
  * Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we
  * always have vSGIs mapped.
@@ -2178,7 +2208,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
 {
 	struct page *prop_page;
 
-	prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ));
+	prop_page = its_alloc_shared_pages(gfp_flags,
+					   get_order(LPI_PROPBASE_SZ));
 	if (!prop_page)
 		return NULL;
 
@@ -2189,8 +2220,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
 
 static void its_free_prop_table(struct page *prop_page)
 {
-	free_pages((unsigned long)page_address(prop_page),
-		   get_order(LPI_PROPBASE_SZ));
+	its_free_shared_pages(page_address(prop_page),
+			      get_order(LPI_PROPBASE_SZ));
 }
 
 static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size)
@@ -2312,10 +2343,10 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
 		order = get_order(GITS_BASER_PAGES_MAX * psz);
 	}
 
-	page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
+	page = its_alloc_shared_pages_node(its->numa_node,
+					   GFP_KERNEL | __GFP_ZERO, order);
 	if (!page)
 		return -ENOMEM;
-
 	base = (void *)page_address(page);
 	baser_phys = virt_to_phys(base);
 
@@ -2325,7 +2356,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
 		/* 52bit PA is supported only when PageSize=64K */
 		if (psz != SZ_64K) {
 			pr_err("ITS: no 52bit PA support when psz=%d\n", psz);
-			free_pages((unsigned long)base, order);
+			its_free_shared_pages(base, order);
 			return -ENXIO;
 		}
 
@@ -2379,7 +2410,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
 		pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n",
 		       &its->phys_base, its_base_type_string[type],
 		       val, tmp);
-		free_pages((unsigned long)base, order);
+		its_free_shared_pages(base, order);
 		return -ENXIO;
 	}
 
@@ -2518,8 +2549,8 @@ static void its_free_tables(struct its_node *its)
 
 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
 		if (its->tables[i].base) {
-			free_pages((unsigned long)its->tables[i].base,
-				   its->tables[i].order);
+			its_free_shared_pages(its->tables[i].base,
+					      its->tables[i].order);
 			its->tables[i].base = NULL;
 		}
 	}
@@ -2778,7 +2809,8 @@ static bool allocate_vpe_l2_table(int cpu, u32 id)
 
 	/* Allocate memory for 2nd level table */
 	if (!table[idx]) {
-		page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
+		page = its_alloc_shared_pages(GFP_KERNEL | __GFP_ZERO,
+					      get_order(psz));
 		if (!page)
 			return false;
 
@@ -2897,7 +2929,8 @@ static int allocate_vpe_l1_table(void)
 
 	pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n",
 		 np, npg, psz, epp, esz);
-	page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE));
+	page = its_alloc_shared_pages(GFP_ATOMIC | __GFP_ZERO,
+				      get_order(np * PAGE_SIZE));
 	if (!page)
 		return -ENOMEM;
 
@@ -2941,8 +2974,8 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
 {
 	struct page *pend_page;
 
-	pend_page = alloc_pages(gfp_flags | __GFP_ZERO,
-				get_order(LPI_PENDBASE_SZ));
+	pend_page = its_alloc_shared_pages(gfp_flags | __GFP_ZERO,
+					   get_order(LPI_PENDBASE_SZ));
 	if (!pend_page)
 		return NULL;
 
@@ -2954,7 +2987,8 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
 
 static void its_free_pending_table(struct page *pt)
 {
-	free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ));
+	its_free_shared_pages(page_address(pt),
+			      get_order(LPI_PENDBASE_SZ));
 }
 
 /*
@@ -3283,8 +3317,9 @@ static bool its_alloc_table_entry(struct its_node *its,
 
 	/* Allocate memory for 2nd level table */
 	if (!table[idx]) {
-		page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
-					get_order(baser->psz));
+		page = its_alloc_shared_pages_node(its->numa_node,
+						   GFP_KERNEL | __GFP_ZERO,
+						   get_order(baser->psz));
 		if (!page)
 			return false;
 
@@ -3367,7 +3402,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 	unsigned long *lpi_map = NULL;
 	unsigned long flags;
 	u16 *col_map = NULL;
+	struct page *page;
 	void *itt;
+	int itt_order;
 	int lpi_base;
 	int nr_lpis;
 	int nr_ites;
@@ -3379,7 +3416,6 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 	if (WARN_ON(!is_power_of_2(nvecs)))
 		nvecs = roundup_pow_of_two(nvecs);
 
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	/*
 	 * Even if the device wants a single LPI, the ITT must be
 	 * sized as a power of two (and you need at least one bit...).
@@ -3387,7 +3423,16 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 	nr_ites = max(2, nvecs);
 	sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
 	sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
-	itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node);
+	itt_order = get_order(sz);
+	page = its_alloc_shared_pages_node(its->numa_node,
+					   GFP_KERNEL | __GFP_ZERO,
+					   itt_order);
+	if (!page)
+		return NULL;
+	itt = (void *)page_address(page);
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
 	if (alloc_lpis) {
 		lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis);
 		if (lpi_map)
@@ -3399,9 +3444,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 		lpi_base = 0;
 	}
 
-	if (!dev || !itt ||  !col_map || (!lpi_map && alloc_lpis)) {
+	if (!dev || !col_map || (!lpi_map && alloc_lpis)) {
 		kfree(dev);
-		kfree(itt);
+		its_free_shared_pages(itt, itt_order);
 		bitmap_free(lpi_map);
 		kfree(col_map);
 		return NULL;
@@ -3411,6 +3456,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 
 	dev->its = its;
 	dev->itt = itt;
+	dev->itt_order = itt_order;
 	dev->nr_ites = nr_ites;
 	dev->event_map.lpi_map = lpi_map;
 	dev->event_map.col_map = col_map;
@@ -3438,7 +3484,7 @@ static void its_free_device(struct its_device *its_dev)
 	list_del(&its_dev->entry);
 	raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
 	kfree(its_dev->event_map.col_map);
-	kfree(its_dev->itt);
+	its_free_shared_pages(its_dev->itt, its_dev->itt_order);
 	kfree(its_dev);
 }
 
@@ -5064,8 +5110,9 @@ static int __init its_probe_one(struct resource *res,
 
 	its->numa_node = numa_node;
 
-	page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
-				get_order(ITS_CMD_QUEUE_SZ));
+	page = its_alloc_shared_pages_node(its->numa_node,
+					   GFP_KERNEL | __GFP_ZERO,
+					   get_order(ITS_CMD_QUEUE_SZ));
 	if (!page) {
 		err = -ENOMEM;
 		goto out_unmap_sgir;
@@ -5131,7 +5178,7 @@ static int __init its_probe_one(struct resource *res,
 out_free_tables:
 	its_free_tables(its);
 out_free_cmd:
-	free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
+	its_free_shared_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
 out_unmap_sgir:
 	if (its->sgir_base)
 		iounmap(its->sgir_base);
-- 
2.34.1


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

* [RFC PATCH 14/14] HACK: Accept prototype RSI version
  2023-01-27 11:27   ` Steven Price
@ 2023-01-27 11:27     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The upstream RMM currently advertises the major version of an internal
prototype (v12.0) rather than the expected version from the RMM
architecture specification (v1.0).

Add a config option to enable support for the prototype RSI v12.0.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rsi_smc.h | 2 ++
 arch/arm64/kernel/rsi.c          | 5 +++++
 arch/arm64/kvm/Kconfig           | 8 ++++++++
 3 files changed, 15 insertions(+)

diff --git a/arch/arm64/include/asm/rsi_smc.h b/arch/arm64/include/asm/rsi_smc.h
index bc0cdd83f164..baf07f905353 100644
--- a/arch/arm64/include/asm/rsi_smc.h
+++ b/arch/arm64/include/asm/rsi_smc.h
@@ -29,6 +29,8 @@
 #define RSI_ABI_VERSION			((RSI_ABI_VERSION_MAJOR << 16) | \
 					 RSI_ABI_VERSION_MINOR)
 
+#define RSI_LEGACY_ABI_VERSION		0xc0000
+
 #define RSI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
 #define RSI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
 
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 1cc292826f2b..45b26f23e706 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -41,6 +41,11 @@ static bool rsi_version_matches(void)
 		RSI_ABI_VERSION_GET_MAJOR(ver),
 		RSI_ABI_VERSION_GET_MINOR(ver));
 
+#ifdef CONFIG_RME_USE_PROTOTYPE_HACKS
+	if (ver == RSI_LEGACY_ABI_VERSION)
+		return true;
+#endif
+
 	return (ver >= RSI_ABI_VERSION &&
 		RSI_ABI_VERSION_GET_MAJOR(ver) == RSI_ABI_VERSION_MAJOR);
 }
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 05da3c8f7e88..13858a5047fd 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -58,6 +58,14 @@ config NVHE_EL2_DEBUG
 
 	  If unsure, say N.
 
+config RME_USE_PROTOTYPE_HACKS
+	bool "Allow RMM prototype version numbers"
+	default y
+	help
+	  For compatibility with the the current RMM code allow versions
+	  numbers from a prototype implementation as well as the expected
+	  version number from the RMM specification.
+
 config PROTECTED_NVHE_STACKTRACE
 	bool "Protected KVM hypervisor stacktraces"
 	depends on NVHE_EL2_DEBUG
-- 
2.34.1


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

* [RFC PATCH 14/14] HACK: Accept prototype RSI version
@ 2023-01-27 11:27     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:27 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Steven Price, Catalin Marinas, Ard Biesheuvel, Marc Zyngier,
	Will Deacon, Suzuki K Poulose, James Morse, Oliver Upton,
	Zenghui Yu, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The upstream RMM currently advertises the major version of an internal
prototype (v12.0) rather than the expected version from the RMM
architecture specification (v1.0).

Add a config option to enable support for the prototype RSI v12.0.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rsi_smc.h | 2 ++
 arch/arm64/kernel/rsi.c          | 5 +++++
 arch/arm64/kvm/Kconfig           | 8 ++++++++
 3 files changed, 15 insertions(+)

diff --git a/arch/arm64/include/asm/rsi_smc.h b/arch/arm64/include/asm/rsi_smc.h
index bc0cdd83f164..baf07f905353 100644
--- a/arch/arm64/include/asm/rsi_smc.h
+++ b/arch/arm64/include/asm/rsi_smc.h
@@ -29,6 +29,8 @@
 #define RSI_ABI_VERSION			((RSI_ABI_VERSION_MAJOR << 16) | \
 					 RSI_ABI_VERSION_MINOR)
 
+#define RSI_LEGACY_ABI_VERSION		0xc0000
+
 #define RSI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
 #define RSI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
 
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 1cc292826f2b..45b26f23e706 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -41,6 +41,11 @@ static bool rsi_version_matches(void)
 		RSI_ABI_VERSION_GET_MAJOR(ver),
 		RSI_ABI_VERSION_GET_MINOR(ver));
 
+#ifdef CONFIG_RME_USE_PROTOTYPE_HACKS
+	if (ver == RSI_LEGACY_ABI_VERSION)
+		return true;
+#endif
+
 	return (ver >= RSI_ABI_VERSION &&
 		RSI_ABI_VERSION_GET_MAJOR(ver) == RSI_ABI_VERSION_MAJOR);
 }
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 05da3c8f7e88..13858a5047fd 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -58,6 +58,14 @@ config NVHE_EL2_DEBUG
 
 	  If unsure, say N.
 
+config RME_USE_PROTOTYPE_HACKS
+	bool "Allow RMM prototype version numbers"
+	default y
+	help
+	  For compatibility with the the current RMM code allow versions
+	  numbers from a prototype implementation as well as the expected
+	  version number from the RMM specification.
+
 config PROTECTED_NVHE_STACKTRACE
 	bool "Protected KVM hypervisor stacktraces"
 	depends on NVHE_EL2_DEBUG
-- 
2.34.1


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

* [RFC PATCH 00/28] arm64: Support for Arm CCA in KVM
  2023-01-27 11:22 ` Suzuki K Poulose
@ 2023-01-27 11:29   ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

This series is an RFC adding support for running protected VMs using KVM
under the new Arm Confidential Compute Architecture (CCA). The purpose
of this series is to gather feedback on the proposed changes to the
architecture code for CCA.

The user ABI is not in it's final form, we plan to make use of the
memfd_restricted() allocator[1] and associated infrastructure which will
avoid problems in the current user ABI where a malicious VMM may be able
to cause a Granule Protection Fault in the kernel (which is fatal).

The ABI to the RMM (the RMI) is based on the Beta 0 specification[2] and
will be updated in the future when a final version of the specification
is published.

This series is based on v6.2-rc1. It is also available as a git
repository:

https://gitlab.arm.com/linux-arm/linux-cca cca-host/rfc-v1

Introduction
============
A more general introduction to Arm CCA is available on the Arm
website[3], and links to the other components involved are available in
the overall cover letter[4].

Arm Confidential Compute Architecture adds two new 'worlds' to the
architecture: Root and Realm. A new software component known as the RMM
(Realm Management Monitor) runs in Realm EL2 and is trusted by both the
Normal World and VMs running within Realms. This enables mutual
distrust between the Realm VMs and the Normal World.

Virtual machines running within a Realm can decide on a (4k)
page-by-page granularity whether to share a page with the (Normal World)
host or to keep it private (protected). This protection is provided by
the hardware and attempts to access a page which isn't shared by the
Normal World will trigger a Granule Protection Fault. The series starts
by adding handling for these; faults within user space can be handled by
killing the process, faults within kernel space are considered fatal.

The Normal World host can communicate with the RMM via an SMC interface
known as RMI (Realm Management Interface), and Realm VMs can communicate
with the RMM via another SMC interface known as RSI (Realm Services
Interface). This series adds wrappers for the full set of RMI commands
and uses them to manage the realm guests.

The Normal World can use RMI commands to delegate pages to the Realm
world and to create, manage and run Realm VMs. Once delegated the pages
are inaccessible to the Normal World (unless explicitly shared by the
guest). However the Normal World may destroy the Realm VM at any time to
be able to reclaim (undelegate) the pages.

Entry/exit of a Realm VM attempts to reuse the KVM infrastructure, but
ultimately the final mechanism is different. So this series has a bunch
of commits handling the differences. As much as possible is placed in a
two new files: rme.c and rme-exit.c.

The RMM specification provides a new mechanism for a guest to
communicate with host which goes by the name "Host Call". For now this
is simply hooked up to the existing support for HVC calls from a normal
guest.

[1] https://lore.kernel.org/r/20221202061347.1070246-1-chao.p.peng%40linux.intel.com
[2] https://developer.arm.com/documentation/den0137/1-0bet0/
[3] https://www.arm.com/architecture/security-features/arm-confidential-compute-architecture
[4] .. cover letter ..

Joey Gouly (2):
  arm64: rme: allow userspace to inject aborts
  arm64: rme: support RSI_HOST_CALL

Steven Price (25):
  arm64: RME: Handle Granule Protection Faults (GPFs)
  arm64: RME: Add SMC definitions for calling the RMM
  arm64: RME: Add wrappers for RMI calls
  arm64: RME: Check for RME support at KVM init
  arm64: RME: Define the user ABI
  arm64: RME: ioctls to create and configure realms
  arm64: kvm: Allow passing machine type in KVM creation
  arm64: RME: Keep a spare page delegated to the RMM
  arm64: RME: RTT handling
  arm64: RME: Allocate/free RECs to match vCPUs
  arm64: RME: Support for the VGIC in realms
  KVM: arm64: Support timers in realm RECs
  arm64: RME: Allow VMM to set RIPAS
  arm64: RME: Handle realm enter/exit
  KVM: arm64: Handle realm MMIO emulation
  arm64: RME: Allow populating initial contents
  arm64: RME: Runtime faulting of memory
  KVM: arm64: Handle realm VCPU load
  KVM: arm64: Validate register access for a Realm VM
  KVM: arm64: Handle Realm PSCI requests
  KVM: arm64: WARN on injected undef exceptions
  arm64: Don't expose stolen time for realm guests
  KVM: arm64: Allow activating realms
  arm64: RME: Always use 4k pages for realms
  HACK: Accept prototype RMI versions

Suzuki K Poulose (1):
  arm64: rme: Allow checking SVE on VM instance

 Documentation/virt/kvm/api.rst       |    3 +
 arch/arm64/include/asm/kvm_emulate.h |   29 +
 arch/arm64/include/asm/kvm_host.h    |    7 +
 arch/arm64/include/asm/kvm_rme.h     |   98 ++
 arch/arm64/include/asm/rmi_cmds.h    |  259 +++++
 arch/arm64/include/asm/rmi_smc.h     |  242 +++++
 arch/arm64/include/asm/virt.h        |    1 +
 arch/arm64/include/uapi/asm/kvm.h    |   63 ++
 arch/arm64/kvm/Kconfig               |    8 +
 arch/arm64/kvm/Makefile              |    3 +-
 arch/arm64/kvm/arch_timer.c          |   53 +-
 arch/arm64/kvm/arm.c                 |  105 +-
 arch/arm64/kvm/guest.c               |   50 +
 arch/arm64/kvm/inject_fault.c        |    2 +
 arch/arm64/kvm/mmio.c                |    7 +
 arch/arm64/kvm/mmu.c                 |   80 +-
 arch/arm64/kvm/psci.c                |   23 +
 arch/arm64/kvm/reset.c               |   41 +
 arch/arm64/kvm/rme-exit.c            |  194 ++++
 arch/arm64/kvm/rme.c                 | 1453 ++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic-v3.c        |    9 +-
 arch/arm64/kvm/vgic/vgic.c           |   37 +-
 arch/arm64/mm/fault.c                |   29 +-
 include/kvm/arm_arch_timer.h         |    2 +
 include/uapi/linux/kvm.h             |   21 +-
 25 files changed, 2772 insertions(+), 47 deletions(-)
 create mode 100644 arch/arm64/include/asm/kvm_rme.h
 create mode 100644 arch/arm64/include/asm/rmi_cmds.h
 create mode 100644 arch/arm64/include/asm/rmi_smc.h
 create mode 100644 arch/arm64/kvm/rme-exit.c
 create mode 100644 arch/arm64/kvm/rme.c

-- 
2.34.1


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

* [RFC PATCH 00/28] arm64: Support for Arm CCA in KVM
@ 2023-01-27 11:29   ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

This series is an RFC adding support for running protected VMs using KVM
under the new Arm Confidential Compute Architecture (CCA). The purpose
of this series is to gather feedback on the proposed changes to the
architecture code for CCA.

The user ABI is not in it's final form, we plan to make use of the
memfd_restricted() allocator[1] and associated infrastructure which will
avoid problems in the current user ABI where a malicious VMM may be able
to cause a Granule Protection Fault in the kernel (which is fatal).

The ABI to the RMM (the RMI) is based on the Beta 0 specification[2] and
will be updated in the future when a final version of the specification
is published.

This series is based on v6.2-rc1. It is also available as a git
repository:

https://gitlab.arm.com/linux-arm/linux-cca cca-host/rfc-v1

Introduction
============
A more general introduction to Arm CCA is available on the Arm
website[3], and links to the other components involved are available in
the overall cover letter[4].

Arm Confidential Compute Architecture adds two new 'worlds' to the
architecture: Root and Realm. A new software component known as the RMM
(Realm Management Monitor) runs in Realm EL2 and is trusted by both the
Normal World and VMs running within Realms. This enables mutual
distrust between the Realm VMs and the Normal World.

Virtual machines running within a Realm can decide on a (4k)
page-by-page granularity whether to share a page with the (Normal World)
host or to keep it private (protected). This protection is provided by
the hardware and attempts to access a page which isn't shared by the
Normal World will trigger a Granule Protection Fault. The series starts
by adding handling for these; faults within user space can be handled by
killing the process, faults within kernel space are considered fatal.

The Normal World host can communicate with the RMM via an SMC interface
known as RMI (Realm Management Interface), and Realm VMs can communicate
with the RMM via another SMC interface known as RSI (Realm Services
Interface). This series adds wrappers for the full set of RMI commands
and uses them to manage the realm guests.

The Normal World can use RMI commands to delegate pages to the Realm
world and to create, manage and run Realm VMs. Once delegated the pages
are inaccessible to the Normal World (unless explicitly shared by the
guest). However the Normal World may destroy the Realm VM at any time to
be able to reclaim (undelegate) the pages.

Entry/exit of a Realm VM attempts to reuse the KVM infrastructure, but
ultimately the final mechanism is different. So this series has a bunch
of commits handling the differences. As much as possible is placed in a
two new files: rme.c and rme-exit.c.

The RMM specification provides a new mechanism for a guest to
communicate with host which goes by the name "Host Call". For now this
is simply hooked up to the existing support for HVC calls from a normal
guest.

[1] https://lore.kernel.org/r/20221202061347.1070246-1-chao.p.peng%40linux.intel.com
[2] https://developer.arm.com/documentation/den0137/1-0bet0/
[3] https://www.arm.com/architecture/security-features/arm-confidential-compute-architecture
[4] .. cover letter ..

Joey Gouly (2):
  arm64: rme: allow userspace to inject aborts
  arm64: rme: support RSI_HOST_CALL

Steven Price (25):
  arm64: RME: Handle Granule Protection Faults (GPFs)
  arm64: RME: Add SMC definitions for calling the RMM
  arm64: RME: Add wrappers for RMI calls
  arm64: RME: Check for RME support at KVM init
  arm64: RME: Define the user ABI
  arm64: RME: ioctls to create and configure realms
  arm64: kvm: Allow passing machine type in KVM creation
  arm64: RME: Keep a spare page delegated to the RMM
  arm64: RME: RTT handling
  arm64: RME: Allocate/free RECs to match vCPUs
  arm64: RME: Support for the VGIC in realms
  KVM: arm64: Support timers in realm RECs
  arm64: RME: Allow VMM to set RIPAS
  arm64: RME: Handle realm enter/exit
  KVM: arm64: Handle realm MMIO emulation
  arm64: RME: Allow populating initial contents
  arm64: RME: Runtime faulting of memory
  KVM: arm64: Handle realm VCPU load
  KVM: arm64: Validate register access for a Realm VM
  KVM: arm64: Handle Realm PSCI requests
  KVM: arm64: WARN on injected undef exceptions
  arm64: Don't expose stolen time for realm guests
  KVM: arm64: Allow activating realms
  arm64: RME: Always use 4k pages for realms
  HACK: Accept prototype RMI versions

Suzuki K Poulose (1):
  arm64: rme: Allow checking SVE on VM instance

 Documentation/virt/kvm/api.rst       |    3 +
 arch/arm64/include/asm/kvm_emulate.h |   29 +
 arch/arm64/include/asm/kvm_host.h    |    7 +
 arch/arm64/include/asm/kvm_rme.h     |   98 ++
 arch/arm64/include/asm/rmi_cmds.h    |  259 +++++
 arch/arm64/include/asm/rmi_smc.h     |  242 +++++
 arch/arm64/include/asm/virt.h        |    1 +
 arch/arm64/include/uapi/asm/kvm.h    |   63 ++
 arch/arm64/kvm/Kconfig               |    8 +
 arch/arm64/kvm/Makefile              |    3 +-
 arch/arm64/kvm/arch_timer.c          |   53 +-
 arch/arm64/kvm/arm.c                 |  105 +-
 arch/arm64/kvm/guest.c               |   50 +
 arch/arm64/kvm/inject_fault.c        |    2 +
 arch/arm64/kvm/mmio.c                |    7 +
 arch/arm64/kvm/mmu.c                 |   80 +-
 arch/arm64/kvm/psci.c                |   23 +
 arch/arm64/kvm/reset.c               |   41 +
 arch/arm64/kvm/rme-exit.c            |  194 ++++
 arch/arm64/kvm/rme.c                 | 1453 ++++++++++++++++++++++++++
 arch/arm64/kvm/vgic/vgic-v3.c        |    9 +-
 arch/arm64/kvm/vgic/vgic.c           |   37 +-
 arch/arm64/mm/fault.c                |   29 +-
 include/kvm/arm_arch_timer.h         |    2 +
 include/uapi/linux/kvm.h             |   21 +-
 25 files changed, 2772 insertions(+), 47 deletions(-)
 create mode 100644 arch/arm64/include/asm/kvm_rme.h
 create mode 100644 arch/arm64/include/asm/rmi_cmds.h
 create mode 100644 arch/arm64/include/asm/rmi_smc.h
 create mode 100644 arch/arm64/kvm/rme-exit.c
 create mode 100644 arch/arm64/kvm/rme.c

-- 
2.34.1


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

* [RFC PATCH 01/28] arm64: RME: Handle Granule Protection Faults (GPFs)
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

If the host attempts to access granules that have been delegated for use
in a realm these accesses will be caught and will trigger a Granule
Protection Fault (GPF).

A fault during a page walk signals a bug in the kernel and is handled by
oopsing the kernel. A non-page walk fault could be caused by user space
having access to a page which has been delegated to the kernel and will
trigger a SIGBUS to allow debugging why user space is trying to access a
delegated page.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/mm/fault.c | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 596f46dabe4e..fd84be115657 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -756,6 +756,25 @@ static int do_tag_check_fault(unsigned long far, unsigned long esr,
 	return 0;
 }
 
+static int do_gpf_ptw(unsigned long far, unsigned long esr, struct pt_regs *regs)
+{
+	const struct fault_info *inf = esr_to_fault_info(esr);
+
+	die_kernel_fault(inf->name, far, esr, regs);
+	return 0;
+}
+
+static int do_gpf(unsigned long far, unsigned long esr, struct pt_regs *regs)
+{
+	const struct fault_info *inf = esr_to_fault_info(esr);
+
+	if (!is_el1_instruction_abort(esr) && fixup_exception(regs))
+		return 0;
+
+	arm64_notify_die(inf->name, regs, inf->sig, inf->code, far, esr);
+	return 0;
+}
+
 static const struct fault_info fault_info[] = {
 	{ do_bad,		SIGKILL, SI_KERNEL,	"ttbr address size fault"	},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"level 1 address size fault"	},
@@ -793,11 +812,11 @@ static const struct fault_info fault_info[] = {
 	{ do_alignment_fault,	SIGBUS,  BUS_ADRALN,	"alignment fault"		},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 34"			},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 35"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 36"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 37"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 38"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 39"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 40"			},
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 0" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 1" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 2" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 3" },
+	{ do_gpf,		SIGBUS,  SI_KERNEL,	"Granule Protection Fault not on table walk" },
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 41"			},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 42"			},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 43"			},
-- 
2.34.1


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

* [RFC PATCH 01/28] arm64: RME: Handle Granule Protection Faults (GPFs)
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

If the host attempts to access granules that have been delegated for use
in a realm these accesses will be caught and will trigger a Granule
Protection Fault (GPF).

A fault during a page walk signals a bug in the kernel and is handled by
oopsing the kernel. A non-page walk fault could be caused by user space
having access to a page which has been delegated to the kernel and will
trigger a SIGBUS to allow debugging why user space is trying to access a
delegated page.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/mm/fault.c | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 596f46dabe4e..fd84be115657 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -756,6 +756,25 @@ static int do_tag_check_fault(unsigned long far, unsigned long esr,
 	return 0;
 }
 
+static int do_gpf_ptw(unsigned long far, unsigned long esr, struct pt_regs *regs)
+{
+	const struct fault_info *inf = esr_to_fault_info(esr);
+
+	die_kernel_fault(inf->name, far, esr, regs);
+	return 0;
+}
+
+static int do_gpf(unsigned long far, unsigned long esr, struct pt_regs *regs)
+{
+	const struct fault_info *inf = esr_to_fault_info(esr);
+
+	if (!is_el1_instruction_abort(esr) && fixup_exception(regs))
+		return 0;
+
+	arm64_notify_die(inf->name, regs, inf->sig, inf->code, far, esr);
+	return 0;
+}
+
 static const struct fault_info fault_info[] = {
 	{ do_bad,		SIGKILL, SI_KERNEL,	"ttbr address size fault"	},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"level 1 address size fault"	},
@@ -793,11 +812,11 @@ static const struct fault_info fault_info[] = {
 	{ do_alignment_fault,	SIGBUS,  BUS_ADRALN,	"alignment fault"		},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 34"			},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 35"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 36"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 37"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 38"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 39"			},
-	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 40"			},
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 0" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 1" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 2" },
+	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 3" },
+	{ do_gpf,		SIGBUS,  SI_KERNEL,	"Granule Protection Fault not on table walk" },
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 41"			},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 42"			},
 	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 43"			},
-- 
2.34.1


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

* [RFC PATCH 02/28] arm64: RME: Add SMC definitions for calling the RMM
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM (Realm Management Monitor) provides functionality that can be
accessed by SMC calls from the host.

The SMC definitions are based on DEN0137[1] version A-bet0.

[1] https://developer.arm.com/documentation/den0137/latest

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rmi_smc.h | 235 +++++++++++++++++++++++++++++++
 1 file changed, 235 insertions(+)
 create mode 100644 arch/arm64/include/asm/rmi_smc.h

diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
new file mode 100644
index 000000000000..16ff65090f3a
--- /dev/null
+++ b/arch/arm64/include/asm/rmi_smc.h
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RME_SMC_H
+#define __ASM_RME_SMC_H
+
+#include <linux/arm-smccc.h>
+
+#define SMC_RxI_CALL(func)				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
+			   ARM_SMCCC_SMC_64,		\
+			   ARM_SMCCC_OWNER_STANDARD,	\
+			   (func))
+
+/* FID numbers from alp10 specification */
+
+#define SMC_RMI_DATA_CREATE		SMC_RxI_CALL(0x0153)
+#define SMC_RMI_DATA_CREATE_UNKNOWN	SMC_RxI_CALL(0x0154)
+#define SMC_RMI_DATA_DESTROY		SMC_RxI_CALL(0x0155)
+#define SMC_RMI_FEATURES		SMC_RxI_CALL(0x0165)
+#define SMC_RMI_GRANULE_DELEGATE	SMC_RxI_CALL(0x0151)
+#define SMC_RMI_GRANULE_UNDELEGATE	SMC_RxI_CALL(0x0152)
+#define SMC_RMI_PSCI_COMPLETE		SMC_RxI_CALL(0x0164)
+#define SMC_RMI_REALM_ACTIVATE		SMC_RxI_CALL(0x0157)
+#define SMC_RMI_REALM_CREATE		SMC_RxI_CALL(0x0158)
+#define SMC_RMI_REALM_DESTROY		SMC_RxI_CALL(0x0159)
+#define SMC_RMI_REC_AUX_COUNT		SMC_RxI_CALL(0x0167)
+#define SMC_RMI_REC_CREATE		SMC_RxI_CALL(0x015a)
+#define SMC_RMI_REC_DESTROY		SMC_RxI_CALL(0x015b)
+#define SMC_RMI_REC_ENTER		SMC_RxI_CALL(0x015c)
+#define SMC_RMI_RTT_CREATE		SMC_RxI_CALL(0x015d)
+#define SMC_RMI_RTT_DESTROY		SMC_RxI_CALL(0x015e)
+#define SMC_RMI_RTT_FOLD		SMC_RxI_CALL(0x0166)
+#define SMC_RMI_RTT_INIT_RIPAS		SMC_RxI_CALL(0x0168)
+#define SMC_RMI_RTT_MAP_UNPROTECTED	SMC_RxI_CALL(0x015f)
+#define SMC_RMI_RTT_READ_ENTRY		SMC_RxI_CALL(0x0161)
+#define SMC_RMI_RTT_SET_RIPAS		SMC_RxI_CALL(0x0169)
+#define SMC_RMI_RTT_UNMAP_UNPROTECTED	SMC_RxI_CALL(0x0162)
+#define SMC_RMI_VERSION			SMC_RxI_CALL(0x0150)
+
+#define RMI_ABI_MAJOR_VERSION	1
+#define RMI_ABI_MINOR_VERSION	0
+
+#define RMI_UNASSIGNED			0
+#define RMI_DESTROYED			1
+#define RMI_ASSIGNED			2
+#define RMI_TABLE			3
+#define RMI_VALID_NS			4
+
+#define RMI_ABI_VERSION_GET_MAJOR(version) ((version) >> 16)
+#define RMI_ABI_VERSION_GET_MINOR(version) ((version) & 0xFFFF)
+
+#define RMI_RETURN_STATUS(ret)		((ret) & 0xFF)
+#define RMI_RETURN_INDEX(ret)		(((ret) >> 8) & 0xFF)
+
+#define RMI_SUCCESS		0
+#define RMI_ERROR_INPUT		1
+#define RMI_ERROR_REALM		2
+#define RMI_ERROR_REC		3
+#define RMI_ERROR_RTT		4
+#define RMI_ERROR_IN_USE	5
+
+#define RMI_EMPTY		0
+#define RMI_RAM			1
+
+#define RMI_NO_MEASURE_CONTENT	0
+#define RMI_MEASURE_CONTENT	1
+
+#define RMI_FEATURE_REGISTER_0_S2SZ		GENMASK(7, 0)
+#define RMI_FEATURE_REGISTER_0_LPA2		BIT(8)
+#define RMI_FEATURE_REGISTER_0_SVE_EN		BIT(9)
+#define RMI_FEATURE_REGISTER_0_SVE_VL		GENMASK(13, 10)
+#define RMI_FEATURE_REGISTER_0_NUM_BPS		GENMASK(17, 14)
+#define RMI_FEATURE_REGISTER_0_NUM_WPS		GENMASK(21, 18)
+#define RMI_FEATURE_REGISTER_0_PMU_EN		BIT(22)
+#define RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS	GENMASK(27, 23)
+#define RMI_FEATURE_REGISTER_0_HASH_SHA_256	BIT(28)
+#define RMI_FEATURE_REGISTER_0_HASH_SHA_512	BIT(29)
+
+struct realm_params {
+	union {
+		u64 features_0;
+		u8 padding_1[0x100];
+	};
+	union {
+		u8 measurement_algo;
+		u8 padding_2[0x300];
+	};
+	union {
+		u8 rpv[64];
+		u8 padding_3[0x400];
+	};
+	union {
+		struct {
+			u16 vmid;
+			u8 padding_4[6];
+			u64 rtt_base;
+			u64 rtt_level_start;
+			u32 rtt_num_start;
+		};
+		u8 padding_5[0x800];
+	};
+};
+
+/*
+ * The number of GPRs (starting from X0) that are
+ * configured by the host when a REC is created.
+ */
+#define REC_CREATE_NR_GPRS		8
+
+#define REC_PARAMS_FLAG_RUNNABLE	BIT_ULL(0)
+
+#define REC_PARAMS_AUX_GRANULES		16
+
+struct rec_params {
+	union {
+		u64 flags;
+		u8 padding1[0x100];
+	};
+	union {
+		u64 mpidr;
+		u8 padding2[0x100];
+	};
+	union {
+		u64 pc;
+		u8 padding3[0x100];
+	};
+	union {
+		u64 gprs[REC_CREATE_NR_GPRS];
+		u8 padding4[0x500];
+	};
+	u64 num_rec_aux;
+	u64 aux[REC_PARAMS_AUX_GRANULES];
+};
+
+#define RMI_EMULATED_MMIO		BIT(0)
+#define RMI_INJECT_SEA			BIT(1)
+#define RMI_TRAP_WFI			BIT(2)
+#define RMI_TRAP_WFE			BIT(3)
+
+#define REC_RUN_GPRS			31
+#define REC_GIC_NUM_LRS			16
+
+struct rec_entry {
+	union { /* 0x000 */
+		u64 flags;
+		u8 padding0[0x200];
+	};
+	union { /* 0x200 */
+		u64 gprs[REC_RUN_GPRS];
+		u8 padding2[0x100];
+	};
+	union { /* 0x300 */
+		struct {
+			u64 gicv3_hcr;
+			u64 gicv3_lrs[REC_GIC_NUM_LRS];
+		};
+		u8 padding3[0x100];
+	};
+	u8 padding4[0x400];
+};
+
+struct rec_exit {
+	union { /* 0x000 */
+		u8 exit_reason;
+		u8 padding0[0x100];
+	};
+	union { /* 0x100 */
+		struct {
+			u64 esr;
+			u64 far;
+			u64 hpfar;
+		};
+		u8 padding1[0x100];
+	};
+	union { /* 0x200 */
+		u64 gprs[REC_RUN_GPRS];
+		u8 padding2[0x100];
+	};
+	union { /* 0x300 */
+		struct {
+			u64 gicv3_hcr;
+			u64 gicv3_lrs[REC_GIC_NUM_LRS];
+			u64 gicv3_misr;
+			u64 gicv3_vmcr;
+		};
+		u8 padding3[0x100];
+	};
+	union { /* 0x400 */
+		struct {
+			u64 cntp_ctl;
+			u64 cntp_cval;
+			u64 cntv_ctl;
+			u64 cntv_cval;
+		};
+		u8 padding4[0x100];
+	};
+	union { /* 0x500 */
+		struct {
+			u64 ripas_base;
+			u64 ripas_size;
+			u64 ripas_value; /* Only lowest bit */
+		};
+		u8 padding5[0x100];
+	};
+	union { /* 0x600 */
+		u16 imm;
+		u8 padding6[0x100];
+	};
+	union { /* 0x700 */
+		struct {
+			u64 pmu_ovf;
+			u64 pmu_intr_en;
+			u64 pmu_cntr_en;
+		};
+		u8 padding7[0x100];
+	};
+};
+
+struct rec_run {
+	struct rec_entry entry;
+	struct rec_exit exit;
+};
+
+#define RMI_EXIT_SYNC			0x00
+#define RMI_EXIT_IRQ			0x01
+#define RMI_EXIT_FIQ			0x02
+#define RMI_EXIT_PSCI			0x03
+#define RMI_EXIT_RIPAS_CHANGE		0x04
+#define RMI_EXIT_HOST_CALL		0x05
+#define RMI_EXIT_SERROR			0x06
+
+#endif
-- 
2.34.1


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

* [RFC PATCH 02/28] arm64: RME: Add SMC definitions for calling the RMM
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM (Realm Management Monitor) provides functionality that can be
accessed by SMC calls from the host.

The SMC definitions are based on DEN0137[1] version A-bet0.

[1] https://developer.arm.com/documentation/den0137/latest

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rmi_smc.h | 235 +++++++++++++++++++++++++++++++
 1 file changed, 235 insertions(+)
 create mode 100644 arch/arm64/include/asm/rmi_smc.h

diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
new file mode 100644
index 000000000000..16ff65090f3a
--- /dev/null
+++ b/arch/arm64/include/asm/rmi_smc.h
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RME_SMC_H
+#define __ASM_RME_SMC_H
+
+#include <linux/arm-smccc.h>
+
+#define SMC_RxI_CALL(func)				\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
+			   ARM_SMCCC_SMC_64,		\
+			   ARM_SMCCC_OWNER_STANDARD,	\
+			   (func))
+
+/* FID numbers from alp10 specification */
+
+#define SMC_RMI_DATA_CREATE		SMC_RxI_CALL(0x0153)
+#define SMC_RMI_DATA_CREATE_UNKNOWN	SMC_RxI_CALL(0x0154)
+#define SMC_RMI_DATA_DESTROY		SMC_RxI_CALL(0x0155)
+#define SMC_RMI_FEATURES		SMC_RxI_CALL(0x0165)
+#define SMC_RMI_GRANULE_DELEGATE	SMC_RxI_CALL(0x0151)
+#define SMC_RMI_GRANULE_UNDELEGATE	SMC_RxI_CALL(0x0152)
+#define SMC_RMI_PSCI_COMPLETE		SMC_RxI_CALL(0x0164)
+#define SMC_RMI_REALM_ACTIVATE		SMC_RxI_CALL(0x0157)
+#define SMC_RMI_REALM_CREATE		SMC_RxI_CALL(0x0158)
+#define SMC_RMI_REALM_DESTROY		SMC_RxI_CALL(0x0159)
+#define SMC_RMI_REC_AUX_COUNT		SMC_RxI_CALL(0x0167)
+#define SMC_RMI_REC_CREATE		SMC_RxI_CALL(0x015a)
+#define SMC_RMI_REC_DESTROY		SMC_RxI_CALL(0x015b)
+#define SMC_RMI_REC_ENTER		SMC_RxI_CALL(0x015c)
+#define SMC_RMI_RTT_CREATE		SMC_RxI_CALL(0x015d)
+#define SMC_RMI_RTT_DESTROY		SMC_RxI_CALL(0x015e)
+#define SMC_RMI_RTT_FOLD		SMC_RxI_CALL(0x0166)
+#define SMC_RMI_RTT_INIT_RIPAS		SMC_RxI_CALL(0x0168)
+#define SMC_RMI_RTT_MAP_UNPROTECTED	SMC_RxI_CALL(0x015f)
+#define SMC_RMI_RTT_READ_ENTRY		SMC_RxI_CALL(0x0161)
+#define SMC_RMI_RTT_SET_RIPAS		SMC_RxI_CALL(0x0169)
+#define SMC_RMI_RTT_UNMAP_UNPROTECTED	SMC_RxI_CALL(0x0162)
+#define SMC_RMI_VERSION			SMC_RxI_CALL(0x0150)
+
+#define RMI_ABI_MAJOR_VERSION	1
+#define RMI_ABI_MINOR_VERSION	0
+
+#define RMI_UNASSIGNED			0
+#define RMI_DESTROYED			1
+#define RMI_ASSIGNED			2
+#define RMI_TABLE			3
+#define RMI_VALID_NS			4
+
+#define RMI_ABI_VERSION_GET_MAJOR(version) ((version) >> 16)
+#define RMI_ABI_VERSION_GET_MINOR(version) ((version) & 0xFFFF)
+
+#define RMI_RETURN_STATUS(ret)		((ret) & 0xFF)
+#define RMI_RETURN_INDEX(ret)		(((ret) >> 8) & 0xFF)
+
+#define RMI_SUCCESS		0
+#define RMI_ERROR_INPUT		1
+#define RMI_ERROR_REALM		2
+#define RMI_ERROR_REC		3
+#define RMI_ERROR_RTT		4
+#define RMI_ERROR_IN_USE	5
+
+#define RMI_EMPTY		0
+#define RMI_RAM			1
+
+#define RMI_NO_MEASURE_CONTENT	0
+#define RMI_MEASURE_CONTENT	1
+
+#define RMI_FEATURE_REGISTER_0_S2SZ		GENMASK(7, 0)
+#define RMI_FEATURE_REGISTER_0_LPA2		BIT(8)
+#define RMI_FEATURE_REGISTER_0_SVE_EN		BIT(9)
+#define RMI_FEATURE_REGISTER_0_SVE_VL		GENMASK(13, 10)
+#define RMI_FEATURE_REGISTER_0_NUM_BPS		GENMASK(17, 14)
+#define RMI_FEATURE_REGISTER_0_NUM_WPS		GENMASK(21, 18)
+#define RMI_FEATURE_REGISTER_0_PMU_EN		BIT(22)
+#define RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS	GENMASK(27, 23)
+#define RMI_FEATURE_REGISTER_0_HASH_SHA_256	BIT(28)
+#define RMI_FEATURE_REGISTER_0_HASH_SHA_512	BIT(29)
+
+struct realm_params {
+	union {
+		u64 features_0;
+		u8 padding_1[0x100];
+	};
+	union {
+		u8 measurement_algo;
+		u8 padding_2[0x300];
+	};
+	union {
+		u8 rpv[64];
+		u8 padding_3[0x400];
+	};
+	union {
+		struct {
+			u16 vmid;
+			u8 padding_4[6];
+			u64 rtt_base;
+			u64 rtt_level_start;
+			u32 rtt_num_start;
+		};
+		u8 padding_5[0x800];
+	};
+};
+
+/*
+ * The number of GPRs (starting from X0) that are
+ * configured by the host when a REC is created.
+ */
+#define REC_CREATE_NR_GPRS		8
+
+#define REC_PARAMS_FLAG_RUNNABLE	BIT_ULL(0)
+
+#define REC_PARAMS_AUX_GRANULES		16
+
+struct rec_params {
+	union {
+		u64 flags;
+		u8 padding1[0x100];
+	};
+	union {
+		u64 mpidr;
+		u8 padding2[0x100];
+	};
+	union {
+		u64 pc;
+		u8 padding3[0x100];
+	};
+	union {
+		u64 gprs[REC_CREATE_NR_GPRS];
+		u8 padding4[0x500];
+	};
+	u64 num_rec_aux;
+	u64 aux[REC_PARAMS_AUX_GRANULES];
+};
+
+#define RMI_EMULATED_MMIO		BIT(0)
+#define RMI_INJECT_SEA			BIT(1)
+#define RMI_TRAP_WFI			BIT(2)
+#define RMI_TRAP_WFE			BIT(3)
+
+#define REC_RUN_GPRS			31
+#define REC_GIC_NUM_LRS			16
+
+struct rec_entry {
+	union { /* 0x000 */
+		u64 flags;
+		u8 padding0[0x200];
+	};
+	union { /* 0x200 */
+		u64 gprs[REC_RUN_GPRS];
+		u8 padding2[0x100];
+	};
+	union { /* 0x300 */
+		struct {
+			u64 gicv3_hcr;
+			u64 gicv3_lrs[REC_GIC_NUM_LRS];
+		};
+		u8 padding3[0x100];
+	};
+	u8 padding4[0x400];
+};
+
+struct rec_exit {
+	union { /* 0x000 */
+		u8 exit_reason;
+		u8 padding0[0x100];
+	};
+	union { /* 0x100 */
+		struct {
+			u64 esr;
+			u64 far;
+			u64 hpfar;
+		};
+		u8 padding1[0x100];
+	};
+	union { /* 0x200 */
+		u64 gprs[REC_RUN_GPRS];
+		u8 padding2[0x100];
+	};
+	union { /* 0x300 */
+		struct {
+			u64 gicv3_hcr;
+			u64 gicv3_lrs[REC_GIC_NUM_LRS];
+			u64 gicv3_misr;
+			u64 gicv3_vmcr;
+		};
+		u8 padding3[0x100];
+	};
+	union { /* 0x400 */
+		struct {
+			u64 cntp_ctl;
+			u64 cntp_cval;
+			u64 cntv_ctl;
+			u64 cntv_cval;
+		};
+		u8 padding4[0x100];
+	};
+	union { /* 0x500 */
+		struct {
+			u64 ripas_base;
+			u64 ripas_size;
+			u64 ripas_value; /* Only lowest bit */
+		};
+		u8 padding5[0x100];
+	};
+	union { /* 0x600 */
+		u16 imm;
+		u8 padding6[0x100];
+	};
+	union { /* 0x700 */
+		struct {
+			u64 pmu_ovf;
+			u64 pmu_intr_en;
+			u64 pmu_cntr_en;
+		};
+		u8 padding7[0x100];
+	};
+};
+
+struct rec_run {
+	struct rec_entry entry;
+	struct rec_exit exit;
+};
+
+#define RMI_EXIT_SYNC			0x00
+#define RMI_EXIT_IRQ			0x01
+#define RMI_EXIT_FIQ			0x02
+#define RMI_EXIT_PSCI			0x03
+#define RMI_EXIT_RIPAS_CHANGE		0x04
+#define RMI_EXIT_HOST_CALL		0x05
+#define RMI_EXIT_SERROR			0x06
+
+#endif
-- 
2.34.1


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

* [RFC PATCH 03/28] arm64: RME: Add wrappers for RMI calls
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The wrappers make the call sites easier to read and deal with the
boiler plate of handling the error codes from the RMM.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rmi_cmds.h | 259 ++++++++++++++++++++++++++++++
 1 file changed, 259 insertions(+)
 create mode 100644 arch/arm64/include/asm/rmi_cmds.h

diff --git a/arch/arm64/include/asm/rmi_cmds.h b/arch/arm64/include/asm/rmi_cmds.h
new file mode 100644
index 000000000000..d5468ee46f35
--- /dev/null
+++ b/arch/arm64/include/asm/rmi_cmds.h
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RMI_CMDS_H
+#define __ASM_RMI_CMDS_H
+
+#include <linux/arm-smccc.h>
+
+#include <asm/rmi_smc.h>
+
+struct rtt_entry {
+	unsigned long walk_level;
+	unsigned long desc;
+	int state;
+	bool ripas;
+};
+
+static inline int rmi_data_create(unsigned long data, unsigned long rd,
+				  unsigned long map_addr, unsigned long src,
+				  unsigned long flags)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_CREATE, data, rd, map_addr, src,
+			     flags, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_data_create_unknown(unsigned long data,
+					  unsigned long rd,
+					  unsigned long map_addr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_CREATE_UNKNOWN, data, rd, map_addr,
+			     &res);
+
+	return res.a0;
+}
+
+static inline int rmi_data_destroy(unsigned long rd, unsigned long map_addr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_DESTROY, rd, map_addr, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_features(unsigned long index, unsigned long *out)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_FEATURES, index, &res);
+
+	*out = res.a1;
+	return res.a0;
+}
+
+static inline int rmi_granule_delegate(unsigned long phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_GRANULE_DELEGATE, phys, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_granule_undelegate(unsigned long phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_GRANULE_UNDELEGATE, phys, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_psci_complete(unsigned long calling_rec,
+				    unsigned long target_rec)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PSCI_COMPLETE, calling_rec, target_rec,
+			     &res);
+
+	return res.a0;
+}
+
+static inline int rmi_realm_activate(unsigned long rd)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_ACTIVATE, rd, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_realm_create(unsigned long rd, unsigned long params_ptr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_CREATE, rd, params_ptr, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_realm_destroy(unsigned long rd)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_DESTROY, rd, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rec_aux_count(unsigned long rd, unsigned long *aux_count)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_AUX_COUNT, rd, &res);
+
+	*aux_count = res.a1;
+	return res.a0;
+}
+
+static inline int rmi_rec_create(unsigned long rec, unsigned long rd,
+				 unsigned long params_ptr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_CREATE, rec, rd, params_ptr, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rec_destroy(unsigned long rec)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_DESTROY, rec, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rec_enter(unsigned long rec, unsigned long run_ptr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_ENTER, rec, run_ptr, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_create(unsigned long rtt, unsigned long rd,
+				 unsigned long map_addr, unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_CREATE, rtt, rd, map_addr, level,
+			     &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_destroy(unsigned long rtt, unsigned long rd,
+				  unsigned long map_addr, unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_DESTROY, rtt, rd, map_addr, level,
+			     &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_fold(unsigned long rtt, unsigned long rd,
+			       unsigned long map_addr, unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_FOLD, rtt, rd, map_addr, level, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_init_ripas(unsigned long rd, unsigned long map_addr,
+				     unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_INIT_RIPAS, rd, map_addr, level, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_map_unprotected(unsigned long rd,
+					  unsigned long map_addr,
+					  unsigned long level,
+					  unsigned long desc)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_MAP_UNPROTECTED, rd, map_addr, level,
+			     desc, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_read_entry(unsigned long rd, unsigned long map_addr,
+				     unsigned long level, struct rtt_entry *rtt)
+{
+	struct arm_smccc_1_2_regs regs = {
+		SMC_RMI_RTT_READ_ENTRY,
+		rd, map_addr, level
+	};
+
+	arm_smccc_1_2_smc(&regs, &regs);
+
+	rtt->walk_level = regs.a1;
+	rtt->state = regs.a2 & 0xFF;
+	rtt->desc = regs.a3;
+	rtt->ripas = regs.a4 & 1;
+
+	return regs.a0;
+}
+
+static inline int rmi_rtt_set_ripas(unsigned long rd, unsigned long rec,
+				    unsigned long map_addr, unsigned long level,
+				    unsigned long ripas)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_SET_RIPAS, rd, rec, map_addr, level,
+			     ripas, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_unmap_unprotected(unsigned long rd,
+					    unsigned long map_addr,
+					    unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_UNMAP_UNPROTECTED, rd, map_addr,
+			     level, &res);
+
+	return res.a0;
+}
+
+static inline phys_addr_t rmi_rtt_get_phys(struct rtt_entry *rtt)
+{
+	return rtt->desc & GENMASK(47, 12);
+}
+
+#endif
-- 
2.34.1


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

* [RFC PATCH 03/28] arm64: RME: Add wrappers for RMI calls
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The wrappers make the call sites easier to read and deal with the
boiler plate of handling the error codes from the RMM.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rmi_cmds.h | 259 ++++++++++++++++++++++++++++++
 1 file changed, 259 insertions(+)
 create mode 100644 arch/arm64/include/asm/rmi_cmds.h

diff --git a/arch/arm64/include/asm/rmi_cmds.h b/arch/arm64/include/asm/rmi_cmds.h
new file mode 100644
index 000000000000..d5468ee46f35
--- /dev/null
+++ b/arch/arm64/include/asm/rmi_cmds.h
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_RMI_CMDS_H
+#define __ASM_RMI_CMDS_H
+
+#include <linux/arm-smccc.h>
+
+#include <asm/rmi_smc.h>
+
+struct rtt_entry {
+	unsigned long walk_level;
+	unsigned long desc;
+	int state;
+	bool ripas;
+};
+
+static inline int rmi_data_create(unsigned long data, unsigned long rd,
+				  unsigned long map_addr, unsigned long src,
+				  unsigned long flags)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_CREATE, data, rd, map_addr, src,
+			     flags, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_data_create_unknown(unsigned long data,
+					  unsigned long rd,
+					  unsigned long map_addr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_CREATE_UNKNOWN, data, rd, map_addr,
+			     &res);
+
+	return res.a0;
+}
+
+static inline int rmi_data_destroy(unsigned long rd, unsigned long map_addr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_DATA_DESTROY, rd, map_addr, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_features(unsigned long index, unsigned long *out)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_FEATURES, index, &res);
+
+	*out = res.a1;
+	return res.a0;
+}
+
+static inline int rmi_granule_delegate(unsigned long phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_GRANULE_DELEGATE, phys, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_granule_undelegate(unsigned long phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_GRANULE_UNDELEGATE, phys, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_psci_complete(unsigned long calling_rec,
+				    unsigned long target_rec)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PSCI_COMPLETE, calling_rec, target_rec,
+			     &res);
+
+	return res.a0;
+}
+
+static inline int rmi_realm_activate(unsigned long rd)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_ACTIVATE, rd, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_realm_create(unsigned long rd, unsigned long params_ptr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_CREATE, rd, params_ptr, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_realm_destroy(unsigned long rd)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REALM_DESTROY, rd, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rec_aux_count(unsigned long rd, unsigned long *aux_count)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_AUX_COUNT, rd, &res);
+
+	*aux_count = res.a1;
+	return res.a0;
+}
+
+static inline int rmi_rec_create(unsigned long rec, unsigned long rd,
+				 unsigned long params_ptr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_CREATE, rec, rd, params_ptr, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rec_destroy(unsigned long rec)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_DESTROY, rec, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rec_enter(unsigned long rec, unsigned long run_ptr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_REC_ENTER, rec, run_ptr, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_create(unsigned long rtt, unsigned long rd,
+				 unsigned long map_addr, unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_CREATE, rtt, rd, map_addr, level,
+			     &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_destroy(unsigned long rtt, unsigned long rd,
+				  unsigned long map_addr, unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_DESTROY, rtt, rd, map_addr, level,
+			     &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_fold(unsigned long rtt, unsigned long rd,
+			       unsigned long map_addr, unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_FOLD, rtt, rd, map_addr, level, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_init_ripas(unsigned long rd, unsigned long map_addr,
+				     unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_INIT_RIPAS, rd, map_addr, level, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_map_unprotected(unsigned long rd,
+					  unsigned long map_addr,
+					  unsigned long level,
+					  unsigned long desc)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_MAP_UNPROTECTED, rd, map_addr, level,
+			     desc, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_read_entry(unsigned long rd, unsigned long map_addr,
+				     unsigned long level, struct rtt_entry *rtt)
+{
+	struct arm_smccc_1_2_regs regs = {
+		SMC_RMI_RTT_READ_ENTRY,
+		rd, map_addr, level
+	};
+
+	arm_smccc_1_2_smc(&regs, &regs);
+
+	rtt->walk_level = regs.a1;
+	rtt->state = regs.a2 & 0xFF;
+	rtt->desc = regs.a3;
+	rtt->ripas = regs.a4 & 1;
+
+	return regs.a0;
+}
+
+static inline int rmi_rtt_set_ripas(unsigned long rd, unsigned long rec,
+				    unsigned long map_addr, unsigned long level,
+				    unsigned long ripas)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_SET_RIPAS, rd, rec, map_addr, level,
+			     ripas, &res);
+
+	return res.a0;
+}
+
+static inline int rmi_rtt_unmap_unprotected(unsigned long rd,
+					    unsigned long map_addr,
+					    unsigned long level)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_RTT_UNMAP_UNPROTECTED, rd, map_addr,
+			     level, &res);
+
+	return res.a0;
+}
+
+static inline phys_addr_t rmi_rtt_get_phys(struct rtt_entry *rtt)
+{
+	return rtt->desc & GENMASK(47, 12);
+}
+
+#endif
-- 
2.34.1


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

* [RFC PATCH 04/28] arm64: RME: Check for RME support at KVM init
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Query the RMI version number and check if it is a compatible version. A
static key is also provided to signal that a supported RMM is available.

Functions are provided to query if a VM or VCPU is a realm (or rec)
which currently will always return false.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h | 17 ++++++++++
 arch/arm64/include/asm/kvm_host.h    |  4 +++
 arch/arm64/include/asm/kvm_rme.h     | 22 +++++++++++++
 arch/arm64/include/asm/virt.h        |  1 +
 arch/arm64/kvm/Makefile              |  3 +-
 arch/arm64/kvm/arm.c                 |  8 +++++
 arch/arm64/kvm/rme.c                 | 49 ++++++++++++++++++++++++++++
 7 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/include/asm/kvm_rme.h
 create mode 100644 arch/arm64/kvm/rme.c

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9bdba47f7e14..5a2b7229e83f 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -490,4 +490,21 @@ static inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature)
 	return test_bit(feature, vcpu->arch.features);
 }
 
+static inline bool kvm_is_realm(struct kvm *kvm)
+{
+	if (static_branch_unlikely(&kvm_rme_is_available))
+		return kvm->arch.is_realm;
+	return false;
+}
+
+static inline enum realm_state kvm_realm_state(struct kvm *kvm)
+{
+	return READ_ONCE(kvm->arch.realm.state);
+}
+
+static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+
 #endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 35a159d131b5..04347c3a8c6b 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -26,6 +26,7 @@
 #include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_asm.h>
+#include <asm/kvm_rme.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
 
@@ -240,6 +241,9 @@ struct kvm_arch {
 	 * the associated pKVM instance in the hypervisor.
 	 */
 	struct kvm_protected_vm pkvm;
+
+	bool is_realm;
+	struct realm realm;
 };
 
 struct kvm_vcpu_fault_info {
diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
new file mode 100644
index 000000000000..c26bc2c6770d
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_KVM_RME_H
+#define __ASM_KVM_RME_H
+
+enum realm_state {
+	REALM_STATE_NONE,
+	REALM_STATE_NEW,
+	REALM_STATE_ACTIVE,
+	REALM_STATE_DYING
+};
+
+struct realm {
+	enum realm_state state;
+};
+
+int kvm_init_rme(void);
+
+#endif
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index 4eb601e7de50..be1383e26626 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -80,6 +80,7 @@ void __hyp_set_vectors(phys_addr_t phys_vector_base);
 void __hyp_reset_vectors(void);
 
 DECLARE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
+DECLARE_STATIC_KEY_FALSE(kvm_rme_is_available);
 
 /* Reports the availability of HYP mode */
 static inline bool is_hyp_mode_available(void)
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 5e33c2d4645a..d2f0400c50da 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -20,7 +20,8 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 	 vgic/vgic-v3.o vgic/vgic-v4.o \
 	 vgic/vgic-mmio.o vgic/vgic-mmio-v2.o \
 	 vgic/vgic-mmio-v3.o vgic/vgic-kvm-device.o \
-	 vgic/vgic-its.o vgic/vgic-debug.o
+	 vgic/vgic-its.o vgic/vgic-debug.o \
+	 rme.o
 
 kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 9c5573bc4614..d97b39d042ab 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -38,6 +38,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_pkvm.h>
+#include <asm/kvm_rme.h>
 #include <asm/kvm_emulate.h>
 #include <asm/sections.h>
 
@@ -47,6 +48,7 @@
 
 static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
 DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
+DEFINE_STATIC_KEY_FALSE(kvm_rme_is_available);
 
 DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
 
@@ -2213,6 +2215,12 @@ int kvm_arch_init(void *opaque)
 
 	in_hyp_mode = is_kernel_in_hyp_mode();
 
+	if (in_hyp_mode) {
+		err = kvm_init_rme();
+		if (err)
+			return err;
+	}
+
 	if (cpus_have_final_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ||
 	    cpus_have_final_cap(ARM64_WORKAROUND_1508412))
 		kvm_info("Guests without required CPU erratum workarounds can deadlock system!\n" \
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
new file mode 100644
index 000000000000..f6b587bc116e
--- /dev/null
+++ b/arch/arm64/kvm/rme.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#include <linux/kvm_host.h>
+
+#include <asm/rmi_cmds.h>
+#include <asm/virt.h>
+
+static int rmi_check_version(void)
+{
+	struct arm_smccc_res res;
+	int version_major, version_minor;
+
+	arm_smccc_1_1_invoke(SMC_RMI_VERSION, &res);
+
+	if (res.a0 == SMCCC_RET_NOT_SUPPORTED)
+		return -ENXIO;
+
+	version_major = RMI_ABI_VERSION_GET_MAJOR(res.a0);
+	version_minor = RMI_ABI_VERSION_GET_MINOR(res.a0);
+
+	if (version_major != RMI_ABI_MAJOR_VERSION) {
+		kvm_err("Unsupported RMI ABI (version %d.%d) we support %d\n",
+			version_major, version_minor,
+			RMI_ABI_MAJOR_VERSION);
+		return -ENXIO;
+	}
+
+	kvm_info("RMI ABI version %d.%d\n", version_major, version_minor);
+
+	return 0;
+}
+
+int kvm_init_rme(void)
+{
+	if (PAGE_SIZE != SZ_4K)
+		/* Only 4k page size on the host is supported */
+		return 0;
+
+	if (rmi_check_version())
+		/* Continue without realm support */
+		return 0;
+
+	/* Future patch will enable static branch kvm_rme_is_available */
+
+	return 0;
+}
-- 
2.34.1


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

* [RFC PATCH 04/28] arm64: RME: Check for RME support at KVM init
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Query the RMI version number and check if it is a compatible version. A
static key is also provided to signal that a supported RMM is available.

Functions are provided to query if a VM or VCPU is a realm (or rec)
which currently will always return false.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h | 17 ++++++++++
 arch/arm64/include/asm/kvm_host.h    |  4 +++
 arch/arm64/include/asm/kvm_rme.h     | 22 +++++++++++++
 arch/arm64/include/asm/virt.h        |  1 +
 arch/arm64/kvm/Makefile              |  3 +-
 arch/arm64/kvm/arm.c                 |  8 +++++
 arch/arm64/kvm/rme.c                 | 49 ++++++++++++++++++++++++++++
 7 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/include/asm/kvm_rme.h
 create mode 100644 arch/arm64/kvm/rme.c

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9bdba47f7e14..5a2b7229e83f 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -490,4 +490,21 @@ static inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature)
 	return test_bit(feature, vcpu->arch.features);
 }
 
+static inline bool kvm_is_realm(struct kvm *kvm)
+{
+	if (static_branch_unlikely(&kvm_rme_is_available))
+		return kvm->arch.is_realm;
+	return false;
+}
+
+static inline enum realm_state kvm_realm_state(struct kvm *kvm)
+{
+	return READ_ONCE(kvm->arch.realm.state);
+}
+
+static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+
 #endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 35a159d131b5..04347c3a8c6b 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -26,6 +26,7 @@
 #include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_asm.h>
+#include <asm/kvm_rme.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
 
@@ -240,6 +241,9 @@ struct kvm_arch {
 	 * the associated pKVM instance in the hypervisor.
 	 */
 	struct kvm_protected_vm pkvm;
+
+	bool is_realm;
+	struct realm realm;
 };
 
 struct kvm_vcpu_fault_info {
diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
new file mode 100644
index 000000000000..c26bc2c6770d
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#ifndef __ASM_KVM_RME_H
+#define __ASM_KVM_RME_H
+
+enum realm_state {
+	REALM_STATE_NONE,
+	REALM_STATE_NEW,
+	REALM_STATE_ACTIVE,
+	REALM_STATE_DYING
+};
+
+struct realm {
+	enum realm_state state;
+};
+
+int kvm_init_rme(void);
+
+#endif
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index 4eb601e7de50..be1383e26626 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -80,6 +80,7 @@ void __hyp_set_vectors(phys_addr_t phys_vector_base);
 void __hyp_reset_vectors(void);
 
 DECLARE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
+DECLARE_STATIC_KEY_FALSE(kvm_rme_is_available);
 
 /* Reports the availability of HYP mode */
 static inline bool is_hyp_mode_available(void)
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 5e33c2d4645a..d2f0400c50da 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -20,7 +20,8 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 	 vgic/vgic-v3.o vgic/vgic-v4.o \
 	 vgic/vgic-mmio.o vgic/vgic-mmio-v2.o \
 	 vgic/vgic-mmio-v3.o vgic/vgic-kvm-device.o \
-	 vgic/vgic-its.o vgic/vgic-debug.o
+	 vgic/vgic-its.o vgic/vgic-debug.o \
+	 rme.o
 
 kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 9c5573bc4614..d97b39d042ab 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -38,6 +38,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_pkvm.h>
+#include <asm/kvm_rme.h>
 #include <asm/kvm_emulate.h>
 #include <asm/sections.h>
 
@@ -47,6 +48,7 @@
 
 static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
 DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
+DEFINE_STATIC_KEY_FALSE(kvm_rme_is_available);
 
 DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
 
@@ -2213,6 +2215,12 @@ int kvm_arch_init(void *opaque)
 
 	in_hyp_mode = is_kernel_in_hyp_mode();
 
+	if (in_hyp_mode) {
+		err = kvm_init_rme();
+		if (err)
+			return err;
+	}
+
 	if (cpus_have_final_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ||
 	    cpus_have_final_cap(ARM64_WORKAROUND_1508412))
 		kvm_info("Guests without required CPU erratum workarounds can deadlock system!\n" \
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
new file mode 100644
index 000000000000..f6b587bc116e
--- /dev/null
+++ b/arch/arm64/kvm/rme.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#include <linux/kvm_host.h>
+
+#include <asm/rmi_cmds.h>
+#include <asm/virt.h>
+
+static int rmi_check_version(void)
+{
+	struct arm_smccc_res res;
+	int version_major, version_minor;
+
+	arm_smccc_1_1_invoke(SMC_RMI_VERSION, &res);
+
+	if (res.a0 == SMCCC_RET_NOT_SUPPORTED)
+		return -ENXIO;
+
+	version_major = RMI_ABI_VERSION_GET_MAJOR(res.a0);
+	version_minor = RMI_ABI_VERSION_GET_MINOR(res.a0);
+
+	if (version_major != RMI_ABI_MAJOR_VERSION) {
+		kvm_err("Unsupported RMI ABI (version %d.%d) we support %d\n",
+			version_major, version_minor,
+			RMI_ABI_MAJOR_VERSION);
+		return -ENXIO;
+	}
+
+	kvm_info("RMI ABI version %d.%d\n", version_major, version_minor);
+
+	return 0;
+}
+
+int kvm_init_rme(void)
+{
+	if (PAGE_SIZE != SZ_4K)
+		/* Only 4k page size on the host is supported */
+		return 0;
+
+	if (rmi_check_version())
+		/* Continue without realm support */
+		return 0;
+
+	/* Future patch will enable static branch kvm_rme_is_available */
+
+	return 0;
+}
-- 
2.34.1


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

* [RFC PATCH 05/28] arm64: RME: Define the user ABI
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

There is one (multiplexed) CAP which can be used to create, populate and
then activate the realm.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 Documentation/virt/kvm/api.rst    |  1 +
 arch/arm64/include/uapi/asm/kvm.h | 63 +++++++++++++++++++++++++++++++
 include/uapi/linux/kvm.h          |  2 +
 3 files changed, 66 insertions(+)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 0dd5d8733dd5..f1a59d6fb7fc 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -4965,6 +4965,7 @@ Recognised values for feature:
 
   =====      ===========================================
   arm64      KVM_ARM_VCPU_SVE (requires KVM_CAP_ARM_SVE)
+  arm64      KVM_ARM_VCPU_REC (requires KVM_CAP_ARM_RME)
   =====      ===========================================
 
 Finalizes the configuration of the specified vcpu feature.
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index a7a857f1784d..fcc0b8dce29b 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -109,6 +109,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
 #define KVM_ARM_VCPU_PTRAUTH_ADDRESS	5 /* VCPU uses address authentication */
 #define KVM_ARM_VCPU_PTRAUTH_GENERIC	6 /* VCPU uses generic authentication */
+#define KVM_ARM_VCPU_REC		7 /* VCPU REC state as part of Realm */
 
 struct kvm_vcpu_init {
 	__u32 target;
@@ -401,6 +402,68 @@ enum {
 #define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 #define   KVM_DEV_ARM_ITS_CTRL_RESET		4
 
+/* KVM_CAP_ARM_RME on VM fd */
+#define KVM_CAP_ARM_RME_CONFIG_REALM		0
+#define KVM_CAP_ARM_RME_CREATE_RD		1
+#define KVM_CAP_ARM_RME_INIT_IPA_REALM		2
+#define KVM_CAP_ARM_RME_POPULATE_REALM		3
+#define KVM_CAP_ARM_RME_ACTIVATE_REALM		4
+
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256		0
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA512		1
+
+#define KVM_CAP_ARM_RME_RPV_SIZE 64
+
+/* List of configuration items accepted for KVM_CAP_ARM_RME_CONFIG_REALM */
+#define KVM_CAP_ARM_RME_CFG_RPV			0
+#define KVM_CAP_ARM_RME_CFG_HASH_ALGO		1
+#define KVM_CAP_ARM_RME_CFG_SVE			2
+#define KVM_CAP_ARM_RME_CFG_DBG			3
+#define KVM_CAP_ARM_RME_CFG_PMU			4
+
+struct kvm_cap_arm_rme_config_item {
+	__u32 cfg;
+	union {
+		/* cfg == KVM_CAP_ARM_RME_CFG_RPV */
+		struct {
+			__u8	rpv[KVM_CAP_ARM_RME_RPV_SIZE];
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_HASH_ALGO */
+		struct {
+			__u32	hash_algo;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_SVE */
+		struct {
+			__u32	sve_vq;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_DBG */
+		struct {
+			__u32	num_brps;
+			__u32	num_wrps;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_PMU */
+		struct {
+			__u32	num_pmu_cntrs;
+		};
+		/* Fix the size of the union */
+		__u8	reserved[256];
+	};
+};
+
+struct kvm_cap_arm_rme_populate_realm_args {
+	__u64 populate_ipa_base;
+	__u64 populate_ipa_size;
+};
+
+struct kvm_cap_arm_rme_init_ipa_args {
+	__u64 init_ipa_base;
+	__u64 init_ipa_size;
+};
+
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
 #define   KVM_ARM_VCPU_PMU_V3_IRQ	0
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 20522d4ba1e0..fec1909e8b73 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1176,6 +1176,8 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_S390_PROTECTED_ASYNC_DISABLE 224
 #define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225
 
+#define KVM_CAP_ARM_RME 300 // FIXME: Large number to prevent conflicts
+
 #ifdef KVM_CAP_IRQ_ROUTING
 
 struct kvm_irq_routing_irqchip {
-- 
2.34.1


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

* [RFC PATCH 05/28] arm64: RME: Define the user ABI
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

There is one (multiplexed) CAP which can be used to create, populate and
then activate the realm.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 Documentation/virt/kvm/api.rst    |  1 +
 arch/arm64/include/uapi/asm/kvm.h | 63 +++++++++++++++++++++++++++++++
 include/uapi/linux/kvm.h          |  2 +
 3 files changed, 66 insertions(+)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 0dd5d8733dd5..f1a59d6fb7fc 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -4965,6 +4965,7 @@ Recognised values for feature:
 
   =====      ===========================================
   arm64      KVM_ARM_VCPU_SVE (requires KVM_CAP_ARM_SVE)
+  arm64      KVM_ARM_VCPU_REC (requires KVM_CAP_ARM_RME)
   =====      ===========================================
 
 Finalizes the configuration of the specified vcpu feature.
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index a7a857f1784d..fcc0b8dce29b 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -109,6 +109,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
 #define KVM_ARM_VCPU_PTRAUTH_ADDRESS	5 /* VCPU uses address authentication */
 #define KVM_ARM_VCPU_PTRAUTH_GENERIC	6 /* VCPU uses generic authentication */
+#define KVM_ARM_VCPU_REC		7 /* VCPU REC state as part of Realm */
 
 struct kvm_vcpu_init {
 	__u32 target;
@@ -401,6 +402,68 @@ enum {
 #define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 #define   KVM_DEV_ARM_ITS_CTRL_RESET		4
 
+/* KVM_CAP_ARM_RME on VM fd */
+#define KVM_CAP_ARM_RME_CONFIG_REALM		0
+#define KVM_CAP_ARM_RME_CREATE_RD		1
+#define KVM_CAP_ARM_RME_INIT_IPA_REALM		2
+#define KVM_CAP_ARM_RME_POPULATE_REALM		3
+#define KVM_CAP_ARM_RME_ACTIVATE_REALM		4
+
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256		0
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA512		1
+
+#define KVM_CAP_ARM_RME_RPV_SIZE 64
+
+/* List of configuration items accepted for KVM_CAP_ARM_RME_CONFIG_REALM */
+#define KVM_CAP_ARM_RME_CFG_RPV			0
+#define KVM_CAP_ARM_RME_CFG_HASH_ALGO		1
+#define KVM_CAP_ARM_RME_CFG_SVE			2
+#define KVM_CAP_ARM_RME_CFG_DBG			3
+#define KVM_CAP_ARM_RME_CFG_PMU			4
+
+struct kvm_cap_arm_rme_config_item {
+	__u32 cfg;
+	union {
+		/* cfg == KVM_CAP_ARM_RME_CFG_RPV */
+		struct {
+			__u8	rpv[KVM_CAP_ARM_RME_RPV_SIZE];
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_HASH_ALGO */
+		struct {
+			__u32	hash_algo;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_SVE */
+		struct {
+			__u32	sve_vq;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_DBG */
+		struct {
+			__u32	num_brps;
+			__u32	num_wrps;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_PMU */
+		struct {
+			__u32	num_pmu_cntrs;
+		};
+		/* Fix the size of the union */
+		__u8	reserved[256];
+	};
+};
+
+struct kvm_cap_arm_rme_populate_realm_args {
+	__u64 populate_ipa_base;
+	__u64 populate_ipa_size;
+};
+
+struct kvm_cap_arm_rme_init_ipa_args {
+	__u64 init_ipa_base;
+	__u64 init_ipa_size;
+};
+
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
 #define   KVM_ARM_VCPU_PMU_V3_IRQ	0
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 20522d4ba1e0..fec1909e8b73 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1176,6 +1176,8 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_S390_PROTECTED_ASYNC_DISABLE 224
 #define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225
 
+#define KVM_CAP_ARM_RME 300 // FIXME: Large number to prevent conflicts
+
 #ifdef KVM_CAP_IRQ_ROUTING
 
 struct kvm_irq_routing_irqchip {
-- 
2.34.1


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

* [RFC PATCH 06/28] arm64: RME: ioctls to create and configure realms
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Add the KVM_CAP_ARM_RME_CREATE_FD ioctl to create a realm. This involves
delegating pages to the RMM to hold the Realm Descriptor (RD) and for
the base level of the Realm Translation Tables (RTT). A VMID also need
to be picked, since the RMM has a separate VMID address space a
dedicated allocator is added for this purpose.

KVM_CAP_ARM_RME_CONFIG_REALM is provided to allow configuring the realm
before it is created.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |  14 ++
 arch/arm64/kvm/arm.c             |  19 ++
 arch/arm64/kvm/mmu.c             |   6 +
 arch/arm64/kvm/reset.c           |  33 +++
 arch/arm64/kvm/rme.c             | 357 +++++++++++++++++++++++++++++++
 5 files changed, 429 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index c26bc2c6770d..055a22accc08 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -6,6 +6,8 @@
 #ifndef __ASM_KVM_RME_H
 #define __ASM_KVM_RME_H
 
+#include <uapi/linux/kvm.h>
+
 enum realm_state {
 	REALM_STATE_NONE,
 	REALM_STATE_NEW,
@@ -15,8 +17,20 @@ enum realm_state {
 
 struct realm {
 	enum realm_state state;
+
+	void *rd;
+	struct realm_params *params;
+
+	unsigned long num_aux;
+	unsigned int vmid;
+	unsigned int ia_bits;
 };
 
 int kvm_init_rme(void);
+u32 kvm_realm_ipa_limit(void);
+
+int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap);
+int kvm_init_realm_vm(struct kvm *kvm);
+void kvm_destroy_realm(struct kvm *kvm);
 
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index d97b39d042ab..50f54a63732a 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -103,6 +103,13 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 		r = 0;
 		set_bit(KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED, &kvm->arch.flags);
 		break;
+	case KVM_CAP_ARM_RME:
+		if (!static_branch_unlikely(&kvm_rme_is_available))
+			return -EINVAL;
+		mutex_lock(&kvm->lock);
+		r = kvm_realm_enable_cap(kvm, cap);
+		mutex_unlock(&kvm->lock);
+		break;
 	default:
 		r = -EINVAL;
 		break;
@@ -172,6 +179,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	 */
 	kvm->arch.dfr0_pmuver.imp = kvm_arm_pmu_get_pmuver_limit();
 
+	/* Initialise the realm bits after the generic bits are enabled */
+	if (kvm_is_realm(kvm)) {
+		ret = kvm_init_realm_vm(kvm);
+		if (ret)
+			goto err_free_cpumask;
+	}
+
 	return 0;
 
 err_free_cpumask:
@@ -204,6 +218,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 	kvm_destroy_vcpus(kvm);
 
 	kvm_unshare_hyp(kvm, kvm + 1);
+
+	kvm_destroy_realm(kvm);
 }
 
 int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
@@ -300,6 +316,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
 		r = system_has_full_ptr_auth();
 		break;
+	case KVM_CAP_ARM_RME:
+		r = static_key_enabled(&kvm_rme_is_available);
+		break;
 	default:
 		r = 0;
 	}
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 31d7fa4c7c14..d0f707767d05 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -840,6 +840,12 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 	struct kvm_pgtable *pgt = NULL;
 
 	write_lock(&kvm->mmu_lock);
+	if (kvm_is_realm(kvm) &&
+	    kvm_realm_state(kvm) != REALM_STATE_DYING) {
+		/* TODO: teardown rtts */
+		write_unlock(&kvm->mmu_lock);
+		return;
+	}
 	pgt = mmu->pgt;
 	if (pgt) {
 		mmu->pgd_phys = 0;
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index e0267f672b8a..c165df174737 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -395,3 +395,36 @@ int kvm_set_ipa_limit(void)
 
 	return 0;
 }
+
+int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
+{
+	u64 mmfr0, mmfr1;
+	u32 phys_shift;
+	u32 ipa_limit = kvm_ipa_limit;
+
+	if (kvm_is_realm(kvm))
+		ipa_limit = kvm_realm_ipa_limit();
+
+	if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+		return -EINVAL;
+
+	phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
+	if (phys_shift) {
+		if (phys_shift > ipa_limit ||
+		    phys_shift < ARM64_MIN_PARANGE_BITS)
+			return -EINVAL;
+	} else {
+		phys_shift = KVM_PHYS_SHIFT;
+		if (phys_shift > ipa_limit) {
+			pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n",
+				     current->comm);
+			return -EINVAL;
+		}
+	}
+
+	mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+	mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
+	kvm->arch.vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift);
+
+	return 0;
+}
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index f6b587bc116e..9f8c5a91b8fc 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -5,9 +5,49 @@
 
 #include <linux/kvm_host.h>
 
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_mmu.h>
 #include <asm/rmi_cmds.h>
 #include <asm/virt.h>
 
+/************ FIXME: Copied from kvm/hyp/pgtable.c **********/
+#include <asm/kvm_pgtable.h>
+
+struct kvm_pgtable_walk_data {
+	struct kvm_pgtable		*pgt;
+	struct kvm_pgtable_walker	*walker;
+
+	u64				addr;
+	u64				end;
+};
+
+static u32 __kvm_pgd_page_idx(struct kvm_pgtable *pgt, u64 addr)
+{
+	u64 shift = kvm_granule_shift(pgt->start_level - 1); /* May underflow */
+	u64 mask = BIT(pgt->ia_bits) - 1;
+
+	return (addr & mask) >> shift;
+}
+
+static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
+{
+	struct kvm_pgtable pgt = {
+		.ia_bits	= ia_bits,
+		.start_level	= start_level,
+	};
+
+	return __kvm_pgd_page_idx(&pgt, -1ULL) + 1;
+}
+
+/******************/
+
+static unsigned long rmm_feat_reg0;
+
+static bool rme_supports(unsigned long feature)
+{
+	return !!u64_get_bits(rmm_feat_reg0, feature);
+}
+
 static int rmi_check_version(void)
 {
 	struct arm_smccc_res res;
@@ -33,8 +73,319 @@ static int rmi_check_version(void)
 	return 0;
 }
 
+static unsigned long create_realm_feat_reg0(struct kvm *kvm)
+{
+	unsigned long ia_bits = VTCR_EL2_IPA(kvm->arch.vtcr);
+	u64 feat_reg0 = 0;
+
+	int num_bps = u64_get_bits(rmm_feat_reg0,
+				   RMI_FEATURE_REGISTER_0_NUM_BPS);
+	int num_wps = u64_get_bits(rmm_feat_reg0,
+				   RMI_FEATURE_REGISTER_0_NUM_WPS);
+
+	feat_reg0 |= u64_encode_bits(ia_bits, RMI_FEATURE_REGISTER_0_S2SZ);
+	feat_reg0 |= u64_encode_bits(num_bps, RMI_FEATURE_REGISTER_0_NUM_BPS);
+	feat_reg0 |= u64_encode_bits(num_wps, RMI_FEATURE_REGISTER_0_NUM_WPS);
+
+	return feat_reg0;
+}
+
+u32 kvm_realm_ipa_limit(void)
+{
+	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_S2SZ);
+}
+
+static u32 get_start_level(struct kvm *kvm)
+{
+	long sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, kvm->arch.vtcr);
+
+	return VTCR_EL2_TGRAN_SL0_BASE - sl0;
+}
+
+static int realm_create_rd(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct realm_params *params = realm->params;
+	void *rd = NULL;
+	phys_addr_t rd_phys, params_phys;
+	struct kvm_pgtable *pgt = kvm->arch.mmu.pgt;
+	unsigned int pgd_sz;
+	int i, r;
+
+	if (WARN_ON(realm->rd) || WARN_ON(!realm->params))
+		return -EEXIST;
+
+	rd = (void *)__get_free_page(GFP_KERNEL);
+	if (!rd)
+		return -ENOMEM;
+
+	rd_phys = virt_to_phys(rd);
+	if (rmi_granule_delegate(rd_phys)) {
+		r = -ENXIO;
+		goto out;
+	}
+
+	pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level);
+	for (i = 0; i < pgd_sz; i++) {
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i * PAGE_SIZE;
+
+		if (rmi_granule_delegate(pgd_phys)) {
+			r = -ENXIO;
+			goto out_undelegate_tables;
+		}
+	}
+
+	params->rtt_level_start = get_start_level(kvm);
+	params->rtt_num_start = pgd_sz;
+	params->rtt_base = kvm->arch.mmu.pgd_phys;
+	params->vmid = realm->vmid;
+
+	params_phys = virt_to_phys(params);
+
+	if (rmi_realm_create(rd_phys, params_phys)) {
+		r = -ENXIO;
+		goto out_undelegate_tables;
+	}
+
+	realm->rd = rd;
+	realm->ia_bits = VTCR_EL2_IPA(kvm->arch.vtcr);
+
+	if (WARN_ON(rmi_rec_aux_count(rd_phys, &realm->num_aux))) {
+		WARN_ON(rmi_realm_destroy(rd_phys));
+		goto out_undelegate_tables;
+	}
+
+	return 0;
+
+out_undelegate_tables:
+	while (--i >= 0) {
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i * PAGE_SIZE;
+
+		WARN_ON(rmi_granule_undelegate(pgd_phys));
+	}
+	WARN_ON(rmi_granule_undelegate(rd_phys));
+out:
+	free_page((unsigned long)rd);
+	return r;
+}
+
+/* Protects access to rme_vmid_bitmap */
+static DEFINE_SPINLOCK(rme_vmid_lock);
+static unsigned long *rme_vmid_bitmap;
+
+static int rme_vmid_init(void)
+{
+	unsigned int vmid_count = 1 << kvm_get_vmid_bits();
+
+	rme_vmid_bitmap = bitmap_zalloc(vmid_count, GFP_KERNEL);
+	if (!rme_vmid_bitmap) {
+		kvm_err("%s: Couldn't allocate rme vmid bitmap\n", __func__);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int rme_vmid_reserve(void)
+{
+	int ret;
+	unsigned int vmid_count = 1 << kvm_get_vmid_bits();
+
+	spin_lock(&rme_vmid_lock);
+	ret = bitmap_find_free_region(rme_vmid_bitmap, vmid_count, 0);
+	spin_unlock(&rme_vmid_lock);
+
+	return ret;
+}
+
+static void rme_vmid_release(unsigned int vmid)
+{
+	spin_lock(&rme_vmid_lock);
+	bitmap_release_region(rme_vmid_bitmap, vmid, 0);
+	spin_unlock(&rme_vmid_lock);
+}
+
+static int kvm_create_realm(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	int ret;
+
+	if (!kvm_is_realm(kvm) || kvm_realm_state(kvm) != REALM_STATE_NONE)
+		return -EEXIST;
+
+	ret = rme_vmid_reserve();
+	if (ret < 0)
+		return ret;
+	realm->vmid = ret;
+
+	ret = realm_create_rd(kvm);
+	if (ret) {
+		rme_vmid_release(realm->vmid);
+		return ret;
+	}
+
+	WRITE_ONCE(realm->state, REALM_STATE_NEW);
+
+	/* The realm is up, free the parameters.  */
+	free_page((unsigned long)realm->params);
+	realm->params = NULL;
+
+	return 0;
+}
+
+static int config_realm_hash_algo(struct realm *realm,
+				  struct kvm_cap_arm_rme_config_item *cfg)
+{
+	switch (cfg->hash_algo) {
+	case KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256:
+		if (!rme_supports(RMI_FEATURE_REGISTER_0_HASH_SHA_256))
+			return -EINVAL;
+		break;
+	case KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA512:
+		if (!rme_supports(RMI_FEATURE_REGISTER_0_HASH_SHA_512))
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	realm->params->measurement_algo = cfg->hash_algo;
+	return 0;
+}
+
+static int config_realm_sve(struct realm *realm,
+			    struct kvm_cap_arm_rme_config_item *cfg)
+{
+	u64 features_0 = realm->params->features_0;
+	int max_sve_vq = u64_get_bits(rmm_feat_reg0,
+				      RMI_FEATURE_REGISTER_0_SVE_VL);
+
+	if (!rme_supports(RMI_FEATURE_REGISTER_0_SVE_EN))
+		return -EINVAL;
+
+	if (cfg->sve_vq > max_sve_vq)
+		return -EINVAL;
+
+	features_0 &= ~(RMI_FEATURE_REGISTER_0_SVE_EN |
+			RMI_FEATURE_REGISTER_0_SVE_VL);
+	features_0 |= u64_encode_bits(1, RMI_FEATURE_REGISTER_0_SVE_EN);
+	features_0 |= u64_encode_bits(cfg->sve_vq,
+				      RMI_FEATURE_REGISTER_0_SVE_VL);
+
+	realm->params->features_0 = features_0;
+	return 0;
+}
+
+static int kvm_rme_config_realm(struct kvm *kvm, struct kvm_enable_cap *cap)
+{
+	struct kvm_cap_arm_rme_config_item cfg;
+	struct realm *realm = &kvm->arch.realm;
+	int r = 0;
+
+	if (kvm_realm_state(kvm) != REALM_STATE_NONE)
+		return -EBUSY;
+
+	if (copy_from_user(&cfg, (void __user *)cap->args[1], sizeof(cfg)))
+		return -EFAULT;
+
+	switch (cfg.cfg) {
+	case KVM_CAP_ARM_RME_CFG_RPV:
+		memcpy(&realm->params->rpv, &cfg.rpv, sizeof(cfg.rpv));
+		break;
+	case KVM_CAP_ARM_RME_CFG_HASH_ALGO:
+		r = config_realm_hash_algo(realm, &cfg);
+		break;
+	case KVM_CAP_ARM_RME_CFG_SVE:
+		r = config_realm_sve(realm, &cfg);
+		break;
+	default:
+		r = -EINVAL;
+	}
+
+	return r;
+}
+
+int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
+{
+	int r = 0;
+
+	switch (cap->args[0]) {
+	case KVM_CAP_ARM_RME_CONFIG_REALM:
+		r = kvm_rme_config_realm(kvm, cap);
+		break;
+	case KVM_CAP_ARM_RME_CREATE_RD:
+		if (kvm->created_vcpus) {
+			r = -EBUSY;
+			break;
+		}
+
+		r = kvm_create_realm(kvm);
+		break;
+	default:
+		r = -EINVAL;
+		break;
+	}
+
+	return r;
+}
+
+void kvm_destroy_realm(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct kvm_pgtable *pgt = kvm->arch.mmu.pgt;
+	unsigned int pgd_sz;
+	int i;
+
+	if (realm->params) {
+		free_page((unsigned long)realm->params);
+		realm->params = NULL;
+	}
+
+	if (kvm_realm_state(kvm) == REALM_STATE_NONE)
+		return;
+
+	WRITE_ONCE(realm->state, REALM_STATE_DYING);
+
+	rme_vmid_release(realm->vmid);
+
+	if (realm->rd) {
+		phys_addr_t rd_phys = virt_to_phys(realm->rd);
+
+		if (WARN_ON(rmi_realm_destroy(rd_phys)))
+			return;
+		if (WARN_ON(rmi_granule_undelegate(rd_phys)))
+			return;
+		free_page((unsigned long)realm->rd);
+		realm->rd = NULL;
+	}
+
+	pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level);
+	for (i = 0; i < pgd_sz; i++) {
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i * PAGE_SIZE;
+
+		if (WARN_ON(rmi_granule_undelegate(pgd_phys)))
+			return;
+	}
+
+	kvm_free_stage2_pgd(&kvm->arch.mmu);
+}
+
+int kvm_init_realm_vm(struct kvm *kvm)
+{
+	struct realm_params *params;
+
+	params = (struct realm_params *)get_zeroed_page(GFP_KERNEL);
+	if (!params)
+		return -ENOMEM;
+
+	params->features_0 = create_realm_feat_reg0(kvm);
+	kvm->arch.realm.params = params;
+	return 0;
+}
+
 int kvm_init_rme(void)
 {
+	int ret;
+
 	if (PAGE_SIZE != SZ_4K)
 		/* Only 4k page size on the host is supported */
 		return 0;
@@ -43,6 +394,12 @@ int kvm_init_rme(void)
 		/* Continue without realm support */
 		return 0;
 
+	ret = rme_vmid_init();
+	if (ret)
+		return ret;
+
+	WARN_ON(rmi_features(0, &rmm_feat_reg0));
+
 	/* Future patch will enable static branch kvm_rme_is_available */
 
 	return 0;
-- 
2.34.1


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

* [RFC PATCH 06/28] arm64: RME: ioctls to create and configure realms
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Add the KVM_CAP_ARM_RME_CREATE_FD ioctl to create a realm. This involves
delegating pages to the RMM to hold the Realm Descriptor (RD) and for
the base level of the Realm Translation Tables (RTT). A VMID also need
to be picked, since the RMM has a separate VMID address space a
dedicated allocator is added for this purpose.

KVM_CAP_ARM_RME_CONFIG_REALM is provided to allow configuring the realm
before it is created.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |  14 ++
 arch/arm64/kvm/arm.c             |  19 ++
 arch/arm64/kvm/mmu.c             |   6 +
 arch/arm64/kvm/reset.c           |  33 +++
 arch/arm64/kvm/rme.c             | 357 +++++++++++++++++++++++++++++++
 5 files changed, 429 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index c26bc2c6770d..055a22accc08 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -6,6 +6,8 @@
 #ifndef __ASM_KVM_RME_H
 #define __ASM_KVM_RME_H
 
+#include <uapi/linux/kvm.h>
+
 enum realm_state {
 	REALM_STATE_NONE,
 	REALM_STATE_NEW,
@@ -15,8 +17,20 @@ enum realm_state {
 
 struct realm {
 	enum realm_state state;
+
+	void *rd;
+	struct realm_params *params;
+
+	unsigned long num_aux;
+	unsigned int vmid;
+	unsigned int ia_bits;
 };
 
 int kvm_init_rme(void);
+u32 kvm_realm_ipa_limit(void);
+
+int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap);
+int kvm_init_realm_vm(struct kvm *kvm);
+void kvm_destroy_realm(struct kvm *kvm);
 
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index d97b39d042ab..50f54a63732a 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -103,6 +103,13 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 		r = 0;
 		set_bit(KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED, &kvm->arch.flags);
 		break;
+	case KVM_CAP_ARM_RME:
+		if (!static_branch_unlikely(&kvm_rme_is_available))
+			return -EINVAL;
+		mutex_lock(&kvm->lock);
+		r = kvm_realm_enable_cap(kvm, cap);
+		mutex_unlock(&kvm->lock);
+		break;
 	default:
 		r = -EINVAL;
 		break;
@@ -172,6 +179,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	 */
 	kvm->arch.dfr0_pmuver.imp = kvm_arm_pmu_get_pmuver_limit();
 
+	/* Initialise the realm bits after the generic bits are enabled */
+	if (kvm_is_realm(kvm)) {
+		ret = kvm_init_realm_vm(kvm);
+		if (ret)
+			goto err_free_cpumask;
+	}
+
 	return 0;
 
 err_free_cpumask:
@@ -204,6 +218,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 	kvm_destroy_vcpus(kvm);
 
 	kvm_unshare_hyp(kvm, kvm + 1);
+
+	kvm_destroy_realm(kvm);
 }
 
 int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
@@ -300,6 +316,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
 		r = system_has_full_ptr_auth();
 		break;
+	case KVM_CAP_ARM_RME:
+		r = static_key_enabled(&kvm_rme_is_available);
+		break;
 	default:
 		r = 0;
 	}
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 31d7fa4c7c14..d0f707767d05 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -840,6 +840,12 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 	struct kvm_pgtable *pgt = NULL;
 
 	write_lock(&kvm->mmu_lock);
+	if (kvm_is_realm(kvm) &&
+	    kvm_realm_state(kvm) != REALM_STATE_DYING) {
+		/* TODO: teardown rtts */
+		write_unlock(&kvm->mmu_lock);
+		return;
+	}
 	pgt = mmu->pgt;
 	if (pgt) {
 		mmu->pgd_phys = 0;
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index e0267f672b8a..c165df174737 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -395,3 +395,36 @@ int kvm_set_ipa_limit(void)
 
 	return 0;
 }
+
+int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
+{
+	u64 mmfr0, mmfr1;
+	u32 phys_shift;
+	u32 ipa_limit = kvm_ipa_limit;
+
+	if (kvm_is_realm(kvm))
+		ipa_limit = kvm_realm_ipa_limit();
+
+	if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+		return -EINVAL;
+
+	phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
+	if (phys_shift) {
+		if (phys_shift > ipa_limit ||
+		    phys_shift < ARM64_MIN_PARANGE_BITS)
+			return -EINVAL;
+	} else {
+		phys_shift = KVM_PHYS_SHIFT;
+		if (phys_shift > ipa_limit) {
+			pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n",
+				     current->comm);
+			return -EINVAL;
+		}
+	}
+
+	mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+	mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
+	kvm->arch.vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift);
+
+	return 0;
+}
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index f6b587bc116e..9f8c5a91b8fc 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -5,9 +5,49 @@
 
 #include <linux/kvm_host.h>
 
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_mmu.h>
 #include <asm/rmi_cmds.h>
 #include <asm/virt.h>
 
+/************ FIXME: Copied from kvm/hyp/pgtable.c **********/
+#include <asm/kvm_pgtable.h>
+
+struct kvm_pgtable_walk_data {
+	struct kvm_pgtable		*pgt;
+	struct kvm_pgtable_walker	*walker;
+
+	u64				addr;
+	u64				end;
+};
+
+static u32 __kvm_pgd_page_idx(struct kvm_pgtable *pgt, u64 addr)
+{
+	u64 shift = kvm_granule_shift(pgt->start_level - 1); /* May underflow */
+	u64 mask = BIT(pgt->ia_bits) - 1;
+
+	return (addr & mask) >> shift;
+}
+
+static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
+{
+	struct kvm_pgtable pgt = {
+		.ia_bits	= ia_bits,
+		.start_level	= start_level,
+	};
+
+	return __kvm_pgd_page_idx(&pgt, -1ULL) + 1;
+}
+
+/******************/
+
+static unsigned long rmm_feat_reg0;
+
+static bool rme_supports(unsigned long feature)
+{
+	return !!u64_get_bits(rmm_feat_reg0, feature);
+}
+
 static int rmi_check_version(void)
 {
 	struct arm_smccc_res res;
@@ -33,8 +73,319 @@ static int rmi_check_version(void)
 	return 0;
 }
 
+static unsigned long create_realm_feat_reg0(struct kvm *kvm)
+{
+	unsigned long ia_bits = VTCR_EL2_IPA(kvm->arch.vtcr);
+	u64 feat_reg0 = 0;
+
+	int num_bps = u64_get_bits(rmm_feat_reg0,
+				   RMI_FEATURE_REGISTER_0_NUM_BPS);
+	int num_wps = u64_get_bits(rmm_feat_reg0,
+				   RMI_FEATURE_REGISTER_0_NUM_WPS);
+
+	feat_reg0 |= u64_encode_bits(ia_bits, RMI_FEATURE_REGISTER_0_S2SZ);
+	feat_reg0 |= u64_encode_bits(num_bps, RMI_FEATURE_REGISTER_0_NUM_BPS);
+	feat_reg0 |= u64_encode_bits(num_wps, RMI_FEATURE_REGISTER_0_NUM_WPS);
+
+	return feat_reg0;
+}
+
+u32 kvm_realm_ipa_limit(void)
+{
+	return u64_get_bits(rmm_feat_reg0, RMI_FEATURE_REGISTER_0_S2SZ);
+}
+
+static u32 get_start_level(struct kvm *kvm)
+{
+	long sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, kvm->arch.vtcr);
+
+	return VTCR_EL2_TGRAN_SL0_BASE - sl0;
+}
+
+static int realm_create_rd(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct realm_params *params = realm->params;
+	void *rd = NULL;
+	phys_addr_t rd_phys, params_phys;
+	struct kvm_pgtable *pgt = kvm->arch.mmu.pgt;
+	unsigned int pgd_sz;
+	int i, r;
+
+	if (WARN_ON(realm->rd) || WARN_ON(!realm->params))
+		return -EEXIST;
+
+	rd = (void *)__get_free_page(GFP_KERNEL);
+	if (!rd)
+		return -ENOMEM;
+
+	rd_phys = virt_to_phys(rd);
+	if (rmi_granule_delegate(rd_phys)) {
+		r = -ENXIO;
+		goto out;
+	}
+
+	pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level);
+	for (i = 0; i < pgd_sz; i++) {
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i * PAGE_SIZE;
+
+		if (rmi_granule_delegate(pgd_phys)) {
+			r = -ENXIO;
+			goto out_undelegate_tables;
+		}
+	}
+
+	params->rtt_level_start = get_start_level(kvm);
+	params->rtt_num_start = pgd_sz;
+	params->rtt_base = kvm->arch.mmu.pgd_phys;
+	params->vmid = realm->vmid;
+
+	params_phys = virt_to_phys(params);
+
+	if (rmi_realm_create(rd_phys, params_phys)) {
+		r = -ENXIO;
+		goto out_undelegate_tables;
+	}
+
+	realm->rd = rd;
+	realm->ia_bits = VTCR_EL2_IPA(kvm->arch.vtcr);
+
+	if (WARN_ON(rmi_rec_aux_count(rd_phys, &realm->num_aux))) {
+		WARN_ON(rmi_realm_destroy(rd_phys));
+		goto out_undelegate_tables;
+	}
+
+	return 0;
+
+out_undelegate_tables:
+	while (--i >= 0) {
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i * PAGE_SIZE;
+
+		WARN_ON(rmi_granule_undelegate(pgd_phys));
+	}
+	WARN_ON(rmi_granule_undelegate(rd_phys));
+out:
+	free_page((unsigned long)rd);
+	return r;
+}
+
+/* Protects access to rme_vmid_bitmap */
+static DEFINE_SPINLOCK(rme_vmid_lock);
+static unsigned long *rme_vmid_bitmap;
+
+static int rme_vmid_init(void)
+{
+	unsigned int vmid_count = 1 << kvm_get_vmid_bits();
+
+	rme_vmid_bitmap = bitmap_zalloc(vmid_count, GFP_KERNEL);
+	if (!rme_vmid_bitmap) {
+		kvm_err("%s: Couldn't allocate rme vmid bitmap\n", __func__);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int rme_vmid_reserve(void)
+{
+	int ret;
+	unsigned int vmid_count = 1 << kvm_get_vmid_bits();
+
+	spin_lock(&rme_vmid_lock);
+	ret = bitmap_find_free_region(rme_vmid_bitmap, vmid_count, 0);
+	spin_unlock(&rme_vmid_lock);
+
+	return ret;
+}
+
+static void rme_vmid_release(unsigned int vmid)
+{
+	spin_lock(&rme_vmid_lock);
+	bitmap_release_region(rme_vmid_bitmap, vmid, 0);
+	spin_unlock(&rme_vmid_lock);
+}
+
+static int kvm_create_realm(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	int ret;
+
+	if (!kvm_is_realm(kvm) || kvm_realm_state(kvm) != REALM_STATE_NONE)
+		return -EEXIST;
+
+	ret = rme_vmid_reserve();
+	if (ret < 0)
+		return ret;
+	realm->vmid = ret;
+
+	ret = realm_create_rd(kvm);
+	if (ret) {
+		rme_vmid_release(realm->vmid);
+		return ret;
+	}
+
+	WRITE_ONCE(realm->state, REALM_STATE_NEW);
+
+	/* The realm is up, free the parameters.  */
+	free_page((unsigned long)realm->params);
+	realm->params = NULL;
+
+	return 0;
+}
+
+static int config_realm_hash_algo(struct realm *realm,
+				  struct kvm_cap_arm_rme_config_item *cfg)
+{
+	switch (cfg->hash_algo) {
+	case KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256:
+		if (!rme_supports(RMI_FEATURE_REGISTER_0_HASH_SHA_256))
+			return -EINVAL;
+		break;
+	case KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA512:
+		if (!rme_supports(RMI_FEATURE_REGISTER_0_HASH_SHA_512))
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	realm->params->measurement_algo = cfg->hash_algo;
+	return 0;
+}
+
+static int config_realm_sve(struct realm *realm,
+			    struct kvm_cap_arm_rme_config_item *cfg)
+{
+	u64 features_0 = realm->params->features_0;
+	int max_sve_vq = u64_get_bits(rmm_feat_reg0,
+				      RMI_FEATURE_REGISTER_0_SVE_VL);
+
+	if (!rme_supports(RMI_FEATURE_REGISTER_0_SVE_EN))
+		return -EINVAL;
+
+	if (cfg->sve_vq > max_sve_vq)
+		return -EINVAL;
+
+	features_0 &= ~(RMI_FEATURE_REGISTER_0_SVE_EN |
+			RMI_FEATURE_REGISTER_0_SVE_VL);
+	features_0 |= u64_encode_bits(1, RMI_FEATURE_REGISTER_0_SVE_EN);
+	features_0 |= u64_encode_bits(cfg->sve_vq,
+				      RMI_FEATURE_REGISTER_0_SVE_VL);
+
+	realm->params->features_0 = features_0;
+	return 0;
+}
+
+static int kvm_rme_config_realm(struct kvm *kvm, struct kvm_enable_cap *cap)
+{
+	struct kvm_cap_arm_rme_config_item cfg;
+	struct realm *realm = &kvm->arch.realm;
+	int r = 0;
+
+	if (kvm_realm_state(kvm) != REALM_STATE_NONE)
+		return -EBUSY;
+
+	if (copy_from_user(&cfg, (void __user *)cap->args[1], sizeof(cfg)))
+		return -EFAULT;
+
+	switch (cfg.cfg) {
+	case KVM_CAP_ARM_RME_CFG_RPV:
+		memcpy(&realm->params->rpv, &cfg.rpv, sizeof(cfg.rpv));
+		break;
+	case KVM_CAP_ARM_RME_CFG_HASH_ALGO:
+		r = config_realm_hash_algo(realm, &cfg);
+		break;
+	case KVM_CAP_ARM_RME_CFG_SVE:
+		r = config_realm_sve(realm, &cfg);
+		break;
+	default:
+		r = -EINVAL;
+	}
+
+	return r;
+}
+
+int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
+{
+	int r = 0;
+
+	switch (cap->args[0]) {
+	case KVM_CAP_ARM_RME_CONFIG_REALM:
+		r = kvm_rme_config_realm(kvm, cap);
+		break;
+	case KVM_CAP_ARM_RME_CREATE_RD:
+		if (kvm->created_vcpus) {
+			r = -EBUSY;
+			break;
+		}
+
+		r = kvm_create_realm(kvm);
+		break;
+	default:
+		r = -EINVAL;
+		break;
+	}
+
+	return r;
+}
+
+void kvm_destroy_realm(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct kvm_pgtable *pgt = kvm->arch.mmu.pgt;
+	unsigned int pgd_sz;
+	int i;
+
+	if (realm->params) {
+		free_page((unsigned long)realm->params);
+		realm->params = NULL;
+	}
+
+	if (kvm_realm_state(kvm) == REALM_STATE_NONE)
+		return;
+
+	WRITE_ONCE(realm->state, REALM_STATE_DYING);
+
+	rme_vmid_release(realm->vmid);
+
+	if (realm->rd) {
+		phys_addr_t rd_phys = virt_to_phys(realm->rd);
+
+		if (WARN_ON(rmi_realm_destroy(rd_phys)))
+			return;
+		if (WARN_ON(rmi_granule_undelegate(rd_phys)))
+			return;
+		free_page((unsigned long)realm->rd);
+		realm->rd = NULL;
+	}
+
+	pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level);
+	for (i = 0; i < pgd_sz; i++) {
+		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i * PAGE_SIZE;
+
+		if (WARN_ON(rmi_granule_undelegate(pgd_phys)))
+			return;
+	}
+
+	kvm_free_stage2_pgd(&kvm->arch.mmu);
+}
+
+int kvm_init_realm_vm(struct kvm *kvm)
+{
+	struct realm_params *params;
+
+	params = (struct realm_params *)get_zeroed_page(GFP_KERNEL);
+	if (!params)
+		return -ENOMEM;
+
+	params->features_0 = create_realm_feat_reg0(kvm);
+	kvm->arch.realm.params = params;
+	return 0;
+}
+
 int kvm_init_rme(void)
 {
+	int ret;
+
 	if (PAGE_SIZE != SZ_4K)
 		/* Only 4k page size on the host is supported */
 		return 0;
@@ -43,6 +394,12 @@ int kvm_init_rme(void)
 		/* Continue without realm support */
 		return 0;
 
+	ret = rme_vmid_init();
+	if (ret)
+		return ret;
+
+	WARN_ON(rmi_features(0, &rmm_feat_reg0));
+
 	/* Future patch will enable static branch kvm_rme_is_available */
 
 	return 0;
-- 
2.34.1


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

* [RFC PATCH 07/28] arm64: kvm: Allow passing machine type in KVM creation
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Previously machine type was used purely for specifying the physical
address size of the guest. Reserve the higher bits to specify an ARM
specific machine type and declare a new type 'KVM_VM_TYPE_ARM_REALM'
used to create a realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arm.c     | 13 +++++++++++++
 arch/arm64/kvm/mmu.c     |  3 ---
 arch/arm64/kvm/reset.c   |  3 ---
 include/uapi/linux/kvm.h | 19 +++++++++++++++----
 4 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 50f54a63732a..badd775547b8 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -147,6 +147,19 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
 	int ret;
 
+	if (type & ~(KVM_VM_TYPE_ARM_MASK | KVM_VM_TYPE_ARM_IPA_SIZE_MASK))
+		return -EINVAL;
+
+	switch (type & KVM_VM_TYPE_ARM_MASK) {
+	case KVM_VM_TYPE_ARM_NORMAL:
+		break;
+	case KVM_VM_TYPE_ARM_REALM:
+		kvm->arch.is_realm = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	ret = kvm_share_hyp(kvm, kvm + 1);
 	if (ret)
 		return ret;
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index d0f707767d05..22c00274884a 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -709,9 +709,6 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
 	u64 mmfr0, mmfr1;
 	u32 phys_shift;
 
-	if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
-		return -EINVAL;
-
 	phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
 	if (is_protected_kvm_enabled()) {
 		phys_shift = kvm_ipa_limit;
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index c165df174737..9e71d69e051f 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -405,9 +405,6 @@ int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
 	if (kvm_is_realm(kvm))
 		ipa_limit = kvm_realm_ipa_limit();
 
-	if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
-		return -EINVAL;
-
 	phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
 	if (phys_shift) {
 		if (phys_shift > ipa_limit ||
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index fec1909e8b73..bcfc4d58dc19 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -898,14 +898,25 @@ struct kvm_ppc_resize_hpt {
 #define KVM_S390_SIE_PAGE_OFFSET 1
 
 /*
- * On arm64, machine type can be used to request the physical
- * address size for the VM. Bits[7-0] are reserved for the guest
- * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
- * value 0 implies the default IPA size, 40bits.
+ * On arm64, machine type can be used to request both the machine type and
+ * the physical address size for the VM.
+ *
+ * Bits[11-8] are reserved for the ARM specific machine type.
+ *
+ * Bits[7-0] are reserved for the guest PA size shift (i.e, log2(PA_Size)).
+ * For backward compatibility, value 0 implies the default IPA size, 40bits.
  */
+#define KVM_VM_TYPE_ARM_SHIFT		8
+#define KVM_VM_TYPE_ARM_MASK		(0xfULL << KVM_VM_TYPE_ARM_SHIFT)
+#define KVM_VM_TYPE_ARM(_type)		\
+	(((_type) << KVM_VM_TYPE_ARM_SHIFT) & KVM_VM_TYPE_ARM_MASK)
+#define KVM_VM_TYPE_ARM_NORMAL		KVM_VM_TYPE_ARM(0)
+#define KVM_VM_TYPE_ARM_REALM		KVM_VM_TYPE_ARM(1)
+
 #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK	0xffULL
 #define KVM_VM_TYPE_ARM_IPA_SIZE(x)		\
 	((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+
 /*
  * ioctls for /dev/kvm fds:
  */
-- 
2.34.1


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

* [RFC PATCH 07/28] arm64: kvm: Allow passing machine type in KVM creation
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Previously machine type was used purely for specifying the physical
address size of the guest. Reserve the higher bits to specify an ARM
specific machine type and declare a new type 'KVM_VM_TYPE_ARM_REALM'
used to create a realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arm.c     | 13 +++++++++++++
 arch/arm64/kvm/mmu.c     |  3 ---
 arch/arm64/kvm/reset.c   |  3 ---
 include/uapi/linux/kvm.h | 19 +++++++++++++++----
 4 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 50f54a63732a..badd775547b8 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -147,6 +147,19 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
 	int ret;
 
+	if (type & ~(KVM_VM_TYPE_ARM_MASK | KVM_VM_TYPE_ARM_IPA_SIZE_MASK))
+		return -EINVAL;
+
+	switch (type & KVM_VM_TYPE_ARM_MASK) {
+	case KVM_VM_TYPE_ARM_NORMAL:
+		break;
+	case KVM_VM_TYPE_ARM_REALM:
+		kvm->arch.is_realm = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	ret = kvm_share_hyp(kvm, kvm + 1);
 	if (ret)
 		return ret;
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index d0f707767d05..22c00274884a 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -709,9 +709,6 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
 	u64 mmfr0, mmfr1;
 	u32 phys_shift;
 
-	if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
-		return -EINVAL;
-
 	phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
 	if (is_protected_kvm_enabled()) {
 		phys_shift = kvm_ipa_limit;
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index c165df174737..9e71d69e051f 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -405,9 +405,6 @@ int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
 	if (kvm_is_realm(kvm))
 		ipa_limit = kvm_realm_ipa_limit();
 
-	if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
-		return -EINVAL;
-
 	phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
 	if (phys_shift) {
 		if (phys_shift > ipa_limit ||
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index fec1909e8b73..bcfc4d58dc19 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -898,14 +898,25 @@ struct kvm_ppc_resize_hpt {
 #define KVM_S390_SIE_PAGE_OFFSET 1
 
 /*
- * On arm64, machine type can be used to request the physical
- * address size for the VM. Bits[7-0] are reserved for the guest
- * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
- * value 0 implies the default IPA size, 40bits.
+ * On arm64, machine type can be used to request both the machine type and
+ * the physical address size for the VM.
+ *
+ * Bits[11-8] are reserved for the ARM specific machine type.
+ *
+ * Bits[7-0] are reserved for the guest PA size shift (i.e, log2(PA_Size)).
+ * For backward compatibility, value 0 implies the default IPA size, 40bits.
  */
+#define KVM_VM_TYPE_ARM_SHIFT		8
+#define KVM_VM_TYPE_ARM_MASK		(0xfULL << KVM_VM_TYPE_ARM_SHIFT)
+#define KVM_VM_TYPE_ARM(_type)		\
+	(((_type) << KVM_VM_TYPE_ARM_SHIFT) & KVM_VM_TYPE_ARM_MASK)
+#define KVM_VM_TYPE_ARM_NORMAL		KVM_VM_TYPE_ARM(0)
+#define KVM_VM_TYPE_ARM_REALM		KVM_VM_TYPE_ARM(1)
+
 #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK	0xffULL
 #define KVM_VM_TYPE_ARM_IPA_SIZE(x)		\
 	((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+
 /*
  * ioctls for /dev/kvm fds:
  */
-- 
2.34.1


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

* [RFC PATCH 08/28] arm64: RME: Keep a spare page delegated to the RMM
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Pages can only be populated/destroyed on the RMM at the 4KB granule,
this requires creating the full depth of RTTs. However if the pages are
going to be combined into a 4MB huge page the last RTT is only
temporarily needed. Similarly when freeing memory the huge page must be
temporarily split requiring temporary usage of the full depth oF RTTs.

To avoid needing to perform a temporary allocation and delegation of a
page for this purpose we keep a spare delegated page around. In
particular this avoids the need for memory allocation while destroying
the realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h | 3 +++
 arch/arm64/kvm/rme.c             | 6 ++++++
 2 files changed, 9 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 055a22accc08..a6318af3ed11 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -21,6 +21,9 @@ struct realm {
 	void *rd;
 	struct realm_params *params;
 
+	/* A spare already delegated page */
+	phys_addr_t spare_page;
+
 	unsigned long num_aux;
 	unsigned int vmid;
 	unsigned int ia_bits;
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 9f8c5a91b8fc..0c9d70e4d9e6 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -148,6 +148,7 @@ static int realm_create_rd(struct kvm *kvm)
 	}
 
 	realm->rd = rd;
+	realm->spare_page = PHYS_ADDR_MAX;
 	realm->ia_bits = VTCR_EL2_IPA(kvm->arch.vtcr);
 
 	if (WARN_ON(rmi_rec_aux_count(rd_phys, &realm->num_aux))) {
@@ -357,6 +358,11 @@ void kvm_destroy_realm(struct kvm *kvm)
 		free_page((unsigned long)realm->rd);
 		realm->rd = NULL;
 	}
+	if (realm->spare_page != PHYS_ADDR_MAX) {
+		if (!WARN_ON(rmi_granule_undelegate(realm->spare_page)))
+			free_page((unsigned long)phys_to_virt(realm->spare_page));
+		realm->spare_page = PHYS_ADDR_MAX;
+	}
 
 	pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level);
 	for (i = 0; i < pgd_sz; i++) {
-- 
2.34.1


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

* [RFC PATCH 08/28] arm64: RME: Keep a spare page delegated to the RMM
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Pages can only be populated/destroyed on the RMM at the 4KB granule,
this requires creating the full depth of RTTs. However if the pages are
going to be combined into a 4MB huge page the last RTT is only
temporarily needed. Similarly when freeing memory the huge page must be
temporarily split requiring temporary usage of the full depth oF RTTs.

To avoid needing to perform a temporary allocation and delegation of a
page for this purpose we keep a spare delegated page around. In
particular this avoids the need for memory allocation while destroying
the realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h | 3 +++
 arch/arm64/kvm/rme.c             | 6 ++++++
 2 files changed, 9 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 055a22accc08..a6318af3ed11 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -21,6 +21,9 @@ struct realm {
 	void *rd;
 	struct realm_params *params;
 
+	/* A spare already delegated page */
+	phys_addr_t spare_page;
+
 	unsigned long num_aux;
 	unsigned int vmid;
 	unsigned int ia_bits;
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 9f8c5a91b8fc..0c9d70e4d9e6 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -148,6 +148,7 @@ static int realm_create_rd(struct kvm *kvm)
 	}
 
 	realm->rd = rd;
+	realm->spare_page = PHYS_ADDR_MAX;
 	realm->ia_bits = VTCR_EL2_IPA(kvm->arch.vtcr);
 
 	if (WARN_ON(rmi_rec_aux_count(rd_phys, &realm->num_aux))) {
@@ -357,6 +358,11 @@ void kvm_destroy_realm(struct kvm *kvm)
 		free_page((unsigned long)realm->rd);
 		realm->rd = NULL;
 	}
+	if (realm->spare_page != PHYS_ADDR_MAX) {
+		if (!WARN_ON(rmi_granule_undelegate(realm->spare_page)))
+			free_page((unsigned long)phys_to_virt(realm->spare_page));
+		realm->spare_page = PHYS_ADDR_MAX;
+	}
 
 	pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level);
 	for (i = 0; i < pgd_sz; i++) {
-- 
2.34.1


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

* [RFC PATCH 09/28] arm64: RME: RTT handling
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM owns the stage 2 page tables for a realm, and KVM must request
that the RMM creates/destroys entries as necessary. The physical pages
to store the page tables are delegated to the realm as required, and can
be undelegated when no longer used.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |  19 +++++
 arch/arm64/kvm/mmu.c             |   7 +-
 arch/arm64/kvm/rme.c             | 139 +++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index a6318af3ed11..eea5118dfa8a 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -35,5 +35,24 @@ u32 kvm_realm_ipa_limit(void);
 int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap);
 int kvm_init_realm_vm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
+void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level);
+
+#define RME_RTT_BLOCK_LEVEL	2
+#define RME_RTT_MAX_LEVEL	3
+
+#define RME_PAGE_SHIFT		12
+#define RME_PAGE_SIZE		BIT(RME_PAGE_SHIFT)
+/* See ARM64_HW_PGTABLE_LEVEL_SHIFT() */
+#define RME_RTT_LEVEL_SHIFT(l)	\
+	((RME_PAGE_SHIFT - 3) * (4 - (l)) + 3)
+#define RME_L2_BLOCK_SIZE	BIT(RME_RTT_LEVEL_SHIFT(2))
+
+static inline unsigned long rme_rtt_level_mapsize(int level)
+{
+	if (WARN_ON(level > RME_RTT_MAX_LEVEL))
+		return RME_PAGE_SIZE;
+
+	return (1UL << RME_RTT_LEVEL_SHIFT(level));
+}
 
 #endif
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 22c00274884a..f29558c5dcbc 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -834,16 +834,17 @@ void stage2_unmap_vm(struct kvm *kvm)
 void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 {
 	struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
-	struct kvm_pgtable *pgt = NULL;
+	struct kvm_pgtable *pgt;
 
 	write_lock(&kvm->mmu_lock);
+	pgt = mmu->pgt;
 	if (kvm_is_realm(kvm) &&
 	    kvm_realm_state(kvm) != REALM_STATE_DYING) {
-		/* TODO: teardown rtts */
 		write_unlock(&kvm->mmu_lock);
+		kvm_realm_destroy_rtts(&kvm->arch.realm, pgt->ia_bits,
+				       pgt->start_level);
 		return;
 	}
-	pgt = mmu->pgt;
 	if (pgt) {
 		mmu->pgd_phys = 0;
 		mmu->pgt = NULL;
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 0c9d70e4d9e6..f7b0e5a779f8 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -73,6 +73,28 @@ static int rmi_check_version(void)
 	return 0;
 }
 
+static void realm_destroy_undelegate_range(struct realm *realm,
+					   unsigned long ipa,
+					   unsigned long addr,
+					   ssize_t size)
+{
+	unsigned long rd = virt_to_phys(realm->rd);
+	int ret;
+
+	while (size > 0) {
+		ret = rmi_data_destroy(rd, ipa);
+		WARN_ON(ret);
+		ret = rmi_granule_undelegate(addr);
+
+		if (ret)
+			get_page(phys_to_page(addr));
+
+		addr += PAGE_SIZE;
+		ipa += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+}
+
 static unsigned long create_realm_feat_reg0(struct kvm *kvm)
 {
 	unsigned long ia_bits = VTCR_EL2_IPA(kvm->arch.vtcr);
@@ -170,6 +192,123 @@ static int realm_create_rd(struct kvm *kvm)
 	return r;
 }
 
+static int realm_rtt_destroy(struct realm *realm, unsigned long addr,
+			     int level, phys_addr_t rtt_granule)
+{
+	addr = ALIGN_DOWN(addr, rme_rtt_level_mapsize(level - 1));
+	return rmi_rtt_destroy(rtt_granule, virt_to_phys(realm->rd), addr,
+			level);
+}
+
+static int realm_destroy_free_rtt(struct realm *realm, unsigned long addr,
+				  int level, phys_addr_t rtt_granule)
+{
+	if (realm_rtt_destroy(realm, addr, level, rtt_granule))
+		return -ENXIO;
+	if (!WARN_ON(rmi_granule_undelegate(rtt_granule)))
+		put_page(phys_to_page(rtt_granule));
+
+	return 0;
+}
+
+static int realm_rtt_create(struct realm *realm,
+			    unsigned long addr,
+			    int level,
+			    phys_addr_t phys)
+{
+	addr = ALIGN_DOWN(addr, rme_rtt_level_mapsize(level - 1));
+	return rmi_rtt_create(phys, virt_to_phys(realm->rd), addr, level);
+}
+
+static int realm_tear_down_rtt_range(struct realm *realm, int level,
+				     unsigned long start, unsigned long end)
+{
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	ssize_t map_size = rme_rtt_level_mapsize(level);
+	unsigned long addr, next_addr;
+	bool failed = false;
+
+	for (addr = start; addr < end; addr = next_addr) {
+		phys_addr_t rtt_addr, tmp_rtt;
+		struct rtt_entry rtt;
+		unsigned long end_addr;
+
+		next_addr = ALIGN(addr + 1, map_size);
+
+		end_addr = min(next_addr, end);
+
+		if (rmi_rtt_read_entry(rd, ALIGN_DOWN(addr, map_size),
+				       level, &rtt)) {
+			failed = true;
+			continue;
+		}
+
+		rtt_addr = rmi_rtt_get_phys(&rtt);
+		WARN_ON(level != rtt.walk_level);
+
+		switch (rtt.state) {
+		case RMI_UNASSIGNED:
+		case RMI_DESTROYED:
+			break;
+		case RMI_TABLE:
+			if (realm_tear_down_rtt_range(realm, level + 1,
+						      addr, end_addr)) {
+				failed = true;
+				break;
+			}
+			if (IS_ALIGNED(addr, map_size) &&
+			    next_addr <= end &&
+			    realm_destroy_free_rtt(realm, addr, level + 1,
+						   rtt_addr))
+				failed = true;
+			break;
+		case RMI_ASSIGNED:
+			WARN_ON(!rtt_addr);
+			/*
+			 * If there is a block mapping, break it now, using the
+			 * spare_page. We are sure to have a valid delegated
+			 * page at spare_page before we enter here, otherwise
+			 * WARN once, which will be followed by further
+			 * warnings.
+			 */
+			tmp_rtt = realm->spare_page;
+			if (level == 2 &&
+			    !WARN_ON_ONCE(tmp_rtt == PHYS_ADDR_MAX) &&
+			    realm_rtt_create(realm, addr,
+					     RME_RTT_MAX_LEVEL, tmp_rtt)) {
+				WARN_ON(1);
+				failed = true;
+				break;
+			}
+			realm_destroy_undelegate_range(realm, addr,
+						       rtt_addr, map_size);
+			/*
+			 * Collapse the last level table and make the spare page
+			 * reusable again.
+			 */
+			if (level == 2 &&
+			    realm_rtt_destroy(realm, addr, RME_RTT_MAX_LEVEL,
+					      tmp_rtt))
+				failed = true;
+			break;
+		case RMI_VALID_NS:
+			WARN_ON(rmi_rtt_unmap_unprotected(rd, addr, level));
+			break;
+		default:
+			WARN_ON(1);
+			failed = true;
+			break;
+		}
+	}
+
+	return failed ? -EINVAL : 0;
+}
+
+void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level)
+{
+	realm_tear_down_rtt_range(realm, start_level, 0, (1UL << ia_bits));
+}
+
 /* Protects access to rme_vmid_bitmap */
 static DEFINE_SPINLOCK(rme_vmid_lock);
 static unsigned long *rme_vmid_bitmap;
-- 
2.34.1


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

* [RFC PATCH 09/28] arm64: RME: RTT handling
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM owns the stage 2 page tables for a realm, and KVM must request
that the RMM creates/destroys entries as necessary. The physical pages
to store the page tables are delegated to the realm as required, and can
be undelegated when no longer used.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |  19 +++++
 arch/arm64/kvm/mmu.c             |   7 +-
 arch/arm64/kvm/rme.c             | 139 +++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index a6318af3ed11..eea5118dfa8a 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -35,5 +35,24 @@ u32 kvm_realm_ipa_limit(void);
 int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap);
 int kvm_init_realm_vm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
+void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level);
+
+#define RME_RTT_BLOCK_LEVEL	2
+#define RME_RTT_MAX_LEVEL	3
+
+#define RME_PAGE_SHIFT		12
+#define RME_PAGE_SIZE		BIT(RME_PAGE_SHIFT)
+/* See ARM64_HW_PGTABLE_LEVEL_SHIFT() */
+#define RME_RTT_LEVEL_SHIFT(l)	\
+	((RME_PAGE_SHIFT - 3) * (4 - (l)) + 3)
+#define RME_L2_BLOCK_SIZE	BIT(RME_RTT_LEVEL_SHIFT(2))
+
+static inline unsigned long rme_rtt_level_mapsize(int level)
+{
+	if (WARN_ON(level > RME_RTT_MAX_LEVEL))
+		return RME_PAGE_SIZE;
+
+	return (1UL << RME_RTT_LEVEL_SHIFT(level));
+}
 
 #endif
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 22c00274884a..f29558c5dcbc 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -834,16 +834,17 @@ void stage2_unmap_vm(struct kvm *kvm)
 void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 {
 	struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
-	struct kvm_pgtable *pgt = NULL;
+	struct kvm_pgtable *pgt;
 
 	write_lock(&kvm->mmu_lock);
+	pgt = mmu->pgt;
 	if (kvm_is_realm(kvm) &&
 	    kvm_realm_state(kvm) != REALM_STATE_DYING) {
-		/* TODO: teardown rtts */
 		write_unlock(&kvm->mmu_lock);
+		kvm_realm_destroy_rtts(&kvm->arch.realm, pgt->ia_bits,
+				       pgt->start_level);
 		return;
 	}
-	pgt = mmu->pgt;
 	if (pgt) {
 		mmu->pgd_phys = 0;
 		mmu->pgt = NULL;
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 0c9d70e4d9e6..f7b0e5a779f8 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -73,6 +73,28 @@ static int rmi_check_version(void)
 	return 0;
 }
 
+static void realm_destroy_undelegate_range(struct realm *realm,
+					   unsigned long ipa,
+					   unsigned long addr,
+					   ssize_t size)
+{
+	unsigned long rd = virt_to_phys(realm->rd);
+	int ret;
+
+	while (size > 0) {
+		ret = rmi_data_destroy(rd, ipa);
+		WARN_ON(ret);
+		ret = rmi_granule_undelegate(addr);
+
+		if (ret)
+			get_page(phys_to_page(addr));
+
+		addr += PAGE_SIZE;
+		ipa += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+}
+
 static unsigned long create_realm_feat_reg0(struct kvm *kvm)
 {
 	unsigned long ia_bits = VTCR_EL2_IPA(kvm->arch.vtcr);
@@ -170,6 +192,123 @@ static int realm_create_rd(struct kvm *kvm)
 	return r;
 }
 
+static int realm_rtt_destroy(struct realm *realm, unsigned long addr,
+			     int level, phys_addr_t rtt_granule)
+{
+	addr = ALIGN_DOWN(addr, rme_rtt_level_mapsize(level - 1));
+	return rmi_rtt_destroy(rtt_granule, virt_to_phys(realm->rd), addr,
+			level);
+}
+
+static int realm_destroy_free_rtt(struct realm *realm, unsigned long addr,
+				  int level, phys_addr_t rtt_granule)
+{
+	if (realm_rtt_destroy(realm, addr, level, rtt_granule))
+		return -ENXIO;
+	if (!WARN_ON(rmi_granule_undelegate(rtt_granule)))
+		put_page(phys_to_page(rtt_granule));
+
+	return 0;
+}
+
+static int realm_rtt_create(struct realm *realm,
+			    unsigned long addr,
+			    int level,
+			    phys_addr_t phys)
+{
+	addr = ALIGN_DOWN(addr, rme_rtt_level_mapsize(level - 1));
+	return rmi_rtt_create(phys, virt_to_phys(realm->rd), addr, level);
+}
+
+static int realm_tear_down_rtt_range(struct realm *realm, int level,
+				     unsigned long start, unsigned long end)
+{
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	ssize_t map_size = rme_rtt_level_mapsize(level);
+	unsigned long addr, next_addr;
+	bool failed = false;
+
+	for (addr = start; addr < end; addr = next_addr) {
+		phys_addr_t rtt_addr, tmp_rtt;
+		struct rtt_entry rtt;
+		unsigned long end_addr;
+
+		next_addr = ALIGN(addr + 1, map_size);
+
+		end_addr = min(next_addr, end);
+
+		if (rmi_rtt_read_entry(rd, ALIGN_DOWN(addr, map_size),
+				       level, &rtt)) {
+			failed = true;
+			continue;
+		}
+
+		rtt_addr = rmi_rtt_get_phys(&rtt);
+		WARN_ON(level != rtt.walk_level);
+
+		switch (rtt.state) {
+		case RMI_UNASSIGNED:
+		case RMI_DESTROYED:
+			break;
+		case RMI_TABLE:
+			if (realm_tear_down_rtt_range(realm, level + 1,
+						      addr, end_addr)) {
+				failed = true;
+				break;
+			}
+			if (IS_ALIGNED(addr, map_size) &&
+			    next_addr <= end &&
+			    realm_destroy_free_rtt(realm, addr, level + 1,
+						   rtt_addr))
+				failed = true;
+			break;
+		case RMI_ASSIGNED:
+			WARN_ON(!rtt_addr);
+			/*
+			 * If there is a block mapping, break it now, using the
+			 * spare_page. We are sure to have a valid delegated
+			 * page at spare_page before we enter here, otherwise
+			 * WARN once, which will be followed by further
+			 * warnings.
+			 */
+			tmp_rtt = realm->spare_page;
+			if (level == 2 &&
+			    !WARN_ON_ONCE(tmp_rtt == PHYS_ADDR_MAX) &&
+			    realm_rtt_create(realm, addr,
+					     RME_RTT_MAX_LEVEL, tmp_rtt)) {
+				WARN_ON(1);
+				failed = true;
+				break;
+			}
+			realm_destroy_undelegate_range(realm, addr,
+						       rtt_addr, map_size);
+			/*
+			 * Collapse the last level table and make the spare page
+			 * reusable again.
+			 */
+			if (level == 2 &&
+			    realm_rtt_destroy(realm, addr, RME_RTT_MAX_LEVEL,
+					      tmp_rtt))
+				failed = true;
+			break;
+		case RMI_VALID_NS:
+			WARN_ON(rmi_rtt_unmap_unprotected(rd, addr, level));
+			break;
+		default:
+			WARN_ON(1);
+			failed = true;
+			break;
+		}
+	}
+
+	return failed ? -EINVAL : 0;
+}
+
+void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level)
+{
+	realm_tear_down_rtt_range(realm, start_level, 0, (1UL << ia_bits));
+}
+
 /* Protects access to rme_vmid_bitmap */
 static DEFINE_SPINLOCK(rme_vmid_lock);
 static unsigned long *rme_vmid_bitmap;
-- 
2.34.1


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

* [RFC PATCH 10/28] arm64: RME: Allocate/free RECs to match vCPUs
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM maintains a data structure known as the Realm Execution Context
(or REC). It is similar to struct kvm_vcpu and tracks the state of the
virtual CPUs. KVM must delegate memory and request the structures are
created when vCPUs are created, and suitably tear down on destruction.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h |   2 +
 arch/arm64/include/asm/kvm_host.h    |   3 +
 arch/arm64/include/asm/kvm_rme.h     |  10 ++
 arch/arm64/kvm/arm.c                 |   1 +
 arch/arm64/kvm/reset.c               |  11 ++
 arch/arm64/kvm/rme.c                 | 144 +++++++++++++++++++++++++++
 6 files changed, 171 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 5a2b7229e83f..285e62914ca4 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -504,6 +504,8 @@ static inline enum realm_state kvm_realm_state(struct kvm *kvm)
 
 static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
 {
+	if (static_branch_unlikely(&kvm_rme_is_available))
+		return vcpu->arch.rec.mpidr != INVALID_HWID;
 	return false;
 }
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 04347c3a8c6b..ef497b718cdb 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -505,6 +505,9 @@ struct kvm_vcpu_arch {
 		u64 last_steal;
 		gpa_t base;
 	} steal;
+
+	/* Realm meta data */
+	struct rec rec;
 };
 
 /*
diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index eea5118dfa8a..4b219ebe1400 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -6,6 +6,7 @@
 #ifndef __ASM_KVM_RME_H
 #define __ASM_KVM_RME_H
 
+#include <asm/rmi_smc.h>
 #include <uapi/linux/kvm.h>
 
 enum realm_state {
@@ -29,6 +30,13 @@ struct realm {
 	unsigned int ia_bits;
 };
 
+struct rec {
+	unsigned long mpidr;
+	void *rec_page;
+	struct page *aux_pages[REC_PARAMS_AUX_GRANULES];
+	struct rec_run *run;
+};
+
 int kvm_init_rme(void);
 u32 kvm_realm_ipa_limit(void);
 
@@ -36,6 +44,8 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap);
 int kvm_init_realm_vm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
 void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level);
+int kvm_create_rec(struct kvm_vcpu *vcpu);
+void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 
 #define RME_RTT_BLOCK_LEVEL	2
 #define RME_RTT_MAX_LEVEL	3
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index badd775547b8..52affed2f3cf 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -373,6 +373,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 	/* Force users to call KVM_ARM_VCPU_INIT */
 	vcpu->arch.target = -1;
 	bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);
+	vcpu->arch.rec.mpidr = INVALID_HWID;
 
 	vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO;
 
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 9e71d69e051f..0c84392a4bf2 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -135,6 +135,11 @@ int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
 			return -EPERM;
 
 		return kvm_vcpu_finalize_sve(vcpu);
+	case KVM_ARM_VCPU_REC:
+		if (!kvm_is_realm(vcpu->kvm))
+			return -EINVAL;
+
+		return kvm_create_rec(vcpu);
 	}
 
 	return -EINVAL;
@@ -145,6 +150,11 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
 	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
 		return false;
 
+	if (kvm_is_realm(vcpu->kvm) &&
+	    !(vcpu_is_rec(vcpu) &&
+	      READ_ONCE(vcpu->kvm->arch.realm.state) == REALM_STATE_ACTIVE))
+		return false;
+
 	return true;
 }
 
@@ -157,6 +167,7 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
 	if (sve_state)
 		kvm_unshare_hyp(sve_state, sve_state + vcpu_sve_state_size(vcpu));
 	kfree(sve_state);
+	kvm_destroy_rec(vcpu);
 }
 
 static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index f7b0e5a779f8..d79ed889ca4d 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -514,6 +514,150 @@ void kvm_destroy_realm(struct kvm *kvm)
 	kvm_free_stage2_pgd(&kvm->arch.mmu);
 }
 
+static void free_rec_aux(struct page **aux_pages,
+			 unsigned int num_aux)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_aux; i++) {
+		phys_addr_t aux_page_phys = page_to_phys(aux_pages[i]);
+
+		if (WARN_ON(rmi_granule_undelegate(aux_page_phys)))
+			continue;
+
+		__free_page(aux_pages[i]);
+	}
+}
+
+static int alloc_rec_aux(struct page **aux_pages,
+			 u64 *aux_phys_pages,
+			 unsigned int num_aux)
+{
+	int ret;
+	unsigned int i;
+
+	for (i = 0; i < num_aux; i++) {
+		struct page *aux_page;
+		phys_addr_t aux_page_phys;
+
+		aux_page = alloc_page(GFP_KERNEL);
+		if (!aux_page) {
+			ret = -ENOMEM;
+			goto out_err;
+		}
+		aux_page_phys = page_to_phys(aux_page);
+		if (rmi_granule_delegate(aux_page_phys)) {
+			__free_page(aux_page);
+			ret = -ENXIO;
+			goto out_err;
+		}
+		aux_pages[i] = aux_page;
+		aux_phys_pages[i] = aux_page_phys;
+	}
+
+	return 0;
+out_err:
+	free_rec_aux(aux_pages, i);
+	return ret;
+}
+
+int kvm_create_rec(struct kvm_vcpu *vcpu)
+{
+	struct user_pt_regs *vcpu_regs = vcpu_gp_regs(vcpu);
+	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+	struct realm *realm = &vcpu->kvm->arch.realm;
+	struct rec *rec = &vcpu->arch.rec;
+	unsigned long rec_page_phys;
+	struct rec_params *params;
+	int r, i;
+
+	if (kvm_realm_state(vcpu->kvm) != REALM_STATE_NEW)
+		return -ENOENT;
+
+	/*
+	 * The RMM will report PSCI v1.0 to Realms and the KVM_ARM_VCPU_PSCI_0_2
+	 * flag covers v0.2 and onwards.
+	 */
+	if (!test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
+		return -EINVAL;
+
+	BUILD_BUG_ON(sizeof(*params) > PAGE_SIZE);
+	BUILD_BUG_ON(sizeof(*rec->run) > PAGE_SIZE);
+
+	params = (struct rec_params *)get_zeroed_page(GFP_KERNEL);
+	rec->rec_page = (void *)__get_free_page(GFP_KERNEL);
+	rec->run = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!params || !rec->rec_page || !rec->run) {
+		r = -ENOMEM;
+		goto out_free_pages;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(params->gprs); i++)
+		params->gprs[i] = vcpu_regs->regs[i];
+
+	params->pc = vcpu_regs->pc;
+
+	if (vcpu->vcpu_id == 0)
+		params->flags |= REC_PARAMS_FLAG_RUNNABLE;
+
+	rec_page_phys = virt_to_phys(rec->rec_page);
+
+	if (rmi_granule_delegate(rec_page_phys)) {
+		r = -ENXIO;
+		goto out_free_pages;
+	}
+
+	r = alloc_rec_aux(rec->aux_pages, params->aux, realm->num_aux);
+	if (r)
+		goto out_undelegate_rmm_rec;
+
+	params->num_rec_aux = realm->num_aux;
+	params->mpidr = mpidr;
+
+	if (rmi_rec_create(rec_page_phys,
+			   virt_to_phys(realm->rd),
+			   virt_to_phys(params))) {
+		r = -ENXIO;
+		goto out_free_rec_aux;
+	}
+
+	rec->mpidr = mpidr;
+
+	free_page((unsigned long)params);
+	return 0;
+
+out_free_rec_aux:
+	free_rec_aux(rec->aux_pages, realm->num_aux);
+out_undelegate_rmm_rec:
+	if (WARN_ON(rmi_granule_undelegate(rec_page_phys)))
+		rec->rec_page = NULL;
+out_free_pages:
+	free_page((unsigned long)rec->run);
+	free_page((unsigned long)rec->rec_page);
+	free_page((unsigned long)params);
+	return r;
+}
+
+void kvm_destroy_rec(struct kvm_vcpu *vcpu)
+{
+	struct realm *realm = &vcpu->kvm->arch.realm;
+	struct rec *rec = &vcpu->arch.rec;
+	unsigned long rec_page_phys;
+
+	if (!vcpu_is_rec(vcpu))
+		return;
+
+	rec_page_phys = virt_to_phys(rec->rec_page);
+
+	if (WARN_ON(rmi_rec_destroy(rec_page_phys)))
+		return;
+	if (WARN_ON(rmi_granule_undelegate(rec_page_phys)))
+		return;
+
+	free_rec_aux(rec->aux_pages, realm->num_aux);
+	free_page((unsigned long)rec->rec_page);
+}
+
 int kvm_init_realm_vm(struct kvm *kvm)
 {
 	struct realm_params *params;
-- 
2.34.1


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

* [RFC PATCH 10/28] arm64: RME: Allocate/free RECs to match vCPUs
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM maintains a data structure known as the Realm Execution Context
(or REC). It is similar to struct kvm_vcpu and tracks the state of the
virtual CPUs. KVM must delegate memory and request the structures are
created when vCPUs are created, and suitably tear down on destruction.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h |   2 +
 arch/arm64/include/asm/kvm_host.h    |   3 +
 arch/arm64/include/asm/kvm_rme.h     |  10 ++
 arch/arm64/kvm/arm.c                 |   1 +
 arch/arm64/kvm/reset.c               |  11 ++
 arch/arm64/kvm/rme.c                 | 144 +++++++++++++++++++++++++++
 6 files changed, 171 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 5a2b7229e83f..285e62914ca4 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -504,6 +504,8 @@ static inline enum realm_state kvm_realm_state(struct kvm *kvm)
 
 static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
 {
+	if (static_branch_unlikely(&kvm_rme_is_available))
+		return vcpu->arch.rec.mpidr != INVALID_HWID;
 	return false;
 }
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 04347c3a8c6b..ef497b718cdb 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -505,6 +505,9 @@ struct kvm_vcpu_arch {
 		u64 last_steal;
 		gpa_t base;
 	} steal;
+
+	/* Realm meta data */
+	struct rec rec;
 };
 
 /*
diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index eea5118dfa8a..4b219ebe1400 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -6,6 +6,7 @@
 #ifndef __ASM_KVM_RME_H
 #define __ASM_KVM_RME_H
 
+#include <asm/rmi_smc.h>
 #include <uapi/linux/kvm.h>
 
 enum realm_state {
@@ -29,6 +30,13 @@ struct realm {
 	unsigned int ia_bits;
 };
 
+struct rec {
+	unsigned long mpidr;
+	void *rec_page;
+	struct page *aux_pages[REC_PARAMS_AUX_GRANULES];
+	struct rec_run *run;
+};
+
 int kvm_init_rme(void);
 u32 kvm_realm_ipa_limit(void);
 
@@ -36,6 +44,8 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap);
 int kvm_init_realm_vm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
 void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level);
+int kvm_create_rec(struct kvm_vcpu *vcpu);
+void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 
 #define RME_RTT_BLOCK_LEVEL	2
 #define RME_RTT_MAX_LEVEL	3
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index badd775547b8..52affed2f3cf 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -373,6 +373,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 	/* Force users to call KVM_ARM_VCPU_INIT */
 	vcpu->arch.target = -1;
 	bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);
+	vcpu->arch.rec.mpidr = INVALID_HWID;
 
 	vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO;
 
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 9e71d69e051f..0c84392a4bf2 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -135,6 +135,11 @@ int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
 			return -EPERM;
 
 		return kvm_vcpu_finalize_sve(vcpu);
+	case KVM_ARM_VCPU_REC:
+		if (!kvm_is_realm(vcpu->kvm))
+			return -EINVAL;
+
+		return kvm_create_rec(vcpu);
 	}
 
 	return -EINVAL;
@@ -145,6 +150,11 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
 	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
 		return false;
 
+	if (kvm_is_realm(vcpu->kvm) &&
+	    !(vcpu_is_rec(vcpu) &&
+	      READ_ONCE(vcpu->kvm->arch.realm.state) == REALM_STATE_ACTIVE))
+		return false;
+
 	return true;
 }
 
@@ -157,6 +167,7 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
 	if (sve_state)
 		kvm_unshare_hyp(sve_state, sve_state + vcpu_sve_state_size(vcpu));
 	kfree(sve_state);
+	kvm_destroy_rec(vcpu);
 }
 
 static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index f7b0e5a779f8..d79ed889ca4d 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -514,6 +514,150 @@ void kvm_destroy_realm(struct kvm *kvm)
 	kvm_free_stage2_pgd(&kvm->arch.mmu);
 }
 
+static void free_rec_aux(struct page **aux_pages,
+			 unsigned int num_aux)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_aux; i++) {
+		phys_addr_t aux_page_phys = page_to_phys(aux_pages[i]);
+
+		if (WARN_ON(rmi_granule_undelegate(aux_page_phys)))
+			continue;
+
+		__free_page(aux_pages[i]);
+	}
+}
+
+static int alloc_rec_aux(struct page **aux_pages,
+			 u64 *aux_phys_pages,
+			 unsigned int num_aux)
+{
+	int ret;
+	unsigned int i;
+
+	for (i = 0; i < num_aux; i++) {
+		struct page *aux_page;
+		phys_addr_t aux_page_phys;
+
+		aux_page = alloc_page(GFP_KERNEL);
+		if (!aux_page) {
+			ret = -ENOMEM;
+			goto out_err;
+		}
+		aux_page_phys = page_to_phys(aux_page);
+		if (rmi_granule_delegate(aux_page_phys)) {
+			__free_page(aux_page);
+			ret = -ENXIO;
+			goto out_err;
+		}
+		aux_pages[i] = aux_page;
+		aux_phys_pages[i] = aux_page_phys;
+	}
+
+	return 0;
+out_err:
+	free_rec_aux(aux_pages, i);
+	return ret;
+}
+
+int kvm_create_rec(struct kvm_vcpu *vcpu)
+{
+	struct user_pt_regs *vcpu_regs = vcpu_gp_regs(vcpu);
+	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+	struct realm *realm = &vcpu->kvm->arch.realm;
+	struct rec *rec = &vcpu->arch.rec;
+	unsigned long rec_page_phys;
+	struct rec_params *params;
+	int r, i;
+
+	if (kvm_realm_state(vcpu->kvm) != REALM_STATE_NEW)
+		return -ENOENT;
+
+	/*
+	 * The RMM will report PSCI v1.0 to Realms and the KVM_ARM_VCPU_PSCI_0_2
+	 * flag covers v0.2 and onwards.
+	 */
+	if (!test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
+		return -EINVAL;
+
+	BUILD_BUG_ON(sizeof(*params) > PAGE_SIZE);
+	BUILD_BUG_ON(sizeof(*rec->run) > PAGE_SIZE);
+
+	params = (struct rec_params *)get_zeroed_page(GFP_KERNEL);
+	rec->rec_page = (void *)__get_free_page(GFP_KERNEL);
+	rec->run = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!params || !rec->rec_page || !rec->run) {
+		r = -ENOMEM;
+		goto out_free_pages;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(params->gprs); i++)
+		params->gprs[i] = vcpu_regs->regs[i];
+
+	params->pc = vcpu_regs->pc;
+
+	if (vcpu->vcpu_id == 0)
+		params->flags |= REC_PARAMS_FLAG_RUNNABLE;
+
+	rec_page_phys = virt_to_phys(rec->rec_page);
+
+	if (rmi_granule_delegate(rec_page_phys)) {
+		r = -ENXIO;
+		goto out_free_pages;
+	}
+
+	r = alloc_rec_aux(rec->aux_pages, params->aux, realm->num_aux);
+	if (r)
+		goto out_undelegate_rmm_rec;
+
+	params->num_rec_aux = realm->num_aux;
+	params->mpidr = mpidr;
+
+	if (rmi_rec_create(rec_page_phys,
+			   virt_to_phys(realm->rd),
+			   virt_to_phys(params))) {
+		r = -ENXIO;
+		goto out_free_rec_aux;
+	}
+
+	rec->mpidr = mpidr;
+
+	free_page((unsigned long)params);
+	return 0;
+
+out_free_rec_aux:
+	free_rec_aux(rec->aux_pages, realm->num_aux);
+out_undelegate_rmm_rec:
+	if (WARN_ON(rmi_granule_undelegate(rec_page_phys)))
+		rec->rec_page = NULL;
+out_free_pages:
+	free_page((unsigned long)rec->run);
+	free_page((unsigned long)rec->rec_page);
+	free_page((unsigned long)params);
+	return r;
+}
+
+void kvm_destroy_rec(struct kvm_vcpu *vcpu)
+{
+	struct realm *realm = &vcpu->kvm->arch.realm;
+	struct rec *rec = &vcpu->arch.rec;
+	unsigned long rec_page_phys;
+
+	if (!vcpu_is_rec(vcpu))
+		return;
+
+	rec_page_phys = virt_to_phys(rec->rec_page);
+
+	if (WARN_ON(rmi_rec_destroy(rec_page_phys)))
+		return;
+	if (WARN_ON(rmi_granule_undelegate(rec_page_phys)))
+		return;
+
+	free_rec_aux(rec->aux_pages, realm->num_aux);
+	free_page((unsigned long)rec->rec_page);
+}
+
 int kvm_init_realm_vm(struct kvm *kvm)
 {
 	struct realm_params *params;
-- 
2.34.1


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

* [RFC PATCH 11/28] arm64: RME: Support for the VGIC in realms
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM provides emulation of a VGIC to the realm guest but delegates
much of the handling to the host. Implement support in KVM for
saving/restoring state to/from the REC structure.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arm.c          | 15 +++++++++++---
 arch/arm64/kvm/vgic/vgic-v3.c |  9 +++++++--
 arch/arm64/kvm/vgic/vgic.c    | 37 +++++++++++++++++++++++++++++++++--
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 52affed2f3cf..1b2547516f62 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -475,17 +475,22 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
+	kvm_timer_vcpu_put(vcpu);
+	kvm_vgic_put(vcpu);
+
+	vcpu->cpu = -1;
+
+	if (vcpu_is_rec(vcpu))
+		return;
+
 	kvm_arch_vcpu_put_debug_state_flags(vcpu);
 	kvm_arch_vcpu_put_fp(vcpu);
 	if (has_vhe())
 		kvm_vcpu_put_sysregs_vhe(vcpu);
-	kvm_timer_vcpu_put(vcpu);
-	kvm_vgic_put(vcpu);
 	kvm_vcpu_pmu_restore_host(vcpu);
 	kvm_arm_vmid_clear_active();
 
 	vcpu_clear_on_unsupported_cpu(vcpu);
-	vcpu->cpu = -1;
 }
 
 void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu)
@@ -623,6 +628,10 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
 	}
 
 	if (!irqchip_in_kernel(kvm)) {
+		/* Userspace irqchip not yet supported with Realms */
+		if (kvm_is_realm(vcpu->kvm))
+			return -EOPNOTSUPP;
+
 		/*
 		 * Tell the rest of the code that there are userspace irqchip
 		 * VMs in the wild.
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 826ff6f2a4e7..121c7a68c397 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -6,9 +6,11 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_asm.h>
+#include <asm/rmi_smc.h>
 
 #include "vgic.h"
 
@@ -669,7 +671,8 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 			(unsigned long long)info->vcpu.start);
 	} else if (kvm_get_mode() != KVM_MODE_PROTECTED) {
 		kvm_vgic_global_state.vcpu_base = info->vcpu.start;
-		kvm_vgic_global_state.can_emulate_gicv2 = true;
+		if (!static_branch_unlikely(&kvm_rme_is_available))
+			kvm_vgic_global_state.can_emulate_gicv2 = true;
 		ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
 		if (ret) {
 			kvm_err("Cannot register GICv2 KVM device.\n");
@@ -744,7 +747,9 @@ void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 
-	if (likely(cpu_if->vgic_sre))
+	if (vcpu_is_rec(vcpu))
+		cpu_if->vgic_vmcr = vcpu->arch.rec.run->exit.gicv3_vmcr;
+	else if (likely(cpu_if->vgic_sre))
 		cpu_if->vgic_vmcr = kvm_call_hyp_ret(__vgic_v3_read_vmcr);
 }
 
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index d97e6080b421..bc77660f7051 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -10,7 +10,9 @@
 #include <linux/list_sort.h>
 #include <linux/nospec.h>
 
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
+#include <asm/rmi_smc.h>
 
 #include "vgic.h"
 
@@ -848,10 +850,23 @@ static inline bool can_access_vgic_from_kernel(void)
 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
 }
 
+static inline void vgic_rmm_save_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	int i;
+
+	for (i = 0; i < kvm_vgic_global_state.nr_lr; i++) {
+		cpu_if->vgic_lr[i] = vcpu->arch.rec.run->exit.gicv3_lrs[i];
+		vcpu->arch.rec.run->entry.gicv3_lrs[i] = 0;
+	}
+}
+
 static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_save_state(vcpu);
+	else if (vcpu_is_rec(vcpu))
+		vgic_rmm_save_state(vcpu);
 	else
 		__vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
 }
@@ -878,10 +893,28 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	vgic_prune_ap_list(vcpu);
 }
 
+static inline void vgic_rmm_restore_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	int i;
+
+	for (i = 0; i < kvm_vgic_global_state.nr_lr; i++) {
+		vcpu->arch.rec.run->entry.gicv3_lrs[i] = cpu_if->vgic_lr[i];
+		/*
+		 * Also populate the rec.run->exit copies so that a late
+		 * decision to back out from entering the realm doesn't cause
+		 * the state to be lost
+		 */
+		vcpu->arch.rec.run->exit.gicv3_lrs[i] = cpu_if->vgic_lr[i];
+	}
+}
+
 static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_restore_state(vcpu);
+	else if (vcpu_is_rec(vcpu))
+		vgic_rmm_restore_state(vcpu);
 	else
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
 }
@@ -922,7 +955,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	if (unlikely(!vgic_initialized(vcpu->kvm)) || vcpu_is_rec(vcpu))
 		return;
 
 	if (kvm_vgic_global_state.type == VGIC_V2)
@@ -933,7 +966,7 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_put(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	if (unlikely(!vgic_initialized(vcpu->kvm)) || vcpu_is_rec(vcpu))
 		return;
 
 	if (kvm_vgic_global_state.type == VGIC_V2)
-- 
2.34.1


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

* [RFC PATCH 11/28] arm64: RME: Support for the VGIC in realms
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM provides emulation of a VGIC to the realm guest but delegates
much of the handling to the host. Implement support in KVM for
saving/restoring state to/from the REC structure.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arm.c          | 15 +++++++++++---
 arch/arm64/kvm/vgic/vgic-v3.c |  9 +++++++--
 arch/arm64/kvm/vgic/vgic.c    | 37 +++++++++++++++++++++++++++++++++--
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 52affed2f3cf..1b2547516f62 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -475,17 +475,22 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
+	kvm_timer_vcpu_put(vcpu);
+	kvm_vgic_put(vcpu);
+
+	vcpu->cpu = -1;
+
+	if (vcpu_is_rec(vcpu))
+		return;
+
 	kvm_arch_vcpu_put_debug_state_flags(vcpu);
 	kvm_arch_vcpu_put_fp(vcpu);
 	if (has_vhe())
 		kvm_vcpu_put_sysregs_vhe(vcpu);
-	kvm_timer_vcpu_put(vcpu);
-	kvm_vgic_put(vcpu);
 	kvm_vcpu_pmu_restore_host(vcpu);
 	kvm_arm_vmid_clear_active();
 
 	vcpu_clear_on_unsupported_cpu(vcpu);
-	vcpu->cpu = -1;
 }
 
 void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu)
@@ -623,6 +628,10 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
 	}
 
 	if (!irqchip_in_kernel(kvm)) {
+		/* Userspace irqchip not yet supported with Realms */
+		if (kvm_is_realm(vcpu->kvm))
+			return -EOPNOTSUPP;
+
 		/*
 		 * Tell the rest of the code that there are userspace irqchip
 		 * VMs in the wild.
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 826ff6f2a4e7..121c7a68c397 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -6,9 +6,11 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_asm.h>
+#include <asm/rmi_smc.h>
 
 #include "vgic.h"
 
@@ -669,7 +671,8 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 			(unsigned long long)info->vcpu.start);
 	} else if (kvm_get_mode() != KVM_MODE_PROTECTED) {
 		kvm_vgic_global_state.vcpu_base = info->vcpu.start;
-		kvm_vgic_global_state.can_emulate_gicv2 = true;
+		if (!static_branch_unlikely(&kvm_rme_is_available))
+			kvm_vgic_global_state.can_emulate_gicv2 = true;
 		ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
 		if (ret) {
 			kvm_err("Cannot register GICv2 KVM device.\n");
@@ -744,7 +747,9 @@ void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 
-	if (likely(cpu_if->vgic_sre))
+	if (vcpu_is_rec(vcpu))
+		cpu_if->vgic_vmcr = vcpu->arch.rec.run->exit.gicv3_vmcr;
+	else if (likely(cpu_if->vgic_sre))
 		cpu_if->vgic_vmcr = kvm_call_hyp_ret(__vgic_v3_read_vmcr);
 }
 
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index d97e6080b421..bc77660f7051 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -10,7 +10,9 @@
 #include <linux/list_sort.h>
 #include <linux/nospec.h>
 
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
+#include <asm/rmi_smc.h>
 
 #include "vgic.h"
 
@@ -848,10 +850,23 @@ static inline bool can_access_vgic_from_kernel(void)
 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
 }
 
+static inline void vgic_rmm_save_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	int i;
+
+	for (i = 0; i < kvm_vgic_global_state.nr_lr; i++) {
+		cpu_if->vgic_lr[i] = vcpu->arch.rec.run->exit.gicv3_lrs[i];
+		vcpu->arch.rec.run->entry.gicv3_lrs[i] = 0;
+	}
+}
+
 static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_save_state(vcpu);
+	else if (vcpu_is_rec(vcpu))
+		vgic_rmm_save_state(vcpu);
 	else
 		__vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
 }
@@ -878,10 +893,28 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	vgic_prune_ap_list(vcpu);
 }
 
+static inline void vgic_rmm_restore_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	int i;
+
+	for (i = 0; i < kvm_vgic_global_state.nr_lr; i++) {
+		vcpu->arch.rec.run->entry.gicv3_lrs[i] = cpu_if->vgic_lr[i];
+		/*
+		 * Also populate the rec.run->exit copies so that a late
+		 * decision to back out from entering the realm doesn't cause
+		 * the state to be lost
+		 */
+		vcpu->arch.rec.run->exit.gicv3_lrs[i] = cpu_if->vgic_lr[i];
+	}
+}
+
 static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_restore_state(vcpu);
+	else if (vcpu_is_rec(vcpu))
+		vgic_rmm_restore_state(vcpu);
 	else
 		__vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
 }
@@ -922,7 +955,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	if (unlikely(!vgic_initialized(vcpu->kvm)) || vcpu_is_rec(vcpu))
 		return;
 
 	if (kvm_vgic_global_state.type == VGIC_V2)
@@ -933,7 +966,7 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_put(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!vgic_initialized(vcpu->kvm)))
+	if (unlikely(!vgic_initialized(vcpu->kvm)) || vcpu_is_rec(vcpu))
 		return;
 
 	if (kvm_vgic_global_state.type == VGIC_V2)
-- 
2.34.1


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

* [RFC PATCH 12/28] KVM: arm64: Support timers in realm RECs
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM keeps track of the timer while the realm REC is running, but on
exit to the normal world KVM is responsible for handling the timers.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arch_timer.c  | 53 ++++++++++++++++++++++++++++++++----
 include/kvm/arm_arch_timer.h |  2 ++
 2 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index bb24a76b4224..d4af9ee58550 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -130,6 +130,11 @@ static void timer_set_offset(struct arch_timer_context *ctxt, u64 offset)
 {
 	struct kvm_vcpu *vcpu = ctxt->vcpu;
 
+	if (kvm_is_realm(vcpu->kvm)) {
+		WARN_ON(offset);
+		return;
+	}
+
 	switch(arch_timer_ctx_index(ctxt)) {
 	case TIMER_VTIMER:
 		__vcpu_sys_reg(vcpu, CNTVOFF_EL2) = offset;
@@ -411,6 +416,21 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 	}
 }
 
+void kvm_realm_timers_update(struct kvm_vcpu *vcpu)
+{
+	struct arch_timer_cpu *arch_timer = &vcpu->arch.timer_cpu;
+	int i;
+
+	for (i = 0; i < NR_KVM_TIMERS; i++) {
+		struct arch_timer_context *timer = &arch_timer->timers[i];
+		bool status = timer_get_ctl(timer) & ARCH_TIMER_CTRL_IT_STAT;
+		bool level = kvm_timer_irq_can_fire(timer) && status;
+
+		if (level != timer->irq.level)
+			kvm_timer_update_irq(vcpu, level, timer);
+	}
+}
+
 /* Only called for a fully emulated timer */
 static void timer_emulate(struct arch_timer_context *ctx)
 {
@@ -621,6 +641,11 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 	if (unlikely(!timer->enabled))
 		return;
 
+	kvm_timer_unblocking(vcpu);
+
+	if (vcpu_is_rec(vcpu))
+		return;
+
 	get_timer_map(vcpu, &map);
 
 	if (static_branch_likely(&has_gic_active_state)) {
@@ -633,8 +658,6 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 
 	set_cntvoff(timer_get_offset(map.direct_vtimer));
 
-	kvm_timer_unblocking(vcpu);
-
 	timer_restore_state(map.direct_vtimer);
 	if (map.direct_ptimer)
 		timer_restore_state(map.direct_ptimer);
@@ -668,6 +691,9 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	if (unlikely(!timer->enabled))
 		return;
 
+	if (vcpu_is_rec(vcpu))
+		goto out;
+
 	get_timer_map(vcpu, &map);
 
 	timer_save_state(map.direct_vtimer);
@@ -686,9 +712,6 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	if (map.emul_ptimer)
 		soft_timer_cancel(&map.emul_ptimer->hrtimer);
 
-	if (kvm_vcpu_is_blocking(vcpu))
-		kvm_timer_blocking(vcpu);
-
 	/*
 	 * The kernel may decide to run userspace after calling vcpu_put, so
 	 * we reset cntvoff to 0 to ensure a consistent read between user
@@ -697,6 +720,11 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	 * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
 	 */
 	set_cntvoff(0);
+
+out:
+	if (kvm_vcpu_is_blocking(vcpu))
+		kvm_timer_blocking(vcpu);
+
 }
 
 /*
@@ -785,12 +813,18 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	u64 cntvoff;
 
 	vtimer->vcpu = vcpu;
 	ptimer->vcpu = vcpu;
 
+	if (kvm_is_realm(vcpu->kvm))
+		cntvoff = 0;
+	else
+		cntvoff = kvm_phys_timer_read();
+
 	/* Synchronize cntvoff across all vtimers of a VM. */
-	update_vtimer_cntvoff(vcpu, kvm_phys_timer_read());
+	update_vtimer_cntvoff(vcpu, cntvoff);
 	timer_set_offset(ptimer, 0);
 
 	hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
@@ -1265,6 +1299,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
+	/*
+	 * We don't use mapped IRQs for Realms because the RMI doesn't allow
+	 * us setting the LR.HW bit in the VGIC.
+	 */
+	if (vcpu_is_rec(vcpu))
+		return 0;
+
 	get_timer_map(vcpu, &map);
 
 	ret = kvm_vgic_map_phys_irq(vcpu,
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index cd6d8f260eab..158280e15a33 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -76,6 +76,8 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 
+void kvm_realm_timers_update(struct kvm_vcpu *vcpu);
+
 u64 kvm_phys_timer_read(void);
 
 void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu);
-- 
2.34.1


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

* [RFC PATCH 12/28] KVM: arm64: Support timers in realm RECs
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM keeps track of the timer while the realm REC is running, but on
exit to the normal world KVM is responsible for handling the timers.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arch_timer.c  | 53 ++++++++++++++++++++++++++++++++----
 include/kvm/arm_arch_timer.h |  2 ++
 2 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index bb24a76b4224..d4af9ee58550 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -130,6 +130,11 @@ static void timer_set_offset(struct arch_timer_context *ctxt, u64 offset)
 {
 	struct kvm_vcpu *vcpu = ctxt->vcpu;
 
+	if (kvm_is_realm(vcpu->kvm)) {
+		WARN_ON(offset);
+		return;
+	}
+
 	switch(arch_timer_ctx_index(ctxt)) {
 	case TIMER_VTIMER:
 		__vcpu_sys_reg(vcpu, CNTVOFF_EL2) = offset;
@@ -411,6 +416,21 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 	}
 }
 
+void kvm_realm_timers_update(struct kvm_vcpu *vcpu)
+{
+	struct arch_timer_cpu *arch_timer = &vcpu->arch.timer_cpu;
+	int i;
+
+	for (i = 0; i < NR_KVM_TIMERS; i++) {
+		struct arch_timer_context *timer = &arch_timer->timers[i];
+		bool status = timer_get_ctl(timer) & ARCH_TIMER_CTRL_IT_STAT;
+		bool level = kvm_timer_irq_can_fire(timer) && status;
+
+		if (level != timer->irq.level)
+			kvm_timer_update_irq(vcpu, level, timer);
+	}
+}
+
 /* Only called for a fully emulated timer */
 static void timer_emulate(struct arch_timer_context *ctx)
 {
@@ -621,6 +641,11 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 	if (unlikely(!timer->enabled))
 		return;
 
+	kvm_timer_unblocking(vcpu);
+
+	if (vcpu_is_rec(vcpu))
+		return;
+
 	get_timer_map(vcpu, &map);
 
 	if (static_branch_likely(&has_gic_active_state)) {
@@ -633,8 +658,6 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 
 	set_cntvoff(timer_get_offset(map.direct_vtimer));
 
-	kvm_timer_unblocking(vcpu);
-
 	timer_restore_state(map.direct_vtimer);
 	if (map.direct_ptimer)
 		timer_restore_state(map.direct_ptimer);
@@ -668,6 +691,9 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	if (unlikely(!timer->enabled))
 		return;
 
+	if (vcpu_is_rec(vcpu))
+		goto out;
+
 	get_timer_map(vcpu, &map);
 
 	timer_save_state(map.direct_vtimer);
@@ -686,9 +712,6 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	if (map.emul_ptimer)
 		soft_timer_cancel(&map.emul_ptimer->hrtimer);
 
-	if (kvm_vcpu_is_blocking(vcpu))
-		kvm_timer_blocking(vcpu);
-
 	/*
 	 * The kernel may decide to run userspace after calling vcpu_put, so
 	 * we reset cntvoff to 0 to ensure a consistent read between user
@@ -697,6 +720,11 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	 * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
 	 */
 	set_cntvoff(0);
+
+out:
+	if (kvm_vcpu_is_blocking(vcpu))
+		kvm_timer_blocking(vcpu);
+
 }
 
 /*
@@ -785,12 +813,18 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	u64 cntvoff;
 
 	vtimer->vcpu = vcpu;
 	ptimer->vcpu = vcpu;
 
+	if (kvm_is_realm(vcpu->kvm))
+		cntvoff = 0;
+	else
+		cntvoff = kvm_phys_timer_read();
+
 	/* Synchronize cntvoff across all vtimers of a VM. */
-	update_vtimer_cntvoff(vcpu, kvm_phys_timer_read());
+	update_vtimer_cntvoff(vcpu, cntvoff);
 	timer_set_offset(ptimer, 0);
 
 	hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
@@ -1265,6 +1299,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
+	/*
+	 * We don't use mapped IRQs for Realms because the RMI doesn't allow
+	 * us setting the LR.HW bit in the VGIC.
+	 */
+	if (vcpu_is_rec(vcpu))
+		return 0;
+
 	get_timer_map(vcpu, &map);
 
 	ret = kvm_vgic_map_phys_irq(vcpu,
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index cd6d8f260eab..158280e15a33 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -76,6 +76,8 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 
+void kvm_realm_timers_update(struct kvm_vcpu *vcpu);
+
 u64 kvm_phys_timer_read(void);
 
 void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu);
-- 
2.34.1


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

* [RFC PATCH 13/28] arm64: RME: Allow VMM to set RIPAS
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Each page within the protected region of the realm guest can be marked
as either RAM or EMPTY. Allow the VMM to control this before the guest
has started and provide the equivalent functions to change this (with
the guest's approval) at runtime.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |   4 +
 arch/arm64/kvm/rme.c             | 288 +++++++++++++++++++++++++++++++
 2 files changed, 292 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 4b219ebe1400..3e75cedaad18 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -47,6 +47,10 @@ void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level);
 int kvm_create_rec(struct kvm_vcpu *vcpu);
 void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 
+int realm_set_ipa_state(struct kvm_vcpu *vcpu,
+			unsigned long addr, unsigned long end,
+			unsigned long ripas);
+
 #define RME_RTT_BLOCK_LEVEL	2
 #define RME_RTT_MAX_LEVEL	3
 
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index d79ed889ca4d..b3ea79189839 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -73,6 +73,58 @@ static int rmi_check_version(void)
 	return 0;
 }
 
+static phys_addr_t __alloc_delegated_page(struct realm *realm,
+					  struct kvm_mmu_memory_cache *mc, gfp_t flags)
+{
+	phys_addr_t phys = PHYS_ADDR_MAX;
+	void *virt;
+
+	if (realm->spare_page != PHYS_ADDR_MAX) {
+		swap(realm->spare_page, phys);
+		goto out;
+	}
+
+	if (mc)
+		virt = kvm_mmu_memory_cache_alloc(mc);
+	else
+		virt = (void *)__get_free_page(flags);
+
+	if (!virt)
+		goto out;
+
+	phys = virt_to_phys(virt);
+
+	if (rmi_granule_delegate(phys)) {
+		free_page((unsigned long)virt);
+
+		phys = PHYS_ADDR_MAX;
+	}
+
+out:
+	return phys;
+}
+
+static phys_addr_t alloc_delegated_page(struct realm *realm,
+					struct kvm_mmu_memory_cache *mc)
+{
+	return __alloc_delegated_page(realm, mc, GFP_KERNEL);
+}
+
+static void free_delegated_page(struct realm *realm, phys_addr_t phys)
+{
+	if (realm->spare_page == PHYS_ADDR_MAX) {
+		realm->spare_page = phys;
+		return;
+	}
+
+	if (WARN_ON(rmi_granule_undelegate(phys))) {
+		/* Undelegate failed: leak the page */
+		return;
+	}
+
+	free_page((unsigned long)phys_to_virt(phys));
+}
+
 static void realm_destroy_undelegate_range(struct realm *realm,
 					   unsigned long ipa,
 					   unsigned long addr,
@@ -220,6 +272,30 @@ static int realm_rtt_create(struct realm *realm,
 	return rmi_rtt_create(phys, virt_to_phys(realm->rd), addr, level);
 }
 
+static int realm_create_rtt_levels(struct realm *realm,
+				   unsigned long ipa,
+				   int level,
+				   int max_level,
+				   struct kvm_mmu_memory_cache *mc)
+{
+	if (WARN_ON(level == max_level))
+		return 0;
+
+	while (level++ < max_level) {
+		phys_addr_t rtt = alloc_delegated_page(realm, mc);
+
+		if (rtt == PHYS_ADDR_MAX)
+			return -ENOMEM;
+
+		if (realm_rtt_create(realm, ipa, level, rtt)) {
+			free_delegated_page(realm, rtt);
+			return -ENXIO;
+		}
+	}
+
+	return 0;
+}
+
 static int realm_tear_down_rtt_range(struct realm *realm, int level,
 				     unsigned long start, unsigned long end)
 {
@@ -309,6 +385,206 @@ void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level)
 	realm_tear_down_rtt_range(realm, start_level, 0, (1UL << ia_bits));
 }
 
+void kvm_realm_unmap_range(struct kvm *kvm, unsigned long ipa, u64 size)
+{
+	u32 ia_bits = kvm->arch.mmu.pgt->ia_bits;
+	u32 start_level = kvm->arch.mmu.pgt->start_level;
+	unsigned long end = ipa + size;
+	struct realm *realm = &kvm->arch.realm;
+	phys_addr_t tmp_rtt = PHYS_ADDR_MAX;
+
+	if (end > (1UL << ia_bits))
+		end = 1UL << ia_bits;
+	/*
+	 * Make sure we have a spare delegated page for tearing down the
+	 * block mappings. We must use Atomic allocations as we are called
+	 * with kvm->mmu_lock held.
+	 */
+	if (realm->spare_page == PHYS_ADDR_MAX) {
+		tmp_rtt = __alloc_delegated_page(realm, NULL, GFP_ATOMIC);
+		/*
+		 * We don't have to check the status here, as we may not
+		 * have a block level mapping. Delay any error to the point
+		 * where we need it.
+		 */
+		realm->spare_page = tmp_rtt;
+	}
+
+	realm_tear_down_rtt_range(&kvm->arch.realm, start_level, ipa, end);
+
+	/* Free up the atomic page, if there were any */
+	if (tmp_rtt != PHYS_ADDR_MAX) {
+		free_delegated_page(realm, tmp_rtt);
+		/*
+		 * Update the spare_page after we have freed the
+		 * above page to make sure it doesn't get cached
+		 * in spare_page.
+		 * We should re-write this part and always have
+		 * a dedicated page for handling block mappings.
+		 */
+		realm->spare_page = PHYS_ADDR_MAX;
+	}
+}
+
+static int set_ipa_state(struct kvm_vcpu *vcpu,
+			 unsigned long ipa,
+			 unsigned long end,
+			 int level,
+			 unsigned long ripas)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct realm *realm = &kvm->arch.realm;
+	struct rec *rec = &vcpu->arch.rec;
+	phys_addr_t rd_phys = virt_to_phys(realm->rd);
+	phys_addr_t rec_phys = virt_to_phys(rec->rec_page);
+	unsigned long map_size = rme_rtt_level_mapsize(level);
+	int ret;
+
+	while (ipa < end) {
+		ret = rmi_rtt_set_ripas(rd_phys, rec_phys, ipa, level, ripas);
+
+		if (!ret) {
+			if (!ripas)
+				kvm_realm_unmap_range(kvm, ipa, map_size);
+		} else if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			int walk_level = RMI_RETURN_INDEX(ret);
+
+			if (walk_level < level) {
+				ret = realm_create_rtt_levels(realm, ipa,
+							      walk_level,
+							      level, NULL);
+				if (ret)
+					return ret;
+				continue;
+			}
+
+			if (WARN_ON(level >= RME_RTT_MAX_LEVEL))
+				return -EINVAL;
+
+			/* Recurse one level lower */
+			ret = set_ipa_state(vcpu, ipa, ipa + map_size,
+					    level + 1, ripas);
+			if (ret)
+				return ret;
+		} else {
+			WARN(1, "Unexpected error in %s: %#x\n", __func__,
+			     ret);
+			return -EINVAL;
+		}
+		ipa += map_size;
+	}
+
+	return 0;
+}
+
+static int realm_init_ipa_state(struct realm *realm,
+				unsigned long ipa,
+				unsigned long end,
+				int level)
+{
+	unsigned long map_size = rme_rtt_level_mapsize(level);
+	phys_addr_t rd_phys = virt_to_phys(realm->rd);
+	int ret;
+
+	while (ipa < end) {
+		ret = rmi_rtt_init_ripas(rd_phys, ipa, level);
+
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			int cur_level = RMI_RETURN_INDEX(ret);
+
+			if (cur_level < level) {
+				ret = realm_create_rtt_levels(realm, ipa,
+							      cur_level,
+							      level, NULL);
+				if (ret)
+					return ret;
+				/* Retry with the RTT levels in place */
+				continue;
+			}
+
+			/* There's an entry at a lower level, recurse */
+			if (WARN_ON(level >= RME_RTT_MAX_LEVEL))
+				return -EINVAL;
+
+			realm_init_ipa_state(realm, ipa, ipa + map_size,
+					     level + 1);
+		} else if (WARN_ON(ret)) {
+			return -ENXIO;
+		}
+
+		ipa += map_size;
+	}
+
+	return 0;
+}
+
+static int find_map_level(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+	int level = RME_RTT_MAX_LEVEL;
+
+	while (level > get_start_level(kvm) + 1) {
+		unsigned long map_size = rme_rtt_level_mapsize(level - 1);
+
+		if (!IS_ALIGNED(start, map_size) ||
+		    (start + map_size) > end)
+			break;
+
+		level--;
+	}
+
+	return level;
+}
+
+int realm_set_ipa_state(struct kvm_vcpu *vcpu,
+			unsigned long addr, unsigned long end,
+			unsigned long ripas)
+{
+	int ret = 0;
+
+	while (addr < end) {
+		int level = find_map_level(vcpu->kvm, addr, end);
+		unsigned long map_size = rme_rtt_level_mapsize(level);
+
+		ret = set_ipa_state(vcpu, addr, addr + map_size, level, ripas);
+		if (ret)
+			break;
+
+		addr += map_size;
+	}
+
+	return ret;
+}
+
+static int kvm_init_ipa_range_realm(struct kvm *kvm,
+				    struct kvm_cap_arm_rme_init_ipa_args *args)
+{
+	int ret = 0;
+	gpa_t addr, end;
+	struct realm *realm = &kvm->arch.realm;
+
+	addr = args->init_ipa_base;
+	end = addr + args->init_ipa_size;
+
+	if (end < addr)
+		return -EINVAL;
+
+	if (kvm_realm_state(kvm) != REALM_STATE_NEW)
+		return -EBUSY;
+
+	while (addr < end) {
+		int level = find_map_level(kvm, addr, end);
+		unsigned long map_size = rme_rtt_level_mapsize(level);
+
+		ret = realm_init_ipa_state(realm, addr, addr + map_size, level);
+		if (ret)
+			break;
+
+		addr += map_size;
+	}
+
+	return ret;
+}
+
 /* Protects access to rme_vmid_bitmap */
 static DEFINE_SPINLOCK(rme_vmid_lock);
 static unsigned long *rme_vmid_bitmap;
@@ -460,6 +736,18 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
 
 		r = kvm_create_realm(kvm);
 		break;
+	case KVM_CAP_ARM_RME_INIT_IPA_REALM: {
+		struct kvm_cap_arm_rme_init_ipa_args args;
+		void __user *argp = u64_to_user_ptr(cap->args[1]);
+
+		if (copy_from_user(&args, argp, sizeof(args))) {
+			r = -EFAULT;
+			break;
+		}
+
+		r = kvm_init_ipa_range_realm(kvm, &args);
+		break;
+	}
 	default:
 		r = -EINVAL;
 		break;
-- 
2.34.1


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

* [RFC PATCH 13/28] arm64: RME: Allow VMM to set RIPAS
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Each page within the protected region of the realm guest can be marked
as either RAM or EMPTY. Allow the VMM to control this before the guest
has started and provide the equivalent functions to change this (with
the guest's approval) at runtime.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |   4 +
 arch/arm64/kvm/rme.c             | 288 +++++++++++++++++++++++++++++++
 2 files changed, 292 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 4b219ebe1400..3e75cedaad18 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -47,6 +47,10 @@ void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level);
 int kvm_create_rec(struct kvm_vcpu *vcpu);
 void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 
+int realm_set_ipa_state(struct kvm_vcpu *vcpu,
+			unsigned long addr, unsigned long end,
+			unsigned long ripas);
+
 #define RME_RTT_BLOCK_LEVEL	2
 #define RME_RTT_MAX_LEVEL	3
 
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index d79ed889ca4d..b3ea79189839 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -73,6 +73,58 @@ static int rmi_check_version(void)
 	return 0;
 }
 
+static phys_addr_t __alloc_delegated_page(struct realm *realm,
+					  struct kvm_mmu_memory_cache *mc, gfp_t flags)
+{
+	phys_addr_t phys = PHYS_ADDR_MAX;
+	void *virt;
+
+	if (realm->spare_page != PHYS_ADDR_MAX) {
+		swap(realm->spare_page, phys);
+		goto out;
+	}
+
+	if (mc)
+		virt = kvm_mmu_memory_cache_alloc(mc);
+	else
+		virt = (void *)__get_free_page(flags);
+
+	if (!virt)
+		goto out;
+
+	phys = virt_to_phys(virt);
+
+	if (rmi_granule_delegate(phys)) {
+		free_page((unsigned long)virt);
+
+		phys = PHYS_ADDR_MAX;
+	}
+
+out:
+	return phys;
+}
+
+static phys_addr_t alloc_delegated_page(struct realm *realm,
+					struct kvm_mmu_memory_cache *mc)
+{
+	return __alloc_delegated_page(realm, mc, GFP_KERNEL);
+}
+
+static void free_delegated_page(struct realm *realm, phys_addr_t phys)
+{
+	if (realm->spare_page == PHYS_ADDR_MAX) {
+		realm->spare_page = phys;
+		return;
+	}
+
+	if (WARN_ON(rmi_granule_undelegate(phys))) {
+		/* Undelegate failed: leak the page */
+		return;
+	}
+
+	free_page((unsigned long)phys_to_virt(phys));
+}
+
 static void realm_destroy_undelegate_range(struct realm *realm,
 					   unsigned long ipa,
 					   unsigned long addr,
@@ -220,6 +272,30 @@ static int realm_rtt_create(struct realm *realm,
 	return rmi_rtt_create(phys, virt_to_phys(realm->rd), addr, level);
 }
 
+static int realm_create_rtt_levels(struct realm *realm,
+				   unsigned long ipa,
+				   int level,
+				   int max_level,
+				   struct kvm_mmu_memory_cache *mc)
+{
+	if (WARN_ON(level == max_level))
+		return 0;
+
+	while (level++ < max_level) {
+		phys_addr_t rtt = alloc_delegated_page(realm, mc);
+
+		if (rtt == PHYS_ADDR_MAX)
+			return -ENOMEM;
+
+		if (realm_rtt_create(realm, ipa, level, rtt)) {
+			free_delegated_page(realm, rtt);
+			return -ENXIO;
+		}
+	}
+
+	return 0;
+}
+
 static int realm_tear_down_rtt_range(struct realm *realm, int level,
 				     unsigned long start, unsigned long end)
 {
@@ -309,6 +385,206 @@ void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level)
 	realm_tear_down_rtt_range(realm, start_level, 0, (1UL << ia_bits));
 }
 
+void kvm_realm_unmap_range(struct kvm *kvm, unsigned long ipa, u64 size)
+{
+	u32 ia_bits = kvm->arch.mmu.pgt->ia_bits;
+	u32 start_level = kvm->arch.mmu.pgt->start_level;
+	unsigned long end = ipa + size;
+	struct realm *realm = &kvm->arch.realm;
+	phys_addr_t tmp_rtt = PHYS_ADDR_MAX;
+
+	if (end > (1UL << ia_bits))
+		end = 1UL << ia_bits;
+	/*
+	 * Make sure we have a spare delegated page for tearing down the
+	 * block mappings. We must use Atomic allocations as we are called
+	 * with kvm->mmu_lock held.
+	 */
+	if (realm->spare_page == PHYS_ADDR_MAX) {
+		tmp_rtt = __alloc_delegated_page(realm, NULL, GFP_ATOMIC);
+		/*
+		 * We don't have to check the status here, as we may not
+		 * have a block level mapping. Delay any error to the point
+		 * where we need it.
+		 */
+		realm->spare_page = tmp_rtt;
+	}
+
+	realm_tear_down_rtt_range(&kvm->arch.realm, start_level, ipa, end);
+
+	/* Free up the atomic page, if there were any */
+	if (tmp_rtt != PHYS_ADDR_MAX) {
+		free_delegated_page(realm, tmp_rtt);
+		/*
+		 * Update the spare_page after we have freed the
+		 * above page to make sure it doesn't get cached
+		 * in spare_page.
+		 * We should re-write this part and always have
+		 * a dedicated page for handling block mappings.
+		 */
+		realm->spare_page = PHYS_ADDR_MAX;
+	}
+}
+
+static int set_ipa_state(struct kvm_vcpu *vcpu,
+			 unsigned long ipa,
+			 unsigned long end,
+			 int level,
+			 unsigned long ripas)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct realm *realm = &kvm->arch.realm;
+	struct rec *rec = &vcpu->arch.rec;
+	phys_addr_t rd_phys = virt_to_phys(realm->rd);
+	phys_addr_t rec_phys = virt_to_phys(rec->rec_page);
+	unsigned long map_size = rme_rtt_level_mapsize(level);
+	int ret;
+
+	while (ipa < end) {
+		ret = rmi_rtt_set_ripas(rd_phys, rec_phys, ipa, level, ripas);
+
+		if (!ret) {
+			if (!ripas)
+				kvm_realm_unmap_range(kvm, ipa, map_size);
+		} else if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			int walk_level = RMI_RETURN_INDEX(ret);
+
+			if (walk_level < level) {
+				ret = realm_create_rtt_levels(realm, ipa,
+							      walk_level,
+							      level, NULL);
+				if (ret)
+					return ret;
+				continue;
+			}
+
+			if (WARN_ON(level >= RME_RTT_MAX_LEVEL))
+				return -EINVAL;
+
+			/* Recurse one level lower */
+			ret = set_ipa_state(vcpu, ipa, ipa + map_size,
+					    level + 1, ripas);
+			if (ret)
+				return ret;
+		} else {
+			WARN(1, "Unexpected error in %s: %#x\n", __func__,
+			     ret);
+			return -EINVAL;
+		}
+		ipa += map_size;
+	}
+
+	return 0;
+}
+
+static int realm_init_ipa_state(struct realm *realm,
+				unsigned long ipa,
+				unsigned long end,
+				int level)
+{
+	unsigned long map_size = rme_rtt_level_mapsize(level);
+	phys_addr_t rd_phys = virt_to_phys(realm->rd);
+	int ret;
+
+	while (ipa < end) {
+		ret = rmi_rtt_init_ripas(rd_phys, ipa, level);
+
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			int cur_level = RMI_RETURN_INDEX(ret);
+
+			if (cur_level < level) {
+				ret = realm_create_rtt_levels(realm, ipa,
+							      cur_level,
+							      level, NULL);
+				if (ret)
+					return ret;
+				/* Retry with the RTT levels in place */
+				continue;
+			}
+
+			/* There's an entry at a lower level, recurse */
+			if (WARN_ON(level >= RME_RTT_MAX_LEVEL))
+				return -EINVAL;
+
+			realm_init_ipa_state(realm, ipa, ipa + map_size,
+					     level + 1);
+		} else if (WARN_ON(ret)) {
+			return -ENXIO;
+		}
+
+		ipa += map_size;
+	}
+
+	return 0;
+}
+
+static int find_map_level(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+	int level = RME_RTT_MAX_LEVEL;
+
+	while (level > get_start_level(kvm) + 1) {
+		unsigned long map_size = rme_rtt_level_mapsize(level - 1);
+
+		if (!IS_ALIGNED(start, map_size) ||
+		    (start + map_size) > end)
+			break;
+
+		level--;
+	}
+
+	return level;
+}
+
+int realm_set_ipa_state(struct kvm_vcpu *vcpu,
+			unsigned long addr, unsigned long end,
+			unsigned long ripas)
+{
+	int ret = 0;
+
+	while (addr < end) {
+		int level = find_map_level(vcpu->kvm, addr, end);
+		unsigned long map_size = rme_rtt_level_mapsize(level);
+
+		ret = set_ipa_state(vcpu, addr, addr + map_size, level, ripas);
+		if (ret)
+			break;
+
+		addr += map_size;
+	}
+
+	return ret;
+}
+
+static int kvm_init_ipa_range_realm(struct kvm *kvm,
+				    struct kvm_cap_arm_rme_init_ipa_args *args)
+{
+	int ret = 0;
+	gpa_t addr, end;
+	struct realm *realm = &kvm->arch.realm;
+
+	addr = args->init_ipa_base;
+	end = addr + args->init_ipa_size;
+
+	if (end < addr)
+		return -EINVAL;
+
+	if (kvm_realm_state(kvm) != REALM_STATE_NEW)
+		return -EBUSY;
+
+	while (addr < end) {
+		int level = find_map_level(kvm, addr, end);
+		unsigned long map_size = rme_rtt_level_mapsize(level);
+
+		ret = realm_init_ipa_state(realm, addr, addr + map_size, level);
+		if (ret)
+			break;
+
+		addr += map_size;
+	}
+
+	return ret;
+}
+
 /* Protects access to rme_vmid_bitmap */
 static DEFINE_SPINLOCK(rme_vmid_lock);
 static unsigned long *rme_vmid_bitmap;
@@ -460,6 +736,18 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
 
 		r = kvm_create_realm(kvm);
 		break;
+	case KVM_CAP_ARM_RME_INIT_IPA_REALM: {
+		struct kvm_cap_arm_rme_init_ipa_args args;
+		void __user *argp = u64_to_user_ptr(cap->args[1]);
+
+		if (copy_from_user(&args, argp, sizeof(args))) {
+			r = -EFAULT;
+			break;
+		}
+
+		r = kvm_init_ipa_range_realm(kvm, &args);
+		break;
+	}
 	default:
 		r = -EINVAL;
 		break;
-- 
2.34.1


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

* [RFC PATCH 14/28] arm64: RME: Handle realm enter/exit
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Entering a realm is done using a SMC call to the RMM. On exit the
exit-codes need to be handled slightly differently to the normal KVM
path so define our own functions for realm enter/exit and hook them
in if the guest is a realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |  11 ++
 arch/arm64/kvm/Makefile          |   2 +-
 arch/arm64/kvm/arm.c             |  19 +++-
 arch/arm64/kvm/rme-exit.c        | 168 +++++++++++++++++++++++++++++++
 arch/arm64/kvm/rme.c             |  11 ++
 5 files changed, 205 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm64/kvm/rme-exit.c

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 3e75cedaad18..9d1583c44a99 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -47,6 +47,9 @@ void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level);
 int kvm_create_rec(struct kvm_vcpu *vcpu);
 void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 
+int kvm_rec_enter(struct kvm_vcpu *vcpu);
+int handle_rme_exit(struct kvm_vcpu *vcpu, int rec_run_status);
+
 int realm_set_ipa_state(struct kvm_vcpu *vcpu,
 			unsigned long addr, unsigned long end,
 			unsigned long ripas);
@@ -69,4 +72,12 @@ static inline unsigned long rme_rtt_level_mapsize(int level)
 	return (1UL << RME_RTT_LEVEL_SHIFT(level));
 }
 
+static inline bool realm_is_addr_protected(struct realm *realm,
+					   unsigned long addr)
+{
+	unsigned int ia_bits = realm->ia_bits;
+
+	return !(addr & ~(BIT(ia_bits - 1) - 1));
+}
+
 #endif
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d2f0400c50da..884c7c44439f 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -21,7 +21,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 	 vgic/vgic-mmio.o vgic/vgic-mmio-v2.o \
 	 vgic/vgic-mmio-v3.o vgic/vgic-kvm-device.o \
 	 vgic/vgic-its.o vgic/vgic-debug.o \
-	 rme.o
+	 rme.o rme-exit.o
 
 kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 1b2547516f62..fd9e28f48903 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -985,7 +985,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 		trace_kvm_entry(*vcpu_pc(vcpu));
 		guest_timing_enter_irqoff();
 
-		ret = kvm_arm_vcpu_enter_exit(vcpu);
+		if (vcpu_is_rec(vcpu))
+			ret = kvm_rec_enter(vcpu);
+		else
+			ret = kvm_arm_vcpu_enter_exit(vcpu);
 
 		vcpu->mode = OUTSIDE_GUEST_MODE;
 		vcpu->stat.exits++;
@@ -1039,10 +1042,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
 		local_irq_enable();
 
-		trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
-
 		/* Exit types that need handling before we can be preempted */
-		handle_exit_early(vcpu, ret);
+		if (!vcpu_is_rec(vcpu)) {
+			trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu),
+				       *vcpu_pc(vcpu));
+
+			handle_exit_early(vcpu, ret);
+		}
 
 		preempt_enable();
 
@@ -1065,7 +1071,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 			ret = ARM_EXCEPTION_IL;
 		}
 
-		ret = handle_exit(vcpu, ret);
+		if (vcpu_is_rec(vcpu))
+			ret = handle_rme_exit(vcpu, ret);
+		else
+			ret = handle_exit(vcpu, ret);
 	}
 
 	/* Tell userspace about in-kernel device output levels */
diff --git a/arch/arm64/kvm/rme-exit.c b/arch/arm64/kvm/rme-exit.c
new file mode 100644
index 000000000000..15a4ff3517db
--- /dev/null
+++ b/arch/arm64/kvm/rme-exit.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#include <linux/kvm_host.h>
+#include <kvm/arm_psci.h>
+
+#include <asm/rmi_smc.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_rme.h>
+#include <asm/kvm_mmu.h>
+
+typedef int (*exit_handler_fn)(struct kvm_vcpu *vcpu);
+
+static int rec_exit_reason_notimpl(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	pr_err("[vcpu %d] Unhandled exit reason from realm (ESR: %#llx)\n",
+	       vcpu->vcpu_id, rec->run->exit.esr);
+	return -ENXIO;
+}
+
+static int rec_exit_sync_dabt(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	if (kvm_vcpu_dabt_iswrite(vcpu) && kvm_vcpu_dabt_isvalid(vcpu))
+		vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu),
+			     rec->run->exit.gprs[0]);
+
+	return kvm_handle_guest_abort(vcpu);
+}
+
+static int rec_exit_sync_iabt(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	pr_err("[vcpu %d] Unhandled instruction abort (ESR: %#llx).\n",
+	       vcpu->vcpu_id, rec->run->exit.esr);
+	return -ENXIO;
+}
+
+static int rec_exit_sys_reg(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+	unsigned long esr = kvm_vcpu_get_esr(vcpu);
+	int rt = kvm_vcpu_sys_get_rt(vcpu);
+	bool is_write = !(esr & 1);
+	int ret;
+
+	if (is_write)
+		vcpu_set_reg(vcpu, rt, rec->run->exit.gprs[0]);
+
+	ret = kvm_handle_sys_reg(vcpu);
+
+	if (ret >= 0 && !is_write)
+		rec->run->entry.gprs[0] = vcpu_get_reg(vcpu, rt);
+
+	return ret;
+}
+
+static exit_handler_fn rec_exit_handlers[] = {
+	[0 ... ESR_ELx_EC_MAX]	= rec_exit_reason_notimpl,
+	[ESR_ELx_EC_SYS64]	= rec_exit_sys_reg,
+	[ESR_ELx_EC_DABT_LOW]	= rec_exit_sync_dabt,
+	[ESR_ELx_EC_IABT_LOW]	= rec_exit_sync_iabt
+};
+
+static int rec_exit_psci(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+	int i;
+
+	for (i = 0; i < REC_RUN_GPRS; i++)
+		vcpu_set_reg(vcpu, i, rec->run->exit.gprs[i]);
+
+	return kvm_psci_call(vcpu);
+}
+
+static int rec_exit_ripas_change(struct kvm_vcpu *vcpu)
+{
+	struct realm *realm = &vcpu->kvm->arch.realm;
+	struct rec *rec = &vcpu->arch.rec;
+	unsigned long base = rec->run->exit.ripas_base;
+	unsigned long size = rec->run->exit.ripas_size;
+	unsigned long ripas = rec->run->exit.ripas_value & 1;
+	int ret = -EINVAL;
+
+	if (realm_is_addr_protected(realm, base) &&
+	    realm_is_addr_protected(realm, base + size))
+		ret = realm_set_ipa_state(vcpu, base, base + size, ripas);
+
+	WARN(ret, "Unable to satisfy SET_IPAS for %#lx - %#lx, ripas: %#lx\n",
+	     base, base + size, ripas);
+
+	return 1;
+}
+
+static void update_arch_timer_irq_lines(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	__vcpu_sys_reg(vcpu, CNTV_CTL_EL0) = rec->run->exit.cntv_ctl;
+	__vcpu_sys_reg(vcpu, CNTV_CVAL_EL0) = rec->run->exit.cntv_cval;
+	__vcpu_sys_reg(vcpu, CNTP_CTL_EL0) = rec->run->exit.cntp_ctl;
+	__vcpu_sys_reg(vcpu, CNTP_CVAL_EL0) = rec->run->exit.cntp_cval;
+
+	kvm_realm_timers_update(vcpu);
+}
+
+/*
+ * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
+ * proper exit to userspace.
+ */
+int handle_rme_exit(struct kvm_vcpu *vcpu, int rec_run_ret)
+{
+	struct rec *rec = &vcpu->arch.rec;
+	u8 esr_ec = ESR_ELx_EC(rec->run->exit.esr);
+	unsigned long status, index;
+
+	status = RMI_RETURN_STATUS(rec_run_ret);
+	index = RMI_RETURN_INDEX(rec_run_ret);
+
+	/*
+	 * If a PSCI_SYSTEM_OFF request raced with a vcpu executing, we might
+	 * see the following status code and index indicating an attempt to run
+	 * a REC when the RD state is SYSTEM_OFF.  In this case, we just need to
+	 * return to user space which can deal with the system event or will try
+	 * to run the KVM VCPU again, at which point we will no longer attempt
+	 * to enter the Realm because we will have a sleep request pending on
+	 * the VCPU as a result of KVM's PSCI handling.
+	 */
+	if (status == RMI_ERROR_REALM && index == 1) {
+		vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
+		return 0;
+	}
+
+	if (rec_run_ret)
+		return -ENXIO;
+
+	vcpu->arch.fault.esr_el2 = rec->run->exit.esr;
+	vcpu->arch.fault.far_el2 = rec->run->exit.far;
+	vcpu->arch.fault.hpfar_el2 = rec->run->exit.hpfar;
+
+	update_arch_timer_irq_lines(vcpu);
+
+	/* Reset the emulation flags for the next run of the REC */
+	rec->run->entry.flags = 0;
+
+	switch (rec->run->exit.exit_reason) {
+	case RMI_EXIT_SYNC:
+		return rec_exit_handlers[esr_ec](vcpu);
+	case RMI_EXIT_IRQ:
+	case RMI_EXIT_FIQ:
+		return 1;
+	case RMI_EXIT_PSCI:
+		return rec_exit_psci(vcpu);
+	case RMI_EXIT_RIPAS_CHANGE:
+		return rec_exit_ripas_change(vcpu);
+	}
+
+	kvm_pr_unimpl("Unsupported exit reason: %u\n",
+		      rec->run->exit.exit_reason);
+	vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+	return 0;
+}
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index b3ea79189839..16e0bfea98b1 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -802,6 +802,17 @@ void kvm_destroy_realm(struct kvm *kvm)
 	kvm_free_stage2_pgd(&kvm->arch.mmu);
 }
 
+int kvm_rec_enter(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	if (kvm_realm_state(vcpu->kvm) != REALM_STATE_ACTIVE)
+		return -EINVAL;
+
+	return rmi_rec_enter(virt_to_phys(rec->rec_page),
+			     virt_to_phys(rec->run));
+}
+
 static void free_rec_aux(struct page **aux_pages,
 			 unsigned int num_aux)
 {
-- 
2.34.1


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

* [RFC PATCH 14/28] arm64: RME: Handle realm enter/exit
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Entering a realm is done using a SMC call to the RMM. On exit the
exit-codes need to be handled slightly differently to the normal KVM
path so define our own functions for realm enter/exit and hook them
in if the guest is a realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |  11 ++
 arch/arm64/kvm/Makefile          |   2 +-
 arch/arm64/kvm/arm.c             |  19 +++-
 arch/arm64/kvm/rme-exit.c        | 168 +++++++++++++++++++++++++++++++
 arch/arm64/kvm/rme.c             |  11 ++
 5 files changed, 205 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm64/kvm/rme-exit.c

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 3e75cedaad18..9d1583c44a99 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -47,6 +47,9 @@ void kvm_realm_destroy_rtts(struct realm *realm, u32 ia_bits, u32 start_level);
 int kvm_create_rec(struct kvm_vcpu *vcpu);
 void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 
+int kvm_rec_enter(struct kvm_vcpu *vcpu);
+int handle_rme_exit(struct kvm_vcpu *vcpu, int rec_run_status);
+
 int realm_set_ipa_state(struct kvm_vcpu *vcpu,
 			unsigned long addr, unsigned long end,
 			unsigned long ripas);
@@ -69,4 +72,12 @@ static inline unsigned long rme_rtt_level_mapsize(int level)
 	return (1UL << RME_RTT_LEVEL_SHIFT(level));
 }
 
+static inline bool realm_is_addr_protected(struct realm *realm,
+					   unsigned long addr)
+{
+	unsigned int ia_bits = realm->ia_bits;
+
+	return !(addr & ~(BIT(ia_bits - 1) - 1));
+}
+
 #endif
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d2f0400c50da..884c7c44439f 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -21,7 +21,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 	 vgic/vgic-mmio.o vgic/vgic-mmio-v2.o \
 	 vgic/vgic-mmio-v3.o vgic/vgic-kvm-device.o \
 	 vgic/vgic-its.o vgic/vgic-debug.o \
-	 rme.o
+	 rme.o rme-exit.o
 
 kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 1b2547516f62..fd9e28f48903 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -985,7 +985,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 		trace_kvm_entry(*vcpu_pc(vcpu));
 		guest_timing_enter_irqoff();
 
-		ret = kvm_arm_vcpu_enter_exit(vcpu);
+		if (vcpu_is_rec(vcpu))
+			ret = kvm_rec_enter(vcpu);
+		else
+			ret = kvm_arm_vcpu_enter_exit(vcpu);
 
 		vcpu->mode = OUTSIDE_GUEST_MODE;
 		vcpu->stat.exits++;
@@ -1039,10 +1042,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
 		local_irq_enable();
 
-		trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
-
 		/* Exit types that need handling before we can be preempted */
-		handle_exit_early(vcpu, ret);
+		if (!vcpu_is_rec(vcpu)) {
+			trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu),
+				       *vcpu_pc(vcpu));
+
+			handle_exit_early(vcpu, ret);
+		}
 
 		preempt_enable();
 
@@ -1065,7 +1071,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 			ret = ARM_EXCEPTION_IL;
 		}
 
-		ret = handle_exit(vcpu, ret);
+		if (vcpu_is_rec(vcpu))
+			ret = handle_rme_exit(vcpu, ret);
+		else
+			ret = handle_exit(vcpu, ret);
 	}
 
 	/* Tell userspace about in-kernel device output levels */
diff --git a/arch/arm64/kvm/rme-exit.c b/arch/arm64/kvm/rme-exit.c
new file mode 100644
index 000000000000..15a4ff3517db
--- /dev/null
+++ b/arch/arm64/kvm/rme-exit.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#include <linux/kvm_host.h>
+#include <kvm/arm_psci.h>
+
+#include <asm/rmi_smc.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_rme.h>
+#include <asm/kvm_mmu.h>
+
+typedef int (*exit_handler_fn)(struct kvm_vcpu *vcpu);
+
+static int rec_exit_reason_notimpl(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	pr_err("[vcpu %d] Unhandled exit reason from realm (ESR: %#llx)\n",
+	       vcpu->vcpu_id, rec->run->exit.esr);
+	return -ENXIO;
+}
+
+static int rec_exit_sync_dabt(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	if (kvm_vcpu_dabt_iswrite(vcpu) && kvm_vcpu_dabt_isvalid(vcpu))
+		vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu),
+			     rec->run->exit.gprs[0]);
+
+	return kvm_handle_guest_abort(vcpu);
+}
+
+static int rec_exit_sync_iabt(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	pr_err("[vcpu %d] Unhandled instruction abort (ESR: %#llx).\n",
+	       vcpu->vcpu_id, rec->run->exit.esr);
+	return -ENXIO;
+}
+
+static int rec_exit_sys_reg(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+	unsigned long esr = kvm_vcpu_get_esr(vcpu);
+	int rt = kvm_vcpu_sys_get_rt(vcpu);
+	bool is_write = !(esr & 1);
+	int ret;
+
+	if (is_write)
+		vcpu_set_reg(vcpu, rt, rec->run->exit.gprs[0]);
+
+	ret = kvm_handle_sys_reg(vcpu);
+
+	if (ret >= 0 && !is_write)
+		rec->run->entry.gprs[0] = vcpu_get_reg(vcpu, rt);
+
+	return ret;
+}
+
+static exit_handler_fn rec_exit_handlers[] = {
+	[0 ... ESR_ELx_EC_MAX]	= rec_exit_reason_notimpl,
+	[ESR_ELx_EC_SYS64]	= rec_exit_sys_reg,
+	[ESR_ELx_EC_DABT_LOW]	= rec_exit_sync_dabt,
+	[ESR_ELx_EC_IABT_LOW]	= rec_exit_sync_iabt
+};
+
+static int rec_exit_psci(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+	int i;
+
+	for (i = 0; i < REC_RUN_GPRS; i++)
+		vcpu_set_reg(vcpu, i, rec->run->exit.gprs[i]);
+
+	return kvm_psci_call(vcpu);
+}
+
+static int rec_exit_ripas_change(struct kvm_vcpu *vcpu)
+{
+	struct realm *realm = &vcpu->kvm->arch.realm;
+	struct rec *rec = &vcpu->arch.rec;
+	unsigned long base = rec->run->exit.ripas_base;
+	unsigned long size = rec->run->exit.ripas_size;
+	unsigned long ripas = rec->run->exit.ripas_value & 1;
+	int ret = -EINVAL;
+
+	if (realm_is_addr_protected(realm, base) &&
+	    realm_is_addr_protected(realm, base + size))
+		ret = realm_set_ipa_state(vcpu, base, base + size, ripas);
+
+	WARN(ret, "Unable to satisfy SET_IPAS for %#lx - %#lx, ripas: %#lx\n",
+	     base, base + size, ripas);
+
+	return 1;
+}
+
+static void update_arch_timer_irq_lines(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	__vcpu_sys_reg(vcpu, CNTV_CTL_EL0) = rec->run->exit.cntv_ctl;
+	__vcpu_sys_reg(vcpu, CNTV_CVAL_EL0) = rec->run->exit.cntv_cval;
+	__vcpu_sys_reg(vcpu, CNTP_CTL_EL0) = rec->run->exit.cntp_ctl;
+	__vcpu_sys_reg(vcpu, CNTP_CVAL_EL0) = rec->run->exit.cntp_cval;
+
+	kvm_realm_timers_update(vcpu);
+}
+
+/*
+ * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
+ * proper exit to userspace.
+ */
+int handle_rme_exit(struct kvm_vcpu *vcpu, int rec_run_ret)
+{
+	struct rec *rec = &vcpu->arch.rec;
+	u8 esr_ec = ESR_ELx_EC(rec->run->exit.esr);
+	unsigned long status, index;
+
+	status = RMI_RETURN_STATUS(rec_run_ret);
+	index = RMI_RETURN_INDEX(rec_run_ret);
+
+	/*
+	 * If a PSCI_SYSTEM_OFF request raced with a vcpu executing, we might
+	 * see the following status code and index indicating an attempt to run
+	 * a REC when the RD state is SYSTEM_OFF.  In this case, we just need to
+	 * return to user space which can deal with the system event or will try
+	 * to run the KVM VCPU again, at which point we will no longer attempt
+	 * to enter the Realm because we will have a sleep request pending on
+	 * the VCPU as a result of KVM's PSCI handling.
+	 */
+	if (status == RMI_ERROR_REALM && index == 1) {
+		vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
+		return 0;
+	}
+
+	if (rec_run_ret)
+		return -ENXIO;
+
+	vcpu->arch.fault.esr_el2 = rec->run->exit.esr;
+	vcpu->arch.fault.far_el2 = rec->run->exit.far;
+	vcpu->arch.fault.hpfar_el2 = rec->run->exit.hpfar;
+
+	update_arch_timer_irq_lines(vcpu);
+
+	/* Reset the emulation flags for the next run of the REC */
+	rec->run->entry.flags = 0;
+
+	switch (rec->run->exit.exit_reason) {
+	case RMI_EXIT_SYNC:
+		return rec_exit_handlers[esr_ec](vcpu);
+	case RMI_EXIT_IRQ:
+	case RMI_EXIT_FIQ:
+		return 1;
+	case RMI_EXIT_PSCI:
+		return rec_exit_psci(vcpu);
+	case RMI_EXIT_RIPAS_CHANGE:
+		return rec_exit_ripas_change(vcpu);
+	}
+
+	kvm_pr_unimpl("Unsupported exit reason: %u\n",
+		      rec->run->exit.exit_reason);
+	vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+	return 0;
+}
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index b3ea79189839..16e0bfea98b1 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -802,6 +802,17 @@ void kvm_destroy_realm(struct kvm *kvm)
 	kvm_free_stage2_pgd(&kvm->arch.mmu);
 }
 
+int kvm_rec_enter(struct kvm_vcpu *vcpu)
+{
+	struct rec *rec = &vcpu->arch.rec;
+
+	if (kvm_realm_state(vcpu->kvm) != REALM_STATE_ACTIVE)
+		return -EINVAL;
+
+	return rmi_rec_enter(virt_to_phys(rec->rec_page),
+			     virt_to_phys(rec->run));
+}
+
 static void free_rec_aux(struct page **aux_pages,
 			 unsigned int num_aux)
 {
-- 
2.34.1


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

* [RFC PATCH 15/28] KVM: arm64: Handle realm MMIO emulation
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

MMIO emulation for a realm cannot be done directly with the VM's
registers as they are protected from the host. However the RMM interface
provides a structure member for providing the read/written value and
we can transfer this to the appropriate VCPU's register entry and then
depend on the generic MMIO handling code in KVM.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/mmio.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c
index 3dd38a151d2a..c4879fa3a8d3 100644
--- a/arch/arm64/kvm/mmio.c
+++ b/arch/arm64/kvm/mmio.c
@@ -6,6 +6,7 @@
 
 #include <linux/kvm_host.h>
 #include <asm/kvm_emulate.h>
+#include <asm/rmi_smc.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
@@ -109,6 +110,9 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
 			       &data);
 		data = vcpu_data_host_to_guest(vcpu, data, len);
 		vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data);
+
+		if (vcpu_is_rec(vcpu))
+			vcpu->arch.rec.run->entry.gprs[0] = data;
 	}
 
 	/*
@@ -179,6 +183,9 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 	run->mmio.len		= len;
 	vcpu->mmio_needed	= 1;
 
+	if (vcpu_is_rec(vcpu))
+		vcpu->arch.rec.run->entry.flags |= RMI_EMULATED_MMIO;
+
 	if (!ret) {
 		/* We handled the access successfully in the kernel. */
 		if (!is_write)
-- 
2.34.1


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

* [RFC PATCH 15/28] KVM: arm64: Handle realm MMIO emulation
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

MMIO emulation for a realm cannot be done directly with the VM's
registers as they are protected from the host. However the RMM interface
provides a structure member for providing the read/written value and
we can transfer this to the appropriate VCPU's register entry and then
depend on the generic MMIO handling code in KVM.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/mmio.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c
index 3dd38a151d2a..c4879fa3a8d3 100644
--- a/arch/arm64/kvm/mmio.c
+++ b/arch/arm64/kvm/mmio.c
@@ -6,6 +6,7 @@
 
 #include <linux/kvm_host.h>
 #include <asm/kvm_emulate.h>
+#include <asm/rmi_smc.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
@@ -109,6 +110,9 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
 			       &data);
 		data = vcpu_data_host_to_guest(vcpu, data, len);
 		vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data);
+
+		if (vcpu_is_rec(vcpu))
+			vcpu->arch.rec.run->entry.gprs[0] = data;
 	}
 
 	/*
@@ -179,6 +183,9 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 	run->mmio.len		= len;
 	vcpu->mmio_needed	= 1;
 
+	if (vcpu_is_rec(vcpu))
+		vcpu->arch.rec.run->entry.flags |= RMI_EMULATED_MMIO;
+
 	if (!ret) {
 		/* We handled the access successfully in the kernel. */
 		if (!is_write)
-- 
2.34.1


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

* [RFC PATCH 16/28] arm64: RME: Allow populating initial contents
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The VMM needs to populate the realm with some data before starting (e.g.
a kernel and initrd). This is measured by the RMM and used as part of
the attestation later on.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/rme.c | 366 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 366 insertions(+)

diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 16e0bfea98b1..3405b43e1421 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/kvm_host.h>
+#include <linux/hugetlb.h>
 
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
@@ -426,6 +427,359 @@ void kvm_realm_unmap_range(struct kvm *kvm, unsigned long ipa, u64 size)
 	}
 }
 
+static int realm_create_protected_data_page(struct realm *realm,
+					    unsigned long ipa,
+					    struct page *dst_page,
+					    struct page *tmp_page)
+{
+	phys_addr_t dst_phys, tmp_phys;
+	int ret;
+
+	copy_page(page_address(tmp_page), page_address(dst_page));
+
+	dst_phys = page_to_phys(dst_page);
+	tmp_phys = page_to_phys(tmp_page);
+
+	if (rmi_granule_delegate(dst_phys))
+		return -ENXIO;
+
+	ret = rmi_data_create(dst_phys, virt_to_phys(realm->rd), ipa, tmp_phys,
+			      RMI_MEASURE_CONTENT);
+
+	if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+		/* Create missing RTTs and retry */
+		int level = RMI_RETURN_INDEX(ret);
+
+		ret = realm_create_rtt_levels(realm, ipa, level,
+					      RME_RTT_MAX_LEVEL, NULL);
+		if (ret)
+			goto err;
+
+		ret = rmi_data_create(dst_phys, virt_to_phys(realm->rd), ipa,
+				      tmp_phys, RMI_MEASURE_CONTENT);
+	}
+
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	if (WARN_ON(rmi_granule_undelegate(dst_phys))) {
+		/* Page can't be returned to NS world so is lost */
+		get_page(dst_page);
+	}
+	return -ENXIO;
+}
+
+static int fold_rtt(phys_addr_t rd, unsigned long addr, int level,
+		    struct realm *realm)
+{
+	struct rtt_entry rtt;
+	phys_addr_t rtt_addr;
+
+	if (rmi_rtt_read_entry(rd, addr, level, &rtt))
+		return -ENXIO;
+
+	if (rtt.state != RMI_TABLE)
+		return -EINVAL;
+
+	rtt_addr = rmi_rtt_get_phys(&rtt);
+	if (rmi_rtt_fold(rtt_addr, rd, addr, level + 1))
+		return -ENXIO;
+
+	free_delegated_page(realm, rtt_addr);
+
+	return 0;
+}
+
+int realm_map_protected(struct realm *realm,
+			unsigned long hva,
+			unsigned long base_ipa,
+			struct page *dst_page,
+			unsigned long map_size,
+			struct kvm_mmu_memory_cache *memcache)
+{
+	phys_addr_t dst_phys = page_to_phys(dst_page);
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	unsigned long phys = dst_phys;
+	unsigned long ipa = base_ipa;
+	unsigned long size;
+	int map_level;
+	int ret = 0;
+
+	if (WARN_ON(!IS_ALIGNED(ipa, map_size)))
+		return -EINVAL;
+
+	switch (map_size) {
+	case PAGE_SIZE:
+		map_level = 3;
+		break;
+	case RME_L2_BLOCK_SIZE:
+		map_level = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (map_level < RME_RTT_MAX_LEVEL) {
+		/*
+		 * A temporary RTT is needed during the map, precreate it,
+		 * however if there is an error (e.g. missing parent tables)
+		 * this will be handled below.
+		 */
+		realm_create_rtt_levels(realm, ipa, map_level,
+					RME_RTT_MAX_LEVEL, memcache);
+	}
+
+	for (size = 0; size < map_size; size += PAGE_SIZE) {
+		if (rmi_granule_delegate(phys)) {
+			struct rtt_entry rtt;
+
+			/*
+			 * It's possible we raced with another VCPU on the same
+			 * fault. If the entry exists and matches then exit
+			 * early and assume the other VCPU will handle the
+			 * mapping.
+			 */
+			if (rmi_rtt_read_entry(rd, ipa, RME_RTT_MAX_LEVEL, &rtt))
+				goto err;
+
+			// FIXME: For a block mapping this could race at level
+			// 2 or 3...
+			if (WARN_ON((rtt.walk_level != RME_RTT_MAX_LEVEL ||
+				     rtt.state != RMI_ASSIGNED ||
+				     rtt.desc != phys))) {
+				goto err;
+			}
+
+			return 0;
+		}
+
+		ret = rmi_data_create_unknown(phys, rd, ipa);
+
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			/* Create missing RTTs and retry */
+			int level = RMI_RETURN_INDEX(ret);
+
+			ret = realm_create_rtt_levels(realm, ipa, level,
+						      RME_RTT_MAX_LEVEL,
+						      memcache);
+			WARN_ON(ret);
+			if (ret)
+				goto err_undelegate;
+
+			ret = rmi_data_create_unknown(phys, rd, ipa);
+		}
+		WARN_ON(ret);
+
+		if (ret)
+			goto err_undelegate;
+
+		phys += PAGE_SIZE;
+		ipa += PAGE_SIZE;
+	}
+
+	if (map_size == RME_L2_BLOCK_SIZE)
+		ret = fold_rtt(rd, base_ipa, map_level, realm);
+	if (WARN_ON(ret))
+		goto err;
+
+	return 0;
+
+err_undelegate:
+	if (WARN_ON(rmi_granule_undelegate(phys))) {
+		/* Page can't be returned to NS world so is lost */
+		get_page(phys_to_page(phys));
+	}
+err:
+	while (size > 0) {
+		phys -= PAGE_SIZE;
+		size -= PAGE_SIZE;
+		ipa -= PAGE_SIZE;
+
+		rmi_data_destroy(rd, ipa);
+
+		if (WARN_ON(rmi_granule_undelegate(phys))) {
+			/* Page can't be returned to NS world so is lost */
+			get_page(phys_to_page(phys));
+		}
+	}
+	return -ENXIO;
+}
+
+static int populate_par_region(struct kvm *kvm,
+			       phys_addr_t ipa_base,
+			       phys_addr_t ipa_end)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct kvm_memory_slot *memslot;
+	gfn_t base_gfn, end_gfn;
+	int idx;
+	phys_addr_t ipa;
+	int ret = 0;
+	struct page *tmp_page;
+	phys_addr_t rd = virt_to_phys(realm->rd);
+
+	base_gfn = gpa_to_gfn(ipa_base);
+	end_gfn = gpa_to_gfn(ipa_end);
+
+	idx = srcu_read_lock(&kvm->srcu);
+	memslot = gfn_to_memslot(kvm, base_gfn);
+	if (!memslot) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	/* We require the region to be contained within a single memslot */
+	if (memslot->base_gfn + memslot->npages < end_gfn) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tmp_page = alloc_page(GFP_KERNEL);
+	if (!tmp_page) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mmap_read_lock(current->mm);
+
+	ipa = ipa_base;
+
+	while (ipa < ipa_end) {
+		struct vm_area_struct *vma;
+		unsigned long map_size;
+		unsigned int vma_shift;
+		unsigned long offset;
+		unsigned long hva;
+		struct page *page;
+		kvm_pfn_t pfn;
+		int level;
+
+		hva = gfn_to_hva_memslot(memslot, gpa_to_gfn(ipa));
+		vma = vma_lookup(current->mm, hva);
+		if (!vma) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (is_vm_hugetlb_page(vma))
+			vma_shift = huge_page_shift(hstate_vma(vma));
+		else
+			vma_shift = PAGE_SHIFT;
+
+		map_size = 1 << vma_shift;
+
+		/*
+		 * FIXME: This causes over mapping, but there's no good
+		 * solution here with the ABI as it stands
+		 */
+		ipa = ALIGN_DOWN(ipa, map_size);
+
+		switch (map_size) {
+		case RME_L2_BLOCK_SIZE:
+			level = 2;
+			break;
+		case PAGE_SIZE:
+			level = 3;
+			break;
+		default:
+			WARN_ONCE(1, "Unsupport vma_shift %d", vma_shift);
+			ret = -EFAULT;
+			break;
+		}
+
+		pfn = gfn_to_pfn_memslot(memslot, gpa_to_gfn(ipa));
+
+		if (is_error_pfn(pfn)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = rmi_rtt_init_ripas(rd, ipa, level);
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			ret = realm_create_rtt_levels(realm, ipa,
+						      RMI_RETURN_INDEX(ret),
+						      level, NULL);
+			if (ret)
+				break;
+			ret = rmi_rtt_init_ripas(rd, ipa, level);
+			if (ret) {
+				ret = -ENXIO;
+				break;
+			}
+		}
+
+		if (level < RME_RTT_MAX_LEVEL) {
+			/*
+			 * A temporary RTT is needed during the map, precreate
+			 * it, however if there is an error (e.g. missing
+			 * parent tables) this will be handled in the
+			 * realm_create_protected_data_page() call.
+			 */
+			realm_create_rtt_levels(realm, ipa, level,
+						RME_RTT_MAX_LEVEL, NULL);
+		}
+
+		page = pfn_to_page(pfn);
+
+		for (offset = 0; offset < map_size && !ret;
+		     offset += PAGE_SIZE, page++) {
+			phys_addr_t page_ipa = ipa + offset;
+
+			ret = realm_create_protected_data_page(realm, page_ipa,
+							       page, tmp_page);
+		}
+		if (ret)
+			goto err_release_pfn;
+
+		if (level == 2) {
+			ret = fold_rtt(rd, ipa, level, realm);
+			if (ret)
+				goto err_release_pfn;
+		}
+
+		ipa += map_size;
+		kvm_set_pfn_accessed(pfn);
+		kvm_set_pfn_dirty(pfn);
+		kvm_release_pfn_dirty(pfn);
+err_release_pfn:
+		if (ret) {
+			kvm_release_pfn_clean(pfn);
+			break;
+		}
+	}
+
+	mmap_read_unlock(current->mm);
+	__free_page(tmp_page);
+
+out:
+	srcu_read_unlock(&kvm->srcu, idx);
+	return ret;
+}
+
+static int kvm_populate_realm(struct kvm *kvm,
+			      struct kvm_cap_arm_rme_populate_realm_args *args)
+{
+	phys_addr_t ipa_base, ipa_end;
+
+	if (kvm_realm_state(kvm) != REALM_STATE_NEW)
+		return -EBUSY;
+
+	if (!IS_ALIGNED(args->populate_ipa_base, PAGE_SIZE) ||
+	    !IS_ALIGNED(args->populate_ipa_size, PAGE_SIZE))
+		return -EINVAL;
+
+	ipa_base = args->populate_ipa_base;
+	ipa_end = ipa_base + args->populate_ipa_size;
+
+	if (ipa_end < ipa_base)
+		return -EINVAL;
+
+	return populate_par_region(kvm, ipa_base, ipa_end);
+}
+
 static int set_ipa_state(struct kvm_vcpu *vcpu,
 			 unsigned long ipa,
 			 unsigned long end,
@@ -748,6 +1102,18 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
 		r = kvm_init_ipa_range_realm(kvm, &args);
 		break;
 	}
+	case KVM_CAP_ARM_RME_POPULATE_REALM: {
+		struct kvm_cap_arm_rme_populate_realm_args args;
+		void __user *argp = u64_to_user_ptr(cap->args[1]);
+
+		if (copy_from_user(&args, argp, sizeof(args))) {
+			r = -EFAULT;
+			break;
+		}
+
+		r = kvm_populate_realm(kvm, &args);
+		break;
+	}
 	default:
 		r = -EINVAL;
 		break;
-- 
2.34.1


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

* [RFC PATCH 16/28] arm64: RME: Allow populating initial contents
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The VMM needs to populate the realm with some data before starting (e.g.
a kernel and initrd). This is measured by the RMM and used as part of
the attestation later on.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/rme.c | 366 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 366 insertions(+)

diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 16e0bfea98b1..3405b43e1421 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/kvm_host.h>
+#include <linux/hugetlb.h>
 
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
@@ -426,6 +427,359 @@ void kvm_realm_unmap_range(struct kvm *kvm, unsigned long ipa, u64 size)
 	}
 }
 
+static int realm_create_protected_data_page(struct realm *realm,
+					    unsigned long ipa,
+					    struct page *dst_page,
+					    struct page *tmp_page)
+{
+	phys_addr_t dst_phys, tmp_phys;
+	int ret;
+
+	copy_page(page_address(tmp_page), page_address(dst_page));
+
+	dst_phys = page_to_phys(dst_page);
+	tmp_phys = page_to_phys(tmp_page);
+
+	if (rmi_granule_delegate(dst_phys))
+		return -ENXIO;
+
+	ret = rmi_data_create(dst_phys, virt_to_phys(realm->rd), ipa, tmp_phys,
+			      RMI_MEASURE_CONTENT);
+
+	if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+		/* Create missing RTTs and retry */
+		int level = RMI_RETURN_INDEX(ret);
+
+		ret = realm_create_rtt_levels(realm, ipa, level,
+					      RME_RTT_MAX_LEVEL, NULL);
+		if (ret)
+			goto err;
+
+		ret = rmi_data_create(dst_phys, virt_to_phys(realm->rd), ipa,
+				      tmp_phys, RMI_MEASURE_CONTENT);
+	}
+
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	if (WARN_ON(rmi_granule_undelegate(dst_phys))) {
+		/* Page can't be returned to NS world so is lost */
+		get_page(dst_page);
+	}
+	return -ENXIO;
+}
+
+static int fold_rtt(phys_addr_t rd, unsigned long addr, int level,
+		    struct realm *realm)
+{
+	struct rtt_entry rtt;
+	phys_addr_t rtt_addr;
+
+	if (rmi_rtt_read_entry(rd, addr, level, &rtt))
+		return -ENXIO;
+
+	if (rtt.state != RMI_TABLE)
+		return -EINVAL;
+
+	rtt_addr = rmi_rtt_get_phys(&rtt);
+	if (rmi_rtt_fold(rtt_addr, rd, addr, level + 1))
+		return -ENXIO;
+
+	free_delegated_page(realm, rtt_addr);
+
+	return 0;
+}
+
+int realm_map_protected(struct realm *realm,
+			unsigned long hva,
+			unsigned long base_ipa,
+			struct page *dst_page,
+			unsigned long map_size,
+			struct kvm_mmu_memory_cache *memcache)
+{
+	phys_addr_t dst_phys = page_to_phys(dst_page);
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	unsigned long phys = dst_phys;
+	unsigned long ipa = base_ipa;
+	unsigned long size;
+	int map_level;
+	int ret = 0;
+
+	if (WARN_ON(!IS_ALIGNED(ipa, map_size)))
+		return -EINVAL;
+
+	switch (map_size) {
+	case PAGE_SIZE:
+		map_level = 3;
+		break;
+	case RME_L2_BLOCK_SIZE:
+		map_level = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (map_level < RME_RTT_MAX_LEVEL) {
+		/*
+		 * A temporary RTT is needed during the map, precreate it,
+		 * however if there is an error (e.g. missing parent tables)
+		 * this will be handled below.
+		 */
+		realm_create_rtt_levels(realm, ipa, map_level,
+					RME_RTT_MAX_LEVEL, memcache);
+	}
+
+	for (size = 0; size < map_size; size += PAGE_SIZE) {
+		if (rmi_granule_delegate(phys)) {
+			struct rtt_entry rtt;
+
+			/*
+			 * It's possible we raced with another VCPU on the same
+			 * fault. If the entry exists and matches then exit
+			 * early and assume the other VCPU will handle the
+			 * mapping.
+			 */
+			if (rmi_rtt_read_entry(rd, ipa, RME_RTT_MAX_LEVEL, &rtt))
+				goto err;
+
+			// FIXME: For a block mapping this could race at level
+			// 2 or 3...
+			if (WARN_ON((rtt.walk_level != RME_RTT_MAX_LEVEL ||
+				     rtt.state != RMI_ASSIGNED ||
+				     rtt.desc != phys))) {
+				goto err;
+			}
+
+			return 0;
+		}
+
+		ret = rmi_data_create_unknown(phys, rd, ipa);
+
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			/* Create missing RTTs and retry */
+			int level = RMI_RETURN_INDEX(ret);
+
+			ret = realm_create_rtt_levels(realm, ipa, level,
+						      RME_RTT_MAX_LEVEL,
+						      memcache);
+			WARN_ON(ret);
+			if (ret)
+				goto err_undelegate;
+
+			ret = rmi_data_create_unknown(phys, rd, ipa);
+		}
+		WARN_ON(ret);
+
+		if (ret)
+			goto err_undelegate;
+
+		phys += PAGE_SIZE;
+		ipa += PAGE_SIZE;
+	}
+
+	if (map_size == RME_L2_BLOCK_SIZE)
+		ret = fold_rtt(rd, base_ipa, map_level, realm);
+	if (WARN_ON(ret))
+		goto err;
+
+	return 0;
+
+err_undelegate:
+	if (WARN_ON(rmi_granule_undelegate(phys))) {
+		/* Page can't be returned to NS world so is lost */
+		get_page(phys_to_page(phys));
+	}
+err:
+	while (size > 0) {
+		phys -= PAGE_SIZE;
+		size -= PAGE_SIZE;
+		ipa -= PAGE_SIZE;
+
+		rmi_data_destroy(rd, ipa);
+
+		if (WARN_ON(rmi_granule_undelegate(phys))) {
+			/* Page can't be returned to NS world so is lost */
+			get_page(phys_to_page(phys));
+		}
+	}
+	return -ENXIO;
+}
+
+static int populate_par_region(struct kvm *kvm,
+			       phys_addr_t ipa_base,
+			       phys_addr_t ipa_end)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct kvm_memory_slot *memslot;
+	gfn_t base_gfn, end_gfn;
+	int idx;
+	phys_addr_t ipa;
+	int ret = 0;
+	struct page *tmp_page;
+	phys_addr_t rd = virt_to_phys(realm->rd);
+
+	base_gfn = gpa_to_gfn(ipa_base);
+	end_gfn = gpa_to_gfn(ipa_end);
+
+	idx = srcu_read_lock(&kvm->srcu);
+	memslot = gfn_to_memslot(kvm, base_gfn);
+	if (!memslot) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	/* We require the region to be contained within a single memslot */
+	if (memslot->base_gfn + memslot->npages < end_gfn) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tmp_page = alloc_page(GFP_KERNEL);
+	if (!tmp_page) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mmap_read_lock(current->mm);
+
+	ipa = ipa_base;
+
+	while (ipa < ipa_end) {
+		struct vm_area_struct *vma;
+		unsigned long map_size;
+		unsigned int vma_shift;
+		unsigned long offset;
+		unsigned long hva;
+		struct page *page;
+		kvm_pfn_t pfn;
+		int level;
+
+		hva = gfn_to_hva_memslot(memslot, gpa_to_gfn(ipa));
+		vma = vma_lookup(current->mm, hva);
+		if (!vma) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (is_vm_hugetlb_page(vma))
+			vma_shift = huge_page_shift(hstate_vma(vma));
+		else
+			vma_shift = PAGE_SHIFT;
+
+		map_size = 1 << vma_shift;
+
+		/*
+		 * FIXME: This causes over mapping, but there's no good
+		 * solution here with the ABI as it stands
+		 */
+		ipa = ALIGN_DOWN(ipa, map_size);
+
+		switch (map_size) {
+		case RME_L2_BLOCK_SIZE:
+			level = 2;
+			break;
+		case PAGE_SIZE:
+			level = 3;
+			break;
+		default:
+			WARN_ONCE(1, "Unsupport vma_shift %d", vma_shift);
+			ret = -EFAULT;
+			break;
+		}
+
+		pfn = gfn_to_pfn_memslot(memslot, gpa_to_gfn(ipa));
+
+		if (is_error_pfn(pfn)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = rmi_rtt_init_ripas(rd, ipa, level);
+		if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+			ret = realm_create_rtt_levels(realm, ipa,
+						      RMI_RETURN_INDEX(ret),
+						      level, NULL);
+			if (ret)
+				break;
+			ret = rmi_rtt_init_ripas(rd, ipa, level);
+			if (ret) {
+				ret = -ENXIO;
+				break;
+			}
+		}
+
+		if (level < RME_RTT_MAX_LEVEL) {
+			/*
+			 * A temporary RTT is needed during the map, precreate
+			 * it, however if there is an error (e.g. missing
+			 * parent tables) this will be handled in the
+			 * realm_create_protected_data_page() call.
+			 */
+			realm_create_rtt_levels(realm, ipa, level,
+						RME_RTT_MAX_LEVEL, NULL);
+		}
+
+		page = pfn_to_page(pfn);
+
+		for (offset = 0; offset < map_size && !ret;
+		     offset += PAGE_SIZE, page++) {
+			phys_addr_t page_ipa = ipa + offset;
+
+			ret = realm_create_protected_data_page(realm, page_ipa,
+							       page, tmp_page);
+		}
+		if (ret)
+			goto err_release_pfn;
+
+		if (level == 2) {
+			ret = fold_rtt(rd, ipa, level, realm);
+			if (ret)
+				goto err_release_pfn;
+		}
+
+		ipa += map_size;
+		kvm_set_pfn_accessed(pfn);
+		kvm_set_pfn_dirty(pfn);
+		kvm_release_pfn_dirty(pfn);
+err_release_pfn:
+		if (ret) {
+			kvm_release_pfn_clean(pfn);
+			break;
+		}
+	}
+
+	mmap_read_unlock(current->mm);
+	__free_page(tmp_page);
+
+out:
+	srcu_read_unlock(&kvm->srcu, idx);
+	return ret;
+}
+
+static int kvm_populate_realm(struct kvm *kvm,
+			      struct kvm_cap_arm_rme_populate_realm_args *args)
+{
+	phys_addr_t ipa_base, ipa_end;
+
+	if (kvm_realm_state(kvm) != REALM_STATE_NEW)
+		return -EBUSY;
+
+	if (!IS_ALIGNED(args->populate_ipa_base, PAGE_SIZE) ||
+	    !IS_ALIGNED(args->populate_ipa_size, PAGE_SIZE))
+		return -EINVAL;
+
+	ipa_base = args->populate_ipa_base;
+	ipa_end = ipa_base + args->populate_ipa_size;
+
+	if (ipa_end < ipa_base)
+		return -EINVAL;
+
+	return populate_par_region(kvm, ipa_base, ipa_end);
+}
+
 static int set_ipa_state(struct kvm_vcpu *vcpu,
 			 unsigned long ipa,
 			 unsigned long end,
@@ -748,6 +1102,18 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
 		r = kvm_init_ipa_range_realm(kvm, &args);
 		break;
 	}
+	case KVM_CAP_ARM_RME_POPULATE_REALM: {
+		struct kvm_cap_arm_rme_populate_realm_args args;
+		void __user *argp = u64_to_user_ptr(cap->args[1]);
+
+		if (copy_from_user(&args, argp, sizeof(args))) {
+			r = -EFAULT;
+			break;
+		}
+
+		r = kvm_populate_realm(kvm, &args);
+		break;
+	}
 	default:
 		r = -EINVAL;
 		break;
-- 
2.34.1


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

* [RFC PATCH 17/28] arm64: RME: Runtime faulting of memory
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

At runtime if the realm guest accesses memory which hasn't yet been
mapped then KVM needs to either populate the region or fault the guest.

For memory in the lower (protected) region of IPA a fresh page is
provided to the RMM which will zero the contents. For memory in the
upper (shared) region of IPA, the memory from the memslot is mapped
into the realm VM non secure.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h | 10 +++++
 arch/arm64/include/asm/kvm_rme.h     | 12 ++++++
 arch/arm64/kvm/mmu.c                 | 64 +++++++++++++++++++++++++---
 arch/arm64/kvm/rme.c                 | 48 +++++++++++++++++++++
 4 files changed, 128 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 285e62914ca4..3a71b3d2e10a 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -502,6 +502,16 @@ static inline enum realm_state kvm_realm_state(struct kvm *kvm)
 	return READ_ONCE(kvm->arch.realm.state);
 }
 
+static inline gpa_t kvm_gpa_stolen_bits(struct kvm *kvm)
+{
+	if (kvm_is_realm(kvm)) {
+		struct realm *realm = &kvm->arch.realm;
+
+		return BIT(realm->ia_bits - 1);
+	}
+	return 0;
+}
+
 static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_rme_is_available))
diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 9d1583c44a99..303e4a5e5704 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -50,6 +50,18 @@ void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 int kvm_rec_enter(struct kvm_vcpu *vcpu);
 int handle_rme_exit(struct kvm_vcpu *vcpu, int rec_run_status);
 
+void kvm_realm_unmap_range(struct kvm *kvm, unsigned long ipa, u64 size);
+int realm_map_protected(struct realm *realm,
+			unsigned long hva,
+			unsigned long base_ipa,
+			struct page *dst_page,
+			unsigned long map_size,
+			struct kvm_mmu_memory_cache *memcache);
+int realm_map_non_secure(struct realm *realm,
+			 unsigned long ipa,
+			 struct page *page,
+			 unsigned long map_size,
+			 struct kvm_mmu_memory_cache *memcache);
 int realm_set_ipa_state(struct kvm_vcpu *vcpu,
 			unsigned long addr, unsigned long end,
 			unsigned long ripas);
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index f29558c5dcbc..5417c273861b 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -235,8 +235,13 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64
 
 	lockdep_assert_held_write(&kvm->mmu_lock);
 	WARN_ON(size & ~PAGE_MASK);
-	WARN_ON(stage2_apply_range(kvm, start, end, kvm_pgtable_stage2_unmap,
-				   may_block));
+
+	if (kvm_is_realm(kvm))
+		kvm_realm_unmap_range(kvm, start, size);
+	else
+		WARN_ON(stage2_apply_range(kvm, start, end,
+					   kvm_pgtable_stage2_unmap,
+					   may_block));
 }
 
 static void unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size)
@@ -250,7 +255,11 @@ static void stage2_flush_memslot(struct kvm *kvm,
 	phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
 	phys_addr_t end = addr + PAGE_SIZE * memslot->npages;
 
-	stage2_apply_range_resched(kvm, addr, end, kvm_pgtable_stage2_flush);
+	if (kvm_is_realm(kvm))
+		kvm_realm_unmap_range(kvm, addr, end - addr);
+	else
+		stage2_apply_range_resched(kvm, addr, end,
+					   kvm_pgtable_stage2_flush);
 }
 
 /**
@@ -818,6 +827,10 @@ void stage2_unmap_vm(struct kvm *kvm)
 	struct kvm_memory_slot *memslot;
 	int idx, bkt;
 
+	/* For realms this is handled by the RMM so nothing to do here */
+	if (kvm_is_realm(kvm))
+		return;
+
 	idx = srcu_read_lock(&kvm->srcu);
 	mmap_read_lock(current->mm);
 	write_lock(&kvm->mmu_lock);
@@ -840,6 +853,7 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 	pgt = mmu->pgt;
 	if (kvm_is_realm(kvm) &&
 	    kvm_realm_state(kvm) != REALM_STATE_DYING) {
+		unmap_stage2_range(mmu, 0, (~0ULL) & PAGE_MASK);
 		write_unlock(&kvm->mmu_lock);
 		kvm_realm_destroy_rtts(&kvm->arch.realm, pgt->ia_bits,
 				       pgt->start_level);
@@ -1190,6 +1204,24 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma)
 	return vma->vm_flags & VM_MTE_ALLOWED;
 }
 
+static int realm_map_ipa(struct kvm *kvm, phys_addr_t ipa, unsigned long hva,
+			 kvm_pfn_t pfn, unsigned long map_size,
+			 enum kvm_pgtable_prot prot,
+			 struct kvm_mmu_memory_cache *memcache)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct page *page = pfn_to_page(pfn);
+
+	if (WARN_ON(!(prot & KVM_PGTABLE_PROT_W)))
+		return -EFAULT;
+
+	if (!realm_is_addr_protected(realm, ipa))
+		return realm_map_non_secure(realm, ipa, page, map_size,
+					    memcache);
+
+	return realm_map_protected(realm, hva, ipa, page, map_size, memcache);
+}
+
 static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 			  struct kvm_memory_slot *memslot, unsigned long hva,
 			  unsigned long fault_status)
@@ -1210,9 +1242,15 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	unsigned long vma_pagesize, fault_granule;
 	enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
 	struct kvm_pgtable *pgt;
+	gpa_t gpa_stolen_mask = kvm_gpa_stolen_bits(vcpu->kvm);
 
 	fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level);
 	write_fault = kvm_is_write_fault(vcpu);
+
+	/* Realms cannot map read-only */
+	if (vcpu_is_rec(vcpu))
+		write_fault = true;
+
 	exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
 	VM_BUG_ON(write_fault && exec_fault);
 
@@ -1272,7 +1310,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE)
 		fault_ipa &= ~(vma_pagesize - 1);
 
-	gfn = fault_ipa >> PAGE_SHIFT;
+	gfn = (fault_ipa & ~gpa_stolen_mask) >> PAGE_SHIFT;
 	mmap_read_unlock(current->mm);
 
 	/*
@@ -1345,7 +1383,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	 * If we are not forced to use page mapping, check if we are
 	 * backed by a THP and thus use block mapping if possible.
 	 */
-	if (vma_pagesize == PAGE_SIZE && !(force_pte || device)) {
+	/* FIXME: We shouldn't need to disable this for realms */
+	if (vma_pagesize == PAGE_SIZE && !(force_pte || device || kvm_is_realm(kvm))) {
 		if (fault_status == FSC_PERM && fault_granule > PAGE_SIZE)
 			vma_pagesize = fault_granule;
 		else
@@ -1382,6 +1421,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	 */
 	if (fault_status == FSC_PERM && vma_pagesize == fault_granule)
 		ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot);
+	else if (kvm_is_realm(kvm))
+		ret = realm_map_ipa(kvm, fault_ipa, hva, pfn, vma_pagesize,
+				    prot, memcache);
 	else
 		ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize,
 					     __pfn_to_phys(pfn), prot,
@@ -1437,6 +1479,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 	struct kvm_memory_slot *memslot;
 	unsigned long hva;
 	bool is_iabt, write_fault, writable;
+	gpa_t gpa_stolen_mask = kvm_gpa_stolen_bits(vcpu->kvm);
 	gfn_t gfn;
 	int ret, idx;
 
@@ -1491,7 +1534,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
 
-	gfn = fault_ipa >> PAGE_SHIFT;
+	gfn = (fault_ipa & ~gpa_stolen_mask) >> PAGE_SHIFT;
 	memslot = gfn_to_memslot(vcpu->kvm, gfn);
 	hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
 	write_fault = kvm_is_write_fault(vcpu);
@@ -1536,6 +1579,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 		 * of the page size.
 		 */
 		fault_ipa |= kvm_vcpu_get_hfar(vcpu) & ((1 << 12) - 1);
+		fault_ipa &= ~gpa_stolen_mask;
 		ret = io_mem_abort(vcpu, fault_ipa);
 		goto out_unlock;
 	}
@@ -1617,6 +1661,10 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 	if (!kvm->arch.mmu.pgt)
 		return false;
 
+	/* We don't support aging for Realms */
+	if (kvm_is_realm(kvm))
+		return true;
+
 	WARN_ON(size != PAGE_SIZE && size != PMD_SIZE && size != PUD_SIZE);
 
 	kpte = kvm_pgtable_stage2_mkold(kvm->arch.mmu.pgt,
@@ -1630,6 +1678,10 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 	if (!kvm->arch.mmu.pgt)
 		return false;
 
+	/* We don't support aging for Realms */
+	if (kvm_is_realm(kvm))
+		return true;
+
 	return kvm_pgtable_stage2_is_young(kvm->arch.mmu.pgt,
 					   range->start << PAGE_SHIFT);
 }
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 3405b43e1421..3d46191798e5 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -608,6 +608,54 @@ int realm_map_protected(struct realm *realm,
 	return -ENXIO;
 }
 
+int realm_map_non_secure(struct realm *realm,
+			 unsigned long ipa,
+			 struct page *page,
+			 unsigned long map_size,
+			 struct kvm_mmu_memory_cache *memcache)
+{
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	int map_level;
+	int ret = 0;
+	unsigned long desc = page_to_phys(page) |
+			     PTE_S2_MEMATTR(MT_S2_FWB_NORMAL) |
+			     /* FIXME: Read+Write permissions for now */
+			     (3 << 6) |
+			     PTE_SHARED;
+
+	if (WARN_ON(!IS_ALIGNED(ipa, map_size)))
+		return -EINVAL;
+
+	switch (map_size) {
+	case PAGE_SIZE:
+		map_level = 3;
+		break;
+	case RME_L2_BLOCK_SIZE:
+		map_level = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = rmi_rtt_map_unprotected(rd, ipa, map_level, desc);
+
+	if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+		/* Create missing RTTs and retry */
+		int level = RMI_RETURN_INDEX(ret);
+
+		ret = realm_create_rtt_levels(realm, ipa, level, map_level,
+					      memcache);
+		if (WARN_ON(ret))
+			return -ENXIO;
+
+		ret = rmi_rtt_map_unprotected(rd, ipa, map_level, desc);
+	}
+	if (WARN_ON(ret))
+		return -ENXIO;
+
+	return 0;
+}
+
 static int populate_par_region(struct kvm *kvm,
 			       phys_addr_t ipa_base,
 			       phys_addr_t ipa_end)
-- 
2.34.1


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

* [RFC PATCH 17/28] arm64: RME: Runtime faulting of memory
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

At runtime if the realm guest accesses memory which hasn't yet been
mapped then KVM needs to either populate the region or fault the guest.

For memory in the lower (protected) region of IPA a fresh page is
provided to the RMM which will zero the contents. For memory in the
upper (shared) region of IPA, the memory from the memslot is mapped
into the realm VM non secure.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h | 10 +++++
 arch/arm64/include/asm/kvm_rme.h     | 12 ++++++
 arch/arm64/kvm/mmu.c                 | 64 +++++++++++++++++++++++++---
 arch/arm64/kvm/rme.c                 | 48 +++++++++++++++++++++
 4 files changed, 128 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 285e62914ca4..3a71b3d2e10a 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -502,6 +502,16 @@ static inline enum realm_state kvm_realm_state(struct kvm *kvm)
 	return READ_ONCE(kvm->arch.realm.state);
 }
 
+static inline gpa_t kvm_gpa_stolen_bits(struct kvm *kvm)
+{
+	if (kvm_is_realm(kvm)) {
+		struct realm *realm = &kvm->arch.realm;
+
+		return BIT(realm->ia_bits - 1);
+	}
+	return 0;
+}
+
 static inline bool vcpu_is_rec(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_rme_is_available))
diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 9d1583c44a99..303e4a5e5704 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -50,6 +50,18 @@ void kvm_destroy_rec(struct kvm_vcpu *vcpu);
 int kvm_rec_enter(struct kvm_vcpu *vcpu);
 int handle_rme_exit(struct kvm_vcpu *vcpu, int rec_run_status);
 
+void kvm_realm_unmap_range(struct kvm *kvm, unsigned long ipa, u64 size);
+int realm_map_protected(struct realm *realm,
+			unsigned long hva,
+			unsigned long base_ipa,
+			struct page *dst_page,
+			unsigned long map_size,
+			struct kvm_mmu_memory_cache *memcache);
+int realm_map_non_secure(struct realm *realm,
+			 unsigned long ipa,
+			 struct page *page,
+			 unsigned long map_size,
+			 struct kvm_mmu_memory_cache *memcache);
 int realm_set_ipa_state(struct kvm_vcpu *vcpu,
 			unsigned long addr, unsigned long end,
 			unsigned long ripas);
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index f29558c5dcbc..5417c273861b 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -235,8 +235,13 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64
 
 	lockdep_assert_held_write(&kvm->mmu_lock);
 	WARN_ON(size & ~PAGE_MASK);
-	WARN_ON(stage2_apply_range(kvm, start, end, kvm_pgtable_stage2_unmap,
-				   may_block));
+
+	if (kvm_is_realm(kvm))
+		kvm_realm_unmap_range(kvm, start, size);
+	else
+		WARN_ON(stage2_apply_range(kvm, start, end,
+					   kvm_pgtable_stage2_unmap,
+					   may_block));
 }
 
 static void unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size)
@@ -250,7 +255,11 @@ static void stage2_flush_memslot(struct kvm *kvm,
 	phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
 	phys_addr_t end = addr + PAGE_SIZE * memslot->npages;
 
-	stage2_apply_range_resched(kvm, addr, end, kvm_pgtable_stage2_flush);
+	if (kvm_is_realm(kvm))
+		kvm_realm_unmap_range(kvm, addr, end - addr);
+	else
+		stage2_apply_range_resched(kvm, addr, end,
+					   kvm_pgtable_stage2_flush);
 }
 
 /**
@@ -818,6 +827,10 @@ void stage2_unmap_vm(struct kvm *kvm)
 	struct kvm_memory_slot *memslot;
 	int idx, bkt;
 
+	/* For realms this is handled by the RMM so nothing to do here */
+	if (kvm_is_realm(kvm))
+		return;
+
 	idx = srcu_read_lock(&kvm->srcu);
 	mmap_read_lock(current->mm);
 	write_lock(&kvm->mmu_lock);
@@ -840,6 +853,7 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
 	pgt = mmu->pgt;
 	if (kvm_is_realm(kvm) &&
 	    kvm_realm_state(kvm) != REALM_STATE_DYING) {
+		unmap_stage2_range(mmu, 0, (~0ULL) & PAGE_MASK);
 		write_unlock(&kvm->mmu_lock);
 		kvm_realm_destroy_rtts(&kvm->arch.realm, pgt->ia_bits,
 				       pgt->start_level);
@@ -1190,6 +1204,24 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma)
 	return vma->vm_flags & VM_MTE_ALLOWED;
 }
 
+static int realm_map_ipa(struct kvm *kvm, phys_addr_t ipa, unsigned long hva,
+			 kvm_pfn_t pfn, unsigned long map_size,
+			 enum kvm_pgtable_prot prot,
+			 struct kvm_mmu_memory_cache *memcache)
+{
+	struct realm *realm = &kvm->arch.realm;
+	struct page *page = pfn_to_page(pfn);
+
+	if (WARN_ON(!(prot & KVM_PGTABLE_PROT_W)))
+		return -EFAULT;
+
+	if (!realm_is_addr_protected(realm, ipa))
+		return realm_map_non_secure(realm, ipa, page, map_size,
+					    memcache);
+
+	return realm_map_protected(realm, hva, ipa, page, map_size, memcache);
+}
+
 static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 			  struct kvm_memory_slot *memslot, unsigned long hva,
 			  unsigned long fault_status)
@@ -1210,9 +1242,15 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	unsigned long vma_pagesize, fault_granule;
 	enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
 	struct kvm_pgtable *pgt;
+	gpa_t gpa_stolen_mask = kvm_gpa_stolen_bits(vcpu->kvm);
 
 	fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level);
 	write_fault = kvm_is_write_fault(vcpu);
+
+	/* Realms cannot map read-only */
+	if (vcpu_is_rec(vcpu))
+		write_fault = true;
+
 	exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
 	VM_BUG_ON(write_fault && exec_fault);
 
@@ -1272,7 +1310,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE)
 		fault_ipa &= ~(vma_pagesize - 1);
 
-	gfn = fault_ipa >> PAGE_SHIFT;
+	gfn = (fault_ipa & ~gpa_stolen_mask) >> PAGE_SHIFT;
 	mmap_read_unlock(current->mm);
 
 	/*
@@ -1345,7 +1383,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	 * If we are not forced to use page mapping, check if we are
 	 * backed by a THP and thus use block mapping if possible.
 	 */
-	if (vma_pagesize == PAGE_SIZE && !(force_pte || device)) {
+	/* FIXME: We shouldn't need to disable this for realms */
+	if (vma_pagesize == PAGE_SIZE && !(force_pte || device || kvm_is_realm(kvm))) {
 		if (fault_status == FSC_PERM && fault_granule > PAGE_SIZE)
 			vma_pagesize = fault_granule;
 		else
@@ -1382,6 +1421,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	 */
 	if (fault_status == FSC_PERM && vma_pagesize == fault_granule)
 		ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot);
+	else if (kvm_is_realm(kvm))
+		ret = realm_map_ipa(kvm, fault_ipa, hva, pfn, vma_pagesize,
+				    prot, memcache);
 	else
 		ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize,
 					     __pfn_to_phys(pfn), prot,
@@ -1437,6 +1479,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 	struct kvm_memory_slot *memslot;
 	unsigned long hva;
 	bool is_iabt, write_fault, writable;
+	gpa_t gpa_stolen_mask = kvm_gpa_stolen_bits(vcpu->kvm);
 	gfn_t gfn;
 	int ret, idx;
 
@@ -1491,7 +1534,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
 
-	gfn = fault_ipa >> PAGE_SHIFT;
+	gfn = (fault_ipa & ~gpa_stolen_mask) >> PAGE_SHIFT;
 	memslot = gfn_to_memslot(vcpu->kvm, gfn);
 	hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
 	write_fault = kvm_is_write_fault(vcpu);
@@ -1536,6 +1579,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 		 * of the page size.
 		 */
 		fault_ipa |= kvm_vcpu_get_hfar(vcpu) & ((1 << 12) - 1);
+		fault_ipa &= ~gpa_stolen_mask;
 		ret = io_mem_abort(vcpu, fault_ipa);
 		goto out_unlock;
 	}
@@ -1617,6 +1661,10 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 	if (!kvm->arch.mmu.pgt)
 		return false;
 
+	/* We don't support aging for Realms */
+	if (kvm_is_realm(kvm))
+		return true;
+
 	WARN_ON(size != PAGE_SIZE && size != PMD_SIZE && size != PUD_SIZE);
 
 	kpte = kvm_pgtable_stage2_mkold(kvm->arch.mmu.pgt,
@@ -1630,6 +1678,10 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 	if (!kvm->arch.mmu.pgt)
 		return false;
 
+	/* We don't support aging for Realms */
+	if (kvm_is_realm(kvm))
+		return true;
+
 	return kvm_pgtable_stage2_is_young(kvm->arch.mmu.pgt,
 					   range->start << PAGE_SHIFT);
 }
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 3405b43e1421..3d46191798e5 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -608,6 +608,54 @@ int realm_map_protected(struct realm *realm,
 	return -ENXIO;
 }
 
+int realm_map_non_secure(struct realm *realm,
+			 unsigned long ipa,
+			 struct page *page,
+			 unsigned long map_size,
+			 struct kvm_mmu_memory_cache *memcache)
+{
+	phys_addr_t rd = virt_to_phys(realm->rd);
+	int map_level;
+	int ret = 0;
+	unsigned long desc = page_to_phys(page) |
+			     PTE_S2_MEMATTR(MT_S2_FWB_NORMAL) |
+			     /* FIXME: Read+Write permissions for now */
+			     (3 << 6) |
+			     PTE_SHARED;
+
+	if (WARN_ON(!IS_ALIGNED(ipa, map_size)))
+		return -EINVAL;
+
+	switch (map_size) {
+	case PAGE_SIZE:
+		map_level = 3;
+		break;
+	case RME_L2_BLOCK_SIZE:
+		map_level = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = rmi_rtt_map_unprotected(rd, ipa, map_level, desc);
+
+	if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+		/* Create missing RTTs and retry */
+		int level = RMI_RETURN_INDEX(ret);
+
+		ret = realm_create_rtt_levels(realm, ipa, level, map_level,
+					      memcache);
+		if (WARN_ON(ret))
+			return -ENXIO;
+
+		ret = rmi_rtt_map_unprotected(rd, ipa, map_level, desc);
+	}
+	if (WARN_ON(ret))
+		return -ENXIO;
+
+	return 0;
+}
+
 static int populate_par_region(struct kvm *kvm,
 			       phys_addr_t ipa_base,
 			       phys_addr_t ipa_end)
-- 
2.34.1


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

* [RFC PATCH 18/28] KVM: arm64: Handle realm VCPU load
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

When loading a realm VCPU much of the work is handled by the RMM so only
some of the actions are required. Rearrange kvm_arch_vcpu_load()
slightly so we can bail out early for a realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arm.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index fd9e28f48903..46c152a9a150 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -451,19 +451,25 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
 	vcpu->cpu = cpu;
 
+	if (single_task_running())
+		vcpu_clear_wfx_traps(vcpu);
+	else
+		vcpu_set_wfx_traps(vcpu);
+
 	kvm_vgic_load(vcpu);
 	kvm_timer_vcpu_load(vcpu);
+
+	if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
+		kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
+
+	/* No additional state needs to be loaded on Realmed VMs */
+	if (vcpu_is_rec(vcpu))
+		return;
+
 	if (has_vhe())
 		kvm_vcpu_load_sysregs_vhe(vcpu);
 	kvm_arch_vcpu_load_fp(vcpu);
 	kvm_vcpu_pmu_restore_guest(vcpu);
-	if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
-		kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
-
-	if (single_task_running())
-		vcpu_clear_wfx_traps(vcpu);
-	else
-		vcpu_set_wfx_traps(vcpu);
 
 	if (vcpu_has_ptrauth(vcpu))
 		vcpu_ptrauth_disable(vcpu);
-- 
2.34.1


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

* [RFC PATCH 18/28] KVM: arm64: Handle realm VCPU load
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

When loading a realm VCPU much of the work is handled by the RMM so only
some of the actions are required. Rearrange kvm_arch_vcpu_load()
slightly so we can bail out early for a realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arm.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index fd9e28f48903..46c152a9a150 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -451,19 +451,25 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
 	vcpu->cpu = cpu;
 
+	if (single_task_running())
+		vcpu_clear_wfx_traps(vcpu);
+	else
+		vcpu_set_wfx_traps(vcpu);
+
 	kvm_vgic_load(vcpu);
 	kvm_timer_vcpu_load(vcpu);
+
+	if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
+		kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
+
+	/* No additional state needs to be loaded on Realmed VMs */
+	if (vcpu_is_rec(vcpu))
+		return;
+
 	if (has_vhe())
 		kvm_vcpu_load_sysregs_vhe(vcpu);
 	kvm_arch_vcpu_load_fp(vcpu);
 	kvm_vcpu_pmu_restore_guest(vcpu);
-	if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
-		kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
-
-	if (single_task_running())
-		vcpu_clear_wfx_traps(vcpu);
-	else
-		vcpu_set_wfx_traps(vcpu);
 
 	if (vcpu_has_ptrauth(vcpu))
 		vcpu_ptrauth_disable(vcpu);
-- 
2.34.1


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

* [RFC PATCH 19/28] KVM: arm64: Validate register access for a Realm VM
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM only allows setting the lower GPRS (x0-x7) and PC for a realm
guest. Check this in kvm_arm_set_reg() so that the VMM can receive a
suitable error return if other registers are accessed.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/guest.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 5626ddb540ce..93468bbfb50e 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -768,12 +768,38 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return kvm_arm_sys_reg_get_reg(vcpu, reg);
 }
 
+/*
+ * The RMI ABI only enables setting the lower GPRs (x0-x7) and PC.
+ * All other registers are reset to architectural or otherwise defined reset
+ * values by the RMM
+ */
+static bool validate_realm_set_reg(struct kvm_vcpu *vcpu,
+				   const struct kvm_one_reg *reg)
+{
+	u64 off = core_reg_offset_from_id(reg->id);
+
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM_CORE)
+		return false;
+
+	switch (off) {
+	case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
+	     KVM_REG_ARM_CORE_REG(regs.regs[7]):
+	case KVM_REG_ARM_CORE_REG(regs.pc):
+		return true;
+	}
+
+	return false;
+}
+
 int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	/* We currently use nothing arch-specific in upper 32 bits */
 	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
 		return -EINVAL;
 
+	if (kvm_is_realm(vcpu->kvm) && !validate_realm_set_reg(vcpu, reg))
+		return -EINVAL;
+
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
 	case KVM_REG_ARM_FW:
-- 
2.34.1


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

* [RFC PATCH 19/28] KVM: arm64: Validate register access for a Realm VM
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM only allows setting the lower GPRS (x0-x7) and PC for a realm
guest. Check this in kvm_arm_set_reg() so that the VMM can receive a
suitable error return if other registers are accessed.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/guest.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 5626ddb540ce..93468bbfb50e 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -768,12 +768,38 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return kvm_arm_sys_reg_get_reg(vcpu, reg);
 }
 
+/*
+ * The RMI ABI only enables setting the lower GPRs (x0-x7) and PC.
+ * All other registers are reset to architectural or otherwise defined reset
+ * values by the RMM
+ */
+static bool validate_realm_set_reg(struct kvm_vcpu *vcpu,
+				   const struct kvm_one_reg *reg)
+{
+	u64 off = core_reg_offset_from_id(reg->id);
+
+	if ((reg->id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM_CORE)
+		return false;
+
+	switch (off) {
+	case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
+	     KVM_REG_ARM_CORE_REG(regs.regs[7]):
+	case KVM_REG_ARM_CORE_REG(regs.pc):
+		return true;
+	}
+
+	return false;
+}
+
 int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	/* We currently use nothing arch-specific in upper 32 bits */
 	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
 		return -EINVAL;
 
+	if (kvm_is_realm(vcpu->kvm) && !validate_realm_set_reg(vcpu, reg))
+		return -EINVAL;
+
 	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
 	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
 	case KVM_REG_ARM_FW:
-- 
2.34.1


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

* [RFC PATCH 20/28] KVM: arm64: Handle Realm PSCI requests
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM needs to be informed of the target REC when a PSCI call is made
with an MPIDR argument.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |  1 +
 arch/arm64/kvm/psci.c            | 23 +++++++++++++++++++++++
 arch/arm64/kvm/rme.c             | 13 +++++++++++++
 3 files changed, 37 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 303e4a5e5704..2254e28c855e 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -65,6 +65,7 @@ int realm_map_non_secure(struct realm *realm,
 int realm_set_ipa_state(struct kvm_vcpu *vcpu,
 			unsigned long addr, unsigned long end,
 			unsigned long ripas);
+int realm_psci_complete(struct kvm_vcpu *calling, struct kvm_vcpu *target);
 
 #define RME_RTT_BLOCK_LEVEL	2
 #define RME_RTT_MAX_LEVEL	3
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index 7fbc4c1b9df0..e2061cab9b26 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -76,6 +76,10 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	 */
 	if (!vcpu)
 		return PSCI_RET_INVALID_PARAMS;
+
+	if (vcpu_is_rec(vcpu))
+		realm_psci_complete(source_vcpu, vcpu);
+
 	if (!kvm_arm_vcpu_stopped(vcpu)) {
 		if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
 			return PSCI_RET_ALREADY_ON;
@@ -135,6 +139,25 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
 	/* Ignore other bits of target affinity */
 	target_affinity &= target_affinity_mask;
 
+	if (vcpu_is_rec(vcpu)) {
+		struct kvm_vcpu *target_vcpu;
+
+		/* RMM supports only zero affinity level */
+		if (lowest_affinity_level != 0)
+			return PSCI_RET_INVALID_PARAMS;
+
+		target_vcpu = kvm_mpidr_to_vcpu(kvm, target_affinity);
+		if (!target_vcpu)
+			return PSCI_RET_INVALID_PARAMS;
+
+		/*
+		 * Provide the references of running and target RECs to the RMM
+		 * so that the RMM can complete the PSCI request.
+		 */
+		realm_psci_complete(vcpu, target_vcpu);
+		return PSCI_RET_SUCCESS;
+	}
+
 	/*
 	 * If one or more VCPU matching target affinity are running
 	 * then ON else OFF
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 3d46191798e5..6ac50481a138 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -126,6 +126,19 @@ static void free_delegated_page(struct realm *realm, phys_addr_t phys)
 	free_page((unsigned long)phys_to_virt(phys));
 }
 
+int realm_psci_complete(struct kvm_vcpu *calling, struct kvm_vcpu *target)
+{
+	int ret;
+
+	ret = rmi_psci_complete(virt_to_phys(calling->arch.rec.rec_page),
+				virt_to_phys(target->arch.rec.rec_page));
+
+	if (ret)
+		return -EINVAL;
+
+	return 0;
+}
+
 static void realm_destroy_undelegate_range(struct realm *realm,
 					   unsigned long ipa,
 					   unsigned long addr,
-- 
2.34.1


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

* [RFC PATCH 20/28] KVM: arm64: Handle Realm PSCI requests
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM needs to be informed of the target REC when a PSCI call is made
with an MPIDR argument.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h |  1 +
 arch/arm64/kvm/psci.c            | 23 +++++++++++++++++++++++
 arch/arm64/kvm/rme.c             | 13 +++++++++++++
 3 files changed, 37 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 303e4a5e5704..2254e28c855e 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -65,6 +65,7 @@ int realm_map_non_secure(struct realm *realm,
 int realm_set_ipa_state(struct kvm_vcpu *vcpu,
 			unsigned long addr, unsigned long end,
 			unsigned long ripas);
+int realm_psci_complete(struct kvm_vcpu *calling, struct kvm_vcpu *target);
 
 #define RME_RTT_BLOCK_LEVEL	2
 #define RME_RTT_MAX_LEVEL	3
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c
index 7fbc4c1b9df0..e2061cab9b26 100644
--- a/arch/arm64/kvm/psci.c
+++ b/arch/arm64/kvm/psci.c
@@ -76,6 +76,10 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
 	 */
 	if (!vcpu)
 		return PSCI_RET_INVALID_PARAMS;
+
+	if (vcpu_is_rec(vcpu))
+		realm_psci_complete(source_vcpu, vcpu);
+
 	if (!kvm_arm_vcpu_stopped(vcpu)) {
 		if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
 			return PSCI_RET_ALREADY_ON;
@@ -135,6 +139,25 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
 	/* Ignore other bits of target affinity */
 	target_affinity &= target_affinity_mask;
 
+	if (vcpu_is_rec(vcpu)) {
+		struct kvm_vcpu *target_vcpu;
+
+		/* RMM supports only zero affinity level */
+		if (lowest_affinity_level != 0)
+			return PSCI_RET_INVALID_PARAMS;
+
+		target_vcpu = kvm_mpidr_to_vcpu(kvm, target_affinity);
+		if (!target_vcpu)
+			return PSCI_RET_INVALID_PARAMS;
+
+		/*
+		 * Provide the references of running and target RECs to the RMM
+		 * so that the RMM can complete the PSCI request.
+		 */
+		realm_psci_complete(vcpu, target_vcpu);
+		return PSCI_RET_SUCCESS;
+	}
+
 	/*
 	 * If one or more VCPU matching target affinity are running
 	 * then ON else OFF
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 3d46191798e5..6ac50481a138 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -126,6 +126,19 @@ static void free_delegated_page(struct realm *realm, phys_addr_t phys)
 	free_page((unsigned long)phys_to_virt(phys));
 }
 
+int realm_psci_complete(struct kvm_vcpu *calling, struct kvm_vcpu *target)
+{
+	int ret;
+
+	ret = rmi_psci_complete(virt_to_phys(calling->arch.rec.rec_page),
+				virt_to_phys(target->arch.rec.rec_page));
+
+	if (ret)
+		return -EINVAL;
+
+	return 0;
+}
+
 static void realm_destroy_undelegate_range(struct realm *realm,
 					   unsigned long ipa,
 					   unsigned long addr,
-- 
2.34.1


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

* [RFC PATCH 21/28] KVM: arm64: WARN on injected undef exceptions
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM doesn't allow injection of a undefined exception into a realm
guest. Add a WARN to catch if this ever happens.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/inject_fault.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index f32f4a2a347f..29966a3e5a71 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -175,6 +175,8 @@ void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 {
+	if (vcpu_is_rec(vcpu))
+		WARN(1, "Cannot inject undefined exception into REC. Continuing with unknown behaviour");
 	if (vcpu_el1_is_32bit(vcpu))
 		inject_undef32(vcpu);
 	else
-- 
2.34.1


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

* [RFC PATCH 21/28] KVM: arm64: WARN on injected undef exceptions
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The RMM doesn't allow injection of a undefined exception into a realm
guest. Add a WARN to catch if this ever happens.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/inject_fault.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index f32f4a2a347f..29966a3e5a71 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -175,6 +175,8 @@ void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 {
+	if (vcpu_is_rec(vcpu))
+		WARN(1, "Cannot inject undefined exception into REC. Continuing with unknown behaviour");
 	if (vcpu_el1_is_32bit(vcpu))
 		inject_undef32(vcpu);
 	else
-- 
2.34.1


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

* [RFC PATCH 22/28] arm64: Don't expose stolen time for realm guests
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

It doesn't make much sense and with the ABI as it is it's a footgun for
the VMM which makes fatal granule protection faults easy to trigger.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arm.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 46c152a9a150..645df5968e1e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -302,7 +302,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		r = system_supports_mte();
 		break;
 	case KVM_CAP_STEAL_TIME:
-		r = kvm_arm_pvtime_supported();
+		if (kvm && kvm_is_realm(kvm))
+			r = 0;
+		else
+			r = kvm_arm_pvtime_supported();
 		break;
 	case KVM_CAP_ARM_EL1_32BIT:
 		r = cpus_have_const_cap(ARM64_HAS_32BIT_EL1);
-- 
2.34.1


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

* [RFC PATCH 22/28] arm64: Don't expose stolen time for realm guests
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

It doesn't make much sense and with the ABI as it is it's a footgun for
the VMM which makes fatal granule protection faults easy to trigger.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/arm.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 46c152a9a150..645df5968e1e 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -302,7 +302,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		r = system_supports_mte();
 		break;
 	case KVM_CAP_STEAL_TIME:
-		r = kvm_arm_pvtime_supported();
+		if (kvm && kvm_is_realm(kvm))
+			r = 0;
+		else
+			r = kvm_arm_pvtime_supported();
 		break;
 	case KVM_CAP_ARM_EL1_32BIT:
 		r = cpus_have_const_cap(ARM64_HAS_32BIT_EL1);
-- 
2.34.1


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

* [RFC PATCH 23/28] KVM: arm64: Allow activating realms
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Add the ioctl to activate a realm and set the static branch to enable
access to the realm functionality if the RMM is detected.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/rme.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 6ac50481a138..543e8d10f532 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -1000,6 +1000,20 @@ static int kvm_init_ipa_range_realm(struct kvm *kvm,
 	return ret;
 }
 
+static int kvm_activate_realm(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+
+	if (kvm_realm_state(kvm) != REALM_STATE_NEW)
+		return -EBUSY;
+
+	if (rmi_realm_activate(virt_to_phys(realm->rd)))
+		return -ENXIO;
+
+	WRITE_ONCE(realm->state, REALM_STATE_ACTIVE);
+	return 0;
+}
+
 /* Protects access to rme_vmid_bitmap */
 static DEFINE_SPINLOCK(rme_vmid_lock);
 static unsigned long *rme_vmid_bitmap;
@@ -1175,6 +1189,9 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
 		r = kvm_populate_realm(kvm, &args);
 		break;
 	}
+	case KVM_CAP_ARM_RME_ACTIVATE_REALM:
+		r = kvm_activate_realm(kvm);
+		break;
 	default:
 		r = -EINVAL;
 		break;
@@ -1415,7 +1432,7 @@ int kvm_init_rme(void)
 
 	WARN_ON(rmi_features(0, &rmm_feat_reg0));
 
-	/* Future patch will enable static branch kvm_rme_is_available */
+	static_branch_enable(&kvm_rme_is_available);
 
 	return 0;
 }
-- 
2.34.1


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

* [RFC PATCH 23/28] KVM: arm64: Allow activating realms
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Add the ioctl to activate a realm and set the static branch to enable
access to the realm functionality if the RMM is detected.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/rme.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 6ac50481a138..543e8d10f532 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -1000,6 +1000,20 @@ static int kvm_init_ipa_range_realm(struct kvm *kvm,
 	return ret;
 }
 
+static int kvm_activate_realm(struct kvm *kvm)
+{
+	struct realm *realm = &kvm->arch.realm;
+
+	if (kvm_realm_state(kvm) != REALM_STATE_NEW)
+		return -EBUSY;
+
+	if (rmi_realm_activate(virt_to_phys(realm->rd)))
+		return -ENXIO;
+
+	WRITE_ONCE(realm->state, REALM_STATE_ACTIVE);
+	return 0;
+}
+
 /* Protects access to rme_vmid_bitmap */
 static DEFINE_SPINLOCK(rme_vmid_lock);
 static unsigned long *rme_vmid_bitmap;
@@ -1175,6 +1189,9 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
 		r = kvm_populate_realm(kvm, &args);
 		break;
 	}
+	case KVM_CAP_ARM_RME_ACTIVATE_REALM:
+		r = kvm_activate_realm(kvm);
+		break;
 	default:
 		r = -EINVAL;
 		break;
@@ -1415,7 +1432,7 @@ int kvm_init_rme(void)
 
 	WARN_ON(rmi_features(0, &rmm_feat_reg0));
 
-	/* Future patch will enable static branch kvm_rme_is_available */
+	static_branch_enable(&kvm_rme_is_available);
 
 	return 0;
 }
-- 
2.34.1


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

* [RFC PATCH 24/28] arm64: rme: allow userspace to inject aborts
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Joey Gouly <joey.gouly@arm.com>

Extend KVM_SET_VCPU_EVENTS to support realms, where KVM cannot set the
system registers, and the RMM must perform it on next REC entry.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 Documentation/virt/kvm/api.rst |  2 ++
 arch/arm64/kvm/guest.c         | 24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index f1a59d6fb7fc..18a8ddaf31d8 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -1238,6 +1238,8 @@ User space may need to inject several types of events to the guest.
 Set the pending SError exception state for this VCPU. It is not possible to
 'cancel' an Serror that has been made pending.
 
+User space cannot inject SErrors into Realms.
+
 If the guest performed an access to I/O memory which could not be handled by
 userspace, for example because of missing instruction syndrome decode
 information or because there is no device mapped at the accessed IPA, then
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 93468bbfb50e..6e53e0ef2fba 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -851,6 +851,30 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
 	bool has_esr = events->exception.serror_has_esr;
 	bool ext_dabt_pending = events->exception.ext_dabt_pending;
 
+	if (vcpu_is_rec(vcpu)) {
+		/* Cannot inject SError into a Realm. */
+		if (serror_pending)
+			return -EINVAL;
+
+		/*
+		 * If a data abort is pending, set the flag and let the RMM
+		 * inject an SEA when the REC is scheduled to be run.
+		 */
+		if (ext_dabt_pending) {
+			/*
+			 * Can only inject SEA into a Realm if the previous exit
+			 * was due to a data abort of an Unprotected IPA.
+			 */
+			if (!(vcpu->arch.rec.run->entry.flags & RMI_EMULATED_MMIO))
+				return -EINVAL;
+
+			vcpu->arch.rec.run->entry.flags &= ~RMI_EMULATED_MMIO;
+			vcpu->arch.rec.run->entry.flags |= RMI_INJECT_SEA;
+		}
+
+		return 0;
+	}
+
 	if (serror_pending && has_esr) {
 		if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
 			return -EINVAL;
-- 
2.34.1


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

* [RFC PATCH 24/28] arm64: rme: allow userspace to inject aborts
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Joey Gouly <joey.gouly@arm.com>

Extend KVM_SET_VCPU_EVENTS to support realms, where KVM cannot set the
system registers, and the RMM must perform it on next REC entry.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 Documentation/virt/kvm/api.rst |  2 ++
 arch/arm64/kvm/guest.c         | 24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index f1a59d6fb7fc..18a8ddaf31d8 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -1238,6 +1238,8 @@ User space may need to inject several types of events to the guest.
 Set the pending SError exception state for this VCPU. It is not possible to
 'cancel' an Serror that has been made pending.
 
+User space cannot inject SErrors into Realms.
+
 If the guest performed an access to I/O memory which could not be handled by
 userspace, for example because of missing instruction syndrome decode
 information or because there is no device mapped at the accessed IPA, then
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 93468bbfb50e..6e53e0ef2fba 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -851,6 +851,30 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
 	bool has_esr = events->exception.serror_has_esr;
 	bool ext_dabt_pending = events->exception.ext_dabt_pending;
 
+	if (vcpu_is_rec(vcpu)) {
+		/* Cannot inject SError into a Realm. */
+		if (serror_pending)
+			return -EINVAL;
+
+		/*
+		 * If a data abort is pending, set the flag and let the RMM
+		 * inject an SEA when the REC is scheduled to be run.
+		 */
+		if (ext_dabt_pending) {
+			/*
+			 * Can only inject SEA into a Realm if the previous exit
+			 * was due to a data abort of an Unprotected IPA.
+			 */
+			if (!(vcpu->arch.rec.run->entry.flags & RMI_EMULATED_MMIO))
+				return -EINVAL;
+
+			vcpu->arch.rec.run->entry.flags &= ~RMI_EMULATED_MMIO;
+			vcpu->arch.rec.run->entry.flags |= RMI_INJECT_SEA;
+		}
+
+		return 0;
+	}
+
 	if (serror_pending && has_esr) {
 		if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
 			return -EINVAL;
-- 
2.34.1


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

* [RFC PATCH 25/28] arm64: rme: support RSI_HOST_CALL
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Joey Gouly <joey.gouly@arm.com>

Forward RSI_HOST_CALLS to KVM's HVC handler.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/rme-exit.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/arm64/kvm/rme-exit.c b/arch/arm64/kvm/rme-exit.c
index 15a4ff3517db..fcdc87e8f6bc 100644
--- a/arch/arm64/kvm/rme-exit.c
+++ b/arch/arm64/kvm/rme-exit.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/kvm_host.h>
+#include <kvm/arm_hypercalls.h>
 #include <kvm/arm_psci.h>
 
 #include <asm/rmi_smc.h>
@@ -98,6 +99,29 @@ static int rec_exit_ripas_change(struct kvm_vcpu *vcpu)
 	return 1;
 }
 
+static int rec_exit_host_call(struct kvm_vcpu *vcpu)
+{
+	int ret, i;
+	struct rec *rec = &vcpu->arch.rec;
+
+	vcpu->stat.hvc_exit_stat++;
+
+	for (i = 0; i < REC_RUN_GPRS; i++)
+		vcpu_set_reg(vcpu, i, rec->run->exit.gprs[i]);
+
+	ret = kvm_hvc_call_handler(vcpu);
+
+	if (ret < 0) {
+		vcpu_set_reg(vcpu, 0, ~0UL);
+		ret = 1;
+	}
+
+	for (i = 0; i < REC_RUN_GPRS; i++)
+		rec->run->entry.gprs[i] = vcpu_get_reg(vcpu, i);
+
+	return ret;
+}
+
 static void update_arch_timer_irq_lines(struct kvm_vcpu *vcpu)
 {
 	struct rec *rec = &vcpu->arch.rec;
@@ -159,6 +183,8 @@ int handle_rme_exit(struct kvm_vcpu *vcpu, int rec_run_ret)
 		return rec_exit_psci(vcpu);
 	case RMI_EXIT_RIPAS_CHANGE:
 		return rec_exit_ripas_change(vcpu);
+	case RMI_EXIT_HOST_CALL:
+		return rec_exit_host_call(vcpu);
 	}
 
 	kvm_pr_unimpl("Unsupported exit reason: %u\n",
-- 
2.34.1


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

* [RFC PATCH 25/28] arm64: rme: support RSI_HOST_CALL
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Joey Gouly <joey.gouly@arm.com>

Forward RSI_HOST_CALLS to KVM's HVC handler.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/rme-exit.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/arm64/kvm/rme-exit.c b/arch/arm64/kvm/rme-exit.c
index 15a4ff3517db..fcdc87e8f6bc 100644
--- a/arch/arm64/kvm/rme-exit.c
+++ b/arch/arm64/kvm/rme-exit.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/kvm_host.h>
+#include <kvm/arm_hypercalls.h>
 #include <kvm/arm_psci.h>
 
 #include <asm/rmi_smc.h>
@@ -98,6 +99,29 @@ static int rec_exit_ripas_change(struct kvm_vcpu *vcpu)
 	return 1;
 }
 
+static int rec_exit_host_call(struct kvm_vcpu *vcpu)
+{
+	int ret, i;
+	struct rec *rec = &vcpu->arch.rec;
+
+	vcpu->stat.hvc_exit_stat++;
+
+	for (i = 0; i < REC_RUN_GPRS; i++)
+		vcpu_set_reg(vcpu, i, rec->run->exit.gprs[i]);
+
+	ret = kvm_hvc_call_handler(vcpu);
+
+	if (ret < 0) {
+		vcpu_set_reg(vcpu, 0, ~0UL);
+		ret = 1;
+	}
+
+	for (i = 0; i < REC_RUN_GPRS; i++)
+		rec->run->entry.gprs[i] = vcpu_get_reg(vcpu, i);
+
+	return ret;
+}
+
 static void update_arch_timer_irq_lines(struct kvm_vcpu *vcpu)
 {
 	struct rec *rec = &vcpu->arch.rec;
@@ -159,6 +183,8 @@ int handle_rme_exit(struct kvm_vcpu *vcpu, int rec_run_ret)
 		return rec_exit_psci(vcpu);
 	case RMI_EXIT_RIPAS_CHANGE:
 		return rec_exit_ripas_change(vcpu);
+	case RMI_EXIT_HOST_CALL:
+		return rec_exit_host_call(vcpu);
 	}
 
 	kvm_pr_unimpl("Unsupported exit reason: %u\n",
-- 
2.34.1


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

* [RFC PATCH 26/28] arm64: rme: Allow checking SVE on VM instance
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

Given we have different types of VMs supported, check the
support for SVE for the given instance of the VM to accurately
report the status.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h | 2 ++
 arch/arm64/kvm/arm.c             | 5 ++++-
 arch/arm64/kvm/rme.c             | 7 ++++++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 2254e28c855e..68e99e5107bc 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -40,6 +40,8 @@ struct rec {
 int kvm_init_rme(void);
 u32 kvm_realm_ipa_limit(void);
 
+bool kvm_rme_supports_sve(void);
+
 int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap);
 int kvm_init_realm_vm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 645df5968e1e..1d0b8ac7314f 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -326,7 +326,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		r = get_kvm_ipa_limit();
 		break;
 	case KVM_CAP_ARM_SVE:
-		r = system_supports_sve();
+		if (kvm && kvm_is_realm(kvm))
+			r = kvm_rme_supports_sve();
+		else
+			r = system_supports_sve();
 		break;
 	case KVM_CAP_ARM_PTRAUTH_ADDRESS:
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 543e8d10f532..6ae7871aa6ed 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -49,6 +49,11 @@ static bool rme_supports(unsigned long feature)
 	return !!u64_get_bits(rmm_feat_reg0, feature);
 }
 
+bool kvm_rme_supports_sve(void)
+{
+	return rme_supports(RMI_FEATURE_REGISTER_0_SVE_EN);
+}
+
 static int rmi_check_version(void)
 {
 	struct arm_smccc_res res;
@@ -1104,7 +1109,7 @@ static int config_realm_sve(struct realm *realm,
 	int max_sve_vq = u64_get_bits(rmm_feat_reg0,
 				      RMI_FEATURE_REGISTER_0_SVE_VL);
 
-	if (!rme_supports(RMI_FEATURE_REGISTER_0_SVE_EN))
+	if (!kvm_rme_supports_sve())
 		return -EINVAL;
 
 	if (cfg->sve_vq > max_sve_vq)
-- 
2.34.1


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

* [RFC PATCH 26/28] arm64: rme: Allow checking SVE on VM instance
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

From: Suzuki K Poulose <suzuki.poulose@arm.com>

Given we have different types of VMs supported, check the
support for SVE for the given instance of the VM to accurately
report the status.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h | 2 ++
 arch/arm64/kvm/arm.c             | 5 ++++-
 arch/arm64/kvm/rme.c             | 7 ++++++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index 2254e28c855e..68e99e5107bc 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -40,6 +40,8 @@ struct rec {
 int kvm_init_rme(void);
 u32 kvm_realm_ipa_limit(void);
 
+bool kvm_rme_supports_sve(void);
+
 int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap);
 int kvm_init_realm_vm(struct kvm *kvm);
 void kvm_destroy_realm(struct kvm *kvm);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 645df5968e1e..1d0b8ac7314f 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -326,7 +326,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		r = get_kvm_ipa_limit();
 		break;
 	case KVM_CAP_ARM_SVE:
-		r = system_supports_sve();
+		if (kvm && kvm_is_realm(kvm))
+			r = kvm_rme_supports_sve();
+		else
+			r = system_supports_sve();
 		break;
 	case KVM_CAP_ARM_PTRAUTH_ADDRESS:
 	case KVM_CAP_ARM_PTRAUTH_GENERIC:
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 543e8d10f532..6ae7871aa6ed 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -49,6 +49,11 @@ static bool rme_supports(unsigned long feature)
 	return !!u64_get_bits(rmm_feat_reg0, feature);
 }
 
+bool kvm_rme_supports_sve(void)
+{
+	return rme_supports(RMI_FEATURE_REGISTER_0_SVE_EN);
+}
+
 static int rmi_check_version(void)
 {
 	struct arm_smccc_res res;
@@ -1104,7 +1109,7 @@ static int config_realm_sve(struct realm *realm,
 	int max_sve_vq = u64_get_bits(rmm_feat_reg0,
 				      RMI_FEATURE_REGISTER_0_SVE_VL);
 
-	if (!rme_supports(RMI_FEATURE_REGISTER_0_SVE_EN))
+	if (!kvm_rme_supports_sve())
 		return -EINVAL;
 
 	if (cfg->sve_vq > max_sve_vq)
-- 
2.34.1


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

* [RFC PATCH 27/28] arm64: RME: Always use 4k pages for realms
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Always split up huge pages to avoid problems managing huge pages. There
are two issues currently:

1. The uABI for the VMM allows populating memory on 4k boundaries even
   if the underlying allocator (e.g. hugetlbfs) is using a larger page
   size. Using a memfd for private allocations will push this issue onto
   the VMM as it will need to respect the granularity of the allocator.

2. The guest is able to request arbitrary ranges to be remapped as
   shared. Again with a memfd approach it will be up to the VMM to deal
   with the complexity and either overmap (need the huge mapping and add
   an additional 'overlapping' shared mapping) or reject the request as
   invalid due to the use of a huge page allocator.

For now just break everything down to 4k pages in the RMM controlled
stage 2.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/mmu.c | 4 ++++
 arch/arm64/kvm/rme.c | 4 +++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 5417c273861b..b5fc8d8f7049 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1278,6 +1278,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	if (logging_active) {
 		force_pte = true;
 		vma_shift = PAGE_SHIFT;
+	} else if (kvm_is_realm(kvm)) {
+		// Force PTE level mappings for realms
+		force_pte = true;
+		vma_shift = PAGE_SHIFT;
 	} else {
 		vma_shift = get_vma_page_shift(vma, hva);
 	}
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 6ae7871aa6ed..1eb76cbee267 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -730,7 +730,9 @@ static int populate_par_region(struct kvm *kvm,
 			break;
 		}
 
-		if (is_vm_hugetlb_page(vma))
+		// FIXME: To avoid the overmapping issue (see below comment)
+		// force the use of 4k pages
+		if (is_vm_hugetlb_page(vma) && 0)
 			vma_shift = huge_page_shift(hstate_vma(vma));
 		else
 			vma_shift = PAGE_SHIFT;
-- 
2.34.1


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

* [RFC PATCH 27/28] arm64: RME: Always use 4k pages for realms
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

Always split up huge pages to avoid problems managing huge pages. There
are two issues currently:

1. The uABI for the VMM allows populating memory on 4k boundaries even
   if the underlying allocator (e.g. hugetlbfs) is using a larger page
   size. Using a memfd for private allocations will push this issue onto
   the VMM as it will need to respect the granularity of the allocator.

2. The guest is able to request arbitrary ranges to be remapped as
   shared. Again with a memfd approach it will be up to the VMM to deal
   with the complexity and either overmap (need the huge mapping and add
   an additional 'overlapping' shared mapping) or reject the request as
   invalid due to the use of a huge page allocator.

For now just break everything down to 4k pages in the RMM controlled
stage 2.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/kvm/mmu.c | 4 ++++
 arch/arm64/kvm/rme.c | 4 +++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 5417c273861b..b5fc8d8f7049 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1278,6 +1278,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	if (logging_active) {
 		force_pte = true;
 		vma_shift = PAGE_SHIFT;
+	} else if (kvm_is_realm(kvm)) {
+		// Force PTE level mappings for realms
+		force_pte = true;
+		vma_shift = PAGE_SHIFT;
 	} else {
 		vma_shift = get_vma_page_shift(vma, hva);
 	}
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 6ae7871aa6ed..1eb76cbee267 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -730,7 +730,9 @@ static int populate_par_region(struct kvm *kvm,
 			break;
 		}
 
-		if (is_vm_hugetlb_page(vma))
+		// FIXME: To avoid the overmapping issue (see below comment)
+		// force the use of 4k pages
+		if (is_vm_hugetlb_page(vma) && 0)
 			vma_shift = huge_page_shift(hstate_vma(vma));
 		else
 			vma_shift = PAGE_SHIFT;
-- 
2.34.1


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

* [RFC PATCH 28/28] HACK: Accept prototype RMI versions
  2023-01-27 11:29   ` Steven Price
@ 2023-01-27 11:29     ` Steven Price
  -1 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The upstream RMM currently advertises the major version of an internal
prototype (v56.0) rather than the expected version from the RMM
architecture specification (v1.0).

Add a config option to enable support for the prototype RMI v56.0.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rmi_smc.h | 7 +++++++
 arch/arm64/kvm/Kconfig           | 8 ++++++++
 arch/arm64/kvm/rme.c             | 8 ++++++++
 3 files changed, 23 insertions(+)

diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
index 16ff65090f3a..d6bbd7d92b8f 100644
--- a/arch/arm64/include/asm/rmi_smc.h
+++ b/arch/arm64/include/asm/rmi_smc.h
@@ -6,6 +6,13 @@
 #ifndef __ASM_RME_SMC_H
 #define __ASM_RME_SMC_H
 
+#ifdef CONFIG_RME_USE_PROTOTYPE_HACKS
+
+// Allow the prototype RMI version
+#define PROTOTYPE_RMI_ABI_MAJOR_VERSION  56
+
+#endif /* CONFIG_RME_USE_PROTOTYPE_HACKS */
+
 #include <linux/arm-smccc.h>
 
 #define SMC_RxI_CALL(func)				\
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 05da3c8f7e88..13858a5047fd 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -58,6 +58,14 @@ config NVHE_EL2_DEBUG
 
 	  If unsure, say N.
 
+config RME_USE_PROTOTYPE_HACKS
+	bool "Allow RMM prototype version numbers"
+	default y
+	help
+	  For compatibility with the the current RMM code allow versions
+	  numbers from a prototype implementation as well as the expected
+	  version number from the RMM specification.
+
 config PROTECTED_NVHE_STACKTRACE
 	bool "Protected KVM hypervisor stacktraces"
 	depends on NVHE_EL2_DEBUG
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 1eb76cbee267..894060635226 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -67,6 +67,14 @@ static int rmi_check_version(void)
 	version_major = RMI_ABI_VERSION_GET_MAJOR(res.a0);
 	version_minor = RMI_ABI_VERSION_GET_MINOR(res.a0);
 
+#ifdef PROTOTYPE_RMI_ABI_MAJOR_VERSION
+	// Support the prototype
+	if (version_major == PROTOTYPE_RMI_ABI_MAJOR_VERSION) {
+		kvm_err("Using prototype RMM support (version %d.%d)\n",
+			version_major, version_minor);
+		return 0;
+	}
+#endif
 	if (version_major != RMI_ABI_MAJOR_VERSION) {
 		kvm_err("Unsupported RMI ABI (version %d.%d) we support %d\n",
 			version_major, version_minor,
-- 
2.34.1


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

* [RFC PATCH 28/28] HACK: Accept prototype RMI versions
@ 2023-01-27 11:29     ` Steven Price
  0 siblings, 0 replies; 386+ messages in thread
From: Steven Price @ 2023-01-27 11:29 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
	James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
	linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
	Christoffer Dall, Fuad Tabba, linux-coco

The upstream RMM currently advertises the major version of an internal
prototype (v56.0) rather than the expected version from the RMM
architecture specification (v1.0).

Add a config option to enable support for the prototype RMI v56.0.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/rmi_smc.h | 7 +++++++
 arch/arm64/kvm/Kconfig           | 8 ++++++++
 arch/arm64/kvm/rme.c             | 8 ++++++++
 3 files changed, 23 insertions(+)

diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
index 16ff65090f3a..d6bbd7d92b8f 100644
--- a/arch/arm64/include/asm/rmi_smc.h
+++ b/arch/arm64/include/asm/rmi_smc.h
@@ -6,6 +6,13 @@
 #ifndef __ASM_RME_SMC_H
 #define __ASM_RME_SMC_H
 
+#ifdef CONFIG_RME_USE_PROTOTYPE_HACKS
+
+// Allow the prototype RMI version
+#define PROTOTYPE_RMI_ABI_MAJOR_VERSION  56
+
+#endif /* CONFIG_RME_USE_PROTOTYPE_HACKS */
+
 #include <linux/arm-smccc.h>
 
 #define SMC_RxI_CALL(func)				\
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 05da3c8f7e88..13858a5047fd 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -58,6 +58,14 @@ config NVHE_EL2_DEBUG
 
 	  If unsure, say N.
 
+config RME_USE_PROTOTYPE_HACKS
+	bool "Allow RMM prototype version numbers"
+	default y
+	help
+	  For compatibility with the the current RMM code allow versions
+	  numbers from a prototype implementation as well as the expected
+	  version number from the RMM specification.
+
 config PROTECTED_NVHE_STACKTRACE
 	bool "Protected KVM hypervisor stacktraces"
 	depends on NVHE_EL2_DEBUG
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 1eb76cbee267..894060635226 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -67,6 +67,14 @@ static int rmi_check_version(void)
 	version_major = RMI_ABI_VERSION_GET_MAJOR(res.a0);
 	version_minor = RMI_ABI_VERSION_GET_MINOR(res.a0);
 
+#ifdef PROTOTYPE_RMI_ABI_MAJOR_VERSION
+	// Support the prototype
+	if (version_major == PROTOTYPE_RMI_ABI_MAJOR_VERSION) {
+		kvm_err("Using prototype RMM support (version %d.%d)\n",
+			version_major, version_minor);
+		return 0;
+	}
+#endif
 	if (version_major != RMI_ABI_MAJOR_VERSION) {
 		kvm_err("Unsupported RMI ABI (version %d.%d) we support %d\n",
 			version_major, version_minor,
-- 
2.34.1


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

* [RFC kvmtool 00/31] arm64: Support for Arm Confidential Compute Architecture
  2023-01-27 11:22 ` Suzuki K Poulose
@ 2023-01-27 11:39   ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

This series is an initial version of the support for running VMs under the
Arm Confidential Compute Architecture. The purpose of the series is to gather
feedback on the proposed UABI changes for running Confidential VMs with KVM.
More information on the Arm CCA and instructions for how to get, build and run
the entire software stack is available here [0].

A new option, `--realm` is added to the the `run` command to mark the VM as a
confidential compute VM. This version doesn't use the Guest private memory [1]
support yet, instead uses normal anonymous/hugetlbfs backed memory. Our aim is
to switch to the guest private memory for the Realm.

The host including the kernel and kvmtool, must not access any memory allocated
to the protected IPA of the Realm.

The series adds the support for managing the lifecycle of the Realm, which includes:
   * Configuration
   * Creation of Realm (RD)
   * Load initial memory images
   * Creation of Realm Execution Contexts (RECs aka VCPUs)a
   * Activation of the Realm.

Patches are split as follows :

Patches 1 and 2 are fixes to existing code.
Patch 3 adds a new option --nocompat to disable compat warnings
Patches 4 - 6 are some preparations for Realm specific changes.

The remaining patches adds Realm support and using the --realm option is
enabled in patch 30.

The v1.0 of the Realm Management Monitor (RMM) specification doesn't support
paging protected memory of a Realm. Thus all of the memory backing the RAM
is locked by the VMM.

Since the IPA space of a Realm is split into Protected and Unprotected, with
one alias of the other, the VMM doubles the IPA Size for a Realm VM.

The KVM support for Arm CCA is advertised with a new cap KVM_CAP_ARM_RME.
A new "VM type" field is defined in the vm_type for CREATE_VM ioctl to indicate
that a VM is "Realm". Once the VM is created, the life cycle of the Realm is
managed via KVM_ENABLE_CAP of KVM_CAP_ARM_RME.

Command line options are also added to configure the Realm parameters.
These include :
 - Hash algorithm for measurements
 - Realm personalisation value
 - SVE vector Length (Optional feature in v1.0 RMM spec. Not yet supported
   by the TF-RMM. coming soon).

Support for PMU and self-hosted debug (number of watchpoint/breakpoit registers)
are not supported yet in the KVM/RMM implementation. This will be added soon.

The UABI doesn't support discovering the "supported" configuration values. In
real world, the Realm configuration 'affects' the initial measurement of the
Realms and which may be verified by a remote entity. Thus, the VMM is not at
liberty to make choices for configurations based on the "host" capabilities.
Instead, VMM should launch a Realm with the user requested parameters. If this
cannot be satisfied, there is no point in running the Realm. We are happy to
change this if there is interest.

Special actions are required to load the initial memory images (e.g, kernel,
firmware, DTB, initrd) in to the Realm memory.

For VCPUs, we add a new feature KVM_ARM_VCPU_REC, which will be used to control
the creation of the REC object (via KVM_ARM_VCPU_FINALIZE). This must be done
after the initial register state of the VCPUs are set.
RMM imposes an order in which the RECs are created. i.e., they must be created
in the ascending order of the MPIDR. This is for now a responsibility of the
VMM.

Once the Realm images are loaded, VCPUs created, Realm is activated before
the first vCPU is run.

virtio for the Realms enforces VIRTIO_F_ACCESS_PLATFORM flag.

Also, added support for injecting SEA into the VM for unhandled MMIO.

A tree with the patches are also available here :

	https://gitlab.arm.com/linux-arm/kvmtool-cca cca/rfc-v1

Running the Realm
------------------

A realm VM can be launched using :

 $ lkvm run						\
	 --realm					\
	 --disable-sve					\
	 [ --measurement-algo="sha256","sha512" ]	\
	 [ --realm-pv="<realm-pv>" ]			\
	 <normal-VM options>

[0] https://lkml.kernel.org/r/20230127112248.136810-1-suzuki.poulose@arm.com
[1] https://lkml.kernel.org/r/20221202061347.1070246-1-chao.p.peng@linux.intel.com

To: kvmarm@lists.linux.dev
To: kvm@vger.kernel.org
Cc: Alexandru Elisei <alexandru.elisei@arm.com>
Cc: Andrew Jones <andrew.jones@linux.dev>
Cc: Christoffer Dall <christoffer.dall@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Cc: Jean-Philippe Brucker <jean-philippe@linaro.org>
Cc: Joey Gouly <Joey.Gouly@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Quentin Perret <qperret@google.com>
Cc: Steven Price <steven.price@arm.com>
Cc: Thomas Huth <thuth@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Zenghui Yu <yuzenghui@huawei.com>
Cc: linux-coco@lists.linux.dev
Cc: kvmarm@lists.cs.columbia.edu
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org

Alexandru Elisei (11):
  Add --nocompat option to disable compat warnings
  arm64: Add --realm command line option
  arm64: Lock realm RAM in memory
  arm64: Create Realm Descriptor
  arm: Add kernel size to VM context
  arm64: Populate initial realm contents
  arm64: Finalize realm VCPU after reset
  init: Add last_{init, exit} list macros
  arm64: Activate realm before the first VCPU is run
  arm64: Don't try to debug a realm
  arm64: Allow the user to create a realm

Christoffer Dall (4):
  arm64: Create a realm virtual machine
  arm64: Add --measurement-algo command line option for a realm
  arm64: Don't try to set PSTATE for VCPUs belonging to a realm
  arm64: Specify SMC as the PSCI conduits for realms

Joey Gouly (2):
  mmio: add arch hook for an unhandled MMIO access
  arm64: realm: inject an abort on an unhandled MMIO access

Suzuki K Poulose (14):
  arm64: Disable MTE when CFI flash is emulated
  script: update_headers: Ignore missing architectures
  hw: cfi flash: Handle errors in memory transitions
  arm64: Check pvtime support against the KVM instance
  arm64: Check SVE capability on the VM instance
  arm64: Add option to disable SVE
  linux: Update kernel headers for RME support
  arm64: Add configuration step for Realms
  arm64: Add support for Realm Personalisation Value
  arm64: Add support for specifying the SVE vector length for Realm
  arm64: realm: Double the IPA space
  virtio: Add a wrapper for get_host_features
  virtio: Add arch specific hook for virtio host flags
  arm64: realm: Enforce virtio F_ACCESS_PLATFORM flag

 Makefile                                  |   1 +
 arm/aarch32/include/asm/realm.h           |  13 ++
 arm/aarch32/kvm.c                         |   5 +
 arm/aarch64/include/asm/kvm.h             |  64 ++++++
 arm/aarch64/include/asm/realm.h           |  13 ++
 arm/aarch64/include/kvm/kvm-config-arch.h |  16 +-
 arm/aarch64/kvm-cpu.c                     |  41 +++-
 arm/aarch64/kvm.c                         |  95 ++++++++-
 arm/aarch64/pvtime.c                      |   4 +-
 arm/aarch64/realm.c                       | 229 ++++++++++++++++++++++
 arm/fdt.c                                 |  15 +-
 arm/include/arm-common/kvm-arch.h         |   4 +
 arm/include/arm-common/kvm-config-arch.h  |   5 +
 arm/kvm-cpu.c                             |  13 ++
 arm/kvm.c                                 |  75 ++++++-
 builtin-run.c                             |   5 +-
 guest_compat.c                            |   1 +
 hw/cfi_flash.c                            |   4 +
 include/kvm/kvm-config.h                  |   1 +
 include/kvm/kvm-cpu.h                     |   2 +
 include/kvm/kvm.h                         |   2 +
 include/kvm/util-init.h                   |   6 +-
 include/kvm/virtio.h                      |   2 +
 include/linux/kernel.h                    |   1 +
 include/linux/kvm.h                       |  22 ++-
 include/linux/virtio_blk.h                |  19 --
 include/linux/virtio_net.h                |  14 +-
 include/linux/virtio_ring.h               |  16 +-
 mips/kvm-cpu.c                            |   4 +
 mips/kvm.c                                |   5 +
 mmio.c                                    |   3 +
 powerpc/kvm-cpu.c                         |   4 +
 powerpc/kvm.c                             |   5 +
 riscv/kvm-cpu.c                           |   4 +
 riscv/kvm.c                               |   5 +
 util/update_headers.sh                    |   1 +
 virtio/core.c                             |   8 +
 virtio/mmio-legacy.c                      |   2 +-
 virtio/mmio-modern.c                      |   2 +-
 virtio/pci-legacy.c                       |   2 +-
 virtio/pci-modern.c                       |   2 +-
 x86/kvm-cpu.c                             |   4 +
 x86/kvm.c                                 |   5 +
 43 files changed, 667 insertions(+), 77 deletions(-)
 create mode 100644 arm/aarch32/include/asm/realm.h
 create mode 100644 arm/aarch64/include/asm/realm.h
 create mode 100644 arm/aarch64/realm.c

-- 
2.34.1


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

* [RFC kvmtool 00/31] arm64: Support for Arm Confidential Compute Architecture
@ 2023-01-27 11:39   ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

This series is an initial version of the support for running VMs under the
Arm Confidential Compute Architecture. The purpose of the series is to gather
feedback on the proposed UABI changes for running Confidential VMs with KVM.
More information on the Arm CCA and instructions for how to get, build and run
the entire software stack is available here [0].

A new option, `--realm` is added to the the `run` command to mark the VM as a
confidential compute VM. This version doesn't use the Guest private memory [1]
support yet, instead uses normal anonymous/hugetlbfs backed memory. Our aim is
to switch to the guest private memory for the Realm.

The host including the kernel and kvmtool, must not access any memory allocated
to the protected IPA of the Realm.

The series adds the support for managing the lifecycle of the Realm, which includes:
   * Configuration
   * Creation of Realm (RD)
   * Load initial memory images
   * Creation of Realm Execution Contexts (RECs aka VCPUs)a
   * Activation of the Realm.

Patches are split as follows :

Patches 1 and 2 are fixes to existing code.
Patch 3 adds a new option --nocompat to disable compat warnings
Patches 4 - 6 are some preparations for Realm specific changes.

The remaining patches adds Realm support and using the --realm option is
enabled in patch 30.

The v1.0 of the Realm Management Monitor (RMM) specification doesn't support
paging protected memory of a Realm. Thus all of the memory backing the RAM
is locked by the VMM.

Since the IPA space of a Realm is split into Protected and Unprotected, with
one alias of the other, the VMM doubles the IPA Size for a Realm VM.

The KVM support for Arm CCA is advertised with a new cap KVM_CAP_ARM_RME.
A new "VM type" field is defined in the vm_type for CREATE_VM ioctl to indicate
that a VM is "Realm". Once the VM is created, the life cycle of the Realm is
managed via KVM_ENABLE_CAP of KVM_CAP_ARM_RME.

Command line options are also added to configure the Realm parameters.
These include :
 - Hash algorithm for measurements
 - Realm personalisation value
 - SVE vector Length (Optional feature in v1.0 RMM spec. Not yet supported
   by the TF-RMM. coming soon).

Support for PMU and self-hosted debug (number of watchpoint/breakpoit registers)
are not supported yet in the KVM/RMM implementation. This will be added soon.

The UABI doesn't support discovering the "supported" configuration values. In
real world, the Realm configuration 'affects' the initial measurement of the
Realms and which may be verified by a remote entity. Thus, the VMM is not at
liberty to make choices for configurations based on the "host" capabilities.
Instead, VMM should launch a Realm with the user requested parameters. If this
cannot be satisfied, there is no point in running the Realm. We are happy to
change this if there is interest.

Special actions are required to load the initial memory images (e.g, kernel,
firmware, DTB, initrd) in to the Realm memory.

For VCPUs, we add a new feature KVM_ARM_VCPU_REC, which will be used to control
the creation of the REC object (via KVM_ARM_VCPU_FINALIZE). This must be done
after the initial register state of the VCPUs are set.
RMM imposes an order in which the RECs are created. i.e., they must be created
in the ascending order of the MPIDR. This is for now a responsibility of the
VMM.

Once the Realm images are loaded, VCPUs created, Realm is activated before
the first vCPU is run.

virtio for the Realms enforces VIRTIO_F_ACCESS_PLATFORM flag.

Also, added support for injecting SEA into the VM for unhandled MMIO.

A tree with the patches are also available here :

	https://gitlab.arm.com/linux-arm/kvmtool-cca cca/rfc-v1

Running the Realm
------------------

A realm VM can be launched using :

 $ lkvm run						\
	 --realm					\
	 --disable-sve					\
	 [ --measurement-algo="sha256","sha512" ]	\
	 [ --realm-pv="<realm-pv>" ]			\
	 <normal-VM options>

[0] https://lkml.kernel.org/r/20230127112248.136810-1-suzuki.poulose@arm.com
[1] https://lkml.kernel.org/r/20221202061347.1070246-1-chao.p.peng@linux.intel.com

To: kvmarm@lists.linux.dev
To: kvm@vger.kernel.org
Cc: Alexandru Elisei <alexandru.elisei@arm.com>
Cc: Andrew Jones <andrew.jones@linux.dev>
Cc: Christoffer Dall <christoffer.dall@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Cc: Jean-Philippe Brucker <jean-philippe@linaro.org>
Cc: Joey Gouly <Joey.Gouly@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Quentin Perret <qperret@google.com>
Cc: Steven Price <steven.price@arm.com>
Cc: Thomas Huth <thuth@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Zenghui Yu <yuzenghui@huawei.com>
Cc: linux-coco@lists.linux.dev
Cc: kvmarm@lists.cs.columbia.edu
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org

Alexandru Elisei (11):
  Add --nocompat option to disable compat warnings
  arm64: Add --realm command line option
  arm64: Lock realm RAM in memory
  arm64: Create Realm Descriptor
  arm: Add kernel size to VM context
  arm64: Populate initial realm contents
  arm64: Finalize realm VCPU after reset
  init: Add last_{init, exit} list macros
  arm64: Activate realm before the first VCPU is run
  arm64: Don't try to debug a realm
  arm64: Allow the user to create a realm

Christoffer Dall (4):
  arm64: Create a realm virtual machine
  arm64: Add --measurement-algo command line option for a realm
  arm64: Don't try to set PSTATE for VCPUs belonging to a realm
  arm64: Specify SMC as the PSCI conduits for realms

Joey Gouly (2):
  mmio: add arch hook for an unhandled MMIO access
  arm64: realm: inject an abort on an unhandled MMIO access

Suzuki K Poulose (14):
  arm64: Disable MTE when CFI flash is emulated
  script: update_headers: Ignore missing architectures
  hw: cfi flash: Handle errors in memory transitions
  arm64: Check pvtime support against the KVM instance
  arm64: Check SVE capability on the VM instance
  arm64: Add option to disable SVE
  linux: Update kernel headers for RME support
  arm64: Add configuration step for Realms
  arm64: Add support for Realm Personalisation Value
  arm64: Add support for specifying the SVE vector length for Realm
  arm64: realm: Double the IPA space
  virtio: Add a wrapper for get_host_features
  virtio: Add arch specific hook for virtio host flags
  arm64: realm: Enforce virtio F_ACCESS_PLATFORM flag

 Makefile                                  |   1 +
 arm/aarch32/include/asm/realm.h           |  13 ++
 arm/aarch32/kvm.c                         |   5 +
 arm/aarch64/include/asm/kvm.h             |  64 ++++++
 arm/aarch64/include/asm/realm.h           |  13 ++
 arm/aarch64/include/kvm/kvm-config-arch.h |  16 +-
 arm/aarch64/kvm-cpu.c                     |  41 +++-
 arm/aarch64/kvm.c                         |  95 ++++++++-
 arm/aarch64/pvtime.c                      |   4 +-
 arm/aarch64/realm.c                       | 229 ++++++++++++++++++++++
 arm/fdt.c                                 |  15 +-
 arm/include/arm-common/kvm-arch.h         |   4 +
 arm/include/arm-common/kvm-config-arch.h  |   5 +
 arm/kvm-cpu.c                             |  13 ++
 arm/kvm.c                                 |  75 ++++++-
 builtin-run.c                             |   5 +-
 guest_compat.c                            |   1 +
 hw/cfi_flash.c                            |   4 +
 include/kvm/kvm-config.h                  |   1 +
 include/kvm/kvm-cpu.h                     |   2 +
 include/kvm/kvm.h                         |   2 +
 include/kvm/util-init.h                   |   6 +-
 include/kvm/virtio.h                      |   2 +
 include/linux/kernel.h                    |   1 +
 include/linux/kvm.h                       |  22 ++-
 include/linux/virtio_blk.h                |  19 --
 include/linux/virtio_net.h                |  14 +-
 include/linux/virtio_ring.h               |  16 +-
 mips/kvm-cpu.c                            |   4 +
 mips/kvm.c                                |   5 +
 mmio.c                                    |   3 +
 powerpc/kvm-cpu.c                         |   4 +
 powerpc/kvm.c                             |   5 +
 riscv/kvm-cpu.c                           |   4 +
 riscv/kvm.c                               |   5 +
 util/update_headers.sh                    |   1 +
 virtio/core.c                             |   8 +
 virtio/mmio-legacy.c                      |   2 +-
 virtio/mmio-modern.c                      |   2 +-
 virtio/pci-legacy.c                       |   2 +-
 virtio/pci-modern.c                       |   2 +-
 x86/kvm-cpu.c                             |   4 +
 x86/kvm.c                                 |   5 +
 43 files changed, 667 insertions(+), 77 deletions(-)
 create mode 100644 arm/aarch32/include/asm/realm.h
 create mode 100644 arm/aarch64/include/asm/realm.h
 create mode 100644 arm/aarch64/realm.c

-- 
2.34.1


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

* [RFC kvmtool 01/31] arm64: Disable MTE when CFI flash is emulated
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

CFI Flash file image cannot be mapped into the memory of the
guest if MTE is enabled. Thus disable MTE if flash emulation
is requested.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 54200c9e..5a53badb 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -145,6 +145,12 @@ void kvm__arch_enable_mte(struct kvm *kvm)
 		return;
 	}
 
+	if (kvm->cfg.flash_filename) {
+		kvm->cfg.arch.mte_disabled = true;
+		pr_info("MTE is incompatible with CFI flash support, disabling");
+		return;
+	}
+
 	if (kvm->cfg.arch.mte_disabled) {
 		pr_debug("MTE disabled by user");
 		return;
-- 
2.34.1


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

* [RFC kvmtool 01/31] arm64: Disable MTE when CFI flash is emulated
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

CFI Flash file image cannot be mapped into the memory of the
guest if MTE is enabled. Thus disable MTE if flash emulation
is requested.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 54200c9e..5a53badb 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -145,6 +145,12 @@ void kvm__arch_enable_mte(struct kvm *kvm)
 		return;
 	}
 
+	if (kvm->cfg.flash_filename) {
+		kvm->cfg.arch.mte_disabled = true;
+		pr_info("MTE is incompatible with CFI flash support, disabling");
+		return;
+	}
+
 	if (kvm->cfg.arch.mte_disabled) {
 		pr_debug("MTE disabled by user");
 		return;
-- 
2.34.1


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

* [RFC kvmtool 02/31] script: update_headers: Ignore missing architectures
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Ignore missing architectures for header updates, for use with
older kernels.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 util/update_headers.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/util/update_headers.sh b/util/update_headers.sh
index 789e2a42..bdfb798c 100755
--- a/util/update_headers.sh
+++ b/util/update_headers.sh
@@ -48,6 +48,7 @@ copy_optional_arch () {
 
 for arch in arm64 mips powerpc riscv x86
 do
+	[ -f $LINUX_ROOT/arch/${arch} ] || continue;
 	case "$arch" in
 		arm64)	KVMTOOL_PATH=arm/aarch64
 			copy_optional_arch asm/sve_context.h ;;
-- 
2.34.1


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

* [RFC kvmtool 02/31] script: update_headers: Ignore missing architectures
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Ignore missing architectures for header updates, for use with
older kernels.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 util/update_headers.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/util/update_headers.sh b/util/update_headers.sh
index 789e2a42..bdfb798c 100755
--- a/util/update_headers.sh
+++ b/util/update_headers.sh
@@ -48,6 +48,7 @@ copy_optional_arch () {
 
 for arch in arm64 mips powerpc riscv x86
 do
+	[ -f $LINUX_ROOT/arch/${arch} ] || continue;
 	case "$arch" in
 		arm64)	KVMTOOL_PATH=arm/aarch64
 			copy_optional_arch asm/sve_context.h ;;
-- 
2.34.1


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

* [RFC kvmtool 03/31] hw: cfi flash: Handle errors in memory transitions
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Handle failures in creating the memory maps and back in
transitioning the CFI flash. e.g., with MTE enabled, CFI
flash emulation breaks with the map operation, silently.
And we later hit unhandled aborts in the guest.

To avoid such issues, let us make sure we catch the error
and handle it right at source.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 hw/cfi_flash.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/cfi_flash.c b/hw/cfi_flash.c
index 7faecdfb..bce546bc 100644
--- a/hw/cfi_flash.c
+++ b/hw/cfi_flash.c
@@ -455,6 +455,8 @@ static int map_flash_memory(struct kvm *kvm, struct cfi_flash_device *sfdev)
 				KVM_MEM_TYPE_RAM | KVM_MEM_TYPE_READONLY);
 	if (!ret)
 		sfdev->is_mapped = true;
+	else
+		die("CFI Flash: ERROR: Unable to map memory: %d\n", ret);
 
 	return ret;
 }
@@ -472,6 +474,8 @@ static int unmap_flash_memory(struct kvm *kvm, struct cfi_flash_device *sfdev)
 
 	if (!ret)
 		sfdev->is_mapped = false;
+	else
+		die("CFI Flash: Failed to unmap Flash %d", ret);
 
 	return ret;
 }
-- 
2.34.1


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

* [RFC kvmtool 03/31] hw: cfi flash: Handle errors in memory transitions
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Handle failures in creating the memory maps and back in
transitioning the CFI flash. e.g., with MTE enabled, CFI
flash emulation breaks with the map operation, silently.
And we later hit unhandled aborts in the guest.

To avoid such issues, let us make sure we catch the error
and handle it right at source.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 hw/cfi_flash.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/cfi_flash.c b/hw/cfi_flash.c
index 7faecdfb..bce546bc 100644
--- a/hw/cfi_flash.c
+++ b/hw/cfi_flash.c
@@ -455,6 +455,8 @@ static int map_flash_memory(struct kvm *kvm, struct cfi_flash_device *sfdev)
 				KVM_MEM_TYPE_RAM | KVM_MEM_TYPE_READONLY);
 	if (!ret)
 		sfdev->is_mapped = true;
+	else
+		die("CFI Flash: ERROR: Unable to map memory: %d\n", ret);
 
 	return ret;
 }
@@ -472,6 +474,8 @@ static int unmap_flash_memory(struct kvm *kvm, struct cfi_flash_device *sfdev)
 
 	if (!ret)
 		sfdev->is_mapped = false;
+	else
+		die("CFI Flash: Failed to unmap Flash %d", ret);
 
 	return ret;
 }
-- 
2.34.1


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

* [RFC kvmtool 04/31] Add --nocompat option to disable compat warnings
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Commit e66942073035 ("kvm tools: Guest kernel compatability") added the
functionality that enables devices to print a warning message if the device
hasn't been initialized by the time the VM is destroyed. The purpose of
these messages is to let the user know if the kernel hasn't been built with
the correct Kconfig options to take advantage of the said devices (all
using virtio).

Since then, kvmtool has evolved and now supports loading different payloads
(like firmware images), and having those warnings even when it is entirely
intentional for the payload not to touch the devices can be confusing for
the user and makes the output unnecessarily verbose in those cases.

Add the --nocompat option to disable the warnings; the warnings are still
enabled by default.

Reported-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 builtin-run.c            | 5 ++++-
 guest_compat.c           | 1 +
 include/kvm/kvm-config.h | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/builtin-run.c b/builtin-run.c
index bb7e6e8d..f8edfb3f 100644
--- a/builtin-run.c
+++ b/builtin-run.c
@@ -183,6 +183,8 @@ static int mem_parser(const struct option *opt, const char *arg, int unset)
 	OPT_BOOLEAN('\0', "nodefaults", &(cfg)->nodefaults, "Disable"   \
 			" implicit configuration that cannot be"	\
 			" disabled otherwise"),				\
+	OPT_BOOLEAN('\0', "nocompat", &(cfg)->nocompat, "Disable"	\
+			" compat warnings"),				\
 	OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name",		\
 		     "Enable virtio 9p to share files between host and"	\
 		     " guest", virtio_9p_rootdir_parser, kvm),		\
@@ -797,7 +799,8 @@ static int kvm_cmd_run_work(struct kvm *kvm)
 
 static void kvm_cmd_run_exit(struct kvm *kvm, int guest_ret)
 {
-	compat__print_all_messages();
+	if (!kvm->cfg.nocompat)
+		compat__print_all_messages();
 
 	init_list__exit(kvm);
 
diff --git a/guest_compat.c b/guest_compat.c
index fd4704b2..a413c12c 100644
--- a/guest_compat.c
+++ b/guest_compat.c
@@ -88,6 +88,7 @@ int compat__print_all_messages(void)
 
 		printf("\n  # KVM compatibility warning.\n\t%s\n\t%s\n",
 			msg->title, msg->desc);
+		printf("\tTo stop seeing this warning, use the --nocompat option.\n");
 
 		list_del(&msg->list);
 		compat__free(msg);
diff --git a/include/kvm/kvm-config.h b/include/kvm/kvm-config.h
index 368e6c7d..88df7cc2 100644
--- a/include/kvm/kvm-config.h
+++ b/include/kvm/kvm-config.h
@@ -30,6 +30,7 @@ struct kvm_config {
 	u64 vsock_cid;
 	bool virtio_rng;
 	bool nodefaults;
+	bool nocompat;
 	int active_console;
 	int debug_iodelay;
 	int nrcpus;
-- 
2.34.1


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

* [RFC kvmtool 04/31] Add --nocompat option to disable compat warnings
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Commit e66942073035 ("kvm tools: Guest kernel compatability") added the
functionality that enables devices to print a warning message if the device
hasn't been initialized by the time the VM is destroyed. The purpose of
these messages is to let the user know if the kernel hasn't been built with
the correct Kconfig options to take advantage of the said devices (all
using virtio).

Since then, kvmtool has evolved and now supports loading different payloads
(like firmware images), and having those warnings even when it is entirely
intentional for the payload not to touch the devices can be confusing for
the user and makes the output unnecessarily verbose in those cases.

Add the --nocompat option to disable the warnings; the warnings are still
enabled by default.

Reported-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 builtin-run.c            | 5 ++++-
 guest_compat.c           | 1 +
 include/kvm/kvm-config.h | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/builtin-run.c b/builtin-run.c
index bb7e6e8d..f8edfb3f 100644
--- a/builtin-run.c
+++ b/builtin-run.c
@@ -183,6 +183,8 @@ static int mem_parser(const struct option *opt, const char *arg, int unset)
 	OPT_BOOLEAN('\0', "nodefaults", &(cfg)->nodefaults, "Disable"   \
 			" implicit configuration that cannot be"	\
 			" disabled otherwise"),				\
+	OPT_BOOLEAN('\0', "nocompat", &(cfg)->nocompat, "Disable"	\
+			" compat warnings"),				\
 	OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name",		\
 		     "Enable virtio 9p to share files between host and"	\
 		     " guest", virtio_9p_rootdir_parser, kvm),		\
@@ -797,7 +799,8 @@ static int kvm_cmd_run_work(struct kvm *kvm)
 
 static void kvm_cmd_run_exit(struct kvm *kvm, int guest_ret)
 {
-	compat__print_all_messages();
+	if (!kvm->cfg.nocompat)
+		compat__print_all_messages();
 
 	init_list__exit(kvm);
 
diff --git a/guest_compat.c b/guest_compat.c
index fd4704b2..a413c12c 100644
--- a/guest_compat.c
+++ b/guest_compat.c
@@ -88,6 +88,7 @@ int compat__print_all_messages(void)
 
 		printf("\n  # KVM compatibility warning.\n\t%s\n\t%s\n",
 			msg->title, msg->desc);
+		printf("\tTo stop seeing this warning, use the --nocompat option.\n");
 
 		list_del(&msg->list);
 		compat__free(msg);
diff --git a/include/kvm/kvm-config.h b/include/kvm/kvm-config.h
index 368e6c7d..88df7cc2 100644
--- a/include/kvm/kvm-config.h
+++ b/include/kvm/kvm-config.h
@@ -30,6 +30,7 @@ struct kvm_config {
 	u64 vsock_cid;
 	bool virtio_rng;
 	bool nodefaults;
+	bool nocompat;
 	int active_console;
 	int debug_iodelay;
 	int nrcpus;
-- 
2.34.1


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

* [RFC kvmtool 05/31] arm64: Check pvtime support against the KVM instance
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

KVM_CAP_STEAL_TIME can be checked against a VM instance.
To allow controlling the feature depending on the VM type,
use the cap against the VM.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/pvtime.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arm/aarch64/pvtime.c b/arm/aarch64/pvtime.c
index 2933ac7c..839aa8a7 100644
--- a/arm/aarch64/pvtime.c
+++ b/arm/aarch64/pvtime.c
@@ -58,8 +58,8 @@ int kvm_cpu__setup_pvtime(struct kvm_cpu *vcpu)
 	if (kvm_cfg->no_pvtime)
 		return 0;
 
-	has_stolen_time = kvm__supports_extension(vcpu->kvm,
-						  KVM_CAP_STEAL_TIME);
+	has_stolen_time = kvm__supports_vm_extension(vcpu->kvm,
+						     KVM_CAP_STEAL_TIME);
 	if (!has_stolen_time) {
 		kvm_cfg->no_pvtime = true;
 		return 0;
-- 
2.34.1


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

* [RFC kvmtool 05/31] arm64: Check pvtime support against the KVM instance
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

KVM_CAP_STEAL_TIME can be checked against a VM instance.
To allow controlling the feature depending on the VM type,
use the cap against the VM.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/pvtime.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arm/aarch64/pvtime.c b/arm/aarch64/pvtime.c
index 2933ac7c..839aa8a7 100644
--- a/arm/aarch64/pvtime.c
+++ b/arm/aarch64/pvtime.c
@@ -58,8 +58,8 @@ int kvm_cpu__setup_pvtime(struct kvm_cpu *vcpu)
 	if (kvm_cfg->no_pvtime)
 		return 0;
 
-	has_stolen_time = kvm__supports_extension(vcpu->kvm,
-						  KVM_CAP_STEAL_TIME);
+	has_stolen_time = kvm__supports_vm_extension(vcpu->kvm,
+						     KVM_CAP_STEAL_TIME);
 	if (!has_stolen_time) {
 		kvm_cfg->no_pvtime = true;
 		return 0;
-- 
2.34.1


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

* [RFC kvmtool 06/31] arm64: Check SVE capability on the VM instance
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Similar to PVtime, check the SVE capability on the VM instance
to account for the different VM types and the corresponding support.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index c8be10b3..da809806 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -150,13 +150,15 @@ void kvm_cpu__select_features(struct kvm *kvm, struct kvm_vcpu_init *init)
 	}
 
 	/* Enable SVE if available */
-	if (kvm__supports_extension(kvm, KVM_CAP_ARM_SVE))
+	if (kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE))
 		init->features[0] |= 1UL << KVM_ARM_VCPU_SVE;
 }
 
 int kvm_cpu__configure_features(struct kvm_cpu *vcpu)
 {
-	if (kvm__supports_extension(vcpu->kvm, KVM_CAP_ARM_SVE)) {
+	struct kvm *kvm = vcpu->kvm;
+
+	if (kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE)) {
 		int feature = KVM_ARM_VCPU_SVE;
 
 		if (ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_FINALIZE, &feature)) {
-- 
2.34.1


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

* [RFC kvmtool 06/31] arm64: Check SVE capability on the VM instance
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Similar to PVtime, check the SVE capability on the VM instance
to account for the different VM types and the corresponding support.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index c8be10b3..da809806 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -150,13 +150,15 @@ void kvm_cpu__select_features(struct kvm *kvm, struct kvm_vcpu_init *init)
 	}
 
 	/* Enable SVE if available */
-	if (kvm__supports_extension(kvm, KVM_CAP_ARM_SVE))
+	if (kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE))
 		init->features[0] |= 1UL << KVM_ARM_VCPU_SVE;
 }
 
 int kvm_cpu__configure_features(struct kvm_cpu *vcpu)
 {
-	if (kvm__supports_extension(vcpu->kvm, KVM_CAP_ARM_SVE)) {
+	struct kvm *kvm = vcpu->kvm;
+
+	if (kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE)) {
 		int feature = KVM_ARM_VCPU_SVE;
 
 		if (ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_FINALIZE, &feature)) {
-- 
2.34.1


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

* [RFC kvmtool 07/31] arm64: Add option to disable SVE
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

kvmtool enables SVE whenever it is supported by the KVM.
However, Realm VMs may want controlled features, which gets
measured during the creation. Thus, provide an option to disable
the SVE, to preserve the current behavior of SVE on by default.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h | 4 +++-
 arm/aarch64/kvm-cpu.c                     | 8 +++++---
 arm/include/arm-common/kvm-config-arch.h  | 1 +
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index eae8080d..b055fef4 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -19,7 +19,9 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 			"Specify random seed for Kernel Address Space "	\
 			"Layout Randomization (KASLR)"),		\
 	OPT_BOOLEAN('\0', "no-pvtime", &(cfg)->no_pvtime, "Disable"	\
-			" stolen time"),
+			" stolen time"),				\
+	OPT_BOOLEAN('\0', "disable-sve", &(cfg)->disable_sve,		\
+			"Disable SVE"),
 #include "arm-common/kvm-config-arch.h"
 
 #endif /* KVM__KVM_CONFIG_ARCH_H */
diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index da809806..e7649239 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -149,8 +149,9 @@ void kvm_cpu__select_features(struct kvm *kvm, struct kvm_vcpu_init *init)
 		init->features[0] |= 1UL << KVM_ARM_VCPU_PTRAUTH_GENERIC;
 	}
 
-	/* Enable SVE if available */
-	if (kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE))
+	/* If SVE is not disabled explicitly, enable if available */
+	if (!kvm->cfg.arch.disable_sve &&
+	    kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE))
 		init->features[0] |= 1UL << KVM_ARM_VCPU_SVE;
 }
 
@@ -158,7 +159,8 @@ int kvm_cpu__configure_features(struct kvm_cpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
 
-	if (kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE)) {
+	if (!kvm->cfg.arch.disable_sve &&
+	    kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE)) {
 		int feature = KVM_ARM_VCPU_SVE;
 
 		if (ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_FINALIZE, &feature)) {
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index 9949bfe4..6599305b 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -15,6 +15,7 @@ struct kvm_config_arch {
 	enum irqchip_type irqchip;
 	u64		fw_addr;
 	bool no_pvtime;
+	bool		disable_sve;
 };
 
 int irqchip_parser(const struct option *opt, const char *arg, int unset);
-- 
2.34.1


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

* [RFC kvmtool 07/31] arm64: Add option to disable SVE
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

kvmtool enables SVE whenever it is supported by the KVM.
However, Realm VMs may want controlled features, which gets
measured during the creation. Thus, provide an option to disable
the SVE, to preserve the current behavior of SVE on by default.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h | 4 +++-
 arm/aarch64/kvm-cpu.c                     | 8 +++++---
 arm/include/arm-common/kvm-config-arch.h  | 1 +
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index eae8080d..b055fef4 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -19,7 +19,9 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 			"Specify random seed for Kernel Address Space "	\
 			"Layout Randomization (KASLR)"),		\
 	OPT_BOOLEAN('\0', "no-pvtime", &(cfg)->no_pvtime, "Disable"	\
-			" stolen time"),
+			" stolen time"),				\
+	OPT_BOOLEAN('\0', "disable-sve", &(cfg)->disable_sve,		\
+			"Disable SVE"),
 #include "arm-common/kvm-config-arch.h"
 
 #endif /* KVM__KVM_CONFIG_ARCH_H */
diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index da809806..e7649239 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -149,8 +149,9 @@ void kvm_cpu__select_features(struct kvm *kvm, struct kvm_vcpu_init *init)
 		init->features[0] |= 1UL << KVM_ARM_VCPU_PTRAUTH_GENERIC;
 	}
 
-	/* Enable SVE if available */
-	if (kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE))
+	/* If SVE is not disabled explicitly, enable if available */
+	if (!kvm->cfg.arch.disable_sve &&
+	    kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE))
 		init->features[0] |= 1UL << KVM_ARM_VCPU_SVE;
 }
 
@@ -158,7 +159,8 @@ int kvm_cpu__configure_features(struct kvm_cpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
 
-	if (kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE)) {
+	if (!kvm->cfg.arch.disable_sve &&
+	    kvm__supports_vm_extension(kvm, KVM_CAP_ARM_SVE)) {
 		int feature = KVM_ARM_VCPU_SVE;
 
 		if (ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_FINALIZE, &feature)) {
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index 9949bfe4..6599305b 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -15,6 +15,7 @@ struct kvm_config_arch {
 	enum irqchip_type irqchip;
 	u64		fw_addr;
 	bool no_pvtime;
+	bool		disable_sve;
 };
 
 int irqchip_parser(const struct option *opt, const char *arg, int unset);
-- 
2.34.1


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

* [RFC kvmtool 08/31] linux: Update kernel headers for RME support
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Update the RME specific ABI bits from the kernel headers.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/asm/kvm.h | 64 +++++++++++++++++++++++++++++++++++
 include/linux/kvm.h           | 22 +++++++++---
 include/linux/virtio_blk.h    | 19 -----------
 include/linux/virtio_net.h    | 14 ++++----
 include/linux/virtio_ring.h   | 16 +++------
 5 files changed, 93 insertions(+), 42 deletions(-)

diff --git a/arm/aarch64/include/asm/kvm.h b/arm/aarch64/include/asm/kvm.h
index 316917b9..653a08fb 100644
--- a/arm/aarch64/include/asm/kvm.h
+++ b/arm/aarch64/include/asm/kvm.h
@@ -108,6 +108,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
 #define KVM_ARM_VCPU_PTRAUTH_ADDRESS	5 /* VCPU uses address authentication */
 #define KVM_ARM_VCPU_PTRAUTH_GENERIC	6 /* VCPU uses generic authentication */
+#define KVM_ARM_VCPU_REC		7 /* VCPU REC state as part of Realm */
 
 struct kvm_vcpu_init {
 	__u32 target;
@@ -400,6 +401,69 @@ enum {
 #define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 #define   KVM_DEV_ARM_ITS_CTRL_RESET		4
 
+/* KVM_CAP_ARM_RME kvm_enable_cap->args[0] points to this */
+#define KVM_CAP_ARM_RME_CONFIG_REALM		0
+#define KVM_CAP_ARM_RME_CREATE_RD		1
+#define KVM_CAP_ARM_RME_INIT_IPA_REALM		2
+#define KVM_CAP_ARM_RME_POPULATE_REALM		3
+#define KVM_CAP_ARM_RME_ACTIVATE_REALM		4
+
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_ZERO	(0x01ULL << 7)
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256 0
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA512 1
+
+#define KVM_CAP_ARM_RME_RPV_SIZE 64
+
+/* List of configuration items accepted for KVM_CAP_ARM_RME_CONFIG_REALM */
+#define KVM_CAP_ARM_RME_CFG_RPV			0
+#define KVM_CAP_ARM_RME_CFG_HASH_ALGO		1
+#define KVM_CAP_ARM_RME_CFG_SVE			2
+#define KVM_CAP_ARM_RME_CFG_DBG			3
+#define KVM_CAP_ARM_RME_CFG_PMU			4
+
+struct kvm_cap_arm_rme_config_item {
+	__u32 cfg;
+	union {
+		/* cfg == KVM_CAP_ARM_RME_CFG_RPV */
+		struct {
+			__u8	rpv[KVM_CAP_ARM_RME_RPV_SIZE];
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_HASH_ALGO */
+		struct {
+			__u32	hash_algo;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_SVE */
+		struct {
+			__u32	sve_vq;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_DBG */
+		struct {
+			__u32	num_brps;
+			__u32	num_wrps;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_PMU */
+		struct {
+			__u32	num_pmu_cntrs;
+		};
+		/* Fix the size of the union */
+		__u8	reserved[256];
+	};
+};
+
+struct kvm_cap_arm_rme_populate_realm_args {
+	__u64 populate_ipa_base;
+	__u64 populate_ipa_size;
+};
+
+struct kvm_cap_arm_rme_init_ipa_args {
+	__u64 init_ipa_base;
+	__u64 init_ipa_size;
+};
+
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
 #define   KVM_ARM_VCPU_PMU_V3_IRQ	0
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 0d5d4419..789c7f89 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -903,14 +903,25 @@ struct kvm_ppc_resize_hpt {
 #define KVM_S390_SIE_PAGE_OFFSET 1
 
 /*
- * On arm64, machine type can be used to request the physical
- * address size for the VM. Bits[7-0] are reserved for the guest
- * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
- * value 0 implies the default IPA size, 40bits.
+ * On arm64, machine type can be used to request both the machine type and
+ * the physical address size for the VM.
+ *
+ * Bits[11-8] are reserved for the ARM specific machine type.
+ *
+ * Bits[7-0] are reserved for the guest PA size shift (i.e, log2(PA_Size)).
+ * For backward compatibility, value 0 implies the default IPA size, 40bits.
  */
+#define KVM_VM_TYPE_ARM_SHIFT		8
+#define KVM_VM_TYPE_ARM_MASK		(0xfULL << KVM_VM_TYPE_ARM_SHIFT)
+#define KVM_VM_TYPE_ARM(_type)		\
+	(((_type) << KVM_VM_TYPE_ARM_SHIFT) & KVM_VM_TYPE_ARM_MASK)
+#define KVM_VM_TYPE_ARM_NORMAL		KVM_VM_TYPE_ARM(0)
+#define KVM_VM_TYPE_ARM_REALM		KVM_VM_TYPE_ARM(1)
+
 #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK	0xffULL
 #define KVM_VM_TYPE_ARM_IPA_SIZE(x)		\
 	((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+
 /*
  * ioctls for /dev/kvm fds:
  */
@@ -1177,7 +1188,8 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220
 #define KVM_CAP_S390_ZPCI_OP 221
 #define KVM_CAP_S390_CPU_TOPOLOGY 222
-#define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223
+
+#define KVM_CAP_ARM_RME 300 // FIXME: Large number to prevent conflicts
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index 58e70b24..d888f013 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -40,7 +40,6 @@
 #define VIRTIO_BLK_F_MQ		12	/* support more than one vq */
 #define VIRTIO_BLK_F_DISCARD	13	/* DISCARD is supported */
 #define VIRTIO_BLK_F_WRITE_ZEROES	14	/* WRITE ZEROES is supported */
-#define VIRTIO_BLK_F_SECURE_ERASE	16 /* Secure Erase is supported */
 
 /* Legacy feature bits */
 #ifndef VIRTIO_BLK_NO_LEGACY
@@ -122,21 +121,6 @@ struct virtio_blk_config {
 	__u8 write_zeroes_may_unmap;
 
 	__u8 unused1[3];
-
-	/* the next 3 entries are guarded by VIRTIO_BLK_F_SECURE_ERASE */
-	/*
-	 * The maximum secure erase sectors (in 512-byte sectors) for
-	 * one segment.
-	 */
-	__virtio32 max_secure_erase_sectors;
-	/*
-	 * The maximum number of secure erase segments in a
-	 * secure erase command.
-	 */
-	__virtio32 max_secure_erase_seg;
-	/* Secure erase commands must be aligned to this number of sectors. */
-	__virtio32 secure_erase_sector_alignment;
-
 } __attribute__((packed));
 
 /*
@@ -171,9 +155,6 @@ struct virtio_blk_config {
 /* Write zeroes command */
 #define VIRTIO_BLK_T_WRITE_ZEROES	13
 
-/* Secure erase command */
-#define VIRTIO_BLK_T_SECURE_ERASE	14
-
 #ifndef VIRTIO_BLK_NO_LEGACY
 /* Barrier before this op. */
 #define VIRTIO_BLK_T_BARRIER	0x80000000
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 6cb842ea..29ced555 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -56,7 +56,7 @@
 #define VIRTIO_NET_F_MQ	22	/* Device supports Receive Flow
 					 * Steering */
 #define VIRTIO_NET_F_CTRL_MAC_ADDR 23	/* Set MAC address */
-#define VIRTIO_NET_F_NOTF_COAL	53	/* Device supports notifications coalescing */
+#define VIRTIO_NET_F_NOTF_COAL	53	/* Guest can handle notifications coalescing */
 #define VIRTIO_NET_F_HASH_REPORT  57	/* Supports hash report */
 #define VIRTIO_NET_F_RSS	  60	/* Supports RSS RX steering */
 #define VIRTIO_NET_F_RSC_EXT	  61	/* extended coalescing info */
@@ -364,24 +364,24 @@ struct virtio_net_hash_config {
  */
 #define VIRTIO_NET_CTRL_NOTF_COAL		6
 /*
- * Set the tx-usecs/tx-max-packets parameters.
+ * Set the tx-usecs/tx-max-packets patameters.
+ * tx-usecs - Maximum number of usecs to delay a TX notification.
+ * tx-max-packets - Maximum number of packets to send before a TX notification.
  */
 struct virtio_net_ctrl_coal_tx {
-	/* Maximum number of packets to send before a TX notification */
 	__le32 tx_max_packets;
-	/* Maximum number of usecs to delay a TX notification */
 	__le32 tx_usecs;
 };
 
 #define VIRTIO_NET_CTRL_NOTF_COAL_TX_SET		0
 
 /*
- * Set the rx-usecs/rx-max-packets parameters.
+ * Set the rx-usecs/rx-max-packets patameters.
+ * rx-usecs - Maximum number of usecs to delay a RX notification.
+ * rx-max-frames - Maximum number of packets to receive before a RX notification.
  */
 struct virtio_net_ctrl_coal_rx {
-	/* Maximum number of packets to receive before a RX notification */
 	__le32 rx_max_packets;
-	/* Maximum number of usecs to delay a RX notification */
 	__le32 rx_usecs;
 };
 
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index f8c20d3d..476d3e5c 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -93,21 +93,15 @@
 #define VRING_USED_ALIGN_SIZE 4
 #define VRING_DESC_ALIGN_SIZE 16
 
-/**
- * struct vring_desc - Virtio ring descriptors,
- * 16 bytes long. These can chain together via @next.
- *
- * @addr: buffer address (guest-physical)
- * @len: buffer length
- * @flags: descriptor flags
- * @next: index of the next descriptor in the chain,
- *        if the VRING_DESC_F_NEXT flag is set. We chain unused
- *        descriptors via this, too.
- */
+/* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
 struct vring_desc {
+	/* Address (guest-physical). */
 	__virtio64 addr;
+	/* Length. */
 	__virtio32 len;
+	/* The flags as indicated above. */
 	__virtio16 flags;
+	/* We chain unused descriptors via this, too */
 	__virtio16 next;
 };
 
-- 
2.34.1


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

* [RFC kvmtool 08/31] linux: Update kernel headers for RME support
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Update the RME specific ABI bits from the kernel headers.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/asm/kvm.h | 64 +++++++++++++++++++++++++++++++++++
 include/linux/kvm.h           | 22 +++++++++---
 include/linux/virtio_blk.h    | 19 -----------
 include/linux/virtio_net.h    | 14 ++++----
 include/linux/virtio_ring.h   | 16 +++------
 5 files changed, 93 insertions(+), 42 deletions(-)

diff --git a/arm/aarch64/include/asm/kvm.h b/arm/aarch64/include/asm/kvm.h
index 316917b9..653a08fb 100644
--- a/arm/aarch64/include/asm/kvm.h
+++ b/arm/aarch64/include/asm/kvm.h
@@ -108,6 +108,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
 #define KVM_ARM_VCPU_PTRAUTH_ADDRESS	5 /* VCPU uses address authentication */
 #define KVM_ARM_VCPU_PTRAUTH_GENERIC	6 /* VCPU uses generic authentication */
+#define KVM_ARM_VCPU_REC		7 /* VCPU REC state as part of Realm */
 
 struct kvm_vcpu_init {
 	__u32 target;
@@ -400,6 +401,69 @@ enum {
 #define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 #define   KVM_DEV_ARM_ITS_CTRL_RESET		4
 
+/* KVM_CAP_ARM_RME kvm_enable_cap->args[0] points to this */
+#define KVM_CAP_ARM_RME_CONFIG_REALM		0
+#define KVM_CAP_ARM_RME_CREATE_RD		1
+#define KVM_CAP_ARM_RME_INIT_IPA_REALM		2
+#define KVM_CAP_ARM_RME_POPULATE_REALM		3
+#define KVM_CAP_ARM_RME_ACTIVATE_REALM		4
+
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_ZERO	(0x01ULL << 7)
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256 0
+#define KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA512 1
+
+#define KVM_CAP_ARM_RME_RPV_SIZE 64
+
+/* List of configuration items accepted for KVM_CAP_ARM_RME_CONFIG_REALM */
+#define KVM_CAP_ARM_RME_CFG_RPV			0
+#define KVM_CAP_ARM_RME_CFG_HASH_ALGO		1
+#define KVM_CAP_ARM_RME_CFG_SVE			2
+#define KVM_CAP_ARM_RME_CFG_DBG			3
+#define KVM_CAP_ARM_RME_CFG_PMU			4
+
+struct kvm_cap_arm_rme_config_item {
+	__u32 cfg;
+	union {
+		/* cfg == KVM_CAP_ARM_RME_CFG_RPV */
+		struct {
+			__u8	rpv[KVM_CAP_ARM_RME_RPV_SIZE];
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_HASH_ALGO */
+		struct {
+			__u32	hash_algo;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_SVE */
+		struct {
+			__u32	sve_vq;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_DBG */
+		struct {
+			__u32	num_brps;
+			__u32	num_wrps;
+		};
+
+		/* cfg == KVM_CAP_ARM_RME_CFG_PMU */
+		struct {
+			__u32	num_pmu_cntrs;
+		};
+		/* Fix the size of the union */
+		__u8	reserved[256];
+	};
+};
+
+struct kvm_cap_arm_rme_populate_realm_args {
+	__u64 populate_ipa_base;
+	__u64 populate_ipa_size;
+};
+
+struct kvm_cap_arm_rme_init_ipa_args {
+	__u64 init_ipa_base;
+	__u64 init_ipa_size;
+};
+
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
 #define   KVM_ARM_VCPU_PMU_V3_IRQ	0
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 0d5d4419..789c7f89 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -903,14 +903,25 @@ struct kvm_ppc_resize_hpt {
 #define KVM_S390_SIE_PAGE_OFFSET 1
 
 /*
- * On arm64, machine type can be used to request the physical
- * address size for the VM. Bits[7-0] are reserved for the guest
- * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
- * value 0 implies the default IPA size, 40bits.
+ * On arm64, machine type can be used to request both the machine type and
+ * the physical address size for the VM.
+ *
+ * Bits[11-8] are reserved for the ARM specific machine type.
+ *
+ * Bits[7-0] are reserved for the guest PA size shift (i.e, log2(PA_Size)).
+ * For backward compatibility, value 0 implies the default IPA size, 40bits.
  */
+#define KVM_VM_TYPE_ARM_SHIFT		8
+#define KVM_VM_TYPE_ARM_MASK		(0xfULL << KVM_VM_TYPE_ARM_SHIFT)
+#define KVM_VM_TYPE_ARM(_type)		\
+	(((_type) << KVM_VM_TYPE_ARM_SHIFT) & KVM_VM_TYPE_ARM_MASK)
+#define KVM_VM_TYPE_ARM_NORMAL		KVM_VM_TYPE_ARM(0)
+#define KVM_VM_TYPE_ARM_REALM		KVM_VM_TYPE_ARM(1)
+
 #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK	0xffULL
 #define KVM_VM_TYPE_ARM_IPA_SIZE(x)		\
 	((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+
 /*
  * ioctls for /dev/kvm fds:
  */
@@ -1177,7 +1188,8 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220
 #define KVM_CAP_S390_ZPCI_OP 221
 #define KVM_CAP_S390_CPU_TOPOLOGY 222
-#define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223
+
+#define KVM_CAP_ARM_RME 300 // FIXME: Large number to prevent conflicts
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index 58e70b24..d888f013 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -40,7 +40,6 @@
 #define VIRTIO_BLK_F_MQ		12	/* support more than one vq */
 #define VIRTIO_BLK_F_DISCARD	13	/* DISCARD is supported */
 #define VIRTIO_BLK_F_WRITE_ZEROES	14	/* WRITE ZEROES is supported */
-#define VIRTIO_BLK_F_SECURE_ERASE	16 /* Secure Erase is supported */
 
 /* Legacy feature bits */
 #ifndef VIRTIO_BLK_NO_LEGACY
@@ -122,21 +121,6 @@ struct virtio_blk_config {
 	__u8 write_zeroes_may_unmap;
 
 	__u8 unused1[3];
-
-	/* the next 3 entries are guarded by VIRTIO_BLK_F_SECURE_ERASE */
-	/*
-	 * The maximum secure erase sectors (in 512-byte sectors) for
-	 * one segment.
-	 */
-	__virtio32 max_secure_erase_sectors;
-	/*
-	 * The maximum number of secure erase segments in a
-	 * secure erase command.
-	 */
-	__virtio32 max_secure_erase_seg;
-	/* Secure erase commands must be aligned to this number of sectors. */
-	__virtio32 secure_erase_sector_alignment;
-
 } __attribute__((packed));
 
 /*
@@ -171,9 +155,6 @@ struct virtio_blk_config {
 /* Write zeroes command */
 #define VIRTIO_BLK_T_WRITE_ZEROES	13
 
-/* Secure erase command */
-#define VIRTIO_BLK_T_SECURE_ERASE	14
-
 #ifndef VIRTIO_BLK_NO_LEGACY
 /* Barrier before this op. */
 #define VIRTIO_BLK_T_BARRIER	0x80000000
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 6cb842ea..29ced555 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -56,7 +56,7 @@
 #define VIRTIO_NET_F_MQ	22	/* Device supports Receive Flow
 					 * Steering */
 #define VIRTIO_NET_F_CTRL_MAC_ADDR 23	/* Set MAC address */
-#define VIRTIO_NET_F_NOTF_COAL	53	/* Device supports notifications coalescing */
+#define VIRTIO_NET_F_NOTF_COAL	53	/* Guest can handle notifications coalescing */
 #define VIRTIO_NET_F_HASH_REPORT  57	/* Supports hash report */
 #define VIRTIO_NET_F_RSS	  60	/* Supports RSS RX steering */
 #define VIRTIO_NET_F_RSC_EXT	  61	/* extended coalescing info */
@@ -364,24 +364,24 @@ struct virtio_net_hash_config {
  */
 #define VIRTIO_NET_CTRL_NOTF_COAL		6
 /*
- * Set the tx-usecs/tx-max-packets parameters.
+ * Set the tx-usecs/tx-max-packets patameters.
+ * tx-usecs - Maximum number of usecs to delay a TX notification.
+ * tx-max-packets - Maximum number of packets to send before a TX notification.
  */
 struct virtio_net_ctrl_coal_tx {
-	/* Maximum number of packets to send before a TX notification */
 	__le32 tx_max_packets;
-	/* Maximum number of usecs to delay a TX notification */
 	__le32 tx_usecs;
 };
 
 #define VIRTIO_NET_CTRL_NOTF_COAL_TX_SET		0
 
 /*
- * Set the rx-usecs/rx-max-packets parameters.
+ * Set the rx-usecs/rx-max-packets patameters.
+ * rx-usecs - Maximum number of usecs to delay a RX notification.
+ * rx-max-frames - Maximum number of packets to receive before a RX notification.
  */
 struct virtio_net_ctrl_coal_rx {
-	/* Maximum number of packets to receive before a RX notification */
 	__le32 rx_max_packets;
-	/* Maximum number of usecs to delay a RX notification */
 	__le32 rx_usecs;
 };
 
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index f8c20d3d..476d3e5c 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -93,21 +93,15 @@
 #define VRING_USED_ALIGN_SIZE 4
 #define VRING_DESC_ALIGN_SIZE 16
 
-/**
- * struct vring_desc - Virtio ring descriptors,
- * 16 bytes long. These can chain together via @next.
- *
- * @addr: buffer address (guest-physical)
- * @len: buffer length
- * @flags: descriptor flags
- * @next: index of the next descriptor in the chain,
- *        if the VRING_DESC_F_NEXT flag is set. We chain unused
- *        descriptors via this, too.
- */
+/* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
 struct vring_desc {
+	/* Address (guest-physical). */
 	__virtio64 addr;
+	/* Length. */
 	__virtio32 len;
+	/* The flags as indicated above. */
 	__virtio16 flags;
+	/* We chain unused descriptors via this, too */
 	__virtio16 next;
 };
 
-- 
2.34.1


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

* [RFC kvmtool 09/31] arm64: Add --realm command line option
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Add the --realm command line option which causes kvmtool to exit with an
error if specified, but which will be enabled once realms are fully
supported by kvmtool.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h |  5 ++++-
 arm/aarch64/kvm.c                         | 20 ++++++++++++++++++--
 arm/include/arm-common/kvm-config-arch.h  |  1 +
 3 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index b055fef4..d2df850a 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -21,7 +21,10 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 	OPT_BOOLEAN('\0', "no-pvtime", &(cfg)->no_pvtime, "Disable"	\
 			" stolen time"),				\
 	OPT_BOOLEAN('\0', "disable-sve", &(cfg)->disable_sve,		\
-			"Disable SVE"),
+			"Disable SVE"),					\
+	OPT_BOOLEAN('\0', "realm", &(cfg)->is_realm,			\
+			"Create VM running in a realm using Arm RME"),
+
 #include "arm-common/kvm-config-arch.h"
 
 #endif /* KVM__KVM_CONFIG_ARCH_H */
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 5a53badb..25be2f2d 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -38,9 +38,8 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
-void kvm__arch_validate_cfg(struct kvm *kvm)
+static void validate_mem_cfg(struct kvm *kvm)
 {
-
 	if (kvm->cfg.ram_addr < ARM_MEMORY_AREA) {
 		die("RAM address is below the I/O region ending at %luGB",
 		    ARM_MEMORY_AREA >> 30);
@@ -52,6 +51,23 @@ void kvm__arch_validate_cfg(struct kvm *kvm)
 	}
 }
 
+static void validate_realm_cfg(struct kvm *kvm)
+{
+	if (!kvm->cfg.arch.is_realm)
+		return;
+
+	if (kvm->cfg.arch.aarch32_guest)
+		die("Realms supported only for 64bit guests");
+
+	die("Realms not supported");
+}
+
+void kvm__arch_validate_cfg(struct kvm *kvm)
+{
+	validate_mem_cfg(kvm);
+	validate_realm_cfg(kvm);
+}
+
 u64 kvm__arch_default_ram_address(void)
 {
 	return ARM_MEMORY_AREA;
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index 6599305b..5eb791da 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -11,6 +11,7 @@ struct kvm_config_arch {
 	bool		aarch32_guest;
 	bool		has_pmuv3;
 	bool		mte_disabled;
+	bool		is_realm;
 	u64		kaslr_seed;
 	enum irqchip_type irqchip;
 	u64		fw_addr;
-- 
2.34.1


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

* [RFC kvmtool 09/31] arm64: Add --realm command line option
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Add the --realm command line option which causes kvmtool to exit with an
error if specified, but which will be enabled once realms are fully
supported by kvmtool.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h |  5 ++++-
 arm/aarch64/kvm.c                         | 20 ++++++++++++++++++--
 arm/include/arm-common/kvm-config-arch.h  |  1 +
 3 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index b055fef4..d2df850a 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -21,7 +21,10 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 	OPT_BOOLEAN('\0', "no-pvtime", &(cfg)->no_pvtime, "Disable"	\
 			" stolen time"),				\
 	OPT_BOOLEAN('\0', "disable-sve", &(cfg)->disable_sve,		\
-			"Disable SVE"),
+			"Disable SVE"),					\
+	OPT_BOOLEAN('\0', "realm", &(cfg)->is_realm,			\
+			"Create VM running in a realm using Arm RME"),
+
 #include "arm-common/kvm-config-arch.h"
 
 #endif /* KVM__KVM_CONFIG_ARCH_H */
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 5a53badb..25be2f2d 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -38,9 +38,8 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
-void kvm__arch_validate_cfg(struct kvm *kvm)
+static void validate_mem_cfg(struct kvm *kvm)
 {
-
 	if (kvm->cfg.ram_addr < ARM_MEMORY_AREA) {
 		die("RAM address is below the I/O region ending at %luGB",
 		    ARM_MEMORY_AREA >> 30);
@@ -52,6 +51,23 @@ void kvm__arch_validate_cfg(struct kvm *kvm)
 	}
 }
 
+static void validate_realm_cfg(struct kvm *kvm)
+{
+	if (!kvm->cfg.arch.is_realm)
+		return;
+
+	if (kvm->cfg.arch.aarch32_guest)
+		die("Realms supported only for 64bit guests");
+
+	die("Realms not supported");
+}
+
+void kvm__arch_validate_cfg(struct kvm *kvm)
+{
+	validate_mem_cfg(kvm);
+	validate_realm_cfg(kvm);
+}
+
 u64 kvm__arch_default_ram_address(void)
 {
 	return ARM_MEMORY_AREA;
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index 6599305b..5eb791da 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -11,6 +11,7 @@ struct kvm_config_arch {
 	bool		aarch32_guest;
 	bool		has_pmuv3;
 	bool		mte_disabled;
+	bool		is_realm;
 	u64		kaslr_seed;
 	enum irqchip_type irqchip;
 	u64		fw_addr;
-- 
2.34.1


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

* [RFC kvmtool 10/31] arm64: Create a realm virtual machine
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Christoffer Dall <christoffer.dall@arm.com>

Set the machine type to realm when creating a VM via the KVM_CREATE_VM
ioctl.

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
[ Alex E: Reworked patch, split the command line option into a different
          patch ]
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 25be2f2d..5db4c572 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -131,12 +131,15 @@ int kvm__arch_get_ipa_limit(struct kvm *kvm)
 int kvm__get_vm_type(struct kvm *kvm)
 {
 	unsigned int ipa_bits, max_ipa_bits;
-	unsigned long max_ipa;
+	unsigned long max_ipa, vm_type;
 
-	/* If we're running on an old kernel, use 0 as the VM type */
+	vm_type = kvm->cfg.arch.is_realm ? \
+		  KVM_VM_TYPE_ARM_REALM : KVM_VM_TYPE_ARM_NORMAL;
+
+	/* If we're running on an old kernel, use 0 as the IPA bits */
 	max_ipa_bits = kvm__arch_get_ipa_limit(kvm);
 	if (!max_ipa_bits)
-		return 0;
+		return vm_type;
 
 	/* Otherwise, compute the minimal required IPA size */
 	max_ipa = kvm->cfg.ram_addr + kvm->cfg.ram_size - 1;
@@ -147,7 +150,8 @@ int kvm__get_vm_type(struct kvm *kvm)
 	if (ipa_bits > max_ipa_bits)
 		die("Memory too large for this system (needs %d bits, %d available)", ipa_bits, max_ipa_bits);
 
-	return KVM_VM_TYPE_ARM_IPA_SIZE(ipa_bits);
+	vm_type |= KVM_VM_TYPE_ARM_IPA_SIZE(ipa_bits);
+	return vm_type;
 }
 
 void kvm__arch_enable_mte(struct kvm *kvm)
-- 
2.34.1


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

* [RFC kvmtool 10/31] arm64: Create a realm virtual machine
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Christoffer Dall <christoffer.dall@arm.com>

Set the machine type to realm when creating a VM via the KVM_CREATE_VM
ioctl.

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
[ Alex E: Reworked patch, split the command line option into a different
          patch ]
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 25be2f2d..5db4c572 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -131,12 +131,15 @@ int kvm__arch_get_ipa_limit(struct kvm *kvm)
 int kvm__get_vm_type(struct kvm *kvm)
 {
 	unsigned int ipa_bits, max_ipa_bits;
-	unsigned long max_ipa;
+	unsigned long max_ipa, vm_type;
 
-	/* If we're running on an old kernel, use 0 as the VM type */
+	vm_type = kvm->cfg.arch.is_realm ? \
+		  KVM_VM_TYPE_ARM_REALM : KVM_VM_TYPE_ARM_NORMAL;
+
+	/* If we're running on an old kernel, use 0 as the IPA bits */
 	max_ipa_bits = kvm__arch_get_ipa_limit(kvm);
 	if (!max_ipa_bits)
-		return 0;
+		return vm_type;
 
 	/* Otherwise, compute the minimal required IPA size */
 	max_ipa = kvm->cfg.ram_addr + kvm->cfg.ram_size - 1;
@@ -147,7 +150,8 @@ int kvm__get_vm_type(struct kvm *kvm)
 	if (ipa_bits > max_ipa_bits)
 		die("Memory too large for this system (needs %d bits, %d available)", ipa_bits, max_ipa_bits);
 
-	return KVM_VM_TYPE_ARM_IPA_SIZE(ipa_bits);
+	vm_type |= KVM_VM_TYPE_ARM_IPA_SIZE(ipa_bits);
+	return vm_type;
 }
 
 void kvm__arch_enable_mte(struct kvm *kvm)
-- 
2.34.1


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

* [RFC kvmtool 11/31] arm64: Lock realm RAM in memory
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

RMM doesn't yet support paging protected memory pages. Thus the VMM
must pin the entire VM memory.

Use mlock2 to keep the realm pages pinned in memory once they are faulted
in. Use the MLOCK_ONFAULT flag to prevent pre-mapping the pages and
maintain some semblance of on demand-paging for a realm VM.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/kvm.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/arm/kvm.c b/arm/kvm.c
index d51cc15d..0e40b753 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -7,6 +7,8 @@
 
 #include "arm-common/gic.h"
 
+#include <sys/resource.h>
+
 #include <linux/kernel.h>
 #include <linux/kvm.h>
 #include <linux/sizes.h>
@@ -24,6 +26,25 @@ bool kvm__arch_cpu_supports_vm(void)
 	return true;
 }
 
+static void try_increase_mlock_limit(struct kvm *kvm)
+{
+	u64 size = kvm->arch.ram_alloc_size;
+	struct rlimit mlock_limit, new_limit;
+
+	if (getrlimit(RLIMIT_MEMLOCK, &mlock_limit)) {
+		perror("getrlimit(RLIMIT_MEMLOCK)");
+		return;
+	}
+
+	if (mlock_limit.rlim_cur > size)
+		return;
+
+	new_limit.rlim_cur = size;
+	new_limit.rlim_max = max((rlim_t)size, mlock_limit.rlim_max);
+	/* Requires CAP_SYS_RESOURCE capability. */
+	setrlimit(RLIMIT_MEMLOCK, &new_limit);
+}
+
 void kvm__init_ram(struct kvm *kvm)
 {
 	u64 phys_start, phys_size;
@@ -49,8 +70,27 @@ void kvm__init_ram(struct kvm *kvm)
 	kvm->ram_start = (void *)ALIGN((unsigned long)kvm->arch.ram_alloc_start,
 					SZ_2M);
 
-	madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
-		MADV_MERGEABLE);
+	/*
+	 * Do not merge pages if this is a Realm.
+	 *  a) We cannot replace a page in realm stage2 without export/import
+	 *
+	 * Pin the realm memory until we have export/import, due to the same
+	 * reason as above.
+	 *
+	 * Use mlock2(,,MLOCK_ONFAULT) to allow faulting in pages and thus
+	 * allowing to lazily populate the PAR.
+	 */
+	if (kvm->cfg.arch.is_realm) {
+		int ret;
+
+		try_increase_mlock_limit(kvm);
+		ret = mlock2(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
+			     MLOCK_ONFAULT);
+		if (ret)
+			die_perror("mlock2");
+	} else {
+		madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size, MADV_MERGEABLE);
+	}
 
 	madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
 		MADV_HUGEPAGE);
-- 
2.34.1


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

* [RFC kvmtool 11/31] arm64: Lock realm RAM in memory
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

RMM doesn't yet support paging protected memory pages. Thus the VMM
must pin the entire VM memory.

Use mlock2 to keep the realm pages pinned in memory once they are faulted
in. Use the MLOCK_ONFAULT flag to prevent pre-mapping the pages and
maintain some semblance of on demand-paging for a realm VM.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/kvm.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/arm/kvm.c b/arm/kvm.c
index d51cc15d..0e40b753 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -7,6 +7,8 @@
 
 #include "arm-common/gic.h"
 
+#include <sys/resource.h>
+
 #include <linux/kernel.h>
 #include <linux/kvm.h>
 #include <linux/sizes.h>
@@ -24,6 +26,25 @@ bool kvm__arch_cpu_supports_vm(void)
 	return true;
 }
 
+static void try_increase_mlock_limit(struct kvm *kvm)
+{
+	u64 size = kvm->arch.ram_alloc_size;
+	struct rlimit mlock_limit, new_limit;
+
+	if (getrlimit(RLIMIT_MEMLOCK, &mlock_limit)) {
+		perror("getrlimit(RLIMIT_MEMLOCK)");
+		return;
+	}
+
+	if (mlock_limit.rlim_cur > size)
+		return;
+
+	new_limit.rlim_cur = size;
+	new_limit.rlim_max = max((rlim_t)size, mlock_limit.rlim_max);
+	/* Requires CAP_SYS_RESOURCE capability. */
+	setrlimit(RLIMIT_MEMLOCK, &new_limit);
+}
+
 void kvm__init_ram(struct kvm *kvm)
 {
 	u64 phys_start, phys_size;
@@ -49,8 +70,27 @@ void kvm__init_ram(struct kvm *kvm)
 	kvm->ram_start = (void *)ALIGN((unsigned long)kvm->arch.ram_alloc_start,
 					SZ_2M);
 
-	madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
-		MADV_MERGEABLE);
+	/*
+	 * Do not merge pages if this is a Realm.
+	 *  a) We cannot replace a page in realm stage2 without export/import
+	 *
+	 * Pin the realm memory until we have export/import, due to the same
+	 * reason as above.
+	 *
+	 * Use mlock2(,,MLOCK_ONFAULT) to allow faulting in pages and thus
+	 * allowing to lazily populate the PAR.
+	 */
+	if (kvm->cfg.arch.is_realm) {
+		int ret;
+
+		try_increase_mlock_limit(kvm);
+		ret = mlock2(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
+			     MLOCK_ONFAULT);
+		if (ret)
+			die_perror("mlock2");
+	} else {
+		madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size, MADV_MERGEABLE);
+	}
 
 	madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
 		MADV_HUGEPAGE);
-- 
2.34.1


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

* [RFC kvmtool 12/31] arm64: Create Realm Descriptor
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Create the Realm Descriptor using the measurement algorithm set
with --measurement-algo.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 Makefile                        |  1 +
 arm/aarch32/include/asm/realm.h | 10 ++++++++++
 arm/aarch64/include/asm/realm.h | 10 ++++++++++
 arm/aarch64/realm.c             | 14 ++++++++++++++
 arm/kvm.c                       |  3 +++
 5 files changed, 38 insertions(+)
 create mode 100644 arm/aarch32/include/asm/realm.h
 create mode 100644 arm/aarch64/include/asm/realm.h
 create mode 100644 arm/aarch64/realm.c

diff --git a/Makefile b/Makefile
index ed2414bd..88cdf6d2 100644
--- a/Makefile
+++ b/Makefile
@@ -192,6 +192,7 @@ ifeq ($(ARCH), arm64)
 	OBJS		+= arm/aarch64/kvm.o
 	OBJS		+= arm/aarch64/pvtime.o
 	OBJS		+= arm/aarch64/pmu.o
+	OBJS		+= arm/aarch64/realm.o
 	ARCH_INCLUDE	:= $(HDRS_ARM_COMMON)
 	ARCH_INCLUDE	+= -Iarm/aarch64/include
 
diff --git a/arm/aarch32/include/asm/realm.h b/arm/aarch32/include/asm/realm.h
new file mode 100644
index 00000000..5aca6cca
--- /dev/null
+++ b/arm/aarch32/include/asm/realm.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_REALM_H
+#define __ASM_REALM_H
+
+#include "kvm/kvm.h"
+
+static inline void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm) {}
+
+#endif /* ! __ASM_REALM_H */
diff --git a/arm/aarch64/include/asm/realm.h b/arm/aarch64/include/asm/realm.h
new file mode 100644
index 00000000..e176f15f
--- /dev/null
+++ b/arm/aarch64/include/asm/realm.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_REALM_H
+#define __ASM_REALM_H
+
+#include "kvm/kvm.h"
+
+void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm);
+
+#endif /* ! __ASM_REALM_H */
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
new file mode 100644
index 00000000..3a4adb66
--- /dev/null
+++ b/arm/aarch64/realm.c
@@ -0,0 +1,14 @@
+#include "kvm/kvm.h"
+
+#include <asm/realm.h>
+
+void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
+{
+	struct kvm_enable_cap rme_create_rd = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_CREATE_RD,
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_create_rd) < 0)
+		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CREATE_RD)");
+}
diff --git a/arm/kvm.c b/arm/kvm.c
index 0e40b753..2510a322 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -127,6 +127,9 @@ void kvm__arch_set_cmdline(char *cmdline, bool video)
 
 void kvm__arch_init(struct kvm *kvm)
 {
+	if (kvm->cfg.arch.is_realm)
+		kvm_arm_realm_create_realm_descriptor(kvm);
+
 	/* Create the virtual GIC. */
 	if (gic__create(kvm, kvm->cfg.arch.irqchip))
 		die("Failed to create virtual GIC");
-- 
2.34.1


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

* [RFC kvmtool 12/31] arm64: Create Realm Descriptor
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Create the Realm Descriptor using the measurement algorithm set
with --measurement-algo.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 Makefile                        |  1 +
 arm/aarch32/include/asm/realm.h | 10 ++++++++++
 arm/aarch64/include/asm/realm.h | 10 ++++++++++
 arm/aarch64/realm.c             | 14 ++++++++++++++
 arm/kvm.c                       |  3 +++
 5 files changed, 38 insertions(+)
 create mode 100644 arm/aarch32/include/asm/realm.h
 create mode 100644 arm/aarch64/include/asm/realm.h
 create mode 100644 arm/aarch64/realm.c

diff --git a/Makefile b/Makefile
index ed2414bd..88cdf6d2 100644
--- a/Makefile
+++ b/Makefile
@@ -192,6 +192,7 @@ ifeq ($(ARCH), arm64)
 	OBJS		+= arm/aarch64/kvm.o
 	OBJS		+= arm/aarch64/pvtime.o
 	OBJS		+= arm/aarch64/pmu.o
+	OBJS		+= arm/aarch64/realm.o
 	ARCH_INCLUDE	:= $(HDRS_ARM_COMMON)
 	ARCH_INCLUDE	+= -Iarm/aarch64/include
 
diff --git a/arm/aarch32/include/asm/realm.h b/arm/aarch32/include/asm/realm.h
new file mode 100644
index 00000000..5aca6cca
--- /dev/null
+++ b/arm/aarch32/include/asm/realm.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_REALM_H
+#define __ASM_REALM_H
+
+#include "kvm/kvm.h"
+
+static inline void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm) {}
+
+#endif /* ! __ASM_REALM_H */
diff --git a/arm/aarch64/include/asm/realm.h b/arm/aarch64/include/asm/realm.h
new file mode 100644
index 00000000..e176f15f
--- /dev/null
+++ b/arm/aarch64/include/asm/realm.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_REALM_H
+#define __ASM_REALM_H
+
+#include "kvm/kvm.h"
+
+void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm);
+
+#endif /* ! __ASM_REALM_H */
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
new file mode 100644
index 00000000..3a4adb66
--- /dev/null
+++ b/arm/aarch64/realm.c
@@ -0,0 +1,14 @@
+#include "kvm/kvm.h"
+
+#include <asm/realm.h>
+
+void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
+{
+	struct kvm_enable_cap rme_create_rd = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_CREATE_RD,
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_create_rd) < 0)
+		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CREATE_RD)");
+}
diff --git a/arm/kvm.c b/arm/kvm.c
index 0e40b753..2510a322 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -127,6 +127,9 @@ void kvm__arch_set_cmdline(char *cmdline, bool video)
 
 void kvm__arch_init(struct kvm *kvm)
 {
+	if (kvm->cfg.arch.is_realm)
+		kvm_arm_realm_create_realm_descriptor(kvm);
+
 	/* Create the virtual GIC. */
 	if (gic__create(kvm, kvm->cfg.arch.irqchip))
 		die("Failed to create virtual GIC");
-- 
2.34.1


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

* [RFC kvmtool 13/31] arm64: Add --measurement-algo command line option for a realm
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Christoffer Dall <christoffer.dall@arm.com>

Add the command line option to specify the algorithm that will be used
to create the cryptographic measurement of the realm. Valid options are
"sha256" and "sha512". The final measurement will be a hash using the
selected algorithm

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h |  5 ++++-
 arm/aarch64/kvm.c                         | 17 ++++++++++++++++-
 arm/include/arm-common/kvm-arch.h         |  1 +
 arm/include/arm-common/kvm-config-arch.h  |  1 +
 4 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index d2df850a..b93999b6 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -23,7 +23,10 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 	OPT_BOOLEAN('\0', "disable-sve", &(cfg)->disable_sve,		\
 			"Disable SVE"),					\
 	OPT_BOOLEAN('\0', "realm", &(cfg)->is_realm,			\
-			"Create VM running in a realm using Arm RME"),
+			"Create VM running in a realm using Arm RME"),	\
+	OPT_STRING('\0', "measurement-algo", &(cfg)->measurement_algo,	\
+			 "sha256, sha512",				\
+			 "Realm Measurement algorithm, default: sha256"),
 
 #include "arm-common/kvm-config-arch.h"
 
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 5db4c572..a5a98b2e 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -53,12 +53,27 @@ static void validate_mem_cfg(struct kvm *kvm)
 
 static void validate_realm_cfg(struct kvm *kvm)
 {
-	if (!kvm->cfg.arch.is_realm)
+	if (!kvm->cfg.arch.is_realm) {
+		if (kvm->cfg.arch.measurement_algo)
+			die("--measurement-algo valid only with --realm");
 		return;
+	}
 
 	if (kvm->cfg.arch.aarch32_guest)
 		die("Realms supported only for 64bit guests");
 
+	if (kvm->cfg.arch.measurement_algo) {
+		if (strcmp(kvm->cfg.arch.measurement_algo, "sha256") == 0)
+			kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256;
+		else if (strcmp(kvm->cfg.arch.measurement_algo, "sha512") == 0)
+			kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA512;
+		else
+			die("unknown realm measurement algorithm");
+	} else {
+		pr_debug("Realm Hash algorithm: Using default SHA256\n");
+		kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256;
+	}
+
 	die("Realms not supported");
 }
 
diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index b2ae373c..68224b1c 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -113,6 +113,7 @@ struct kvm_arch {
 	u64	dtb_guest_start;
 
 	cpu_set_t *vcpu_affinity_cpuset;
+	u64	measurement_algo;
 };
 
 #endif /* ARM_COMMON__KVM_ARCH_H */
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index 5eb791da..a2faa3af 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -6,6 +6,7 @@
 struct kvm_config_arch {
 	const char	*dump_dtb_filename;
 	const char	*vcpu_affinity;
+	const char	*measurement_algo;
 	unsigned int	force_cntfrq;
 	bool		virtio_trans_pci;
 	bool		aarch32_guest;
-- 
2.34.1


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

* [RFC kvmtool 13/31] arm64: Add --measurement-algo command line option for a realm
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Christoffer Dall <christoffer.dall@arm.com>

Add the command line option to specify the algorithm that will be used
to create the cryptographic measurement of the realm. Valid options are
"sha256" and "sha512". The final measurement will be a hash using the
selected algorithm

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h |  5 ++++-
 arm/aarch64/kvm.c                         | 17 ++++++++++++++++-
 arm/include/arm-common/kvm-arch.h         |  1 +
 arm/include/arm-common/kvm-config-arch.h  |  1 +
 4 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index d2df850a..b93999b6 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -23,7 +23,10 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 	OPT_BOOLEAN('\0', "disable-sve", &(cfg)->disable_sve,		\
 			"Disable SVE"),					\
 	OPT_BOOLEAN('\0', "realm", &(cfg)->is_realm,			\
-			"Create VM running in a realm using Arm RME"),
+			"Create VM running in a realm using Arm RME"),	\
+	OPT_STRING('\0', "measurement-algo", &(cfg)->measurement_algo,	\
+			 "sha256, sha512",				\
+			 "Realm Measurement algorithm, default: sha256"),
 
 #include "arm-common/kvm-config-arch.h"
 
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 5db4c572..a5a98b2e 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -53,12 +53,27 @@ static void validate_mem_cfg(struct kvm *kvm)
 
 static void validate_realm_cfg(struct kvm *kvm)
 {
-	if (!kvm->cfg.arch.is_realm)
+	if (!kvm->cfg.arch.is_realm) {
+		if (kvm->cfg.arch.measurement_algo)
+			die("--measurement-algo valid only with --realm");
 		return;
+	}
 
 	if (kvm->cfg.arch.aarch32_guest)
 		die("Realms supported only for 64bit guests");
 
+	if (kvm->cfg.arch.measurement_algo) {
+		if (strcmp(kvm->cfg.arch.measurement_algo, "sha256") == 0)
+			kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256;
+		else if (strcmp(kvm->cfg.arch.measurement_algo, "sha512") == 0)
+			kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA512;
+		else
+			die("unknown realm measurement algorithm");
+	} else {
+		pr_debug("Realm Hash algorithm: Using default SHA256\n");
+		kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256;
+	}
+
 	die("Realms not supported");
 }
 
diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index b2ae373c..68224b1c 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -113,6 +113,7 @@ struct kvm_arch {
 	u64	dtb_guest_start;
 
 	cpu_set_t *vcpu_affinity_cpuset;
+	u64	measurement_algo;
 };
 
 #endif /* ARM_COMMON__KVM_ARCH_H */
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index 5eb791da..a2faa3af 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -6,6 +6,7 @@
 struct kvm_config_arch {
 	const char	*dump_dtb_filename;
 	const char	*vcpu_affinity;
+	const char	*measurement_algo;
 	unsigned int	force_cntfrq;
 	bool		virtio_trans_pci;
 	bool		aarch32_guest;
-- 
2.34.1


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

* [RFC kvmtool 14/31] arm64: Add configuration step for Realms
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Realm must be configured before it is created. Add the
step to specify the parameters for the Realm.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/realm.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index 3a4adb66..31543e55 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -2,6 +2,29 @@
 
 #include <asm/realm.h>
 
+
+static void realm_configure_hash_algo(struct kvm *kvm)
+{
+	struct kvm_cap_arm_rme_config_item hash_algo_cfg = {
+		.cfg	= KVM_CAP_ARM_RME_CFG_HASH_ALGO,
+		.hash_algo = kvm->arch.measurement_algo,
+	};
+
+	struct kvm_enable_cap rme_config = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_CONFIG_REALM,
+		.args[1] = (u64)&hash_algo_cfg,
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_config) < 0)
+		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) hash_algo");
+}
+
+static void realm_configure_parameters(struct kvm *kvm)
+{
+	realm_configure_hash_algo(kvm);
+}
+
 void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
 {
 	struct kvm_enable_cap rme_create_rd = {
@@ -9,6 +32,7 @@ void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
 		.args[0] = KVM_CAP_ARM_RME_CREATE_RD,
 	};
 
+	realm_configure_parameters(kvm);
 	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_create_rd) < 0)
 		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CREATE_RD)");
 }
-- 
2.34.1


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

* [RFC kvmtool 14/31] arm64: Add configuration step for Realms
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Realm must be configured before it is created. Add the
step to specify the parameters for the Realm.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/realm.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index 3a4adb66..31543e55 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -2,6 +2,29 @@
 
 #include <asm/realm.h>
 
+
+static void realm_configure_hash_algo(struct kvm *kvm)
+{
+	struct kvm_cap_arm_rme_config_item hash_algo_cfg = {
+		.cfg	= KVM_CAP_ARM_RME_CFG_HASH_ALGO,
+		.hash_algo = kvm->arch.measurement_algo,
+	};
+
+	struct kvm_enable_cap rme_config = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_CONFIG_REALM,
+		.args[1] = (u64)&hash_algo_cfg,
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_config) < 0)
+		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) hash_algo");
+}
+
+static void realm_configure_parameters(struct kvm *kvm)
+{
+	realm_configure_hash_algo(kvm);
+}
+
 void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
 {
 	struct kvm_enable_cap rme_create_rd = {
@@ -9,6 +32,7 @@ void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
 		.args[0] = KVM_CAP_ARM_RME_CREATE_RD,
 	};
 
+	realm_configure_parameters(kvm);
 	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_create_rd) < 0)
 		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CREATE_RD)");
 }
-- 
2.34.1


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

* [RFC kvmtool 15/31] arm64: Add support for Realm Personalisation Value
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Add option to specify Realm personalisation value

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h |  6 +++++-
 arm/aarch64/kvm.c                         |  7 +++++++
 arm/aarch64/realm.c                       | 23 +++++++++++++++++++++++
 arm/include/arm-common/kvm-config-arch.h  |  1 +
 4 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index b93999b6..f2e659ad 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -26,7 +26,11 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 			"Create VM running in a realm using Arm RME"),	\
 	OPT_STRING('\0', "measurement-algo", &(cfg)->measurement_algo,	\
 			 "sha256, sha512",				\
-			 "Realm Measurement algorithm, default: sha256"),
+			 "Realm Measurement algorithm, default: sha256"),\
+	OPT_STRING('\0', "realm-pv", &(cfg)->realm_pv,			\
+			"personalisation value",			\
+			"Personalisation Value (only) for Realm VMs"),
+
 
 #include "arm-common/kvm-config-arch.h"
 
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index a5a98b2e..4798e359 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -56,6 +56,8 @@ static void validate_realm_cfg(struct kvm *kvm)
 	if (!kvm->cfg.arch.is_realm) {
 		if (kvm->cfg.arch.measurement_algo)
 			die("--measurement-algo valid only with --realm");
+		if (kvm->cfg.arch.realm_pv)
+			die("--realm-pv valid only with --realm");
 		return;
 	}
 
@@ -74,6 +76,11 @@ static void validate_realm_cfg(struct kvm *kvm)
 		kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256;
 	}
 
+	if (kvm->cfg.arch.realm_pv) {
+		if (strlen(kvm->cfg.arch.realm_pv) > KVM_CAP_ARM_RME_RPV_SIZE)
+			die("Invalid size for Realm Personalization Value\n");
+	}
+
 	die("Realms not supported");
 }
 
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index 31543e55..2e0be982 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -20,9 +20,32 @@ static void realm_configure_hash_algo(struct kvm *kvm)
 		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) hash_algo");
 }
 
+static void realm_configure_rpv(struct kvm *kvm)
+{
+	struct kvm_cap_arm_rme_config_item rpv_cfg  = {
+		.cfg	= KVM_CAP_ARM_RME_CFG_RPV,
+	};
+
+	struct kvm_enable_cap rme_config = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_CONFIG_REALM,
+		.args[1] = (u64)&rpv_cfg,
+	};
+
+	if (!kvm->cfg.arch.realm_pv)
+		return;
+
+	memset(&rpv_cfg.rpv, 0, sizeof(rpv_cfg.rpv));
+	memcpy(&rpv_cfg.rpv, kvm->cfg.arch.realm_pv, strlen(kvm->cfg.arch.realm_pv));
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_config) < 0)
+		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) RPV");
+}
+
 static void realm_configure_parameters(struct kvm *kvm)
 {
 	realm_configure_hash_algo(kvm);
+	realm_configure_rpv(kvm);
 }
 
 void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index a2faa3af..80a3b18e 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -7,6 +7,7 @@ struct kvm_config_arch {
 	const char	*dump_dtb_filename;
 	const char	*vcpu_affinity;
 	const char	*measurement_algo;
+	const char	*realm_pv;
 	unsigned int	force_cntfrq;
 	bool		virtio_trans_pci;
 	bool		aarch32_guest;
-- 
2.34.1


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

* [RFC kvmtool 15/31] arm64: Add support for Realm Personalisation Value
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Add option to specify Realm personalisation value

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h |  6 +++++-
 arm/aarch64/kvm.c                         |  7 +++++++
 arm/aarch64/realm.c                       | 23 +++++++++++++++++++++++
 arm/include/arm-common/kvm-config-arch.h  |  1 +
 4 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index b93999b6..f2e659ad 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -26,7 +26,11 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 			"Create VM running in a realm using Arm RME"),	\
 	OPT_STRING('\0', "measurement-algo", &(cfg)->measurement_algo,	\
 			 "sha256, sha512",				\
-			 "Realm Measurement algorithm, default: sha256"),
+			 "Realm Measurement algorithm, default: sha256"),\
+	OPT_STRING('\0', "realm-pv", &(cfg)->realm_pv,			\
+			"personalisation value",			\
+			"Personalisation Value (only) for Realm VMs"),
+
 
 #include "arm-common/kvm-config-arch.h"
 
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index a5a98b2e..4798e359 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -56,6 +56,8 @@ static void validate_realm_cfg(struct kvm *kvm)
 	if (!kvm->cfg.arch.is_realm) {
 		if (kvm->cfg.arch.measurement_algo)
 			die("--measurement-algo valid only with --realm");
+		if (kvm->cfg.arch.realm_pv)
+			die("--realm-pv valid only with --realm");
 		return;
 	}
 
@@ -74,6 +76,11 @@ static void validate_realm_cfg(struct kvm *kvm)
 		kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256;
 	}
 
+	if (kvm->cfg.arch.realm_pv) {
+		if (strlen(kvm->cfg.arch.realm_pv) > KVM_CAP_ARM_RME_RPV_SIZE)
+			die("Invalid size for Realm Personalization Value\n");
+	}
+
 	die("Realms not supported");
 }
 
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index 31543e55..2e0be982 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -20,9 +20,32 @@ static void realm_configure_hash_algo(struct kvm *kvm)
 		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) hash_algo");
 }
 
+static void realm_configure_rpv(struct kvm *kvm)
+{
+	struct kvm_cap_arm_rme_config_item rpv_cfg  = {
+		.cfg	= KVM_CAP_ARM_RME_CFG_RPV,
+	};
+
+	struct kvm_enable_cap rme_config = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_CONFIG_REALM,
+		.args[1] = (u64)&rpv_cfg,
+	};
+
+	if (!kvm->cfg.arch.realm_pv)
+		return;
+
+	memset(&rpv_cfg.rpv, 0, sizeof(rpv_cfg.rpv));
+	memcpy(&rpv_cfg.rpv, kvm->cfg.arch.realm_pv, strlen(kvm->cfg.arch.realm_pv));
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_config) < 0)
+		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) RPV");
+}
+
 static void realm_configure_parameters(struct kvm *kvm)
 {
 	realm_configure_hash_algo(kvm);
+	realm_configure_rpv(kvm);
 }
 
 void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index a2faa3af..80a3b18e 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -7,6 +7,7 @@ struct kvm_config_arch {
 	const char	*dump_dtb_filename;
 	const char	*vcpu_affinity;
 	const char	*measurement_algo;
+	const char	*realm_pv;
 	unsigned int	force_cntfrq;
 	bool		virtio_trans_pci;
 	bool		aarch32_guest;
-- 
2.34.1


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

* [RFC kvmtool 16/31] arm64: Add support for specifying the SVE vector length for Realm
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Add option to specify SVE vector length for realms.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h |  6 ++++--
 arm/aarch64/kvm.c                         | 23 +++++++++++++++++++++++
 arm/aarch64/realm.c                       | 21 +++++++++++++++++++++
 arm/include/arm-common/kvm-arch.h         |  1 +
 arm/include/arm-common/kvm-config-arch.h  |  1 +
 5 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index f2e659ad..0f42c2c2 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -29,8 +29,10 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 			 "Realm Measurement algorithm, default: sha256"),\
 	OPT_STRING('\0', "realm-pv", &(cfg)->realm_pv,			\
 			"personalisation value",			\
-			"Personalisation Value (only) for Realm VMs"),
-
+			"Personalisation Value (only) for Realm VMs"),	\
+	OPT_U64('\0', "sve-vl", &(cfg)->sve_vl,				\
+			"SVE Vector Length the VM"			\
+			"(only supported for Realms)"),
 
 #include "arm-common/kvm-config-arch.h"
 
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 4798e359..fca1410b 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -51,13 +51,19 @@ static void validate_mem_cfg(struct kvm *kvm)
 	}
 }
 
+#define SVE_VL_ALIGN	128
+
 static void validate_realm_cfg(struct kvm *kvm)
 {
+	u32 sve_vl;
+
 	if (!kvm->cfg.arch.is_realm) {
 		if (kvm->cfg.arch.measurement_algo)
 			die("--measurement-algo valid only with --realm");
 		if (kvm->cfg.arch.realm_pv)
 			die("--realm-pv valid only with --realm");
+		if (kvm->cfg.arch.sve_vl)
+			die("--sve-vl valid only with --realm");
 		return;
 	}
 
@@ -76,6 +82,23 @@ static void validate_realm_cfg(struct kvm *kvm)
 		kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256;
 	}
 
+	sve_vl = kvm->cfg.arch.sve_vl;
+	if (sve_vl) {
+		if (kvm->cfg.arch.disable_sve)
+			die("SVE VL requested when SVE is disabled");
+		if (!IS_ALIGNED(sve_vl, SVE_VL_ALIGN))
+			die("SVE VL is not aligned to %dbit\n", SVE_VL_ALIGN);
+		kvm->arch.sve_vq = (sve_vl / SVE_VL_ALIGN) - 1;
+	} else {
+		/*
+		 * Disable SVE for Realms, if a VL is not requested.
+		 * The SVE VL will be measured as part of the parameter
+		 * and we do not want to add an unknown entity to the
+		 * measurement.
+		 */
+		kvm->cfg.arch.disable_sve = true;
+	}
+
 	if (kvm->cfg.arch.realm_pv) {
 		if (strlen(kvm->cfg.arch.realm_pv) > KVM_CAP_ARM_RME_RPV_SIZE)
 			die("Invalid size for Realm Personalization Value\n");
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index 2e0be982..fc7f8d6a 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -42,10 +42,31 @@ static void realm_configure_rpv(struct kvm *kvm)
 		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) RPV");
 }
 
+static void realm_configure_sve(struct kvm *kvm)
+{
+	struct kvm_cap_arm_rme_config_item sve_cfg = {
+		.cfg	= KVM_CAP_ARM_RME_CFG_SVE,
+		.sve_vq = kvm->arch.sve_vq,
+	};
+
+	struct kvm_enable_cap rme_config = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_CONFIG_REALM,
+		.args[1] = (u64)&sve_cfg,
+	};
+
+	if (kvm->cfg.arch.disable_sve)
+		return;
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_config) < 0)
+		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) SVE");
+}
+
 static void realm_configure_parameters(struct kvm *kvm)
 {
 	realm_configure_hash_algo(kvm);
 	realm_configure_rpv(kvm);
+	realm_configure_sve(kvm);
 }
 
 void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index 68224b1c..41b31f11 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -114,6 +114,7 @@ struct kvm_arch {
 
 	cpu_set_t *vcpu_affinity_cpuset;
 	u64	measurement_algo;
+	u64	sve_vq;
 };
 
 #endif /* ARM_COMMON__KVM_ARCH_H */
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index 80a3b18e..d923fd9e 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -19,6 +19,7 @@ struct kvm_config_arch {
 	u64		fw_addr;
 	bool no_pvtime;
 	bool		disable_sve;
+	u64		sve_vl;
 };
 
 int irqchip_parser(const struct option *opt, const char *arg, int unset);
-- 
2.34.1


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

* [RFC kvmtool 16/31] arm64: Add support for specifying the SVE vector length for Realm
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Add option to specify SVE vector length for realms.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/include/kvm/kvm-config-arch.h |  6 ++++--
 arm/aarch64/kvm.c                         | 23 +++++++++++++++++++++++
 arm/aarch64/realm.c                       | 21 +++++++++++++++++++++
 arm/include/arm-common/kvm-arch.h         |  1 +
 arm/include/arm-common/kvm-config-arch.h  |  1 +
 5 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/arm/aarch64/include/kvm/kvm-config-arch.h b/arm/aarch64/include/kvm/kvm-config-arch.h
index f2e659ad..0f42c2c2 100644
--- a/arm/aarch64/include/kvm/kvm-config-arch.h
+++ b/arm/aarch64/include/kvm/kvm-config-arch.h
@@ -29,8 +29,10 @@ int vcpu_affinity_parser(const struct option *opt, const char *arg, int unset);
 			 "Realm Measurement algorithm, default: sha256"),\
 	OPT_STRING('\0', "realm-pv", &(cfg)->realm_pv,			\
 			"personalisation value",			\
-			"Personalisation Value (only) for Realm VMs"),
-
+			"Personalisation Value (only) for Realm VMs"),	\
+	OPT_U64('\0', "sve-vl", &(cfg)->sve_vl,				\
+			"SVE Vector Length the VM"			\
+			"(only supported for Realms)"),
 
 #include "arm-common/kvm-config-arch.h"
 
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 4798e359..fca1410b 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -51,13 +51,19 @@ static void validate_mem_cfg(struct kvm *kvm)
 	}
 }
 
+#define SVE_VL_ALIGN	128
+
 static void validate_realm_cfg(struct kvm *kvm)
 {
+	u32 sve_vl;
+
 	if (!kvm->cfg.arch.is_realm) {
 		if (kvm->cfg.arch.measurement_algo)
 			die("--measurement-algo valid only with --realm");
 		if (kvm->cfg.arch.realm_pv)
 			die("--realm-pv valid only with --realm");
+		if (kvm->cfg.arch.sve_vl)
+			die("--sve-vl valid only with --realm");
 		return;
 	}
 
@@ -76,6 +82,23 @@ static void validate_realm_cfg(struct kvm *kvm)
 		kvm->arch.measurement_algo = KVM_CAP_ARM_RME_MEASUREMENT_ALGO_SHA256;
 	}
 
+	sve_vl = kvm->cfg.arch.sve_vl;
+	if (sve_vl) {
+		if (kvm->cfg.arch.disable_sve)
+			die("SVE VL requested when SVE is disabled");
+		if (!IS_ALIGNED(sve_vl, SVE_VL_ALIGN))
+			die("SVE VL is not aligned to %dbit\n", SVE_VL_ALIGN);
+		kvm->arch.sve_vq = (sve_vl / SVE_VL_ALIGN) - 1;
+	} else {
+		/*
+		 * Disable SVE for Realms, if a VL is not requested.
+		 * The SVE VL will be measured as part of the parameter
+		 * and we do not want to add an unknown entity to the
+		 * measurement.
+		 */
+		kvm->cfg.arch.disable_sve = true;
+	}
+
 	if (kvm->cfg.arch.realm_pv) {
 		if (strlen(kvm->cfg.arch.realm_pv) > KVM_CAP_ARM_RME_RPV_SIZE)
 			die("Invalid size for Realm Personalization Value\n");
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index 2e0be982..fc7f8d6a 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -42,10 +42,31 @@ static void realm_configure_rpv(struct kvm *kvm)
 		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) RPV");
 }
 
+static void realm_configure_sve(struct kvm *kvm)
+{
+	struct kvm_cap_arm_rme_config_item sve_cfg = {
+		.cfg	= KVM_CAP_ARM_RME_CFG_SVE,
+		.sve_vq = kvm->arch.sve_vq,
+	};
+
+	struct kvm_enable_cap rme_config = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_CONFIG_REALM,
+		.args[1] = (u64)&sve_cfg,
+	};
+
+	if (kvm->cfg.arch.disable_sve)
+		return;
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_config) < 0)
+		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CONFIG_REALM) SVE");
+}
+
 static void realm_configure_parameters(struct kvm *kvm)
 {
 	realm_configure_hash_algo(kvm);
 	realm_configure_rpv(kvm);
+	realm_configure_sve(kvm);
 }
 
 void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index 68224b1c..41b31f11 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -114,6 +114,7 @@ struct kvm_arch {
 
 	cpu_set_t *vcpu_affinity_cpuset;
 	u64	measurement_algo;
+	u64	sve_vq;
 };
 
 #endif /* ARM_COMMON__KVM_ARCH_H */
diff --git a/arm/include/arm-common/kvm-config-arch.h b/arm/include/arm-common/kvm-config-arch.h
index 80a3b18e..d923fd9e 100644
--- a/arm/include/arm-common/kvm-config-arch.h
+++ b/arm/include/arm-common/kvm-config-arch.h
@@ -19,6 +19,7 @@ struct kvm_config_arch {
 	u64		fw_addr;
 	bool no_pvtime;
 	bool		disable_sve;
+	u64		sve_vl;
 };
 
 int irqchip_parser(const struct option *opt, const char *arg, int unset);
-- 
2.34.1


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

* [RFC kvmtool 17/31] arm: Add kernel size to VM context
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Add the kernel image size to the VM context, as we are going to use it
later. This matches what we already do with the initrd.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
[Fix kernel size printed in debug messages]
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/include/arm-common/kvm-arch.h | 1 +
 arm/kvm.c                         | 8 +++++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index 41b31f11..b5a4b851 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -108,6 +108,7 @@ struct kvm_arch {
 	 */
 	u64	memory_guest_start;
 	u64	kern_guest_start;
+	u64	kern_size;
 	u64	initrd_guest_start;
 	u64	initrd_size;
 	u64	dtb_guest_start;
diff --git a/arm/kvm.c b/arm/kvm.c
index 2510a322..acb627b2 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -153,7 +153,6 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 	limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1;
 
 	pos = kvm->ram_start + kvm__arch_get_kern_offset(kvm, fd_kernel);
-	kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
 	file_size = read_file(fd_kernel, pos, limit - pos);
 	if (file_size < 0) {
 		if (errno == ENOMEM)
@@ -161,9 +160,12 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 
 		die_perror("kernel read");
 	}
+
+	kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
+	kvm->arch.kern_size = file_size;
 	kernel_end = pos + file_size;
-	pr_debug("Loaded kernel to 0x%llx (%zd bytes)",
-		 kvm->arch.kern_guest_start, file_size);
+	pr_debug("Loaded kernel to 0x%llx (%llu bytes)",
+		 kvm->arch.kern_guest_start, kvm->arch.kern_size);
 
 	/*
 	 * Now load backwards from the end of memory so the kernel
-- 
2.34.1


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

* [RFC kvmtool 17/31] arm: Add kernel size to VM context
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Add the kernel image size to the VM context, as we are going to use it
later. This matches what we already do with the initrd.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
[Fix kernel size printed in debug messages]
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/include/arm-common/kvm-arch.h | 1 +
 arm/kvm.c                         | 8 +++++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index 41b31f11..b5a4b851 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -108,6 +108,7 @@ struct kvm_arch {
 	 */
 	u64	memory_guest_start;
 	u64	kern_guest_start;
+	u64	kern_size;
 	u64	initrd_guest_start;
 	u64	initrd_size;
 	u64	dtb_guest_start;
diff --git a/arm/kvm.c b/arm/kvm.c
index 2510a322..acb627b2 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -153,7 +153,6 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 	limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1;
 
 	pos = kvm->ram_start + kvm__arch_get_kern_offset(kvm, fd_kernel);
-	kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
 	file_size = read_file(fd_kernel, pos, limit - pos);
 	if (file_size < 0) {
 		if (errno == ENOMEM)
@@ -161,9 +160,12 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 
 		die_perror("kernel read");
 	}
+
+	kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
+	kvm->arch.kern_size = file_size;
 	kernel_end = pos + file_size;
-	pr_debug("Loaded kernel to 0x%llx (%zd bytes)",
-		 kvm->arch.kern_guest_start, file_size);
+	pr_debug("Loaded kernel to 0x%llx (%llu bytes)",
+		 kvm->arch.kern_guest_start, kvm->arch.kern_size);
 
 	/*
 	 * Now load backwards from the end of memory so the kernel
-- 
2.34.1


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

* [RFC kvmtool 18/31] arm64: Populate initial realm contents
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Populate the realm memory with the initial contents, which include
the device tree blob, the kernel image, and initrd, if specified,
or the firmware image.

Populating an image in the realm involves two steps:
 a) Mark the IPA area as RAM - INIT_IPA_REALM
 b) Load the contents into the IPA - POPULATE_REALM

Wherever we know the actual size of an image in memory, we make
sure the "memory area" is initialised to RAM.
e.g., Linux kernel image size from the header which includes the bss etc.
The "file size" on disk for the Linux image is much smaller.
We mark the region of size Image.header.size as RAM (a), from the kernel
load address. And load the Image file into the memory (b) above.
At the moment we only detect the Arm64 Linux Image header format.

Since we're already touching the code that copies the
initrd in guest memory, let's do a bit of cleaning and remove a
useless local variable.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
[ Make sure the Linux kernel image area is marked as RAM ]
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch32/include/asm/realm.h |   3 +
 arm/aarch64/include/asm/realm.h |   3 +
 arm/aarch64/realm.c             | 112 ++++++++++++++++++++++++++++++++
 arm/fdt.c                       |   6 ++
 arm/kvm.c                       |  20 ++++--
 include/linux/kernel.h          |   1 +
 6 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/arm/aarch32/include/asm/realm.h b/arm/aarch32/include/asm/realm.h
index 5aca6cca..fcff0e55 100644
--- a/arm/aarch32/include/asm/realm.h
+++ b/arm/aarch32/include/asm/realm.h
@@ -6,5 +6,8 @@
 #include "kvm/kvm.h"
 
 static inline void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm) {}
+static inline void kvm_arm_realm_populate_kernel(struct kvm *kvm) {}
+static inline void kvm_arm_realm_populate_initrd(struct kvm *kvm) {}
+static inline void kvm_arm_realm_populate_dtb(struct kvm *kvm) {}
 
 #endif /* ! __ASM_REALM_H */
diff --git a/arm/aarch64/include/asm/realm.h b/arm/aarch64/include/asm/realm.h
index e176f15f..6e760ac9 100644
--- a/arm/aarch64/include/asm/realm.h
+++ b/arm/aarch64/include/asm/realm.h
@@ -6,5 +6,8 @@
 #include "kvm/kvm.h"
 
 void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm);
+void kvm_arm_realm_populate_kernel(struct kvm *kvm);
+void kvm_arm_realm_populate_initrd(struct kvm *kvm);
+void kvm_arm_realm_populate_dtb(struct kvm *kvm);
 
 #endif /* ! __ASM_REALM_H */
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index fc7f8d6a..eddccece 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -1,5 +1,7 @@
 #include "kvm/kvm.h"
 
+#include <linux/byteorder.h>
+#include <asm/image.h>
 #include <asm/realm.h>
 
 
@@ -80,3 +82,113 @@ void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
 	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_create_rd) < 0)
 		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CREATE_RD)");
 }
+
+static void realm_init_ipa_range(struct kvm *kvm, u64 start, u64 size)
+{
+	struct kvm_cap_arm_rme_init_ipa_args init_ipa_args = {
+		.init_ipa_base = start,
+		.init_ipa_size = size
+	};
+	struct kvm_enable_cap rme_init_ipa_realm = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_INIT_IPA_REALM,
+		.args[1] = (u64)&init_ipa_args
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_init_ipa_realm) < 0)
+		die("unable to intialise IPA range for Realm %llx - %llx (size %llu)",
+		    start, start + size, size);
+
+}
+
+static void __realm_populate(struct kvm *kvm, u64 start, u64 size)
+{
+	struct kvm_cap_arm_rme_populate_realm_args populate_args = {
+		.populate_ipa_base = start,
+		.populate_ipa_size = size
+	};
+	struct kvm_enable_cap rme_populate_realm = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_POPULATE_REALM,
+		.args[1] = (u64)&populate_args
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_populate_realm) < 0)
+		die("unable to populate Realm memory %llx - %llx (size %llu)",
+		    start, start + size, size);
+}
+
+static void realm_populate(struct kvm *kvm, u64 start, u64 size)
+{
+	realm_init_ipa_range(kvm, start, size);
+	__realm_populate(kvm, start, size);
+}
+
+static bool is_arm64_linux_kernel_image(void *header)
+{
+	struct arm64_image_header *hdr = header;
+
+	return memcmp(&hdr->magic, ARM64_IMAGE_MAGIC, sizeof(hdr->magic)) == 0;
+}
+
+static ssize_t arm64_linux_kernel_image_size(void *header)
+{
+	struct arm64_image_header *hdr = header;
+
+	if (is_arm64_linux_kernel_image(header))
+		return le64_to_cpu(hdr->image_size);
+	die("Not arm64 Linux kernel Image");
+}
+
+void kvm_arm_realm_populate_kernel(struct kvm *kvm)
+{
+	u64 start, end, mem_size;
+	void *header = guest_flat_to_host(kvm, kvm->arch.kern_guest_start);
+
+	start = ALIGN_DOWN(kvm->arch.kern_guest_start, SZ_4K);
+	end = ALIGN(kvm->arch.kern_guest_start + kvm->arch.kern_size, SZ_4K);
+
+	if (is_arm64_linux_kernel_image(header))
+		mem_size = arm64_linux_kernel_image_size(header);
+	else
+		mem_size = end - start;
+
+	realm_init_ipa_range(kvm, start, mem_size);
+	__realm_populate(kvm, start, end - start);
+}
+
+void kvm_arm_realm_populate_initrd(struct kvm *kvm)
+{
+	u64 kernel_end, start, end;
+
+	kernel_end = ALIGN(kvm->arch.kern_guest_start + kvm->arch.kern_size, SZ_4K);
+	start = ALIGN_DOWN(kvm->arch.initrd_guest_start, SZ_4K);
+	/*
+	 * Because we align the initrd to 4 bytes, it is theoretically possible
+	 * for the start of the initrd to overlap with the same page where the
+	 * kernel ends.
+	 */
+	if (start < kernel_end)
+		start = kernel_end;
+	end = ALIGN(kvm->arch.initrd_guest_start + kvm->arch.initrd_size, SZ_4K);
+	if (end > start)
+		realm_populate(kvm, start, end - start);
+}
+
+void kvm_arm_realm_populate_dtb(struct kvm *kvm)
+{
+	u64 initrd_end, start, end;
+
+	initrd_end = ALIGN(kvm->arch.initrd_guest_start + kvm->arch.initrd_size, SZ_4K);
+	start = ALIGN_DOWN(kvm->arch.dtb_guest_start, SZ_4K);
+	/*
+	 * Same situation as with the initrd, but now it is the DTB which is
+	 * overlapping with the last page of the initrd, because the initrd is
+	 * populated first.
+	 */
+	if (start < initrd_end)
+		start = initrd_end;
+	end = ALIGN(kvm->arch.dtb_guest_start + FDT_MAX_SIZE, SZ_4K);
+	if (end > start)
+		realm_populate(kvm, start, end - start);
+}
diff --git a/arm/fdt.c b/arm/fdt.c
index 286ccadf..762a604d 100644
--- a/arm/fdt.c
+++ b/arm/fdt.c
@@ -7,6 +7,8 @@
 #include "arm-common/gic.h"
 #include "arm-common/pci.h"
 
+#include <asm/realm.h>
+
 #include <stdbool.h>
 
 #include <linux/byteorder.h>
@@ -231,6 +233,10 @@ static int setup_fdt(struct kvm *kvm)
 
 	if (kvm->cfg.arch.dump_dtb_filename)
 		dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
+
+	if (kvm->cfg.arch.is_realm)
+		kvm_arm_realm_populate_dtb(kvm);
+
 	return 0;
 }
 late_init(setup_fdt);
diff --git a/arm/kvm.c b/arm/kvm.c
index acb627b2..57c5b5f7 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -6,6 +6,7 @@
 #include "kvm/fdt.h"
 
 #include "arm-common/gic.h"
+#include <asm/realm.h>
 
 #include <sys/resource.h>
 
@@ -167,6 +168,9 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 	pr_debug("Loaded kernel to 0x%llx (%llu bytes)",
 		 kvm->arch.kern_guest_start, kvm->arch.kern_size);
 
+	if (kvm->cfg.arch.is_realm)
+		kvm_arm_realm_populate_kernel(kvm);
+
 	/*
 	 * Now load backwards from the end of memory so the kernel
 	 * decompressor has plenty of space to work with. First up is
@@ -188,7 +192,6 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 	/* ... and finally the initrd, if we have one. */
 	if (fd_initrd != -1) {
 		struct stat sb;
-		unsigned long initrd_start;
 
 		if (fstat(fd_initrd, &sb))
 			die_perror("fstat");
@@ -199,7 +202,6 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 		if (pos < kernel_end)
 			die("initrd overlaps with kernel image.");
 
-		initrd_start = guest_addr;
 		file_size = read_file(fd_initrd, pos, limit - pos);
 		if (file_size == -1) {
 			if (errno == ENOMEM)
@@ -208,11 +210,13 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 			die_perror("initrd read");
 		}
 
-		kvm->arch.initrd_guest_start = initrd_start;
+		kvm->arch.initrd_guest_start = guest_addr;
 		kvm->arch.initrd_size = file_size;
 		pr_debug("Loaded initrd to 0x%llx (%llu bytes)",
-			 kvm->arch.initrd_guest_start,
-			 kvm->arch.initrd_size);
+			 kvm->arch.initrd_guest_start, kvm->arch.initrd_size);
+
+		if (kvm->cfg.arch.is_realm)
+			kvm_arm_realm_populate_initrd(kvm);
 	} else {
 		kvm->arch.initrd_size = 0;
 	}
@@ -269,6 +273,8 @@ bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
 
 	/* Kernel isn't loaded by kvm, point start address to firmware */
 	kvm->arch.kern_guest_start = fw_addr;
+	kvm->arch.kern_size = fw_sz;
+
 	pr_debug("Loaded firmware to 0x%llx (%zd bytes)",
 		 kvm->arch.kern_guest_start, fw_sz);
 
@@ -283,6 +289,10 @@ bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
 		 kvm->arch.dtb_guest_start,
 		 kvm->arch.dtb_guest_start + FDT_MAX_SIZE);
 
+	if (kvm->cfg.arch.is_realm)
+		/* We hijack the kernel fields to describe the firmware. */
+		kvm_arm_realm_populate_kernel(kvm);
+
 	return true;
 }
 
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 6c22f1c0..25f19c20 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -9,6 +9,7 @@
 
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 
+#define ALIGN_DOWN(x,a)		__ALIGN_MASK(x - (typeof(x))((a) - 1),(typeof(x))(a)-1)
 #define ALIGN(x,a)		__ALIGN_MASK(x,(typeof(x))(a)-1)
 #define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
 #define IS_ALIGNED(x, a)	(((x) & ((typeof(x))(a) - 1)) == 0)
-- 
2.34.1


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

* [RFC kvmtool 18/31] arm64: Populate initial realm contents
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Populate the realm memory with the initial contents, which include
the device tree blob, the kernel image, and initrd, if specified,
or the firmware image.

Populating an image in the realm involves two steps:
 a) Mark the IPA area as RAM - INIT_IPA_REALM
 b) Load the contents into the IPA - POPULATE_REALM

Wherever we know the actual size of an image in memory, we make
sure the "memory area" is initialised to RAM.
e.g., Linux kernel image size from the header which includes the bss etc.
The "file size" on disk for the Linux image is much smaller.
We mark the region of size Image.header.size as RAM (a), from the kernel
load address. And load the Image file into the memory (b) above.
At the moment we only detect the Arm64 Linux Image header format.

Since we're already touching the code that copies the
initrd in guest memory, let's do a bit of cleaning and remove a
useless local variable.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
[ Make sure the Linux kernel image area is marked as RAM ]
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch32/include/asm/realm.h |   3 +
 arm/aarch64/include/asm/realm.h |   3 +
 arm/aarch64/realm.c             | 112 ++++++++++++++++++++++++++++++++
 arm/fdt.c                       |   6 ++
 arm/kvm.c                       |  20 ++++--
 include/linux/kernel.h          |   1 +
 6 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/arm/aarch32/include/asm/realm.h b/arm/aarch32/include/asm/realm.h
index 5aca6cca..fcff0e55 100644
--- a/arm/aarch32/include/asm/realm.h
+++ b/arm/aarch32/include/asm/realm.h
@@ -6,5 +6,8 @@
 #include "kvm/kvm.h"
 
 static inline void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm) {}
+static inline void kvm_arm_realm_populate_kernel(struct kvm *kvm) {}
+static inline void kvm_arm_realm_populate_initrd(struct kvm *kvm) {}
+static inline void kvm_arm_realm_populate_dtb(struct kvm *kvm) {}
 
 #endif /* ! __ASM_REALM_H */
diff --git a/arm/aarch64/include/asm/realm.h b/arm/aarch64/include/asm/realm.h
index e176f15f..6e760ac9 100644
--- a/arm/aarch64/include/asm/realm.h
+++ b/arm/aarch64/include/asm/realm.h
@@ -6,5 +6,8 @@
 #include "kvm/kvm.h"
 
 void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm);
+void kvm_arm_realm_populate_kernel(struct kvm *kvm);
+void kvm_arm_realm_populate_initrd(struct kvm *kvm);
+void kvm_arm_realm_populate_dtb(struct kvm *kvm);
 
 #endif /* ! __ASM_REALM_H */
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index fc7f8d6a..eddccece 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -1,5 +1,7 @@
 #include "kvm/kvm.h"
 
+#include <linux/byteorder.h>
+#include <asm/image.h>
 #include <asm/realm.h>
 
 
@@ -80,3 +82,113 @@ void kvm_arm_realm_create_realm_descriptor(struct kvm *kvm)
 	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_create_rd) < 0)
 		die_perror("KVM_CAP_RME(KVM_CAP_ARM_RME_CREATE_RD)");
 }
+
+static void realm_init_ipa_range(struct kvm *kvm, u64 start, u64 size)
+{
+	struct kvm_cap_arm_rme_init_ipa_args init_ipa_args = {
+		.init_ipa_base = start,
+		.init_ipa_size = size
+	};
+	struct kvm_enable_cap rme_init_ipa_realm = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_INIT_IPA_REALM,
+		.args[1] = (u64)&init_ipa_args
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_init_ipa_realm) < 0)
+		die("unable to intialise IPA range for Realm %llx - %llx (size %llu)",
+		    start, start + size, size);
+
+}
+
+static void __realm_populate(struct kvm *kvm, u64 start, u64 size)
+{
+	struct kvm_cap_arm_rme_populate_realm_args populate_args = {
+		.populate_ipa_base = start,
+		.populate_ipa_size = size
+	};
+	struct kvm_enable_cap rme_populate_realm = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_POPULATE_REALM,
+		.args[1] = (u64)&populate_args
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &rme_populate_realm) < 0)
+		die("unable to populate Realm memory %llx - %llx (size %llu)",
+		    start, start + size, size);
+}
+
+static void realm_populate(struct kvm *kvm, u64 start, u64 size)
+{
+	realm_init_ipa_range(kvm, start, size);
+	__realm_populate(kvm, start, size);
+}
+
+static bool is_arm64_linux_kernel_image(void *header)
+{
+	struct arm64_image_header *hdr = header;
+
+	return memcmp(&hdr->magic, ARM64_IMAGE_MAGIC, sizeof(hdr->magic)) == 0;
+}
+
+static ssize_t arm64_linux_kernel_image_size(void *header)
+{
+	struct arm64_image_header *hdr = header;
+
+	if (is_arm64_linux_kernel_image(header))
+		return le64_to_cpu(hdr->image_size);
+	die("Not arm64 Linux kernel Image");
+}
+
+void kvm_arm_realm_populate_kernel(struct kvm *kvm)
+{
+	u64 start, end, mem_size;
+	void *header = guest_flat_to_host(kvm, kvm->arch.kern_guest_start);
+
+	start = ALIGN_DOWN(kvm->arch.kern_guest_start, SZ_4K);
+	end = ALIGN(kvm->arch.kern_guest_start + kvm->arch.kern_size, SZ_4K);
+
+	if (is_arm64_linux_kernel_image(header))
+		mem_size = arm64_linux_kernel_image_size(header);
+	else
+		mem_size = end - start;
+
+	realm_init_ipa_range(kvm, start, mem_size);
+	__realm_populate(kvm, start, end - start);
+}
+
+void kvm_arm_realm_populate_initrd(struct kvm *kvm)
+{
+	u64 kernel_end, start, end;
+
+	kernel_end = ALIGN(kvm->arch.kern_guest_start + kvm->arch.kern_size, SZ_4K);
+	start = ALIGN_DOWN(kvm->arch.initrd_guest_start, SZ_4K);
+	/*
+	 * Because we align the initrd to 4 bytes, it is theoretically possible
+	 * for the start of the initrd to overlap with the same page where the
+	 * kernel ends.
+	 */
+	if (start < kernel_end)
+		start = kernel_end;
+	end = ALIGN(kvm->arch.initrd_guest_start + kvm->arch.initrd_size, SZ_4K);
+	if (end > start)
+		realm_populate(kvm, start, end - start);
+}
+
+void kvm_arm_realm_populate_dtb(struct kvm *kvm)
+{
+	u64 initrd_end, start, end;
+
+	initrd_end = ALIGN(kvm->arch.initrd_guest_start + kvm->arch.initrd_size, SZ_4K);
+	start = ALIGN_DOWN(kvm->arch.dtb_guest_start, SZ_4K);
+	/*
+	 * Same situation as with the initrd, but now it is the DTB which is
+	 * overlapping with the last page of the initrd, because the initrd is
+	 * populated first.
+	 */
+	if (start < initrd_end)
+		start = initrd_end;
+	end = ALIGN(kvm->arch.dtb_guest_start + FDT_MAX_SIZE, SZ_4K);
+	if (end > start)
+		realm_populate(kvm, start, end - start);
+}
diff --git a/arm/fdt.c b/arm/fdt.c
index 286ccadf..762a604d 100644
--- a/arm/fdt.c
+++ b/arm/fdt.c
@@ -7,6 +7,8 @@
 #include "arm-common/gic.h"
 #include "arm-common/pci.h"
 
+#include <asm/realm.h>
+
 #include <stdbool.h>
 
 #include <linux/byteorder.h>
@@ -231,6 +233,10 @@ static int setup_fdt(struct kvm *kvm)
 
 	if (kvm->cfg.arch.dump_dtb_filename)
 		dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
+
+	if (kvm->cfg.arch.is_realm)
+		kvm_arm_realm_populate_dtb(kvm);
+
 	return 0;
 }
 late_init(setup_fdt);
diff --git a/arm/kvm.c b/arm/kvm.c
index acb627b2..57c5b5f7 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -6,6 +6,7 @@
 #include "kvm/fdt.h"
 
 #include "arm-common/gic.h"
+#include <asm/realm.h>
 
 #include <sys/resource.h>
 
@@ -167,6 +168,9 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 	pr_debug("Loaded kernel to 0x%llx (%llu bytes)",
 		 kvm->arch.kern_guest_start, kvm->arch.kern_size);
 
+	if (kvm->cfg.arch.is_realm)
+		kvm_arm_realm_populate_kernel(kvm);
+
 	/*
 	 * Now load backwards from the end of memory so the kernel
 	 * decompressor has plenty of space to work with. First up is
@@ -188,7 +192,6 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 	/* ... and finally the initrd, if we have one. */
 	if (fd_initrd != -1) {
 		struct stat sb;
-		unsigned long initrd_start;
 
 		if (fstat(fd_initrd, &sb))
 			die_perror("fstat");
@@ -199,7 +202,6 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 		if (pos < kernel_end)
 			die("initrd overlaps with kernel image.");
 
-		initrd_start = guest_addr;
 		file_size = read_file(fd_initrd, pos, limit - pos);
 		if (file_size == -1) {
 			if (errno == ENOMEM)
@@ -208,11 +210,13 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
 			die_perror("initrd read");
 		}
 
-		kvm->arch.initrd_guest_start = initrd_start;
+		kvm->arch.initrd_guest_start = guest_addr;
 		kvm->arch.initrd_size = file_size;
 		pr_debug("Loaded initrd to 0x%llx (%llu bytes)",
-			 kvm->arch.initrd_guest_start,
-			 kvm->arch.initrd_size);
+			 kvm->arch.initrd_guest_start, kvm->arch.initrd_size);
+
+		if (kvm->cfg.arch.is_realm)
+			kvm_arm_realm_populate_initrd(kvm);
 	} else {
 		kvm->arch.initrd_size = 0;
 	}
@@ -269,6 +273,8 @@ bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
 
 	/* Kernel isn't loaded by kvm, point start address to firmware */
 	kvm->arch.kern_guest_start = fw_addr;
+	kvm->arch.kern_size = fw_sz;
+
 	pr_debug("Loaded firmware to 0x%llx (%zd bytes)",
 		 kvm->arch.kern_guest_start, fw_sz);
 
@@ -283,6 +289,10 @@ bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
 		 kvm->arch.dtb_guest_start,
 		 kvm->arch.dtb_guest_start + FDT_MAX_SIZE);
 
+	if (kvm->cfg.arch.is_realm)
+		/* We hijack the kernel fields to describe the firmware. */
+		kvm_arm_realm_populate_kernel(kvm);
+
 	return true;
 }
 
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 6c22f1c0..25f19c20 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -9,6 +9,7 @@
 
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 
+#define ALIGN_DOWN(x,a)		__ALIGN_MASK(x - (typeof(x))((a) - 1),(typeof(x))(a)-1)
 #define ALIGN(x,a)		__ALIGN_MASK(x,(typeof(x))(a)-1)
 #define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
 #define IS_ALIGNED(x, a)	(((x) & ((typeof(x))(a) - 1)) == 0)
-- 
2.34.1


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

* [RFC kvmtool 19/31] arm64: Don't try to set PSTATE for VCPUs belonging to a realm
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Christoffer Dall <christoffer.dall@arm.com>

RME doesn't allow setting the PSTATE but resets it to an architectural
value, and KVM also does not allow setting this register from user
space, so stop trying to do that.

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index e7649239..37f9aa9d 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -92,11 +92,13 @@ static void reset_vcpu_aarch64(struct kvm_cpu *vcpu)
 
 	reg.addr = (u64)&data;
 
-	/* pstate = all interrupts masked */
-	data	= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL1h;
-	reg.id	= ARM64_CORE_REG(regs.pstate);
-	if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
-		die_perror("KVM_SET_ONE_REG failed (spsr[EL1])");
+	if (!kvm->cfg.arch.is_realm) {
+		/* pstate = all interrupts masked */
+		data	= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL1h;
+		reg.id	= ARM64_CORE_REG(regs.pstate);
+		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+			die_perror("KVM_SET_ONE_REG failed (PSTATE)");
+	}
 
 	/* x1...x3 = 0 */
 	data	= 0;
-- 
2.34.1


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

* [RFC kvmtool 19/31] arm64: Don't try to set PSTATE for VCPUs belonging to a realm
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Christoffer Dall <christoffer.dall@arm.com>

RME doesn't allow setting the PSTATE but resets it to an architectural
value, and KVM also does not allow setting this register from user
space, so stop trying to do that.

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index e7649239..37f9aa9d 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -92,11 +92,13 @@ static void reset_vcpu_aarch64(struct kvm_cpu *vcpu)
 
 	reg.addr = (u64)&data;
 
-	/* pstate = all interrupts masked */
-	data	= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL1h;
-	reg.id	= ARM64_CORE_REG(regs.pstate);
-	if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
-		die_perror("KVM_SET_ONE_REG failed (spsr[EL1])");
+	if (!kvm->cfg.arch.is_realm) {
+		/* pstate = all interrupts masked */
+		data	= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL1h;
+		reg.id	= ARM64_CORE_REG(regs.pstate);
+		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+			die_perror("KVM_SET_ONE_REG failed (PSTATE)");
+	}
 
 	/* x1...x3 = 0 */
 	data	= 0;
-- 
2.34.1


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

* [RFC kvmtool 20/31] arm64: Finalize realm VCPU after reset
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

In order to run a VCPU belonging to a realm, that VCPU must be in the
finalized state. Finalize the CPU after reset, since kvmtool won't be
touching the VCPU state afterwards.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index 37f9aa9d..24e570c4 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -128,6 +128,13 @@ static void reset_vcpu_aarch64(struct kvm_cpu *vcpu)
 		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
 			die_perror("KVM_SET_ONE_REG failed (pc)");
 	}
+
+	if (kvm->cfg.arch.is_realm) {
+		int feature = KVM_ARM_VCPU_REC;
+
+		if (ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_FINALIZE, &feature) < 0)
+			die_perror("KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_REC)");
+	}
 }
 
 void kvm_cpu__select_features(struct kvm *kvm, struct kvm_vcpu_init *init)
-- 
2.34.1


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

* [RFC kvmtool 20/31] arm64: Finalize realm VCPU after reset
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

In order to run a VCPU belonging to a realm, that VCPU must be in the
finalized state. Finalize the CPU after reset, since kvmtool won't be
touching the VCPU state afterwards.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index 37f9aa9d..24e570c4 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -128,6 +128,13 @@ static void reset_vcpu_aarch64(struct kvm_cpu *vcpu)
 		if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
 			die_perror("KVM_SET_ONE_REG failed (pc)");
 	}
+
+	if (kvm->cfg.arch.is_realm) {
+		int feature = KVM_ARM_VCPU_REC;
+
+		if (ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_FINALIZE, &feature) < 0)
+			die_perror("KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_REC)");
+	}
 }
 
 void kvm_cpu__select_features(struct kvm *kvm, struct kvm_vcpu_init *init)
-- 
2.34.1


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

* [RFC kvmtool 21/31] init: Add last_{init, exit} list macros
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Add a last_init macro for constructor functions that will be executed last
in the initialization process. Add a symmetrical macro, last_exit, for
destructor functions that will be the last to be executed when kvmtool
exits.

The list priority for the late_{init, exit} macros has been bumped down a
spot, but their relative priority remains unchanged, to keep the same size
for the init_lists and exit_lists.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 include/kvm/util-init.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/kvm/util-init.h b/include/kvm/util-init.h
index 13d4f04d..e6a0e169 100644
--- a/include/kvm/util-init.h
+++ b/include/kvm/util-init.h
@@ -39,7 +39,8 @@ static void __attribute__ ((constructor)) __init__##cb(void)		\
 #define dev_init(cb) __init_list_add(cb, 5)
 #define virtio_dev_init(cb) __init_list_add(cb, 6)
 #define firmware_init(cb) __init_list_add(cb, 7)
-#define late_init(cb) __init_list_add(cb, 9)
+#define late_init(cb) __init_list_add(cb, 8)
+#define last_init(cb) __init_list_add(cb, 9)
 
 #define core_exit(cb) __exit_list_add(cb, 0)
 #define base_exit(cb) __exit_list_add(cb, 2)
@@ -47,5 +48,6 @@ static void __attribute__ ((constructor)) __init__##cb(void)		\
 #define dev_exit(cb) __exit_list_add(cb, 5)
 #define virtio_dev_exit(cb) __exit_list_add(cb, 6)
 #define firmware_exit(cb) __exit_list_add(cb, 7)
-#define late_exit(cb) __exit_list_add(cb, 9)
+#define late_exit(cb) __exit_list_add(cb, 8)
+#define last_exit(cb) __exit_list_add(cb, 9)
 #endif
-- 
2.34.1


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

* [RFC kvmtool 21/31] init: Add last_{init, exit} list macros
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Add a last_init macro for constructor functions that will be executed last
in the initialization process. Add a symmetrical macro, last_exit, for
destructor functions that will be the last to be executed when kvmtool
exits.

The list priority for the late_{init, exit} macros has been bumped down a
spot, but their relative priority remains unchanged, to keep the same size
for the init_lists and exit_lists.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 include/kvm/util-init.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/kvm/util-init.h b/include/kvm/util-init.h
index 13d4f04d..e6a0e169 100644
--- a/include/kvm/util-init.h
+++ b/include/kvm/util-init.h
@@ -39,7 +39,8 @@ static void __attribute__ ((constructor)) __init__##cb(void)		\
 #define dev_init(cb) __init_list_add(cb, 5)
 #define virtio_dev_init(cb) __init_list_add(cb, 6)
 #define firmware_init(cb) __init_list_add(cb, 7)
-#define late_init(cb) __init_list_add(cb, 9)
+#define late_init(cb) __init_list_add(cb, 8)
+#define last_init(cb) __init_list_add(cb, 9)
 
 #define core_exit(cb) __exit_list_add(cb, 0)
 #define base_exit(cb) __exit_list_add(cb, 2)
@@ -47,5 +48,6 @@ static void __attribute__ ((constructor)) __init__##cb(void)		\
 #define dev_exit(cb) __exit_list_add(cb, 5)
 #define virtio_dev_exit(cb) __exit_list_add(cb, 6)
 #define firmware_exit(cb) __exit_list_add(cb, 7)
-#define late_exit(cb) __exit_list_add(cb, 9)
+#define late_exit(cb) __exit_list_add(cb, 8)
+#define last_exit(cb) __exit_list_add(cb, 9)
 #endif
-- 
2.34.1


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

* [RFC kvmtool 22/31] arm64: Activate realm before the first VCPU is run
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Before KVM can run a VCPU belong to a realm, the realm be activated.
Activating a realm prevents the adding of new object and seals the
cryptographic measurement of that realm. The VCPU state is part of the
measurement, which means that realm activation must be performed after
all VCPUs have been reset.

Current RMM implementation can only create RECs in the order of their
MPIDRs. VCPUs get assigned MPIDRs by KVM based on their VCPU id. Reset the
VCPUs in the order they were created from the main thread instead of doing
it from their own thread, which doesn't guarantee any ordering.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c             |  4 ++++
 arm/aarch64/realm.c               | 35 +++++++++++++++++++++++++++++++
 arm/include/arm-common/kvm-arch.h |  1 +
 3 files changed, 40 insertions(+)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index 24e570c4..32fa7609 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -187,6 +187,10 @@ void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
 	cpu_set_t *affinity;
 	int ret;
 
+	/* VCPU reset is done before activating the realm. */
+	if (kvm->arch.realm_is_active)
+		return;
+
 	affinity = kvm->arch.vcpu_affinity_cpuset;
 	if (affinity) {
 		ret = sched_setaffinity(0, sizeof(cpu_set_t), affinity);
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index eddccece..808d39c5 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -1,4 +1,5 @@
 #include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
 
 #include <linux/byteorder.h>
 #include <asm/image.h>
@@ -192,3 +193,37 @@ void kvm_arm_realm_populate_dtb(struct kvm *kvm)
 	if (end > start)
 		realm_populate(kvm, start, end - start);
 }
+
+static void kvm_arm_realm_activate_realm(struct kvm *kvm)
+{
+	struct kvm_enable_cap activate_realm = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_ACTIVATE_REALM,
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &activate_realm) < 0)
+		die_perror("KVM_CAP_ARM_RME(KVM_CAP_ARM_RME_ACTIVATE_REALM)");
+
+	kvm->arch.realm_is_active = true;
+}
+
+static int kvm_arm_realm_finalize(struct kvm *kvm)
+{
+	int i;
+
+	if (!kvm->cfg.arch.is_realm)
+		return 0;
+
+	/*
+	 * VCPU reset must happen before the realm is activated, because their
+	 * state is part of the cryptographic measurement for the realm.
+	 */
+	for (i = 0; i < kvm->nrcpus; i++)
+		kvm_cpu__reset_vcpu(kvm->cpus[i]);
+
+	/* Activate and seal the measurement for the realm. */
+	kvm_arm_realm_activate_realm(kvm);
+
+	return 0;
+}
+last_init(kvm_arm_realm_finalize)
diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index b5a4b851..6d48e13c 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -116,6 +116,7 @@ struct kvm_arch {
 	cpu_set_t *vcpu_affinity_cpuset;
 	u64	measurement_algo;
 	u64	sve_vq;
+	bool	realm_is_active;
 };
 
 #endif /* ARM_COMMON__KVM_ARCH_H */
-- 
2.34.1


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

* [RFC kvmtool 22/31] arm64: Activate realm before the first VCPU is run
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Before KVM can run a VCPU belong to a realm, the realm be activated.
Activating a realm prevents the adding of new object and seals the
cryptographic measurement of that realm. The VCPU state is part of the
measurement, which means that realm activation must be performed after
all VCPUs have been reset.

Current RMM implementation can only create RECs in the order of their
MPIDRs. VCPUs get assigned MPIDRs by KVM based on their VCPU id. Reset the
VCPUs in the order they were created from the main thread instead of doing
it from their own thread, which doesn't guarantee any ordering.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c             |  4 ++++
 arm/aarch64/realm.c               | 35 +++++++++++++++++++++++++++++++
 arm/include/arm-common/kvm-arch.h |  1 +
 3 files changed, 40 insertions(+)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index 24e570c4..32fa7609 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -187,6 +187,10 @@ void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
 	cpu_set_t *affinity;
 	int ret;
 
+	/* VCPU reset is done before activating the realm. */
+	if (kvm->arch.realm_is_active)
+		return;
+
 	affinity = kvm->arch.vcpu_affinity_cpuset;
 	if (affinity) {
 		ret = sched_setaffinity(0, sizeof(cpu_set_t), affinity);
diff --git a/arm/aarch64/realm.c b/arm/aarch64/realm.c
index eddccece..808d39c5 100644
--- a/arm/aarch64/realm.c
+++ b/arm/aarch64/realm.c
@@ -1,4 +1,5 @@
 #include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
 
 #include <linux/byteorder.h>
 #include <asm/image.h>
@@ -192,3 +193,37 @@ void kvm_arm_realm_populate_dtb(struct kvm *kvm)
 	if (end > start)
 		realm_populate(kvm, start, end - start);
 }
+
+static void kvm_arm_realm_activate_realm(struct kvm *kvm)
+{
+	struct kvm_enable_cap activate_realm = {
+		.cap = KVM_CAP_ARM_RME,
+		.args[0] = KVM_CAP_ARM_RME_ACTIVATE_REALM,
+	};
+
+	if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &activate_realm) < 0)
+		die_perror("KVM_CAP_ARM_RME(KVM_CAP_ARM_RME_ACTIVATE_REALM)");
+
+	kvm->arch.realm_is_active = true;
+}
+
+static int kvm_arm_realm_finalize(struct kvm *kvm)
+{
+	int i;
+
+	if (!kvm->cfg.arch.is_realm)
+		return 0;
+
+	/*
+	 * VCPU reset must happen before the realm is activated, because their
+	 * state is part of the cryptographic measurement for the realm.
+	 */
+	for (i = 0; i < kvm->nrcpus; i++)
+		kvm_cpu__reset_vcpu(kvm->cpus[i]);
+
+	/* Activate and seal the measurement for the realm. */
+	kvm_arm_realm_activate_realm(kvm);
+
+	return 0;
+}
+last_init(kvm_arm_realm_finalize)
diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index b5a4b851..6d48e13c 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -116,6 +116,7 @@ struct kvm_arch {
 	cpu_set_t *vcpu_affinity_cpuset;
 	u64	measurement_algo;
 	u64	sve_vq;
+	bool	realm_is_active;
 };
 
 #endif /* ARM_COMMON__KVM_ARCH_H */
-- 
2.34.1


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

* [RFC kvmtool 23/31] arm64: Specify SMC as the PSCI conduits for realms
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Christoffer Dall <christoffer.dall@arm.com>

This lets the VM use the RMM implementation for PSCI.

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/fdt.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arm/fdt.c b/arm/fdt.c
index 762a604d..c46ff410 100644
--- a/arm/fdt.c
+++ b/arm/fdt.c
@@ -208,7 +208,14 @@ static int setup_fdt(struct kvm *kvm)
 		_FDT(fdt_property_string(fdt, "compatible", "arm,psci"));
 		fns = &psci_0_1_fns;
 	}
-	_FDT(fdt_property_string(fdt, "method", "hvc"));
+
+
+	if (kvm->cfg.arch.is_realm) {
+		_FDT(fdt_property_string(fdt, "method", "smc"));
+	} else {
+		_FDT(fdt_property_string(fdt, "method", "hvc"));
+	}
+
 	_FDT(fdt_property_cell(fdt, "cpu_suspend", fns->cpu_suspend));
 	_FDT(fdt_property_cell(fdt, "cpu_off", fns->cpu_off));
 	_FDT(fdt_property_cell(fdt, "cpu_on", fns->cpu_on));
-- 
2.34.1


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

* [RFC kvmtool 23/31] arm64: Specify SMC as the PSCI conduits for realms
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Christoffer Dall <christoffer.dall@arm.com>

This lets the VM use the RMM implementation for PSCI.

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/fdt.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arm/fdt.c b/arm/fdt.c
index 762a604d..c46ff410 100644
--- a/arm/fdt.c
+++ b/arm/fdt.c
@@ -208,7 +208,14 @@ static int setup_fdt(struct kvm *kvm)
 		_FDT(fdt_property_string(fdt, "compatible", "arm,psci"));
 		fns = &psci_0_1_fns;
 	}
-	_FDT(fdt_property_string(fdt, "method", "hvc"));
+
+
+	if (kvm->cfg.arch.is_realm) {
+		_FDT(fdt_property_string(fdt, "method", "smc"));
+	} else {
+		_FDT(fdt_property_string(fdt, "method", "hvc"));
+	}
+
 	_FDT(fdt_property_cell(fdt, "cpu_suspend", fns->cpu_suspend));
 	_FDT(fdt_property_cell(fdt, "cpu_off", fns->cpu_off));
 	_FDT(fdt_property_cell(fdt, "cpu_on", fns->cpu_on));
-- 
2.34.1


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

* [RFC kvmtool 24/31] arm64: Don't try to debug a realm
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Don't read the register values for a running realm, because they don't
reflect the actual hardware state of a realm. And don't try to read realm
memory, because that will promptly lead to kvmtool being killed.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index 32fa7609..a29a3413 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -250,6 +250,9 @@ void kvm_cpu__show_code(struct kvm_cpu *vcpu)
 
 	reg.addr = (u64)&data;
 
+	if (vcpu->kvm->cfg.arch.is_realm)
+		return;
+
 	dprintf(debug_fd, "\n*pc:\n");
 	reg.id = ARM64_CORE_REG(regs.pc);
 	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
@@ -274,6 +277,11 @@ void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
 	reg.addr = (u64)&data;
 	dprintf(debug_fd, "\n Registers:\n");
 
+	if (vcpu->kvm->cfg.arch.is_realm) {
+		dprintf(debug_fd, " UNACCESSIBLE\n");
+		return;
+	}
+
 	reg.id		= ARM64_CORE_REG(regs.pc);
 	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
 		die("KVM_GET_ONE_REG failed (pc)");
-- 
2.34.1


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

* [RFC kvmtool 24/31] arm64: Don't try to debug a realm
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

Don't read the register values for a running realm, because they don't
reflect the actual hardware state of a realm. And don't try to read realm
memory, because that will promptly lead to kvmtool being killed.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm-cpu.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arm/aarch64/kvm-cpu.c b/arm/aarch64/kvm-cpu.c
index 32fa7609..a29a3413 100644
--- a/arm/aarch64/kvm-cpu.c
+++ b/arm/aarch64/kvm-cpu.c
@@ -250,6 +250,9 @@ void kvm_cpu__show_code(struct kvm_cpu *vcpu)
 
 	reg.addr = (u64)&data;
 
+	if (vcpu->kvm->cfg.arch.is_realm)
+		return;
+
 	dprintf(debug_fd, "\n*pc:\n");
 	reg.id = ARM64_CORE_REG(regs.pc);
 	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
@@ -274,6 +277,11 @@ void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
 	reg.addr = (u64)&data;
 	dprintf(debug_fd, "\n Registers:\n");
 
+	if (vcpu->kvm->cfg.arch.is_realm) {
+		dprintf(debug_fd, " UNACCESSIBLE\n");
+		return;
+	}
+
 	reg.id		= ARM64_CORE_REG(regs.pc);
 	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
 		die("KVM_GET_ONE_REG failed (pc)");
-- 
2.34.1


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

* [RFC kvmtool 25/31] arm64: realm: Double the IPA space
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

The Realm's IPA space is divided into 2 halves. Protected
(lower half) and Unprotected (upper half). KVM implements
aliasing of the IPA, where the unprotected IPA is alias of
the corresponding protected ipa. Thus we must double the
IPA space required for a given VM.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index fca1410b..344c568b 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -189,6 +189,9 @@ int kvm__get_vm_type(struct kvm *kvm)
 	/* Otherwise, compute the minimal required IPA size */
 	max_ipa = kvm->cfg.ram_addr + kvm->cfg.ram_size - 1;
 	ipa_bits = max(32, fls_long(max_ipa));
+	/* Realm needs double the IPA space */
+	if (kvm->cfg.arch.is_realm)
+		ipa_bits++;
 	pr_debug("max_ipa %lx ipa_bits %d max_ipa_bits %d",
 		 max_ipa, ipa_bits, max_ipa_bits);
 
-- 
2.34.1


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

* [RFC kvmtool 25/31] arm64: realm: Double the IPA space
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

The Realm's IPA space is divided into 2 halves. Protected
(lower half) and Unprotected (upper half). KVM implements
aliasing of the IPA, where the unprotected IPA is alias of
the corresponding protected ipa. Thus we must double the
IPA space required for a given VM.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index fca1410b..344c568b 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -189,6 +189,9 @@ int kvm__get_vm_type(struct kvm *kvm)
 	/* Otherwise, compute the minimal required IPA size */
 	max_ipa = kvm->cfg.ram_addr + kvm->cfg.ram_size - 1;
 	ipa_bits = max(32, fls_long(max_ipa));
+	/* Realm needs double the IPA space */
+	if (kvm->cfg.arch.is_realm)
+		ipa_bits++;
 	pr_debug("max_ipa %lx ipa_bits %d max_ipa_bits %d",
 		 max_ipa, ipa_bits, max_ipa_bits);
 
-- 
2.34.1


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

* [RFC kvmtool 26/31] virtio: Add a wrapper for get_host_features
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Add a wrapper to the vdev->ops->get_host_features() to allow
setting platform specific flags outside the device

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 include/kvm/virtio.h | 2 ++
 virtio/core.c        | 5 +++++
 virtio/mmio-legacy.c | 2 +-
 virtio/mmio-modern.c | 2 +-
 virtio/pci-legacy.c  | 2 +-
 virtio/pci-modern.c  | 2 +-
 6 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h
index 94bddefe..e95cfad5 100644
--- a/include/kvm/virtio.h
+++ b/include/kvm/virtio.h
@@ -248,4 +248,6 @@ void virtio_set_guest_features(struct kvm *kvm, struct virtio_device *vdev,
 void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev,
 			  void *dev, u8 status);
 
+u64 virtio_dev_get_host_features(struct virtio_device *vdev, struct kvm *kvm, void *dev);
+
 #endif /* KVM__VIRTIO_H */
diff --git a/virtio/core.c b/virtio/core.c
index ea0e5b65..50e7f86d 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -283,6 +283,11 @@ void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev,
 		vdev->ops->notify_status(kvm, dev, ext_status);
 }
 
+u64 virtio_dev_get_host_features(struct virtio_device *vdev, struct kvm *kvm, void *dev)
+{
+	return vdev->ops->get_host_features(kvm, dev);
+}
+
 bool virtio_access_config(struct kvm *kvm, struct virtio_device *vdev,
 			  void *dev, unsigned long offset, void *data,
 			  size_t size, bool is_write)
diff --git a/virtio/mmio-legacy.c b/virtio/mmio-legacy.c
index 7ca7e69f..42673236 100644
--- a/virtio/mmio-legacy.c
+++ b/virtio/mmio-legacy.c
@@ -26,7 +26,7 @@ static void virtio_mmio_config_in(struct kvm_cpu *vcpu,
 		break;
 	case VIRTIO_MMIO_DEVICE_FEATURES:
 		if (vmmio->hdr.host_features_sel == 0)
-			val = vdev->ops->get_host_features(vmmio->kvm,
+			val = virtio_dev_get_host_features(vdev, vmmio->kvm,
 							   vmmio->dev);
 		ioport__write32(data, val);
 		break;
diff --git a/virtio/mmio-modern.c b/virtio/mmio-modern.c
index 6c0bb382..a09fa8e9 100644
--- a/virtio/mmio-modern.c
+++ b/virtio/mmio-modern.c
@@ -26,7 +26,7 @@ static void virtio_mmio_config_in(struct kvm_cpu *vcpu,
 	case VIRTIO_MMIO_DEVICE_FEATURES:
 		if (vmmio->hdr.host_features_sel > 1)
 			break;
-		features |= vdev->ops->get_host_features(vmmio->kvm, vmmio->dev);
+		features |= virtio_dev_get_host_features(vdev, vmmio->kvm, vmmio->dev);
 		val = features >> (32 * vmmio->hdr.host_features_sel);
 		break;
 	case VIRTIO_MMIO_QUEUE_NUM_MAX:
diff --git a/virtio/pci-legacy.c b/virtio/pci-legacy.c
index 58047967..d5f5dee7 100644
--- a/virtio/pci-legacy.c
+++ b/virtio/pci-legacy.c
@@ -44,7 +44,7 @@ static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev
 
 	switch (offset) {
 	case VIRTIO_PCI_HOST_FEATURES:
-		val = vdev->ops->get_host_features(kvm, vpci->dev);
+		val = virtio_dev_get_host_features(vdev, kvm, vpci->dev);
 		ioport__write32(data, val);
 		break;
 	case VIRTIO_PCI_QUEUE_PFN:
diff --git a/virtio/pci-modern.c b/virtio/pci-modern.c
index c5b4bc50..2c5bf3f8 100644
--- a/virtio/pci-modern.c
+++ b/virtio/pci-modern.c
@@ -158,7 +158,7 @@ static bool virtio_pci__common_read(struct virtio_device *vdev,
 	case VIRTIO_PCI_COMMON_DF:
 		if (vpci->device_features_sel > 1)
 			break;
-		features |= vdev->ops->get_host_features(vpci->kvm, vpci->dev);
+		features |= virtio_dev_get_host_features(vdev, vpci->kvm, vpci->dev);
 		val = features >> (32 * vpci->device_features_sel);
 		ioport__write32(data, val);
 		break;
-- 
2.34.1


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

* [RFC kvmtool 26/31] virtio: Add a wrapper for get_host_features
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Add a wrapper to the vdev->ops->get_host_features() to allow
setting platform specific flags outside the device

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 include/kvm/virtio.h | 2 ++
 virtio/core.c        | 5 +++++
 virtio/mmio-legacy.c | 2 +-
 virtio/mmio-modern.c | 2 +-
 virtio/pci-legacy.c  | 2 +-
 virtio/pci-modern.c  | 2 +-
 6 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h
index 94bddefe..e95cfad5 100644
--- a/include/kvm/virtio.h
+++ b/include/kvm/virtio.h
@@ -248,4 +248,6 @@ void virtio_set_guest_features(struct kvm *kvm, struct virtio_device *vdev,
 void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev,
 			  void *dev, u8 status);
 
+u64 virtio_dev_get_host_features(struct virtio_device *vdev, struct kvm *kvm, void *dev);
+
 #endif /* KVM__VIRTIO_H */
diff --git a/virtio/core.c b/virtio/core.c
index ea0e5b65..50e7f86d 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -283,6 +283,11 @@ void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev,
 		vdev->ops->notify_status(kvm, dev, ext_status);
 }
 
+u64 virtio_dev_get_host_features(struct virtio_device *vdev, struct kvm *kvm, void *dev)
+{
+	return vdev->ops->get_host_features(kvm, dev);
+}
+
 bool virtio_access_config(struct kvm *kvm, struct virtio_device *vdev,
 			  void *dev, unsigned long offset, void *data,
 			  size_t size, bool is_write)
diff --git a/virtio/mmio-legacy.c b/virtio/mmio-legacy.c
index 7ca7e69f..42673236 100644
--- a/virtio/mmio-legacy.c
+++ b/virtio/mmio-legacy.c
@@ -26,7 +26,7 @@ static void virtio_mmio_config_in(struct kvm_cpu *vcpu,
 		break;
 	case VIRTIO_MMIO_DEVICE_FEATURES:
 		if (vmmio->hdr.host_features_sel == 0)
-			val = vdev->ops->get_host_features(vmmio->kvm,
+			val = virtio_dev_get_host_features(vdev, vmmio->kvm,
 							   vmmio->dev);
 		ioport__write32(data, val);
 		break;
diff --git a/virtio/mmio-modern.c b/virtio/mmio-modern.c
index 6c0bb382..a09fa8e9 100644
--- a/virtio/mmio-modern.c
+++ b/virtio/mmio-modern.c
@@ -26,7 +26,7 @@ static void virtio_mmio_config_in(struct kvm_cpu *vcpu,
 	case VIRTIO_MMIO_DEVICE_FEATURES:
 		if (vmmio->hdr.host_features_sel > 1)
 			break;
-		features |= vdev->ops->get_host_features(vmmio->kvm, vmmio->dev);
+		features |= virtio_dev_get_host_features(vdev, vmmio->kvm, vmmio->dev);
 		val = features >> (32 * vmmio->hdr.host_features_sel);
 		break;
 	case VIRTIO_MMIO_QUEUE_NUM_MAX:
diff --git a/virtio/pci-legacy.c b/virtio/pci-legacy.c
index 58047967..d5f5dee7 100644
--- a/virtio/pci-legacy.c
+++ b/virtio/pci-legacy.c
@@ -44,7 +44,7 @@ static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev
 
 	switch (offset) {
 	case VIRTIO_PCI_HOST_FEATURES:
-		val = vdev->ops->get_host_features(kvm, vpci->dev);
+		val = virtio_dev_get_host_features(vdev, kvm, vpci->dev);
 		ioport__write32(data, val);
 		break;
 	case VIRTIO_PCI_QUEUE_PFN:
diff --git a/virtio/pci-modern.c b/virtio/pci-modern.c
index c5b4bc50..2c5bf3f8 100644
--- a/virtio/pci-modern.c
+++ b/virtio/pci-modern.c
@@ -158,7 +158,7 @@ static bool virtio_pci__common_read(struct virtio_device *vdev,
 	case VIRTIO_PCI_COMMON_DF:
 		if (vpci->device_features_sel > 1)
 			break;
-		features |= vdev->ops->get_host_features(vpci->kvm, vpci->dev);
+		features |= virtio_dev_get_host_features(vdev, vpci->kvm, vpci->dev);
 		val = features >> (32 * vpci->device_features_sel);
 		ioport__write32(data, val);
 		break;
-- 
2.34.1


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

* [RFC kvmtool 27/31] virtio: Add arch specific hook for virtio host flags
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Add callbacks for archs to provide virtio host flags.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch32/kvm.c | 5 +++++
 arm/aarch64/kvm.c | 5 +++++
 include/kvm/kvm.h | 2 ++
 mips/kvm.c        | 5 +++++
 powerpc/kvm.c     | 5 +++++
 riscv/kvm.c       | 5 +++++
 virtio/core.c     | 5 ++++-
 x86/kvm.c         | 5 +++++
 8 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/arm/aarch32/kvm.c b/arm/aarch32/kvm.c
index 768a56bb..849c55d3 100644
--- a/arm/aarch32/kvm.c
+++ b/arm/aarch32/kvm.c
@@ -12,3 +12,8 @@ u64 kvm__arch_default_ram_address(void)
 {
 	return ARM_MEMORY_AREA;
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 344c568b..a4664237 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -234,3 +234,8 @@ void kvm__arch_enable_mte(struct kvm *kvm)
 
 	pr_debug("MTE capability enabled");
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
index 3872dc65..a3624de4 100644
--- a/include/kvm/kvm.h
+++ b/include/kvm/kvm.h
@@ -203,6 +203,8 @@ int kvm__arch_free_firmware(struct kvm *kvm);
 bool kvm__arch_cpu_supports_vm(void);
 void kvm__arch_read_term(struct kvm *kvm);
 
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm);
+
 #ifdef ARCH_HAS_CFG_RAM_ADDRESS
 static inline bool kvm__arch_has_cfg_ram_address(void)
 {
diff --git a/mips/kvm.c b/mips/kvm.c
index 0faa03a9..e23d5cf9 100644
--- a/mips/kvm.c
+++ b/mips/kvm.c
@@ -374,3 +374,8 @@ void ioport__map_irq(u8 *irq)
 void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
 {
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/powerpc/kvm.c b/powerpc/kvm.c
index 7b0d0669..6b3ab93f 100644
--- a/powerpc/kvm.c
+++ b/powerpc/kvm.c
@@ -529,3 +529,8 @@ int kvm__arch_free_firmware(struct kvm *kvm)
 {
 	return 0;
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/riscv/kvm.c b/riscv/kvm.c
index 4d6f5cb5..884321ca 100644
--- a/riscv/kvm.c
+++ b/riscv/kvm.c
@@ -182,3 +182,8 @@ int kvm__arch_setup_firmware(struct kvm *kvm)
 {
 	return 0;
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/virtio/core.c b/virtio/core.c
index 50e7f86d..674f6fae 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -285,7 +285,10 @@ void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev,
 
 u64 virtio_dev_get_host_features(struct virtio_device *vdev, struct kvm *kvm, void *dev)
 {
-	return vdev->ops->get_host_features(kvm, dev);
+	u64 features = kvm__arch_get_virtio_host_features(kvm);
+
+	features |= vdev->ops->get_host_features(kvm, dev);
+	return features;
 }
 
 bool virtio_access_config(struct kvm *kvm, struct virtio_device *vdev,
diff --git a/x86/kvm.c b/x86/kvm.c
index 328fa750..961b5d3f 100644
--- a/x86/kvm.c
+++ b/x86/kvm.c
@@ -387,3 +387,8 @@ void kvm__arch_read_term(struct kvm *kvm)
 	serial8250__update_consoles(kvm);
 	virtio_console__inject_interrupt(kvm);
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
-- 
2.34.1


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

* [RFC kvmtool 27/31] virtio: Add arch specific hook for virtio host flags
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

Add callbacks for archs to provide virtio host flags.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch32/kvm.c | 5 +++++
 arm/aarch64/kvm.c | 5 +++++
 include/kvm/kvm.h | 2 ++
 mips/kvm.c        | 5 +++++
 powerpc/kvm.c     | 5 +++++
 riscv/kvm.c       | 5 +++++
 virtio/core.c     | 5 ++++-
 x86/kvm.c         | 5 +++++
 8 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/arm/aarch32/kvm.c b/arm/aarch32/kvm.c
index 768a56bb..849c55d3 100644
--- a/arm/aarch32/kvm.c
+++ b/arm/aarch32/kvm.c
@@ -12,3 +12,8 @@ u64 kvm__arch_default_ram_address(void)
 {
 	return ARM_MEMORY_AREA;
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 344c568b..a4664237 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -234,3 +234,8 @@ void kvm__arch_enable_mte(struct kvm *kvm)
 
 	pr_debug("MTE capability enabled");
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
index 3872dc65..a3624de4 100644
--- a/include/kvm/kvm.h
+++ b/include/kvm/kvm.h
@@ -203,6 +203,8 @@ int kvm__arch_free_firmware(struct kvm *kvm);
 bool kvm__arch_cpu_supports_vm(void);
 void kvm__arch_read_term(struct kvm *kvm);
 
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm);
+
 #ifdef ARCH_HAS_CFG_RAM_ADDRESS
 static inline bool kvm__arch_has_cfg_ram_address(void)
 {
diff --git a/mips/kvm.c b/mips/kvm.c
index 0faa03a9..e23d5cf9 100644
--- a/mips/kvm.c
+++ b/mips/kvm.c
@@ -374,3 +374,8 @@ void ioport__map_irq(u8 *irq)
 void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
 {
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/powerpc/kvm.c b/powerpc/kvm.c
index 7b0d0669..6b3ab93f 100644
--- a/powerpc/kvm.c
+++ b/powerpc/kvm.c
@@ -529,3 +529,8 @@ int kvm__arch_free_firmware(struct kvm *kvm)
 {
 	return 0;
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/riscv/kvm.c b/riscv/kvm.c
index 4d6f5cb5..884321ca 100644
--- a/riscv/kvm.c
+++ b/riscv/kvm.c
@@ -182,3 +182,8 @@ int kvm__arch_setup_firmware(struct kvm *kvm)
 {
 	return 0;
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
diff --git a/virtio/core.c b/virtio/core.c
index 50e7f86d..674f6fae 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -285,7 +285,10 @@ void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev,
 
 u64 virtio_dev_get_host_features(struct virtio_device *vdev, struct kvm *kvm, void *dev)
 {
-	return vdev->ops->get_host_features(kvm, dev);
+	u64 features = kvm__arch_get_virtio_host_features(kvm);
+
+	features |= vdev->ops->get_host_features(kvm, dev);
+	return features;
 }
 
 bool virtio_access_config(struct kvm *kvm, struct virtio_device *vdev,
diff --git a/x86/kvm.c b/x86/kvm.c
index 328fa750..961b5d3f 100644
--- a/x86/kvm.c
+++ b/x86/kvm.c
@@ -387,3 +387,8 @@ void kvm__arch_read_term(struct kvm *kvm)
 	serial8250__update_consoles(kvm);
 	virtio_console__inject_interrupt(kvm);
 }
+
+u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
+{
+	return 0;
+}
-- 
2.34.1


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

* [RFC kvmtool 28/31] arm64: realm: Enforce virtio F_ACCESS_PLATFORM flag
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

For realms, force the F_ACCESS_PLATFORM flag to ensure DMA-APIs
are triggered for virtio in Linux

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index a4664237..1f3a0def 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -5,6 +5,7 @@
 #include <linux/byteorder.h>
 #include <linux/cpumask.h>
 #include <linux/sizes.h>
+#include <linux/virtio_config.h>
 
 #include <kvm/util.h>
 
@@ -237,5 +238,10 @@ void kvm__arch_enable_mte(struct kvm *kvm)
 
 u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
 {
-	return 0;
+	u64 features = 0;
+
+	/* Enforce F_ACCESS_PLATFORM for Realms */
+	if (kvm->cfg.arch.is_realm)
+		features |= (1ULL << VIRTIO_F_ACCESS_PLATFORM);
+	return features;
 }
-- 
2.34.1


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

* [RFC kvmtool 28/31] arm64: realm: Enforce virtio F_ACCESS_PLATFORM flag
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

For realms, force the F_ACCESS_PLATFORM flag to ensure DMA-APIs
are triggered for virtio in Linux

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index a4664237..1f3a0def 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -5,6 +5,7 @@
 #include <linux/byteorder.h>
 #include <linux/cpumask.h>
 #include <linux/sizes.h>
+#include <linux/virtio_config.h>
 
 #include <kvm/util.h>
 
@@ -237,5 +238,10 @@ void kvm__arch_enable_mte(struct kvm *kvm)
 
 u64 kvm__arch_get_virtio_host_features(struct kvm *kvm)
 {
-	return 0;
+	u64 features = 0;
+
+	/* Enforce F_ACCESS_PLATFORM for Realms */
+	if (kvm->cfg.arch.is_realm)
+		features |= (1ULL << VIRTIO_F_ACCESS_PLATFORM);
+	return features;
 }
-- 
2.34.1


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

* [RFC kvmtool 29/31] mmio: add arch hook for an unhandled MMIO access
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel, Joey Gouly

From: Joey Gouly <joey.gouly@arm.com>

Add a hook that allows an architecture to run some code on an
unhandled MMIO access.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/kvm-cpu.c         | 4 ++++
 include/kvm/kvm-cpu.h | 2 ++
 mips/kvm-cpu.c        | 4 ++++
 mmio.c                | 3 +++
 powerpc/kvm-cpu.c     | 4 ++++
 riscv/kvm-cpu.c       | 4 ++++
 x86/kvm-cpu.c         | 4 ++++
 7 files changed, 25 insertions(+)

diff --git a/arm/kvm-cpu.c b/arm/kvm-cpu.c
index 98bc5fdf..90a15ae9 100644
--- a/arm/kvm-cpu.c
+++ b/arm/kvm-cpu.c
@@ -152,3 +152,7 @@ bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
 void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
 {
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *vcpu)
+{
+}
diff --git a/include/kvm/kvm-cpu.h b/include/kvm/kvm-cpu.h
index 0f16f8d6..d0c40598 100644
--- a/include/kvm/kvm-cpu.h
+++ b/include/kvm/kvm-cpu.h
@@ -29,4 +29,6 @@ void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu);
 void kvm_cpu__arch_nmi(struct kvm_cpu *cpu);
 void kvm_cpu__run_on_all_cpus(struct kvm *kvm, struct kvm_cpu_task *task);
 
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu);
+
 #endif /* KVM__KVM_CPU_H */
diff --git a/mips/kvm-cpu.c b/mips/kvm-cpu.c
index 30a3de18..0ce88ac3 100644
--- a/mips/kvm-cpu.c
+++ b/mips/kvm-cpu.c
@@ -217,3 +217,7 @@ void kvm_cpu__show_code(struct kvm_cpu *vcpu)
 void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
 {
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu)
+{
+}
diff --git a/mmio.c b/mmio.c
index 5a114e99..7e31079b 100644
--- a/mmio.c
+++ b/mmio.c
@@ -206,6 +206,9 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data,
 			fprintf(stderr,	"Warning: Ignoring MMIO %s at %016llx (length %u)\n",
 				to_direction(is_write),
 				(unsigned long long)phys_addr, len);
+
+		kvm_cpu__arch_unhandled_mmio(vcpu);
+
 		goto out;
 	}
 
diff --git a/powerpc/kvm-cpu.c b/powerpc/kvm-cpu.c
index 461e0a90..e0c20f9d 100644
--- a/powerpc/kvm-cpu.c
+++ b/powerpc/kvm-cpu.c
@@ -288,3 +288,7 @@ void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
 {
 	/* Does nothing yet */
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu)
+{
+}
diff --git a/riscv/kvm-cpu.c b/riscv/kvm-cpu.c
index f98bd7ae..8417e361 100644
--- a/riscv/kvm-cpu.c
+++ b/riscv/kvm-cpu.c
@@ -461,3 +461,7 @@ void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
 
 	kvm_cpu__show_csrs(vcpu);
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu)
+{
+}
diff --git a/x86/kvm-cpu.c b/x86/kvm-cpu.c
index b02ff65e..ac075ee4 100644
--- a/x86/kvm-cpu.c
+++ b/x86/kvm-cpu.c
@@ -444,3 +444,7 @@ void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
 
 	ioctl(cpu->vcpu_fd, KVM_NMI);
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu)
+{
+}
-- 
2.34.1


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

* [RFC kvmtool 29/31] mmio: add arch hook for an unhandled MMIO access
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel, Joey Gouly

From: Joey Gouly <joey.gouly@arm.com>

Add a hook that allows an architecture to run some code on an
unhandled MMIO access.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/kvm-cpu.c         | 4 ++++
 include/kvm/kvm-cpu.h | 2 ++
 mips/kvm-cpu.c        | 4 ++++
 mmio.c                | 3 +++
 powerpc/kvm-cpu.c     | 4 ++++
 riscv/kvm-cpu.c       | 4 ++++
 x86/kvm-cpu.c         | 4 ++++
 7 files changed, 25 insertions(+)

diff --git a/arm/kvm-cpu.c b/arm/kvm-cpu.c
index 98bc5fdf..90a15ae9 100644
--- a/arm/kvm-cpu.c
+++ b/arm/kvm-cpu.c
@@ -152,3 +152,7 @@ bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
 void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
 {
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *vcpu)
+{
+}
diff --git a/include/kvm/kvm-cpu.h b/include/kvm/kvm-cpu.h
index 0f16f8d6..d0c40598 100644
--- a/include/kvm/kvm-cpu.h
+++ b/include/kvm/kvm-cpu.h
@@ -29,4 +29,6 @@ void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu);
 void kvm_cpu__arch_nmi(struct kvm_cpu *cpu);
 void kvm_cpu__run_on_all_cpus(struct kvm *kvm, struct kvm_cpu_task *task);
 
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu);
+
 #endif /* KVM__KVM_CPU_H */
diff --git a/mips/kvm-cpu.c b/mips/kvm-cpu.c
index 30a3de18..0ce88ac3 100644
--- a/mips/kvm-cpu.c
+++ b/mips/kvm-cpu.c
@@ -217,3 +217,7 @@ void kvm_cpu__show_code(struct kvm_cpu *vcpu)
 void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
 {
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu)
+{
+}
diff --git a/mmio.c b/mmio.c
index 5a114e99..7e31079b 100644
--- a/mmio.c
+++ b/mmio.c
@@ -206,6 +206,9 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data,
 			fprintf(stderr,	"Warning: Ignoring MMIO %s at %016llx (length %u)\n",
 				to_direction(is_write),
 				(unsigned long long)phys_addr, len);
+
+		kvm_cpu__arch_unhandled_mmio(vcpu);
+
 		goto out;
 	}
 
diff --git a/powerpc/kvm-cpu.c b/powerpc/kvm-cpu.c
index 461e0a90..e0c20f9d 100644
--- a/powerpc/kvm-cpu.c
+++ b/powerpc/kvm-cpu.c
@@ -288,3 +288,7 @@ void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
 {
 	/* Does nothing yet */
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu)
+{
+}
diff --git a/riscv/kvm-cpu.c b/riscv/kvm-cpu.c
index f98bd7ae..8417e361 100644
--- a/riscv/kvm-cpu.c
+++ b/riscv/kvm-cpu.c
@@ -461,3 +461,7 @@ void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
 
 	kvm_cpu__show_csrs(vcpu);
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu)
+{
+}
diff --git a/x86/kvm-cpu.c b/x86/kvm-cpu.c
index b02ff65e..ac075ee4 100644
--- a/x86/kvm-cpu.c
+++ b/x86/kvm-cpu.c
@@ -444,3 +444,7 @@ void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
 
 	ioctl(cpu->vcpu_fd, KVM_NMI);
 }
+
+void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *cpu)
+{
+}
-- 
2.34.1


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

* [RFC kvmtool 30/31] arm64: realm: inject an abort on an unhandled MMIO access
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel, Joey Gouly

From: Joey Gouly <joey.gouly@arm.com>

For Realms, inject a synchronous external abort, instead of ignoring unknown
MMIO accesses.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/kvm-cpu.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arm/kvm-cpu.c b/arm/kvm-cpu.c
index 90a15ae9..c96d75eb 100644
--- a/arm/kvm-cpu.c
+++ b/arm/kvm-cpu.c
@@ -155,4 +155,13 @@ void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
 
 void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *vcpu)
 {
+	struct kvm_vcpu_events events = { };
+
+	if (!vcpu->kvm->cfg.arch.is_realm)
+		return;
+
+	events.exception.ext_dabt_pending = 1;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_VCPU_EVENTS, &events) < 0)
+		die_perror("KVM_SET_VCPU_EVENTS failed");
 }
-- 
2.34.1


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

* [RFC kvmtool 30/31] arm64: realm: inject an abort on an unhandled MMIO access
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel, Joey Gouly

From: Joey Gouly <joey.gouly@arm.com>

For Realms, inject a synchronous external abort, instead of ignoring unknown
MMIO accesses.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/kvm-cpu.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arm/kvm-cpu.c b/arm/kvm-cpu.c
index 90a15ae9..c96d75eb 100644
--- a/arm/kvm-cpu.c
+++ b/arm/kvm-cpu.c
@@ -155,4 +155,13 @@ void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
 
 void kvm_cpu__arch_unhandled_mmio(struct kvm_cpu *vcpu)
 {
+	struct kvm_vcpu_events events = { };
+
+	if (!vcpu->kvm->cfg.arch.is_realm)
+		return;
+
+	events.exception.ext_dabt_pending = 1;
+
+	if (ioctl(vcpu->vcpu_fd, KVM_SET_VCPU_EVENTS, &events) < 0)
+		die_perror("KVM_SET_VCPU_EVENTS failed");
 }
-- 
2.34.1


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

* [RFC kvmtool 31/31] arm64: Allow the user to create a realm
  2023-01-27 11:39   ` Suzuki K Poulose
@ 2023-01-27 11:39     ` Suzuki K Poulose
  -1 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

We have everything in place to create a realm, allow the user to do so.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 1f3a0def..422dbec2 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -104,8 +104,6 @@ static void validate_realm_cfg(struct kvm *kvm)
 		if (strlen(kvm->cfg.arch.realm_pv) > KVM_CAP_ARM_RME_RPV_SIZE)
 			die("Invalid size for Realm Personalization Value\n");
 	}
-
-	die("Realms not supported");
 }
 
 void kvm__arch_validate_cfg(struct kvm *kvm)
-- 
2.34.1


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

* [RFC kvmtool 31/31] arm64: Allow the user to create a realm
@ 2023-01-27 11:39     ` Suzuki K Poulose
  0 siblings, 0 replies; 386+ messages in thread
From: Suzuki K Poulose @ 2023-01-27 11:39 UTC (permalink / raw)
  To: kvm, kvmarm
  Cc: suzuki.poulose, Alexandru Elisei, Andrew Jones, Christoffer Dall,
	Fuad Tabba, Jean-Philippe Brucker, Joey Gouly, Marc Zyngier,
	Mark Rutland, Oliver Upton, Paolo Bonzini, Quentin Perret,
	Steven Price, Thomas Huth, Will Deacon, Zenghui Yu, linux-coco,
	kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

We have everything in place to create a realm, allow the user to do so.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 arm/aarch64/kvm.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arm/aarch64/kvm.c b/arm/aarch64/kvm.c
index 1f3a0def..422dbec2 100644
--- a/arm/aarch64/kvm.c
+++ b/arm/aarch64/kvm.c
@@ -104,8 +104,6 @@ static void validate_realm_cfg(struct kvm *kvm)
 		if (strlen(kvm->cfg.arch.realm_pv) > KVM_CAP_ARM_RME_RPV_SIZE)
 			die("Invalid size for Realm Personalization Value\n");
 	}
-
-	die("Realms not supported");
 }
 
 void kvm__arch_validate_cfg(struct kvm *kvm)
-- 
2.34.1


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

* [RFC kvm-unit-tests 00/27] Support for Arm Confidential Compute Architecture
  2023-01-27 11:22 ` Suzuki K Poulose
@ 2023-01-27 11:40   ` Joey Gouly
  -1 siblings, 0 replies; 386+ messages in thread
From: Joey Gouly @ 2023-01-27 11:40 UTC (permalink / raw)
  To: Andrew Jones, kvmarm, kvm
  Cc: joey.gouly, Alexandru Elisei, Christoffer Dall, Fuad Tabba,
	Jean-Philippe Brucker, Joey Gouly, Marc Zyngier, Mark Rutland,
	Oliver Upton, Paolo Bonzini, Quentin Perret, Steven Price,
	Suzuki K Poulose, Thomas Huth, Will Deacon, Zenghui Yu,
	linux-coco, kvmarm, linux-arm-kernel, linux-kernel

This series adds support for running the kvm-unit-tests in the Arm CCA reference
software architecture. See more details on Arm CCA and how to build/run the     
entire stack here [0].                                                          
                                                                                
This involves enlightening the boot/setup code with the Realm Service Interface 
(RSI). The series also includes new test cases that exercise the RSI calls.     
                                                                                
Currently we only support "kvmtool" as the VMM for running Realms. There was    
an attempt to add support for running the test scripts using with kvmtool here [1],
which hasn't progressed. It would be good to have that resolved, so that we can 
run all the tests without manually specifying the commandlines for each run.    
For the purposes of running the Realm specific tests, we have added a "temporary"
script "run-realm-tests" until the kvmtool support is added. We do not expect   
this to be merged.                                                              
                                                                                
                                                                                
Base Realm Support                                                              
-------------------                                                             
                                                                                
Realm IPA Space                                                                 
---------------                                                                 
When running on in Realm world, the (Guest) Physical Address - aka Intermediate 
Physical Address (IPA) in Arm terminology - space of the VM is split into two halves,
protected (lower half) and un-protected (upper half). A protected IPA will      
always map pages in the "realm world" and  the contents are not accessible to   
the host. An unprotected IPA on the other hand can be mapped to page in the     
"normal world" and thus shared with the host. All host emulated MMIO ranges must
be in unprotected IPA space.                                                    
                                                                                
Realm can query the Realm Management Monitor for the configuration via RSI call 
(RSI_REALM_CONFIG) and identify the "boundary" of the "IPA" split.              
                                                                                
As far as the hyp/VMM is concerned, there is only one "IPA space" (the lower    
half) of memory map. The "upper half" is "unprotected alias" of the memory map. 
                                                                                
In the guest, this is achieved by "treating the MSB (1 << (IPA_WIDTH - 1))" as  
a protection attribute (PTE_NS_SHARED), where the Realm applies this to any     
address, it thinks is acccessed/managed by host (e.g., MMIO, shared pages).     
Given that this is runtime variable (but fixed for a given Realm), uses a       
variable to track the value.                                                    
                                                                                
All I/O regions are marked as "shared". Care is taken to ensure I/O access (uart)
with MMU off uses the "Unprotected Physical address".                           
                                                                                
                                                                                
Realm IPA State                                                                 
---------------                                                                 
Additionally, each page (4K) in the protected IPA space has a state associated  
(Realm IPA State - RIPAS) with it. It is either of :                            
   RIPAS_EMPTY                                                                  
   RIPAS_RAM                                                                    
                                                                                
Any IPA backed by RAM, must be marked as RIPAS_RAM before an access is made to  
it. The hypervisor/VMM does this for the initial image loaded into the Realm    
memory before the Realm starts execution. Given the kvm-unit-test flat files do 
not contain a metadata header (e.g., like the arm64 Linux kernel Image),        
indicating the "actual image size in memory", the VMM cannot transition the     
area towards the end of the image (e.g., bss, stack) which are accessed very    
early during boot. Thus the early boot assembly code will mark the area upto    
the stack as RAM.                                                               
                                                                                
Once we land in the C code, we mark target relocation area for FDT and          
initrd as RIPAS_RAM. At this point, we can scan the FDT and mark all RAM memory 
blocks as RIPAS_RAM.                                                            
                                                                                
TODO: It would be good to add an image header to the flat files indicating the  
size, which can take the burden off doing the early assembly boot code RSI calls.
                                                                                
Shared Memory support                                                           
---------------------                                                           
Given the "default" memory of a VM is not accessible to host, we add new page   
alloc/free routines for "memory shared" with the host. e.g., GICv3-ITS must use 
shared pages for ITS emulation.                                                 
                                                                                
RSI Test suites                                                                 
--------------                                                                  
There are new testcases added to exercise the RSI interfaces and the RMM flows. 
                                                                                
Attestation and measurement services related RSI tests require parsing tokens   
and claims returned by the RMM. This is achieved with the help of QCBOR library 
[2], which is added as a submodule to the project. We have also added a wrapper 
library - libtokenverifier - around the QCBOR to parse the tokens according to  
the RMM specifications.                                                         
                                                                                
The patches are also available here:                                           
                                                                                
 https://gitlab.arm.com/linux-arm/kvm-unit-tests-cca cca/rfc-v1                     
                                                                                
                                                                                
 [0] https://lore.kernel.org/all/20230127112248.136810-1-suzuki.poulose@arm.com/
 [1] https://lkml.kernel.org/r/20210702163122.96110-1-alexandru.elisei@arm.com  
 [2] https://github.com/laurencelundblade/QCBOR   

Thanks,
Joey

Cc: Alexandru Elisei <alexandru.elisei@arm.com>
Cc: Andrew Jones <andrew.jones@linux.dev>
Cc: Christoffer Dall <christoffer.dall@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Cc: Jean-Philippe Brucker <jean-philippe@linaro.org>
Cc: Joey Gouly <Joey.Gouly@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Quentin Perret <qperret@google.com>
Cc: Steven Price <steven.price@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Thomas Huth <thuth@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Zenghui Yu <yuzenghui@huawei.com>
Cc: linux-coco@lists.linux.dev
Cc: kvmarm@lists.linux.dev
Cc: kvmarm@lists.cs.columbia.edu
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Cc: kvm@vger.kernel.org

Alexandru Elisei (3):
  arm: Expand SMCCC arguments and return values
  arm: selftest: realm: skip pabt test when running in a realm
  NOT-FOR-MERGING: add run-realm-tests

Djordje Kovacevic (1):
  arm: realm: Add tests for in realm SEA

Gareth Stockwell (1):
  arm: realm: add hvc and RSI_HOST_CALL tests

Jean-Philippe Brucker (1):
  arm: Move io_init after vm initialization

Joey Gouly (9):
  lib/string: include stddef.h for size_t
  arm: realm: Add RSI interface header
  arm: Make physical address mask dynamic
  arm: Introduce NS_SHARED PTE attribute
  arm: realm: Make uart available before MMU is enabled
  arm: realm: Realm initialisation
  arm: realm: Add support for changing the state of memory
  arm: realm: Add RSI version test
  lib/alloc_page: Add shared page allocation support

Mate Toth-Pal (2):
  arm: Add a library to verify tokens using the QCBOR library
  arm: realm: Add Realm attestation tests

Subhasish Ghosh (1):
  arm: realm: Add test for FPU/SIMD context save/restore

Suzuki K Poulose (9):
  arm: realm: Set RIPAS state for RAM
  arm: realm: Early memory setup
  arm: gic-v3-its: Use shared pages wherever needed
  arm: realm: Enable memory encryption
  qcbor: Add QCBOR as a submodule
  arm: Add build steps for QCBOR library
  arm: realm: add RSI interface for attestation measurements
  arm: realm: Add helpers to decode RSI return codes
  arm: realm: Add a test for shared memory

 .gitmodules                         |    3 +
 arm/Makefile.arm64                  |   17 +-
 arm/Makefile.common                 |    1 +
 arm/cstart.S                        |   49 +-
 arm/cstart64.S                      |  123 ++-
 arm/realm-attest.c                  | 1125 +++++++++++++++++++++++++++
 arm/realm-fpu.c                     |  242 ++++++
 arm/realm-ns-memory.c               |   86 ++
 arm/realm-rsi.c                     |  157 ++++
 arm/realm-sea.c                     |  143 ++++
 arm/run-realm-tests                 |   56 ++
 arm/selftest.c                      |    9 +-
 arm/unittests.cfg                   |   94 +++
 lib/alloc_page.c                    |   34 +-
 lib/alloc_page.h                    |   24 +
 lib/arm/asm/arm-smccc.h             |   44 ++
 lib/arm/asm/psci.h                  |   13 +-
 lib/arm/asm/rsi.h                   |   16 +
 lib/arm/gic-v3.c                    |    6 +-
 lib/arm/io.c                        |   24 +-
 lib/arm/mmu.c                       |   73 +-
 lib/arm/psci.c                      |   19 +-
 lib/arm/setup.c                     |   17 +-
 lib/arm64/asm/arm-smccc.h           |    6 +
 lib/arm64/asm/io.h                  |    6 +
 lib/arm64/asm/pgtable-hwdef.h       |    6 -
 lib/arm64/asm/pgtable.h             |   20 +
 lib/arm64/asm/processor.h           |    8 +
 lib/arm64/asm/rsi.h                 |   84 ++
 lib/arm64/asm/smc-rsi.h             |  139 ++++
 lib/arm64/gic-v3-its.c              |    6 +-
 lib/arm64/rsi.c                     |  143 ++++
 lib/libcflat.h                      |    1 +
 lib/qcbor                           |    1 +
 lib/string.h                        |    2 +
 lib/token_verifier/attest_defines.h |   50 ++
 lib/token_verifier/token_dumper.c   |  158 ++++
 lib/token_verifier/token_dumper.h   |   15 +
 lib/token_verifier/token_verifier.c |  591 ++++++++++++++
 lib/token_verifier/token_verifier.h |   77 ++
 40 files changed, 3640 insertions(+), 48 deletions(-)
 create mode 100644 .gitmodules
 create mode 100644 arm/realm-attest.c
 create mode 100644 arm/realm-fpu.c
 create mode 100644 arm/realm-ns-memory.c
 create mode 100644 arm/realm-rsi.c
 create mode 100644 arm/realm-sea.c
 create mode 100755 arm/run-realm-tests
 create mode 100644 lib/arm/asm/arm-smccc.h
 create mode 100644 lib/arm/asm/rsi.h
 create mode 100644 lib/arm64/asm/arm-smccc.h
 create mode 100644 lib/arm64/asm/rsi.h
 create mode 100644 lib/arm64/asm/smc-rsi.h
 create mode 100644 lib/arm64/rsi.c
 create mode 160000 lib/qcbor
 create mode 100644 lib/token_verifier/attest_defines.h
 create mode 100644 lib/token_verifier/token_dumper.c
 create mode 100644 lib/token_verifier/token_dumper.h
 create mode 100644 lib/token_verifier/token_verifier.c
 create mode 100644 lib/token_verifier/token_verifier.h

-- 
2.17.1


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

* [RFC kvm-unit-tests 00/27] Support for Arm Confidential Compute Architecture
@ 2023-01-27 11:40   ` Joey Gouly
  0 siblings, 0 replies; 386+ messages in thread
From: Joey Gouly @ 2023-01-27 11:40 UTC (permalink / raw)
  To: Andrew Jones, kvmarm, kvm
  Cc: joey.gouly, Alexandru Elisei, Christoffer Dall, Fuad Tabba,
	Jean-Philippe Brucker, Joey Gouly, Marc Zyngier, Mark Rutland,
	Oliver Upton, Paolo Bonzini, Quentin Perret, Steven Price,
	Suzuki K Poulose, Thomas Huth, Will Deacon, Zenghui Yu,
	linux-coco, kvmarm, linux-arm-kernel, linux-kernel

This series adds support for running the kvm-unit-tests in the Arm CCA reference
software architecture. See more details on Arm CCA and how to build/run the     
entire stack here [0].                                                          
                                                                                
This involves enlightening the boot/setup code with the Realm Service Interface 
(RSI). The series also includes new test cases that exercise the RSI calls.     
                                                                                
Currently we only support "kvmtool" as the VMM for running Realms. There was    
an attempt to add support for running the test scripts using with kvmtool here [1],
which hasn't progressed. It would be good to have that resolved, so that we can 
run all the tests without manually specifying the commandlines for each run.    
For the purposes of running the Realm specific tests, we have added a "temporary"
script "run-realm-tests" until the kvmtool support is added. We do not expect   
this to be merged.                                                              
                                                                                
                                                                                
Base Realm Support                                                              
-------------------                                                             
                                                                                
Realm IPA Space                                                                 
---------------                                                                 
When running on in Realm world, the (Guest) Physical Address - aka Intermediate 
Physical Address (IPA) in Arm terminology - space of the VM is split into two halves,
protected (lower half) and un-protected (upper half). A protected IPA will      
always map pages in the "realm world" and  the contents are not accessible to   
the host. An unprotected IPA on the other hand can be mapped to page in the     
"normal world" and thus shared with the host. All host emulated MMIO ranges must
be in unprotected IPA space.                                                    
                                                                                
Realm can query the Realm Management Monitor for the configuration via RSI call 
(RSI_REALM_CONFIG) and identify the "boundary" of the "IPA" split.              
                                                                                
As far as the hyp/VMM is concerned, there is only one "IPA space" (the lower    
half) of memory map. The "upper half" is "unprotected alias" of the memory map. 
                                                                                
In the guest, this is achieved by "treating the MSB (1 << (IPA_WIDTH - 1))" as  
a protection attribute (PTE_NS_SHARED), where the Realm applies this to any     
address, it thinks is acccessed/managed by host (e.g., MMIO, shared pages).     
Given that this is runtime variable (but fixed for a given Realm), uses a       
variable to track the value.                                                    
                                                                                
All I/O regions are marked as "shared". Care is taken to ensure I/O access (uart)
with MMU off uses the "Unprotected Physical address".                           
                                                                                
                                                                                
Realm IPA State                                                                 
---------------                                                                 
Additionally, each page (4K) in the protected IPA space has a state associated  
(Realm IPA State - RIPAS) with it. It is either of :                            
   RIPAS_EMPTY                                                                  
   RIPAS_RAM                                                                    
                                                                                
Any IPA backed by RAM, must be marked as RIPAS_RAM before an access is made to  
it. The hypervisor/VMM does this for the initial image loaded into the Realm    
memory before the Realm starts execution. Given the kvm-unit-test flat files do 
not contain a metadata header (e.g., like the arm64 Linux kernel Image),        
indicating the "actual image size in memory", the VMM cannot transition the     
area towards the end of the image (e.g., bss, stack) which are accessed very    
early during boot. Thus the early boot assembly code will mark the area upto    
the stack as RAM.                                                               
                                                                                
Once we land in the C code, we mark target relocation area for FDT and          
initrd as RIPAS_RAM. At this point, we can scan the FDT and mark all RAM memory 
blocks as RIPAS_RAM.                                                            
                                                                                
TODO: It would be good to add an image header to the flat files indicating the  
size, which can take the burden off doing the early assembly boot code RSI calls.
                                                                                
Shared Memory support                                                           
---------------------                                                           
Given the "default" memory of a VM is not accessible to host, we add new page   
alloc/free routines for "memory shared" with the host. e.g., GICv3-ITS must use 
shared pages for ITS emulation.                                                 
                                                                                
RSI Test suites                                                                 
--------------                                                                  
There are new testcases added to exercise the RSI interfaces and the RMM flows. 
                                                                                
Attestation and measurement services related RSI tests require parsing tokens   
and claims returned by the RMM. This is achieved with the help of QCBOR library 
[2], which is added as a submodule to the project. We have also added a wrapper 
library - libtokenverifier - around the QCBOR to parse the tokens according to  
the RMM specifications.                                                         
                                                                                
The patches are also available here:                                           
                                                                                
 https://gitlab.arm.com/linux-arm/kvm-unit-tests-cca cca/rfc-v1                     
                                                                                
                                                                                
 [0] https://lore.kernel.org/all/20230127112248.136810-1-suzuki.poulose@arm.com/
 [1] https://lkml.kernel.org/r/20210702163122.96110-1-alexandru.elisei@arm.com  
 [2] https://github.com/laurencelundblade/QCBOR   

Thanks,
Joey

Cc: Alexandru Elisei <alexandru.elisei@arm.com>
Cc: Andrew Jones <andrew.jones@linux.dev>
Cc: Christoffer Dall <christoffer.dall@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Cc: Jean-Philippe Brucker <jean-philippe@linaro.org>
Cc: Joey Gouly <Joey.Gouly@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Quentin Perret <qperret@google.com>
Cc: Steven Price <steven.price@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Thomas Huth <thuth@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Zenghui Yu <yuzenghui@huawei.com>
Cc: linux-coco@lists.linux.dev
Cc: kvmarm@lists.linux.dev
Cc: kvmarm@lists.cs.columbia.edu
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Cc: kvm@vger.kernel.org

Alexandru Elisei (3):
  arm: Expand SMCCC arguments and return values
  arm: selftest: realm: skip pabt test when running in a realm
  NOT-FOR-MERGING: add run-realm-tests

Djordje Kovacevic (1):
  arm: realm: Add tests for in realm SEA

Gareth Stockwell (1):
  arm: realm: add hvc and RSI_HOST_CALL tests

Jean-Philippe Brucker (1):
  arm: Move io_init after vm initialization

Joey Gouly (9):
  lib/string: include stddef.h for size_t
  arm: realm: Add RSI interface header
  arm: Make physical address mask dynamic
  arm: Introduce NS_SHARED PTE attribute
  arm: realm: Make uart available before MMU is enabled
  arm: realm: Realm initialisation
  arm: realm: Add support for changing the state of memory
  arm: realm: Add RSI version test
  lib/alloc_page: Add shared page allocation support

Mate Toth-Pal (2):
  arm: Add a library to verify tokens using the QCBOR library
  arm: realm: Add Realm attestation tests

Subhasish Ghosh (1):
  arm: realm: Add test for FPU/SIMD context save/restore

Suzuki K Poulose (9):
  arm: realm: Set RIPAS state for RAM
  arm: realm: Early memory setup
  arm: gic-v3-its: Use shared pages wherever needed
  arm: realm: Enable memory encryption
  qcbor: Add QCBOR as a submodule
  arm: Add build steps for QCBOR library
  arm: realm: add RSI interface for attestation measurements
  arm: realm: Add helpers to decode RSI return codes
  arm: realm: Add a test for shared memory

 .gitmodules                         |    3 +
 arm/Makefile.arm64                  |   17 +-
 arm/Makefile.common                 |    1 +
 arm/cstart.S                        |   49 +-
 arm/cstart64.S                      |  123 ++-
 arm/realm-attest.c                  | 1125 +++++++++++++++++++++++++++
 arm/realm-fpu.c                     |  242 ++++++
 arm/realm-ns-memory.c               |   86 ++
 arm/realm-rsi.c                     |  157 ++++
 arm/realm-sea.c                     |  143 ++++
 arm/run-realm-tests                 |   56 ++
 arm/selftest.c                      |    9 +-
 arm/unittests.cfg                   |   94 +++
 lib/alloc_page.c                    |   34 +-
 lib/alloc_page.h                    |   24 +
 lib/arm/asm/arm-smccc.h             |   44 ++
 lib/arm/asm/psci.h                  |   13 +-
 lib/arm/asm/rsi.h                   |   16 +
 lib/arm/gic-v3.c                    |    6 +-
 lib/arm/io.c                        |   24 +-
 lib/arm/mmu.c                       |   73 +-
 lib/arm/psci.c                      |   19 +-
 lib/arm/setup.c                     |   17 +-
 lib/arm64/asm/arm-smccc.h           |    6 +
 lib/arm64/asm/io.h                  |    6 +
 lib/arm64/asm/pgtable-hwdef.h       |    6 -
 lib/arm64/asm/pgtable.h             |   20 +
 lib/arm64/asm/processor.h           |    8 +
 lib/arm64/asm/rsi.h                 |   84 ++
 lib/arm64/asm/smc-rsi.h             |  139 ++++
 lib/arm64/gic-v3-its.c              |    6 +-
 lib/arm64/rsi.c                     |  143 ++++
 lib/libcflat.h                      |    1 +
 lib/qcbor                           |    1 +
 lib/string.h                        |    2 +
 lib/token_verifier/attest_defines.h |   50 ++
 lib/token_verifier/token_dumper.c   |  158 ++++
 lib/token_verifier/token_dumper.h   |   15 +
 lib/token_verifier/token_verifier.c |  591 ++++++++++++++
 lib/token_verifier/token_verifier.h |   77 ++
 40 files changed, 3640 insertions(+), 48 deletions(-)
 create mode 100644 .gitmodules
 create mode 100644 arm/realm-attest.c
 create mode 100644 arm/realm-fpu.c
 create mode 100644 arm/realm-ns-memory.c
 create mode 100644 arm/realm-rsi.c
 create mode 100644 arm/realm-sea.c
 create mode 100755 arm/run-realm-tests
 create mode 100644 lib/arm/asm/arm-smccc.h
 create mode 100644 lib/arm/asm/rsi.h
 create mode 100644 lib/arm64/asm/arm-smccc.h
 create mode 100644 lib/arm64/asm/rsi.h
 create mode 100644 lib/arm64/asm/smc-rsi.h
 create mode 100644 lib/arm64/rsi.c
 create mode 160000 lib/qcbor
 create mode 100644 lib/token_verifier/attest_defines.h
 create mode 100644 lib/token_verifier/token_dumper.c
 create mode 100644 lib/token_verifier/token_dumper.h
 create mode 100644 lib/token_verifier/token_verifier.c
 create mode 100644 lib/token_verifier/token_verifier.h

-- 
2.17.1


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

* [RFC kvm-unit-tests 01/27] lib/string: include stddef.h for size_t
  2023-01-27 11:40   ` Joey Gouly
@ 2023-01-27 11:40     ` Joey Gouly
  -1 siblings, 0 replies; 386+ messages in thread
From: Joey Gouly @ 2023-01-27 11:40 UTC (permalink / raw)
  To: Andrew Jones, kvmarm, kvm
  Cc: joey.gouly, Alexandru Elisei, Christoffer Dall, Fuad Tabba,
	Jean-Philippe Brucker, Joey Gouly, Marc Zyngier, Mark Rutland,
	Oliver Upton, Paolo Bonzini, Quentin Perret, Steven Price,
	Suzuki K Poulose, Thomas Huth, Will Deacon, Zenghui Yu,
	linux-coco, kvmarm, linux-arm-kernel, linux-kernel

Don't implicitly rely on this header being included.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
---
 lib/string.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/string.h b/lib/string.h
index b07763ea..758dca8a 100644
--- a/lib/string.h
+++ b/lib/string.h
@@ -7,6 +7,8 @@
 #ifndef _STRING_H_
 #define _STRING_H_
 
+#include <stddef.h>  /* For size_t */
+
 extern size_t strlen(const char *buf);
 extern size_t strnlen(const char *buf, size_t maxlen);
 extern char *strcat(char *dest, const char *src);
-- 
2.17.1


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

* [RFC kvm-unit-tests 01/27] lib/string: include stddef.h for size_t
@ 2023-01-27 11:40     ` Joey Gouly
  0 siblings, 0 replies; 386+ messages in thread
From: Joey Gouly @ 2023-01-27 11:40 UTC (permalink / raw)
  To: Andrew Jones, kvmarm, kvm
  Cc: joey.gouly, Alexandru Elisei, Christoffer Dall, Fuad Tabba,
	Jean-Philippe Brucker, Joey Gouly, Marc Zyngier, Mark Rutland,
	Oliver Upton, Paolo Bonzini, Quentin Perret, Steven Price,
	Suzuki K Poulose, Thomas Huth, Will Deacon, Zenghui Yu,
	linux-coco, kvmarm, linux-arm-kernel, linux-kernel

Don't implicitly rely on this header being included.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
---
 lib/string.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/string.h b/lib/string.h
index b07763ea..758dca8a 100644
--- a/lib/string.h
+++ b/lib/string.h
@@ -7,6 +7,8 @@
 #ifndef _STRING_H_
 #define _STRING_H_
 
+#include <stddef.h>  /* For size_t */
+
 extern size_t strlen(const char *buf);
 extern size_t strnlen(const char *buf, size_t maxlen);
 extern char *strcat(char *dest, const char *src);
-- 
2.17.1


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

* [RFC kvm-unit-tests 02/27] arm: Expand SMCCC arguments and return values
  2023-01-27 11:40   ` Joey Gouly
@ 2023-01-27 11:40     ` Joey Gouly
  -1 siblings, 0 replies; 386+ messages in thread
From: Joey Gouly @ 2023-01-27 11:40 UTC (permalink / raw)
  To: Andrew Jones, kvmarm, kvm
  Cc: joey.gouly, Alexandru Elisei, Christoffer Dall, Fuad Tabba,
	Jean-Philippe Brucker, Joey Gouly, Marc Zyngier, Mark Rutland,
	Oliver Upton, Paolo Bonzini, Quentin Perret, Steven Price,
	Suzuki K Poulose, Thomas Huth, Will Deacon, Zenghui Yu,
	linux-coco, kvmarm, linux-arm-kernel, linux-kernel

From: Alexandru Elisei <alexandru.elisei@arm.com>

PSCI uses the SMC Calling Convention (SMCCC) to communicate with the higher
level software. PSCI uses at most 4 arguments and expend only one return
value. However, SMCCC has provisions for more arguments (upto 17 depending
on the SMCCC version) and upto 10 distinct return values.

We are going to be adding tests that make use of it, so add support for the
extended number of arguments and return values.

Also rename the SMCCC functions to generic, non-PSCI names, so they
can be used for Realm services.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
[ Expand the number of args to 11 /results 10]
Signed-off-by: Joey Gouly <joey.gouly@arm.com>
---
 arm/cstart.S              | 49 ++++++++++++++++++++++++++++------
 arm/cstart64.S            | 55 +++++++++++++++++++++++++++++++++------
 arm/selftest.c            |  2 +-
 lib/arm/asm/arm-smccc.h   | 44 +++++++++++++++++++++++++++++++
 lib/arm/asm/psci.h        | 13 +++++----
 lib/arm/psci.c            | 19 +++++++++++---
 lib/arm64/asm/arm-smccc.h |  6 +++++
 7 files changed, 160 insertions(+), 28 deletions(-)
 create mode 100644 lib/arm/asm/arm-smccc.h
 create mode 100644 lib/arm64/asm/arm-smccc.h

diff --git a/arm/cstart.S b/arm/cstart.S
index 7036e67f..db377668 100644
--- a/arm/cstart.S
+++ b/arm/cstart.S
@@ -96,26 +96,59 @@ start:
 .text
 
 /*
- * psci_invoke_hvc / psci_invoke_smc
+ * arm_smccc_hvc / arm_smccc_smc
  *
  * Inputs:
  *   r0 -- function_id
  *   r1 -- arg0
  *   r2 -- arg1
  *   r3 -- arg2
+ *   [sp] - arg3
+ *   [sp + #4] - arg4
+ *   [sp + #8] - arg5
+ *   [sp + #12] - arg6
+ *   [sp + #16] - arg7
+ *   [sp + #20] - arg8
+ *   [sp + #24] - arg9
+ *   [sp + #28] - arg10
+ *   [sp + #32] - result (as a pointer to a struct smccc_result)
  *
  * Outputs:
  *   r0 -- return code
+ *
+ * If result pointer is not NULL:
+ *   result.r0 -- return code
+ *   result.r1 -- r1
+ *   result.r2 -- r2
+ *   result.r3 -- r3
+ *   result.r4 -- r4
+ *   result.r5 -- r5
+ *   result.r6 -- r6
+ *   result.r7 -- r7
+ *   result.r8 -- r8
+ *   result.r9 -- r9
  */
-.globl psci_invoke_hvc
-psci_invoke_hvc:
-	hvc	#0
+.macro do_smccc_call instr
+	mov	r12, sp
+	push	{r4-r11}
+	ldm	r12, {r4-r11}
+	\instr	#0
+	ldr	r10, [sp, #64]
+	cmp	r10, #0
+	beq	1f
+	stm	r10, {r0-r9}
+1:
+	pop	{r4-r11}
 	mov	pc, lr
+.endm
 
-.globl psci_invoke_smc
-psci_invoke_smc:
-	smc	#0
-	mov	pc, lr
+.globl arm_smccc_hvc
+arm_smccc_hvc:
+	do_smccc_call hvc
+
+.globl arm_smccc_smc
+arm_smccc_smc:
+	do_smccc_call smc
 
 enable_vfp:
 	/* Enable full access to CP10 and CP11: */
diff --git a/arm/cstart64.S b/arm/cstart64.S
index e4ab7d06..b689b132 100644
--- a/arm/cstart64.S
+++ b/arm/cstart64.S
@@ -110,26 +110,65 @@ start:
 .text
 
 /*
- * psci_invoke_hvc / psci_invoke_smc
+ * arm_smccc_hvc / arm_smccc_smc
  *
  * Inputs:
  *   w0 -- function_id
  *   x1 -- arg0
  *   x2 -- arg1
  *   x3 -- arg2
+ *   x4 -- arg3
+ *   x5 -- arg4
+ *   x6 -- arg5
+ *   x7 -- arg