Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TPM on QEMU Arm Virt

This document describes the TPM 2.0 architecture for the QEMU Arm Virt platform. Arm Virt uses a dual-CRB design with an FF-A (Firmware Framework for Arm A-Profile) mediated communication path between the normal world and the secure world.

Table of Contents

Requirements

RequirementNotes
Host OSLinux (native) or WSL on Windows. Native Windows is not supported.
swtpmTPM 2.0 emulator. Install via your distro's package manager (e.g. apt install swtpm swtpm-tools).
QEMUBuilt with tpm-tis-device support (standard upstream QEMU includes this).
Build hostSame Linux/WSL environment used to run stuart_build and launch QEMU.

See swtpm Setup for the full setup commands.

Build Configuration

The TPM is disabled by default. To enable it, set BLD_*_TPM2_ENABLE=TRUE on the command line or in a BuildConfig.conf file placed at the root level of the repo:

stuart_build -c Platforms/QemuArmVirtPkg/PlatformBuild.py --FlashRom BLD_*_TPM2_ENABLE=TRUE

The following defines control TPM behavior in QemuArmVirtPkg.dsc:

DefineDefaultPurpose
TPM2_ENABLEFALSEMaster switch. Guards all TPM drivers, libraries, and PCDs.
TPM2_CONFIG_ENABLEFALSEEnables Tcg2ConfigDxe HII configuration UI.

When TPM2_ENABLE=TRUE, the build additionally passes -DTPM2_ENABLE to the C compiler via build options, allowing C code to use #ifdef TPM2_ENABLE guards.

Platform Memory Layout

The Arm Virt platform defines two distinct TPM memory regions:

RegionAddressSizeVisibility
Internal CRB0x402000000x10 pagesNormal world + Secure world
External CRB0x0c0000000x10 pagesSecure world only

The Internal CRB address is published via PCDs:

  • PcdTpmBaseAddress = 0x40200000
  • PcdTpmMaxAddress = 0x40204FFF (5 localities × 0x1000)

The Internal CRB is marked as EfiACPIMemoryNVS via a HOB in ArmPlatformLibQemu.c so the OS can locate it through the ACPI TPM2 table.

Architecture Overview

