arch/x86/events/intel/pt.c

Source file repositories/reference/linux-study-clean/arch/x86/events/intel/pt.c

File Facts

System
Linux kernel
Corpus path
arch/x86/events/intel/pt.c
Extension
.c
Size
46947 bytes
Lines
1894
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct topa {
	struct list_head	list;
	u64			offset;
	size_t			size;
	int			last;
	unsigned int		z_count;
};

/*
 * Keep ToPA table-related metadata on the same page as the actual table,
 * taking up a few words from the top
 */

#define TENTS_PER_PAGE	\
	((PAGE_SIZE - sizeof(struct topa)) / sizeof(struct topa_entry))

/**
 * struct topa_page - page-sized ToPA table with metadata at the top
 * @table:	actual ToPA table entries, as understood by PT hardware
 * @topa:	metadata
 */
struct topa_page {
	struct topa_entry	table[TENTS_PER_PAGE];
	struct topa		topa;
};

static inline struct topa_page *topa_to_page(struct topa *topa)
{
	return container_of(topa, struct topa_page, topa);
}

static inline struct topa_page *topa_entry_to_page(struct topa_entry *te)
{
	return (struct topa_page *)((unsigned long)te & PAGE_MASK);
}

static inline phys_addr_t topa_pfn(struct topa *topa)
{
	return PFN_DOWN(virt_to_phys(topa_to_page(topa)));
}

/* make -1 stand for the last table entry */
#define TOPA_ENTRY(t, i)				\
	((i) == -1					\
		? &topa_to_page(t)->table[(t)->last]	\
		: &topa_to_page(t)->table[(i)])
#define TOPA_ENTRY_SIZE(t, i) (sizes(TOPA_ENTRY((t), (i))->size))
#define TOPA_ENTRY_PAGES(t, i) (1 << TOPA_ENTRY((t), (i))->size)

static void pt_config_buffer(struct pt_buffer *buf)
{
	struct pt *pt = this_cpu_ptr(&pt_ctx);
	u64 reg, mask;
	void *base;

	if (buf->single) {
		base = buf->data_pages[0];
		mask = (buf->nr_pages * PAGE_SIZE - 1) >> 7;
	} else {
		base = topa_to_page(buf->cur)->table;
		mask = (u64)buf->cur_idx;
	}

	reg = virt_to_phys(base);
	if (pt->output_base != reg) {
		pt->output_base = reg;
		wrmsrq(MSR_IA32_RTIT_OUTPUT_BASE, reg);
	}

	reg = 0x7f | (mask << 7) | ((u64)buf->output_off << 32);
	if (pt->output_mask != reg) {
		pt->output_mask = reg;
		wrmsrq(MSR_IA32_RTIT_OUTPUT_MASK, reg);
	}
}

/**
 * topa_alloc() - allocate page-sized ToPA table
 * @cpu:	CPU on which to allocate.
 * @gfp:	Allocation flags.
 *
 * Return:	On success, return the pointer to ToPA table page.
 */
static struct topa *topa_alloc(int cpu, gfp_t gfp)
{
	int node = cpu_to_node(cpu);
	struct topa_page *tp;
	struct page *p;

	p = alloc_pages_node(node, gfp | __GFP_ZERO, 0);

Annotation

Implementation Notes