Skip to content

WIP: Implement TDShim support#694

Draft
jakecorrenti wants to merge 11 commits into
containers:mainfrom
jakecorrenti:td-shim
Draft

WIP: Implement TDShim support#694
jakecorrenti wants to merge 11 commits into
containers:mainfrom
jakecorrenti:td-shim

Conversation

@jakecorrenti
Copy link
Copy Markdown
Member

Implement support for TDShim, another type of firmware to run TDs with.

Upgrade tdx from 0.1.0 to 0.1.1 to enable access to the tdvf module
needed for TD-Shim support. Also update related KVM dependencies
(kvm-bindings to 0.14, kvm-ioctls to 0.24, vmm-sys-util to 0.15)
across all crates to maintain compatibility.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
@jakecorrenti jakecorrenti force-pushed the td-shim branch 3 times, most recently from f5a626c to 5c99fb9 Compare May 28, 2026 13:31
Add `tee_firmware_config` field to `VmResources` with
`set_tee_firmware_config()` accessor method. Add test to verify the
field and method work correctly.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
Expose krun_set_tee_firmware() in the C API so callers can specify a
TD-Shim binary path for TDX guests. When set, the VMM uses the given
firmware instead of the bundled qboot from libkrunfw-tdx. The path is
stored in ContextConfig and forwarded to VmResources at start time.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
…rement

Add a u32 attributes field to MeasuredRegion so each section can carry
its own TDX measurement flags (e.g. MR_EXTEND). The TDX launcher now
reads attributes from MeasuredRegion instead of inferring them from the
guest address. Existing qboot and SNP regions use attributes=0; the
qboot firmware region uses attributes=1 (measure and extend).

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
Add tdshim.rs under linux/tee/ with TdShim::parse() to open a TD-Shim
binary, extract TDVF section metadata, validate that BFV and TdHob
sections are present, and retain the raw firmware bytes. Provides
load_sections() to copy section data into guest memory with bounds
checking, and high_firmware_range() to compute the address span of
sections above the MMIO gap for memory layout purposes.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
Implement write_hob_chain() to build a UEFI Hand-Off Block list that
TD-Shim expects: PHIT header, resource descriptors for each RAM region,
a payload info HOB with the kernel entry point (RawVmLinux image type),
and an end-of-list marker. Add generate_hobs() on TdShim to write the
chain into the TdHob section of guest memory. Includes unit tests for
HOB chain structure, PHIT validation, and buffer overflow handling.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
Replace the unused firmware_size parameter with a firmware_range tuple
(start_addr, size) so the TEE memory layout can accommodate firmware at
addresses other than the fixed qboot FIRMWARE_START. TD-Shim places
sections at varying addresses; this lets the caller pass the actual
range from high_firmware_range() instead of assuming the qboot layout.
Falls back to the qboot defaults when no range is provided.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
Parse TD-Shim firmware early to extract firmware_range, pass it to
create_guest_memory so arch_memory_regions can carve the correct hole.
In the TDX measured_regions block, branch on td_shim_parsed: load
sections, build RAM HOBs (excluding the firmware hole), write the HOB
chain, collect per-section MeasuredRegions, and return the HOB address.
Pass that address to tdx_secure_virt_init_vcpus instead of 0.

Also fix five MeasuredRegion initializers in amdsnp/mod.rs that were
missing the attributes field added in an earlier task.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
Add --td-shim flag to specify a TD-Shim firmware binary. Configure a
serial console on ttyS0 for kernel output, a virtio console for the
shell, and disable the implicit console to prevent I/O redirection to
/dev/null. Use RAW disk format and set up split irqchip for TDX.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
…e to example

For the TD-Shim boot path, load_cmdline is now called to write the kernel
command line string to CMDLINE_START (0x20000). configure_system already
sets cmd_line_ptr in boot_params to point there, so TD-Shim can reference
the cmdline when setting up the Linux boot environment.

The launch-tee example now adds a legacy serial device (ttyS0) wired to
stdout so early kernel boot messages are visible. The kernel cmdline must
include console=ttyS0 for output to appear.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
td-shim (RawVmLinux) creates boot_params without ramdisk_image/ramdisk_size.
Write a 34-byte x86_64 trampoline into the HOB section and the firmware
sections into guest memory BEFORE setup_vm()/memory_init(), while pages are
still plain anonymous mmap. After KVM registers the memory slots, TDH.MEM.PAGE.ADD
copies the shared content to the TD's private memory, so writing before that
point guarantees the TD sees the trampoline.

The trampoline patches td-shim's boot_params (RSI) with the libkrunfw
initrd location (INITRD_SEV_START = 0xa00000) and size before jumping
to startup_64, letting the kernel find and unpack the initrd normally.

Assisted-by: Claude Code: claude-sonnet-4-6
Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant