Skip to content

feat(tpm): TPM 2.0 CRB kernel driver + syscall ABI for WasmOS-on-Nanos - #1

Draft
zacharywhitley wants to merge 8 commits into
masterfrom
wasmos/tpm-crb-transport
Draft

feat(tpm): TPM 2.0 CRB kernel driver + syscall ABI for WasmOS-on-Nanos#1
zacharywhitley wants to merge 8 commits into
masterfrom
wasmos/tpm-crb-transport

Conversation

@zacharywhitley

@zacharywhitley zacharywhitley commented Aug 4, 2026

Copy link
Copy Markdown

Summary

Adds a TPM 2.0 Command Response Buffer (CRB) transport driver plus a
two-syscall user ABI to the Nanos kernel, per WasmOS ADR-0019
(Phase N2)
and the accepting design at
docs/design/nanos-tpm-crb-transport.md in the wasmos repository.

The change lands as four commits:

  1. tpm: add TPM 2.0 CRB transport driver - state machine, single-in-flight
    transport, discovery pipeline, recovery flow, per-instance timeouts.
    Companion design sections 4 and 8.
  2. tpm: add nanos_tpm_command / nanos_tpm_status syscalls - user-facing
    ABI with argument validation, per-call kernel-owned scratch buffers,
    errno mapping. Companion design section 5.
  3. feat(tpm): wire TPM 2.0 CRB driver + syscalls into Nanos build -
    Nanos-integration commit: relocates from kernel/tpm/ to src/tpm/,
    adapts the two scaffold patches to real Nanos internals, wires the
    files into the pc platform Makefile, registers the syscall
    dispatch entries, and calls init_tpm(kh) from detect_devices().
  4. feat(tpm): implement ACPI TPM2 table discovery - replaces the
    placeholder try_discover_acpi() with a real ACPICA-backed lookup
    of the TPM2 table (design sec 4.4). Adds TPM_ERR_UNSUPPORTED for
    non-CRB start methods and changes the discovery fallback chain to
    fall through on any non-OK stage so the QEMU fixed-base remains a
    safety net.

The first two commits are the scaffold patches from the wasmos repo
applied verbatim (see deploy/nanos/patches/README.md there); commits
three and four are where the Nanos-specific wiring lives.

User-facing ABI (design section 5)

long nanos_tpm_command(
    const void *command, size_t command_length,
    void *response, size_t response_capacity,
    size_t *response_length,
    uint64_t timeout_ns);

long nanos_tpm_status(struct nanos_tpm_status_abi *out);

Syscall numbers (x86_64 only): SYS_nanos_tpm_command = 500,
SYS_nanos_tpm_status = 501, SYS_MAX = 502.

Return codes: 0, -EINVAL, -EOPNOTSUPP, -ETIMEDOUT, -EIO,
-EAGAIN, -EFAULT. These map 1-to-1 to the driver's internal
TPM_ERR_* values per design section 5.2.

Scope

  • x86_64 / pc platform only. The virt (aarch64) and riscv-virt
    platforms deliberately do NOT get the driver or syscall wiring; the
    wasmos-on-Nanos design targets x86_64 QEMU exclusively.
  • The kernel is a raw single-caller-serialized transport. All key
    management, policy, and session state lives above the kernel in the
    wasmos-security crate.
  • On hosts without a TPM the discovery chain declines cleanly and the
    syscall layer returns -EOPNOTSUPP. This is a supported deployment
    shape.

Discovery order (design sec 4.4)

  1. ACPI TPM2 table via AcpiGetTable(ACPI_SIG_TPM2, ...). Accepts
    StartMethod 7 (COMMAND_BUFFER / CRB) and 11 (CRB with ARM SMC);
    any other start method surfaces as TPM_ERR_UNSUPPORTED.
  2. Platform-provided device description - stub for a per-platform
    follow-up.
  3. Nanos boot manifest - stub for a per-platform follow-up.
  4. Fixed QEMU CRB base 0xFED40000 as the final safety net.

Deviations from the wasmos-side design forced by Nanos internals

The scaffold patches (commits 1 and 2) assumed a plausible-but-not-real
Nanos API surface. Commit 3 documents each substitution; the notable
ones are:

  • Nanos status is a tuple type. The driver's error-code return type
    is int using the TPM_ERR_* enumeration.
  • Nanos mutexes are allocated via allocate_mutex(heap, spin_iterations)
    and freed with deallocate(heap, mutex, sizeof(struct mutex)).
  • Nanos time comes from now(CLOCK_ID_MONOTONIC_RAW), which returns a
    fixed-point 32.32 timestamp (1s = 1<<32). The driver stores configured
    timeouts in nanoseconds (matching the user ABI) and converts via
    nanoseconds() at deadline-evaluation time.
  • MMIO mapping uses allocate() from heap_virtual_page() followed by
    map() with pageflags_writable(pageflags_device()).
  • User-pointer validation uses Nanos's validate_process_memory() and
    copy_from_user/copy_to_user; no user pointer reaches the MMIO
    layer.
  • Nanos's per-arch errno.h uses EOPNOTSUPP (95) rather than
    ENOTSUP; the syscall layer emits the former.
  • Nanos headers have no #ifndef include guards - the tpm/ headers
    therefore have none either and must be included from a .c file
    that has already brought in <kernel.h> / <unix_internal.h>.
  • ACPI TPM2 discovery uses ACPICA's existing ACPI_TABLE_TPM2 struct
    from vendor/acpica/source/include/actbl3.h; no new struct
    definitions were required.

Not landed in this PR

  • Driver unit tests. The wasmos repo ships tests/fake_mmio.{h,c},
    tests/test_tpm_crb.c, tests/test_tpm_syscall.c under
    deploy/nanos/patches/tests/. Placement against Nanos's test-harness
    convention is a separate integration patch, per design section 8.1.

Verification

  • make PLATFORM=pc kernel builds a stripped kernel.img.
  • nm kernel.elf | grep tpm shows every expected symbol:
    init_tpm, nanos_sys_tpm_command, nanos_sys_tpm_status,
    nanos_tpm_default, nanos_tpm_discover, nanos_tpm_get_health,
    nanos_tpm_transmit, register_tpm_syscalls, the_default_tpm.
  • Object-level inspection of tpm_crb.o shows relocations for
    AcpiGetTable and AcpiPutTable inside nanos_tpm_discover,
    emitted before the 0xFED40000 immediate that identifies the
    QEMU-fixed fallback path - confirming ACPI is tried first.
  • make image fails only because the host-side mkfs tool has a
    pre-existing macOS PATH_MAX collision (reproducible on master
    before these changes); the kernel binary itself is fine.
  • The kernel was NOT booted under QEMU as part of this PR - that's
    system-level testing and is deliberately deferred. ACPI discovery
    is verified structurally only; runtime observation against a
    QEMU-emitted TPM2 table is left for the boot-side follow-up.

Test plan

  • Reviewer: verify make PLATFORM=pc kernel succeeds locally on
    Linux (macOS blocks at mkfs for unrelated reasons).
  • Reviewer: sanity-check the syscall number allocation (500/501)
    against any local Nanos syscall-table policy.
  • Boot with -device tpm-crb,tpmdev=tpm0 -tpmdev emulator,id=tpm0, chardev=chrtpm -chardev socket,id=chrtpm,path=/tmp/mytpm/swtpm.sock
    and confirm init_tpm binds the default instance via the ACPI
    TPM2 table (not the QEMU fixed-base fallback); then invoke the
    syscalls from a WasmOS ELF built against wasmos-platform-nanos.

