blob: 4ed3e10b2e988cef60a89c16488a17bc77dc41ca [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.hardware.cpu.insntrace;
using zx;
const API_VERSION uint16 = 0;
/// The maximum number of traces that can be collected at once.
/// A "trace" is the instruction stream for one entity, cpu or thread.
const MAX_NUM_TRACES uint16 = 64;
/// The maximum number of supported address ranges.
const MAX_NUM_ADDR_RANGES uint16 = 2;
/// Tracing modes
type Mode = strict enum : uint8 {
// Trace each cpu, regardless of what's running on it.
CPU = 0;
// Trace specific threads.
THREAD = 1;
};
/// The allocation configuration of a trace.
type Allocation = struct {
mode Mode;
// The number of traces to create.
// In CPU mode this must be zx_system_get_num_cpus().
// In THREAD mode this is the maximum number of threads for which traces
// will be collected. Buffer space is allocated on demand, but the
// underlying data structure has a maximum. This value can be at most
// MAX_NUM_TRACES.
num_traces uint16;
};
/// An address range, as [start,end].
type AddressRange = struct {
start uint64;
end uint64;
};
/// A buffer's configuration.
type BufferConfig = struct {
/// A "buffer" is made up of `num_chunks` chunks with each chunk having
/// size `1<<chunk_order` pages.
num_chunks uint32;
/// log2 of the number of pages
chunk_order uint32;
/// If true then use circular buffering.
is_circular bool;
/// The value of the control register.
ctl uint64;
/// If non-zero then the address space of the instruction must match in
/// order for the instruction to be traced. On x86 architectures the
/// address space is specified by CR3.
address_space_match uint64;
/// If non-zero, tracing is restricted to these address ranges.
/// TODO(dje): There's only two, and vectors don't currently work here,
/// so spell these out individually
address_range_0 AddressRange;
address_range_1 AddressRange;
};
/// A buffer's runtime state.
type BufferState = struct {
/// This is the offset in the buffer where tracing stopped (treating all
/// buffers as one large one). If using a circular buffer then all of the
/// buffer may contain data, there's no current way to know if tracing
/// wrapped without scanning records.
capture_end uint64;
};
alias BufferDescriptor = uint32;
protocol Controller {
/// Initialize the trace.
/// This does not include allocating space for the trace buffers, that is
/// done later by `AllocateBuffer()`.
Initialize(struct {
allocation Allocation;
}) -> (struct {}) error zx.status;
/// Free all trace buffers and any other resources allocated for the trace.
/// This is also done when the connection is closed (as well as stopping
/// the trace).
/// May be called multiple times.
/// This can only fail when tracing in THREAD mode where tracing is
/// terminated differently, in which case the error is `ZX_ERR_BAD_STATE`.
// TODO(fxbug.dev/30840): Support terminating the trace in THREAD mode.
Terminate() -> (struct {}) error zx.status;
/// Return the trace allocation configuration.
GetAllocation() -> (struct {
allocation box<Allocation>;
});
/// Allocate a trace buffer.
/// When tracing cpus, buffers are auto-assigned to cpus: the resulting
/// trace buffer descriptor is the number of the cpu using the buffer.
AllocateBuffer(struct {
config BufferConfig;
}) -> (struct {
descriptor BufferDescriptor;
}) error zx.status;
/// Assign a buffer to a thread.
AssignThreadBuffer(resource struct {
descriptor BufferDescriptor;
thread zx.handle:THREAD;
}) -> (struct {}) error zx.status;
/// Release a previously assigned buffer from a thread.
ReleaseThreadBuffer(resource struct {
descriptor BufferDescriptor;
thread zx.handle:THREAD;
}) -> (struct {}) error zx.status;
/// Fetch a buffer's configuration.
GetBufferConfig(struct {
descriptor BufferDescriptor;
}) -> (struct {
config box<BufferConfig>;
});
/// Fetch runtime information about a buffer.
GetBufferState(struct {
descriptor BufferDescriptor;
}) -> (struct {
state box<BufferState>;
});
/// Fetch the handle of a chunk of a trace buffer.
GetChunkHandle(struct {
descriptor BufferDescriptor;
chunk_num uint32;
}) -> (resource struct {
buffer zx.handle:<VMO, optional>;
});
/// Free a previously allocated trace buffer.
FreeBuffer(struct {
descriptor BufferDescriptor;
}) -> ();
/// Start tracing.
/// Must be called after `Initialize()` + `AllocateBuffer()`,
/// with tracing off.
Start() -> ();
/// Stop tracing.
/// May be called any time after `Allocate()` has been called and before
/// `Free()`. If called at other times the call is ignored.
/// May be called multiple times.
// TODO(fxbug.dev/30840): Support terminating the trace in THREAD mode.
Stop() -> ();
};