diff options
| -rw-r--r-- | include/fbos/dt.h | 6 | ||||
| -rw-r--r-- | kernel/main.c | 8 | ||||
| -rw-r--r-- | lib/dt.c | 50 | ||||
| -rw-r--r-- | test/test_dt.c | 5 |
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. @@ -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) |