References

  • WasmOS ADR-0019 (Phase N2, Deferred feat(tpm): TPM 2.0 CRB kernel driver + syscall ABI for WasmOS-on-Nanos #1 - Option A out-of-tree
    patches ratified in wasmos commit db19646).
  • Design doc: docs/design/nanos-tpm-crb-transport.md in the wasmos
    repo. All commit messages cite section numbers.
  • TCG PC Client Platform TPM Profile - CRB interface, Table 8-1.
  • TCG ACPI Specification, Family 2.0, Rev 1.2 Rev 8 - TPM2 table
    shape (ACPI_TABLE_TPM2 in ACPICA's actbl3.h).

WasmOS Nanos Fork and others added 4 commits August 3, 2026 22:04
Introduces a TPM 2.0 Command Response Buffer (CRB) transport driver
for use by WasmOS on Nanos. This patch is scaffolded per the
companion design in the wasmos repository:

    docs/design/nanos-tpm-crb-transport.md  (Sections 4, 6, 8)

Structure:

- Portable MMIO register access layer (crb_mmio_ops) with a fake-MMIO
  seam for driver unit tests (Section 8.1).
- tpm_state state machine + nanos_tpm object (Section 4.1, 4.2).
- nanos_tpm_transmit() single-in-flight transport with distinct
  transport vs TPM error classes, deadline handling, and buffer
  zeroization (Section 4.3).
- Discovery pipeline: ACPI TPM2 -> platform description -> fixed
  QEMU dev address, all guarded by interface-register validation
  (Section 4.4).
- Recovery flow: cancel -> reset -> revalidate -> mark unhealthy
  (Section 4.5).
- Per-instance timeouts for locality / readiness / execution /
  cancellation / recovery (Section 4.6).

Portability note: this patch INTENTIONALLY DOES NOT wire the driver
into the Nanos build system. That step (Makefile / module list /
init-order registration) is Nanos-fork-specific and must be applied
against a chosen upstream Nanos SHA by the maintainer.

The header comment at the top of each new file names the intended
Nanos tree path; adjust to fit the target checkout.

Reviewed-by: WasmOS ADR-0019 (Phase N2)
Adds the two application-facing syscalls specified in the companion
design doc §5:

    long nanos_tpm_command(const void *command,
                           size_t command_length,
                           void *response,
                           size_t response_capacity,
                           size_t *response_length,
                           uint64_t timeout_ns);

    long nanos_tpm_status(struct nanos_tpm_status *out);

Design constraints honoured here:

- Argument validation at the syscall boundary (§5.2).  Every buffer
  address is bounds-checked against the calling process's memory map
  BEFORE the underlying driver is invoked.  No user pointer reaches
  the MMIO layer directly.
- Command and response bytes are copied into kernel-owned buffers
  allocated per-call, then zeroed after use — the CRB command buffer
  may still contain secrets after a signing operation.
- Distinct errno-style return codes (0 / -EINVAL / -ENOTSUP /
  -ETIMEDOUT / -EIO / -EAGAIN) map 1:1 from the driver's TPM_ERR_*
  values, per §5.2.
- nanos_tpm_status returns the SAME enum values the kernel driver
  uses internally (§5.3) so wasmos-platform-nanos can compare
  against symbolic names.

Portability note: this patch INTENTIONALLY DOES NOT wire the
syscalls into a specific Nanos syscall table.  The integration
commit against the target Nanos SHA must register the two functions
in whatever the kernel's syscall-dispatch mechanism is (a static
table, a runtime registration, etc.).

Reviewed-by: WasmOS ADR-0019 (Phase N2)
Adapts the two scaffold patches (2d79412, 8d8d4ec) to the actual
Nanos source layout and internal APIs, and wires them into the build,
syscall dispatch table, and kernel-init sequence.

Relocation
----------
kernel/tpm/  ->  src/tpm/

Nanos keeps kernel source under src/, not kernel/. Files are relocated
via git mv so review tooling can render them as renames; the syscall
files were substantially rewritten and appear as delete + add.

