Skip to content

Add CCA Realm support to ArmVirtQemu#518

Open
jpbrucker wants to merge 78 commits intotianocore:arm-ccafrom
jpbrucker:arm-cca
Open

Add CCA Realm support to ArmVirtQemu#518
jpbrucker wants to merge 78 commits intotianocore:arm-ccafrom
jpbrucker:arm-cca

Conversation

@jpbrucker
Copy link
Copy Markdown

These patches add support for ArmVirtQemu to be run in a Realm guest. A lot of it is just plumbing to use the Arm CCA libraries, for example to create DMA mappings in the shared IPA region. We also need to create a mapping to access the shared UART early, enabled emulated variable storage, and measure blobs loaded via fw_cfg.

Long term it would be good to create a single EDK2 platform for Realms rather than one per VMM, for a number of reasons:

  • Confidential computing requires extra support in the firmware, as highlighted by this series. Although I'm working on cloud-hypervisor support for CCA I haven't yet had time to do ArmVirtCloudHv.
  • For attestation the firmware must be measured. Verifiers would be provisioned with a single firmware image rather than one for each platform.
  • An image with a minimal set of features (for example no networking) would considerably reduce the attack surface of the TCB.
  • For attestation the firmware tables, ACPI and DTB, must be measured. To simplify the provisioning required for this, it would be nice to only provision DTBs and have the FW generate ACPI tables like ArmVirtKvmtool does. The number of variations for firmware tables is likely to be quite high.
  • We would have the opportunity to implement a common mechanism for direct kernel boot.

Although I started working on this, it's unlikely I will have time to complete anytime soon. Adding CCA support to ArmVirtQemu is easier for now.

Arm Confidential Compute Architecture (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.

The 'Realm Guest firmware' is an important part
of the Arm CCA reference software stack.

Support for Realm Guest firmware is not yet merged
in the edk2 mainline and a PR to add initial support
for Arm CCA guest firmware is in review at:
  tianocore/edk2#6480

A staging branch would allow more flexibility for
integration and the review process without
breaking/impacting the edk2 mainline.

This branch will:
 - be used as an integration branch until the PRs
   have been satisfactorily reviewed for merging
   in edk2 mainline
 - provide a central location for developers to
   utilise the latest Realm Guest firmware code
   for testing, and reporting issues
 - serve as a baseline for developers to add new
   features
 - Remove the necessity of maintaining downstream
   forks.

The description is in the Readme.md file.

Please create the following branch:
  1. edk2-staging Repo
     URL: https://github.com/tianocore/edk2-staging.git
     Branch Name: arm-cca

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
The PrePiMemoryAllocationLib supports AllocateAlignedPages(),
however is missing the corresponding FreeAlignedPages().

Although the FreeAlignedPages() in PrePiMemoryAllocationLib
does not support the ability to free pages in the PrePei Memory
Allocator and the allocated memory is lost, it would be good
to have an empty implementation of FreeAlignedPages() so that
implementations utilises the correct deallocation function.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Add a NULL instance of ArmCcaInitPeiLib library that guest firmware
for VMMs that do not implement Arm CCA Realms can use.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
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 <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
The RMM 1.0-bet2 spec expands the set of GPRs for RSI host call
to X0-X30.

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

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
The RMM 1.0-eac0 specification updates the parameter usage for the
RSI_IPA_STATE_SET command to change the parameter 3 from IPA region
size to Top of target IPA region.

Therefore, update the RseSetIpaState () implementation to reflect
this change.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Jean-Philippe Brucker added 7 commits July 1, 2025 13:57
Add QemuPlatformDxe which installs the Variable store emulation when a
Flash device is not available.

Link NorFlashQemuLib as a NULL library so that it can setup
PcdEmuVariableNvModeEnable.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
When code in .text uses adrp to obtain an address from .data, if the
sections don't have the same alignment modulo 4KB, GenFw fails with:

  WriteSections64(): Build/ArmVirtQemu-AARCH64/RELEASE_GCC5/AARCH64/ArmPlatformPkg/Sec/Sec/DEBUG/Sec.dll AARCH64 small code model requires identical ELF and PE/COFF section offsets modulo 4 KB.

Since we will need to move ID-map to .data and introduce a writable
buffer for CCA, define the section alignment to 4kB.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
As we're about to introduce more identity mappings into IdMap.S,
introduce a macro that create identity PTEs, to make the page table code
more readable.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
…ART idmap

In a realm, we'll need to patch the early page tables to access the
emulated uart through the unprotected IPA range. Add a third level table
for the VA range which contains the UART.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
A Realm needs to access emulated devices via the unprotected IPA range
(upper IPA bit set). After probing the RMM using some RSI calls, update
the page table entry that maps the UART.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Pull in the Arm CCA libraries needed for discovering the address space
width and sharing DMA memory with the VMM.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
When creating the identity mapping, copy the 'unprotected' top bit from
the physical address as an attribute in the PTE. The virtual address
then points to the top half of the address space, which in a Realm is
the unprotected half, shared with the host.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Jean-Philippe Brucker added 12 commits October 7, 2025 11:20
…r CCA

A Realm guest needs to access peripherals emulated with the host with
the 'unprotected' bit set (most significant bit of the Intermediate
Physical Address). Initialize the page tables with all device mappings.

When launching QEMU with more than 254M of potential RAM, the high PCIe
regions are shifted to make space for RAM. Find their location in the
device tree.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>

QemuVirtMemInfoLib: Parse device-tree to find the PCIe registers

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
To ensure I/O buffers are shared with the host, add those libs

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Add a small module that calls ArmCcaInitPeiLib function to initialize
the Realm address space.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Before MMU initialization, call the ArmCcaInitPei function to detect
whether we're in a Realm, and provide the IPA width which is needed to
setup device mappings.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
…tributes

An 'unprotected' bit set by ArmCcaConfigureMmio() may get cleared later
by ArmSetMemoryAttributes(). For example the PCIe ECAM region on QEMU is
mapped late by MapGcdMmioSpace(). Ensure the 'unprotected' bit does not
get cleared.

Note that we should probably consolidate this: ArmCcaConfigureMmio()
initializes those page table entries as valid even though they don't
have the correct memory attributes yet.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
The ArmCcaIoMmuDxe driver depends on gEfiRealmApertureManagementProtocolGuid,
and produces either gEdkiiIoMmuProtocolGuid or gIoMmuAbsentProtocolGuid.
Other drivers, for example those including QemuFwCfgLibMmio, thus depend
on either the IOMMU or IOMMU Absent protocol.

Since ArmCcaIoMmuDxe only produces gEfiRealmApertureManagementProtocolGuid
when in a Realm at the moment, those drivers cannot be loaded when not
in a Realm, and boot doesn't reach BDS. Add an empty instance of
gEfiRealmApertureManagementProtocolGuid so that ArmCcaIoMmuDxe always
produces something and unblocks other drivers.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Dhanus M Lal <Dhanus.MLal@fujitsu.com>
Add a NULL library for non-x86 platforms that need the IoMmuDxe driver
without SEV and TDX.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
As the ArmVirtQemu platforms are getting support for confidential
computing, they needs to start supporting IOMMU protocols that share and
unshare DMA buffers with the host. This means we'll need to ensure
that the driver that provides the IOMMU protocol and client drivers
that perform DMA are loaded in the right order. For instance QemuFwCfgLibMmio
needs new Depex entries so that drivers including this library are
loaded after either gEdkiiIoMmuProtocolGuid or gIoMmuAbsentProtocolGuid
get produced.

Since RiscVVirtQemu uses QemuFwCfgLibMmio, it now needs something that
produces gIoMmuAbsentProtocolGuid. Include IoMmuDxe for this purpose.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
---
Only build-tested
When running in a realm, we must explicitly share DMA buffers with the
host. Use the IoMmuProtocol when available.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
The ArmVirtQemu guest firmware loads the kernel and initrd images from
the host through the FwCfg device. When running in a realm, measure
those images and add them to the realm measurement, so that the realm
owner can later authenticate them.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Use the Arm CCA BlobVerifier to add hashes of FwCfg images to the realm
measurement.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
When run early in the QEMU boot, writing the static variable
FlagsInitialised causes a Synchronous Exception. Supposedly the data
page containing the static variable isn't mapped writable at this point,
but I didn't investigate further. Use a GUID HOB to cache the variable.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
@jpbrucker
Copy link
Copy Markdown
Author

This latest version adds support for VMs with more than 254G of RAM, where the shared PCIe MMIO region is shifted and needs to be found in device tree.

@samimujawar
Copy link
Copy Markdown

Summary

PR #518 currently breaks the Kvmtool guest firmware. The issue appears to be caused by:
d2a4d7d – ArmVirtPkg/ArmCcaLib: Use GUID HOB to cache IsRealm value
To address this, I have:

  1. Rebased the Kvmtool guest patch series (edk2-staging/arm-cca branch) with the latest edk2 mainline.
  2. Made several cleanups and improvements to the Kvmtool guest firmware (detailed below).
  3. Reworked the caching mechanism for both the IsRealm value and the IPA width.
  4. Cherry-picked the relevant patches from PR Add CCA Realm support to ArmVirtQemu #518 and resolved merge conflicts, ensuring the firmware builds successfully.
  • Testing has been performed only on the Kvmtool guest firmware.
  • I would appreciate it if someone could test the ArmVirtQemu firmware and report any issues (and ideally propose fixes).

To facilitate broader testing and alignment, I have integrated the PR #518 changes into the edk2-staging/arm-cca branch.

Changes in the Kvmtool Guest firmware series.

  1. Patch cherry-picked from PR Add CCA Realm support to ArmVirtQemu #518
    344b457 <Jean-Phili..> ArmPkg/ArmMmuLib: Handle Realm unprotected bit

  2. Dropped patch [2/57] as it is no longer needed.
    0a993a3 EmbeddedPkg: Add missing FreeAlignedPages() implementation

  3. Rebased and updated patch [4/57] to preserve the Arm CCA Protection attribute and renamed
    the function to set the protection attribute to ArmCcaSetmemoryProtectionAttribute()
    213d7a8 ArmPkg: Introduce SetMemoryProtectionAttribute() for Realms
    Similarly, the subject line for the patch was also modified to reflect the API name change
    and the fact that the ArmMmuLib was moved to UefiCpuPkg
    1923bf9 UefiCpuPkg/ArmMmuLib: Introduce ArmCcaSetMemoryProtectionAttribute()

  4. Dropped patch [10/57]
    8fb3e62 ArmVirtPkg: Define a GUID HOB for IPA width of a Realm
    and replaced it with patch no 33 in the new series
    0319921 ArmVirtPkg: Add GUID HOBs to cache Realm IPA width and execution state

  5. Updated patch [11/57] and [12/57]
    64e663f ArmVirtPkg: Add library for Arm CCA initialisation in PEI
    4dc7284 ArmVirtPkg: Add NULL instance of ArmCcaInitPeiLib
    to drop the ArmCcaInitialize() function from ArmCcaInitPeiLib as it is no longer needed.

  6. Updated patch [13/57] and [14/57]
    50f2c0e ArmVirtPkg: Add library for Arm CCA helper functions
    8c90f3e ArmVirtPkg: Add Null instance of ArmCcaLib

    to drop the ArmCcaSetMemoryProtectAttribute() which called SetMemoryProtectionAttribute()
    from the ArmMmuLib as this has been replaced by ArmCcaSetmemoryProtectionAttribute() in
    ArmMmuLib. Also modified the GetIpaWidth() to read the IPA width by querying the Realm
    Config, instead of reading from the gArmCcaIpaWidthGuid. This was done to remove the
    need for ArmCcaInitialize() in ArmCcaInitPeiLib, and the required optimisation shall be
    introduced in patch no 34 further in the new series
    e9bb253 ArmVirtPkg: Refactor ArmCcaLib for safe early boot

  7. Dropped patches 15 to 19 as these are no longer needed
    b7e134e ArmVirtPkg: Define an interface to configure MMIO regions for Arm CCA
    7f48419 ArmVirtPkg: CloudHv: Add a NULL implementation of ArmCcaConfigureMmio
    474d69b ArmVirtPkg: Qemu: Add a NULL implementation of ArmCcaConfigureMmio
    b19bb51 ArmVirtPkg: Xen: Add a NULL implementation of ArmCcaConfigureMmio
    616efd2 ArmVirtPkg: Configure the MMIO regions for Arm CCA

  8. Dropped patch [23/57]
    0ea7b2b ArmVirtPkg: Perform Arm CCA initialisation in the Pei phase
    as ArmCcaInitialize() function from ArmCcaInitPeiLib was dropped earlier and is no longer
    required to be invoked.

  9. Updated Patch [24/57]
    c97a7af ArmVirtPkg: Introduce Realm Aperture Management Protocol
    to use pragma once, reduce log output by making them verbose logs, and to switch to using
    ArmCcaSetmemoryProtectionAttribute().

  10. Dropped patch [27/57]
    2030a10 MdePkg: Warn if AArch64 RNDR instruction is not supported
    as it only printed a warning message if RNDR instruction was not supported and is not
    required.

  11. Dropped patch [41/57]
    f8f3215 ArmVirtPkg: ArmCcaLib: Cache current world value
    and replaced with patch no 34 in the new series
    e9bb253 ArmVirtPkg: Refactor ArmCcaLib for safe early boot
    which updates the ArmCcaLib function IsRealm() and GetIpaWidth() to cache the
    IsRealm and the IpaWidth value in HOBs when HOBs are initialised otherwise it
    issues RSI calls (which is mostly during early boot phases).

  12. Updated patches 47 to 52 to reflect the FDT API changes i.e. from fdt_xxx to Fdtxxx.
    45c3a88 OvmfPkg: Introduce a PlatformDeviceInfo lib
    b7c7c4b OvmfPkg: PlatformDeviceInfoLib - add Arm GIC parser
    b00629d OvmfPkg: PlatformDeviceInfoLib - add PCI parser
    d6feb90 OvmfPkg: PlatformDeviceInfoLib - add dev parser
    733c982 OvmfPkg: PlatformDeviceInfoLib - add serial parser
    8db807b OvmfPkg: PlatformDeviceInfoLib - add RTC parser

  13. Dropped patch [55/57]
    2eec130 ArmVirtPkg: RMM 1.0-rel0 - Exclude MMIO config of Realm Devices
    and replaced with patch no 48 in new series
    d30ca25 ArmVirtPkg: Rework MMIO mapping and configuration for Arm CCA
    as the Arm CCA shared attribute bit is directly configured in ArmVirtGetMemoryMap() due to
    which the additional adjustment step requiring ArmCcaInitialize() has also been eliminated.
    This patch also determines if the device is a Realm protected device by calling the ArmCcaLib
    function ArmCcaMemRangeIsProtectedMmio() and does not configure the protection attribute for
    the Realm protected devices as unprotected IPA space.

  14. New patches in the series
    6c45113 ArmVirtPkg: ArmCcaIoMmuDxe: unmap all mappings on reset
    20f2181 ArmVirtPkg: Install Realm Aperture Mgmt Absent Protocol if not Realm
    a285faf DynamicTablesPkg: handle missing 'iommu-map' in root complex parser

PR #518 Integration

The following patches from PR #518 were cherry-picked and merge conflicts resolved:

  1. Cherry-picked patches
    0fb42fa <Jean-Phili..> OvmfPkg/FdtNorFlashQemuLib: Parse device tree earlier
    4c9093a <Jean-Phili..> OvmfPkg/FdtNorFlashQemuLib: Fallback to runtime variable emulation
    49b3d34 <Jean-Phili..> ArmVirtPkg/ArmVirtQemu: Dispatch variable store emulation when necessary
    3533d17 <Jean-Phili..> BaseTools/Scripts/GccBase: Align .text and .data to 4KB
    8b89809 <Jean-Phili..> ArmVirtPkg/ArmPlatformLibQemu: Add id_pte macro to IdMap.S
    feb8513 <Jean-Phili..> ArmVirtPkg/ArmPlatformLibQemu: Add a third-level page table for the UART idmap
    99d81fc <Jean-Phili..> ArmVirtPkg/ArmPlatformLibQemu: Setup early UART mapping in a Realm
    b263e3f <Jean-Phili..> ArmVirtPkg/ArmVirtQemu: Add Arm CCA libraries
    344b457 <Jean-Phili..> ArmPkg/ArmMmuLib: Handle Realm unprotected bit
    02ffb3c <Jean-Phili..> ArmVirtPkg/QemuVirtMemInfoLib: Share the MMIO space with the VMM under CCA
    e116a07 <Jean-Phili..> ArmVirtPkg/ArmVirtQemu: Add RAMP and CcaIommu
    6e150ec <Jean-Phili..> ArmSetMemoryAttributes: Don't clear address bits when setting page attributes
    a6819ca <Jean-Phili..> OvmfPkg/MemEncryptSevLib: Add BaseMemEncryptSevLibNull
    8e61dfc <Jean-Phili..> OvmfPkg/RiscVVirtQemu: Include IoMmuDxe
    b5312f1 <Jean-Phili..> QemuFwCfgLibMmio: Use IOMMU for DMA buffers
    1d0ce19 <Jean-Phili..> ArmVirtPkg: Add BlobVerifierLibArmCca library
    29ab1db <Jean-Phili..> ArmVirtPkg/ArmVirtQemu: Use BlobVerifierLibArmCca

  2. Patches dropped
    b6a89d1 <Jean-Phili..> ArmVirtPkg: Add ArmCcaInitPei module
    2f9e54f <Jean-Phili..> ArmVirtPkg/ArmVirtQemu: Use ArmCcaInitPei module
    878f539 <Jean-Phili..> ArmVirtPkg: Add Null instance of gEfiRealmApertureManagementProtocolGuid
    d2a4d7d <Jean-Phili..> ArmVirtPkg/ArmCcaLib: Use GUID HOB to cache IsRealm value

@hajirazaman
Copy link
Copy Markdown

We have tested the ArmVirtQemu firmware with Google's internal VMM and successfully booted a Realm guest.

@samimujawar
Copy link
Copy Markdown

We have tested the ArmVirtQemu firmware with Google's internal VMM and successfully booted a Realm guest.

@hajirazaman Thank you for testing the edk2-staging/arm-cca branch and reporting back.
The final PR to merge the Arm CCA guest firmware support in edk2 mainline is at tianocore/edk2#12224. I had to make some adjustment in the PR tianocore/edk2#12224 to fix CI reported issued. Is it possible for you to test the PR tianocore/edk2#12224 report back, please?

@hajirazaman
Copy link
Copy Markdown

We have tested the ArmVirtQemu firmware with Google's internal VMM and successfully booted a Realm guest.

@hajirazaman Thank you for testing the edk2-staging/arm-cca branch and reporting back. The final PR to merge the Arm CCA guest firmware support in edk2 mainline is at tianocore/edk2#12224. I had to make some adjustment in the PR tianocore/edk2#12224 to fix CI reported issued. Is it possible for you to test the PR tianocore/edk2#12224 report back, please?

I’ve just tested PR tianocore/edk2#12224 and successfully booted a Confidential VM. I left a comment in that PR thread as well.

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.

3 participants