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 02/20] ctlv: Add the UAPI wire format and family API
Date: Thu, 15 Oct 2026 16:50:35 +0200 [thread overview]
Message-ID: <20261015145053.3664509-3-jiri@resnulli.us> (raw)
In-Reply-To: <20261015145053.3664509-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@nvidia.com>
Define CTLV's common TLV transport, ioctl, event records, identifiers
and limits. Add the in-kernel API used by family implementations and
generated code.
Assisted-by: Cursor: GPT-5.6 Sol
Assisted-by: Cursor: Claude Opus 5.5
Signed-off-by: Jiri Pirko <jiri@nvidia.com>
---
.../userspace-api/ioctl/ioctl-number.rst | 2 +
MAINTAINERS | 2 +
include/linux/ctlv.h | 55 +++
include/linux/ctlv_family.h | 316 ++++++++++++++++++
include/uapi/linux/ctlv.h | 183 ++++++++++
5 files changed, 558 insertions(+)
create mode 100644 include/linux/ctlv.h
create mode 100644 include/linux/ctlv_family.h
create mode 100644 include/uapi/linux/ctlv.h
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 2fc53093752d..e545669c773c 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -386,6 +386,8 @@ Code Seq# Include File Comments
<mailto:linux-hyperv@vger.kernel.org>
0xBA 00-0F uapi/linux/liveupdate.h Pasha Tatashin
<mailto:pasha.tatashin@soleen.com>
+0xBB 00-0F uapi/linux/ctlv.h CTLV
+ <mailto:jiri@resnulli.us>
0xC0 00-0F linux/usb/iowarrior.h
0xCA 00-0F uapi/misc/cxl.h Dead since 6.15
0xCA 10-2F uapi/misc/ocxl.h
diff --git a/MAINTAINERS b/MAINTAINERS
index a8508fbae37d..8ab0d6a7a2fd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7006,6 +7006,8 @@ M: Jiri Pirko <jiri@resnulli.us>
L: linux-kernel@vger.kernel.org
S: Maintained
F: Documentation/ctlv/
+F: include/linux/ctlv*.h
+F: include/uapi/linux/ctlv*.h
F: tools/ctlv/
CTU CAN FD DRIVER
diff --git a/include/linux/ctlv.h b/include/linux/ctlv.h
new file mode 100644
index 000000000000..addb893f4b8d
--- /dev/null
+++ b/include/linux/ctlv.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
+ *
+ * CTLV family API.
+ */
+#ifndef _LINUX_CTLV_H
+#define _LINUX_CTLV_H
+
+#include <linux/types.h>
+
+#include <uapi/linux/ctlv.h>
+
+struct ctlv_device;
+struct ctlv_family;
+struct ctlv_msg;
+struct ctlv_op_ctx;
+struct ctlv_schema_tree;
+
+/**
+ * struct ctlv_cursor - One attr position in one message.
+ * @msg: the message this position is in, core-private bookkeeping
+ * @attr: the attr itself, or NULL when a lookup found nothing
+ * @parent: reading, the nest containing @attr, NULL at the root
+ * @up: writing, cursor of the nest containing @attr, NULL at the root. The
+ * chain of them is the open-nest stack
+ * @start: writing, where @attr begins in the message. An append reaches what
+ * it lengthens through the buffer rather than through @attr, that buffer
+ * being the core's own
+ * @tree: schema tree the node belongs to, which is a fill's own tree for an
+ * attr that arrived through one
+ * @node: index of the node within @tree
+ * @depth: nesting levels above this position, the root being zero
+ * @index_nest_scope: schema scope used to read members of the physical nest
+ * @index_scope: core-private schema scope containing this attr
+ *
+ * Fixed-size, so family code can put a child cursor on the stack. The members
+ * belong to the core: a family reaches a message through what was generated
+ * for the op it answers. One direction at a time, a helper of the other
+ * direction refusing the cursor.
+ */
+struct ctlv_cursor {
+ struct ctlv_msg *msg;
+ const struct ctlv_attr *attr;
+ const struct ctlv_attr *parent;
+ struct ctlv_cursor *up;
+ size_t start;
+ const struct ctlv_schema_tree *tree;
+ u32 node;
+ u32 depth;
+ u32 index_nest_scope;
+ u32 index_scope;
+};
+
+#endif /* _LINUX_CTLV_H */
diff --git a/include/linux/ctlv_family.h b/include/linux/ctlv_family.h
new file mode 100644
index 000000000000..1ae4d3a536f7
--- /dev/null
+++ b/include/linux/ctlv_family.h
@@ -0,0 +1,316 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
+ *
+ * CTLV family metadata and generated-code support.
+ */
+#ifndef _LINUX_CTLV_FAMILY_H
+#define _LINUX_CTLV_FAMILY_H
+
+#include <linux/ctlv.h>
+#include <linux/gfp_types.h>
+#include <linux/kobject.h>
+#include <linux/types.h>
+
+#include <uapi/linux/ctlv.h>
+
+/* op-schema-get needs one level to describe the declared schema. */
+#define CTLV_MAX_DECLARED_NEST_DEPTH (CTLV_MAX_NEST_DEPTH - 1)
+
+struct ctlv_node_schema {
+ u64 attr_id;
+ u8 kind;
+ u8 unit;
+ s8 scale;
+ bool reenters;
+ u32 max_occurrences;
+ u32 first_child;
+ u32 children_count;
+ u32 required_children_count;
+ union {
+ struct {
+ u64 min;
+ u64 max;
+ } range;
+ u64 flags_mask;
+ struct {
+ u32 min_len;
+ u32 max_len;
+ } length;
+ struct {
+ u64 max_len;
+ u32 alignment;
+ u16 backings;
+ u8 direction;
+ } blob;
+ };
+};
+
+#define CTLV_NODE_SCHEMA_UNLIMITED 0
+
+#define __CTLV_NODE_SCHEMA(_attr, _kind, _occurrences, ...) \
+ { .attr_id = (_attr), .kind = (_kind), \
+ .max_occurrences = (_occurrences), __VA_ARGS__ }
+
+#define __CTLV_NODE_SCHEMA_CHILDREN(_first, _count, _required) \
+ .first_child = (_first), .children_count = (_count), \
+ .required_children_count = (_required)
+
+#define CTLV_NODE_SCHEMA_ROOT(_first, _count, _required) \
+ __CTLV_NODE_SCHEMA(CTLV_ATTR_ROOT, CTLV_SCHEMA_NEST, 1, \
+ __CTLV_NODE_SCHEMA_CHILDREN(_first, _count, _required))
+
+#define CTLV_NODE_SCHEMA_NEST(_attr, _occurrences, _first, _count, _required) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_NEST, _occurrences, \
+ __CTLV_NODE_SCHEMA_CHILDREN(_first, _count, _required))
+
+#define CTLV_NODE_SCHEMA_NEST_REENTERS(_attr, _occurrences, _first, _count, _required) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_NEST, _occurrences, \
+ .reenters = true, \
+ __CTLV_NODE_SCHEMA_CHILDREN(_first, _count, _required))
+
+#define CTLV_NODE_SCHEMA_UINT(_attr, _occurrences, _min, _max) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_UINT, _occurrences, \
+ .range = { .min = (_min), .max = (_max) })
+
+#define CTLV_NODE_SCHEMA_UINT_UNIT(_attr, _occurrences, _min, _max, _unit, _scale) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_UINT, _occurrences, \
+ .range = { .min = (_min), .max = (_max) }, \
+ .unit = (_unit), .scale = (_scale))
+
+#define CTLV_NODE_SCHEMA_SINT(_attr, _occurrences, _min, _max) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_SINT, _occurrences, \
+ .range = { .min = (_min), .max = (_max) })
+
+#define CTLV_NODE_SCHEMA_SINT_UNIT(_attr, _occurrences, _min, _max, _unit, _scale) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_SINT, _occurrences, \
+ .range = { .min = (_min), .max = (_max) }, \
+ .unit = (_unit), .scale = (_scale))
+
+#define CTLV_NODE_SCHEMA_ENUM(_attr, _occurrences, _max) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_ENUM, _occurrences, \
+ .range = { .min = 1, .max = (_max) })
+
+#define CTLV_NODE_SCHEMA_FLAGS(_attr, _occurrences, _mask) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_FLAGS, _occurrences, \
+ .flags_mask = (_mask))
+
+#define CTLV_NODE_SCHEMA_BOOL(_attr, _occurrences) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_BOOL, _occurrences)
+
+#define CTLV_NODE_SCHEMA_STRING(_attr, _occurrences, _min, _max) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_STRING, _occurrences, \
+ .length = { .min_len = (_min), .max_len = (_max) })
+
+#define CTLV_NODE_SCHEMA_BINARY(_attr, _occurrences, _min, _max) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_BINARY, _occurrences, \
+ .length = { .min_len = (_min), .max_len = (_max) })
+
+#define CTLV_NODE_SCHEMA_BLOB(_attr, _occurrences, _max, _alignment, _backings, _dir) \
+ __CTLV_NODE_SCHEMA(_attr, CTLV_SCHEMA_BLOB, _occurrences, \
+ .blob = { .max_len = (_max), \
+ .alignment = (_alignment), \
+ .backings = (_backings), \
+ .direction = (_dir) })
+
+struct ctlv_stub_schema {
+ u16 family_id;
+ u32 set_id;
+ u32 node;
+ bool optional;
+};
+
+#define __CTLV_STUB_SCHEMA(_family, _set, _node, _optional) \
+ { .family_id = (_family), .set_id = (_set), \
+ .node = (_node), .optional = (_optional) }
+
+#define CTLV_STUB_SCHEMA(_family, _set, _node) \
+ __CTLV_STUB_SCHEMA(_family, _set, _node, false)
+
+#define CTLV_STUB_SCHEMA_OPTIONAL(_family, _set, _node) \
+ __CTLV_STUB_SCHEMA(_family, _set, _node, true)
+
+struct ctlv_schema_tree {
+ const struct ctlv_node_schema *node_schemas;
+ u32 node_schemas_count;
+ const struct ctlv_stub_schema *stub_schemas;
+ u32 stub_schemas_count;
+};
+
+#define CTLV_SCHEMA_TREE(_name) { \
+ .node_schemas = _name##_node_schemas, \
+ .node_schemas_count = ARRAY_SIZE(_name##_node_schemas), \
+}
+
+#define CTLV_SCHEMA_TREE_STUBS(_name) { \
+ .node_schemas = _name##_node_schemas, \
+ .node_schemas_count = ARRAY_SIZE(_name##_node_schemas), \
+ .stub_schemas = _name##_stub_schemas, \
+ .stub_schemas_count = ARRAY_SIZE(_name##_stub_schemas), \
+}
+
+#define CTLV_SCHEMA_TREE_NONE() { }
+
+struct ctlv_stub_fill_schema {
+ u16 family_id;
+ u32 set_id;
+ struct ctlv_schema_tree members;
+};
+
+#define CTLV_STUB_FILL_SCHEMA(_family, _set, _name) { \
+ .family_id = (_family), \
+ .set_id = (_set), \
+ .members = CTLV_SCHEMA_TREE(_name##_fill), \
+}
+
+struct ctlv_op_sizes {
+ u32 request_max_len;
+ u32 action_reply_max_len;
+ u32 query_reply_min_len;
+ u32 query_reply_suggested_len;
+ u32 event_record_max_len;
+};
+
+struct ctlv_op_schema {
+ u64 op_id;
+ u8 type;
+ u8 fd_access;
+ u8 availability;
+ bool optional;
+ bool pre_post;
+ struct ctlv_schema_tree request;
+ struct ctlv_schema_tree reply;
+ struct ctlv_op_sizes sizes;
+};
+
+#define __CTLV_OP_SCHEMA(_op, _type, _availability, ...) \
+ { .op_id = (_op), .type = (_type), \
+ .availability = (_availability), __VA_ARGS__ }
+
+#define CTLV_OP_SCHEMA_ACTION(_op, _access, _availability, _request_len, _reply_len, \
+ _request, _reply, ...) \
+ __CTLV_OP_SCHEMA(_op, CTLV_OP_TYPE_ACTION, _availability, \
+ .fd_access = (_access), \
+ .request = _request, .reply = _reply, \
+ .sizes = { \
+ .request_max_len = (_request_len), \
+ .action_reply_max_len = (_reply_len), \
+ }, \
+ __VA_ARGS__)
+
+#define CTLV_OP_SCHEMA_QUERY(_op, _access, _availability, _request_len, _reply_min, \
+ _reply_suggested, _request, _reply, ...) \
+ __CTLV_OP_SCHEMA(_op, CTLV_OP_TYPE_QUERY, _availability, \
+ .fd_access = (_access), \
+ .request = _request, .reply = _reply, \
+ .sizes = { \
+ .request_max_len = (_request_len), \
+ .query_reply_min_len = (_reply_min), \
+ .query_reply_suggested_len = \
+ (_reply_suggested), \
+ }, \
+ __VA_ARGS__)
+
+#define CTLV_OP_SCHEMA_EVENT(_op, _record_len, _reply, ...) \
+ __CTLV_OP_SCHEMA(_op, CTLV_OP_TYPE_EVENT, \
+ CTLV_OP_AVAILABILITY_FIXED, \
+ .reply = _reply, \
+ .sizes = { \
+ .event_record_max_len = (_record_len), \
+ }, \
+ __VA_ARGS__)
+
+struct ctlv_family_schema {
+ const char *name;
+ u16 family_id;
+ const struct ctlv_op_schema *ops;
+ u32 ops_count;
+ const struct ctlv_stub_fill_schema *stub_fill_schemas;
+ u32 stub_fill_schemas_count;
+};
+
+/* Leave half of a uevent environment to the device model. */
+#define CTLV_UEVENT_MAX_LEN (UEVENT_BUFFER_SIZE / 2)
+#define CTLV_UEVENT_MAX_VARS (UEVENT_NUM_ENVP / 2)
+
+struct ctlv_input_ref {
+ const struct ctlv_schema_tree *tree;
+ u64 attr_id;
+ u32 node;
+ u32 slot;
+ u8 kind;
+};
+
+typedef int (*ctlv_action_fn)(void *priv, struct ctlv_op_ctx *ctx,
+ const struct ctlv_cursor *request,
+ struct ctlv_cursor *reply);
+typedef int (*ctlv_query_fn)(void *priv, struct ctlv_op_ctx *ctx,
+ const struct ctlv_cursor *request,
+ struct ctlv_cursor *reply);
+typedef int (*ctlv_op_pre_fn)(void *priv, struct ctlv_op_ctx *ctx);
+typedef void (*ctlv_op_post_fn)(void *priv, struct ctlv_op_ctx *ctx);
+
+struct ctlv_op {
+ union {
+ ctlv_action_fn action;
+ ctlv_query_fn query;
+ };
+ ctlv_op_pre_fn pre;
+ ctlv_op_post_fn post;
+};
+
+#define CTLV_OP_ACTION(_name) { .action = _name##_action }
+#define CTLV_OP_QUERY(_name) { .query = _name##_query }
+#define CTLV_OP_ACTION_PRE_POST(_name) \
+ { .action = _name##_action, .pre = _name##_pre, \
+ .post = _name##_post }
+#define CTLV_OP_QUERY_PRE_POST(_name) \
+ { .query = _name##_query, .pre = _name##_pre, \
+ .post = _name##_post }
+
+typedef size_t (*ctlv_family_priv_size_fn)(void);
+typedef const void *(*ctlv_family_pre_init_fn)(const void *init_info);
+typedef int (*ctlv_family_init_fn)(struct ctlv_device *ctlvdev,
+ const void *init_info, void *priv);
+typedef int (*ctlv_family_post_init_fn)(struct ctlv_device *ctlvdev,
+ void *priv);
+typedef void (*ctlv_family_pre_fini_fn)(struct ctlv_device *ctlvdev,
+ void *priv);
+typedef void (*ctlv_family_fini_fn)(struct ctlv_device *ctlvdev, void *priv);
+
+typedef int (*ctlv_stub_fill_fn)(void *priv, struct ctlv_op_ctx *ctx,
+ const struct ctlv_cursor *request,
+ struct ctlv_cursor *nest);
+
+struct ctlv_stub_ops {
+ u16 family_id;
+ u32 set_id;
+ ctlv_stub_fill_fn fill;
+};
+
+#define CTLV_STUB_OPS(_family, _set, _name) { \
+ .family_id = (_family), \
+ .set_id = (_set), \
+ .fill = _name##_fill, \
+}
+
+struct ctlv_family {
+ const struct ctlv_family_schema *schema;
+ const struct ctlv_family *parent;
+ const struct ctlv_op *ops;
+ u32 ops_count;
+ ctlv_op_pre_fn pre;
+ ctlv_op_post_fn post;
+ ctlv_family_priv_size_fn priv_size;
+ ctlv_family_pre_init_fn pre_init;
+ ctlv_family_init_fn init;
+ ctlv_family_post_init_fn post_init;
+ ctlv_family_pre_fini_fn pre_fini;
+ ctlv_family_fini_fn fini;
+ const struct ctlv_stub_ops *stub_ops;
+ u32 stub_ops_count;
+};
+
+extern const struct ctlv_family ctlv_family;
+
+#endif /* _LINUX_CTLV_FAMILY_H */
diff --git a/include/uapi/linux/ctlv.h b/include/uapi/linux/ctlv.h
new file mode 100644
index 000000000000..6bc0d1a296e6
--- /dev/null
+++ b/include/uapi/linux/ctlv.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/*
+ * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
+ *
+ * CTLV transport UAPI: the TLV wire format, the op-execution ioctl, the event
+ * record header and transport limits. Schema-free; a family's constants
+ * are generated into <linux/<family>_gen.h>, the root family's into
+ * <linux/ctlv_gen.h>.
+ */
+#ifndef _UAPI_LINUX_CTLV_H
+#define _UAPI_LINUX_CTLV_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * struct ctlv_attr - Attr header.
+ * @len: this header plus its payload, excluding this attr's trailing padding
+ * @flags: CTLV_ATTR_F_* bits
+ * @attr_id: complete attr ID, or CTLV_ATTR_ROOT for a message root
+ *
+ * Attrs are aligned to CTLV_ALIGNTO, which is why @attr_id is __aligned_u64: a
+ * 32-bit ABI would otherwise align this structure to four bytes. A nested
+ * payload is the concatenation of CTLV_ALIGN(child.len) bytes per child, so
+ * child padding counts inside the containing attr's @len while a leaf's own
+ * padding does not. Scalar payloads are native-endian. Within each request
+ * root or nest, occurrences of one @attr_id are contiguous; different IDs
+ * otherwise have no required order.
+ */
+struct ctlv_attr {
+ __u32 len;
+ __u32 flags;
+ __aligned_u64 attr_id;
+};
+
+#define CTLV_ALIGNTO 8
+#define CTLV_ALIGN(_len) (((_len) + CTLV_ALIGNTO - 1) & ~(CTLV_ALIGNTO - 1))
+
+/* Set exactly on root and nested attrs, clear on scalar attrs. */
+#define CTLV_ATTR_F_NESTED (1U << 0)
+/* Query fragments: set on the root and each nest logically open at the end. */
+#define CTLV_ATTR_F_FRAG_MORE (1U << 1)
+/*
+ * A request attr, never the root, that a device whose schema does not declare
+ * its ID skips whole instead of refusing the message. An ID that schema does
+ * declare is held to it wherever it appears, so this asks to be forgiven what
+ * this kernel has never heard of and nothing else.
+ */
+#define CTLV_ATTR_F_IGNORE_IF_UNKNOWN (1U << 2)
+
+/* Root attr: carries CTLV_ATTR_F_NESTED, valid only at a message start. */
+#define CTLV_ATTR_ROOT 0ULL
+
+/* Complete attr: family in bits 63..48, group in 47..32, attr in 31..0. */
+#define CTLV_ATTR(_family, _group, _attr) \
+ (((__u64)(_family) << 48) | \
+ ((__u64)(_group) << 32) | \
+ (__u64)(_attr))
+
+#define CTLV_ATTR_FAMILY(_attr) ((__u16)((_attr) >> 48))
+#define CTLV_ATTR_GROUP(_attr) ((__u16)((_attr) >> 32))
+#define CTLV_ATTR_NUMBER(_attr) ((__u32)(_attr))
+
+/* Complete op: family in bits 63..48, zero in 47..32, op in 31..0. */
+#define CTLV_OP(_family, _op) \
+ (((__u64)(_family) << 48) | (__u64)(_op))
+
+#define CTLV_OP_FAMILY(_op) ((__u16)((_op) >> 48))
+#define CTLV_OP_NUMBER(_op) ((__u32)(_op))
+
+/**
+ * enum ctlv_unit - CTLV-defined unit of an integer attr payload.
+ * @CTLV_UNIT_NONE: dimensionless
+ * @CTLV_UNIT_SECONDS: seconds
+ * @CTLV_UNIT_HERTZ: hertz
+ * @CTLV_UNIT_BYTES: bytes
+ * @CTLV_UNIT_CELSIUS: degrees Celsius
+ *
+ * A payload is value * 10^scale of this unit, from the decimal scale the attr
+ * declares alongside. Changing either is an ABI break.
+ */
+enum ctlv_unit {
+ CTLV_UNIT_NONE = 0,
+ CTLV_UNIT_SECONDS,
+ CTLV_UNIT_HERTZ,
+ CTLV_UNIT_BYTES,
+ CTLV_UNIT_CELSIUS,
+};
+
+/**
+ * enum ctlv_schema_kind - CTLV-defined form of one attr payload.
+ * @CTLV_SCHEMA_UINT: unsigned integer payload bounded by a range
+ * @CTLV_SCHEMA_SINT: signed integer payload bounded by a range
+ * @CTLV_SCHEMA_BOOL: one payload byte holding zero or one
+ * @CTLV_SCHEMA_STRING: NUL-terminated string payload bounded by length
+ * @CTLV_SCHEMA_BINARY: opaque payload bounded by length
+ * @CTLV_SCHEMA_ENUM: unsigned integer payload restricted to a range
+ * @CTLV_SCHEMA_FLAGS: unsigned integer payload restricted to a mask
+ * @CTLV_SCHEMA_NEST: nested payload described by further nodes
+ * @CTLV_SCHEMA_BLOB: blob descriptor nest
+ *
+ * Exactly one form applies to an attr. These are the values op-schema-get
+ * reports, and the set is append-only.
+ */
+enum ctlv_schema_kind {
+ CTLV_SCHEMA_UINT,
+ CTLV_SCHEMA_SINT,
+ CTLV_SCHEMA_BOOL,
+ CTLV_SCHEMA_STRING,
+ CTLV_SCHEMA_BINARY,
+ CTLV_SCHEMA_ENUM,
+ CTLV_SCHEMA_FLAGS,
+ CTLV_SCHEMA_NEST,
+ CTLV_SCHEMA_BLOB,
+};
+
+/**
+ * struct ctlv_op_exec - Op-execution ioctl argument.
+ * @op_id: complete op ID; zero is invalid
+ * @request: struct ctlv_attr __user *, the mandatory complete request root
+ * @reply: struct ctlv_attr __user *, the success reply or the error
+ * information
+ * @request_len: readable bytes beginning at @request, at least one root header;
+ * the transport copy boundary, which may exceed the root's own length
+ * @reply_len: writable bytes beginning at @reply; input only, never
+ * overwritten by the kernel
+ * @generation: query only; zero on a first fragment, the previously returned
+ * value on continuation, and the query generation on output. Actions must
+ * set zero.
+ * @cursor: query only; zero starts a query and a nonzero value resumes it. On
+ * output it is the next cursor when the root carries
+ * CTLV_ATTR_F_FRAG_MORE and zero when no further fragment exists. Actions
+ * must set zero.
+ * @reserved: must be zero
+ *
+ * No size field: the ioctl number encodes the structure size and @reserved
+ * covers compatible growth. @request and @reply are fixed-width
+ * representations of userspace pointers so that the compat layout is identical.
+ */
+struct ctlv_op_exec {
+ __aligned_u64 op_id;
+ __aligned_u64 request;
+ __aligned_u64 reply;
+ __u32 request_len;
+ __u32 reply_len;
+ __aligned_u64 generation;
+ __aligned_u64 cursor;
+ __aligned_u64 reserved[2];
+};
+
+#define CTLV_IOC_MAGIC 0xBB
+
+#define CTLV_IOC_OP_EXEC _IOWR(CTLV_IOC_MAGIC, 0x00, struct ctlv_op_exec)
+
+/**
+ * struct ctlv_event_hdr - Header of one queued event record.
+ * @length: complete record length, this header plus the aligned root
+ * @flags: must be zero
+ * @op_id: complete op ID of the event op that produced the record
+ * @sequence: per open file description sequence number, assigned to every
+ * eligible enqueue attempt including dropped ones
+ *
+ * Exactly one root attr follows the header, and one read() returns one record.
+ */
+struct ctlv_event_hdr {
+ __u32 length;
+ __u32 flags;
+ __aligned_u64 op_id;
+ __aligned_u64 sequence;
+};
+
+/* Implementation limits, not wire-field maxima: raising them is compatible. */
+
+/* Request roots, action replies, query reply fragments and event roots. */
+#define CTLV_MAX_INLINE_MESSAGE_LEN 0x100000 /* 1 MiB */
+/* Includes the error information root. */
+#define CTLV_MAX_ERROR_LEN 0x4000 /* 16 KiB */
+/* The root attr is at depth zero. */
+#define CTLV_MAX_NEST_DEPTH 32
+#define CTLV_DEFAULT_QUERY_REPLY_LEN 0x10000 /* 64 KiB */
+#define CTLV_MAX_EVENT_QUEUE_LEN 0x1000000 /* 16 MiB */
+
+#endif /* _UAPI_LINUX_CTLV_H */
--
2.56.0
next prev 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 ` Jiri Pirko [this message]
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 ` [PATCH RFC 04/20] Documentation: ctlv: Add userspace ABI Jiri Pirko
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-3-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