Skip to content

Commit 01fd290

Browse files
ardbiesheuvelwilldeacon
authored andcommitted
arm64: idreg-override: Prepare for place relative reloc patching
The ID reg override handling code uses a rather elaborate data structure that relies on statically initialized absolute address values in pointer fields. This means that this code cannot run until relocation fixups have been applied, and this is unfortunate, because it means we cannot discover overrides for KASLR or LVA/LPA without creating the kernel mapping and performing the relocations first. This can be solved by switching to place-relative relocations, which can be applied by the linker at build time. This means some additional arithmetic is required when dereferencing these pointers, as we can no longer dereference the pointer members directly. So let's implement this for idreg-override.c in a preliminary way, i.e., convert all the references in code to use a special accessor that produces the correct absolute value at runtime. Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Link: https://lore.kernel.org/r/20231129111555.3594833-58-ardb@google.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent cbc59c9 commit 01fd290

1 file changed

Lines changed: 56 additions & 33 deletions

File tree

arch/arm64/kernel/idreg-override.c

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,25 @@
2121

2222
static u64 __boot_status __initdata;
2323

24+
// temporary __prel64 related definitions
25+
// to be removed when this code is moved under pi/
26+
27+
#define __prel64_initconst __initconst
28+
29+
#define PREL64(type, name) union { type *name; }
30+
31+
#define prel64_pointer(__d) (__d)
32+
33+
typedef bool filter_t(u64 val);
34+
2435
struct ftr_set_desc {
2536
char name[FTR_DESC_NAME_LEN];
26-
struct arm64_ftr_override *override;
37+
PREL64(struct arm64_ftr_override, override);
2738
struct {
2839
char name[FTR_DESC_FIELD_LEN];
2940
u8 shift;
3041
u8 width;
31-
bool (*filter)(u64 val);
42+
PREL64(filter_t, filter);
3243
} fields[];
3344
};
3445

@@ -46,7 +57,7 @@ static bool __init mmfr1_vh_filter(u64 val)
4657
val == 0);
4758
}
4859

