Skip to content

Document the Resolver system #2931

@mattkur

Description

@mattkur

Document the Resolver system

Summary

The resolver system is a core architectural pattern in OpenVMM, but it does not have dedicated documentation yet. This issue covers what should be documented, where it should live, and how to structure it so a new contributor can understand and use the resolver pattern without reverse-engineering existing implementations.


What the resolver system is

The resolver system lives in vm/vmcore/vm_resource/ and is a type-erased, composable resource dependency injection framework. It solves a specific architectural problem: devices need backing resources (disks, network endpoints, serial backends, etc.), but the device code should not be statically coupled to every possible backend implementation.

The key insight is that resource descriptions are serialized via mesh as opaque messages, then resolved at runtime by a registry of resolvers. That breaks the compile-time coupling: a device like NVMe declares that it needs a Resource<DiskHandleKind>, and the resolver system figures out at VM construction time whether that is a file-backed disk, a VHD, a layered disk, a blob-backed disk, or anything else.

Today there are ~40 registered resolvers in openvmm_resources, covering chipset devices, disks, disk layers, network backends, serial backends, PCI devices, SCSI devices, virtio devices, and VMBus devices. About 13 resource kinds are defined in vm_resource/src/kind.rs. The pattern is actively growing.


What needs to be documented

Guide content (architecture + tutorials)

These belong in the Guide because they are conceptual and workflow-oriented. A reader should be able to understand the resolver architecture and know how to use it without reading the source.

1. Architecture overview — what the resolver system is, why it exists, how it fits into VM construction. This is the "explain it to a smart colleague who is new to the project" page. Should cover:

  • the problem: why not just use an enum of all possible backends?
  • the solution: type-erased resources, resource kinds, resource IDs, and resolvers
  • the three-step flow: declare a resource handle → implement a resolver → register it
  • the registration model: declare_static_resolver! / declare_static_async_resolver! + register_static_resolvers! + linkme
  • sub-resource resolution: how NVMe resolves its namespace disks recursively
  • input context injection: how ResolvePciDeviceHandleParams, ResolveDiskParameters, etc. flow into resolvers
  • a mermaid diagram showing the resolution flow from user config → Resource → Resolver → constructed device

2. "How to add a new device backend" — a step-by-step tutorial. Walk through adding a hypothetical new disk backend:

  • define a resource handle struct with #[derive(MeshPayload)] + impl ResourceId<DiskHandleKind>
  • implement ResolveResource or AsyncResolveResource
  • use declare_static_resolver! or declare_static_async_resolver!
  • add the resolver to openvmm_resources/src/lib.rs (and openvmm_hcl_resources if needed for OpenHCL)
  • test it

3. "How to add a new resource kind" — shorter page or section. When you need a wholly new kind (not just a new backend for an existing kind):

  • define the kind tag type + impl ResourceKind
  • implement CanResolveTo with the output type and input context
  • where to put it: vm_resource/src/kind.rs for shared kinds, or a device-specific resource crate for scoped kinds

4. Pattern catalog — a reference page with the notable resolver patterns, each with a one-paragraph explanation and a link to the canonical in-tree example:

Pattern Example Key File
Simple sync resolver FileDiskResolver disk_file/src/lib.rs
Async resolver with sub-resources NvmeControllerResolver nvme/src/resolver.rs
Parallel sub-resource resolution LayeredDiskResolver disk_layered/src/resolver.rs
Virtio-over-PCI wrapping VirtioPciResolver virtio/src/resolver.rs
VMBus device with network backend NetvspResolver netvsp/src/resolver.rs
Platform resource (use-default) HaltResolver vmm_core/src/platform_resolvers.rs
Chipset device resolver BatteryResolver chipset/src/battery/resolver.rs

5. Decision tree — when should you use the resolver pattern versus direct construction? Short page or callout box:

  • if the device has interchangeable backends → resolver
  • if the device is a singleton with no alternatives (CMOS RTC, PIC, PIT, DMA) → direct construction is fine
  • if the resource is runtime-configurable from user input → resolver
  • if the device is firmware → currently direct, could go either way

Rustdoc content (API reference)

These belong as rustdoc because they are type-level, crate-level, or trait-level reference material that should live next to the code.

1. vm_resource crate-level docs — the existing module doc is good but terse. It should be expanded with:

  • a worked example showing the full declare → implement → register → resolve cycle
  • doc links to the key types and traits
  • a "see also" pointing to the Guide architecture page