┌──────────────────────────────────────────────────────────────────────────────────┐
│ UEFI Firmware (AARCH64)                                                          │
│                                                                                  │
│  ┌─── SEC Phase ──────────────────────────────────────────────────────────────┐  │
│  │                                                                            │  │
│  │  Tpm2StartupLib                                                            │  │
│  │    │ 1. Tpm2RequestUseTpm()                                                │  │
│  │    │ 2. Tpm2Startup(TPM_SU_CLEAR)                                          │  │
│  └────┼───────────────────────────────────────────────────────────────────────┘  │
│       ▼                                                                          │
│  ┌─── DXE Phase ──────────────────────────────────────────────────────────────┐  │
│  │                                                                            │  │
│  │  HashLibBaseCryptoRouterDxe + HashInstanceLib*                             │  │
│  │    │ 1. Constructors register each enabled hash algorithm                  │  │
│  │    │ 2. Filtered by PcdTpm2HashMask → PcdTcg2HashAlgorithmBitmap           │  │
│  │    ▼                                                                       │  │
│  │  Tcg2Dxe                                                                   │  │
│  │    │ 1. Verify PcdTpmInstanceGuid is TPM 2.0                               │  │
│  │    │ 2. Verify no TpmErrorHob is present                                   │  │
│  │    │ 3. Tpm2RequestUseTpm()                                                │  │
│  │    │ 4. Query TPM capabilities                                             │  │
│  │    │     ├── Manufacturer                                                  │  │
│  │    │     ├── Firmware version                                              │  │
│  │    │     └── Max cmd/resp size                                             │  │
│  │    │ 5. Get supported/active PCR banks filtered by → HashAlgorithmBitmap   │  │
│  │    │ 6. Decide SupportedEventLogs (TCG_1_2 only if SHA1 active)            │  │
│  │    │ 7. SetupEventLog                                                      │  │
│  │    │     ├── Allocate log area(s)                                          │  │
│  │    │     └── Acquire and log pre-DXE HOB(s)                                │  │
│  │    │ 8. Register events                                                    │  │
│  │    │     ├── ReadyToBoot                                                   │  │
│  │    │     ├── ExitBootServices                                              │  │
│  │    │     └── ExitBootServices Failed                                       │  │
│  │    │ 9. Register protocol notifies                                         │  │
│  │    │     ├── VariableWriteArch (SecureBoot)                                │  │
│  │    │     └── ResetNotification (TPM shutdown)                              │  │
│  │    │ 10. Install Tcg2Protocol                                              │  │
│  │    ▼                                                                       │  │
│  │  Tcg2AcpiFfa                                                               │  │
│  │    │ 1. Publish TPM2 ACPI table                                            │  │
│  │    │ 2. Publish SSDT with TPM0 device node                                 │  │
│  └────┼───────────────────────────────────────────────────────────────────────┘  │
│       ▼                                                                          │
│  ┌─── BDS Phase ──────────────────────────────────────────────────────────────┐  │
│  │                                                                            │  │
│  │  DeviceBootManagerAfterConsole                                             │  │
│  │    │ 1. Tcg2PhysicalPresenceLibProcessRequest (NULL)                       │  │
│  │    │ 2. Process any pending PP request before shell launch                 │  │
│  │    │ 3. Create TCG2_PHYSICAL_PRESENCE_VARIABLE if it doesn't exist         │  │
│  └────┼───────────────────────────────────────────────────────────────────────┘  │
│       ▼                                                                          │
│  ┌─── UEFI Shell ─────────────────────────────────────────────────────────────┐  │
│  │                                                                            │  │
│  │  UEFI Shell / OS / TpmShellApp                                             │  │
│  │    │ 1. gBS->LocateProtocol(&gEfiTcg2ProtocolGuid)                         │  │
│  │    │ 2. Tcg2Protocol->GetCapability / SetActivePcrBanks / etc.             │  │
│  └────┼───────────────────────────────────────────────────────────────────────┘  │
│       ▼                                                                          │
│  Tpm2DeviceLibFfa ─ writes to Internal CRB @ 0x40200000                          │
│       │             then sends FF-A DirectReq2 to the TpmService                 │
│       │                                                                          │
├───────┼──────────────────────────────────────────────────────────────────────────┤
│ EL3 (SPMC / TF-A) ─ routes FF-A message to partition 0x8002                      │
├───────┼──────────────────────────────────────────────────────────────────────────┤
│       ▼                                                                          │
│ SECURE WORLD (SEL1)                                                              │
│                                                                                  │
│  MSSP (MsSecurePartition, id=0x8002)                                             │
│       │                                                                          │
│       ▼                                                                          │
│  TpmServiceLib ─ State machine (IDLE → READY → COMPLETE → IDLE)                  │
│       │                                                                          │
│       ▼                                                                          │
│  TpmServiceStateTranslationLib ─ Translates CRB style communications             │
│       │                          to the style supported by the TPM               │
│       │                          i.e. FIFO for QEMU Arm Virt                     │
│       │  Library Responsibilities:                                               │
│       │  1. Copy command from Internal CRB → local buffer                        │
│       │  2. Write command to External CRB @ 0x0c000000                           │
│       │  3. Trigger execution on external TPM through the CRB MMIO               │
│       │  4. Read response from External CRB                                      │
│       │  5. Copy response back to Internal CRB                                   │
│       │                                                                          │
├───────┼──────────────────────────────────────────────────────────────────────────┤
│       ▼                                                                          │
│  QEMU TPM device (MMIO @ 0x0c000000)                                             │
│       │                                                                          │
│       ▼                                                                          │
│  Unix socket ─ swtpm process (--tpm2)                                            │
└──────────────────────────────────────────────────────────────────────────────────┘

