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/.
| Number | Constant | Signature |
|---|---|---|
| 1090 | SYS_KMES_EMIT | kmes_emit(const char __user *event_type, u16 event_type_len, const void __user *payload, u32 payload_len) |
| 1091 | SYS_KMES_ATTACH | kmes_attach(unsigned int cpu_id, u64 __user *capacity) |
| 1092 | SYS_KMES_EMIT_BATCH | kmes_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.
| Offset | Size | Type | Field |
|---|---|---|---|
| 0 | 8 | __u64 | event_type |
| 8 | 2 | __u16 | event_type_len |
| 10 | 6 | __u8[6] | _pad0 |
| 16 | 8 | __u64 | payload |
| 24 | 4 | __u32 | payload_len |
| 28 | 4 | __u8[4] | _pad1 |
2.A.3 Constants #
Grouped as the header groups them.
Event origin class — kmes_event_header.origin_class.
| Constant | Value |
|---|---|
KMES_ORIGIN_USERSPACE | 0 |
KMES_ORIGIN_KMES | 1 |
KMES_ORIGIN_KACS | 2 |
KMES_ORIGIN_LCS | 3 |
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.
| Constant | Value |
|---|---|
KMES_ATTACH_QUERY_SLOTS | 0xFFFFFFFF |
Largest entry count a single SYS_KMES_EMIT_BATCH call accepts.
| Constant | Value |
|---|---|
KMES_BATCH_MAX_ENTRIES | 256 |
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.
| Constant | Value |
|---|---|
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_DWORD | 4 |
KMES_CONFIG_TYPE_REG_QWORD | 11 |
KMES_CONFIG_BUFFER_CAPACITY_TYPE | 11 |
KMES_CONFIG_BUFFER_CAPACITY_DEFAULT | 4194304 |
KMES_CONFIG_BUFFER_CAPACITY_MIN | 65536 |
KMES_CONFIG_BUFFER_CAPACITY_MAX | 268435456 |
KMES_CONFIG_MAX_EVENT_SIZE_TYPE | 4 |
KMES_CONFIG_MAX_EVENT_SIZE_DEFAULT | 65536 |
KMES_CONFIG_MAX_EVENT_SIZE_MIN | 1024 |
KMES_CONFIG_MAX_EVENT_SIZE_MAX | 4194304 |
KMES_CONFIG_MAX_NESTING_DEPTH_TYPE | 4 |
KMES_CONFIG_MAX_NESTING_DEPTH_DEFAULT | 32 |
KMES_CONFIG_MAX_NESTING_DEPTH_MIN | 4 |
KMES_CONFIG_MAX_NESTING_DEPTH_MAX | 256 |
KMES_CONFIG_MAX_EMIT_RATE_PER_PROCESS_TYPE | 4 |
KMES_CONFIG_MAX_EMIT_RATE_PER_PROCESS_DEFAULT | 10000 |
KMES_CONFIG_MAX_EMIT_RATE_PER_PROCESS_MIN | 100 |
KMES_CONFIG_MAX_EMIT_RATE_PER_PROCESS_MAX | 1000000 |
Privilege requirements.
Values mirror the corresponding KACS privilege bits while keeping this header standalone.
| Constant | Value |
|---|---|
KMES_EMIT_REQUIRED_PRIVILEGE | 0x0000000000200000 (1ULL << 21) |
KMES_ATTACH_REQUIRED_PRIVILEGE | 0x0000000000000100 (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.
| Constant | Value |
|---|---|
KMES_EVENT_SIZE_OFFSET | 0 |
KMES_EVENT_HEADER_SIZE_OFFSET | 4 |
KMES_EVENT_TIMESTAMP_NS_OFFSET | 8 |
KMES_EVENT_SEQUENCE_OFFSET | 16 |
KMES_EVENT_CPU_ID_OFFSET | 24 |
KMES_EVENT_ORIGIN_CLASS_OFFSET | 26 |
KMES_EVENT_EFFECTIVE_TOKEN_GUID_OFFSET | 27 |
KMES_EVENT_TRUE_TOKEN_GUID_OFFSET | 43 |
KMES_EVENT_PROCESS_GUID_OFFSET | 59 |
KMES_EVENT_TYPE_LEN_OFFSET | 75 |
Byte width of each identity GUID in the event header.
| Constant | Value |
|---|---|
KMES_EVENT_GUID_SIZE | 16 |
Byte size of the fixed event header — the offset at which the type string begins.
| Constant | Value |
|---|---|
KMES_EVENT_HEADER_BASE_SIZE | 77 |
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.
| Constant | Value |
|---|---|
KMES_RING_MAGIC | "KMESRING" |
KMES_RING_VERSION | 1 |
KMES_METADATA_PAGE_SIZE | 4096 |
KMES_METADATA_TOTAL_SIZE | 8192 |
KMES_MAPPING_PRODUCER_OFFSET | 0 |
KMES_MAPPING_CONSUMER_OFFSET | 4096 |
KMES_MAPPING_DATA_OFFSET | 8192 |
Field offsets within the producer metadata page.
| Constant | Value |
|---|---|
KMES_PRODUCER_MAGIC_OFFSET | 0 |
KMES_PRODUCER_VERSION_OFFSET | 8 |
KMES_PRODUCER_CPU_ID_OFFSET | 12 |
KMES_PRODUCER_CAPACITY_OFFSET | 16 |
KMES_PRODUCER_DATA_OFFSET_OFFSET | 24 |
KMES_PRODUCER_GENERATION_OFFSET | 32 |
KMES_PRODUCER_WRITE_POS_OFFSET | 64 |
KMES_PRODUCER_TAIL_POS_OFFSET | 72 |
KMES_PRODUCER_FUTEX_COUNTER_OFFSET | 128 |
Field offset within the consumer metadata page.
| Constant | Value |
|---|---|
KMES_CONSUMER_NEED_WAKE_OFFSET | 0 |
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.
| Constant | Value | Notes |
|---|---|---|
KMES_DROP_RING_FULL | 0 | capacity overwrite; oldest event dropped |
KMES_DROP_TAIL_RESYNC | 1 | corrupt ring header; pending events silently discarded |
KMES_DROP_VALIDATE | 2 | single kernel-emit size/type reject |
KMES_DROP_BATCH_STRUCT_INVALID | 3 | kernel-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.
| Constant | Value | Notes |
|---|---|---|
KMES_SWAP_BEGIN | 0 | capacity change accepted, rings allocating |
KMES_SWAP_COMPLETE | 1 | swap committed across all CPUs |
KMES_SWAP_MIGRATE_SKIP | 2 | shrink: old event too large, skipped (ret=bytes) |
KMES_SWAP_FAILED | 3 | swap 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.
| Constant | Value | Notes |
|---|---|---|
KMES_RATE_THROTTLE | 0 | emit denied -EAGAIN; tokens < requested |
KMES_RATE_RECONFIGURE | 1 | max 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.
| Constant | Value | Notes |
|---|---|---|
KMES_WAKE_NOTE | 0 | wake armed; futex counter incremented |
KMES_WAKE_FUTEX | 1 | blocked consumers woken |
kmes_ring_lifecycle reason — a generation-stable ring object transition.
ret is the outcome. Emitted by kmes:kmes_ring_lifecycle.
| Constant | Value | Notes |
|---|---|---|
KMES_RING_ALLOC | 0 | ring backing allocated (or -ENOMEM) |
KMES_RING_FREE | 1 | ring backing released |
KMES_RING_PRODUCER_PAGE | 2 | producer shmem/meta page attached |
KMES_RING_CONSUMER_FD | 3 | consumer 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.
| Constant | Value | Notes |
|---|---|---|
KMES_INGRESS_OVER_MAX | 0 | event_size exceeds configured max_event_size |
KMES_INGRESS_OVER_CAP_HALF | 1 | event_size exceeds ring_capacity/2 |
KMES_INGRESS_SIZE_OVERFLOW | 2 | declared header/event size overflow |
KMES_INGRESS_EMIT_OVERSIZE | 3 | staged event exceeds live capacity/2 at emit |
KMES_INGRESS_BATCH_PARTIAL | 4 | batch 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.
| Constant | Value | Notes |
|---|---|---|
KMES_VAL_EINVAL | 0 | Rust msgpack/structural validation rejected |