-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
base: master
Are you sure you want to change the base?
Support for Arm CCA guest firmware v3 (RMM-v1.0-rel0) #6480
Conversation
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]>
a51539a
to
0dca561
Compare
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]>
0dca561
to
535c33f
Compare
@@ -90,6 +90,7 @@ | |||
[LibraryClasses.AARCH64] | |||
ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf | |||
ArmCcaRsiLib|ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf | |||
RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
The change in MdePkg is OK to me. |
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:
and populate the memory map accordingly.
and if so, skip configuring the shared attribute for the
MMIO region.
a GIVc3-ITS is present.
Summary of updates in the previous v2 Series:
are already merged, hence dropped from this series.
code. Therefore, introduced SetMemoryProtectionAttribute()
to configure the top bit of the Realm IPA space which is
used as the protection bit
dynamic PCD, and introduced ArmVirtMonitorLib, a new
instance of the ArmMonitorLib that reads the conduit to
be used from the FDT.
Call arguments, and to correct the RSI Version mask
to RMM specification v1.0-EAC5.
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].
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:
page
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.
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:
The Kvmtool guest firmware binaries are at the following location:
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:Where:
creating the initial measurements by the RMM for this Realm (defaults
to sha256)
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
No
No
See ‘Running the stack’ section above.
How This Was Tested
See ‘Running the stack’ section above.
Integration Instructions
N/A