Skip to content

Commit

Permalink
WIP more of the fdt walkers
Browse files Browse the repository at this point in the history
  • Loading branch information
travisg committed Apr 15, 2024
1 parent d480b6d commit 04fbd18
Show file tree
Hide file tree
Showing 8 changed files with 355 additions and 633 deletions.
185 changes: 3 additions & 182 deletions lib/fdtwalk/fdtwalk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ status_t _fdt_walk(const void *fdt, callback cb) {

} // anonymous namespace

status_t fdt_walk_dump(const void *fdt_) {
status_t fdt_walk_dump(const void *fdt) {
auto cb = [](const fdt_walk_state &state, const char *name) {
for (auto i = 0; i < state.depth; i++) {
printf(" ");
Expand All @@ -175,188 +175,9 @@ status_t fdt_walk_dump(const void *fdt_) {
state.curr_address_cell(), state.curr_size_cell(), name);
};

return _fdt_walk(fdt_, cb);
}

status_t fdt_walk(const void *fdt_, const fdt_walk_callbacks *cb) {
/* if >= 0, we're inside /reserved-memory */
int reserved_memory_depth = -1;

auto walker = [&cb, &reserved_memory_depth](const fdt_walk_state &state, const char *name) {
int err;

/* look for the 'memory@*' property */
if (cb->mem && strncmp(name, "memory@", 7) == 0 && state.depth == 1) {
int lenp;
const uint8_t *prop_ptr = (const uint8_t *)fdt_getprop(state.fdt, state.offset, "reg", &lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' reg prop len %d, ac %u, sc %u\n", name, lenp,
state.curr_address_cell(), state.curr_size_cell());
/* we're looking at a memory descriptor */
uint64_t base;
uint64_t len;
err = read_base_len_pair(prop_ptr, lenp, state.curr_address_cell(), state.curr_size_cell(), &base, &len);
if (err != NO_ERROR) {
TRACEF("error reading base/length from memory@ node\n");
/* continue on */
} else {
LTRACEF("calling mem callback with base %#llx len %#llx\n", base, len);
cb->mem(base, len, cb->memcookie);
}
}
}

/* look for the 'reserved-memory' tree */
if (cb->reserved_memory) {
/* once we see the reserved-memory first level node, track that we are inside
* it until we step out to a node at the same or higher depth.
*/
if (strncmp(name, "reserved-memory", 15) == 0 && state.depth == 1) {
LTRACEF_LEVEL(2, "found reserved memory node\n");

reserved_memory_depth = state.depth;
} else if (reserved_memory_depth >= 0) {
if (state.depth <= reserved_memory_depth) {
/* we have exited the reserved memory tree, so clear our tracking depth */
LTRACEF_LEVEL(2, "exiting reserved memory node\n");
reserved_memory_depth = -1;
} else {
/* if we're inside the reserved meory tree, so this node must
* be a reserved memory region */
int lenp;
const uint8_t *prop_ptr = (const uint8_t *)fdt_getprop(state.fdt, state.offset, "reg", &lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' reg prop len %d, ac %u, sc %u\n", name, lenp,
state.curr_address_cell(), state.curr_size_cell());
/* we're looking at a memory descriptor */
uint64_t base;
uint64_t len;
err = read_base_len_pair(prop_ptr, lenp, state.curr_address_cell(), state.curr_size_cell(), &base, &len);
if (err != NO_ERROR) {
TRACEF("error reading base/length from reserved-memory node\n");
/* continue on */
} else {
LTRACEF("calling reserved memory callback with base %#llx len %#llx\n", base, len);
cb->reserved_memory(base, len, cb->reserved_memory_cookie);
}
}
}
}
}

/* look for a cpu leaf and count the number of cpus */
if (cb->cpu && strncmp(name, "cpu@", 4) == 0 && state.depth == 2) {
int lenp;
const uint8_t *prop_ptr = (const uint8_t *)fdt_getprop(state.fdt, state.offset, "reg", &lenp);
LTRACEF("%p, lenp %u\n", prop_ptr, lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' reg prop len %d, ac %u, sc %u\n", name, lenp,
state.curr_address_cell(), state.curr_size_cell());
uint32_t id = 0;
if (state.curr_address_cell() == 1 && lenp >= 4) {
id = fdt32_to_cpu(*(const uint32_t *)prop_ptr);
prop_ptr += 4;
lenp -= 4;
} else {
PANIC_UNIMPLEMENTED;
}

// is it disabled?
if (check_prop_is_val_string(state.fdt, state.offset, "status", "disabled")) {
LTRACEF("cpu id %#x is disabled, skipping...\n", id);
} else {
LTRACEF("calling cpu callback with id %#x\n", id);
cb->cpu(id, cb->cpucookie);
}
}
}

/* look for a pcie leaf and pass the address of the ecam and other info to the callback */
if (cb->pcie && (strncmp(name, "pcie@", 5) == 0 || strncmp(name, "pci@", 4) == 0)) {
struct fdt_walk_pcie_info info = {};

/* find the range of the ecam */
int lenp;
const uint8_t *prop_ptr = (const uint8_t *)fdt_getprop(state.fdt, state.offset, "reg", &lenp);
LTRACEF("%p, lenp %u\n", prop_ptr, lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' prop 'reg' len %d, ac %u, sc %u\n", name, lenp,
state.curr_address_cell(), state.curr_size_cell());

/* seems to always be full address cells 2, size cells 2, despite it being 3/2 */
info.ecam_base = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
prop_ptr += 8;
info.ecam_len = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
}

/* find which bus range the ecam covers */
prop_ptr = (const uint8_t *)fdt_getprop(state.fdt, state.offset, "bus-range", &lenp);
LTRACEF("%p, lenp %u\n", prop_ptr, lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' prop 'bus-range' len %d, ac %u, sc %u\n", name, lenp,
state.curr_address_cell(), state.curr_size_cell());

if (lenp == 8) {
info.bus_start = fdt32_to_cpu(*(const uint32_t *)prop_ptr);
prop_ptr += 4;
info.bus_end = fdt32_to_cpu(*(const uint32_t *)prop_ptr);
}
}