Secure Partitions

Two FF-A Secure Partitions are involved in TPM operations.

MSSP — Microsoft Secure Services Partition (id=0x8002)

Configured in Platforms/QemuArmVirtPkg/fdts/qemu_virt_mssp_rust_config.dts:

PropertyValue
Partition ID0x8002
Exception LevelSEL1
Execution StateAARCH64
Load Address0x0e700000
Image Size4 MiB
Boot Order2

The MSSP hosts the TPM service and is granted access to both CRB regions:

device-regions {
    internal_tpm_crb {
        base-address = <0x40200000>;
        pages-count = <0x10>;
        attributes = <SECURE_RW>;
    };
    external_tpm_crb {
        base-address = <0x0c000000>;
        pages-count = <0x10>;
        attributes = <SECURE_RW>;
    };
};

The MSSP publishes three service UUIDs. The TPM service UUID is:

17b862a4-1806-4faf-86b3-089a58353861

Key libraries running inside the MSSP:

  • TpmServiceLib — handles incoming FF-A messages, implements the CRB state machine (IDLE → cmdReady → READY → start → COMPLETE → goIdle → IDLE). Note that this service is based on the CRB over FF-A specification released by ARM. See: TPM Service Command Response Buffer Interface Over FF-A
  • TpmServiceStateTranslationLib — translates between the Internal CRB (CRB interface) and the External CRB (which may be CRB or FIFO depending on QEMU configuration). On QEMU Arm Virt the external interface is FIFO.

StMM — Standalone MM Partition (id=0x8001)

Configured in Platforms/QemuArmVirtPkg/fdts/qemu_virt_stmm_config.dts:

PropertyValue
Partition ID0x8001
Exception LevelSEL0
Execution StateAARCH64
Load Address0x0e400000
Image Size3 MiB
Boot Order0

The StMM partition hosts secure variable storage (FTW, VariableRuntimeDxe), and the Tcg2StandaloneMmArm driver which processes Physical Presence Interface commands from the normal world for NV variable access.

CRB Regions

CRB Register Layout (PTP CRB Interface)

Each locality occupies 0x1000 bytes. The CRB register layout is defined by the TCG PC Client Platform TPM Profile (PTP) specification (and mirrored in TpmPtp.h):

Internal CRB (0x40200000)

This is the CRB visible to normal-world firmware (DXE drivers and UEFI applications). Tpm2DeviceLibFfa writes TPM commands into this CRB's data buffer and reads responses from it. The Internal CRB uses the standard CRB register interface. It is the TPM service's responsibility to set up and maintain this region. The goal is for this region to mimic a normal MMIO CRB region, with the added caveat that an FF-A message must be sent for any register modification to take effect.

The normal-world code performs MMIO writes to the CRB control registers (cmdReady, Start, goIdle) and then sends FF-A messages to notify the secure partition. The secure partition reads the command data from the Internal CRB, proxies it to the External CRB, and writes the response back.

External CRB (0x0c000000)

This is the QEMU-emulated TPM device MMIO region. It is only accessible from the secure world i.e. the TPM Service within the MSSP secure partition. On QEMU Arm Virt, this region presents a FIFO interface (not CRB), which the TpmServiceStateTranslationLib handles by detecting the interface type at initialization and using the appropriate FIFO command/response protocol (burst-count reads, data register writes).

The external CRB connects to the swtpm process through QEMU's chardev/tpmdev infrastructure:

QEMU args: -chardev socket,id=chrtpm,path={BUILD_OUTPUT_BASE}/swtpm-sock
           -tpmdev emulator,id=tpm0,chardev=chrtpm

FF-A Communication Protocol

All TPM commands from normal world to secure world use FF-A Direct Request/Response messaging (FFA_MSG_SEND_DIRECT_REQ2 / FFA_MSG_SEND_DIRECT_RESP2) to/from the TPM Service.

