[PATCH 3/6] bootwrapper: Add flat device tree ops glue code
Mark A. Greer
mgreer at mvista.com
Fri Sep 8 13:38:14 EST 2006
This patch adds the "glue" files that interface between the bootwrapper
code and the shared code that is in flatdevtree.[ch].
Signed-off-by: Mark A. Greer <mgreer at mvista.com>
--
Makefile | 2
flatdevtree_env.h | 34 ++++++
flatdevtree_misc.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 295 insertions(+)
--
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index c2bb541..f1877ac 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -39,6 +39,8 @@ #$(addprefix $(obj)/,main.o): $(addprefi
src-boot := crt0.S string.S stdio.c main.c div64.S
ifeq ($(CONFIG_PPC_MULTIPLATFORM),y)
src-boot += of.c
+else
+src-boot += flatdevtree_misc.c
endif
src-boot += $(zlib)
src-boot := $(addprefix $(obj)/, $(src-boot))
diff --git a/arch/powerpc/boot/flatdevtree_env.h b/arch/powerpc/boot/flatdevtree_env.h
new file mode 100644
index 0000000..90e723b
--- /dev/null
+++ b/arch/powerpc/boot/flatdevtree_env.h
@@ -0,0 +1,34 @@
+/*
+ * This file adds the header file glue so that the shared files
+ * flatdevicetree.[ch] can compile and work in the powerpc bootwrapper.
+ *
+ * Author: Mark A. Greer <mgreer at mvista.com>
+ *
+ * 2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef _PPC_BOOT_FLATDEVTREE_ENV_H_
+#define _PPC_BOOT_FLATDEVTREE_ENV_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+
+#define be16_to_cpu(x) (x)
+#define cpu_to_be16(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_be32(x) (x)
+#define be64_to_cpu(x) (x)
+#define cpu_to_be64(x) (x)
+
+#define ft_malloc(s) malloc(s)
+#define ft_free(p,s) free(p,s)
+#define ft_exit(x) exit()
+
+#endif /* _PPC_BOOT_FLATDEVTREE_ENV_H_ */
diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c
new file mode 100644
index 0000000..603d89d
--- /dev/null
+++ b/arch/powerpc/boot/flatdevtree_misc.c
@@ -0,0 +1,259 @@
+/*
+ * This file does the necessary interface mapping between the bootwrapper
+ * device tree operations and the interface provided by shared source
+ * files flatdevicetree.[ch]. It also provides the bootwrapper-required
+ * functionality that is not provided by flatdevicetree.c
+ *
+ * Author: Mark A. Greer <mgreer at mvista.com>
+ * ft_translate_addr() and related routines came from
+ * <file:arch/powerpc/kernel/prom_parse.c> which has no author or
+ * copyright notice.
+ *
+ * 2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include "flatdevtree.h"
+
+#define MAX_ADDR_CELLS 4
+#define BAD_ADDR ((u64)-1)
+
+struct ft_bus {
+ u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
+ int (*translate)(u32 *addr, u64 offset, int na);
+};
+
+static u32 ft_find_cells(char *path, char *prop)
+{
+ void *devp;
+ u32 num;
+ char p[MAX_PATH_LEN];
+
+ strcpy(p, path);
+ do {
+ if ((devp = finddevice(p))
+ && (getprop(devp, prop, &num, sizeof(num)) > 0))
+ return num;
+ ft_parentize(p, 0);
+ } while (strlen(p) > 0);
+ return 1; /* default of 1 */
+}
+
+static u64 ft_read_addr(u32 *cell, int size)
+{
+ u64 r = 0;
+ while (size--)
+ r = (r << 32) | *(cell++);
+ return r;
+}
+
+static u64 ft_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = ft_read_addr(range, na);
+ s = ft_read_addr(range + na + pna, ns);
+ da = ft_read_addr(addr, na);
+
+ if (da < cp || da >= (cp + s))
+ return BAD_ADDR;
+ return da - cp;
+}
+
+static int ft_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+ u64 a = ft_read_addr(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = a >> 32;
+ addr[na - 1] = a & 0xffffffffu;
+
+ return 0;
+}
+
+static u64 ft_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x03000000)
+ return BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = ft_read_addr(range + 1, na - 1);
+ s = ft_read_addr(range + na + pna, ns);
+ da = ft_read_addr(addr + 1, na - 1);
+
+ if (da < cp || da >= (cp + s))
+ return BAD_ADDR;
+ return da - cp;
+}
+
+static int ft_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+ return ft_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static u64 ft_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x00000001)
+ return BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = ft_read_addr(range + 1, na - 1);
+ s = ft_read_addr(range + na + pna, ns);
+ da = ft_read_addr(addr + 1, na - 1);
+
+ if (da < cp || da >= (cp + s))
+ return BAD_ADDR;
+ return da - cp;
+}
+
+static int ft_bus_isa_translate(u32 *addr, u64 offset, int na)
+{
+ return ft_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static void ft_match_bus(char *path, struct ft_bus *bus)
+{
+ void *devp;
+ char dtype[128]; /* XXXX */
+
+ if ((devp = finddevice(path)) && (getprop(devp, "device_type", dtype,
+ sizeof(dtype)) > 0)) {
+ if (!strcmp(dtype, "isa")) {
+ bus->map = ft_bus_isa_map;
+ bus->translate = ft_bus_isa_translate;
+ } else if (!strcmp(dtype, "pci")) {
+ bus->map = ft_bus_pci_map;
+ bus->translate = ft_bus_pci_translate;
+ } else {
+ bus->map = ft_bus_default_map;
+ bus->translate = ft_bus_default_translate;
+ }
+ }
+}
+
+static int ft_translate_one(char *path, struct ft_bus *bus, struct ft_bus *pbus,
+ u32 *addr, u32 na, u32 ns, u32 pna)
+{
+ void *devp;
+ u32 ranges[10 * (na + pna + ns)]; /* XXXX */
+ u32 *rp;
+ unsigned int rlen;
+ int rone;
+ u64 offset = BAD_ADDR;
+
+ if (!(devp = finddevice(path))
+ || ((rlen = getprop(devp, "ranges", ranges,
+ sizeof(ranges))) < 0)
+ || (rlen == 0)) {
+ offset = ft_read_addr(addr, na);
+ memset(addr, 0, pna * 4);
+ goto finish;
+ }
+
+ rlen /= 4;
+ rone = na + pna + ns;
+ rp = ranges;
+ for (; rlen >= rone; rlen -= rone, rp += rone) {
+ offset = bus->map(addr, rp, na, ns, pna);
+ if (offset != BAD_ADDR)
+ break;
+ }
+ if (offset == BAD_ADDR)
+ return 1;
+ memcpy(addr, rp + na, 4 * pna);
+
+finish:
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+/* 'addr' is modified */
+static u64 ft_translate_addr(const char *p, const u32 *in_addr,
+ const u32 addr_len)
+{
+ struct ft_bus bus, pbus;
+ int na, ns, pna, pns;
+ u32 addr[MAX_ADDR_CELLS];
+ char path[MAX_PATH_LEN], ppath[MAX_PATH_LEN];
+
+ strcpy(ppath, p);
+ ft_parentize(ppath, 0);
+ ft_match_bus(ppath, &bus);
+ na = ft_find_cells(ppath, "#address-cells");
+ ns = ft_find_cells(ppath, "#size-cells");
+ memcpy(addr, in_addr, na * 4);
+
+ for (;;) {
+ strcpy(path, ppath);
+ ft_parentize(ppath, 0);
+
+ if (strlen(ppath) == 0)
+ return ft_read_addr(addr, na);
+
+ ft_match_bus(ppath, &pbus);
+ pna = ft_find_cells(ppath, "#address-cells");
+ pns = ft_find_cells(ppath, "#size-cells");
+
+ if (ft_translate_one(path, &bus, &pbus, addr, na, ns, pna))
+ exit();
+
+ na = pna;
+ ns = pns;
+ memcpy(&bus, &pbus, sizeof(struct ft_bus));
+ }
+}
+
+static void *dtb;
+
+static void *ft_finddevice(const char *name)
+{
+ return ft_find_node(dtb, name);
+}
+
+static int ft_getprop(const void *node, const char *propname, void *buf,
+ const int buflen)
+{
+ return ft_get_prop(dtb, node, propname, buf, buflen);
+}
+
+static int ft_setprop(const void *node, const char *propname, const void *buf,
+ const int buflen)
+{
+ return ft_set_prop(&dtb, node, propname, buf, buflen);
+}
+
+static void ft_call_kernel(void *entry_addr, unsigned long a1, unsigned long a2,
+ void *promptr, void *sp)
+{
+ void (*kernel_entry)(void *dt_blob, void *start_addr,
+ void *must_be_null);
+
+#ifdef DEBUG
+ printf("kernel:\n\r"
+ " entry addr = 0x%lx\n\r"
+ " flattened dt = 0x%lx\n\r",
+ (unsigned long)entry_addr, dtb);
+#endif
+
+ kernel_entry = entry_addr;
+ kernel_entry(dtb, entry_addr, NULL);
+}
+
+void ft_init(void *dt_blob)
+{
+ dt_ops.finddevice = ft_finddevice;
+ dt_ops.getprop = ft_getprop;
+ dt_ops.setprop = ft_setprop;
+ dt_ops.translate_addr = ft_translate_addr;
+ dt_ops.call_kernel = ft_call_kernel;
+
+ dtb = dt_blob;
+}
More information about the Linuxppc-dev
mailing list