Linux userland API discussions
 help / color / mirror / Atom feed
From: Jiri Pirko <jiri@resnulli.us>
To: linux-coco@lists.linux.dev
Cc: linux-kernel@vger.kernel.org, linux-api@vger.kernel.org,
	x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	jgg@ziepe.ca, david.quigley@intel.com, lukas@wunner.de,
	ksinyuk@kernel.org, rodrigo.vivi@intel.com,
	cedric.xing@intel.com, sameo@meta.com, drdeeglaze@gmail.com,
	James.Bottomley@HansenPartnership.com, aik@amd.com,
	jpiotrowski@nvidia.com, qinkun@google.com, pgonda@google.com,
	jic23@kernel.org, alistair.francis@wdc.com, ankita@nvidia.com,
	suzuki.poulose@arm.com, kas@kernel.org,
	rick.p.edgecombe@intel.com, elena.reshetova@intel.com,
	dave.hansen@linux.intel.com,
	sathyanarayanan.kuppuswamy@linux.intel.com, peter.fang@intel.com
Subject: [PATCH RFC 04/20] Documentation: ctlv: Add userspace ABI
Date: Thu, 15 Oct 2026 16:50:37 +0200	[thread overview]
Message-ID: <20261015145053.3664509-5-jiri@resnulli.us> (raw)
In-Reply-To: <20261015145053.3664509-1-jiri@resnulli.us>

From: Jiri Pirko <jiri@nvidia.com>

Describe the CTLV transport, discovery, wire format and userspace
compatibility rules.

Assisted-by: Cursor: GPT-5.6 Sol
Assisted-by: Cursor: Claude Opus 5.5
Signed-off-by: Jiri Pirko <jiri@nvidia.com>
---
 Documentation/userspace-api/ctlv.rst  | 507 ++++++++++++++++++++++++++
 Documentation/userspace-api/index.rst |   1 +
 MAINTAINERS                           |   1 +
 3 files changed, 509 insertions(+)
 create mode 100644 Documentation/userspace-api/ctlv.rst

diff --git a/Documentation/userspace-api/ctlv.rst b/Documentation/userspace-api/ctlv.rst
new file mode 100644
index 000000000000..5ebca3d4d94a
--- /dev/null
+++ b/Documentation/userspace-api/ctlv.rst
@@ -0,0 +1,507 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==================
+CTLV userspace ABI
+==================
+
+:Author: Jiri Pirko
+
+CTLV is a transport for device control interfaces. A family describes what its
+devices accept in YAML, a generator turns that into kernel metadata and UAPI
+headers, and CTLV validates every message before a family callback sees it.
+Userspace sees one character device per instance, one ioctl, and ``read()`` for
+events.
+
+This document is the ABI. What each family accepts is specified under
+``Documentation/ctlv/specs``; writing a family is :doc:`/driver-api/ctlv`.
+
+Why a TLV transport
+===================
+
+CTLV puts the rules of every operation in one description and validates them
+once:
+
+- One ioctl carries every operation of every family, so a new operation is a
+  new specification entry, not a new ioctl number.
+- Attributes are optional or required by declaration, so a message can grow
+  without breaking a caller that does not know the new attribute.
+- An unknown attribute is refused on a request and tolerated on a reply, so a
+  new kernel can say more to an old program. A request may mark an attribute an
+  old kernel is welcome to skip, so a new program can say more too.
+- Bounds, lengths, occurrence counts and nesting depth are checked before a
+  family callback runs.
+
+Devices
+=======
+
+Each registered instance appears as a character device in the ``ctlv`` class
+with a dynamic minor::
+
+    /dev/ctlv0
+    /sys/class/ctlv/ctlv0
+
+Sysfs shows class membership, the ``dev`` number and the device-model link to
+the parent device. There is no family sysfs attribute; ``families-dump`` on an
+open descriptor is the authoritative answer to what a device is.
+
+Each open file description has its own event subscriptions and event queue.
+``O_RDONLY`` opens an observation fd, ``O_RDWR`` opens a full-control fd, and
+``O_WRONLY`` is rejected with ``-EACCES``. Every action and query declares the
+authority it needs: ``read`` permits either accepted fd, while ``read-write``
+requires full control. Events are readable and subscribable through both.
+``dup()`` and ``SCM_RIGHTS`` preserve that authority; attenuation requires a
+separate observation open.
+
+Discovery
+---------
+
+Both uevents, addition and removal, carry the family chain as numbered
+properties::
+
+    CTLV_FAMILY=ctlv-accelerator-foo
+    CTLV_COMPATIBLE_0=ctlv
+    CTLV_COMPATIBLE_1=ctlv-accelerator
+    CTLV_COMPATIBLE_2=ctlv-accelerator-foo
+    CTLV_COMPATIBLE_N=3
+
+``CTLV_FAMILY`` is the family the device answers as, the numbered properties
+are its ancestry from the root to that family, and
+``CTLV_COMPATIBLE_N`` is how many there are. An index never moves: changing a
+family's parent is an ABI
+break, adding a descendant only appends.
+
+A program that wants every device, including ones appearing while it starts,
+must listen before it looks, which closes the window between enumerating and
+subscribing::
+
+    1. create a udev monitor filtered to the ctlv subsystem, and enable it
+    2. enumerate the existing ctlv class devices
+    3. drain the events already queued on the monitor
+    4. deduplicate by sysfs path
+    5. open the device node
+    6. ask families-dump on the open descriptor for the authoritative chain
+
+Steps 1 to 4 are pre-open discovery, all a udev rule can match on; step 6 does
+not need a udev database. A rule matches a family through the compatibility
+properties::
+
+    # /etc/udev/rules.d/70-ctlv.rules
+    #
+    # Anything of one family, whatever family implementation registered it.
+    SUBSYSTEM=="ctlv", ENV{CTLV_FAMILY}=="ctlv-accelerator-foo", \
+        GROUP="accel", MODE="0660"
+
+    # Anything descended from a family.
+    SUBSYSTEM=="ctlv", ENV{CTLV_COMPATIBLE_1}=="ctlv-accelerator", \
+        TAG+="uaccess"
+
+    # A stable name from the parent device, which is deployment policy.
+    SUBSYSTEM=="ctlv", ENV{CTLV_FAMILY}=="ctlv-accelerator-foo", \
+        SYMLINK+="accel/by-path/$env{ID_PATH}"
+
+CTLV does not standardise such aliases and does not promise that a generic
+identifier survives a reboot or a reprobe; a family with a meaningful identity
+exposes it through an operation of its own.
+
+Wire format
+===========
+
+A message is a tree of attributes. Every attribute begins with the same
+header, at an eight-byte boundary::
+
+    struct ctlv_attr {
+            __u32 len;              /* header + payload, without padding */
+            __u32 flags;            /* CTLV_ATTR_F_* */
+            __aligned_u64 attr_id;  /* complete ID, or 0 for a root */
+    };
+
+One unsigned integer attribute with an eight-byte payload, on the wire::
+
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +---------------------------------------------------------------+
+    |                        len = 24                               |
+    +---------------------------------------------------------------+
+    |                        flags = 0                              |
+    +---------------------------------------------------------------+
+    |                                                               |
+    +                       attr_id                                 +
+    |                                                               |
+    +---------------------------------------------------------------+
+    |                                                               |
+    +                       payload                                 +
+    |                                                               |
+    +---------------------------------------------------------------+
+
+The rules that make a tree out of that:
+
+- ``CTLV_ALIGNTO`` is 8 and ``CTLV_ALIGN()`` rounds up to it. Every attribute
+  starts at a multiple of eight.
+- ``len`` counts this header plus this attribute's payload, not its own
+  trailing padding.
+- A nested payload is the concatenation of ``CTLV_ALIGN(child.len)`` bytes per
+  child, so a child's padding is counted inside its parent's ``len`` and a
+  leaf's own padding by nobody.
+- ``CTLV_ATTR_F_NESTED`` is set exactly on a root and on a nest.
+- A message begins with one root attribute, whose ``attr_id`` is
+  ``CTLV_ATTR_ROOT`` (zero) and whose payload is the message. A root never
+  appears inside a nest, and a nest never carries the root ID.
+- Scalar payloads are native-endian and their lengths exact: eight bytes for
+  an integer, one byte holding zero or one for a boolean, the string including
+  its NUL terminator, the declared length for binary data.
+- Nesting is limited to ``CTLV_MAX_NEST_DEPTH`` levels, the root being level
+  zero.
+
+A whole message with every offset, for a request of one integer and one nest
+carrying a string and a further nest::
+
+    offset  attribute                       len  flags   contents
+    ------  ------------------------------  ---  ------  ----------------
+         0  root                            120  NESTED  attr_id = 0
+        16  .. chunks                        24  -       8-byte integer
+        40  .. chunk                         80  NESTED
+        56     .. label                      19  -       "ab" and its NUL
+        80     .. item                       40  NESTED
+        96        .. value                   24  -       8-byte integer
+       120  end of message
+
+    +--------------------------------------------------------------+ 0
+    | root: len = 120, flags = NESTED, attr_id = 0                 |
+    +--------------------------------------------------------------+ 16
+    | chunks: len = 24 | payload: 8 bytes                          |
+    +--------------------------------------------------------------+ 40
+    | chunk: len = 80, flags = NESTED                              |
+    |   +--------------------------------------------------------+ | 56
+    |   | label: len = 19 | payload: 'a' 'b' 0 | 5 bytes padding | |
+    |   +--------------------------------------------------------+ | 80
+    |   | item: len = 40, flags = NESTED                         | |
+    |   |   +--------------------------------------------------+ | | 96
+    |   |   | value: len = 24 | payload: 8 bytes               | | |
+    |   |   +--------------------------------------------------+ | | 120
+    +--------------------------------------------------------------+
+
+``label.len`` is 19: its header and three payload bytes, not the five bytes of
+padding after it. ``chunk`` counts those five, its ``len`` of 80 being its
+header plus ``CTLV_ALIGN(19)`` plus ``CTLV_ALIGN(40)``. A walk over a nest's
+children advances by ``CTLV_ALIGN(child.len)``, a walk of one payload by
+``child.len``.
+
+An attribute ID names the family that declared it, a group within that family
+and an attribute within that group::
+
+    63           48 47           32 31                             0
+    +--------------+--------------+--------------------------------+
+    |    family    |    group     |             attr               |
+    +--------------+--------------+--------------------------------+
+
+    CTLV_ATTR(family, group, attr)
+    CTLV_ATTR_FAMILY(attr) / CTLV_ATTR_GROUP(attr) / CTLV_ATTR_NUMBER(attr)
+
+An operation ID is the same shape with the group bits zero::
+
+    CTLV_OP(family, op)
+    CTLV_OP_FAMILY(op) / CTLV_OP_NUMBER(op)
+
+Use generated complete IDs. A family's header defines every ID it declares
+and includes its parent's.
+
+Request occurrence order
+------------------------
+
+Occurrences of one attribute ID must be contiguous within each request root or
+nest. ``A A B`` is valid, while ``A B A`` is not. An ignored unknown attribute
+is not an occurrence of any known attribute, but it ends the preceding run, so
+``A ignored-unknown A`` is also invalid. Different IDs otherwise have no
+required numeric or schema order.
+
+Attributes a kernel may skip
+----------------------------
+
+A request attribute, the root aside, may carry
+``CTLV_ATTR_F_IGNORE_IF_UNKNOWN``. If no family the device answers declares
+that complete ID, the kernel steps over the whole attribute without looking
+inside it; without the bit, an attribute the schema does not place where it
+appears fails the request as it always has.
+
+The bit forgives an ID this kernel has never heard of and nothing else. An ID
+the device's schema declares somewhere is held to that schema, so an attribute
+sent where it does not belong fails whether the bit is set or not, and one sent
+where it does belong is checked as usual. Every other rule applies too: the
+length has to fit its nest and the header may carry no bit the format does not
+define. Replies and events never carry it.
+
+This is how a program built against a newer version of a family talks to an
+older kernel. What that kernel knows is validated, what it does not is
+ignored, and a caller that has to know which is which asks ``op-schema-get``
+first.
+
+Executing an operation
+======================
+
+One ioctl executes every operation::
+
+    struct ctlv_op_exec {
+            __aligned_u64 op_id;
+            __aligned_u64 request;      /* struct ctlv_attr __user * */
+            __aligned_u64 reply;        /* struct ctlv_attr __user * */
+            __u32 request_len;
+            __u32 reply_len;
+            __aligned_u64 generation;   /* queries only */
+            __aligned_u64 cursor;       /* queries only */
+            __aligned_u64 reserved[2];  /* must be zero */
+    };
+
+    #define CTLV_IOC_OP_EXEC _IOWR(0xBB, 0x00, struct ctlv_op_exec)
+
+``request_len`` is how many bytes the kernel may read at ``request`` and
+``reply_len`` how many it may write at ``reply``. They are copy boundaries, not
+message lengths: a root's ``len`` may be shorter than ``request_len``, the
+bytes after it being ignored, and may not be longer. ``reply_len`` is never
+overwritten; the length written is the reply root's ``len``. The pointers are
+fixed-width so a 32-bit and a 64-bit process pass the same structure, and in
+place of a size field the ioctl number encodes the size and ``reserved``, which
+must be zero, covers compatible growth.
+
+Every action and query carries a physical request root, including an empty
+request. ``request_len`` is therefore at least one attr header and at most the
+1 MiB transport limit. The ``request-max-len`` reported by ``ops-dump`` is the
+maximum request composed from the known schema; a newer caller may exceed it
+with well-formed unknown attrs marked ``IGNORE_IF_UNKNOWN``, up to the
+transport limit.
+
+The three kinds of operation differ in what they answer:
+
+action
+    Executed once and acknowledged. An action with no reply takes
+    ``reply_len`` zero; one with a bounded reply has its maximum in
+    ``ops-dump``.
+
+query
+    Executed once and answered in as many fragments as it needs, using
+    ``generation`` and ``cursor``.
+
+event
+    Not executed. A device produces records and a subscribed file description
+    reads them.
+
+Errors
+------
+
+A failed operation returns a negative errno. Where the failure is a rule the
+message broke and the caller offered a reply buffer, CTLV also writes
+error information there in TLV form: a ``validation-reason`` value, a
+human-readable message, the offset of the offending attribute, the offset of
+the nest it was in, the ID of a missing attribute, and for a stale query the
+expected and the current generation. A buffer too small leaves it unwritten;
+the errno is authoritative either way.
+
+What the transport answers with, as against a family's own callback:
+
+``ENOTTY``
+    Not ``CTLV_IOC_OP_EXEC``; this transport has one ioctl.
+
+``EINVAL``
+    A reserved field was not zero, ``op_id`` was zero, ``generation`` or
+    ``cursor`` was set on something that is not a query, or the message broke
+    a rule of the format or of the schema.
+
+``EFAULT``
+    The structure, the request or the reply was not accessible.
+
+``EOPNOTSUPP``
+    The device does not publish the operation, publishes it but has it
+    disabled, or the operation is an event, which is read rather than executed.
+
+``EACCES``
+    The fd lacks the operation's declared authority, or an ``O_WRONLY`` open
+    was attempted.
+
+``EMSGSIZE``
+    ``reply_len`` is smaller than the smallest fragment the operation can
+    answer with. Nothing was executed.
+
+``ESTALE``
+    A continuation whose ``generation`` no longer matches. Start the query
+    again.
+
+``ENODEV``
+    The device was unregistered. Descriptors stay open and every operation on
+    them fails this way.
+
+``EBADF``, ``EIO``
+    A blob descriptor named something that is not a file, or the file refused
+    the transfer.
+
+``ENOMEM``
+    The kernel could not allocate what the operation needed.
+
+``read()`` answers ``EAGAIN`` when no record is queued on a non-blocking
+description, ``EINTR`` when a blocking read was interrupted, ``EMSGSIZE`` when
+the buffer cannot hold the record at the head of the queue, and ``ENODEV``
+once a removed device's queue has been drained.
+
+Queries and fragments
+=====================
+
+A query's answer may be larger than the buffer the caller wants to commit, so
+the kernel fills the buffer with as much of it as fits where the tree can be
+cut. The first call passes ``generation`` and ``cursor`` zero. On return:
+
+- the kernel puts the query's generation in ``generation``;
+- ``cursor`` is nonzero when there is more to come, zero when the answer is
+  complete;
+- the reply root carries ``CTLV_ATTR_F_FRAG_MORE`` when the answer continues,
+  and so does every nest still logically open at the cut.
+
+To continue, the caller repeats the call with the same ``op_id`` and request,
+the returned ``cursor`` and the returned ``generation``, and reassembles by
+concatenating the children of each still-open nest.
+
+One answer of three items, cut by a buffer that holds two::
+
+    call 1: cursor in = 0             call 2: cursor in = c
+            cursor out = c                    cursor out = 0
+
+    +----------------------------+    +----------------------------+
+    | root: FRAG_MORE            |    | root: (no FRAG_MORE)       |
+    |  +-----------------------+ |    |  +-----------------------+ |
+    |  | chunk: FRAG_MORE      | |    |  | chunk:                | |
+    |  |  +------------------+ | |    |  |  +------------------+ | |
+    |  |  | item: value = 1  | | |    |  |  | item: value = 3  | | |
+    |  |  +------------------+ | |    |  |  +------------------+ | |
+    |  |  | item: value = 2  | | |    |  +-----------------------+ |
+    |  |  +------------------+ | |    +----------------------------+
+    |  +-----------------------+ |
+    +----------------------------+
+
+    reassembled: root -> chunk -> item(1), item(2), item(3)
+
+``FRAG_MORE`` on the root says the answer continues; on ``chunk`` it says the
+next fragment resumes inside that same chunk. A complete nest does not carry
+it, so a reader knows whether to append or to open a new nest beside it.
+
+Every continuing fragment adds at least one complete logical attr beyond its
+repeated path, and a cursor value cannot recur within one logical reply.
+A reader must reject either violation.
+
+A continuation whose generation no longer matches fails with ``-ESTALE``, and
+the error information carries the expected and the current generation.
+
+Events
+======
+
+An event reaches a file description that asked for it, and only that one:
+
+1. subscribe with the ``subscriptions-add`` action, naming operation IDs;
+2. read records with ``read()``, one complete record per call;
+3. unsubscribe with ``subscriptions-remove``.
+
+``poll()`` reports readability when a record is queued. Each record is a
+header followed by exactly one root attribute::
+
+    struct ctlv_event_hdr {
+            __u32 length;             /* header + aligned root */
+            __u32 flags;              /* zero */
+            __aligned_u64 op_id;      /* the event op that produced it */
+            __aligned_u64 sequence;   /* per file description */
+    };
+
+One ``read()`` returns one record, the header and the aligned root::
+
+    +---------------------------------------------------------------+ 0
+    | length = 24 + CTLV_ALIGN(root.len)     | flags = 0            |
+    +---------------------------------------------------------------+ 8
+    | op_id: the event operation that produced this record          |
+    +---------------------------------------------------------------+ 16
+    | sequence: counted per file description                        |
+    +---------------------------------------------------------------+ 24
+    | root: len, flags = NESTED, attr_id = 0                        |
+    |   the event's attributes, exactly as a reply carries them      |
+    +---------------------------------------------------------------+ length
+
+A buffer shorter than ``length`` reads nothing and fails with ``-EMSGSIZE``. A
+record is one message, bounded by ``CTLV_MAX_INLINE_MESSAGE_LEN``. A sequence
+number is assigned to every eligible record, dropped ones included, so a gap in
+the sequence is exactly what was lost.
+
+The queue is per file description: ``event-queue-get`` reports its length and
+how much is in use, ``event-queue-set`` changes it up to
+``CTLV_MAX_EVENT_QUEUE_LEN``. A record that does not fit is dropped, and the
+next read returns an ``event-overflow`` record carrying the first and last
+sequence numbers lost and how many records that was.
+
+Two events come from the root family:
+
+op-changed
+    An operation with dynamic availability was enabled or disabled. The record
+    carries the operation ID, the new state, and the state generation that
+    ``ops-dump`` also reports, so a client can order dump against event.
+
+device-removed
+    The device is gone. Operations fail from then on and the descriptor stays
+    valid until it is closed.
+
+Blobs
+=====
+
+An operation that moves more data than a message should carry declares a blob
+attribute, and the caller passes a descriptor instead of the data: a nest
+carrying the backing type, the length and the identifier of the memory. One
+backing is defined:
+
+``va``
+    Anonymous userspace memory of the calling process, named by an address in
+    ``blob.address``.
+
+The backings an attribute accepts, the direction data may flow, the maximum
+length and the required alignment are declared by the family and reported by
+``op-schema-get``. Memory is acquired for the operation and released before it
+returns; a descriptor the operation may not use is refused before the callback.
+While the operation is in flight, userspace must not modify an ``input`` blob
+or access an ``output`` or ``inout`` blob. Whether two descriptors overlap is
+also the caller's responsibility. Keep every named VA mapping valid until the
+operation returns.
+
+Introspection
+=============
+
+Three queries describe a device to a program that was not compiled against it.
+The CTLV core answers all three on every device.
+
+``families-dump``
+    The device's family chain, root first, as a numeric ID and a name per
+    entry. The authoritative answer to what the device is.
+
+``ops-dump``
+    One entry per published operation: its ID, kind, required fd access,
+    whether its availability is fixed or dynamic, whether it is currently
+    disabled, and the message lengths that apply on this device. An
+    unpublished operation has no entry and is indistinguishable from one no
+    family ever declared. Event entries have no fd-access field.
+
+``op-schema-get``
+    The whole tree of one operation: every attribute of the request and the
+    reply, with its payload form, its bounds, its occurrence limit, and its
+    unit and scale where it has them.
+
+A schema that describes a schema does not end, so it is reported through
+re-entry: a node whose members are those of a level already described carries
+``schema.reenters``, saying how many levels up that level is. A consumer that
+follows ``reenters`` handles any depth.
+
+The lengths in ``ops-dump`` include whatever a descendant family added to an
+inherited operation, so ask rather than compute: a family's generated maximum
+is right for its own devices and a lower bound on a descendant's.
+
+Limits
+======
+
+Implementation limits, not encoded maxima of the wire fields, so raising one
+later is a compatible change::
+
+    CTLV_MAX_INLINE_MESSAGE_LEN   1 MiB    request roots, action replies,
+                                           query fragments, event roots
+    CTLV_MAX_ERROR_LEN            16 KiB   error information
+    CTLV_MAX_NEST_DEPTH           32       levels, root at zero
+    CTLV_DEFAULT_QUERY_REPLY_LEN  64 KiB   suggested query buffer
+    CTLV_MAX_EVENT_QUEUE_LEN      16 MiB   per file description
diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst
index a68b1bea57a8..d1b53c4e16eb 100644
--- a/Documentation/userspace-api/index.rst
+++ b/Documentation/userspace-api/index.rst
@@ -45,6 +45,7 @@ Devices and I/O
    :maxdepth: 1
 
    accelerators/ocxl
