Skip to content

Commit 048fa98

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 048fa98

1 file changed

Lines changed: 140 additions & 0 deletions

File tree

lib/utils/fdt/fdt_fixup.c

Lines changed: 140 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,143 @@ 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[1024];
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+
int end = len - 1;
170+
171+
i++;
172+
while (i < end) {
173+
int tok_start = i;
174+
175+
while (i < end && isa[i] != '_')
176+
i++;
177+
178+
int tok_len = i - tok_start;
179+
char name[64];
180+
181+
if (tok_len > 0 && tok_len < (int)sizeof(name)) {
182+
sbi_memcpy(name, isa + tok_start, tok_len);
183+
name[tok_len] = '\0';
184+
if (isa_ext_is_valid(name, fdt, cpu_offset)) {
185+
if (j + 1 + tok_len >= (int)sizeof(new_isa))
186+
break;
187+
new_isa[j++] = '_';
188+
sbi_memcpy(new_isa + j, isa + tok_start, tok_len);
189+
j += tok_len;
190+
} else {
191+
sbi_printf("fdt: ISA fixup: removed \"%s\" (validation failed)\n", name);
192+
}
193+
}
194+
195+
if (i < end && isa[i] == '_')
196+
i++;
197+
}
198+
break;
199+
} else if (c >= 'a' && c <= 'z') {
200+
if (misa_extension_imp(c - 'a' + 'A'))
201+
new_isa[j++] = c;
202+
else
203+
sbi_printf("fdt: ISA fixup: removed '%c' (MISA bit %d not set)\n", c, c - 'a');
204+
}
205+
}
206+
new_isa[j] = '\0';
207+
208+
if (sbi_strcmp(new_isa, isa) != 0)
209+
fdt_setprop_string(fdt, cpu_offset, "riscv,isa", new_isa);
210+
}
211+
212+
/* Fix riscv,isa-extensions property (stringlist) */
213+
isa = fdt_getprop(fdt, cpu_offset, "riscv,isa-extensions", &len);
214+
if (isa && len > 0) {
215+
char new_ext[512];
216+
int new_len = 0;
217+
218+
i = 0;
219+
while (i < len) {
220+
const char *entry = isa + i;
221+
int entry_len = sbi_strlen(entry);
222+
223+
if (entry_len == 1 && entry[0] >= 'a' && entry[0] <= 'z' && !misa_extension_imp(entry[0] - 'a' + 'A')) {
224+
sbi_printf("fdt: ISA ext fixup: removed \"%s\" (MISA bit %d not set)\n", entry, entry[0] - 'a');
225+
i += entry_len + 1;
226+
continue;
227+
}
228+
229+
if (entry_len > 1 && !isa_ext_is_valid(entry, fdt, cpu_offset)) {
230+
sbi_printf("fdt: ISA ext fixup: removed \"%s\" (validation failed)\n", entry);
231+
i += entry_len + 1;
232+
continue;
233+
}
234+
235+
if (new_len + entry_len + 1 <= (int)sizeof(new_ext)) {
236+
sbi_memcpy(new_ext + new_len, entry, entry_len + 1);
237+
new_len += entry_len + 1;
238+
}
239+
i += entry_len + 1;
240+
}
241+
242+
if (new_len != len)
243+
fdt_setprop(fdt, cpu_offset, "riscv,isa-extensions", new_ext, new_len);
244+
}
245+
}
246+
109247
void fdt_cpu_fixup(void *fdt)
110248
{
111249
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
@@ -153,6 +291,8 @@ void fdt_cpu_fixup(void *fdt)
153291
fdt_setprop_string(fdt, cpu_offset, "status",
154292
"disabled");
155293

294+
fdt_fixup_cpu_isa(fdt, cpu_offset);
295+
156296
if (!emulated_zicntr)
157297
continue;
158298

0 commit comments

Comments
 (0)