Common: Started writing a DTB/FDT parser

This commit is contained in:
Thomas Muller 2022-06-07 01:06:02 -04:00
parent 4367e38f39
commit ad1ac3f9d7
Signed by: thomas
GPG key ID: AF006EB730564952
5 changed files with 174 additions and 0 deletions

117
kernel/common/dtb/dtb.cpp Normal file
View file

@ -0,0 +1,117 @@
#include "dtb/dtb.h"
#include <opensbi/extensions/legacy.h>
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<typename T>
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<typename T>
struct big_endian {
T value() {
return bswap(m_value);
}
private:
T m_value;
};
struct [[gnu::packed]] FdtHeader {
big_endian<uint32_t> magic;
big_endian<uint32_t> size;
big_endian<uint32_t> struct_offset;
big_endian<uint32_t> strings_offset;
big_endian<uint32_t> reserved_map_offset;
big_endian<uint32_t> version;
big_endian<uint32_t> last_compatible_version;
big_endian<uint32_t> boot_cpu_id;
big_endian<uint32_t> strings_size;
big_endian<uint32_t> struct_size;
};
struct [[gnu::packed]] FdtReserveEntry {
big_endian<uint64_t> address;
big_endian<uint64_t> size;
};
};
int validate_and_parse_header(DeviceTree &dt, void *base) {
auto header = reinterpret_cast<FdtHeader *>(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<char *>(base) + header->reserved_map_offset.value();
dt.structure_block =
reinterpret_cast<char *>(base) + header->struct_offset.value();
dt.strings_block =
reinterpret_cast<char *>(base) + header->strings_offset.value();
return 0;
}
void print_reserved_regions(DeviceTree dt) {
auto regions = reinterpret_cast<FdtReserveEntry *>(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

View file

@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
#include <cstddef>
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

View file

@ -0,0 +1,9 @@
kernel_sources += [
files(
'dtb.cpp',
),
]
kernel_includes += include_directories(
'include'
)

View file

@ -1,6 +1,8 @@
#include <stdarg.h>
#include <inttypes.h>
#include <dtb/dtb.h>
#include <opensbi/opensbi.h>
#include <opensbi/extensions/legacy.h>
#include <opensbi/extensions/base.h>
@ -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;

View file

@ -9,6 +9,7 @@ kernel_includes = [
]
subdir('drivers/opensbi')
subdir('common/dtb')
includes = [
# arch_includes,