Common: Started writing a DTB/FDT parser
This commit is contained in:
parent
4367e38f39
commit
ad1ac3f9d7
5 changed files with 174 additions and 0 deletions
117
kernel/common/dtb/dtb.cpp
Normal file
117
kernel/common/dtb/dtb.cpp
Normal 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
|
34
kernel/common/dtb/include/dtb/dtb.h
Normal file
34
kernel/common/dtb/include/dtb/dtb.h
Normal 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
|
9
kernel/common/dtb/meson.build
Normal file
9
kernel/common/dtb/meson.build
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
kernel_sources += [
|
||||||
|
files(
|
||||||
|
'dtb.cpp',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
kernel_includes += include_directories(
|
||||||
|
'include'
|
||||||
|
)
|
|
@ -1,6 +1,8 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <dtb/dtb.h>
|
||||||
|
|
||||||
#include <opensbi/opensbi.h>
|
#include <opensbi/opensbi.h>
|
||||||
#include <opensbi/extensions/legacy.h>
|
#include <opensbi/extensions/legacy.h>
|
||||||
#include <opensbi/extensions/base.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) {
|
extern "C" void kmain(unsigned long hart, void *dtb) {
|
||||||
(void)hart;
|
(void)hart;
|
||||||
(void)dtb;
|
(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 legacy = drivers::opensbi::legacy;
|
||||||
namespace base = drivers::opensbi::base;
|
namespace base = drivers::opensbi::base;
|
||||||
|
|
|
@ -9,6 +9,7 @@ kernel_includes = [
|
||||||
]
|
]
|
||||||
|
|
||||||
subdir('drivers/opensbi')
|
subdir('drivers/opensbi')
|
||||||
|
subdir('common/dtb')
|
||||||
|
|
||||||
includes = [
|
includes = [
|
||||||
# arch_includes,
|
# arch_includes,
|
||||||
|
|
Loading…
Reference in a new issue