117 lines
3.8 KiB
C++
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
|