49-
static const struct ftr_set_desc mmfr1 __initconst = {
60+
static const struct ftr_set_desc mmfr1 __prel64_initconst = {
5061
.name = "id_aa64mmfr1",
5162
.override = &id_aa64mmfr1_override,
5263
.fields = {
@@ -70,7 +81,7 @@ static bool __init pfr0_sve_filter(u64 val)
7081
return true;
7182
}
7283

73-
static const struct ftr_set_desc pfr0 __initconst = {
84+
static const struct ftr_set_desc pfr0 __prel64_initconst = {
7485
.name = "id_aa64pfr0",
7586
.override = &id_aa64pfr0_override,
7687
.fields = {
@@ -94,7 +105,7 @@ static bool __init pfr1_sme_filter(u64 val)
94105
return true;
95106
}
96107

97-
static const struct ftr_set_desc pfr1 __initconst = {
108+
static const struct ftr_set_desc pfr1 __prel64_initconst = {
98109
.name = "id_aa64pfr1",
99110
.override = &id_aa64pfr1_override,
100111
.fields = {
@@ -105,7 +116,7 @@ static const struct ftr_set_desc pfr1 __initconst = {
105116
},
106117
};
107118

108-
static const struct ftr_set_desc isar1 __initconst = {
119+
static const struct ftr_set_desc isar1 __prel64_initconst = {
109120
.name = "id_aa64isar1",
110121
.override = &id_aa64isar1_override,
111122
.fields = {
@@ -117,7 +128,7 @@ static const struct ftr_set_desc isar1 __initconst = {
117128
},
118129
};
119130

120-
static const struct ftr_set_desc isar2 __initconst = {
131+
static const struct ftr_set_desc isar2 __prel64_initconst = {
121132
.name = "id_aa64isar2",
122133
.override = &id_aa64isar2_override,
123134
.fields = {
@@ -128,7 +139,7 @@ static const struct ftr_set_desc isar2 __initconst = {
128139
},
129140
};
130141

131-
static const struct ftr_set_desc smfr0 __initconst = {
142+
static const struct ftr_set_desc smfr0 __prel64_initconst = {
132143
.name = "id_aa64smfr0",
133144
.override = &id_aa64smfr0_override,
134145
.fields = {
@@ -149,7 +160,7 @@ static bool __init hvhe_filter(u64 val)
149160
ID_AA64MMFR1_EL1_VH_SHIFT));
150161
}
151162

152-
static const struct ftr_set_desc sw_features __initconst = {
163+
static const struct ftr_set_desc sw_features __prel64_initconst = {
153164
.name = "arm64_sw",
154165
.override = &arm64_sw_feature_override,
155166
.fields = {
@@ -159,14 +170,15 @@ static const struct ftr_set_desc sw_features __initconst = {
159170
},
160171
};
161172

162-
static const struct ftr_set_desc * const regs[] __initconst = {
163-
&mmfr1,
164-
&pfr0,
165-
&pfr1,
166-
&isar1,
167-
&isar2,
168-
&smfr0,
169-
&sw_features,
173+
static const
174+
PREL64(const struct ftr_set_desc, reg) regs[] __prel64_initconst = {
175+
{ &mmfr1 },
176+
{ &pfr0 },
177+
{ &pfr1 },
178+
{ &isar1 },
179+
{ &isar2 },
180+
{ &smfr0 },
181+
{ &sw_features },
170182
};
171183

172184
static const struct {
@@ -214,32 +226,37 @@ static void __init match_options(const char *cmdline)
214226
int i;
215227

216228
for (i = 0; i < ARRAY_SIZE(regs); i++) {
229+
const struct ftr_set_desc *reg = prel64_pointer(regs[i].reg);
230+
struct arm64_ftr_override *override;
217231
int f;
218232

219-
for (f = 0; strlen(regs[i]->fields[f].name); f++) {
220-
u64 shift = regs[i]->fields[f].shift;
221-
u64 width = regs[i]->fields[f].width ?: 4;
233+
override = prel64_pointer(reg->override);
234+
235+
for (f = 0; strlen(reg->fields[f].name); f++) {
236+
u64 shift = reg->fields[f].shift;
237+
u64 width = reg->fields[f].width ?: 4;
222238
u64 mask = GENMASK_ULL(shift + width - 1, shift);
239+
bool (*filter)(u64 val);
223240
u64 v;
224241

225-
if (find_field(cmdline, regs[i], f, &v))
242+
if (find_field(cmdline, reg, f, &v))
226243
continue;
227244

228245
/*
229246
* If an override gets filtered out, advertise
230247
* it by setting the value to the all-ones while
231248
* clearing the mask... Yes, this is fragile.
232249
*/
233-
if (regs[i]->fields[f].filter &&
234-
!regs[i]->fields[f].filter(v)) {
235-
regs[i]->override->val |= mask;
236-
regs[i]->override->mask &= ~mask;
250+
filter = prel64_pointer(reg->fields[f].filter);
251+
if (filter && !filter(v)) {
252+
override->val |= mask;
253+
override->mask &= ~mask;
237254
continue;
238255
}
239256

240-
regs[i]->override->val &= ~mask;
241-
regs[i]->override->val |= (v << shift) & mask;
242-
regs[i]->override->mask |= mask;
257+
override->val &= ~mask;
258+
override->val |= (v << shift) & mask;
259+
override->mask |= mask;
243260

244261
return;
245262
}
@@ -313,20 +330,26 @@ void init_feature_override(u64 boot_status);
313330

314331
asmlinkage void __init init_feature_override(u64 boot_status)
315332
{
333+
struct arm64_ftr_override *override;
334+
const struct ftr_set_desc *reg;
316335
int i;
317336

318337
for (i = 0; i < ARRAY_SIZE(regs); i++) {
319-
regs[i]->override->val = 0;
320-
regs[i]->override->mask = 0;
338+
reg = prel64_pointer(regs[i].reg);
339+
override = prel64_pointer(reg->override);
340+
341+
override->val = 0;
342+
override->mask = 0;
321343
}
322344

323345
__boot_status = boot_status;
324346

325347
parse_cmdline();
326348

327349
for (i = 0; i < ARRAY_SIZE(regs); i++) {
328-
dcache_clean_inval_poc((unsigned long)regs[i]->override,
329-
(unsigned long)regs[i]->override +
330-
sizeof(*regs[i]->override));
350+
reg = prel64_pointer(regs[i].reg);
351+
override = prel64_pointer(reg->override);
352+
dcache_clean_inval_poc((unsigned long)override,
353+
(unsigned long)(override + 1));
331354
}
332355
}

0 commit comments

Comments
 (0)