Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Arm CCA guest firmware v3 (RMM-v1.0-rel0) #6480

Open
wants to merge 57 commits into
base: master
Choose a base branch
from

Conversation

samimujawar
Copy link
Contributor

@samimujawar samimujawar commented Nov 27, 2024

Description

This v3 series enables the Arm Confidential Compute Architecture (CCA)
support for the Kvmtool guest firmware and is aligned with the ARM CCA
RMM 1.0-rel0 specification.

In addition to the RMM 1.0-rel0 specification updated this series has
been rebased with the latest edk2 & edk2-platforms codebase and the
intention is to integrate the Arm CCA support in ArmVirtPkg and enable
the guest firmware support for Realms.

Summary of updates in this v3 Series:

  1. Updates to align with RMM 1.0-rel0 specification.
  2. Add support to parse the Kvmtool guest VM Device Tree
    and populate the memory map accordingly.
  3. Check if the MMIO range is for a protected Realm device
    and if so, skip configuring the shared attribute for the
    MMIO region.
  4. Add check to conditionally install the IORT table if
    a GIVc3-ITS is present.

Summary of updates in the previous v2 Series:

  1. Variable emulation support patches that we part of v1 series
    are already merged, hence dropped from this series.
  2. SetMemoryRegionAttributes() was dropped in the upstream
    code. Therefore, introduced SetMemoryProtectionAttribute()
    to configure the top bit of the Realm IPA space which is
    used as the protection bit
  3. The patch to add the APRIORI Dxe ArmCcaDxe has been dropped.
  4. Dropped patch that configured PcdMonitorConduitHvc as a
    dynamic PCD, and introduced ArmVirtMonitorLib, a new
    instance of the ArmMonitorLib that reads the conduit to
    be used from the FDT.
  5. Bug fixes to correct the size of IMM field in RSI Host
    Call arguments, and to correct the RSI Version mask
  6. Patches 32 to 43 include updates to the firmware support
    to RMM specification v1.0-EAC5.
  7. Minor optimisations, e.g. to cache the current world value.

Introduction

Arm Confidential Compute Architecture (CCA)

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

More information on the architecture is available here [1].


        Realm World     ||    Normal World   ||  Secure World  ||
                        ||        |          ||                ||
 EL0 x---------x        || x----x | x------x ||                ||
     | Realm   |        || |    | | |      | ||                ||
     |  VM*    |        || | VM | | |      | ||                ||
     |x-------x|        || |    | | |      | ||                ||
     ||       ||        || |    | | |  H   | ||                ||
     || Guest ||        || |    | | |      | ||                ||
 ----||  OS   ||--------||-|    |---|  o   |-||----------------||
     ||       ||        || |    | | |      | ||                ||
     |x-------x|        || |    | | |  s   | ||                ||
     |    ^    |        || |    | | |      | ||                ||
     |    |    |        || |    | | |  t   | ||                ||
     |+-------+|        || |    | | |      | ||                ||
     || REALM ||        || |    | | |      | ||                ||
     || GUEST ||        || |    | | |  O   | ||                ||
     || UEFI  ||        || |    | | |      | ||                ||
     |+-------+|        || |    | | |  S   | ||                ||
 EL1 x---------x        || x----x | |      | ||                ||
          ^             ||        | |      | ||                ||
          |             ||        | |      | ||                ||
 -------- R*------------||----------|      |-||----------------||
          S             ||          |      | ||                ||
          I             ||      x-->|      | ||                ||
          |             ||      |   |      | ||                ||
          |             ||      |   x------x ||                ||
          |             ||      |       ^    ||                ||
          v             ||     SMC      |    ||                ||
      x-------x         ||      |   x------x ||                ||
      |  RMM* |         ||      |   | HOST | ||                ||
      x-------x         ||      |   | UEFI | ||                ||
          ^             ||      |   x------x ||                ||
 EL2      |             ||      |            ||                ||
          |             ||      |            ||                ||
 =========|=====================|================================
          |                     |
          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 two added additional worlds, "Realm world" and "Root
World" in addition to the traditional Secure world and Normal world.
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 a standard interface Realm Management Interface (RMI)
to the Normal world hypervisor to manage the VMs running in the Realm
world (also called Realms). These are exposed via SMC and are routed
through the EL3 firmware.

The RMM also provides certain services to the Realms via SMC, called
the 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).

This patch series aligns with the RMM v1.0-rel0 specification, and
the latest version is available here [2].

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

Implementation

This version of the Realm Guest UEFI firmware is intended to be
used with the Linux Kernel stack[7] which is also based on the
RMM specification v1.0-rel0[3].

This release includes the following features:
a) Boot a Linux Kernel in a Realm VM using the Realm Guest UEFI
firmware
b) Hardware description is provided using ACPI tables
c) Support for Virtio v1.0
d) All I/O are treated as non-secure/shared
e) Load the Linux Kernel and RootFS from a Virtio attached disk
using the Virtio-1.0 PCIe transport.

Overview of updates for enabling Arm CCA

The Arm CCA implementation is spread across a number of libraries
that provide required functionality during various phases of the
firmware boot.

