QTechOS/kernel/common/dtb/dtb.cpp

117 lines
3.8 KiB
C++

#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