arch/arm64/kernel/pi/idreg-override.c

Source file repositories/reference/linux-study-clean/arch/arm64/kernel/pi/idreg-override.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kernel/pi/idreg-override.c
Extension
.c
Size
10715 bytes
Lines
428
Domain
Architecture Layer
Bucket
arch/arm64
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

struct ftr_set_desc {
	char 				name[FTR_DESC_NAME_LEN];
	PREL64(struct arm64_ftr_override, override);
	struct {
		char			name[FTR_DESC_FIELD_LEN];
		u8			shift;
		u8			width;
		PREL64(filter_t,	filter);
	} 				fields[];
};

#define FIELD(n, s, f)	{ .name = n, .shift = s, .width = 4, .filter = f }

static const struct ftr_set_desc mmfr0 __prel64_initconst = {
	.name		= "id_aa64mmfr0",
	.override	= &id_aa64mmfr0_override,
	.fields		= {
		FIELD("ecv", ID_AA64MMFR0_EL1_ECV_SHIFT, NULL),
		{}
	},
};

static bool __init mmfr1_vh_filter(u64 val)
{
	/*
	 * If we ever reach this point while running VHE, we're
	 * guaranteed to be on one of these funky, VHE-stuck CPUs. If
	 * the user was trying to force nVHE on us, proceed with
	 * attitude adjustment.
	 */
	return !(__boot_status == (BOOT_CPU_FLAG_E2H | BOOT_CPU_MODE_EL2) &&
		 val == 0);
}

static const struct ftr_set_desc mmfr1 __prel64_initconst = {
	.name		= "id_aa64mmfr1",
	.override	= &id_aa64mmfr1_override,
	.fields		= {
		FIELD("vh", ID_AA64MMFR1_EL1_VH_SHIFT, mmfr1_vh_filter),
		{}
	},
};


static bool __init mmfr2_varange_filter(u64 val)
{
	int __maybe_unused feat;

	if (val)
		return false;

#ifdef CONFIG_ARM64_LPA2
	feat = cpuid_feature_extract_signed_field(read_sysreg(id_aa64mmfr0_el1),
						  ID_AA64MMFR0_EL1_TGRAN_SHIFT);
	if (feat >= ID_AA64MMFR0_EL1_TGRAN_LPA2) {
		id_aa64mmfr0_override.val |=
			(ID_AA64MMFR0_EL1_TGRAN_LPA2 - 1) << ID_AA64MMFR0_EL1_TGRAN_SHIFT;
		id_aa64mmfr0_override.mask |= 0xfU << ID_AA64MMFR0_EL1_TGRAN_SHIFT;

		/*
		 * Override PARange to 48 bits - the override will just be
		 * ignored if the actual PARange is smaller, but this is
		 * unlikely to be the case for LPA2 capable silicon.
		 */
		id_aa64mmfr0_override.val |=
			ID_AA64MMFR0_EL1_PARANGE_48 << ID_AA64MMFR0_EL1_PARANGE_SHIFT;
		id_aa64mmfr0_override.mask |= 0xfU << ID_AA64MMFR0_EL1_PARANGE_SHIFT;
	}
#endif
	return true;
}

static const struct ftr_set_desc mmfr2 __prel64_initconst = {
	.name		= "id_aa64mmfr2",
	.override	= &id_aa64mmfr2_override,
	.fields		= {
		FIELD("varange", ID_AA64MMFR2_EL1_VARange_SHIFT, mmfr2_varange_filter),
		{}
	},
};

static bool __init pfr0_sve_filter(u64 val)
{
	/*
	 * Disabling SVE also means disabling all the features that
	 * are associated with it. The easiest way to do it is just to
	 * override id_aa64zfr0_el1 to be 0.
	 */
	if (!val) {
		id_aa64zfr0_override.val = 0;

Annotation

Implementation Notes