aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2024-11-26 21:43:54 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2024-11-26 21:43:54 +0100
commit87d1a2597ceedd03a7d4005db1bf82b72b423a18 (patch)
treee53bf20d06016b37fde0067526ed7abd95b848e8
parenteec442be4d2dd0a1630a820ee43220e635450aa7 (diff)
downloadfbos-87d1a2597ceedd03a7d4005db1bf82b72b423a18.tar.gz
fbos-87d1a2597ceedd03a7d4005db1bf82b72b423a18.zip
Show the detected machine model
Originally I was planning to detect the machine model just in case we needed to do workaround for special cases. But since apparently even VisionFive2 brings its own CPU frequency base on DT, this is not even needed. Hence, fetching the model is now a cool message being shown on boot. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
-rw-r--r--include/fbos/dt.h6
-rw-r--r--kernel/main.c8
-rw-r--r--lib/dt.c50
-rw-r--r--test/test_dt.c5
4 files changed, 69 insertions, 0 deletions
diff --git a/include/fbos/dt.h b/include/fbos/dt.h
index bbeb7cd..49ac27a 100644
--- a/include/fbos/dt.h
+++ b/include/fbos/dt.h
@@ -6,8 +6,14 @@
// Default value for the 'dt_info.cpu_freq' property if none could be retrieved.
#define DEFAULT_CPU_FREQ 10000000
+// Maximum length for the string representing the model.
+#define DT_MODEL_MAX 64
+
// Holds all the information that we gather from the initial DeviceTree blob.
struct dt_info {
+ // Model of the system that this kernel is running on.
+ char model[DT_MODEL_MAX];
+
// Ticks per second. If `get_dt_info` fails at setting this value, then
// `DEFAULT_CPU_FREQ` is used.
uint64_t cpu_freq;
diff --git a/kernel/main.c b/kernel/main.c
index a39ed29..ecb93da 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -18,6 +18,7 @@ struct task_struct tasks[4] = {
// Defined in fbos/init.h.
struct dt_info info = {
+ .model = { '\0' },
.cpu_freq = 0,
.initrd_start = 0,
.initrd_end = 0,
@@ -36,6 +37,13 @@ __noreturn __kernel void start_kernel(void *dtb)
get_dt_info(dtb, &info);
extract_initrd((unsigned char *)info.initrd_start, info.initrd_end - info.initrd_start, tasks);
+ // If we were able to fetch the model, print it now.
+ if (info.model[0] != '\0') {
+ printk("Running on: ");
+ printk(info.model);
+ printk("\n");
+ }
+
// At this point everything has already been handled: setup the interrupt
// vector and enable the timer to start ticking and scheduling the three
// tasks at hand.
diff --git a/lib/dt.c b/lib/dt.c
index ddf01f3..f5eed92 100644
--- a/lib/dt.c
+++ b/lib/dt.c
@@ -96,6 +96,54 @@ __kernel int32_t find_dt_node(uint32_t *dtb, struct fdt_header *header, const ch
return (int32_t)idx;
}
+// Returns the index in the 'dtb' of the first proper node.
+__kernel uint32_t first_dt_node(uint32_t *dtb, struct fdt_header *header)
+{
+ uint32_t idx;
+
+ for (idx = header->off_dt_struct; idx < header->size_dt_struct; idx++) {
+ if (dtb[idx] == FDT_BEGIN_NODE_LE) {
+ return idx;
+ }
+ }
+
+ return 0;
+}
+
+// Set the 'model' buffer from 'info' if available on the 'dtb' blob.
+__kernel void set_dt_model(uint32_t *dtb, struct dt_info *info, struct fdt_header *header)
+{
+ uint32_t len, nameoff;
+ uint32_t idx = first_dt_node(dtb, header);
+ char *base_dt_string = ((char *)dtb) + header->off_dt_string;
+
+ while (idx < header->size_dt_struct) {
+ len = __bswap_constant_32(dtb[idx + 1]);
+ nameoff = __bswap_constant_32(dtb[idx + 2]);
+ idx += 3;
+
+ if (strcmp(&base_dt_string[nameoff], "model") == 0) {
+ // In the (very unlikely) case that the model string is huge, don't
+ // even try.
+ if (len >= DT_MODEL_MAX) {
+ printk("WARNING: The model string is too large!\n");
+ break;
+ }
+
+ // And copy the string. Since we know the length of it, we can
+ // simply use 'memcpy' which is already available on kernel code as
+ // well.
+ memcpy(info->model, (char *)&dtb[idx], len);
+ info->model[len] = '\0';
+ break;
+ }
+
+ // Skip until the beginning of the next node.
+ for (; dtb[idx] != FDT_PROP_LE && idx < header->size_dt_struct; idx++)
+ ;
+ }
+}
+
// Set the 'cpu_freq' field of 'info' if available on the 'dtb' blob.
__kernel void set_cpu_freq(uint32_t *dtb, struct dt_info *info, struct fdt_header *header)
{
@@ -151,6 +199,8 @@ __kernel void get_dt_info(uint32_t *dtb, struct dt_info *info)
.size_dt_struct = __bswap_constant_32(dtb[9]) / sizeof(uint32_t),
};
+ set_dt_model(dtb, info, &header);
+
set_initrd_addr(dtb, info, &header);
if (!info->initrd_start || !info->initrd_end) {
die("Could not fetch the addresses for the initramfs\n");
diff --git a/test/test_dt.c b/test/test_dt.c
index f606d2e..b80be33 100644
--- a/test/test_dt.c
+++ b/test/test_dt.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
#include <fbos/dt.h>
@@ -28,6 +29,7 @@ void dt_info_from(const char *const path, struct dt_info *info)
void test_qemu(void)
{
struct dt_info info = {
+ .model = { '\0' },
.cpu_freq = 0,
.initrd_start = 0,
.initrd_end = 0,
@@ -38,11 +40,13 @@ void test_qemu(void)
assert(info.initrd_start == 0x84200000);
assert(info.initrd_end == 0x84200c00);
assert(info.cpu_freq == 0x989680);
+ assert(strcmp(info.model, "riscv-virtio,qemu") == 0);
}
void test_vf2(void)
{
struct dt_info info = {
+ .model = { '\0' },
.cpu_freq = 0,
.initrd_start = 0,
.initrd_end = 0,
@@ -53,6 +57,7 @@ void test_vf2(void)
assert(info.initrd_start == 0x46100000);
assert(info.initrd_end == 0x47139ce3);
assert(info.cpu_freq == 0x3d0900);
+ assert(strcmp(info.model, "StarFive VisionFive 2 v1.3B") == 0);
}
int main(void)