These docs are under active development and cover the v0.20 Kobicha security model.
On this page
§2.2

KMES Consumption

§2.2.1 Attachment

On startup, eventd MUST discover the CPU count and attach to each per-CPU ring buffer by calling kmes_attach(cpu_id) (PSD-003 §4.1) with incrementing cpu_id values starting from 0 until EINVAL is returned. Each call returns a single file descriptor for that CPU's ring buffer. eventd MUST map each file descriptor to obtain the per-CPU ring buffer. The caller's effective token MUST hold SeSecurityPrivilege.

eventd MUST read the capacity value returned by kmes_attach and use it to compute the mapping size (8192 + 2 * capacity).

§2.2.2 Drain threads

eventd MUST create one drain thread per CPU. Each drain thread is responsible for reading events from exactly one per-CPU ring buffer. A drain thread MUST NOT read from more than one ring buffer.

Each drain thread MUST follow the read protocol defined in PSD-003 §5.1, including:

  • Initialising read_pos to tail_pos on first attachment, starting from the oldest surviving event.
  • Following the drain loop: load write_pos with acquire, check for lapping via tail_pos, validate event structural integrity, advance read_pos by event_size.
  • Performing the torn read check (re-reading tail_pos after reading an event to detect concurrent overwrite).
  • Using the notification wait protocol (need_wake, futex_wait) when no events are available, to avoid spinning.

§2.2.3 Event copying

When a drain thread reads an event from the ring buffer, it MUST copy the event data (header and payload) into process-local memory before advancing read_pos. The drain thread MUST NOT pass pointers into the mapped ring buffer region to the writer thread, as the ring buffer memory may be overwritten by KMES at any time after read_pos advances past the event.

The copy is bounded by the event's event_size field. The drain thread MUST NOT read beyond event_size bytes from the event's position in the ring buffer.

§2.2.4 Generation changes

After completing a drain cycle, the drain thread MUST check the ring buffer's generation field as specified in PSD-003 §5.1. If the generation has changed (due to a ring buffer resize triggered by a BufferCapacity configuration change), the drain thread MUST:

  1. Record the sequence number of the last successfully processed event.
  2. Call kmes_attach(cpu_id) to obtain a new file descriptor for this CPU's resized ring buffer.
  3. Map the new ring buffer.
  4. Unmap the old ring buffer and close the old file descriptor.
  5. Scan events in the new buffer to find the first event with a sequence number greater than the recorded sequence number.
  6. Resume draining from that position.

Each drain thread handles generation changes independently. There is no coordination between drain threads during reattach. Each drain thread attaches only to its own CPU's ring buffer.

Events MUST NOT be lost or duplicated during a generation change.

§2.2.5 Sequence tracking

Each drain thread MUST maintain the last seen sequence number for its CPU. This value is used for gap detection (§2.3) and for resumption after generation changes or restarts.

On startup, if eventd has previously persisted data for this boot (identified by boot ID), it MUST read the last persisted sequence number per CPU from the event store and initialise the drain thread's sequence tracking from that value. This allows eventd to detect gaps that span a restart.

If no prior data exists for the current boot, the drain thread initialises its sequence tracker to 0 (no events seen). The first event on each CPU has sequence number 1 (PSD-003 §2.1).