aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)