diff mbox series

[RFC,v1,41/57] arm64: Pass desired page size on command line

Message ID 20241014105912.3207374-41-ryan.roberts@arm.com (mailing list archive)
State New
Headers show
Series Boot-time page size selection for arm64 | expand

Commit Message

Ryan Roberts Oct. 14, 2024, 10:58 a.m. UTC
Allow user to pass desired page size via command line as either
"arm64.pagesize=4k", "arm64.pagesize=16k", or "arm64.pagesize=64k". The
specified value is stored in the SW_FEATURE register as an encoded page
shift in a 4 bit field.

We only allow setting the page size override if the requested size is
supported by the HW and is within the compile-time [PAGE_SIZE_MIN,
PAGE_SIZE_MAX] range. This second condition means that overrides get
ignored when we have a compile-time page size (because PAGE_SIZE_MIN ==
PAGE_SIZE_MAX).

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---

***NOTE***
Any confused maintainers may want to read the cover note here for context:
https://lore.kernel.org/all/20241014105514.3206191-1-ryan.roberts@arm.com/

 arch/arm64/include/asm/cpufeature.h   | 11 ++++++++
 arch/arm64/kernel/pi/idreg-override.c | 36 +++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 5584342672715..4edbb586810d7 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -18,6 +18,7 @@ 
 #define ARM64_SW_FEATURE_OVERRIDE_NOKASLR	0
 #define ARM64_SW_FEATURE_OVERRIDE_HVHE		4
 #define ARM64_SW_FEATURE_OVERRIDE_RODATA_OFF	8
+#define ARM64_SW_FEATURE_OVERRIDE_PAGESHIFT	12
 
 #ifndef __ASSEMBLY__
 
@@ -963,6 +964,16 @@  static inline bool arm64_test_sw_feature_override(int feat)
 					    &arm64_sw_feature_override);
 }
 
+static inline int arm64_pageshift_cmdline(void)
+{
+	int val;
+
+	val = arm64_apply_feature_override(0,
+					   ARM64_SW_FEATURE_OVERRIDE_PAGESHIFT,
+					   4, &arm64_sw_feature_override);
+	return val ? val * 2 + 10 : 0;
+}
+
 static inline bool kaslr_disabled_cmdline(void)
 {
 	return arm64_test_sw_feature_override(ARM64_SW_FEATURE_OVERRIDE_NOKASLR);
diff --git a/arch/arm64/kernel/pi/idreg-override.c b/arch/arm64/kernel/pi/idreg-override.c
index 29d4b6244a6f6..5a38bdb231bc8 100644
--- a/arch/arm64/kernel/pi/idreg-override.c
+++ b/arch/arm64/kernel/pi/idreg-override.c
@@ -183,6 +183,38 @@  static bool __init hvhe_filter(u64 val)
 						     ID_AA64MMFR1_EL1_VH_SHIFT));
 }
 
+static bool __init pageshift_filter(u64 val)
+{
+	u64 mmfr0 = read_sysreg_s(SYS_ID_AA64MMFR0_EL1);
+	u32 tgran64 = SYS_FIELD_GET(ID_AA64MMFR0_EL1, TGRAN64, mmfr0);
+	u32 tgran16 = SYS_FIELD_GET(ID_AA64MMFR0_EL1, TGRAN16, mmfr0);
+	u32 tgran4 = SYS_FIELD_GET(ID_AA64MMFR0_EL1, TGRAN4, mmfr0);
+
+	/* pageshift is stored compressed in 4 bit field. */
+	if (val)
+		val = val * 2 + 10;
+
+	if (val < PAGE_SHIFT_MIN || val > PAGE_SHIFT_MAX)
+		return false;
+
+	if (val == ARM64_PAGE_SHIFT_64K &&
+	    tgran64 >= ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN &&
+	    tgran64 <= ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX)
+		return true;
+
+	if (val == ARM64_PAGE_SHIFT_16K &&
+	    tgran16 >= ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN &&
+	    tgran16 <= ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX)
+		return true;
+
+	if (val == ARM64_PAGE_SHIFT_4K &&
+	    tgran4 >= ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN &&
+	    tgran4 <= ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX)
+		return true;
+
+	return false;
+}
+
 static const struct ftr_set_desc sw_features __prel64_initconst = {
 	.name		= "arm64_sw",
 	.override	= &arm64_sw_feature_override,
@@ -190,6 +222,7 @@  static const struct ftr_set_desc sw_features __prel64_initconst = {
 		FIELD("nokaslr", ARM64_SW_FEATURE_OVERRIDE_NOKASLR, NULL),
 		FIELD("hvhe", ARM64_SW_FEATURE_OVERRIDE_HVHE, hvhe_filter),
 		FIELD("rodataoff", ARM64_SW_FEATURE_OVERRIDE_RODATA_OFF, NULL),
+		FIELD("pageshift", ARM64_SW_FEATURE_OVERRIDE_PAGESHIFT, pageshift_filter),
 		{}
 	},
 };
@@ -225,6 +258,9 @@  static const struct {
 	{ "rodata=off",			"arm64_sw.rodataoff=1" },
 	{ "arm64.nolva",		"id_aa64mmfr2.varange=0" },
 	{ "arm64.no32bit_el0",		"id_aa64pfr0.el0=1" },
+	{ "arm64.pagesize=4k",		"arm64_sw.pageshift=1" },
+	{ "arm64.pagesize=16k",		"arm64_sw.pageshift=2" },
+	{ "arm64.pagesize=64k",		"arm64_sw.pageshift=3" },
 };
 
 static int __init parse_hexdigit(const char *p, u64 *v)