-
Notifications
You must be signed in to change notification settings - Fork 628
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[arch][riscv] read the riscv feature string out of device tree
Also added initial implementation of a way to query run time features of the cpu.
- Loading branch information
Showing
8 changed files
with
348 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
/* | ||
* Copyright (c) 2024 Travis Geiselbrecht | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT | ||
*/ | ||
#include "arch/riscv/feature.h" | ||
|
||
#include <lk/trace.h> | ||
#include <lk/debug.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <ctype.h> | ||
|
||
#define LOCAL_TRACE 0 | ||
|
||
// Make feature bitmap | ||
uint32_t riscv_feature_bitmap[ROUNDUP(RISCV_FEAT_COUNT, 32) / 32]; | ||
|
||
static void set_feature(enum riscv_feature feature) { | ||
riscv_feature_bitmap[feature / 32] |= (1U << feature % 32); | ||
} | ||
|
||
// match a one word feature from a known list | ||
static void match_feature(const char *str, size_t start, size_t end) { | ||
const struct { | ||
const char *str; | ||
enum riscv_feature feat; | ||
} oneword[] = { | ||
{ "zba", RISCV_FEAT_ZBA }, | ||
{ "zbb", RISCV_FEAT_ZBB }, | ||
{ "zbc", RISCV_FEAT_ZBC }, | ||
{ "zbs", RISCV_FEAT_ZBS }, | ||
{ "sstc", RISCV_FEAT_SSTC }, | ||
{ "zicsr", RISCV_FEAT_ZICSR }, | ||
{ "zfencei", RISCV_FEAT_ZIFENCEI }, | ||
}; | ||
|
||
if (LOCAL_TRACE) { | ||
char feat[128]; | ||
strlcpy(feat, &str[start], end - start + 1); | ||
printf("feature '%s'\n", feat); | ||
} | ||
|
||
for (size_t i = 0; i < countof(oneword); i++) { | ||
if (strlen(oneword[i].str) != end - start) | ||
continue; | ||
|
||
if (strncasecmp(oneword[i].str, &str[start], end - start) == 0) { | ||
dprintf(INFO, "riscv: found feature '%s'\n", oneword[i].str); | ||
set_feature(oneword[i].feat); | ||
} | ||
} | ||
} | ||
|
||
void riscv_set_isa_string(const char *str) { | ||
LTRACEF("%s\n", str); | ||
|
||
const size_t slen = strlen(str); | ||
|
||
// Handle simple features first. | ||
// Feature string must start with either 'rv64' or 'rv32' followed by | ||
// one or more one character features until _ or null. | ||
if (slen < 4 || str[0] != 'r' || str[1] != 'v') { | ||
return; | ||
} | ||
|
||
// We're going to continue, so wipe out the existing default feature list | ||
memset(riscv_feature_bitmap, 0, 4 * countof(riscv_feature_bitmap)); | ||
|
||
size_t pos = 4; | ||
while (str[pos] != 0 && str[pos] != '_') { | ||
bool found = true; | ||
switch (tolower(str[pos])) { | ||
// TODO: make sure this is the complete list | ||
case 'i': set_feature(RISCV_FEAT_I); break; | ||
case 'm': set_feature(RISCV_FEAT_M); break; | ||
case 'a': set_feature(RISCV_FEAT_A); break; | ||
case 'q': set_feature(RISCV_FEAT_Q); | ||
// fallthrough | ||
case 'd': | ||
feat_d: | ||
set_feature(RISCV_FEAT_D); | ||
// fallthrough | ||
case 'f': set_feature(RISCV_FEAT_F); break; | ||
case 'c': set_feature(RISCV_FEAT_C); break; | ||
case 'b': set_feature(RISCV_FEAT_B); break; | ||
case 'p': set_feature(RISCV_FEAT_P); break; | ||
case 'h': set_feature(RISCV_FEAT_H); break; | ||
case 'v': | ||
set_feature(RISCV_FEAT_V); | ||
goto feat_d; | ||
case 'g': | ||
// 'g' is a special case that implies IMAFDZisr_Zifenci | ||
set_feature(RISCV_FEAT_I); | ||
set_feature(RISCV_FEAT_M); | ||
set_feature(RISCV_FEAT_A); | ||
set_feature(RISCV_FEAT_ZICSR); | ||
set_feature(RISCV_FEAT_ZIFENCEI); | ||
goto feat_d; | ||
default: | ||
found = false; | ||
} | ||
if (found) { | ||
dprintf(INFO, "riscv: found feature '%c'\n", tolower(str[pos])); | ||
} | ||
|
||
pos++; | ||
} | ||
|
||
// walk the one-word features | ||
bool in_word = false; | ||
size_t start; | ||
for (; pos <= slen; pos++) { | ||
if (!in_word) { | ||
if (str[pos] == '_') { | ||
continue; | ||
} else if (str[pos] == 0) { | ||
break; | ||
} | ||
start = pos; | ||
in_word = true; | ||
} else { | ||
// we're in a word | ||
if (str[pos] == '_' || str[pos] == 0) { | ||
// end of word | ||
in_word = false; | ||
|
||
// process the feature word, between str[start...pos] | ||
match_feature(str, start, pos); | ||
} | ||
} | ||
} | ||
} | ||
|
||
void riscv_feature_early_init(void) { | ||
// set the default features based on the compiler switches | ||
#if __riscv_i | ||
set_feature(RISCV_FEAT_I); | ||
#endif | ||
#if __riscv_m | ||
set_feature(RISCV_FEAT_M); | ||
#endif | ||
#if __riscv_a | ||
set_feature(RISCV_FEAT_A); | ||
#endif | ||
#if __riscv_f | ||
set_feature(RISCV_FEAT_F); | ||
#endif | ||
#if __riscv_d | ||
set_feature(RISCV_FEAT_D); | ||
#endif | ||
#if __riscv_q | ||
set_feature(RISCV_FEAT_Q); | ||
#endif | ||
#if __riscv_c | ||
set_feature(RISCV_FEAT_C); | ||
#endif | ||
#if __riscv_zba | ||
set_feature(RISCV_FEAT_ZBA); | ||
#endif | ||
#if __riscv_zbb | ||
set_feature(RISCV_FEAT_ZBB); | ||
#endif | ||
#if __riscv_zba | ||
set_feature(RISCV_FEAT_ZBA); | ||
#endif | ||
#if __riscv_zbc | ||
set_feature(RISCV_FEAT_ZBC); | ||
#endif | ||
#if __riscv_zbs | ||
set_feature(RISCV_FEAT_ZBS); | ||
#endif | ||
} | ||
|
||
const char *riscv_feature_to_string(enum riscv_feature feature) { | ||
switch (feature) { | ||
case RISCV_FEAT_I: return "i"; | ||
case RISCV_FEAT_M: return "m"; | ||
case RISCV_FEAT_A: return "a"; | ||
case RISCV_FEAT_F: return "f"; | ||
case RISCV_FEAT_D: return "d"; | ||
case RISCV_FEAT_Q: return "q"; | ||
case RISCV_FEAT_C: return "c"; | ||
case RISCV_FEAT_B: return "b"; | ||
case RISCV_FEAT_P: return "p"; | ||
case RISCV_FEAT_V: return "v"; | ||
case RISCV_FEAT_H: return "h"; | ||
case RISCV_FEAT_ZBA: return "zba"; | ||
case RISCV_FEAT_ZBB: return "zbb"; | ||
case RISCV_FEAT_ZBC: return "zbc"; | ||
case RISCV_FEAT_ZBS: return "zbs"; | ||
case RISCV_FEAT_ZICSR: return "zicsr"; | ||
case RISCV_FEAT_ZIFENCEI: return "zifencei"; | ||
case RISCV_FEAT_SSTC: return "sstc"; | ||
|
||
// keep this in so the compiler warns if something is missing | ||
case RISCV_FEAT_COUNT: return ""; | ||
} | ||
return ""; | ||
} | ||
|
||
void riscv_feature_init(void) { | ||
dprintf(INFO, "RISCV: detected features"); | ||
for (size_t i = 0; i < countof(riscv_feature_bitmap); i++) { | ||
for (size_t j = 0; j < sizeof(riscv_feature_bitmap[i]) * 8; j++) { | ||
if (riscv_feature_bitmap[i] & (1U << j)) { | ||
dprintf(INFO, " %s", riscv_feature_to_string(i * 32 + j)); | ||
} | ||
} | ||
} | ||
dprintf(INFO, "\n"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright (c) 2024 Travis Geiselbrecht | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT | ||
*/ | ||
#pragma once | ||
|
||
#include <lk/compiler.h> | ||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
|
||
__BEGIN_CDECLS | ||
|
||
// Given a list of features in foo_bar_baz form, break out known features. | ||
// Does not keep a pointer to the string. | ||
void riscv_set_isa_string(const char *string); | ||
|
||
enum riscv_feature { | ||
// Basic one character features | ||
RISCV_FEAT_I, | ||
RISCV_FEAT_M, | ||
RISCV_FEAT_A, | ||
RISCV_FEAT_F, | ||
RISCV_FEAT_D, | ||
RISCV_FEAT_Q, | ||
RISCV_FEAT_C, | ||
RISCV_FEAT_B, | ||
RISCV_FEAT_P, | ||
RISCV_FEAT_V, | ||
RISCV_FEAT_H, | ||
|
||
// multichar features | ||
RISCV_FEAT_ZBA, | ||
RISCV_FEAT_ZBB, | ||
RISCV_FEAT_ZBC, | ||
RISCV_FEAT_ZBS, | ||
RISCV_FEAT_ZICSR, | ||
RISCV_FEAT_ZIFENCEI, | ||
RISCV_FEAT_SSTC, | ||
|
||
RISCV_FEAT_COUNT | ||
}; | ||
|
||
extern uint32_t riscv_feature_bitmap[]; | ||
|
||
// Test if a particular feature is present | ||
static inline bool riscv_feature_test(enum riscv_feature feature) { | ||
return riscv_feature_bitmap[feature / 32] & (1U << feature % 32); | ||
} | ||
|
||
const char *riscv_feature_to_string(enum riscv_feature feature); | ||
|
||
void riscv_feature_early_init(void); | ||
void riscv_feature_init(void); | ||
|
||
__END_CDECLS |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.