The following libraries have been provided:
i. ArmCcaInitPeiLib - A library that implements the hook functions
in the PEI phase
ii. ArmCcaLib - A library that implements common functions like
checking if RME extension is implemented and to configure the
Protection attribute for the memory regions
iii. ArmCcaRsiLib - A library that implements the Realm Service
Interface functions.

A NULL implementation of the ArmCcaInitPeiLib and ArmCcaLib is also
provided for platforms that do not implement the RME extensions.

Additionally, the following DXE modules have been provided to implement
the required functionality in the DXE phase.
i. RealmApertureManagementProtocolDxe - A DXE that implements the
Realm Aperture Management Protocol, used to manage the sharing
of buffers in a Realm with the Host
ii. ArmCcaIoMmuDxe - A driver which implements the EDKII_IOMMU_PROTOCOL
that provides the necessary hooks so that DMA operations can be
performed by bouncing buffers using pages shared with the Host.

Arm CCA updates in PEI phase

For supporting Arm CCA two hooks have been added in the PrePi module:
i. An early hook to configure the System Memory as Protected RAM
ii. A second hook after the MMU is initialised to perform the
remaining CCA initialisations like reading the Realm Config
to determine the IPA width of the realm, configuring the
Protection attribute for the MMIO regions, etc.

These hook functions are implemented in ArmCcaInitPeiLib. A NULL
version of the library has also been provided for implementations
that do not have the RME extensions.

Additionally, the ArmVirtMemInfoLib has been updated to implement
a platform specific hook function ArmCcaConfigureMmio() that can
configure the protection attribute for the MMIO regions for the
platform.


   +=====+
   |PrePi|
   +=====+
      |
      _ModuleEntryPoint()
      ===================
              |
              DiscoverDramFromDt()
              |
              +--> ArmCcaInitPeiLib|ArmCcaConfigureSystemMemory()
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                             |      // configure System Memory
              ----------------      // as Protected RAM.
              |
             ...
              |
      --------
      |
      CEntryPoint()
      |
      PrePiMain()
      ===========
          |
         ...
          |
          ProcessLibraryConstructorList()
          |
          MemoryPeim()
          |
          ArmCcaInitPeiLib|ArmCcaInitialize()  // Perform Arm CCA
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // initialisations,
                   |                           // like reading the
                   |                           // Realm Config, etc.
                   |
                   ArmVirtMemInfoLib|ArmCcaConfigureMmio()
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                          |   // Configure Protection attribute
                   --------   // for the MMIO region.
                   |
          ----------
          |
         ...
          |
        +===+
        |DXE|
        +===+

Building the UEFI firmware

a. Set up the development environment
Follow the steps as described in
https://github.com/tianocore/edk2-platforms/blob/master/Platform/ARM/Readme.md

b. The source code for the Host and Realm Guest firmware can
be downloaded from [12].

c. Building the Host UEFI firmware for FVP Base RevC AEM Model
Follow the instructions in
https://github.com/tianocore/edk2-platforms/blob/master/Platform/ARM/Readme.md
to "Build the firmware for Arm FVP Base AEMv8A-AEMv8A model
platform" based on your development environment configuration.

Note: The same firmware binary can be used for both the Arm FVP
Base AEMv8A-AEMv8A and the FVP Base RevC AEM Model.

d. Building the Realm Guest UEFI firmware for kvmtool:
To build the kvmtool guest firmware, run the following commands:

   $build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtKvmTool.dsc -b DEBUG
   $build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtKvmTool.dsc -b RELEASE

The Kvmtool guest firmware binaries are at the following location:

   $WORKSPACE/Build/ArmVirtKvmTool-AARCH64/<DEBUG|RELEASE>_GCC5/FV/KVMTOOL_EFI.fd

Running the stack

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

i. FVP Base AEM RevC model with FEAT_RME support [5]
ii. TF-A firmware for EL3 [6]
iii. TF-A RMM for R-EL2 [4]
iv. Linux Kernel [7]
v. kvmtool [8]
vi. UEFI Firmware for Arm CCA [12].

Instructions for building the remaining firmware components and
running the model are available here [10]. Once, the host kernel
has finished booting, a Realm can be launched by invoking the
lkvm command as follows:

 $ lkvm run --realm \
   --restricted_mem \
   --measurement-algo=["sha256", "sha512"] \
   --firmware KVMTOOL_EFI.fd \
   -m 512 \
   --irqchip=gicv3-its \
   --force-pci \
   --disk <Disk image containing the Guest Kernel & RootFS>
   <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
  • --force-pci is required as only Virtio-v1.0 PCIe transport is
    supported.

Links

[1] Arm CCA Landing page (See Key Resources section for various documentations)
https://www.arm.com/armcca

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

[3] RMM v1.0-rel0 specification
https://developer.arm.com/documentation/den0137/1-0rel0

[4] Trusted Firmware RMM - TF-RMM
https://www.trustedfirmware.org/projects/tf-rmm/
GIT: https://git.trustedfirmware.org/TF-RMM/tf-rmm.git
TAG: rmm-spec-v1.0-rel0

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

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

