From ad1ac3f9d77ae3a5f4d6efc8b1bf325bf9149c57 Mon Sep 17 00:00:00 2001 From: Quantum Date: Tue, 7 Jun 2022 01:06:02 -0400 Subject: [PATCH] Common: Started writing a DTB/FDT parser --- kernel/common/dtb/dtb.cpp | 117 ++++++++++++++++++++++++++++ kernel/common/dtb/include/dtb/dtb.h | 34 ++++++++ kernel/common/dtb/meson.build | 9 +++ kernel/kernel.cpp | 13 ++++ kernel/meson.build | 1 + 5 files changed, 174 insertions(+) create mode 100644 kernel/common/dtb/dtb.cpp create mode 100644 kernel/common/dtb/include/dtb/dtb.h create mode 100644 kernel/common/dtb/meson.build diff --git a/kernel/common/dtb/dtb.cpp b/kernel/common/dtb/dtb.cpp new file mode 100644 index 0000000..389a180 --- /dev/null +++ b/kernel/common/dtb/dtb.cpp @@ -0,0 +1,117 @@ +#include "dtb/dtb.h" + +#include +using drivers::opensbi::legacy::console_putchar; + +extern void fmt(const char *f, ...); + +namespace dtb { + // TEMP + void puts(const char *s) { + while(*s) + console_putchar(*s++); + } + + namespace { + template + inline T bswap(T value) { + if constexpr(sizeof(T) == 1) + return value; + else if constexpr (sizeof(T) == 2) + return __builtin_bswap16(value); + else if constexpr (sizeof(T) == 4) + return __builtin_bswap32(value); + else if constexpr (sizeof(T) == 8) + return __builtin_bswap64(value); + else + __builtin_trap(); + } + + template + struct big_endian { + T value() { + return bswap(m_value); + } + + private: + T m_value; + }; + + struct [[gnu::packed]] FdtHeader { + big_endian magic; + big_endian size; + big_endian struct_offset; + big_endian strings_offset; + big_endian reserved_map_offset; + big_endian version; + big_endian last_compatible_version; + big_endian boot_cpu_id; + big_endian strings_size; + big_endian struct_size; + }; + + struct [[gnu::packed]] FdtReserveEntry { + big_endian address; + big_endian size; + }; + }; + + int validate_and_parse_header(DeviceTree &dt, void *base) { + auto header = reinterpret_cast(base); + + // Make sure the base address is acutally valid + if(header->magic.value() != 0xD00DFEED) { + fmt("magic @ {}\n", header); + fmt("magic is {}\n", header->magic.value()); + puts("Bad magic\n"); + return -1; + } + + // TODO: I would rather copy all data to pointers we own so I + // can be sure we have control over it and can remove this pointer + dt.meta.base = base; + + // Copy metadata and fix it's endianness + dt.meta.size = header->size.value(); + dt.meta.version = header->version.value(); + dt.meta.last_compatible_version = header->last_compatible_version.value(); + dt.meta.boot_cpu_id = header->boot_cpu_id.value(); + + // Calculate other block pointers + dt.memory_reservation_block = + reinterpret_cast(base) + header->reserved_map_offset.value(); + dt.structure_block = + reinterpret_cast(base) + header->struct_offset.value(); + dt.strings_block = + reinterpret_cast(base) + header->strings_offset.value(); + + return 0; + } + + void print_reserved_regions(DeviceTree dt) { + auto regions = reinterpret_cast(dt.memory_reservation_block); + int i = 0; + fmt("Print mem regions\n"); + while(true) { + fmt("----- {}\n", i); + auto region = regions[i++]; + if(region.address.value() == 0 && region.size.value() == 0) + break; + fmt("address {}\n", region.address.value()); + fmt("size {}\n", region.size.value()); + } + } + + void print_structure_block(DeviceTree dt) { + fmt("is start? {}\n", *(uint32_t *)dt.structure_block); + puts("asdasd\n"); + puts(((char *)dt.structure_block+4)); + puts("asdasd\n"); + fmt("is start? {}\n", *(uint32_t *)((char *)dt.structure_block+8)); + fmt("is len? {}\n", *(uint32_t *)((char *)dt.structure_block+8+4)); + fmt("is off? {}\n", *(uint32_t *)((char *)dt.structure_block+8+8)); + puts(((char *)((char *)dt.strings_block+0x1d))); + puts("\n"); + } + +} // End namespace dtb diff --git a/kernel/common/dtb/include/dtb/dtb.h b/kernel/common/dtb/include/dtb/dtb.h new file mode 100644 index 0000000..5abe9d1 --- /dev/null +++ b/kernel/common/dtb/include/dtb/dtb.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +namespace dtb { + + struct DtbMeta { + void *base; + size_t size; + uint32_t version; + uint32_t last_compatible_version; + uint32_t boot_cpu_id; + }; + + struct ReservedRegion { + uintptr_t address; + size_t size; + }; + + struct DeviceTree { + DtbMeta meta; + void *memory_reservation_block; + void *structure_block; + void *strings_block; + }; + + int validate_and_parse_header(DeviceTree &dt, void *base); + + void print_reserved_regions(DeviceTree dt); + + void print_structure_block(DeviceTree dt); + +} // End namespace dtb diff --git a/kernel/common/dtb/meson.build b/kernel/common/dtb/meson.build new file mode 100644 index 0000000..f74be63 --- /dev/null +++ b/kernel/common/dtb/meson.build @@ -0,0 +1,9 @@ +kernel_sources += [ + files( + 'dtb.cpp', + ), +] + +kernel_includes += include_directories( + 'include' +) diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index 25b7456..da914a5 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include #include #include @@ -275,6 +277,17 @@ isr_frame_t global_isr_frames[2]; extern "C" void kmain(unsigned long hart, void *dtb) { (void)hart; (void)dtb; + // D1 doesnt give me dtb ptr? + // dtb = (void *)0x5fb38580; + + dtb::DeviceTree dt; + int res = dtb::validate_and_parse_header(dt, dtb); + if(!res) { + fmt("validate_and_parse_header: {}\n", res); + fmt("magic: {}\n", dt.meta.base); + dtb::print_reserved_regions(dt); + dtb::print_structure_block(dt); + } namespace legacy = drivers::opensbi::legacy; namespace base = drivers::opensbi::base; diff --git a/kernel/meson.build b/kernel/meson.build index 6cb5212..e3f69b0 100644 --- a/kernel/meson.build +++ b/kernel/meson.build @@ -9,6 +9,7 @@ kernel_includes = [ ] subdir('drivers/opensbi') +subdir('common/dtb') includes = [ # arch_includes,