prop_ptr = (const uint8_t *)fdt_getprop(state.fdt, state.offset, "ranges", &lenp);
LTRACEF("%p, lenp %u\n", prop_ptr, lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' prop 'ranges' len %d, ac %u, sc %u\n", name, lenp,
state.curr_address_cell(), state.curr_size_cell());

/* iterate this packed property */
const uint8_t *prop_end = prop_ptr + lenp;
while (prop_ptr < prop_end) {
uint32_t type = fdt32_to_cpu(*(const uint32_t *)(prop_ptr));
prop_ptr += 4;

/* read 3 64bit values */
uint64_t base1, base2, size;
base1 = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
prop_ptr += 8;
base2 = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
prop_ptr += 8;
size = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
prop_ptr += 8;

switch (type) {
case 0x1000000: // io range
LTRACEF_LEVEL(2, "io range\n");
info.io_base = base1;
info.io_base_mmio = base2;
info.io_len = size;
break;
case 0x2000000: // mmio range
LTRACEF_LEVEL(2, "mmio range\n");
info.mmio_base = base1;
info.mmio_len = size;
break;
case 0x3000000: // mmio range (64bit)
LTRACEF_LEVEL(2, "mmio range (64bit)\n");
info.mmio64_base = base1;
info.mmio64_len = size;
break;
default:
LTRACEF_LEVEL(2, "unhandled type %#x\n", type);
}

LTRACEF_LEVEL(2, "base %#llx base2 %#llx size %#llx\n", base1, base2, size);
}
}

if (info.ecam_len > 0) {
LTRACEF("calling pci callback with ecam base %#llx size %#llx\n", info.ecam_base, info.ecam_len);
cb->pcie(&info, cb->pciecookie);
}
}
};
printf("FDT dump: address %p total size %#x\n", fdt, fdt_totalsize(fdt));

return _fdt_walk(fdt_, walker);
return _fdt_walk(fdt, cb);
}

status_t fdt_walk_find_cpus(const void *fdt, struct fdt_walk_cpu_info *cpu, size_t *cpu_count) {
Expand Down
Loading

0 comments on commit 04fbd18

Please sign in to comment.