[7] Linux kernel support for Arm-CCA
https://gitlab.arm.com/linux-arm/linux-cca
Linux Host branch: cca-host/v5
Linux Guest branch: cca-guest/v6
Full stack branch: cca-full/v5+v6

[8] kvmtool support for Arm CCA
https://gitlab.arm.com/linux-arm/kvmtool-cca
Branch: cca/v3

[9] kvm-unit-tests support for Arm CCA
https://gitlab.arm.com/linux-arm/kvm-unit-tests-cca
Branch: cca/v2

[10] 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

[11] RFC series posted previously for adding support for Arm CCA guest firmware:
v2: https://edk2.groups.io/g/devel/message/117716
v1: https://edk2.groups.io/g/devel/message/103581

[12] UEFI Firmware support for Arm CCA
Host & Guest Support:
- Repo:
edk2: https://gitlab.arm.com/linux-arm/edk2-cca
edk2-platforms: https://gitlab.arm.com/linux-arm/edk2-platforms-cca
- Branch: 3223_arm_cca_rmm_v1.0_rel0_v3
- URLs:
edk2: https://gitlab.arm.com/linux-arm/edk2-cca/-/tree/3223_arm_cca_rmm_v1.0_rel0_v3
edk2-platforms: https://gitlab.arm.com/linux-arm/edk2-platforms-cca/-/tree/3223_arm_cca_rmm_v1.0_rel0_v3


  • Breaking change?
    No
  • Impacts security?
    No
  • Includes tests?
    See ‘Running the stack’ section above.

How This Was Tested

See ‘Running the stack’ section above.

Integration Instructions

N/A

Add helper function to check if the Realm Management
Extension (RME) is implemented by the hardware.

Continuous-integration-options: PatchCheck.ignore-multi-package

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Arm CCA requires the software in a Realm to treat the most
significant bit of an IPA as a protection attribute. To
enable/disable sharing of memory regions with the host, the
protection attribute needs to be set/cleared accordingly.

Therefore, introduce SetMemoryProtectionAttribute() so that
the memory regions can be shared/unshared with the host.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The Realm Service Interface (RSI) commands use registers between
X1-X10 as parameters and between X0-X8 as return values for SMC
calls.

According to the SMCCC Section 2.6 SMC32/HVC32 argument passing
  When an SMC32/HVC32 call is made from AArch32:
   - Arguments are passed in registers R1-R7.
   - Results are returned in R0-R7.
  When an SMC32/HVC32 call is made from AArch64:
   - Arguments are passed in registers W1-W7.
   - Results are returned in W0-W7.

According to SMCCC Section 2.7 SMC64/HVC64 argument passing
  When an SMC64/HVC64 call is made from AArch64:
   - Arguments are passed in registers X1-X17.
   - Results are returned in X0-X17.

This means SMC calls can take up to 7/17 arguments and return up
to 7/17 return values.

However, for the current use-case(s):
  - SMC32/HVC32 calls made from AArch32/AArch64 require up to 7
    arguments and 4 return values.
  - SMC64/HVC64 calls made from AArch64 require up to 10 arguments
    and 9 return values.

Therefore, for SMC32/HVC32 calls made from AArch32/AArch64 there is
no update required. However, for AMC64/HVC64 calls made from AArch64,
extend the ArmCallSmc () to use registers X1-X11 as parameters and
return values for SMC call.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The Realm Management Monitor (RMM) is a software component which
forms part of a system which implements the Arm Confidential Compute
Architecture (CCA) and is responsible for management of Realms.
The RMM specification defines a Realm Service Interface (RSI) that
the Guest can use to request services from the RMM.

Therefore, add a library that implements the RSI interfaces to:
  - query the RSI version
  - get the Realm configuration.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The IPA space of a Realm is divided into two halves: Protected IPA space
and Unprotected IPA space. Software in a Realm should treat the most
significant bit of an IPA as a protection attribute. A Protected IPA is
an address in the lower half of a Realm's IPA space. An Unprotected IPA
is an address in the upper half of a Realm's IPA space.

A Protected IPA has an associated Realm IPA state (RIPAS). The RIPAS
values are:
 * EMPTY  - Unused address
 * RAM    - Private code or data owned by the Realm.

Software in the Realm needs to share memory with the host to communicate
with the outside world, e.g. network, disk image, etc.

To share memory, the software in the Realm first transitions the RIPAS
of memory region it wants to share with the host from RAM to EMPTY. The
Realm software can then access the shared memory region using the
Unprotected IPA address.

The RMM specification defines the following Realm Service Interfaces for
managing the IPA state:
 * RSI_IPA_STATE_GET
 * RSI_IPA_STATE_SET

Therefore, update the ArmCcaRsiLib to add interfaces to get and set the
IPA state of Realm memory pages.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
A CCA attestation token is a collection of claims about the state of a
Realm and of the CCA platform on which the Realm is running.
A CCA attestation token consists of two parts:
  * Realm token - Contains attributes of the Realm, including:
    # Realm Initial Measurement
    # Realm Extensible Measurements
  * CCA platform token - Contains attributes of the CCA platform
    on which the Realm is running, including:
    # CCA platform identity
    # CCA platform life cycle state
    # CCA platform software component measurements

The CCA attestation token is used by a verification service to validate
these claims.