Nanos-internal API adaptations
------------------------------
The scaffold patches used a plausible-but-not-real Nanos API surface.
The following substitutions were required against the real tree:

  scaffold identifier        real Nanos identifier
  -------------------        ---------------------
  status (int type)          int + TPM_ERR_*  (Nanos's `status` is
                             a tuple - see src/runtime/status.h)
  mutex_new(),               allocate_mutex(heap,
    mutex_free()               spin_iterations); deallocate() over
                               sizeof(struct mutex)
  allocate(size),            allocate(heap, size),
    allocate_zero(size),       allocate_zero(heap, size),
    deallocate(ptr, sz)        deallocate(heap, ptr, sz)
                             heap is heap_locked(get_kernel_heaps())
  now()                      now(CLOCK_ID_MONOTONIC_RAW)
  kernel_yield()             kern_pause()
  TIMESTAMP_INFINITY,        Nanos uses fixed-point timestamps
    deadline_min()             (1s = 1<<32); timeouts convert via
                               nanoseconds() and compare directly
  map_mmio_region(),         allocate() from heap_virtual_page then
    unmap_mmio_region()        map()/unmap() with pageflags_device()
  process_copy_from_user,    copy_from_user, copy_to_user,
    process_copy_to_user,      validate_process_memory
    process_check_user_range
  ENOTSUP                    EOPNOTSUPP (Nanos uses the POSIX-2001
                             spelling in src/kernel/errno.h)
  process p argument         current->p via <unix_internal.h>

Header layout
-------------
Nanos headers deliberately have no #ifndef include guards and rely on
runtime.h being #included exactly once by each translation unit. The
scaffold's guarded, self-including headers were re-shaped to match:
tpm_crb.h and tpm_crb_mmio.h drop their guards and their <kernel.h>
include; the .c files pull in <kernel.h> or <unix_internal.h> and then
the tpm/ headers via <tpm/...>.

Build wiring
------------
platform/pc/Makefile adds src/tpm/tpm_crb.c and src/tpm/tpm_syscall.c
to SRCS-kernel.elf. The virt (aarch64) and riscv-virt platforms are
NOT wired: the wasmos-on-Nanos design (ADR-0019, docs/design/
nanos-tpm-crb-transport.md) is x86_64/QEMU-only, and the syscall
number allocation is x86_64-specific.

Syscall dispatch
----------------
src/x86_64/unix_syscalls.h allocates:

  SYS_nanos_tpm_command   500
  SYS_nanos_tpm_status    501
  SYS_MAX                 502   (was 451)

Both numbers sit well above the current Linux top-of-table so a future
Nanos rebase against a newer Linux syscall set cannot collide. src/unix/
unix.c invokes register_tpm_syscalls(linux_syscalls) from init_syscalls,
guarded by __x86_64__.

Kernel init
-----------
platform/pc/service.c detect_devices() calls init_tpm(kh) after
init_acpi(kh). The driver's discovery pipeline runs (ACPI -> platform
-> manifest -> QEMU fixed base); on hosts with no TPM the fallback
declines cleanly and the syscall layer reports -EOPNOTSUPP.

Verified
--------
make PLATFORM=pc kernel builds a stripped kernel.img (1.55 MB) with
all TPM symbols present in kernel.elf: init_tpm, nanos_sys_tpm_command,
nanos_sys_tpm_status, nanos_tpm_default, nanos_tpm_discover,
nanos_tpm_get_health, nanos_tpm_transmit, register_tpm_syscalls,
the_default_tpm.

`make image` fails only because the host-side mkfs tool has a
pre-existing macOS PATH_MAX collision (reproducible on master before
these changes); it does not affect the kernel binary.

Not landed in this commit
-------------------------
- ACPI TPM2 table lookup (try_discover_acpi) still returns NO_DEVICE;
  QEMU fixed-base fallback is the sole live discovery path. Filed for
  a follow-up commit against Nanos's AcpiGetTable interface.
- The tests/ scaffolds shipped alongside the two patches remain
  outside the kernel tree; they need placement against Nanos's test
  harness convention and are the subject of a separate integration
  patch per the design doc sec 8.1.

Companion design: docs/design/nanos-tpm-crb-transport.md (wasmos repo).
Reviewed-by: WasmOS ADR-0019 (Phase N2).
Replaces the placeholder try_discover_acpi() with a real ACPICA-backed
lookup of the TPM2 table. When present, the table's ControlAddress
supplies the CRB MMIO base, replacing the QEMU-only 0xFED40000
hard-code that had been the sole live discovery path.

Discovery flow (design doc sec 4.4):
  1. AcpiGetTable(ACPI_SIG_TPM2, ...) - primary.
  2. Platform description - stub (per-platform follow-up).
  3. Boot manifest - stub (per-platform follow-up).
  4. QEMU fixed 0xFED40000 base - final fallback, preserved for
     bare-hardware and dev QEMU setups that omit an ACPI TPM2 table.

Only StartMethod 7 (COMMAND_BUFFER / CRB) and 11 (CRB with ARM SMC)
are accepted. Any other start method returns the new TPM_ERR_UNSUPPORTED
so callers can distinguish "no TPM" from "TPM present but not CRB".

The fallback chain now short-circuits on TPM_ERR_OK rather than only
falling through on TPM_ERR_NO_DEVICE, so an unsupported ACPI TPM2 or a
transient mapping failure still lets the QEMU fallback attempt discovery.

Uses ACPICA's ACPI_TABLE_TPM2 definition
(vendor/acpica/source/include/actbl3.h); no new struct definitions
required. The MMIO window length isn't reported by the ACPI table, so
we map the same 0x5000 span used by the QEMU fallback - enough for the
CRB register block plus localities 0..4 per TCG PC Client CRB spec
Table 8-1.
@zacharywhitley

Copy link
Copy Markdown
Author

Follow-up landed as commit 5902ec8: feat(tpm): implement ACPI TPM2 table discovery.

try_discover_acpi() now performs a real AcpiGetTable(ACPI_SIG_TPM2, ...) lookup, validates the header, extracts ControlAddress + StartMethod, and maps the CRB control area at the address the firmware reports. Only start methods 7 (COMMAND_BUFFER / CRB) and 11 (CRB with ARM SMC) are accepted; any other start method surfaces the new TPM_ERR_UNSUPPORTED. The discovery fallback chain now short-circuits on TPM_ERR_OK (rather than only on TPM_ERR_NO_DEVICE), so unsupported start methods or transient mapping failures still fall through to platform description -> boot manifest -> QEMU fixed base at 0xFED40000.

No new struct definitions were needed - ACPICA already exposes ACPI_TABLE_TPM2 and the ACPI_TPM2_* start-method constants in vendor/acpica/source/include/actbl3.h. Build clean: make PLATFORM=pc kernel. Object inspection of tpm_crb.o confirms AcpiGetTable / AcpiPutTable relocations appear before the 0xFED40000 immediate inside nanos_tpm_discover, so ACPI is tried before the QEMU fallback.

Verified structurally only - runtime observation against a QEMU-emitted TPM2 table is left for the boot-side follow-up.

ACPI TPM2 ControlAddress is CRB-control-area-aligned (0x40 offset per
TCG PC Client CRB Table 8-1), not page-aligned. Nanos's map() asserts
page-aligned physical bases and panicked in Q1'26 boot verify. Round
the base down, pad the length, offset register accesses accordingly.

Fixes the assertion at src/kernel/page.c:551 hit from nanos_tpm_discover
-> tpm_map_mmio -> map() call chain on ACPI-driven discovery.
@zacharywhitley

Copy link
Copy Markdown
Author

Q1'26 boot-verify follow-up: pushed a page-alignment fix (881e9cf) after hitting an assertion panic on ACPI-driven discovery.

Panic trace (before fix):

frame trace:
  map + 0x16b   -> assertion (p & PAGEMASK) == 0 failed at src/kernel/page.c:551
  nanos_tpm_discover + 0x1fb
  init_tpm + 0x2a
  detect_devices + 0x6b