+   ctlv
    dma-buf-heaps
    dma-buf-alloc-exchange
    fwctl/index
diff --git a/MAINTAINERS b/MAINTAINERS
index 8ab0d6a7a2fd..882836d85125 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7006,6 +7006,7 @@ M:	Jiri Pirko <jiri@resnulli.us>
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 F:	Documentation/ctlv/
+F:	Documentation/userspace-api/ctlv.rst
 F:	include/linux/ctlv*.h
 F:	include/uapi/linux/ctlv*.h
 F:	tools/ctlv/
-- 
2.56.0


  parent reply	other threads:[~2026-10-15 14:51 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-15 14:50 [PATCH RFC 00/20] attestation: Add a common subsystem and TDX support Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 01/20] ctlv: Add the schema language and generator Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 02/20] ctlv: Add the UAPI wire format and family API Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 03/20] ctlv: Add the root family specification and generated files Jiri Pirko
2026-10-15 14:50 ` Jiri Pirko [this message]
2026-10-15 14:50 ` [PATCH RFC 05/20] ctlv: Prepare message input handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 06/20] ctlv: Prepare blob descriptor validation Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 07/20] ctlv: Prepare schema validation Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 08/20] ctlv: Prepare message output handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 09/20] ctlv: Prepare VA blob handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 10/20] ctlv: Prepare event queue support Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 11/20] ctlv: Prepare runtime introspection Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 12/20] ctlv: Add device and operation dispatch Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 13/20] Documentation: ctlv: Describe how to write a family Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 14/20] attestation: Add the base family specification and generated files Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 15/20] attestation: Prepare provider and instance core Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 16/20] attestation: Prepare measurement register journal Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 17/20] attestation: Add CTLV operation handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 18/20] tdx-guest: Expose the native attestation service API Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 19/20] attestation: Add the TDX family specification and generated files Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 20/20] attestation: Add the TDX family implementation Jiri Pirko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261015145053.3664509-5-jiri@resnulli.us \
    --to=jiri@resnulli.us \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=aik@amd.com \
    --cc=alistair.francis@wdc.com \
    --cc=ankita@nvidia.com \
    --cc=cedric.xing@intel.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=david.quigley@intel.com \
    --cc=drdeeglaze@gmail.com \
    --cc=elena.reshetova@intel.com \
    --cc=jgg@ziepe.ca \
    --cc=jic23@kernel.org \
    --cc=jpiotrowski@nvidia.com \
    --cc=kas@kernel.org \
    --cc=ksinyuk@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=peter.fang@intel.com \
    --cc=pgonda@google.com \
    --cc=qinkun@google.com \
    --cc=rick.p.edgecombe@intel.com \
    --cc=rodrigo.vivi@intel.com \
    --cc=sameo@meta.com \
    --cc=sathyanarayanan.kuppuswamy@linux.intel.com \
    --cc=suzuki.poulose@arm.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox