Arm Confidential Compute Architecture (Arm CCA) lets a virtual machine run inside a protected environment (Arm calls these environments realms) whose memory and registers the hypervisor that manages it cannot read or modify. It rests on the Realm Management Extension (RME) of Armv9-A, which adds two new security states, a Granule Protection Table that assigns every page of physical memory to a world, a small Realm Management Monitor (RMM) that runs realms, and an attestation token a remote party checks before trusting realms with secrets.
If you know TrustZone, here is the short version. TrustZone splits a chip into a Normal world and a Secure world that the platform vendor configures at boot. CCA keeps both and adds a third world that ordinary workloads can use at run time, isolated from the hypervisor, the host OS and the Secure world alike.
This post goes one level deeper than our explainer on how trusted execution environments protect sensitive workloads. For the x86 side, read the technical comparison of AMD SEV-SNP and Intel TDX. For the firmware underneath CCA, see Arm Trusted Firmware-A explained. For how attestation evidence is appraised in general, see CoRIM and the RATS architecture explained.
Key takeaways
- Arm CCA combines a hardware extension, RME (FEAT_RME, which Trusted Firmware describes as an Armv9-A extension), with firmware specifications and open source reference software.
- RME gives four security states and physical address spaces (PAS): Root,
Realm, Secure and Non-secure. A Granule Protection Table (GPT) in Root memory says which PAS owns each granule, and the MMU checks it after every translation. - The Normal world hypervisor still decides which realms run and what memory they get, but the RMM carries out those requests through the
Realm Management Interface(RMI). Guests call the RMM through theRealm Services Interface(RSI). - TF-RMM is the reference RMM at R-EL2. TF-A at EL3 owns the GPT and has supported RME since v2.6.
- A CCA token pairs a platform token, signed with the CCA Platform Attestation Key (CPAK), with a
realm state token. In the delegated model the platform token carries a hash of the RAK (Realm Attestation Key) that signs the second token. - The format is in draft-ffm-rats-cca-token (revision 04, 7 September 2026), an informational independent submission, not an IETF standard. Veraison is a named open source verifier.
- Linux documents running as a guest inside realms. Confirm host support, VMM support and RME hardware for your own platform.
- TF-A, TF-RMM, its bundled libraries and the guest kernel sit inside your trusted computing base. Track their versions.
What is Arm CCA and what problem does it solve?
In a normal virtualised system the hypervisor is the most privileged software a guest has to live with. It allocates guest memory, builds the stage 2 page tables, saves and restores guest registers on every context switch, and can read or change all of that state. The TF-RMM README states the problem directly: before Arm CCA, virtual machines had to trust the hypervisors that managed them, a resource managed by the hypervisor was also accessible to it, and exploits against hypervisors could leak confidential data held in virtual machines.
For a cloud tenant, that means trusting the provider's hypervisor, its operators and every bug in its code. CCA moves the boundary. According to TF-RMM, any code or data belonging to realms, whether in memory or in registers, cannot be accessed or modified by the hypervisor, so the owner of those realms does not need to trust the hypervisor that manages the resources those realms use.
Which architecture version introduced it?
The Trusted Firmware-A documentation describes FEAT_RME as an Armv9-A extension and one component of Arm CCA, and Arm's CCA overview page describes Armv9-A with RME creating realms to isolate models and data. CCA as a whole combines that hardware extension with firmware specifications (notably the RMM specification, Arm document DEN0137) and reference software (TF-A, TF-RMM, Linux and KVM work, and verification tooling).
Because RME is an extension, an Armv9-A core is not proof that realms are available: confirm FEAT_RME for the exact part, and confirm the firmware ships an RMM.
How is this different from TrustZone?
TrustZone splits the processor into a Normal world and a Secure world that typically hosts a trusted OS and trusted applications. It is a poor fit for general confidential computing: Secure world code is usually built and signed by the silicon vendor or device maker, secure memory is typically carved out at boot, and anything running in the Normal world still has to trust the hypervisor. A cloud tenant cannot ship a virtual machine into it.
CCA leaves TrustZone in place and adds a separate world beside it. Arm's overview page describes TF-RMM as the controlling software there, reacting to requests from the Normal world hypervisor to manage the execution of realms, with resource decisions remaining with the host hypervisor. Realms are created and destroyed at run time, memory moves between worlds one granule at a time, and the workload owner needs nothing signed by the platform vendor. TrustZone protects the platform from the rich OS. CCA protects a workload from the platform's own management software.
The four worlds: Normal, Secure, Realm and Root
The kernel documentation summarises RME in one line: it extends the older two world model (Normal and Secure) into four worlds: Normal, Secure, Root and Realm. Each world has its own physical address space, and every memory access is tagged with the PAS of the security state that issued it.
| World | Physical address space | Exception levels | What runs there |
|---|---|---|---|
| Normal | Non-secure PAS | EL0, EL1, EL2 | Host OS and hypervisor (for example KVM), ordinary VMs and applications, and the VMM that launches realms |
| Secure | Secure PAS | S-EL0, S-EL1, S-EL2 | TrustZone software: a trusted OS, trusted applications, a secure partition manager such as Hafnium |
Realm | Realm PAS | R-EL0, R-EL1, R-EL2 | The RMM at R-EL2; guest kernels and user space of realms at R-EL1 and R-EL0 |
| Root | Root PAS | EL3 | The EL3 monitor (TF-A BL31 in the reference stack), which owns the GPT and switches between worlds |
TF-A's RME chapter lists exactly this tested arrangement: an RME capable Linux host in the Normal world, TF-A at EL3 in Root, the RMM at R-EL2, and in a four world configuration the SPM (Hafnium) at S-EL2.
Two points are easy to miss. EL3 now has a world of its own, Root, and memory assigned to Root cannot be touched by any other world; that is where the GPT lives, so nothing below EL3 can rewrite it. And the world realms use is a peer of the Secure world: secure software cannot read memory owned by realms, and the reverse holds too, so a vendor's trusted OS cannot read a tenant's confidential VM.
Which world can access which memory?
The TF-A Granule Protection Tables library documentation gives the access matrix. Read it as "can software in this state access this PAS":
| Physical address space | Root state | Realm state | Secure state | Non-secure state |
|---|---|---|---|---|
| Root PAS | Yes | No | No | No |
Realm PAS | Yes | Yes | No | No |
| Secure PAS | Yes | No | Yes | No |
| Non-secure PAS | Yes | Yes | Yes | Yes |
Every state can reach Non-secure memory, which is how realms share buffers with the host for I/O. Only Root can reach everything, which is why the EL3 firmware is the single most important piece of software in the trusted computing base.
What does the RMM do?
The kernel documentation describes the RMM as acting "a bit like a hypervisor": it runs at EL2 in the world realms use and manages the stage 2 page tables of their guests. But much of the control stays with the hypervisor in the Normal world, which uses RMI to request operations such as mapping memory or running a virtual CPU.
The split works like this:
- The host decides. It chooses which realms run, when each virtual CPU is scheduled and how much memory each gets. TF-RMM states that policy decisions, such as which realms to run or what memory to delegate, are made by the hypervisor and communicated through RMI.
- The RMM enforces. It validates every request and refuses anything that would break confidentiality or integrity. The host can ask to map a page into protected guest memory, but it cannot replace pages there without the guest's cooperation. The host can ask to run a virtual CPU, but the RMM saves and restores guest registers itself.
- Guests ask for services. Guests call the RMM through RSI. TF-RMM lists cryptographic services and attestation among those services, and RSI is also the channel for memory management requests from guests.
The protected and shared halves of the address space
The RMM splits each guest's intermediate physical address (IPA) space in two. The kernel documentation explains that the lower half is protected: memory mapped there cannot be seen by the Normal world, and the RMM restricts what the Normal world can do with it. The upper half is shared: the Normal world can change pages there freely and can emulate MMIO devices there.
Each protected IPA carries a RIPAS value, such as RAM, EMPTY or DEV. A guest can ask through RSI to move protected ranges between RAM and EMPTY in either direction, which is how it hands memory back to the host or asks for more. Without an explicit request from the guest, the RMM prevents the Normal world from making those changes.
That is why the kernel lists rules for booting Linux inside realms. The VMM or a boot loader must provide them before Linux starts:
- All protected RAM described to Linux (by device tree or ACPI) must be marked RIPAS RAM.
- MMIO devices must be either unprotected (emulated by the Normal world) or marked RIPAS DEV.
- MMIO devices used very early in boot, such as the early console, must sit in the upper half of the IPA space. The kernel's example, for a 33 bit IPA size and an emulated UART at 0x1000000, is
earlycon=uart,mmio,0x101000000. - Linux uses bounce buffers for unprotected devices. It turns some protected memory into RIPAS EMPTY and expects to reach the unprotected pages at the same IPA with the highest valid IPA bit set.
Worked example: the shared alias address
The kernel's early console example shows the rule behind every shared buffer.
- IPA size: 33 bits, so the IPA space is 2^33 bytes, which is 8 GiB (0x2_0000_0000).
- The highest valid IPA bit is bit 32, worth 2^32, which is 0x1_0000_0000 (4 GiB). The lower 4 GiB is the protected half; the upper 4 GiB is the shared half.
- The emulated UART lives at 0x0100_0000 in the device map.
- Its shared alias is 0x0100_0000 plus 0x1_0000_0000, which is 0x1_0100_0000, exactly the
0x101000000in the kernel's example.
The same arithmetic applies to bounce buffers. A buffer at protected IPA 0x4000_0000 that Linux has turned into RIPAS EMPTY is reached through its shared alias at 0x1_4000_0000, where the host can read and write it. Anything placed there is visible to the host, so data crossing that boundary must be protected by the protocol that carries it.
What a guest lifecycle looks like
The RMM specification defines the RMI and RSI commands; the names below appear in TF-RMM's release notes and design pages. This is simplified, and commands differ between specification versions (TF-RMM v0.9.0 adds RMI_RTT_DATA_MAP_INIT and range delegation in its initial RMM v2.0 alignment).
| Step | Who acts | Interface | What happens |
|---|---|---|---|
| 1. Delegate memory | Host | RMI_GRANULE_DELEGATE (or the range variant) | Host memory granules move to the Realm PAS. The RMM asks EL3 to change their GPT entries. |
| 2. Create the guest | Host | RMI create commands | The RMM builds a descriptor recording parameters such as the IPA size and measurement algorithm. |
| 3. Create virtual CPUs | Host | RMI_REC_CREATE | Each REC (Realm Execution Context) is a virtual CPU whose registers the RMM holds. |
| 4. Load and measure the image | Host | Data map commands such as RMI_RTT_DATA_MAP_INIT, plus RMI_RTT_INIT_RIPAS | The host copies the guest image into delegated granules; loaded content is measured into the RIM (initial measurement). |
| 5. Activate | Host | RMI_REALM_ACTIVATE | The initial measurement is fixed; no more measured content can be added. |
| 6. Run | Host | RMI_REC_ENTER | The RMM enters the guest and returns to the host on exits it must handle, such as MMIO emulation. |
| 7. Query and attest | Guest | RSI calls such as RSI_IPA_STATE_GET and RSI_ATTEST_TOKEN_CONTINUE | The guest checks its own memory state and requests an attestation token bound to its challenge. |
| 8. Tear down | Host | RMI_REC_DESTROY, RMI_REALM_DESTROY, RMI_GRANULE_UNDELEGATE | Granules return to Non-secure after the RMM scrubs them. TF-RMM exposes the scrub method as the RMM_MEM_SCRUB_METHOD build option. |
How TF-RMM relates to TF-A at EL3
TF-RMM is the Trusted Firmware implementation of the RMM specification. Its README says it talks to the Root EL3 firmware through the RMM-EL3 Communication Interface, implemented by TF-A, and its getting started guide adds that the RMM relies on EL3 firmware to load it at boot and needs a Non-secure host at run time.
TF-A's RME chapter describes what changes at EL3 when RME is enabled:
- Boot flow. BL2 normally runs at S-EL1, but with RME it runs at EL3. BL1 loads BL2 at EL3; BL2 loads images including the RMM into the
RealmPAS; BL31 initialises the SPM if enabled, then the RMM, then hands control to Normal world software. - GPT library. TF-A gains a library to build the GPTs, enable granule protection checks, and transition granules between PASs at run time.
- RMM Dispatcher (RMMD). A runtime service at EL3 that initialises the RMM and handles RMI SMC calls from the Non-secure world, switching into the RMM's world.
- Test payload (TRP). A small R-EL2 payload implementing a subset of RMI, used to test EL3 when no RMM image is provided.
So TF-A owns and writes the GPT; when TF-RMM needs a granule moved, it asks EL3, and the GPT library makes the change.
The two projects move together. Each TF-RMM release names the TF-A release it was verified with: v0.9.0 was verified with TF-A v2.15 (released 2 June 2026 according to Trusted Firmware's news listing) and updated the EL3 interface version to 2.0; v0.8.0 was verified with TF-A v2.14. Treat the EL3 firmware and RMM as one unit when you plan updates.
TF-RMM is licensed BSD-3-Clause. Its README lists the third party projects it fetches into its ext folder at configure time: Mbed TLS, t_cose, QCBOR and libspdm, with CppUTest, spdm_emu and minicoro used only for host based testing.
How does the Granule Protection Table stop the hypervisor from reading memory inside realms?
Page tables cannot protect guests from the hypervisor, because the hypervisor controls them. RME adds a check it cannot influence. In TF-A's words, isolation between the four physical address spaces is enforced by a Granule Protection Check (GPC) performed by the MMU downstream of any address translation, using a GPT in the Root world that describes the PAS assignment of every granule. Step by step:
- Physical memory is divided into granules. A granule is the smallest unit of memory that can be independently assigned to a PAS. The physical granule size (PGS) can be 4 KB, 16 KB or 64 KB.
- The GPT records the owner of each granule. The table lives in Root memory and only EL3 writes it. TF-A's library requires both its level 0 and level 1 tables to sit in memory of type GPT_GPI_ROOT.
- Every access carries a PAS. Normal world accesses are tagged Non-secure; accesses from the RMM and guests are tagged with the
RealmPAS. - The MMU compares them after translation. Translation produces a physical address; the GPC then looks up that address in the GPT and checks whether the access's PAS is allowed. If it is not, the access faults instead of returning data.
So if the hypervisor maps a delegated granule into its own page tables, translation succeeds but the Non-secure access to a Realm PAS granule is refused. The hypervisor can still deny service, but it cannot read or silently change guest data.
How the table is laid out
TF-A's GPT library can use a one level or two level lookup:
- Level 0 entries each govern a large region whose size, L0GPTSZ, is fixed by hardware and read from the GPCCR_EL3 register. Supported sizes range from 1 GB (30 bits) to 512 GB (39 bits). A level 0 block descriptor can assign the whole region to one PAS.
- Level 1 tables give per granule control. To change the PAS of a region at run time, that region must be mapped through level 1. Adjacent level 1 entries with the same PAS can be combined into contiguous descriptors.
- Protected physical space (PPS) is the total address space the tables cover. TF-A accepts 4 GB, 64 GB, 1 TB, 4 TB, 16 TB, 256 TB and 4 PB.
TF-A gives two sizing rules: the level 0 table needs (PPS / L0GPTSZ) x 8 bytes, and each level 1 table needs (L0GPTSZ / PGS) / 2 bytes, because each byte holds the protection information for two granules.
Worked example 1: a 4 GB development system
Take PPS = 4 GB, L0GPTSZ = 1 GB and PGS = 4 KB.
- Level 0: 4 GB / 1 GB = 4 entries; 4 x 8 bytes = 32 bytes.
- Level 1, per 1 GB region: 1 GB / 4 KB = 262,144 granules; 262,144 / 2 = 131,072 bytes (128 KB).
- If all four regions need per granule control: 4 x 128 KB = 512 KB of Root memory for level 1 tables.
That is about 0.0122% of the protected space (512 KB out of 4 GB), which is why fine grained protection is affordable.
Worked example 2: a larger server with 64 KB granules
Take PPS = 1 TB, L0GPTSZ = 16 GB (34 bits) and PGS = 64 KB.
- Level 0: 1 TB / 16 GB = 64 entries; 64 x 8 bytes = 512 bytes.
- Level 1, per 16 GB region: 16 GB / 64 KB = 262,144 granules; / 2 = 131,072 bytes (128 KB).
- Suppose only 256 GB of DRAM needs dynamic transitions: 256 GB / 16 GB = 16 regions; 16 x 128 KB = 2 MB of level 1 tables. The rest can stay as level 0 block descriptors.
The trade off is granularity. With 64 KB granules, the smallest unit you can move between worlds is 64 KB, so a guest that needs one 4 KB shared page still costs a full granule.
Delegation: moving memory between worlds
TF-A's granule transition service moves Non-secure granules to the Realm or Secure PAS and back through SMC calls. Only level 1 entries can be transitioned, under a lock so one CPU changes an entry at a time.
In practice, the host calls RMI_GRANULE_DELEGATE; the RMM checks the granule is in a state where delegation is allowed and asks EL3 to change the GPT entry. From then on only software in the Realm state can touch that granule. Undelegation runs the other way, after the RMM scrubs the content, so guest data never leaks back through returned memory. TF-RMM v0.9.0 adds range delegate and undelegate commands so the host can move many granules in one call, and a placeholder RMI_GPT_L1_CREATE command for future dynamic GPT management.
What about devices and physical attacks?
The TF-A documentation describes the GPC as performed by the MMU. Device DMA is a separate path, and TF-RMM shows that work in progress: v0.9.0 adds an initial SMMUv3 driver and continues device assignment work, and its Shrinkwrap guide documents a device assignment demonstrator based on a Linux kernel prototype branch. Check how your platform protects device accesses before relying on it.
Granule protection alone does not stop someone probing the memory bus. Memory encryption is a platform property (the token draft has a MEC policy claim and TF-RMM mentions MEC support), so confirm it with the hardware vendor.
How does CCA attestation work?
Isolation is only useful if a relying party can tell that a workload really is running in realms, on a genuine CCA platform, with the expected software. That is attestation, and CCA's version has two layers.
Two attesting environments, one token
The CCA token draft describes a layered attester with exactly two layers:
- The platform layer. Hardware Enforced Security (HES), the platform root of trust, attests to the identity, configuration and state of the platform and to the executables and configuration of the "Monitor Security Domain", which includes the RMM. Its evidence is the CCA platform token, signed with the CCA Platform Attestation Key (CPAK).
- The guest layer. The RMM attests to the initial memory content of each guest, the dynamic measurements the guest provides, and other state. Its evidence is the
realm state token, which the rest of this post calls the guest token.
The draft defines two arrangements:
| Model | How the guest token is protected | How the two tokens are bound |
|---|---|---|
| Delegated | Signed by the RMM with the RAK. The RAK key pair is derived within the HES and transferred to the RMM over a trusted channel. | The platform token's nonce claim carries a hash of the RAK public key. |
| Direct | Left unsigned. The RMM hashes the guest claims and passes the hash to the HES. | The platform token carries that hash, so the CPAK signature covers the guest claims indirectly. |
Either way, the result is wrapped in a Conceptual Message Wrapper (CMW) collection, CBOR tag 907 in the draft's CDDL, holding the platform token and the guest token. Both are EAT (Entity Attestation Token) profiles encoded as CBOR Web Tokens.
What the guest token says
| Claim | Size or form | What it covers |
|---|---|---|
| Challenge | Exactly 64 bytes (EAT nonce, claim key 10) | Freshness: the value the relying party supplied |
| Personalisation value (RPV) | 64 bytes | A value supplied when the guest was created, so otherwise identical guests can be told apart |
| Initial measurement (RIM) | One measurement | The compound extension of measurements of guest memory and state before activation |
| Extensible measurements (REMs) | Four measurements | Values guest software extended at run time |
| Hash algorithm | Named hash string | The algorithm used for all hashes in the token |
| RAK public key and its hash algorithm | Key and identifier | The RAK public key the verifier checks against the platform token |
The draft also defines newer claims such as MEC policy, live firmware activation (LFA) policy, an instance ID and a devices token hash, which track the RMM 2.0 work.
The RIM works like a launch measurement: the host cannot change what was loaded without changing it, and it is fixed at activation. REMs are extend only; guest software can add to them but nobody can set them to an arbitrary value. Together they let a guest build its own measured boot chain on top of the RIM, for example by extending the kernel command line or a root file system hash.
What the platform token says
The platform token carries the implementation and instance IDs, the security lifecycle state, platform configuration, a software components list (measured components that can affect platform behaviour, including the RMM), a hash algorithm and an optional verification service hint. The draft says a non debugged platform reports the "secured" lifecycle state.
Requesting a token from Linux
From inside the guest, the RMM provides tokens through RSI calls, possibly across several calls because a token can be larger than one transfer (hence RSI_ATTEST_TOKEN_CONTINUE). Linux wraps this. The kernel's arm-cca-guest driver (Kconfig symbol ARM_CCA_GUEST) "provides userspace interface to request" an attestation report from the RMM, and it selects TSM_REPORTS, the kernel's generic configfs-tsm report interface.
The configfs-tsm ABI, documented since Linux 6.7, works through a directory under /sys/kernel/config/tsm/report. A privileged process writes up to 64 bytes of its own data to inblob (the documentation says it should include a nonce for replay protection), reads the binary report from outblob, and reads provider to learn which implementation produced it. The 64 byte limit lines up with the 64 byte challenge in the guest token.
The IETF CCA token draft
The document is draft-ffm-rats-cca-token, "Arm's Confidential Compute Architecture Reference Attestation Token", by authors from Arm, Linaro and AMD. Revision 04 is dated 7 September 2026 and expires 11 March 2027. It says the CCA token is a profile of EAT, that it is published as an independent submission to improve interoperability, and that it is "not a standard nor a product of the IETF". It uses the RATS vocabulary from RFC 9334: the CCA platform and RMM are the Attester, the token is Evidence, and the service that checks it is the Verifier. It references the RMM specification 2.0.
Because it is a draft, record which revision and profile your verifier implements. It defines a format, not a trust policy; which measurements you accept is your decision.
Verifying a token: Veraison and CoRIM
A token proves nothing until a verifier compares it with known good values. Section 7 of the draft describes verification:
- Check the token's encoding.
- Check the platform token signature. The verification key comes from an authorised Endorser, matched using the implementation ID and instance ID, or through an X.509 chain if the CPAK is endorsed that way. The verifier may also be told a key has been revoked.
- Check the binding between the platform token and the guest token, which establishes trust in the RAK public key.
- Check the guest token signature with the RAK.
- Check the lifecycle claim is the secured state. Some debug states may be treated as a temporary contraindication rather than a hard failure.
- Compare claims with reference values registered for the deployment, typically the implementation ID and the software component measurements.
Section 7.3 points to a separate draft, draft-ydb-rats-cca-endorsements (revision 04, 26 June 2026), which defines how to carry CCA endorsements, reference values and verification keys using the CoRIM data model. Our CoRIM and RATS explainer covers that format.
For the verifier itself, the draft's implementation status section names two open source implementations: TF-RMM on the token producing side and the Veraison project (its ccatoken package) on the verifying side. Veraison describes itself as building software components that can be used to build an attestation verification service, and it appears in the Confidential Computing Consortium's project listing. Its documentation includes Arm CCA material and an end to end demo.
A worked attestation flow
- A key broker holds a disk decryption key for a confidential workload.
- The guest boots, generates an ephemeral key pair and asks the broker for a nonce.
- The guest computes a 64 byte challenge, for example a SHA-512 hash over the nonce and its ephemeral public key, writes it to configfs-tsm
inblob, and reads the token fromoutblob. - The broker forwards the token to a verifier (for example a Veraison deployment) with its appraisal policy.
- The verifier runs the checks above, including the RIM and REMs against values you published for this guest image.
- Only on a passing result does the broker wrap the disk key to the guest's ephemeral public key.
The important property is step 6: the secret never reaches the guest unless the evidence checks out. Unattested guests are just VMs with a reassuring label.
Arm CCA versus AMD SEV-SNP versus Intel TDX
All three aim to protect a VM from its host, with different mechanisms. This table stays at the level of what you trust and what you check; the SEV-SNP and TDX comparison has the x86 detail.
| Property | Arm CCA | AMD SEV-SNP | Intel TDX |
|---|---|---|---|
| Isolation unit | Realms (VMs in the RME Realm world) | SEV-SNP guest VM | Trust Domain (TD) |
| Hardware feature | FEAT_RME, an Armv9-A extension | SEV-SNP on supported AMD processors | TDX on supported Intel processors |
| How the host is kept out | Granule protection checks after translation, using a GPT owned by EL3 | Memory encryption and SNP integrity protection, managed by AMD Secure Processor firmware | Private memory keys usable only in SEAM mode, managed by the TDX module |
| Trusted firmware or module | EL3 monitor and RMM (reference: TF-A and TF-RMM, both open source) | SEV firmware on the AMD Secure Processor | TDX module, loaded by the SEAM loader |
| Attestation evidence | CCA token: platform token plus guest token in a CMW collection (draft-ffm-rats-cca-token) | SNP attestation report from the SEV firmware | TDREPORT from the TDX module, then a quote for remote verification |
| Linux guest documentation | Kernel arm64 Arm CCA page; arm-cca-guest driver via configfs-tsm | Kernel SEV guest API documentation | Kernel x86 TDX documentation |
Every row depends on version, so check documentation for your processor, firmware and kernel. Open source reference firmware does not mean you build it; the platform vendor usually builds and signs it, so ask which version you run.
Linux and KVM support status, and how to try CCA on emulation
What the kernel documents
The kernel's arm64 documentation has an Arm Confidential Compute Architecture page (the 7.3 documentation at the time of writing). It covers Linux as a guest inside realms: what the VMM or a boot loader must set up, how protected and shared memory work, and how Linux uses bounce buffers. The kernel tree also contains the arm-cca-guest attestation driver described above.
The same kernel's KVM API reference did not describe creating VMs inside realms when we checked it for this post, and the TF-A and TF-RMM documentation describe the Normal world host as an "RME capable Linux" built by Shrinkwrap. Do not assume your distribution kernel can host realms. Confirm three things: the host kernel version and configuration, whether your VMM supports launching realms, and the platform firmware.
Is CCA hardware available?
Silicon vendors decide whether to implement FEAT_RME, and platform vendors decide whether their firmware enables it. Confirm any chip, board or cloud instance in that vendor's own documentation, including the RMM version. Most developers meet CCA today on Arm's Fixed Virtual Platform (FVP) models.
Step by step: build TF-RMM and run a CCA stack on FVP
TF-A recommends Shrinkwrap for building and running an RME enabled reference platform, with three world and four world configurations for the FVP_Base_RevC-2xAEMvA model. TF-RMM's guide documents the same route. The commands below come from the TF-RMM getting started and Shrinkwrap pages; check them against the release you check out, because configuration names change.
1. Get the source and record what you build.
git clone https://git.trustedfirmware.org/TF-RMM/tf-rmm.git
cd tf-rmm
git describe --tags --always # record the exact version you build
2. Build the RMM on its own for FVP (optional, to see the build).
export RMM_SOURCE_DIR="$PWD"
export RMM_BUILD_DIR="$PWD/build"
cmake -DRMM_CONFIG=fvp_defcfg -S ${RMM_SOURCE_DIR} -B ${RMM_BUILD_DIR}
cmake --build ${RMM_BUILD_DIR}
ls ext/ # third party code fetched at configure time: note the versions
3. Point Shrinkwrap at the RMM's configs and a workspace.
export SHRINKWRAP_CONFIG=${PWD}/tools/shrinkwrap/configs
export WORKSPACE=${HOME}/workspace
export SHRINKWRAP_BUILD=${WORKSPACE}
export SHRINKWRAP_PACKAGE=${SHRINKWRAP_BUILD}/package
4. Build and run the three world demonstrator (TF-A at EL3, your local RMM, an RME capable Linux host).
shrinkwrap build cca-3world.yaml --overlay=cca.yaml \
--btvar=GUEST_ROOTFS='${artifact:BUILDROOT}' --btvar=RMM_SRC=${PWD} --no-sync=rmm
shrinkwrap run cca-3world.yaml --overlay=cca.yaml \
--rtvar=ROOTFS=${SHRINKWRAP_PACKAGE}/cca-3world/rootfs.ext2
5. Launch a guest inside realms from the host (log in as root on the model; the guide uses kvmtool from /cca).
cd /cca
./lkvm run --realm -c 2 -m 256 --disk guest-disk.img --kernel Image \
-p "earlycon=uart,mmio,0x101000000 root=/dev/vda2 swiotlb=16384"
The guide explains that swiotlb=16384 asks for 32 MiB of DMA bounce buffers to avoid "swiotlb buffer is full" errors. Notice the early console address: it is the shared alias from the worked example above. The guide also documents an rmm-tftf.yaml configuration that runs the TF-A test framework against the RMM, and a four world configuration if you need the Secure world too.
6. Check the guest from inside. These commands are read only:
uname -r
dmesg | grep -i -E 'realm|rsi|cca'
grep -E 'ARM_CCA_GUEST|TSM_REPORTS' /boot/config-"$(uname -r)" 2>/dev/null
ls /sys/kernel/config/tsm/report 2>/dev/null || echo "configfs-tsm report interface not mounted or not present"
If the report interface is present, the kernel's configfs-tsm ABI documentation describes creating a report directory, writing your challenge to inblob and reading outblob and provider.
The supply chain angle: the CCA trusted computing base is open source software
Confidential computing changes whom you trust; it does not remove trust. Guests in realms still depend on a chain of software, and in the reference stack most of it is open source:
| Layer | Reference component | What to record |
|---|---|---|
| EL3 monitor and GPT owner | Trusted Firmware-A (RME support since v2.6) | Release tag, RME build options, platform port, who signed it |
| RMM | TF-RMM | Release tag, the TF-A release it was verified with, the RMM specification version it targets |
| Libraries inside the RMM | Mbed TLS, t_cose, QCBOR, libspdm (fetched into ext) | Exact versions or commits pulled at build time |
| Host hypervisor and VMM | Linux KVM with support for realms, kvmtool or another VMM | Kernel version and configuration, VMM version |
| Guest kernel and user space | Linux arm64 with the arm-cca-guest driver, plus your packages | Kernel version, configuration and command line; a software bill of materials for the image |
| Verifier | Veraison or your own service | Version, plug-ins, policy, sources of reference values |
Each has its own releases and advisories. A bug in the RMM, or in a library it links, is a bug in the component meant to protect your guests. A bug in the guest kernel or an application package lives inside the protected boundary, where isolation from the host does not help at all.
Three practices follow:
- Inventory firmware and guests like application dependencies. Keep a record of TF-A and TF-RMM versions, including what TF-RMM fetched into
ext, and a software bill of materials for every guest image. - Tie reference values to versions. Each RMM build changes the platform token's software component measurements, and each guest build changes the RIM. Publish new reference values before rolling out an update, and retire old ones on a schedule so the verifier rejects firmware you know is vulnerable.
- Watch advisories for the whole chain. Trusted Firmware runs a security center; the kernel and each library have their own channels. A guest on an unpatched RMM attests, accurately, to a vulnerable configuration.
Step by step: adopting CCA safely
- Confirm the platform. Check FEAT_RME for the exact processor and which TF-A and RMM versions its firmware ships.
- Prototype on FVP with the Shrinkwrap three world demonstrator, built from tagged releases.
- Build guest images reproducibly. Pin the kernel, initramfs and packages, generate a software bill of materials, and record the expected RIM; extend the command line or root file system hash into REMs.
- Stand up a verifier with vendor endorsements and firmware reference values (CoRIM where available) plus your guest reference values.
- Write the policy and gate secrets on it. Require the secured lifecycle state, minimum firmware versions, a fresh 64 byte challenge and the expected measurements. No passing result, no key.
- Update firmware as a pair and patch guests. Update TF-A and TF-RMM together, publish new reference values, then reject the old version. Keep guest images on your normal patch cadence.
Common mistakes
Equating TrustZone with CCA. TrustZone is the Secure world, configured by the platform vendor. CCA adds a separate world for run time guests, isolated from both the Normal and Secure worlds. A device with TrustZone is not a device with realms.
Assuming every Armv9-A chip supports realms. FEAT_RME is an extension. Confirm it for the exact part and confirm the firmware enables it.
Trusting guests without verifying attestation. If you send secrets to a VM because an orchestrator labels it confidential, you are trusting the host again, which is exactly what CCA was meant to remove.
Checking only the guest token. Without the platform token signature and the binding check, you have no evidence that the RMM or the platform is genuine.
Ignoring firmware updates to the RMM and EL3. They are the most privileged software protecting your guests. Treat their advisories like hypervisor advisories and update reference values when they change.
Accepting any version the token reports. A token can accurately describe a vulnerable RMM. Policy needs minimum versions and lifecycle checks, not just a valid signature.
Forgetting the shared half. Bounce buffers and anything else in the upper half of the IPA space are visible to the host. Encrypt and authenticate data in transit to devices and the network.
FAQ
Is Arm CCA the same as TrustZone?
No. TrustZone provides the Secure world, which the platform vendor configures. Arm CCA adds Root and a separate world for realms, so workloads can run isolated from the hypervisor, the host OS and the Secure world.
Which Arm architecture version supports CCA?
CCA relies on RME, which Trusted Firmware describes as an Armv9-A extension (FEAT_RME). A specific processor must implement it and the platform firmware must enable it.
What is the RMM in Arm CCA?
Firmware at R-EL2 that manages guest page tables and virtual CPU state, carries out host requests made through RMI, and serves guests through RSI. TF-RMM is the open source reference.
What is a granule in Arm CCA?
A granule is the smallest unit of physical memory that can be assigned to a physical address space. TF-A supports 4 KB, 16 KB and 64 KB granules, and the Granule Protection Table records which PAS each one belongs to.
Can the hypervisor read memory inside realms?
Not through CPU accesses. Even if it maps a delegated granule into its own page tables, the granule protection check sees a Non-secure access to a Realm PAS granule and refuses it. The hypervisor can still refuse to run or feed the guest.
What is in a CCA attestation token?
A CMW collection of two EAT profiles: a platform token describing hardware identity, lifecycle state and measured firmware including the RMM, and a guest token with a 64 byte challenge, personalisation value, initial measurement, four extensible measurements and the RAK public key.
How do I verify an Arm CCA token?
Check the platform token signature with an endorsed key, check its binding to the guest token, check that token's signature, require the secured lifecycle state, and compare measurements with reference values. Veraison is an open source verifier that implements the CCA token.
Does Linux support Arm CCA?
The kernel documents running Linux as a guest inside realms and includes an arm-cca-guest driver that exposes attestation through configfs-tsm. Host side support depends on your kernel and VMM; check before planning around it.
How can I try Arm CCA without hardware?
Use Arm's FVP models with Shrinkwrap, following the TF-RMM "Building with Shrinkwrap" guide, then launch a guest with lkvm run --realm.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.
3. Gold Registry: start from components that are already fixed
Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
Safeguard does not inspect firmware, verify attestation tokens or manage confidential VMs. Its fit here is the software you build and run inside realms, and the open source components you track around them. You can scan a guest image or the repository that builds it, see which projects carry a vulnerable component and version, and enforce policies and gates in CI with Block, Warn and Notify actions, approving the cases you accept through exceptions.
The first demo is a real Safeguard CLI session: install it, run safeguard to open the interactive terminal, and ask it to fix the lodash CVE in a repository. It reads the finding and the advisory, asks before any command that changes something, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, prints a summary and pushes nothing. The same flow applies to the repository that builds a guest image, where a vulnerable dependency is inside the protected boundary.
Click through it at your own pace, or open it full screen.
The second demo sets up the runner on your own machine, approves it with its device code, then scans from the terminal. It suits teams that build guest images on their own hardware and want scanning to happen where the image is built.
Click through it at your own pace, or open it full screen.
The third demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. Once connected, you can ask about the components in your projects, such as which builds still carry an old version of a library you also ship inside a guest image.
Click through it at your own pace, or open it full screen.
To try it on your own code, download Safeguard and follow the CLI documentation.
Quick check
Which component in the Arm CCA reference stack owns and writes the Granule Protection Table?
The EL3 firmware in the Root world, TF-A in the reference stack. The RMM asks EL3 to move a granule between physical address spaces through the RMM-EL3 interface; it never writes the GPT itself.
Why must a verifier check the platform token as well as the guest token?
The guest token is signed with the RAK, which only means something because the platform token, signed with the hardware rooted CPAK, carries a hash of the RAK public key and describes the firmware (including the RMM) that booted. Without it there is no evidence the RMM or platform is genuine.
Sources
- Arm: Arm Confidential Compute Architecture overview
- Linux kernel documentation: Arm Confidential Compute Architecture (arm64)
- Linux kernel source: arm-cca-guest driver Kconfig
- Linux kernel ABI documentation: configfs-tsm report
- Linux kernel documentation: KVM API
- Linux kernel documentation: Intel Trust Domain Extensions
- Linux kernel documentation: SEV guest API
- Trusted Firmware: TF-RMM project page
- TF-RMM documentation: Readme
- TF-RMM documentation: Change log and release notes
- TF-RMM documentation: Getting started
- TF-RMM documentation: Build options
- TF-RMM documentation: Building with Shrinkwrap
- TF-RMM documentation: MMU setup and memory management design
- TF-A documentation: RME support
- TF-A documentation: Granule Protection Tables library
- IETF Datatracker: draft-ffm-rats-cca-token, Arm's CCA Reference Attestation Token
- RFC 9334: Remote ATtestation procedureS (RATS) Architecture
- Veraison project on GitHub
- Veraison documentation
- Veraison ccatoken package
- Confidential Computing Consortium
Last reviewed: 25 October 2026.