You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
4.4 KiB
142 lines
4.4 KiB
#include "dtb_discovery.h"
|
|
#include "libfdt.h"
|
|
#include "dts.h"
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <cstdlib>
|
|
|
|
|
|
namespace {
|
|
std::vector<std::string> split_csv(const std::string& str) {
|
|
std::vector<std::string> result;
|
|
std::stringstream ss(str);
|
|
std::string item;
|
|
while (std::getline(ss, item, ',')) {
|
|
result.push_back(item);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string join_csv(const std::vector<std::string>& vec) {
|
|
std::string result;
|
|
for (size_t i = 0; i < vec.size(); ++i) {
|
|
result += vec[i];
|
|
if (i < vec.size() - 1) result += ",";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> get_device_params(const void* fdt, int offset) {
|
|
int param_len;
|
|
const char* params = (char*)fdt_getprop(fdt, offset, "spike,plugin-params", ¶m_len);
|
|
return params ? split_csv(params) : std::vector<std::string>();
|
|
}
|
|
|
|
// Helper to parse reg property
|
|
bool parse_reg_property(const void* fdt, int offset, const char* node_name,
|
|
uint64_t& base, uint64_t& size) {
|
|
int len = 0;
|
|
const fdt32_t* reg_prop = (const fdt32_t*)fdt_getprop(fdt, offset, "reg", &len);
|
|
if (!reg_prop) {
|
|
fprintf(stderr, "DTB node '%s' missing 'reg' property\n", node_name);
|
|
return false;
|
|
}
|
|
|
|
int addr_cells = fdt_address_cells(fdt, 0);
|
|
int size_cells = fdt_size_cells(fdt, 0);
|
|
if (addr_cells < 1 || size_cells < 1) {
|
|
fprintf(stderr, "Invalid #address-cells or #size-cells for node '%s'\n", node_name);
|
|
return false;
|
|
}
|
|
|
|
int entry_cells = addr_cells + size_cells;
|
|
int entry_size = entry_cells * sizeof(fdt32_t);
|
|
if ((len % entry_size) != 0) {
|
|
fprintf(stderr, "DTB node '%s' has malformed 'reg'\n", node_name);
|
|
return false;
|
|
}
|
|
|
|
const fdt32_t* p = reg_prop;
|
|
base = 0;
|
|
size = 0;
|
|
|
|
// Parse base address
|
|
for (int i = 0; i < addr_cells; ++i)
|
|
base = (base << 32) | fdt32_to_cpu(p[i]);
|
|
|
|
// Parse size
|
|
for (int i = 0; i < size_cells; ++i)
|
|
size = (size << 32) | fdt32_to_cpu(p[addr_cells + i]);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Core platform devices handled by Spike internally
|
|
const std::set<std::string> SPIKE_DEFAULT_DEVICES = {
|
|
"riscv,plic0",
|
|
"sifive,plic-1.0.0",
|
|
"ns16550a",
|
|
"riscv,clint0"
|
|
};
|
|
|
|
bool should_skip_device(const std::string& device_name) {
|
|
return SPIKE_DEFAULT_DEVICES.find(device_name) != SPIKE_DEFAULT_DEVICES.end();
|
|
}
|
|
} // namespace
|
|
|
|
namespace dtb_discovery {
|
|
|
|
void discover_devices_from_dtb(const void* fdt,
|
|
std::vector<device_factory_sargs_t>& factories) {
|
|
for (const auto& [device_name, factory] : mmio_device_map()) {
|
|
//Spike default devices are not managed by dtb discovery feature
|
|
if (should_skip_device(device_name)) continue;
|
|
|
|
int offset = -1;
|
|
while ((offset = fdt_node_offset_by_compatible(fdt, offset, device_name.c_str())) >= 0) {
|
|
const char* node_name = fdt_get_name(fdt, offset, NULL);
|
|
|
|
uint64_t base = 0, size = 0;
|
|
if (!parse_reg_property(fdt, offset, node_name, base, size)) {
|
|
exit(1);
|
|
}
|
|
|
|
auto parsed_args = get_device_params(fdt, offset);
|
|
|
|
// Prepend base and size to arguments
|
|
std::vector<std::string> full_args;
|
|
full_args.push_back(std::to_string(base));
|
|
full_args.push_back(std::to_string(size));
|
|
full_args.insert(full_args.end(), parsed_args.begin(), parsed_args.end());
|
|
|
|
fprintf(stdout, "DTB discovered device: %s - type: %s - base: 0x%016" PRIx64
|
|
" - size: 0x%016" PRIx64 " - params: %s\n",
|
|
node_name, device_name.c_str(), base, size,
|
|
(parsed_args.empty() ? "" : join_csv(parsed_args).c_str()));
|
|
|
|
factories.push_back({factory, full_args});
|
|
}
|
|
}
|
|
}
|
|
|
|
void discover_memory_from_dtb(const void* fdt,
|
|
std::vector<std::pair<reg_t, abstract_mem_t*>>& mems) {
|
|
int offset = -1;
|
|
while ((offset = fdt_node_offset_by_prop_value(
|
|
fdt, offset, "device_type", "memory", sizeof("memory"))) >= 0) {
|
|
const char* node_name = fdt_get_name(fdt, offset, nullptr);
|
|
|
|
uint64_t base = 0, size = 0;
|
|
if (!parse_reg_property(fdt, offset, node_name, base, size)) {
|
|
exit(1);
|
|
}
|
|
|
|
fprintf(stdout,
|
|
"DTB memory device: %s - Memory initialized at [0x%016" PRIx64 ", 0x%016" PRIx64 ")\n",
|
|
node_name, base, base + size);
|
|
|
|
mems.emplace_back(base, new mem_t(size));
|
|
}
|
|
}
|
|
|
|
} // namespace dtb_discovery
|
|
|