arch/x86/kernel/cpu/cpuid_parser.c

Source file repositories/reference/linux-study-clean/arch/x86/kernel/cpu/cpuid_parser.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/cpu/cpuid_parser.c
Extension
.c
Size
4957 bytes
Lines
183
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source 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

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * CPUID parser; for populating the system's CPUID tables.
 */

#include <linux/kernel.h>

#include <asm/cpuid/api.h>
#include <asm/processor.h>

#include "cpuid_parser.h"

/* Clear a single CPUID table entry */
static void cpuid_clear(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output)
{
	struct cpuid_regs *regs = output->regs;

	for (int i = 0; i < e->maxcnt; i++, regs++)
		memset(regs, 0, sizeof(*regs));

	memset(output->info, 0, sizeof(*output->info));
}

/*
 * Leaf read functions:
 */

/*
 * Default CPUID read function
 * Satisfies the requirements stated at 'struct cpuid_parse_entry'->read().
 */
static void
cpuid_read_generic(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output)
{
	struct cpuid_regs *regs = output->regs;

	for (int i = 0; i < e->maxcnt; i++, regs++, output->info->nr_entries++)
		cpuid_read_subleaf(e->leaf, e->subleaf + i, regs);
}

/*
 * CPUID parser table:
 */

static const struct cpuid_parse_entry cpuid_parse_entries[] = {
	CPUID_PARSE_ENTRIES
};

/*
 * Leaf-independent parser code:
 */

static unsigned int cpuid_range_max_leaf(const struct cpuid_table *t, unsigned int range)
{
	const struct leaf_0x0_0 *l0 = __cpuid_table_subleaf(t, 0x0, 0);

	switch (range) {
	case CPUID_BASE_START:	return l0  ?  l0->max_std_leaf : 0;
	default:		return 0;
	}
}

static void
__cpuid_reset_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[],
		    unsigned int nr_entries, unsigned int start, unsigned int end, bool fill)
{
	const struct cpuid_parse_entry *entry = entries;
	unsigned int range = CPUID_RANGE(start);

	for (unsigned int i = 0; i < nr_entries; i++, entry++) {
		struct cpuid_read_output output = {
			.regs = cpuid_table_regs_p(t, entry->regs_offs),
			.info = cpuid_table_info_p(t, entry->info_offs),
		};

		if (entry->leaf < start || entry->leaf > end)
			continue;

		cpuid_clear(entry, &output);

		/*
		 * Read the range's anchor leaf unconditionally so that the cached
		 * maximum valid leaf value is available for the remaining entries.
		 */
		if (fill && (entry->leaf == range || entry->leaf <= cpuid_range_max_leaf(t, range)))
			entry->read(entry, &output);
	}
}

/*

Annotation

Implementation Notes