2. ResourceKind trait docs — already decent, but should link to kind.rs and explain the "tag type" pattern more explicitly

3. CanResolveTo docs — explain why this is a separate trait (coherence/orphan rules), and show where the input context type comes from

4. Resource<K> docs — explain the type erasure: what id and message contain, how IntoResource works, and why this is a mesh message

5. ResourceResolver docs — explain the resolution lookup flow: static resolvers (linkme) → dynamic resolvers → error

6. Macro docsdeclare_static_resolver!, declare_static_async_resolver!, register_static_resolvers! — each should have a usage example showing the typical declaration pattern

7. Per-resolver rustdoc — each resolver.rs should have a module-level doc comment explaining what resource kind it resolves, what it produces, and any notable sub-resource resolution it performs. Many already have inline comments; those should be promoted to doc comments.


Devices and subsystems not yet on the resolver framework

These are areas that currently use direct construction or manual dependency injection and could potentially benefit from moving to the resolver pattern. I'm listing them for awareness, not as a mandate to migrate everything immediately.

Chipset infrastructure (singletons)

CMOS RTC, DMA, IO APIC, PIC, PIT, power management — these are constructed directly in the chipset builder. They are singletons with no alternative implementations, so the resolver pattern may not add value. Document them as an explicit "we chose not to resolve these" decision.

Firmware

UEFI (firmware_uefi) and PCAT BIOS (firmware_pcat) are constructed directly. These could potentially benefit from a resolver if firmware selection becomes more dynamic, but today it is effectively a compile-time choice. Worth documenting the current state.

Framebuffer / video

framebuffer, video_core, vga_proxy — direct construction. Low priority for resolver migration unless the backend story becomes more pluggable.

VPC relay / VPC client

vpci_relay, vpci_client — infrastructure that wires PCI device pass-through. Not clear that these benefit from the resolver pattern.


What I do NOT want

  • I do not want to document every resolver implementation in detail. The pattern catalog and per-resolver rustdoc should be sufficient.
  • I do not want to mandate migration for devices that are fine with direct construction today. The decision tree should make it clear when the resolver is and is not the right tool.
  • I do not want the Guide pages to duplicate the rustdoc. The Guide should explain concepts and workflows; the rustdoc should be the API reference. Cross-link between them.

Summary: where each piece lives

Content Location Format
Architecture overview Guide/src/dev_guide/ (contributor-oriented) Guide page
"Add a new device backend" tutorial Same page or sub-page Guide page
"Add a new resource kind" Same page or sub-page Guide page
Pattern catalog Same page (table with links to source and rustdoc) Guide page
Decision tree (resolver vs. direct) Same page (callout or short section) Guide page
vm_resource crate docs vm/vmcore/vm_resource/src/lib.rs Rustdoc
Key trait docs (ResourceKind, CanResolveTo, etc.) Same file, per-trait Rustdoc
Macro docs Same file, per-macro Rustdoc
Per-resolver module docs Each resolver.rs Rustdoc

Goals

  • A new contributor can understand the resolver pattern from the Guide without reading source code
  • A contributor adding a new device backend can follow the tutorial and get it right on the first try
  • The rustdoc for vm_resource is comprehensive enough that someone reading the API docs understands the type relationships
  • The pattern catalog gives experienced contributors a quick reference for "which existing resolver should I model mine after?"
  • The decision tree prevents unnecessary resolver adoption for devices that don't benefit from it

Non-goals

  • Migrating all devices to the resolver framework
  • Documenting every individual resolver's implementation logic
  • Redesigning the resolver system itself
  • Covering the mesh serialization layer in depth (that is a separate documentation effort)

Rough implementation plan

  1. Write the Guide architecture page: overview, three-step flow, mermaid diagram, registration model, sub-resource resolution
  2. Add the "how to add a backend" tutorial section with a worked example
  3. Add the pattern catalog table with links to canonical examples
  4. Add the decision tree section
  5. Expand rustdoc on vm_resource crate: crate-level docs, key traits, macros
  6. Add module-level doc comments to the highest-traffic resolver implementations
  7. Update Guide/src/SUMMARY.md to include the new page(s)

Resolved questions

  • Guide placement: This is contributor-oriented content, so it belongs under dev_guide/, not reference/architecture/.
  • Pattern catalog links: Link to both GitHub source and rustdoc pages for each resolver.
  • Troubleshooting / ResolveError patterns: Better left to rustdoc on ResolveError and ResourceResolver rather than a separate Guide section.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions