Appendix 2.A KMES ABI Reference

Every name, value, offset and size in this appendix is generated from pkm/uapi/pkm/kmes.h by pkm/tools/gen-kmes-abi.py, with struct layouts measured by compiling a probe against the real header. Regenerate it whenever the ABI changes; do not edit it by hand. The names here are the ones a program actually compiles against.

What a compiler cannot measure -- the error vocabulary of each syscall, the privilege each requires by name, what the configuration keys do, and the implementation bounds that are not in the header -- is in the notes appendix, §2.B, which this generator does not touch.

2.A.1 Syscall numbers #

Signatures are read from the SYSCALL_DEFINE sites in pkm/kmes/.

NumberConstantSignature
1090SYS_KMES_EMITkmes_emit(const char __user *event_type, u16 event_type_len, const void __user *payload, u32 payload_len)
1091SYS_KMES_ATTACHkmes_attach(unsigned int cpu_id, u64 __user *capacity)
1092SYS_KMES_EMIT_BATCHkmes_emit_batch(const struct kmes_emit_entry __user *entries, u32 count, u32 __user *emitted_out)

2.A.2 Structure layouts #

Offsets and sizes are measured, not declared.

2.A.2.1 struct kmes_emit_entry #

Total size 32 bytes.

OffsetSizeTypeField
08__u64event_type
82__u16event_type_len
106__u8[6]_pad0
168__u64payload
244__u32payload_len
284__u8[4]_pad1

2.A.3 Constants #

Grouped as the header groups them.

Event origin class — kmes_event_header.origin_class.

ConstantValue
KMES_ORIGIN_USERSPACE0
KMES_ORIGIN_KMES1
KMES_ORIGIN_KACS2
KMES_ORIGIN_LCS3

Ring-slot discovery.

Ring slots are indexed by logical CPU id and the array is sized by the kernel's nr_cpu_ids, so a slot inside the array holds no ring when that CPU is not possible. Counting up from 0 until SYS_KMES_ATTACH returns -EINVAL therefore stops at the first hole and misses every ring above it, leaving those CPUs' events permanently unreachable.

Call SYS_KMES_ATTACH with cpu_id KMES_ATTACH_QUERY_SLOTS to learn the slot count instead. It writes the count through the capacity argument, returns 0, and opens no descriptor. Enumerate 0 .. count-1 and treat -EINVAL as "this slot holds no ring", not as the end of the array.

The sentinel is outside the index space for good: nr_cpu_ids is bounded by CONFIG_NR_CPUS, which cannot reach 2^32-1.

ConstantValue
KMES_ATTACH_QUERY_SLOTS0xFFFFFFFF

Largest entry count a single SYS_KMES_EMIT_BATCH call accepts.

ConstantValue
KMES_BATCH_MAX_ENTRIES256

Runtime configuration registry location and keys.

Type values match the LCS REG_* constants: REG_DWORD is 4 and REG_QWORD is 11. They are repeated here so <pkm/kmes.h> remains standalone.

ConstantValue
KMES_CONFIG_ROOT_HIVE"Machine"
KMES_CONFIG_ROOT_SYSTEM_KEY"System"
KMES_CONFIG_ROOT_KMES_KEY"KMES"
KMES_CONFIG_KEY_BUFFER_CAPACITY"BufferCapacity"
KMES_CONFIG_KEY_MAX_EVENT_SIZE"MaxEventSize"
KMES_CONFIG_KEY_MAX_NESTING_DEPTH"MaxNestingDepth"
KMES_CONFIG_KEY_MAX_EMIT_RATE_PER_PROCESS"MaxEmitRatePerProcess"
KMES_CONFIG_TYPE_REG_DWORD4
KMES_CONFIG_TYPE_REG_QWORD11
KMES_CONFIG_BUFFER_CAPACITY_TYPE11
KMES_CONFIG_BUFFER_CAPACITY_DEFAULT4194304
KMES_CONFIG_BUFFER_CAPACITY_MIN65536
KMES_CONFIG_BUFFER_CAPACITY_MAX268435456
KMES_CONFIG_MAX_EVENT_SIZE_TYPE4
KMES_CONFIG_MAX_EVENT_SIZE_DEFAULT65536
KMES_CONFIG_MAX_EVENT_SIZE_MIN1024
KMES_CONFIG_MAX_EVENT_SIZE_MAX4194304
KMES_CONFIG_MAX_NESTING_DEPTH_TYPE4
KMES_CONFIG_MAX_NESTING_DEPTH_DEFAULT32
KMES_CONFIG_MAX_NESTING_DEPTH_MIN4
KMES_CONFIG_MAX_NESTING_DEPTH_MAX256
KMES_CONFIG_MAX_EMIT_RATE_PER_PROCESS_TYPE4
KMES_CONFIG_MAX_EMIT_RATE_PER_PROCESS_DEFAULT10000
KMES_CONFIG_MAX_EMIT_RATE_PER_PROCESS_MIN100
KMES_CONFIG_MAX_EMIT_RATE_PER_PROCESS_MAX1000000

Privilege requirements.

Values mirror the corresponding KACS privilege bits while keeping this header standalone.

ConstantValue
KMES_EMIT_REQUIRED_PRIVILEGE0x0000000000200000 (1ULL << 21)
KMES_ATTACH_REQUIRED_PRIVILEGE0x0000000000000100 (1ULL << 8)

On-wire event header.

Every event in a ring begins with a fixed 77-byte header, followed by event_type_len bytes of type string and then the msgpack payload. Events abut at event_size stride, so a header is not generally aligned; it crosses the ABI as raw bytes, not a C struct. Its fields, in order:

__u32  event_size            total event byte length (header + type + payload)
__u32  header_size           byte offset from the event start to the payload
__u64  timestamp_ns
__u64  sequence
__u16  cpu_id
__u8   origin_class          one of KMES_ORIGIN_* above
__u8   effective_token_guid[16]
__u8   true_token_guid[16]
__u8   process_guid[16]
__u16  event_type_len        length of the type string following the header

The three GUIDs are 16-byte Microsoft GUID binary values (Data1/Data2/Data3 little-endian, Data4 raw), captured from KACS at emission time; the null GUID (16 zero bytes) means identity was unavailable (KACS not initialised, or no process context). KMES copies them opaquely.

Read each field at its KMES_EVENT_*_OFFSET below. header_size locates the payload: it is KMES_EVENT_HEADER_BASE_SIZE + event_type_len. A future revision may grow the header, so consumers must use header_size, not the end of the type string, to find the payload.

ConstantValue
KMES_EVENT_SIZE_OFFSET0
KMES_EVENT_HEADER_SIZE_OFFSET4
KMES_EVENT_TIMESTAMP_NS_OFFSET8
KMES_EVENT_SEQUENCE_OFFSET16
KMES_EVENT_CPU_ID_OFFSET24
KMES_EVENT_ORIGIN_CLASS_OFFSET26
KMES_EVENT_EFFECTIVE_TOKEN_GUID_OFFSET27
KMES_EVENT_TRUE_TOKEN_GUID_OFFSET43
KMES_EVENT_PROCESS_GUID_OFFSET59
KMES_EVENT_TYPE_LEN_OFFSET75

Byte width of each identity GUID in the event header.

ConstantValue
KMES_EVENT_GUID_SIZE16

Byte size of the fixed event header — the offset at which the type string begins.

ConstantValue
KMES_EVENT_HEADER_BASE_SIZE77

Ring-buffer metadata layout.

An attached ring is mmap'd as:

page 0          producer metadata (read-only to the consumer)
page 1          consumer metadata (read-write)
ring data       the event bytes, mapped twice back-to-back so an event
                that wraps the buffer end is still contiguous.

The producer metadata page begins with KMES_RING_MAGIC.

ConstantValue
KMES_RING_MAGIC"KMESRING"
KMES_RING_VERSION1
KMES_METADATA_PAGE_SIZE4096
KMES_METADATA_TOTAL_SIZE8192
KMES_MAPPING_PRODUCER_OFFSET0
KMES_MAPPING_CONSUMER_OFFSET4096
KMES_MAPPING_DATA_OFFSET8192

Field offsets within the producer metadata page.

ConstantValue
KMES_PRODUCER_MAGIC_OFFSET0
KMES_PRODUCER_VERSION_OFFSET8
KMES_PRODUCER_CPU_ID_OFFSET12
KMES_PRODUCER_CAPACITY_OFFSET16
KMES_PRODUCER_DATA_OFFSET_OFFSET24
KMES_PRODUCER_GENERATION_OFFSET32
KMES_PRODUCER_WRITE_POS_OFFSET64
KMES_PRODUCER_TAIL_POS_OFFSET72
KMES_PRODUCER_FUTEX_COUNTER_OFFSET128

