-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
2 changed files
with
146 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |