Skip to content

Commit 36e4433

Browse files
committed
lib: utils/fdt: Add ISA extension validation framework for CPU fixup
Extend the existing MISA-based single-letter ISA fixup into a table-driven validation framework for multi-letter extensions. Extensions declared in DT but missing required properties (e.g. zicbom without riscv,cbom-block-size) are now removed during fixup. New validators: H (MISA check), zicbom (cbom-block-size presence). Adding future validators requires only appending to isa_ext_validators[]. Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
1 parent 4364526 commit 36e4433

1 file changed

Lines changed: 131 additions & 0 deletions

File tree

lib/utils/fdt/fdt_fixup.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
#include <libfdt.h>
12+
#include <sbi/riscv_asm.h>
1213
#include <sbi/sbi_console.h>
1314
#include <sbi/sbi_domain.h>
1415
#include <sbi/sbi_math.h>
@@ -106,6 +107,134 @@ int fdt_add_cpu_idle_states(void *fdt, const struct sbi_cpu_idle_state *state)
106107
return 0;
107108
}
108109

110+
struct isa_ext_validate_entry {
111+
const char *name;
112+
bool (*validate)(void *fdt, int cpu_offset);
113+
};
114+
115+
static bool isa_ext_h_validate(void *fdt, int cpu_offset)
116+
{
117+
(void)fdt;
118+
(void)cpu_offset;
119+
return misa_extension_imp('H');
120+
}
121+
122+
static bool isa_ext_zicbom_validate(void *fdt, int cpu_offset)
123+
{
124+
unsigned long block_size;
125+
return fdt_parse_cbom_block_size(fdt, cpu_offset, &block_size) == 0;
126+
}
127+
128+
static const struct isa_ext_validate_entry isa_ext_validators[] = {
129+
{ "h", isa_ext_h_validate },
130+
{ "zicbom", isa_ext_zicbom_validate },
131+
};
132+
133+
static bool isa_ext_is_valid(const char *name, void *fdt, int cpu_offset)
134+
{
135+
for (int i = 0; i < (int)array_size(isa_ext_validators); i++) {
136+
if (sbi_strcmp(name, isa_ext_validators[i].name) == 0)
137+
return isa_ext_validators[i].validate(fdt, cpu_offset);
138+
}
139+
return true;
140+
}
141+
142+
/*
143+
* Fix up CPU ISA properties based on MISA and extension validation.
144+
* Remove single-letter extensions not present in MISA, and multi-letter
145+
* extensions that fail validation (e.g. missing required DT properties).
146+
*
147+
* Assumes all harts have the same MISA value (homogeneous system).
148+
*/
149+
static void fdt_fixup_cpu_isa(void *fdt, int cpu_offset)
150+
{
151+
const char *isa;
152+
int len, i, j;
153+
char new_isa[256];
154+
155+
/* Fix riscv,isa property */
156+
isa = fdt_getprop(fdt, cpu_offset, "riscv,isa", &len);
157+
if (isa && len > 0) {
158+
j = 0;
159+
160+
/* Copy "rv32" or "rv64" prefix */
161+
for (i = 0; i < len - 1 && i < 4; i++)
162+
new_isa[j++] = isa[i];
163+
164+
for (; i < len - 1 && j < (int)sizeof(new_isa) - 1; i++) {
165+
char c = isa[i];
166+
167+
if (c == '_') {
168+
/* Multi-letter extensions: validate each token */
169+
while (i < len - 1) {
170+
const char *tok = isa + i + 1;
171+
int tok_len = 0;
172+
173+
while (i + 1 + tok_len < len - 1 && tok[tok_len] != '_')
174+
tok_len++;
175+
176+
char name[64];
177+
if (tok_len > 0 && tok_len < (int)sizeof(name)) {
178+
sbi_memcpy(name, tok, tok_len);
179+
name[tok_len] = '\0';
180+
if (isa_ext_is_valid(name, fdt, cpu_offset)) {
181+
new_isa[j++] = '_';
182+
sbi_memcpy(new_isa + j, tok, tok_len);
183+
j += tok_len;
184+
} else
185+
sbi_printf("fdt: ISA fixup: removed \"%s\" (validation failed)\n", name);
186+
}
187+
i += 1 + tok_len;
188+
}
189+
break;
190+
} else if (c >= 'a' && c <= 'z') {
191+
if (misa_extension_imp(c - 'a' + 'A'))
192+
new_isa[j++] = c;
193+
else
194+
sbi_printf("fdt: ISA fixup: removed '%c' (MISA bit %d not set)\n", c, c - 'a');
195+
}
196+
}
197+
new_isa[j] = '\0';
198+
199+
if (sbi_strcmp(new_isa, isa) != 0)
200+
fdt_setprop_string(fdt, cpu_offset, "riscv,isa", new_isa);
201+
}
202+
203+
/* Fix riscv,isa-extensions property (stringlist) */
204+
isa = fdt_getprop(fdt, cpu_offset, "riscv,isa-extensions", &len);
205+
if (isa && len > 0) {
206+
char new_ext[512];
207+
int new_len = 0;
208+
209+
i = 0;
210+
while (i < len) {
211+
const char *entry = isa + i;
212+
int entry_len = sbi_strlen(entry);
213+
214+
if (entry_len == 1 && entry[0] >= 'a' && entry[0] <= 'z' && !misa_extension_imp(entry[0] - 'a' + 'A')) {
215+
sbi_printf("fdt: ISA ext fixup: removed \"%s\" (MISA bit %d not set)\n", entry, entry[0] - 'a');
216+
i += entry_len + 1;
217+
continue;
218+
}
219+
220+
if (entry_len > 1 && !isa_ext_is_valid(entry, fdt, cpu_offset)) {
221+
sbi_printf("fdt: ISA ext fixup: removed \"%s\" (validation failed)\n", entry);
222+
i += entry_len + 1;
223+
continue;
224+
}
225+
226+
if (new_len + entry_len + 1 <= (int)sizeof(new_ext)) {
227+
sbi_memcpy(new_ext + new_len, entry, entry_len + 1);
228+
new_len += entry_len + 1;
229+
}
230+
i += entry_len + 1;
231+
}
232+
233+
if (new_len != len)
234+
fdt_setprop(fdt, cpu_offset, "riscv,isa-extensions", new_ext, new_len);
235+
}
236+
}
237+
109238
void fdt_cpu_fixup(void *fdt)
110239
{
111240
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
@@ -153,6 +282,8 @@ void fdt_cpu_fixup(void *fdt)
153282
fdt_setprop_string(fdt, cpu_offset, "status",
154283
"disabled");
155284

285+
fdt_fixup_cpu_isa(fdt, cpu_offset);
286+
156287
if (!emulated_zicntr)
157288
continue;
158289

0 commit comments

Comments
 (0)