Field offset within the consumer metadata page.

ConstantValue
KMES_CONSUMER_NEED_WAKE_OFFSET0

2.A.4 Tracepoint diagnostic codes #

From uapi/pkm/trace.h. These are a diagnostic contract for ftrace, perf and eBPF consumers, letting a tool decode a kmes: event's reason, op or state field without recompiling against a specific kernel. No KMES syscall accepts or returns them, and values are append-only.

kmes_drop reason — why the KMES ring machinery lost an event.

RING_FULL is a normal overwrite; TAIL_RESYNC is the silent corruption- recovery path that discards ALL pending events; VALIDATE is a kernel- emit size/type reject at the ring boundary; BATCH_STRUCT_INVALID is a per-entry structural reject in the kernel batch path. Emitted by kmes:kmes_drop. No event payload bytes.

ConstantValueNotes
KMES_DROP_RING_FULL0capacity overwrite; oldest event dropped
KMES_DROP_TAIL_RESYNC1corrupt ring header; pending events silently discarded
KMES_DROP_VALIDATE2single kernel-emit size/type reject
KMES_DROP_BATCH_STRUCT_INVALID3kernel-batch entry structurally invalid

kmes_swap reason — a bounded ring capacity swap lifecycle marker.

BEGIN and COMPLETE/FAILED are whole-topology (cpu field is U16_MAX); MIGRATE_SKIP is per-CPU and carries the skipped byte count in ret. Emitted by kmes:kmes_swap.

ConstantValueNotes
KMES_SWAP_BEGIN0capacity change accepted, rings allocating
KMES_SWAP_COMPLETE1swap committed across all CPUs
KMES_SWAP_MIGRATE_SKIP2shrink: old event too large, skipped (ret=bytes)
KMES_SWAP_FAILED3swap aborted; ret is the errno

kmes_rate reason — the per-process token-bucket backpressure signal.

THROTTLE is an -EAGAIN emit rejection; RECONFIGURE marks an admin rate change clamping all buckets. Emitted by kmes:kmes_rate.

ConstantValueNotes
KMES_RATE_THROTTLE0emit denied -EAGAIN; tokens < requested
KMES_RATE_RECONFIGURE1max emit rate reconfigured for all buckets

kmes_wake reason — consumer wakeup machinery.

NOTE arms a pending wake; FUTEX is the actual futex wake of blocked consumers. Emitted by kmes:kmes_wake.

ConstantValueNotes
KMES_WAKE_NOTE0wake armed; futex counter incremented
KMES_WAKE_FUTEX1blocked consumers woken

kmes_ring_lifecycle reason — a generation-stable ring object transition.

ret is the outcome. Emitted by kmes:kmes_ring_lifecycle.

ConstantValueNotes
KMES_RING_ALLOC0ring backing allocated (or -ENOMEM)
KMES_RING_FREE1ring backing released
KMES_RING_PRODUCER_PAGE2producer shmem/meta page attached
KMES_RING_CONSUMER_FD3consumer anon-inode fd created

kmes_ingress_reject reason — why an emit request was rejected before the ring.

OVER_MAX/OVER_CAP_HALF/SIZE_OVERFLOW are declared-size rejects; EMIT_OVERSIZE is a staged event too large at ring-write time; BATCH_PARTIAL marks a batch that validated fewer entries than requested. Emitted by kmes:kmes_ingress_reject.

ConstantValueNotes
KMES_INGRESS_OVER_MAX0event_size exceeds configured max_event_size
KMES_INGRESS_OVER_CAP_HALF1event_size exceeds ring_capacity/2
KMES_INGRESS_SIZE_OVERFLOW2declared header/event size overflow
KMES_INGRESS_EMIT_OVERSIZE3staged event exceeds live capacity/2 at emit
KMES_INGRESS_BATCH_PARTIAL4batch staged fewer entries than requested

kmes_validate reason — the C-boundary result of the Rust staged-event validator.

The Rust side collapses its structural checks into one nonzero return; only visible type/payload lengths and ret are recorded here. Emitted by kmes:kmes_validate.

ConstantValueNotes
KMES_VAL_EINVAL0Rust msgpack/structural validation rejected

Edit this page