The Realm Service Interface defines the following interfaces to retrieve
an attestation token from the Realm Management Monitor (RMM).
  - RSI_ATTESTATION_TOKEN_INIT
  - RSI_ATTESTATION_TOKEN_CONTINUE

Therefore, update the ArmCcaRsiLib to add an interface to get an
attestation token from the RMM.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The Section A2.1.3 Realm attributes, RMM Specification, version A-bet0
introduces the concept of REMs as described below:
  DGRFCS - A Realm Extensible Measurement (REM) is a measurement value
           which can be extended during the lifetime of a Realm.
  IFMPYL - Attributes of a Realm include an array of measurement values.
           The first entry in this array is a RIM. The remaining entries
           in this array are REMs.

The Realm Service Interface commands defined in section
B4.3.7 RSI_MEASUREMENT_READ and B4.3.6 RSI_MEASUREMENT_EXTEND
specify the interfaces to read and extend measurements to REMs.

Therefore, update ArmCcaRsiLib to add interfaces to get and extend REMs.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The Section A4.5 Host call, RMM Specification, version A-bet0
describes the programming model for Realm communication with
the Host and specifies the following:
  DYDJWT - A Host call is a call made by the Realm to the Host, by
           execution of the RSI_HOST_CALL command.
  IXNFKZ - A Host call can be used by a Realm to make a hypercall.
  DYDJWT - A Host call is a call made by the Realm to the Host, by
           execution of the RSI_HOST_CALL command.

Therefore, introduce definition of HOST_CALL_ARGS structure that
represents the arguments to the RSI_HOST_CALL command as defined
in Section B4.3.3 RSI_HOST_CALL command.

Also update the ArmCcaRsiLib library to add a new interface
RsiHostCall () to make a Host call.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The IPA width of a Realm is read from the Realm Config by invoking
the RSI call RSI_REALM_CONFIG to read the Realm Config. The IPA width
is then stored in a GUID HOB gArmCcaIpaWidthGuid for subsequent use.

This GUID HOB is also useful to pass the IPA width of the Realm to the
DXE phase.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add ArmCcaInitPeiLib library that performs the Arm CCA specific
initialisation in the PEI phase like:
 - Configuring the system memory as Protected RAM.
 - Reading the Realm Config and storing the IPA width in
   a GUID HOB i.e., gArmCcaIpaWidthGuid for subsequent use.
 - Calling ArmCcaConfigureMmio () to configure the MMIO regions
   by setting the Unprotected IPA attribute in the page tables.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add a NULL instance of ArmCcaInitPeiLib library that guest firmware
for VMMs that do not implement Arm CCA Realms can use.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Introduce ArmCcaLib library that implements helper
functions to:
- probe if the code is executing in a Realm context
- configure the protection attribute in page tables
  for the memory regions shared with the host
- get the IPA width of the Realm which was stored in
  the GUID HOB gArmCcaIpaWidthGuid.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add a Null instance of ArmCcaLib so that guest firmware that does
not support Arm CCA can link to this Null version of the library.

Also include it in ArmVirt.dsc.inc so that it is linked for the
non-Arm CCA firmware builds.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The IPA space of a Realm is divided into two halves:
  - Protected IPA space and
  - Unprotected IPA space.

Software in a Realm should treat the most significant bit of an
IPA as a protection attribute.

The Unprotected IPA space is used for sharing memory and for performing
MMIO accesses with the Host.

An Unprotected IPA is an address in the upper half of a Realm's
IPA space. The most significant bit of an Unprotected IPA is 1.

Therefore, the page tables for the MMIO regions must be updated to set
the most significant bit of the IPA space.

To facilitate this define ArmCcaConfigureMmio () that can be called
during the early firmware startup.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
To support Arm CCA, a hook function ArmCcaConfigureMmio () has
been added to the ArmVirtMemInfoLib library.

Since, Arm CCA has not been enabled for the Cloud Hypervisor guest
firmware, update the CloudHvVirtMemInfoLib library to add a NULL
implementation for ArmCcaConfigureMmio () that returns
RETURN_UNSUPPORTED.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
To support Arm CCA, a hook function ArmCcaConfigureMmio () has
been added to the ArmVirtMemInfoLib library.

Since, Arm CCA has not been enabled for the Qemu guest firmware,
update the QemuVirtMemInfoLib library to add a NULL implementation
for ArmCcaConfigureMmio () that returns RETURN_UNSUPPORTED.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
To support Arm CCA, a hook function ArmCcaConfigureMmio () has
been added to the ArmVirtMemInfoLib library.

Since, Arm CCA has not been enabled for the Xen guest firmware,
update the XenVirtMemInfoLib library to add a NULL implementation
for ArmCcaConfigureMmio () that returns RETURN_UNSUPPORTED.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The IPA space of a Realm is divided into two halves:
  - Protected IPA space and
  - Unprotected IPA space.

Software in a Realm should treat the most significant bit of an
IPA as a protection attribute.

The Unprotected IPA space is used for sharing memory and for performing
MMIO accesses with the Host.

An Unprotected IPA is an address in the upper half of a Realm's
IPA space. The most significant bit of an Unprotected IPA is 1.

The page tables for the MMIO regions must be updated to set the most
significant bit of the IPA space.

Therefore, implement ArmCcaConfigureMmio () which configures the MMIO
regions as Unprotected IPA by setting the protection attribute in the
page tables for the MMIO regions.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The patch at "6c8a08bd8a680 ArmVirtPkg/PrePi: Ensure timely
 execution of library constructors" moved the processing of
library constructors before the MMU is initialised.

This resulted in the BaseDebugLibSerialPort library constructor
BaseDebugLibSerialPortConstructor () which initialises the serial
port, being invoked before the MMU is enabled.

However, the Realm Code requires the protection attribute of
the MMIO regions to be configured as unprotected (shared with
the host), which requires the MMU to be enabled. Otherwise,
accesses to the MMIO region result in a synchronous external
abort being reflected to the Realm by the RMM.

Therefore, link the Null version of DebugLib in PrePi stage.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The following libraries have been introduced for Arm CCA:
 * ArmCcaInitPeiLib - provides functions for ARM CCA
                      initialisations in early PEI phase.
 * ArmCcaLib        - provides the necessary helper functions
                      for Arm CCA
 * ArmCcaRsiLib     - implements functions to call the Realm
                      Service Interface.

Therefore, add these libraries in the Kvmtool guest firmware
workspace as part of enabling support for Arm CCA.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
When a VMM creates a Realm, a small amount of DRAM (which contains
the firmware image) and the initial content is configured as Protected
RAM. The remaining System Memory is in the Protected Empty state. The
firmware must then initialise the remaining System Memory as Protected
RAM before it can be accessed.

Therefore, call the ArmCcaConfigureSystemMemory () in the early Pei
phase so that the System Memory is configured as Protected RAM.

Note: ArmCcaConfigureSystemMemory () is implemented in ArmCcaInitPeiLib
for which a Null implementation is provided. Therefore, this change
should not have an impact for non-Arm CCA enabled systems.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add ArmCcaInitialize () to perform Arm CCA specific initialisation
like:
 - Reading the Realm Config by calling the RSI interface.
 - Storing the IPA width of the Realm in PcdArmCcaEarlyIpaWidth.
 - Configuring the MMIO regions to update the page tables to set
   the protection attribute as Unprotected IPA.

Note: ArmCcaInitialize () is implemented in ArmCcaInitPeiLib for
which a Null implementation is provided. Therefore, this change
should not break existing platforms that do not implement the
Arm CCA.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The Realm Aperture Management Protocol (RAMP) is used to manage
the sharing of buffers between the Guest and Host. It configures
the memory regions as Protected EMPTY or Protected RAM by calling
RSI_IPA_STATE_SET command. The RAMP provides interfaces that device
drivers can use to open/close apertures for sharing buffers.

The RAMP also keeps track of the apertures that have been opened
and closes them on ExitBootServices. It also registers for reset
notification and closes all open apertures before the platform
resets the system.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
On Arm CCA systems the access to pages inside the Realm is protected.

However, software executing in a Realm needs to interact with the
external world. This may be done using para virtualisation of the
disk, network interfaces, etc. For this to work the buffers in the
Realm need to be shared with the Host. The sharing and management
of the Realm buffers is done by the Realm Aperture Management
Protocol, which invokes the necessary Realm Service Interfaces
to transition the buffers from Protected IPA to Unprotected IPA.

The ArmCcaIoMmu driver provides the necessary hooks so that DMA
operations can be performed by bouncing buffers using pages shared
with the Host. It uses the Realm Aperture Management protocol to
share the buffers with the Host.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Arm CCA Realms protect the access to memory from outside the
Realm. For Virtio to work the Realm Guest and the Host should
be able to share buffers.

Realm Aperture Management protocol (RAMP) manages the sharing
of buffers between the Realm Guest and the Host, while the
ArmCcaIoMmuDxe implements the EDKII_IOMMU_PROTOCOL which
provides the necessary hooks so that DMA accesses can be
performed by bouncing buffers using pages shared with the
host.

Therefore, enable the support for Realm Aperture Management
Protocol and ArmCcaIoMmuDxe for Kvmtool Guest firmware.

Note: The ArmCcaIoMmuDxe and RAMP check if the code is executing
in a Realm before installing the respective protocols. If the
code is not executing in a Realm the gIoMmuAbsentProtocolGuid is
installed, thereby allowing the same firmware to be used both for
normal and Realm Guest firmware.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The BaseRngLib library constructor for AArch64 used to asserts
if the RNDR instruction is not supported by the CPU, until the
patch "4ddf2448ed3a MdePkg/BaseRngLib AARCH64: Remove
overzealous ASSERT()"

It would however be useful to have a warning message that is
printed in the debug builds. Therefore, add a warning message
to print if RNDR instruction is not supported by the processor.

Also modify the computation of mRndrSupported value to be
similar to the rest of the edk2 codebase.

Note:
 - If RNDR instruction is not supported, the GetRandomNumberXXX
   functions will return FALSE to indicate that the random number
   generation has failed. It is expected that the calling function
   checks the status and handles this error appropriately.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Cc: Michael D Kinney <[email protected]>
Cc: Liming Gao <[email protected]>
Cc: Zhiguang Liu <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The kvmtool guest firmware is using the default RNG library
defined in ArmVirtPkg.dsc.inc which is BaseRngLibTimerLib.

BaseRngLibTimerLib is only present to use for test purposes on
platforms that do not have a suitable RNG source and must not be
used for production purposes.

Armv8.5 introduces random number instructions (e.g., RNDR) which
return a 64-bit random number. Although, this feature is optional,
it can be assumed that most modern platforms will implement this
support. This feature i.e. FEAT_RNG can be discovered by examining
the processor feature registers.

It is therefore desirable to use the RNDR instructions instead of
using the default BaseRngLibTimerLib which is unsafe.

The BaseRngLib in MdePkg already implements the RNG support using
RNDR. However, it is worth noting that FEAT_RNG is supported in
AArch64 state only. Therefore, switch to using the BaseRngLib
instance for AArch64 firmware builds. The AArch32 firmware builds
will continue to use BaseRngLibTimerLib.

Note: The guest firmware already supports Virtio RNG. So, should
the processor not implement FEAT_RNG, the guest firmware can fall
back to use Virtio RNG.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The RsiInterfaceVersion fieldset contains an RSI interface
version and the width of this fieldset is 64 bits.

The bits 15:0 of this fieldset represent the RSI minor
revision number and the bits 30:16 represent the major
revision number. The remaining bits 63:31 are reserved
and should be zero.

The RSI version masks were incorrectly defined which
resulted in an incorrect RSI version being returned
by RsiGetVersion (). Therefore, fix the RSI version
masks to reflect the bit fields defined by the RMM
specification.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The section B4.4.2 'RsiHostCall type' of the RMM specification
version A-bet0 specifies the Imm field in HostCallArgs structure
as a 16 bit wide value and the offset for the gprs[0] field is
0x8, which means the 6 bytes after the Imm field are padded.

Therefore, define the Imm field as UINT16 and add an additional
field UINT8 Reserved1[6] for padding.

Also update the RsiHostCall() to initialise the Reserved1 field
to zero.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The RMM 1.0-bet1 updates the width of the RsiHostCall
structure to 256 (0x100) bytes.

Therefore, update the RSI HOST_CALL_ARGS structure to reflect
these changes.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
@samimujawar samimujawar force-pushed the 3223_arm_cca_rmm_v1.0_rel0_v3 branch from a51539a to 0dca561 Compare November 27, 2024 17:32
The RMM 1.0-eac3 specification removed the restriction that
attestation token size must not exceed 4KB. Further it also
extended the RSI_ATTESTATION_TOKEN_CONTINUE command so as to
return up to a granule worth of the attestation token data.

The RMM 1.0-eac5 specification simplified the attestation
token interfaces such that, the RSI_ATTESTATION_TOKEN_INIT
command returns the upper bound of the attestation token
size. This eliminates the need for relocation of token data
buffers during attestation token retrieval.

Therefore, implement the attestation token API updates
from RMM 1.0-eac3 through to RMM 1.0-eac5 specification.

Note: The RsiGetAttestationToken() API has been modified
such that ArmCcaRsiLib allocates memory for the returned
attestation token buffer. The caller is therefore required
to call RsiFreeAttestationToken() to free the memory that
was allocated for the attestation token buffer.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The RMM 1.0-eac5 specification updates the RSI version command
to return the highest interface revision which is supported by
the RMM and the lower revision value which indicates:
  a. The RMM supports an interface revision which is compatible
     with the requested revision and the lower revision is equal
     to the requested revision and the status code is RSI_SUCCESS
  b. The RMM does not support the requested version, but the RMM
     supports an interface revision which is lower than the
     requested revision and the status code is RSI_ERROR_INPUT
  c. The RMM does not support an interface revision which is
     compatible with the requested revision and that it supports
     an interface revision that is greater than the requested
     revision. The status code is RSI_ERROR_INPUT and the lower
     revision is equal to the higher revision.

Therefore, update the RsiGetVersion() to return the lower and
higher revision that is supported by the RMM. The RsiGetVersion
function also returns the RSI version that is implemented by
the firmware.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
IsRealm() probes to check if the code is executing
in a Realm context by checking if RME is supported
and then issuing a RSI_VERSION command to check it
is supported.

Instead of calling RSI_VERSION command every time the
IsRealm() is called, cache the world value we are
running in, to return the value in subsequent calls.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The patch at "049695a0b1e2 MdeModulePkg/PciBusDxe: Add feedback
status for PciIoMap" adds support to propagate the error code
following the invocation of the IoMmu protocol SetAttribute()
operation.

Since the ArmCcaIoMmuDxe implementation of the SetAttribute()
function returned EFI_UNSUPPORTED, it resulted in the virtio
disk not being mounted.

Although there is nothing to be done in SetAttribute(), follow
the approach as done by the patch at "97c3f5b8d272  Provide an
implementation for SetAttribute" to validate the IoMmu access
method being requested against the IoMmu mapping operation and
return a suitable return code.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The section A5.2.2 'Realm IPA state' in the RMM 1.0-rel0 spec
introduces a new Realm IPA state value to represent address
where memory of an assigned Realm device is mapped.

Therefore, update the RIPAS enum to add RipasDev.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The section B5.3.5 'RSI_IPA_STATE_GET command' of the RMM 1.0-rel0
specification extends the RSI_IPA_STATE_GET command to take the
End of the target IPA region as input in addition to the Base of
the IPA region, and returns the Top of IPA region which has the
reported RIPAS value.

Therefore, update the RsiGetIpaState() to reflect the addition
of this IPA range parameter.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The RMM 1.0-rel0 specification updates the RealmConfig
to add a Realm Personalisation Value (RPV), which is
a 64 byte string that can be used to differentiate or
identify a Realm. The RPV value is provided as an input
parameter to the VMM when launching a Realm.

Therefore, update the RealmConfig structure to add a
new field for the RPV. Also add some helper macros
for defining the RealmConfig structure.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The RMM 1.0-rel0 specification introduced a new error code to
indicate that the attestation token generation failed for an
unknown or IMPDEF reason.

Therefore, define the new error code and update the code to
handle the error accordingly.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Introduce an Arm platform device info library that
parses the FDT and extracts the MMIO base address
and the range for the devices present in the FDT.

This is useful for populating the memory map for a
platform. e.g. the Kvmtool memory map is currently
configured such that the address range outside the
DRAM range is considered as peripheral memory.
Although this currently works, starting with the
RMM 1.0 - rel0 specification, it is expected
that the firmware queries the RMM to get the IPA
state for the MMIO address ranges for the devices
to determine if the shared attribute must be set.
If the IPA state is returned as RIPAS device,
the shared attribute must not be set for the
device. Otherwise the shared attribute needs to be
set for the MMIO address range covering the device
as it is emulated by the VMM.

The files in this library are a scaled down version
of the DynamicTablesPkg/Library/FdtHwInfoParserLib
wherein the parsers only parse the device MMIO base
addresses and range. The functionality to parse
other device information e.g. interrupts, etc.
and to populate the Configuration Manager objects
has been removed.

In this patch the initial infrastructure for parsing
the FDT and populating the PLATFROM_DEVICE_INFO
structure is implemented. Subsequent patches shall
introduce the functionality to parse the device
information.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add functionality to parse the GIC objects from the
FDT and populate the PLATFORM_DEVICE_INFO structure.

This patch adds functionality to parse the following
GIC components and populate their base address and
range in the PLATFORM_DEVICE_INFO structure.
 - GICC
 - GICD
 - GICR

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add functionality to parse the PCI components from the
FDT and populate the PLATFORM_DEVICE_INFO structure.

This patch adds functionality to parse the following
PCI components and populates their base address and
range in the PLATFORM_DEVICE_INFO structure.
 - PCI Configuration Space
 - PCI I/O Space
 - PCI 32bit Mem
 - PCI 64bit Mem

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add functionality to parse the FDT for the MMIO base address
and range using the compatibility string provided for a device
and populate the PLATFORM_DEVICE_INFO structure.

This common parsing functionality can then be used to extract
information from devices that follow the generic device register
representation scheme.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add functionality to parse the Serial port information from
the FDT using the previously introduced generic device parser
and populate the PLATFORM_DEVICE_INFO structure.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Add functionality to parse the Real Time Clock (RTC) info
from the FDT using the previously introduced generic device
parser and populate the PLATFORM_DEVICE_INFO structure.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
The memory map for the peripherals available for a Guest VM
launched using Kvmtool is currently populated by treating
all the memory before and after the System DRAM as device
memory.

With the introduction of ArmPlatfromDeviceInfoLib it is
now possible to get the MMIO base address and range for
the devices that are present in the FDT.

Therefore, use the ArmPlatfromDeviceInfoLib to get the
PLATFROM_DEVICE_INFO and populate the mem map accordingly.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Realm Devices are protected devices and are not emulated by
the VMM. The RIPAS value for the MMIO address range for these
devices is RipasDev indicating the address range is protected
MMIO.

Therefore, introduce an helper function to check if the MMIO
address range is protected MMIO by issuing RSI_IPA_STATE_GET
commands.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
Realm Devices are protected devices and are not emulated by
the VMM. The protection attribute for the MMIO regions
covered by these devices must not be set as Unprotected IPA.

Therefore, call the ArmCcaLib ArmCcaMemRangeIsProtectedMmio()
helper function passing in the MMIO base address and range,
to check if the address range is marked as RIPAS_DEV (which
indicates a Realm Device).

The ArmCcaConfigureMmio() then excludes the MMIO address
range for the Realm Devices from being configured as
Unprotected IPA.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
When the Kvmtool guest is launched without ITS support
i.e. when --irq-chip=gicv3-its option is not specified
or if --irq-chip=gicv3 is specified, the guest VM does
not have an ITS.

In such scenarios the guest firmware must not install
the IORT table. Therefore, add checks to see if ITS is
present before installing the IORT ACPI table.

Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Sami Mujawar <[email protected]>
@samimujawar samimujawar force-pushed the 3223_arm_cca_rmm_v1.0_rel0_v3 branch from 0dca561 to 535c33f Compare November 27, 2024 18:47
@samimujawar samimujawar marked this pull request as ready for review November 28, 2024 14:03
@samimujawar samimujawar changed the title 3223 arm cca rmm v1.0 rel0 v3 Support for Arm CCA guest firmware v3 (RMM-v1.0-rel0) Nov 28, 2024
@@ -90,6 +90,7 @@
[LibraryClasses.AARCH64]
ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf
ArmCcaRsiLib|ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf
RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DXE ArmVirt already uses RNDR if available, via DxeRngLib -> EFI_RNG_PROTOCOL -> RngDxe -> BaseRngLib.inf

Using BaseRngLib.inf unconditionally isn't a good idea I think. There is too much hardware in the wild which has no RNDR support.

@@ -28,6 +28,8 @@
HwInfoParser/FdtInfoParser.h
HwInfoParser/FdtUtility.c
HwInfoParser/FdtUtility.h
HwInfoParser/Pci/PciConfigSpaceParser.c
HwInfoParser/Pci/PciConfigSpaceParser.h
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this in the Arm CCA PR? On a quick glance this looks like some independent change.

Also why put this into ArmVirt? We have other platforms like riscv which use device trees too and can probably use this code too, so I think OvmfPkg would be a better place for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Gerd,

Thank you for reviewing the patch series and for the feedback.

Why is this in the Arm CCA PR? On a quick glance this looks like some independent change.

Yes, I agree this is an independent change and is a general improvement for normal VMs as well. However, this was introduced as this a requirement for a Realm VM, please see
43476c3 and therefore submitted along with this series.
However, please do let me know if you think I should submit this as a separate patch.

Also why put this into ArmVirt? We have other platforms like riscv which use device trees too and can probably use this code too, so I think OvmfPkg would be a better place for it.

I agree this can be utilised by other architectures as well and it can be moved to OvmfPkg. However, I think there may be some additional changes required for supporting other architectures, e.g. there is a pending series that should help pave the way for this change, see a1f2654

Since this patch is a subset of the FdtHwInfoParser, I think similar changes would apply here as well. Considering that, I think it would be good to pursue this effort once the RiscV support is enabled in Dynamic Tables.

Please do let me know if you think otherwise, and I will update this PR accordingly.

Regards,

Sami Mujawar

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Phew. Is there some overview how the hardware detection works in for Realm VMs? Apparently this is different from the usual qemu workflow, where qemu generates both FDT and ACPI tables, the guest firmware simply downloads them via FwCfg and installs them in guest memory.

So Realm VMs get a FDT only apparently (where does it come from?), then use DynamicTablesPkg to generate the ACPI tables inside the guest, correct? Where exactly in this workflow is this change needed? Parse the FDT and generate descriptions tables which DynamicTablesPkg can consume?

On riscv: Yes, sure, additinal changes will be needed to have the riscv firmware actually use this (and this is obviously beyond the scope of this PR).. But if this is something which is likely to happen we should merge the code into OvmfPkg right away instead of merging to ArmVirt and move over to OvmfPkg later on.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the ACPI table generation is specific to the ArmVirtKvmTool. If I remember correctly, ArmVirtQemu and ArmVirtCloudHv don't have it, so it's not (yet) a property of Realm VMs, only Kvmtool VMs. At the moment in my experimental Realm support for ArmVirtQemu, QEMU still generates ACPI tables in addition to FDT (though I haven't tested ACPI boot).

There is a larger question of whether we should create a single edk2 image for all Realm VMs, based on ArmVirtKvmtool but supporting QEMU, cloud-hypervisor and others. Given that Realm VMs have specific needs (initialization through RMM RSI, early attestation, lack of NV storage, reduced attack surface...) it would be nice to have all those things in a single image rather than porting them to each existing ArmVirt*. I've been meaning to investigate this but haven't found the time.

Having FDT->ACPI generation on this single image could also be useful for attestation. Given that firmware tables are measured (to ensure the untrusted host does not include harmful data in them), a verifier needs to be able to independently reconstruct the firmware tables, and it would reduce the efforts needed by verifiers to only measure one set of firmware tables rather than both FDT and ACPI. In QEMU the FDT is placed in memory, and ACPI tables are sent via FwCfg (whose address is found in the FDT). I believe CloudHV places both in memory and the project doesn't want to implement FwCfg.

This would require FDT to be able to represent everything ACPI can (at least for arm64 VMs), and some things may be missing. vCPU hotplug is a recent feature on Arm and I believe still requires ACPI at the moment. There might be others.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the reasons qemu generates ACPI tables for the guest is to decouple firmware and qemu, i.e. qemu can add new features which require ACPI table updates without depending on firmware updates.

This might be less of a concern for Realm VMs. I'm wondering whenever it is actually possible to support cpu hotplug (or memory hotplug) for Realm VMs, and there are probably more features which are not useful for CC guests.

So the idea to have a single Realm VM firmware image and have the image generate ACPI tables from FDT looks workable to me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While being at it: Setting PcdConfidentialComputingGuestAttr probably makes sense.

@lgao4
Copy link
Contributor

lgao4 commented Dec 6, 2024

The change in MdePkg is OK to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants