Skip to content

Commit

Permalink
Merge pull request #1 from pzaino/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
pzaino authored Nov 19, 2023
2 parents dc8d467 + cee518f commit 2f7385e
Show file tree
Hide file tree
Showing 16 changed files with 882 additions and 0 deletions.
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# DTBLib

This is a library for reading and parsing Device Tree Blob files. It is written in ANSI C and without Standard C Library (SCL) dependencies.

The reason for writing this library is that I needed a library for parsing DTB files in a project of mine, but I couldn't find any library that was written in ANSI C and without SCL dependencies. So I decided to write my own library.

This library is specifically written to be used in the RISC OS Kernel project, but it can be used in any other project as well as long as you understand what krnllib does and doesn't do.

## Features

* Written in ANSI C and without SCL dependencies.
* Supports parsing DTB files.
* Supports parsing DTB files with a size of up to 4MB.
* Supports parsing DTB files with a maximum depth of 32 levels.
* Supports parsing DTB files with a maximum string length of 256 characters.
* Supports parsing DTB files with a maximum number of 65536 nodes.

## Building

The library is very easy to build. You just need to run the following command:

To build with GCC on RISC OS (go in the src directory):

```bash
MkGCC
```

To build with DDE on RISC OS (go in the src directory):

```bash
MkDDE
```

To build with GCC on Linux:

```bash
./.rocog/scripts/ux-src gen
./ux-src/MkGCC.sh
```

## Usage

The library is very easy to use. You just need to include the header file and link the library to your project. Then you can use the library to parse DTB files.

### Example

```c
#include "DTBLib.h"

...
```

## License

This library is licensed under Apache License 2.0. See the [LICENSE](LICENSE) file for details.
246 changes: 246 additions & 0 deletions src/dtblib/c/dtblib
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
/*
* DTBLib: Device Tree Blob Parsing Library
*
* Copyright (c) 2023 by Paolo Fabio Zaino, all rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Limitations:
* - Redistribution and use of this software in source and binary
* forms, with or without modification, are permitted provided that
* the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions, and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* - Neither the name of Paolo Fabio Zaino, nor the names
* of its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
* - Users of this software are prohibited from misrepresenting
* themselves as the authors or original contributors of this
* software.
*
* This software is provided by the copyright holders and contributors
* "as is" and any express or implied warranties, including, but not
* limited to, the implied warranties of merchantability and fitness
* for a particular purpose are disclaimed. In no event shall the
* copyright owner or contributors be liable for any direct,
* indirect, incidental, special, exemplary, or consequential damages
* (including, but not limited to, procurement of substitute goods or
* services; loss of use, data, or profits; or business interruption)
* however caused and on any theory of liability, whether in
* contract, strict liability, or tort (including negligence or
* otherwise) arising in any way out of the use of this software,
* even if advised of the possibility of such damage.
*
* For more details and the full text of the license, refer to the
* Apache 2.0 License file included with this project or available at
* the above URL.
*/

#include "krnllib.h"
#include "strlib.h"
#include "dtblib.h"

static void free_tree(struct dt_node* node) {
if (node == NULL) return;

free_tree(node->children);
free_tree(node->next_sibling);

krnl_free(node->name);
// Free properties here as well
krnl_free(node);
}

static inline int hndl_fdt_begin_node(struct dt_node** current_node, const char* dtb_data, int* offset) {
char* node_name = str_read(dtb_data, *offset);
if (!node_name) {
return -1;
}
// Move offset to the end of the string
*offset += str_len(node_name) + 1;

struct dt_node* new_node = krnl_malloc(sizeof(struct dt_node));
if (new_node == NULL) {
krnl_free(node_name);
return -1;
}

new_node->name = node_name;
new_node->parent = *current_node;
new_node->children = NULL;
new_node->next_sibling = NULL;
new_node->props = NULL;

// Link new_node into the tree
if ((*current_node)->children == NULL) {
(*current_node)->children = new_node;
} else {
struct dt_node* last_child = (*current_node)->children;
while (last_child->next_sibling != NULL) {
last_child = last_child->next_sibling;
}
last_child->next_sibling = new_node;
}

*current_node = new_node;
return 0;
}

static inline int hndl_fdt_prop(struct dt_node* current_node, const char* dtb_data, int* offset, const char* strings_block) {
uint32_t prop_len = read_uint32(dtb_data, *offset);
*offset += sizeof(uint32_t);
uint32_t name_offset = read_uint32(dtb_data, *offset);
*offset += sizeof(uint32_t);

char* prop_name = str_read(strings_block, name_offset);
if (!prop_name) {
return -1; // Error reading property name
}

void* prop_value = krnl_malloc(prop_len);
if (!prop_value) {
krnl_free(prop_name);
return -1; // Error allocating memory for property value
}

krnl_memcpy(prop_value, dtb_data + *offset, prop_len);
*offset += prop_len;

struct dt_property* new_prop = krnl_malloc(sizeof(struct dt_property));
if (!new_prop) {
krnl_free(prop_name);
krnl_free(prop_value);
return -1; // Error allocating memory for dt_property
}

new_prop->name = prop_name;
new_prop->value = prop_value;
new_prop->size = prop_len;
new_prop->next = NULL;

// Attach new_prop to the current_node's properties
if (current_node->props == NULL) {
current_node->props = new_prop;
} else {
struct dt_property* last_prop = current_node->props;
while (last_prop->next != NULL) {
last_prop = last_prop->next;
}
last_prop->next = new_prop;
}

return 0;
}

static int validate_dtb_header(const char* dtb_data) {
// Verify Magic Number
uint32_t magic = read_uint32(dtb_data, 0);
if (magic != FDT_MAGIC) {
return -1; // Invalid magic number
}

// Check DTB size
/*
uint32_t total_size = read_uint32(dtb_data, 4);
if (total_size > MAX_DTB_SIZE || total_size < MIN_DTB_SIZE) {
return -1; // DTB size is unreasonable
}
*/

// Check version and last compatible version
uint32_t version = read_uint32(dtb_data, 8);
uint32_t last_comp_version = read_uint32(dtb_data, 12);
if (version < MIN_DTB_VERSION || version > MAX_DTB_VERSION ||
last_comp_version > version) {
return -1; // Incompatible DTB version
}

// TODO: Additional header validations as necessary
// Example: Check for structure block and strings block offsets within the total size

return 0;
}

struct dt_node* parse_dtb(
const char* dtb_data,
const char* strings_block,
int offset
) {
// Validate DTB header
if (validate_dtb_header(dtb_data) != 0) {
return NULL;
}

// Allocate root node
struct dt_node* root_node = krnl_malloc(sizeof(struct dt_node));
if (!root_node) {
// Handle allocation error
return NULL;
}

// Initialize root node
root_node->name = NULL; // Root node usually doesn't have a name
root_node->parent = NULL;
root_node->children = NULL;
root_node->next_sibling = NULL;
root_node->props = NULL;

// Parse DTB
struct dt_node* current_node = root_node;
int rval = 0;

while (true) {
uint32_t token = read_uint32(dtb_data, offset);
offset += sizeof(uint32_t);

switch (token) {
case FDT_BEGIN_NODE:
rval = hndl_fdt_begin_node(&current_node, dtb_data, &offset);
if (rval != 0) {
// Handle error
free_tree(root_node); // Assuming free_tree is a function that frees the entire tree
return NULL;
}
break;
case FDT_END_NODE:
current_node = current_node->parent;
break;
case FDT_PROP:
rval = hndl_fdt_prop(current_node, dtb_data, &offset, strings_block); // strings_block is the start of the strings block
if (rval != 0) {
// Handle error
free_tree(root_node);
return NULL;
}
break;
case FDT_NOP:
// NOP handling (usually just skip)
break;
case FDT_END:
if (current_node == root_node) {
return NULL; // Error: root node not closed
}
return root_node;
default:
// Handle unexpected token
free_tree(root_node);
return NULL;
}
}
}
Loading

0 comments on commit 2f7385e

Please sign in to comment.