arch/x86/mm/init.c

Source file repositories/reference/linux-study-clean/arch/x86/mm/init.c

File Facts

System
Linux kernel
Corpus path
arch/x86/mm/init.c
Extension
.c
Size
32954 bytes
Lines
1129
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 map_range {
	unsigned long start;
	unsigned long end;
	unsigned page_size_mask;
};

static int page_size_mask;

/*
 * Save some of cr4 feature set we're using (e.g.  Pentium 4MB
 * enable and PPro Global page enable), so that any CPU's that boot
 * up after us can get the correct flags. Invoked on the boot CPU.
 */
static inline void cr4_set_bits_and_update_boot(unsigned long mask)
{
	mmu_cr4_features |= mask;
	if (trampoline_cr4_features)
		*trampoline_cr4_features = mmu_cr4_features;
	cr4_set_bits(mask);
}

static void __init probe_page_size_mask(void)
{
	/*
	 * For pagealloc debugging, identity mapping will use small pages.
	 * This will simplify cpa(), which otherwise needs to support splitting
	 * large pages into small in interrupt context, etc.
	 */
	if (boot_cpu_has(X86_FEATURE_PSE) && !debug_pagealloc_enabled())
		page_size_mask |= 1 << PG_LEVEL_2M;
	else
		direct_gbpages = 0;

	/* Enable PSE if available */
	if (boot_cpu_has(X86_FEATURE_PSE))
		cr4_set_bits_and_update_boot(X86_CR4_PSE);

	/* Enable PGE if available */
	__supported_pte_mask &= ~_PAGE_GLOBAL;
	if (boot_cpu_has(X86_FEATURE_PGE)) {
		cr4_set_bits_and_update_boot(X86_CR4_PGE);
		__supported_pte_mask |= _PAGE_GLOBAL;
	}

	/* By the default is everything supported: */
	__default_kernel_pte_mask = __supported_pte_mask;
	/* Except when with PTI where the kernel is mostly non-Global: */
	if (cpu_feature_enabled(X86_FEATURE_PTI))
		__default_kernel_pte_mask &= ~_PAGE_GLOBAL;

	/* Enable 1 GB linear kernel mappings if available: */
	if (direct_gbpages && boot_cpu_has(X86_FEATURE_GBPAGES)) {
		printk(KERN_INFO "Using GB pages for direct mapping\n");
		page_size_mask |= 1 << PG_LEVEL_1G;
	} else {
		direct_gbpages = 0;
	}
}

/*
 * INVLPG may not properly flush Global entries on
 * these CPUs.  New microcode fixes the issue.
 */
static const struct x86_cpu_id invlpg_miss_ids[] = {
	X86_MATCH_VFM(INTEL_ALDERLAKE,	    0x2e),
	X86_MATCH_VFM(INTEL_ALDERLAKE_L,    0x42c),
	X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, 0x11),
	X86_MATCH_VFM(INTEL_RAPTORLAKE,	    0x118),
	X86_MATCH_VFM(INTEL_RAPTORLAKE_P,   0x4117),
	X86_MATCH_VFM(INTEL_RAPTORLAKE_S,   0x2e),
	{}
};

static void setup_pcid(void)
{
	const struct x86_cpu_id *invlpg_miss_match;

	if (!IS_ENABLED(CONFIG_X86_64))
		return;

	if (!boot_cpu_has(X86_FEATURE_PCID))
		return;

	invlpg_miss_match = x86_match_cpu(invlpg_miss_ids);

	if (invlpg_miss_match &&
	    boot_cpu_data.microcode < invlpg_miss_match->driver_data) {
		pr_info("Incomplete global flushes, disabling PCID");
		setup_clear_cpu_cap(X86_FEATURE_PCID);
		return;

Annotation

Implementation Notes