Root cause: try_discover_acpi() was reading ACPI_TABLE_TPM2.ControlAddress verbatim and passing it to tpm_map_mmio(). Per TCG PC Client CRB Table 8-1, ControlAddress sits on a 0x40 boundary within the locality register block (the Control Area), not a page boundary. Nanos's map() asserts page-aligned physical bases, so the driver panicked as soon as an ACPI TPM2 table was present (QEMU q35/pc + -device tpm-crb on any recent QEMU emits one).

Fix: tpm_map_mmio() now rounds the physical base down to a page, pads the length to cover the intra-page offset, and returns a virtual pointer with the offset baked back in — callers keep indexing registers as mmio_base + REG_OFF unchanged. tpm_unmap_mmio() mirrors the arithmetic. Verified: kernel rebuilds clean (make PLATFORM=pc kernel), no assertion panic on next boot with qemu-system-x86_64 -accel tcg -device tpm-crb,tpmdev=... -tpmdev emulator,....

Not-fixed follow-up (out of scope for this PR): post-alignment-fix, boot verification reaches the wasmos-nanos-node JSON summary with "tpm":{"present":false} — kernel discovery still falls through all four stages. Suspect areas worth a diagnostic pass:

  1. try_discover_acpi() uses ControlAddress verbatim as mmio_base, but tpm_crb_mmio.h's register offsets (LOC_STATE=0x00, INTF_ID=0x30, CTRL_REQ=0x40, ...) are locality-block-relative, not Control-Area-relative — every ACPI-path register access is off by 0x40.
  2. crb_interface_plausible() accepts only TYPE == 0x1 (CRB active); QEMU / hardware combined-mode devices report 0xF (TIS+CRB) and get rejected.

Recommend a separate follow-up PR with tracing added to each discovery stage so we can confirm which of the two above (or a third factor) is the real blocker before landing further changes. Alignment fix is standalone-mergeable per the panic trace above.

…U/hardware

Two ACPI-path bugs surfaced during Phase N3 boot verification, both of
which left nanos_tpm_default() == NULL despite a working tpm-crb device
attached to QEMU:

1. Locality-vs-Control-Area offset. The ACPI TPM2 table's ControlAddress
   field points at the CRB Control Area, which per TCG PC Client CRB
   Interface Spec Table 8-1 lives at (locality_base + 0x40). The
   driver's CRB_REG_* offsets are all locality-base-relative (LOC_STATE
   at 0x00, INTF_ID at 0x30, CTRL_REQ at 0x40, ...), so storing
   ControlAddress as mmio_base landed every subsequent register read
   0x40 bytes past its intended target. try_discover_acpi() now
   subtracts CRB_LOC_CTRL_AREA_OFFSET before mapping.

2. Interface-type strictness. crb_interface_plausible() only accepted
   TPM_INTERFACE_TYPE == 0x1 (pure CRB). QEMU's tpm-crb device and real
   Intel PTT parts report 0xF (combined FIFO+CRB), where CRB is one of
   several selectable interface modes. Both discovery paths were
   rejecting the device before the rest of the register block was ever
   consulted. The check now accepts 0x1 or 0xF, matching the Linux
   tpm_crb driver.

Also add single-line rprintf diagnostics at every discovery failure
point (silent on success): the absence of any observability into which
stage rejected the device was what forced the prior boot-verify pass to
disassemble the kernel to diagnose. init_tpm() now emits one terminal
line summarising the outcome so future regressions surface immediately
in the serial log.
@zacharywhitley

Copy link
Copy Markdown
Author

Follow-up commit 6520829f — TPM CRB discovery bug fixes surfaced during Phase N3 boot verification.

Bug A (locality-vs-Control-Area offset) — try_discover_acpi():
The ACPI TPM2 table's ControlAddress points at the CRB Control Area, which per TCG PC Client CRB Interface Spec Table 8-1 lives at (locality_base + 0x40). The driver's CRB_REG_* offsets are all locality-base-relative (LOC_STATE at 0x00, INTF_ID at 0x30, CTRL_REQ at 0x40). Storing ControlAddress verbatim as mmio_base shifted every register read 0x40 bytes past its target. Fix subtracts a new CRB_LOC_CTRL_AREA_OFFSET constant before mapping.

Bug B (interface-type strictness) — crb_interface_plausible():
Accepted only TPM_INTERFACE_TYPE == 0x1 (pure CRB). QEMU's tpm-crb device and real Intel PTT parts report 0xF (combined FIFO+CRB), matching Linux's tpm_crb driver behaviour. Check now accepts either.

Diagnostic addition:
Every discovery-stage rejection point now emits a single-line rprintf naming the reason (silent on success). init_tpm() prints one terminal summary line. The absence of this observability is what forced the prior verification pass to disassemble the kernel to isolate the failure — future regressions will surface in the serial log immediately.

Rebuilt clean with make PLATFORM=pc kernel; all 8 exported TPM symbols (init_tpm, nanos_tpm_default, nanos_tpm_discover, nanos_tpm_get_health, nanos_tpm_transmit, nanos_sys_tpm_command, nanos_sys_tpm_status, register_tpm_syscalls) still present.

Zachary Whitley added 2 commits August 4, 2026 17:14
Real TPM hardware and swtpm both refuse every command with
TPM_RC_INITIALIZE (0x100) until Startup has been called once per power
cycle. Kernel-side driver init is the correct home for that call -
having every userspace consumer emit its own Startup as a workaround
does not scale (wasmos-platform-nanos was doing exactly that; that
workaround now becomes belt-and-suspenders).

After discovery reaches TPM_STATE_READY, submit the 12-byte
TPM2_Startup(TPM_SU_CLEAR) command through nanos_tpm_transmit() using
the driver's per-instance execution timeout (design doc sec 4.6, no new
hard-coded deadline). Treat responseCode 0x00 and 0x100 as success -
the latter is the harmless "already started" idempotency case, and
occurs in practice because QEMU / swtpm may auto-start on connection.
Any other responseCode, or a transport failure, is logged via rprintf
and marks the driver TPM_STATE_FAILED so the status syscall surfaces
the condition; the driver does NOT panic - TPM policy is a userspace
concern (design doc sec 4.5).

Kernel boot under QEMU tpm-crb + swtpm now emits:
  tpm: discovery ok (source=1 cmd=0xf80 rsp=0xf80)
  tpm: startup ok (rc=0x100)
and the wasmos-platform-nanos TPM2_GetCapability probe continues to
return manufacturer="IBM" as before.
Add two userspace unit-test binaries for the TPM 2.0 CRB driver:

  test/unit/tpm_crb_test - exercises the abstract MMIO ops table
    (src/tpm/tpm_crb_mmio.h) via a table-driven fake shim, pins the
    TCG PC Client CRB register offsets and bit fields, and exercises
    the TPM 2.0 response-header length decode with valid, truncated,
    device-oversize, and caller-undersize inputs.

  test/unit/tpm_syscall_test - pins the nanos_tpm_status_abi struct
    layout, size, and version at the userspace/kernel boundary; pins
    the TPM_STATE_* / TPM_INTERFACE_* / TPM_DISCOVERY_* / TPM_ERR_*
    enumeration values; and exhaustively exercises the driver-error
    to POSIX-errno mapping used by src/tpm/tpm_syscall.c.

Scope note: the underlying tpm_crb.c and tpm_syscall.c translation
units depend on kernel-only headers (<kernel.h>, mutex, ACPICA,
kernel heaps, validate_process_memory) that this userspace test
harness deliberately does not link. Tests whose intent requires
that linkage are reported as SKIP at run time with a per-test
rationale, so the design-doc sec 8.1 coverage signal is honest
rather than hidden. Extending coverage to those items requires a
future in-kernel test facility (test/runtime or a new test/kernel)
which is out of scope here.

Supersedes the plausible-API scaffold at wasmos
deploy/nanos/patches/tests/.

  tpm_crb_test:     21 pass, 0 fail, 10 skip
  tpm_syscall_test: 15 pass, 0 fail, 10 skip
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