From bf718cf7888e75aaa26acb314ce21e780268a0d0 Mon Sep 17 00:00:00 2001 From: Ben Mezger Date: Sun, 19 Jan 2020 13:38:19 -0300 Subject: [PATCH] Feat: Parse FDT header and add initial FDT dt_struct scanner This adds support for the following features required by #2: - Map all FDT structure block - Convert big-endian to little-endian - Read FDT header --- include/kernel/fdt.h | 97 ++++++++++++++++++++++++++++++++++++++++++++ src/ftd.c | 49 ++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 include/kernel/fdt.h create mode 100644 src/ftd.c diff --git a/include/kernel/fdt.h b/include/kernel/fdt.h new file mode 100644 index 0000000..2d96abd --- /dev/null +++ b/include/kernel/fdt.h @@ -0,0 +1,97 @@ +#ifndef _FDT_H +#define _FDT_H + +#include "types.h" + +#define FDT_MAGIC 0xd00dfeed +#define FDT_VERSION 0x11 +#define FDT_DEFAULT_ADDRESS_CELL 0x2 +#define FDT_DEFAULT_SIZE_CELLS 0x1 + +/* + * marks the beginning of the node's representation and is followed by the + * node's unit name as extra data + */ +#define FDT_BEGIN_NODE 0x00000001 +/* + * marks the end of the node's representation and has not extra data + * as extra data, so is if followed immediately by the next token, which may be + * any token except for the FDT_NOP + */ +#define FDT_END_NODE 0x00000002 + +/* Marks the beginning of the representation of one property in the device-tree. + * It shall be followed by an extra data describing the property which consists + * of the property's length and name representation + * + */ +#define FDT_PROP 0x00000003 +/* FDT_NOP tokens will be ignored by the parsing device */ +#define FDT_NOP 0x00000004 +/* marks the end of the structure block. There is only one FTD_END token and has + * no extra data. The byte immediately after it has the offset of the beginning + * of the structure block equal to the value of the size header->size_dt_struct + * field in the device-tree + */ +#define FDT_END 0x00000009 + +/* + * Convert from big-endian and little-endian + * + * RISC-V ISA has no explicit byte swapping instructions. + * Our best bet here is rely on the compiler for the best implementation + * available. + * This returns with the order of bytes reversed, for example, 0xaabb becomes + * 0xbbaa. Byte here always means exactly 8 bits. + */ +#define swapb(x) ({ __builtin_bswap32(x); }) + +/* from: + * https://github.com/devicetree-org/devicetree-specification/blob/master/source/flattened-format.rst + */ +struct fdt_header { + /* contains the value 0xd00dfeed */ + uint32_t magic; + /* contains total size in bytes of the device tree */ + uint32_t totalsize; + /* contains the offset in bytes of the structured block */ + uint32_t off_dt_struct; + /* contains the offset in bytes of the strings block */ + uint32_t off_dt_strings; + /* contains the offset in bytes of the memory reservation block */ + uint32_t off_mem_rsvmap; + /* contains the version of the devicetree data structure */ + uint32_t version; + /* last version of the device tree with which the version used backwads + * compatibility */ + uint32_t last_comp_version; + /* contains the physical ID of the system's boot CPU */ + uint32_t boot_cpuid_phys; + /* contains the length in bytes of the strings block section of the + * devicetree blob */ + uint32_t size_dt_strings; + /* contains the length in bytes of the structure block section of the + * devicetree blob */ + uint32_t size_dt_struct; +}; + +struct fdt_node { + uint32_t *name; + uint32_t address; + uint32_t size_cells; + struct fdt_property *properties; + struct fdt_node *nodes; +}; + +struct fdt_property { + uint32_t len; /* in bytes */ + uint32_t *value; /* byte string of length = len */ + uint32_t *name; /* offset to the string block where the name is + stored */ +}; + +struct fdt_header *fdt_header(uintptr_t *); +void scan_fdt(uintptr_t *); +uint32_t _scan_fdt(const char *, uint32_t *, struct fdt_node *); + +#endif diff --git a/src/ftd.c b/src/ftd.c new file mode 100644 index 0000000..0bf6f27 --- /dev/null +++ b/src/ftd.c @@ -0,0 +1,49 @@ +#include +#include + +volatile uintptr_t *fdt_map; + +uint32_t +_scan_fdt(const char *dt_strings, uint32_t *dt_struct, struct fdt_node *node) +{ + parent->address = FDT_DEFAULT_ADDRESS_CELL; + parent->size_cells = FDT_DEFAULT_SIZE_CELLS; + + while (1) { + uint32_t token = swapb(dt_struct[0]); + switch (token) { + case FDT_NOP: + dt_struct++; + break; + case FDT_BEGIN_NODE: + break; + } + } +} + +struct fdt_header * +fdt_header(uintptr_t *fdt) +{ + struct fdt_header *header = (struct fdt_header *)fdt; + if (swapb(header->magic) != FDT_MAGIC || + swapb(header->last_comp_version) > FDT_VERSION) { + return NULL; + } + return header; +} + +void +scan_fdt(uintptr_t *fdt) +{ + fdt_map = fdt; + struct fdt_header *header = fdt_header(fdt); + + /* get the string block */ + const char *dt_strings = + (const char *)(fdt + swapb(header->off_dt_strings)); + + /* get the structure block */ + uint32_t *dt_struct = (uint32_t *)(fdt + swapb(header->off_dt_struct)); + struct fdt_node *parent = NULL; + _scan_fdt(dt_strings, dt_struct); +}