|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCHv4 5/9] plat/common: Add fdt address translation support
The ranges property provides a means of defining a mapping or
translation between the address space of the bus (the child
address space) and the address space of the bus node's parent
(the parent address space).
Currently only 1:1 mapping between parent and child address is
supported.
Signed-off-by: Jia He <justin.he@xxxxxxx>
---
plat/common/fdt.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 136 insertions(+)
diff --git a/plat/common/fdt.c b/plat/common/fdt.c
index 6feec0a..1246dec 100644
--- a/plat/common/fdt.c
+++ b/plat/common/fdt.c
@@ -40,6 +40,11 @@
#include "libfdt_internal.h"
#include "uk/print.h"
+#define FDT_BAD_ADDR (uint64_t)(-1)
+#define FDT_MAX_ADDR_CELLS FDT_MAX_NCELLS
+#define FDT_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= FDT_MAX_ADDR_CELLS && \
+ (ns) > 0)
+
int fdt_getprop_u32_by_offset(const void *fdt, int offset,
const char *name, uint32_t *out)
{
@@ -156,3 +161,134 @@ int fdt_size_cells_or_parent(const void *fdt, int
nodeoffset)
return -FDT_ERR_NOTFOUND;
}
+
+static uint64_t fdt_reg_read_number(const fdt32_t *regs, uint32_t size)
+{
+ uint64_t number = 0;
+
+ if (size >= 3 || size <= 0)
+ return -FDT_ERR_BADNCELLS;
+
+ for (uint32_t i = 0; i < size; i++) {
+ number <<= 32;
+ number |= fdt32_to_cpu(*regs);
+ regs++;
+ }
+
+ return number;
+}
+
+/* Default translator (generic bus) */
+static void fdt_default_count_cells(const void *fdt, int parentoffset,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = fdt_address_cells(fdt, parentoffset);
+
+ if (sizec)
+ *sizec = fdt_size_cells(fdt, parentoffset);
+}
+
+static int fdt_default_translate(fdt32_t *addr, uint64_t offset, int na)
+{
+ uint64_t a = fdt_reg_read_number(addr, na);
+
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = cpu_to_fdt32(a >> 32);
+ addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
+
+ return 0;
+}
+
+static int fdt_translate_one(const void *fdt, int parent, fdt32_t *addr,
+ int na, int pna, const char *rprop)
+{
+ const fdt32_t *ranges;
+ int rlen;
+ uint64_t offset = FDT_BAD_ADDR;
+
+ ranges = fdt_getprop(fdt, parent, rprop, &rlen);
+ if (!ranges)
+ return 1;
+ if (rlen == 0) {
+ offset = fdt_reg_read_number(addr, na);
+ memset(addr, 0, pna * 4);
+ uk_pr_debug("empty ranges, 1:1 translation\n");
+ goto finish;
+ }
+
+ uk_pr_err("Error, only 1:1 translation is supported...\n");
+ return 1;
+ finish:
+ uk_pr_debug("with offset: 0x%lx\n", offset);
+
+ /* Translate it into parent bus space */
+ return fdt_default_translate(addr, offset, pna);
+}
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ */
+static uint64_t fdt_translate_address_by_ranges(const void *fdt,
+ int node_offset, const fdt32_t *regs)
+{
+ int parent;
+ fdt32_t addr[FDT_MAX_ADDR_CELLS];
+ int na, ns, pna, pns;
+ uint64_t result = FDT_BAD_ADDR;
+
+ /* Get parent */
+ parent = fdt_parent_offset(fdt, node_offset);
+ if (parent < 0)
+ goto bail;
+
+ /* Count address cells & copy address locally */
+ fdt_default_count_cells(fdt, parent, &na, &ns);
+ if (!FDT_CHECK_COUNTS(na, ns)) {
+ uk_pr_err("Bad cell count for %s\n",
+ fdt_get_name(fdt, node_offset, NULL));
+ goto bail;
+ }
+ memcpy(addr, regs, na * 4);
+
+ /* Translate */
+ for (;;) {
+ /* Switch to parent bus */
+ node_offset = parent;
+ parent = fdt_parent_offset(fdt, node_offset);
+
+ /* If root, we have finished */
+ if (parent < 0) {
+ uk_pr_debug("reached root node\n");
+ result = fdt_reg_read_number(addr, na);
+ break;
+ }
+
+ /* Get new parent bus and counts */
+ fdt_default_count_cells(fdt, parent, &pna, &pns);
+ if (!FDT_CHECK_COUNTS(pna, pns)) {
+ uk_pr_err("Bad cell count for %s\n",
+ fdt_get_name(fdt, node_offset, NULL));
+ break;
+ }
+
+ uk_pr_debug("parent bus (na=%d, ns=%d) on %s\n",
+ pna, pns, fdt_get_name(fdt, parent, NULL));
+
+ /* Apply bus translation */
+ if (fdt_translate_one(fdt, node_offset,
+ addr, na, pna, "ranges"))
+ break;
+
+ /* Complete the move up one level */
+ na = pna;
+ ns = pns;
+ }
+bail:
+ return result;
+}
+
--
2.17.1
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |