diff options
-rw-r--r-- | bbl/bbl.c | 6 | ||||
-rw-r--r-- | machine/fdt.c | 156 | ||||
-rw-r--r-- | machine/fdt.h | 6 |
3 files changed, 166 insertions, 2 deletions
@@ -21,6 +21,12 @@ static void filter_dtb(uintptr_t source) uintptr_t dest = dtb_output(); uint32_t size = fdt_size(source); memcpy((void*)dest, (void*)source, size); + + // Remove information from the chained FDT + // filter_harts(dest, 0x2); + filter_plic(dest); + filter_compat(dest, "riscv,clint0"); + filter_compat(dest, "riscv,debug-013"); } void boot_other_hart(uintptr_t dtb) diff --git a/machine/fdt.c b/machine/fdt.c index bd8da74..908b2ea 100644 --- a/machine/fdt.c +++ b/machine/fdt.c @@ -106,6 +106,19 @@ const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *v return value; } +int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str) +{ + const char *list = (const char *)prop->value; + const char *end = list + prop->len; + int index = 0; + while (end - list > 0) { + if (!strcmp(list, str)) return index; + ++index; + list += strlen(list) + 1; + } + return -1; +} + //////////////////////////////////////////// MEMORY SCAN ///////////////////////////////////////// struct mem_scan { @@ -280,7 +293,7 @@ static void clint_open(const struct fdt_scan_node *node, void *extra) static void clint_prop(const struct fdt_scan_prop *prop, void *extra) { struct clint_scan *scan = (struct clint_scan *)extra; - if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "riscv,clint0")) { + if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,clint0") >= 0) { scan->compat = 1; } else if (!strcmp(prop->name, "reg")) { fdt_get_address(prop->node->parent, prop->value, &scan->reg); @@ -358,7 +371,7 @@ static void plic_open(const struct fdt_scan_node *node, void *extra) static void plic_prop(const struct fdt_scan_prop *prop, void *extra) { struct plic_scan *scan = (struct plic_scan *)extra; - if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "riscv,plic0")) { + if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,plic0") >= 0) { scan->compat = 1; } else if (!strcmp(prop->name, "reg")) { fdt_get_address(prop->node->parent, prop->value, &scan->reg); @@ -435,3 +448,142 @@ void query_plic(uintptr_t fdt) scan.done = 0; fdt_scan(fdt, &cb); } + +static void plic_redact(const struct fdt_scan_node *node, void *extra) +{ + struct plic_scan *scan = (struct plic_scan *)extra; + uint32_t *value = scan->int_value; + uint32_t *end = value + scan->int_len/4; + + if (!scan->compat) return; + scan->done = 1; + + while (end - value > 0) { + if (bswap(value[1]) == IRQ_M_EXT) value[1] = bswap(-1); + value += 2; + } +} + +void filter_plic(uintptr_t fdt) +{ + struct fdt_cb cb; + struct plic_scan scan; + + memset(&cb, 0, sizeof(cb)); + cb.open = plic_open; + cb.prop = plic_prop; + cb.done = plic_redact; + cb.extra = &scan; + + scan.done = 0; + fdt_scan(fdt, &cb); +} + +//////////////////////////////////////////// COMPAT SCAN //////////////////////////////////////// + +struct compat_scan +{ + const char *compat; + int depth; + int kill; +}; + +static void compat_open(const struct fdt_scan_node *node, void *extra) +{ + struct compat_scan *scan = (struct compat_scan *)extra; + ++scan->depth; +} + +static void compat_prop(const struct fdt_scan_prop *prop, void *extra) +{ + struct compat_scan *scan = (struct compat_scan *)extra; + if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, scan->compat) >= 0) + if (scan->depth < scan->kill) + scan->kill = scan->depth; +} + +static int compat_close(const struct fdt_scan_node *node, void *extra) +{ + struct compat_scan *scan = (struct compat_scan *)extra; + if (scan->kill == scan->depth--) { + scan->kill = 999; + return -1; + } else { + return 0; + } +} + +void filter_compat(uintptr_t fdt, const char *compat) +{ + struct fdt_cb cb; + struct compat_scan scan; + + memset(&cb, 0, sizeof(cb)); + cb.open = compat_open; + cb.prop = compat_prop; + cb.close = compat_close; + cb.extra = &scan; + + scan.compat = compat; + scan.depth = 0; + scan.kill = 999; + fdt_scan(fdt, &cb); +} + +//////////////////////////////////////////// HART FILTER //////////////////////////////////////// + +struct hart_filter { + int compat; + int hart; + char *status; + unsigned long mask; +}; + +static void hart_filter_open(const struct fdt_scan_node *node, void *extra) +{ + struct hart_filter *filter = (struct hart_filter *)extra; + filter->status = 0; + filter->compat = 0; + filter->hart = -1; +} + +static void hart_filter_prop(const struct fdt_scan_prop *prop, void *extra) +{ + struct hart_filter *filter = (struct hart_filter *)extra; + if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "cpu")) { + filter->compat = 1; + } else if (!strcmp(prop->name, "reg")) { + uintptr_t reg; + fdt_get_address(prop->node->parent, prop->value, ®); + filter->hart = reg; + } else if (!strcmp(prop->name, "status")) { + filter->status = (char*)prop->value; + } +} + +static void hart_filter_done(const struct fdt_scan_node *node, void *extra) +{ + struct hart_filter *filter = (struct hart_filter *)extra; + + if (!filter->compat) return; + assert (filter->status); + assert (filter->hart >= 0); + + if (((filter->mask >> filter->hart) & 1)) + strcpy(filter->status, "masked"); +} + +void filter_harts(uintptr_t fdt, unsigned long hart_mask) +{ + struct fdt_cb cb; + struct hart_filter filter; + + memset(&cb, 0, sizeof(cb)); + cb.open = hart_filter_open; + cb.prop = hart_filter_prop; + cb.done = hart_filter_done; + cb.extra = &filter; + + filter.mask = hart_mask; + fdt_scan(fdt, &cb); +} diff --git a/machine/fdt.h b/machine/fdt.h index 235bb2e..0581e95 100644 --- a/machine/fdt.h +++ b/machine/fdt.h @@ -52,6 +52,7 @@ uint32_t fdt_size(uintptr_t fdt); // Extract fields const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *base, uintptr_t *value); const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *base, uintptr_t *value); +int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str); // -1 if not found // Setup memory+clint+plic void query_mem(uintptr_t fdt); @@ -59,6 +60,11 @@ void query_harts(uintptr_t fdt); void query_plic(uintptr_t fdt); void query_clint(uintptr_t fdt); +// Remove information from FDT +void filter_harts(uintptr_t fdt, unsigned long hart_mask); +void filter_plic(uintptr_t fdt); +void filter_compat(uintptr_t fdt, const char *compat); + // The hartids of available harts extern uint64_t hart_mask; |