| // Copyright 2016 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. |
| |
| #pragma once |
| |
| #include <zircon/compiler.h> |
| #include <stdint.h> |
| |
| #ifdef __Fuchsia__ |
| #include <zircon/device/ioctl.h> |
| #include <zircon/device/ioctl-wrapper.h> |
| #include <zircon/types.h> |
| #include <stddef.h> |
| #endif |
| |
| __BEGIN_CDECLS |
| |
| #if !defined(__x86_64__) |
| #error "unsupported architecture" |
| #endif |
| |
| #define IPT_MSR_BITS(len, shift) (((1ULL << (len)) - 1) << (shift)) |
| |
| // Bits in the IA32_RTIT_CTL MSR. |
| // These bits are writable by the user with ioctl_ipt_set_ctl_config. |
| // The driver will override a setting if it's unsafe (e.g., causes #gpf). |
| |
| #define IPT_CTL_CYC_EN_SHIFT (1) |
| #define IPT_CTL_CYC_EN_LEN (1) |
| #define IPT_CTL_CYC_EN_MASK IPT_MSR_BITS(IPT_CTL_CYC_EN_LEN, IPT_CTL_CYC_EN_SHIFT) |
| |
| #define IPT_CTL_OS_ALLOWED_SHIFT (2) |
| #define IPT_CTL_OS_ALLOWED_LEN (1) |
| #define IPT_CTL_OS_ALLOWED_MASK IPT_MSR_BITS(IPT_CTL_OS_ALLOWED_LEN, IPT_CTL_OS_ALLOWED_SHIFT) |
| |
| #define IPT_CTL_USER_ALLOWED_SHIFT (3) |
| #define IPT_CTL_USER_ALLOWED_LEN (1) |
| #define IPT_CTL_USER_ALLOWED_MASK IPT_MSR_BITS(IPT_CTL_USER_ALLOWED_LEN, IPT_CTL_USER_ALLOWED_SHIFT) |
| |
| #define IPT_CTL_POWER_EVENT_EN_SHIFT (4) |
| #define IPT_CTL_POWER_EVENT_EN_LEN (1) |
| #define IPT_CTL_POWER_EVENT_EN_MASK IPT_MSR_BITS(IPT_CTL_POWER_EVENT_EN_LEN, IPT_CTL_POWER_EVENT_EN_SHIFT) |
| |
| #define IPT_CTL_FUP_ON_PTW_SHIFT (5) |
| #define IPT_CTL_FUP_ON_PTW_LEN (1) |
| #define IPT_CTL_FUP_ON_PTW_MASK IPT_MSR_BITS(IPT_CTL_FUP_ON_PTW_LEN, IPT_CTL_FUP_ON_PTW_SHIFT) |
| |
| #define IPT_CTL_CR3_FILTER_SHIFT (7) |
| #define IPT_CTL_CR3_FILTER_LEN (1) |
| #define IPT_CTL_CR3_FILTER_MASK IPT_MSR_BITS(IPT_CTL_CR3_FILTER_LEN, IPT_CTL_CR3_FILTER_SHIFT) |
| |
| #define IPT_CTL_MTC_EN_SHIFT (9) |
| #define IPT_CTL_MTC_EN_LEN (1) |
| #define IPT_CTL_MTC_EN_MASK IPT_MSR_BITS(IPT_CTL_MTC_EN_LEN, IPT_CTL_MTC_EN_SHIFT) |
| |
| #define IPT_CTL_TSC_EN_SHIFT (10) |
| #define IPT_CTL_TSC_EN_LEN (1) |
| #define IPT_CTL_TSC_EN_MASK IPT_MSR_BITS(IPT_CTL_TSC_EN_LEN, IPT_CTL_TSC_EN_SHIFT) |
| |
| #define IPT_CTL_DIS_RETC_SHIFT (11) |
| #define IPT_CTL_DIS_RETC_LEN (1) |
| #define IPT_CTL_DIS_RETC_MASK IPT_MSR_BITS(IPT_CTL_DIS_RETC_LEN, IPT_CTL_DIS_RETC_SHIFT) |
| |
| #define IPT_CTL_PTW_EN_SHIFT (12) |
| #define IPT_CTL_PTW_EN_LEN (1) |
| #define IPT_CTL_PTW_EN_MASK IPT_MSR_BITS(IPT_CTL_PTW_EN_LEN, IPT_CTL_PTW_EN_SHIFT) |
| |
| #define IPT_CTL_BRANCH_EN_SHIFT (13) |
| #define IPT_CTL_BRANCH_EN_LEN (1) |
| #define IPT_CTL_BRANCH_EN_MASK IPT_MSR_BITS(IPT_CTL_BRANCH_EN_LEN, IPT_CTL_BRANCH_EN_SHIFT) |
| |
| #define IPT_CTL_MTC_FREQ_SHIFT (14) |
| #define IPT_CTL_MTC_FREQ_LEN (4) |
| #define IPT_CTL_MTC_FREQ_MASK IPT_MSR_BITS(IPT_CTL_MTC_FREQ_LEN, IPT_CTL_MTC_FREQ_SHIFT) |
| |
| #define IPT_CTL_CYC_THRESH_SHIFT (19) |
| #define IPT_CTL_CYC_THRESH_LEN (4) |
| #define IPT_CTL_CYC_THRESH_MASK IPT_MSR_BITS(IPT_CTL_CYC_THRESH_LEN, IPT_CTL_CYC_THRESH_SHIFT) |
| |
| #define IPT_CTL_PSB_FREQ_SHIFT (24) |
| #define IPT_CTL_PSB_FREQ_LEN (4) |
| #define IPT_CTL_PSB_FREQ_MASK IPT_MSR_BITS(IPT_CTL_PSB_FREQ_LEN, IPT_CTL_PSB_FREQ_SHIFT) |
| |
| #define IPT_CTL_ADDR0_SHIFT (32) |
| #define IPT_CTL_ADDR_LEN (4) |
| #define IPT_CTL_ADDR0_MASK IPT_MSR_BITS(IPT_CTL_ADDR_LEN, IPT_CTL_ADDR0_SHIFT) |
| |
| #define IPT_CTL_ADDR1_SHIFT (36) |
| #define IPT_CTL_ADDR1_MASK IPT_MSR_BITS(IPT_CTL_ADDR_LEN, IPT_CTL_ADDR1_SHIFT) |
| |
| #define IPT_CTL_ADDR2_SHIFT (40) |
| #define IPT_CTL_ADDR2_MASK IPT_MSR_BITS(IPT_CTL_ADDR_LEN, IPT_CTL_ADDR2_SHIFT) |
| |
| #define IPT_CTL_ADDR3_SHIFT (44) |
| #define IPT_CTL_ADDR3_MASK IPT_MSR_BITS(IPT_CTL_ADDR_LEN, IPT_CTL_ADDR3_SHIFT) |
| |
| // Other bits in IA32_RTIT_CTL MSR, not writable with ioctl_ipt_set_ctl_config. |
| |
| #define IPT_CTL_TRACE_EN_SHIFT (0) |
| #define IPT_CTL_TRACE_EN_LEN (1) |
| #define IPT_CTL_TRACE_EN_MASK IPT_MSR_BITS(IPT_CTL_TRACE_EN_LEN, IPT_CTL_TRACE_EN_SHIFT) |
| |
| #define IPT_CTL_FABRIC_EN_SHIFT (6) |
| #define IPT_CTL_FABRIC_EN_LEN (1) |
| #define IPT_CTL_FABRIC_EN_MASK IPT_MSR_BITS(IPT_CTL_FABRIC_EN_LEN, IPT_CTL_FABRIC_EN_SHIFT) |
| |
| #define IPT_CTL_TOPA_SHIFT (8) |
| #define IPT_CTL_TOPA_LEN (1) |
| #define IPT_CTL_TOPA_MASK IPT_MSR_BITS(IPT_CTL_TOPA_LEN, IPT_CTL_TOPA_SHIFT) |
| |
| // Masks for reading IA32_RTIT_STATUS. |
| |
| #define IPT_STATUS_FILTER_EN_SHIFT (0) |
| #define IPT_STATUS_FILTER_EN_LEN (1) |
| #define IPT_STATUS_FILTER_EN_MASK IPT_MSR_BITS(IPT_STATUS_FILTER_EN_LEN, IPT_STATUS_FILTER_EN_SHIFT) |
| |
| #define IPT_STATUS_CONTEXT_EN_SHIFT (1) |
| #define IPT_STATUS_CONTEXT_EN_LEN (1) |
| #define IPT_STATUS_CONTEXT_EN_MASK IPT_MSR_BITS(IPT_STATUS_CONTEXT_EN_LEN, IPT_STATUS_CONTEXT_EN_SHIFT) |
| |
| #define IPT_STATUS_TRIGGER_EN_SHIFT (2) |
| #define IPT_STATUS_TRIGGER_EN_LEN (1) |
| #define IPT_STATUS_TRIGGER_EN_MASK IPT_MSR_BITS(IPT_STATUS_TRIGGER_EN_LEN, IPT_STATUS_TRIGGER_EN_SHIFT) |
| |
| #define IPT_STATUS_ERROR_SHIFT (4) |
| #define IPT_STATUS_ERROR_LEN (1) |
| #define IPT_STATUS_ERROR_MASK IPT_MSR_BITS(IPT_STATUS_ERROR_LEN, IPT_STATUS_ERROR_SHIFT) |
| |
| #define IPT_STATUS_STOPPED_SHIFT (5) |
| #define IPT_STATUS_STOPPED_LEN (1) |
| #define IPT_STATUS_STOPPED_MASK IPT_MSR_BITS(IPT_STATUS_STOPPED_LEN, IPT_STATUS_STOPPED_SHIFT) |
| |
| #define IPT_STATUS_PACKET_BYTE_COUNT_SHIFT (32) |
| #define IPT_STATUS_PACKET_BYTE_COUNT_LEN (17) |
| #define IPT_STATUS_PACKET_BYTE_COUNT_MASK \ |
| IPT_MSR_BITS(IPT_STATUS_IPT_STATUS_PACKET_BYTE_COUNT_LEN_LEN, \ |
| IPT_STATUS_IPT_STATUS_PACKET_BYTE_COUNT_LEN_SHIFT) |
| |
| // Maximum number of address ranges that h/w may support. |
| #define IPT_MAX_NUM_ADDR_RANGES 4 |
| |
| // Valid ToPA entry sizes. |
| #define IPT_TOPA_MIN_SHIFT 12 |
| #define IPT_TOPA_MAX_SHIFT 27 |
| |
| // These bits are for internal use |
| |
| // Macros for building entries for the Table of Physical Addresses |
| #define IPT_TOPA_ENTRY_PHYS_ADDR(x) ((uint64_t)(x) & ~((1ULL<<12)-1)) |
| #define IPT_TOPA_ENTRY_SIZE(size_log2) ((uint64_t)((size_log2) - 12) << 6) |
| #define IPT_TOPA_ENTRY_STOP (1ULL << 4) |
| #define IPT_TOPA_ENTRY_INT (1ULL << 2) |
| #define IPT_TOPA_ENTRY_END (1ULL << 0) |
| |
| // Macros for extracting info from ToPA entries |
| #define IPT_TOPA_ENTRY_EXTRACT_PHYS_ADDR(e) \ |
| ((zx_paddr_t)((e) & ~((1ULL<<12)-1))) |
| #define IPT_TOPA_ENTRY_EXTRACT_SIZE(e) ((uint)((((e) >> 6) & 0xf) + 12)) |
| |
| // Arbitarily picked constants for ourselves. |
| // ToPA tables are 16KB in size (technically can be up to 256MB). |
| // A 16KB table provides 2047 non-END entries, so at the |
| // minimum can provide a capture buffer of just under 8MB. |
| #define IPT_TOPA_MAX_TABLE_ENTRIES 2048 |
| |
| // The PT register set. |
| // This is accessed via mtrace, but basically it's a regset. |
| typedef struct { |
| uint64_t ctl; |
| uint64_t status; |
| uint64_t output_base; |
| uint64_t output_mask_ptrs; |
| uint64_t cr3_match; |
| struct { |
| uint64_t a,b; |
| } addr_ranges[IPT_MAX_NUM_ADDR_RANGES]; |
| } zx_x86_pt_regs_t; |
| |
| // Two "modes" of tracing are supported: |
| // trace each cpu, regardless of what's running on it |
| #define IPT_MODE_CPUS 0 |
| // trace specific threads |
| #define IPT_MODE_THREADS 1 |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #ifdef __Fuchsia__ |
| |
| // ioctls |
| |
| // set the trace mode, either cpus or threads |
| // Input: one of IPT_MODE_CPUS, IPT_MODE_THREADS |
| #define IOCTL_IPT_SET_MODE \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 0) |
| IOCTL_WRAPPER_IN(ioctl_ipt_set_mode, IOCTL_IPT_SET_MODE, uint32_t); |
| |
| typedef struct { |
| uint32_t num_buffers; |
| // #pages as a power of 2 |
| uint32_t buffer_order; |
| bool is_circular; |
| uint64_t ctl; |
| uint64_t cr3_match; |
| struct { |
| uint64_t a,b; |
| } addr_ranges[IPT_MAX_NUM_ADDR_RANGES]; |
| } ioctl_ipt_buffer_config_t; |
| |
| // allocate a trace buffer |
| // Input: ioctl_ipt_buffer_config_t |
| // Output: trace buffer descriptor (think file descriptor for trace buffers) |
| // When tracing cpus, buffers are auto-assigned to cpus: the resulting trace |
| // buffer descriptor is the number of the cpu using the buffer. |
| #define IOCTL_IPT_ALLOC_BUFFER \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 1) |
| IOCTL_WRAPPER_INOUT(ioctl_ipt_alloc_buffer, IOCTL_IPT_ALLOC_BUFFER, ioctl_ipt_buffer_config_t, uint32_t); |
| |
| typedef struct { |
| // for IOCTL_KIND_SET_HANDLE first element must be the handle |
| zx_handle_t thread; |
| uint32_t descriptor; |
| } ioctl_ipt_assign_buffer_thread_t; |
| |
| // assign a buffer to a thread |
| // Input: ioctl_ipt_assign_buffer_thread_t |
| #define IOCTL_IPT_ASSIGN_BUFFER_THREAD \ |
| IOCTL(IOCTL_KIND_SET_HANDLE, IOCTL_FAMILY_IPT, 3) |
| IOCTL_WRAPPER_IN(ioctl_ipt_assign_buffer_thread, IOCTL_IPT_ASSIGN_BUFFER_THREAD, |
| ioctl_ipt_assign_buffer_thread_t); |
| |
| // release a buffer from a thread |
| // Input: ioctl_ipt_assign_buffer_thread_t |
| #define IOCTL_IPT_RELEASE_BUFFER_THREAD \ |
| IOCTL(IOCTL_KIND_SET_HANDLE, IOCTL_FAMILY_IPT, 5) |
| IOCTL_WRAPPER_IN(ioctl_ipt_release_buffer_thread, IOCTL_IPT_RELEASE_BUFFER_THREAD, |
| ioctl_ipt_assign_buffer_thread_t); |
| |
| // return config data for a trace buffer |
| // Input: trace buffer descriptor |
| // Output: ioctl_ipt_trace_buffer_config_t |
| #define IOCTL_IPT_GET_BUFFER_CONFIG \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 6) |
| IOCTL_WRAPPER_INOUT(ioctl_ipt_get_buffer_config, IOCTL_IPT_GET_BUFFER_CONFIG, |
| uint32_t, ioctl_ipt_buffer_config_t); |
| |
| // This contains the run-time produced data about the buffer. |
| // Not the trace data itself, just info about the data. |
| typedef struct { |
| // N.B. 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. |
| uint64_t capture_end; |
| } ioctl_ipt_buffer_info_t; |
| |
| // get trace data associated with the buffer |
| // Input: trace buffer descriptor |
| // Output: ioctl_ipt_buffer_info_t |
| #define IOCTL_IPT_GET_BUFFER_INFO \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 7) |
| IOCTL_WRAPPER_INOUT(ioctl_ipt_get_buffer_info, IOCTL_IPT_GET_BUFFER_INFO, |
| uint32_t, ioctl_ipt_buffer_info_t); |
| |
| typedef struct { |
| uint32_t descriptor; |
| uint32_t buffer_num; |
| } ioctl_ipt_buffer_handle_req_t; |
| |
| // return a handle of a trace buffer |
| // There is no API to get N handles, we have to get them one at a time. |
| // [There's no point in trying to micro-optimize this and, say, get 3 at |
| // a time.] |
| #define IOCTL_IPT_GET_BUFFER_HANDLE \ |
| IOCTL(IOCTL_KIND_GET_HANDLE, IOCTL_FAMILY_IPT, 8) |
| IOCTL_WRAPPER_INOUT(ioctl_ipt_get_buffer_handle, IOCTL_IPT_GET_BUFFER_HANDLE, |
| ioctl_ipt_buffer_handle_req_t, zx_handle_t); |
| |
| // free a trace buffer |
| // Input: trace buffer descriptor |
| #define IOCTL_IPT_FREE_BUFFER \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 9) |
| IOCTL_WRAPPER_IN(ioctl_ipt_free_buffer, IOCTL_IPT_FREE_BUFFER, |
| uint32_t); |
| |
| // must be called prior to START, allocate buffers of the specified size |
| #define IOCTL_IPT_CPU_MODE_ALLOC \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 10) |
| IOCTL_WRAPPER(ioctl_ipt_cpu_mode_alloc, IOCTL_IPT_CPU_MODE_ALLOC); |
| |
| // turn on processor tracing |
| #define IOCTL_IPT_CPU_MODE_START \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 11) |
| IOCTL_WRAPPER(ioctl_ipt_cpu_mode_start, IOCTL_IPT_CPU_MODE_START); |
| |
| // turn off processor tracing |
| #define IOCTL_IPT_CPU_MODE_STOP \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 12) |
| IOCTL_WRAPPER(ioctl_ipt_cpu_mode_stop, IOCTL_IPT_CPU_MODE_STOP); |
| |
| // release resources allocated with IOCTL_IPT_CPU_MODE_ALLOC |
| // must be called prior to reconfiguring buffer sizes |
| #define IOCTL_IPT_CPU_MODE_FREE \ |
| IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_IPT, 13) |
| IOCTL_WRAPPER(ioctl_ipt_cpu_mode_free, IOCTL_IPT_CPU_MODE_FREE); |
| |
| #endif // __Fuchsia__ |
| |
| __END_CDECLS |