Skip to content

Commit

Permalink
Feat: Parse FDT header and add initial FDT dt_struct scanner
Browse files Browse the repository at this point in the history
This adds support for the following features required by #2:

- Map all FDT structure block
- Convert big-endian to little-endian
- Read FDT header
  • Loading branch information
benmezger committed Jan 19, 2020
1 parent f8bbe7b commit bf718cf
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 0 deletions.
97 changes: 97 additions & 0 deletions include/kernel/fdt.h
Original file line number Diff line number Diff line change
@@ -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
49 changes: 49 additions & 0 deletions src/ftd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <kernel/fdt.h>
#include <kernel/string.h>

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);
}

0 comments on commit bf718cf

Please sign in to comment.