Service Discovery

On first use, Tpm2DeviceLibFfa discovers the TPM service partition:

ArmFfaLibGetPartitionInfo(&gTpm2ServiceFfaGuid, &TpmPartInfo);

This queries the SPMC (EL3) for the partition hosting UUID 17b862a4-1806-4faf-86b3-089a58353861, which returns partition ID 0x8002. This information can be found in the manifest of the secure partition.

Function IDs

IDNameDirectionSupported
0x0f000001TPM2_FFA_GET_INTERFACE_VERSIONNW → SWYES
0x0f000101TPM2_FFA_GET_FEATURE_INFONW → SWNO
0x0f000201TPM2_FFA_STARTNW → SWYES
0x0f000301TPM2_FFA_REGISTER_FOR_NOTIFICATIONNW → SWNO
0x0f000401TPM2_FFA_UNREGISTER_FROM_NOTIFICATIONNW → SWNO
0x0f000501TPM2_FFA_FINISH_NOTIFIEDNW → SWNO
0x1f000001TPM2_FFA_MANAGE_LOCALITYTF-A → SW onlyYES

The TPM2_FFA_START function carries a qualifier in Arg1:

QualifierValuePurpose
TPM2_FFA_START_FUNC_QUALIFIER_COMMAND0x0Execute a CRB state transition (cmdReady, start, or goIdle)
TPM2_FFA_START_FUNC_QUALIFIER_LOCALITY0x1Request or relinquish locality access

The TPM2_FFA_MANAGE_LOCALITY function carries a qualifier in Arg1:

QualifierValuePurpose
TPM2_FFA_MANAGE_LOCALITY_OPEN0x0Allows access to a locality
TPM2_FFA_MANAGE_LOCALITY_CLOSE0x1Prevents access to a locality

Note that for both TPM2_FFA_START and TPM2_FFA_MANAGE_LOCALITY Arg2 specifies the locality to take action upon.

FF-A Message Sequence (Per TPM Command)

A locality must first be requested before any commands can be sent to the TPM via that locality's CRB region. The active locality must be relinquished before another locality is requested. The entity currently engaging with the TPM is responsible for relinquishing the active locality when it is no longer in use. If the locality being requested is CLOSED, a DENIED error is returned. If the locality being relinquished is not the current active locality, a DENIED error is returned.

A single TPM command requires multiple FF-A round trips:

sequenceDiagram
    participant NW as Normal World
    participant SW as Secure World (MSSP)

    Note over NW: Write LocalityControl = request access
    NW->>SW: FFA DirectReq2(START, LOCALITY)
    Note over SW: LocalityX becomes active
    SW-->>NW: FFA DirectResp2(SUCCESS)

    Note over NW: Write CrbControlRequest = cmdReady
    NW->>SW: FFA DirectReq2(START, COMMAND)
    Note over SW: State: IDLE → READY<br/>(prepare external TPM)
    SW-->>NW: FFA DirectResp2(SUCCESS)

    Note over NW: Write command to CrbDataBuffer<br/>Write CrbControlStart = 1
    NW->>SW: FFA DirectReq2(START, COMMAND)
    Note over SW: State: READY → COMPLETE<br/>• Copy cmd from Internal CRB<br/>• Write cmd to External CRB<br/>• Trigger external TPM<br/>• Read response from External CRB<br/>• Copy response to Internal CRB
    SW-->>NW: FFA DirectResp2(SUCCESS)

    Note over NW: Read response from CrbDataBuffer<br/>Write CrbControlRequest = goIdle
    NW->>SW: FFA DirectReq2(START, COMMAND)
    Note over SW: State: COMPLETE → IDLE<br/>(idle external TPM)
    SW-->>NW: FFA DirectResp2(SUCCESS)

    rect rgba(200, 200, 200, 0.2)
        Note over NW,SW: OPTIONAL
        Note over NW: Write LocalityControl = relinquish access
        NW->>SW: FFA DirectReq2(START, LOCALITY)
        Note over SW: LocalityX is relinquished
        SW-->>NW: FFA DirectResp2(SUCCESS)
    end

If the secure partition is preempted by a non-secure interrupt during processing, the FF-A call returns EFI_INTERRUPT_PENDING. The normal-world code handles this by calling ArmFfaLibRun() in a loop until the operation completes. Note that this can only happen if ns-interrupts-action in the secure partition's manifest is set to 0x02, otherwise, the non-secure interrupt is queued and the service continues execution until it completes or responds with a YIELD.

Hash Library Architecture

Tcg2Dxe uses HashLibBaseCryptoRouterDxe with all hash instance libraries included.

Registration Flow

  1. HashLibBaseCryptoRouterConstructor resets PcdTcg2HashAlgorithmBitmap to 0.
  2. Each HashInstanceLib constructor calls RegisterHashInterfaceLib().
  3. RegisterHashInterfaceLib() checks the algorithm against PcdTpm2HashMask (0x02 = SHA256 only). Algorithms not in the mask return EFI_UNSUPPORTED.

Hash Algorithm Bitmask Values

The bit positions used in PcdTpm2HashMask, PcdTcg2HashAlgorithmBitmap, and the EFI_TCG2_BOOT_SERVICE_CAPABILITY.HashAlgorithmBitmap field are defined by the EFI TCG2 protocol and the TCG algorithm registry:

For this platform, PcdTpm2HashMask = 0x02 enables SHA256 only.

Filtering Chain

PcdTpm2HashMask (0x02)
        │
        ▼
RegisterHashInterfaceLib() ── gates which HashInstanceLibs register
        │
        ▼
PcdTcg2HashAlgorithmBitmap ── result of all successful registrations
        │
        ▼
Tcg2Dxe intersects with TPM-reported capabilities
        │
        ▼
Final ActivePcrBanks / HashAlgorithmBitmap in EFI_TCG2_BOOT_SERVICE_CAPABILITY

Physical Presence Interface

Library Selection

TPM2_ENABLELibraryBehavior
FALSETcg2PhysicalPresenceLibNullAll functions stubbed
TRUEDxeTcg2PhysicalPresenceMinimumLibAuto-confirms Clear; rejects all other operations

The MinimumLib implementation:

  • Auto-confirms TPM Clear operations without user prompting.
  • Rejects SET_PCR_BANKS, LOG_ALL_DIGESTS, and other operations with TCG_PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE.
  • Does not create or use TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE.

ProcessRequest in BDS

Tcg2PhysicalPresenceLibProcessRequest() is invoked from the platform's DeviceBootManagerLib during DeviceBootManagerAfterConsole(), before the shell launches. It:

  1. Reads the Tcg2PhysicalPresence NV variable (creates it if missing).
  2. Executes any pending PP request stored in the variable.
  3. Stores the result back for ReturnOperationResponseToOsFunction() to report.

Tcg2StandaloneMmArm (Secure World)

The Tcg2StandaloneMmArm driver runs in the StMM partition (id=0x8001). It handles Physical Presence NV variable operations when called from the DXE-phase PP library via MM communicate. This is necessary because NV variable writes go through the secure variable store in StMM.

ACPI Integration

TPM2 ACPI Table

Published by Tcg2AcpiFfa.c:

FieldValue
Start MethodCRB with FF-A (0x0C)
Control Area AddressPcdTpmBaseAddress + 0x40
Command BufferPcdTpmBaseAddress + 0x80, size 0xF80
Response BufferPcdTpmBaseAddress + 0x80, size 0xF80
Platform ParametersPartition ID from PcdTpmServiceFfaPartitionId

TPM ACPI Device (SSDT)

An SSDT is published with a TPM0 device node containing:

  • _HID patched with the TPM manufacturer ID read from hardware.
  • _CRS with a QWordMemory resource pointing to PcdTpmBaseAddress through PcdTpmMaxAddress.
  • _DSM implementing TCG PPI operations 1–8 for OS-initiated Physical Presence requests.
  • An FFixedHw OperationRegion for FF-A DirectReq2 passthrough from the OS.

swtpm Setup

Installation

swtpm requires Unix sockets, so it must run in a Linux environment. On Windows, use WSL (Windows Subsystem for Linux).

# Windows (from a WSL terminal)
wsl --install          # if WSL is not yet enabled
wsl                    # enter the WSL environment

# Ubuntu/Debian (native or WSL)
sudo apt install swtpm swtpm-tools

# Fedora
sudo dnf install swtpm swtpm-tools

Manual Setup

Create the TPM state directory and start swtpm before launching QEMU:

mkdir -p /tmp/mytpm1
swtpm socket \
  --tpmstate dir=/tmp/mytpm1 \
  --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \
  --tpm2 \
  --log level=20

Automatic Setup (QemuRunner)

When SWTPM_ENABLE=TRUE, QemuRunner.py automatically starts swtpm as a subprocess before launching QEMU. The swtpm state directory is set to BUILD_OUTPUT_BASE and the Unix socket is placed at {BUILD_OUTPUT_BASE}/swtpm-sock:

# Platforms/QemuArmVirtPkg/Plugins/QemuRunner/QemuRunner.py
@staticmethod
def StartSwTpm(tpm_dir, tpm_sock):
    """Starts the swtpm emulator and returns its Popen handle."""
    cmd = [
        "swtpm", "socket",
        "--tpmstate", f"dir={tpm_dir}",
        "--ctrl", f"type=unixio,path={tpm_sock}",
        "--tpm2",
        "--log", "level=1",
    ]
    return subprocess.Popen(cmd)

swtpm is started before QEMU launches. QemuRunner then waits (up to 30 seconds) for the Unix socket to appear before starting QEMU, and terminates the swtpm process so it doesn't outlive the run. SWTPM is enabled by default. Disable it by setting SWTPM_ENABLE=FALSE on the command line or in the BuildConfig.conf file.

Note

SWTPM is only available on Linux builds. QemuRunner automatically disables it on Windows hosts even if SWTPM_ENABLE=TRUE.

QEMU Arguments

When SWTPM_ENABLE=TRUE, QemuRunner.py adds the following to the QEMU command line (with the socket path under BUILD_OUTPUT_BASE):

-chardev socket,id=chrtpm,path={BUILD_OUTPUT_BASE}/swtpm-sock
-tpmdev emulator,id=tpm0,chardev=chrtpm
-device tpm-tis-device,tpmdev=tpm0

The -device tpm-tis-device argument is Arm-specific. It attaches a sysbus TIS-compatible TPM device to the Arm Virt machine at the Internal CRB address 0x40200000. This differs from Q35, which uses the ISA/PCI tpm-tis device instead (see TPM on QEMU Q35).

Communication Flow

Complete path from a shell application to swtpm:

TpmShellApp (UEFI Shell)
  │ gBS->LocateProtocol(&gEfiTcg2ProtocolGuid)
  │ Tcg2Protocol->SetActivePcrBanks(0x02)
  ▼
Tcg2Dxe (EFI_TCG2_PROTOCOL)
  │ Validates bank mask against HashAlgorithmBitmap
  │ Calls Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction()
  │   ├── MinimumLib: rejects SET_PCR_BANKS → returns EFI_UNSUPPORTED
  │   └── MinimumLib: NO_ACTION (already-active) → writes to NV variable → EFI_SUCCESS
  ▼
Tpm2CommandLib (for direct TPM commands like GetCapability)
  │ Serializes TPM2_CC command structure into byte buffer
  │ Calls Tpm2SubmitCommand(cmdBuffer, cmdSize, rspBuffer, &rspSize)
  ▼
Tpm2DeviceLibFfa — FfaTpm2SubmitCommand()
  │ PtpCrbTpmCommand(CrbReg = PcdTpmBaseAddress)
  │
  │ ┌─ STEP 1: cmdReady ──────────────────────────────────────────┐
  │ │  MmioWrite32(&CrbReg->CrbControlRequest, PTP_CRB_CONTROL    │
  │ │              _AREA_REQUEST_COMMAND_READY)                   │
  │ │  Tpm2ServiceStart(QUALIFIER_COMMAND, 0) ── FF-A ──► MSSP    │
  │ └─────────────────────────────────────────────────────────────┘
  │
  │ ┌─ STEP 2: submit ────────────────────────────────────────────┐
  │ │  CopyMem(CrbReg->CrbDataBuffer, cmdBuffer, cmdSize)         │
  │ │  MmioWrite32(&CrbReg->CrbControlStart, 1)                   │
  │ │  Tpm2ServiceStart(QUALIFIER_COMMAND, 0) ── FF-A ──► MSSP    │
  │ └─────────────────────────────────────────────────────────────┘
  │
  │                    ════ WORLD SWITCH ════
  │
  │   MSSP (secure world, partition 0x8002):
  │     TpmServiceLib: state READY → execute
  │     TpmServiceStateTranslationLib:
  │       1. Read command from Internal CRB data buffer
  │       2. CopyCommandData() → write to External CRB @ 0x0c000000 (FIFO)
  │       3. StartCommand() → trigger TPM execution
  │       4. CopyResponseData() → read response from External CRB
  │       5. Write response to Internal CRB data buffer
  │
  │                    ════ QEMU MMIO ════
  │
  │     QEMU TPM device @ 0x0c000000
  │       └── Unix socket ──── swtpm process
  │
  │                    ════ WORLD SWITCH BACK ════
  │
  │ ┌─ STEP 3: goIdle ────────────────────────────────────────────┐
  │ │  Read response from CrbReg->CrbDataBuffer                   │
  │ │  MmioWrite32(&CrbReg->CrbControlRequest, PTP_CRB_CONTROL    │
  │ │              _AREA_REQUEST_GO_IDLE)                         │
  │ │  Tpm2ServiceStart(QUALIFIER_COMMAND, 0) ── FF-A ──► MSSP    │
  │ └─────────────────────────────────────────────────────────────┘
  ▼
Response returned to caller

PCDs Reference

Required PCDs (set when TPM2_ENABLE=TRUE)

PCDValueTypePurpose
PcdTpmBaseAddress0x40200000FixedAtBuildInternal CRB base address
PcdTpmMaxAddress0x40204FFFFixedAtBuildInternal CRB end address (5 localities)
PcdTpm2HashMask0x02DynamicDefaultHash algorithm filter (SHA256 only)
PcdTpmInstanceGuidgEfiTpmDeviceInstanceTpm20DtpmGuidFixedAtBuildSelects discrete TPM 2.0 device type
PcdTpm2AcpiTableRev5DynamicHiiACPI TPM2 table revision
PcdUserPhysicalPresenceFALSEFixedAtBuildNo physical user presence assertion

Memory Type PCDs

PCDValuePurpose
PcdMemoryTypeEfiACPIReclaimMemory0x143ACPI reclaim memory pages (includes TPM ACPI tables)
PcdMemoryTypeEfiACPIMemoryNVS0x3CACPI NVS pages (includes CRB region)
PcdMemoryTypeEfiRuntimeServicesData0x642Runtime services data pages
PcdMemoryTypeEfiRuntimeServicesCode0x424Runtime services code pages
PcdMemoryTypeEfiReservedMemoryType0x505Reserved memory pages

Conditional PCDs (TPM2_CONFIG_ENABLE=TRUE)

PCDValuePurpose
PcdTcgPhysicalPresenceInterfaceVer"1.3"TCG PPI specification version reported to OS