123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include "libfdt.h"
- #include "dtb_node.h"
- static struct
- {
- const char *ptr;
- const char *end;
- char *cur;
- } paths_buf = {NULL, NULL};
- static void *current_fdt;
- int fdt_exec_status = FDT_RET_GET_OK;
- int dtb_node_get_exec_status()
- {
- return fdt_exec_status;
- }
- static int _dtb_node_get_dtb_properties_list(struct dtb_property *dtb_property, off_t node_off)
- {
- /* caller alrealy checked current_fdt */
- off_t property_off = fdt_first_property_offset(current_fdt, node_off);
- struct fdt_property *fdt_property;
- if (property_off < 0)
- {
- return FDT_RET_GET_EMPTY;
- }
- for (;;)
- {
- fdt_property = (struct fdt_property *)fdt_get_property_by_offset(current_fdt, property_off, &dtb_property->size);
- if (fdt_property != NULL)
- {
- dtb_property->name = fdt_string(current_fdt, fdt32_to_cpu(fdt_property->nameoff));
- dtb_property->value = fdt_property->data;
- dtb_property->size = fdt32_to_cpu(fdt_property->len);
- }
- property_off = fdt_next_property_offset(current_fdt, property_off);
- if (property_off >= 0)
- {
- dtb_property->next = (struct dtb_property *)malloc(sizeof(struct dtb_property));
- if (dtb_property->next == NULL)
- {
- return FDT_RET_NO_MEMORY;
- }
- dtb_property = dtb_property->next;
- }
- else
- {
- dtb_property->next = NULL;
- break;
- }
- }
- return FDT_RET_GET_OK;
- }
- static int _dtb_node_get_dtb_nodes_list(struct dtb_node *dtb_node_head, struct dtb_node *dtb_node, const char *pathname)
- {
- off_t root_off;
- off_t node_off;
- int pathname_sz;
- int node_name_sz;
- /* caller alrealy checked current_fdt */
- if ((root_off = fdt_path_offset(current_fdt, pathname)) >= 0)
- {
- pathname_sz = strlen(pathname);
- node_off = fdt_first_subnode(current_fdt, root_off);
- if (node_off < 0)
- {
- return FDT_RET_GET_EMPTY;
- }
- for (;;)
- {
- dtb_node->parent = dtb_node_head;
- dtb_node->sibling = NULL;
- dtb_node->name = fdt_get_name(current_fdt, node_off, &node_name_sz);
- /* parent_path + name + '/' + '\0' */
- if (paths_buf.cur + pathname_sz + node_name_sz + 2 < paths_buf.end)
- {
- dtb_node->path = (const char *)paths_buf.cur;
- strncpy(paths_buf.cur, pathname, pathname_sz);
- paths_buf.cur += pathname_sz;
- strncpy(paths_buf.cur, (char *)dtb_node->name, node_name_sz);
- paths_buf.cur += node_name_sz;
- *paths_buf.cur++ = '/';
- *paths_buf.cur++ = '\0';
- dtb_node->level = dtb_node_head->level + 1;
- }
- else
- {
- dtb_node->path = NULL;
- rt_kprintf("\033[31m\rERROR: `FDT_DTB_ALL_NODES_PATH_SIZE' = %d bytes is configured too low.\033[0m\n", FDT_DTB_ALL_NODES_PATH_SIZE);
- return FDT_RET_NO_MEMORY;
- }
- dtb_node->handle = fdt_get_phandle(current_fdt, node_off);
- dtb_node->properties = (struct dtb_property *)malloc(sizeof(struct dtb_property));
- dtb_node->child = (struct dtb_node *)malloc(sizeof(struct dtb_node));
- if (dtb_node->properties == NULL || dtb_node->child == NULL)
- {
- return FDT_RET_NO_MEMORY;
- }
- fdt_exec_status = _dtb_node_get_dtb_properties_list(dtb_node->properties, node_off);
- if (fdt_exec_status == FDT_RET_GET_EMPTY)
- {
- free(dtb_node->properties);
- dtb_node->properties = NULL;
- }
- else if (fdt_exec_status != FDT_RET_GET_OK)
- {
- return fdt_exec_status;
- }
- fdt_exec_status = _dtb_node_get_dtb_nodes_list(dtb_node, dtb_node->child, dtb_node->path);
- if (fdt_exec_status == FDT_RET_GET_EMPTY)
- {
- free(dtb_node->child);
- dtb_node->child = NULL;
- }
- else if (fdt_exec_status != FDT_RET_GET_OK)
- {
- return fdt_exec_status;
- }
- node_off = fdt_next_subnode(current_fdt, node_off);
- if (node_off >= 0)
- {
- dtb_node->sibling = (struct dtb_node *)malloc(sizeof(struct dtb_node));
- if (dtb_node->sibling == NULL)
- {
- return FDT_RET_NO_MEMORY;
- }
- dtb_node = dtb_node->sibling;
- dtb_node->level--;
- }
- else
- {
- break;
- }
- }
- }
- return FDT_RET_GET_OK;
- }
- struct dtb_node *dtb_node_get_dtb_list(void *fdt)
- {
- int root_off;
- struct dtb_node *dtb_node_head = NULL;
- if (fdt == NULL)
- {
- fdt_exec_status = FDT_RET_NO_LOADED;
- goto fail;
- }
- current_fdt = fdt;
- if ((dtb_node_head = (struct dtb_node *)malloc(sizeof(struct dtb_node))) == NULL)
- {
- fdt_exec_status = FDT_RET_NO_MEMORY;
- goto fail;
- }
- if (paths_buf.ptr == NULL)
- {
- paths_buf.ptr = (char *)malloc(FDT_DTB_ALL_NODES_PATH_SIZE);
- if (paths_buf.ptr == NULL)
- {
- fdt_exec_status = FDT_RET_NO_MEMORY;
- goto fail;
- }
- paths_buf.cur = (char *)paths_buf.ptr;
- paths_buf.end = (char *)(paths_buf.ptr + FDT_DTB_ALL_NODES_PATH_SIZE);
- }
- root_off = fdt_path_offset(fdt, "/");
- if ((dtb_node_head->header = (struct dtb_header *)malloc(sizeof(struct dtb_header))) == NULL)
- {
- fdt_exec_status = FDT_RET_NO_MEMORY;
- goto fail;
- }
- else
- {
- ((struct dtb_header *)dtb_node_head->header)->root = '/';
- ((struct dtb_header *)dtb_node_head->header)->zero = '\0';
- ((struct dtb_header *)dtb_node_head->header)->memreserve_sz = fdt_num_mem_rsv(fdt);
- if (dtb_node_head->header->memreserve_sz > 0)
- {
- int i;
- int memreserve_sz = dtb_node_head->header->memreserve_sz;
- uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(fdt);
- struct fdt_reserve_entry *rsvmap = (struct fdt_reserve_entry *)((char *)fdt + off_mem_rsvmap);
- ((struct dtb_header *)dtb_node_head->header)->memreserve = (struct dtb_memreserve *)malloc(sizeof(struct dtb_memreserve) * memreserve_sz);
- if (dtb_node_head->header->memreserve == NULL)
- {
- fdt_exec_status = FDT_RET_NO_MEMORY;
- goto fail;
- }
- for (i = 0; i < memreserve_sz; ++i)
- {
- ((struct dtb_header *)dtb_node_head->header)->memreserve[i].address = fdt64_to_cpu(rsvmap[i].address);
- ((struct dtb_header *)dtb_node_head->header)->memreserve[i].size = fdt64_to_cpu(rsvmap[i].size);
- }
- }
- else
- {
- ((struct dtb_header *)dtb_node_head->header)->memreserve = NULL;
- }
- }
- dtb_node_head->path = paths_buf.ptr;
- *paths_buf.cur++ = '/';
- *paths_buf.cur++ = '\0';
- dtb_node_head->parent = NULL;
- dtb_node_head->sibling = NULL;
- dtb_node_head->handle = fdt_get_phandle(fdt, root_off);
- dtb_node_head->properties = (struct dtb_property *)malloc(sizeof(struct dtb_property));
- dtb_node_head->child = (struct dtb_node *)malloc(sizeof(struct dtb_node));
- dtb_node_head->level = 0;
- if (dtb_node_head->properties == NULL || dtb_node_head->child == NULL)
- {
- fdt_exec_status = FDT_RET_NO_MEMORY;
- goto fail;
- }
- if ((fdt_exec_status = _dtb_node_get_dtb_properties_list(dtb_node_head->properties, root_off)) != FDT_RET_GET_OK)
- {
- goto fail;
- }
- if ((fdt_exec_status = _dtb_node_get_dtb_nodes_list(dtb_node_head, dtb_node_head->child, dtb_node_head->path)) != FDT_RET_GET_OK)
- {
- goto fail;
- }
- /* paths_buf.ptr addr save in the dtb_node_head's path */
- paths_buf.ptr = NULL;
- paths_buf.cur = NULL;
- return dtb_node_head;
- fail:
- if (dtb_node_head != NULL)
- {
- dtb_node_free_dtb_list(dtb_node_head);
- }
- return NULL;
- }
- static void _dtb_node_free_dtb_node(struct dtb_node *dtb_node)
- {
- struct dtb_node *dtb_node_last;
- struct dtb_property *dtb_property;
- struct dtb_property *dtb_property_last;
- while (dtb_node != NULL)
- {
- dtb_property = dtb_node->properties;
- while (dtb_property != NULL)
- {
- dtb_property_last = dtb_property;
- dtb_property = dtb_property->next;
- free(dtb_property_last);
- }
- _dtb_node_free_dtb_node(dtb_node->child);
- dtb_node_last = dtb_node;
- dtb_node = dtb_node->sibling;
- free(dtb_node_last);
- }
- }
- void dtb_node_free_dtb_list(struct dtb_node *dtb_node_head)
- {
- if (dtb_node_head == NULL)
- {
- return;
- }
- /* only root node can free all path buffer */
- if (dtb_node_head->parent == NULL || (dtb_node_head->path != NULL && !strcmp(dtb_node_head->path, "/")))
- {
- if (dtb_node_head->path != NULL)
- {
- free((void *)dtb_node_head->path);
- }
- if (dtb_node_head->header != NULL)
- {
- if (dtb_node_head->header->memreserve != NULL)
- {
- free((void *)dtb_node_head->header->memreserve);
- }
- free((void *)dtb_node_head->header);
- }
- }
- _dtb_node_free_dtb_node(dtb_node_head);
- }
- static void _dtb_node_printf_depth(int depth)
- {
- int i = depth;
- while (i --> 0)
- {
- rt_kputs("\t");
- }
- }
- rt_bool_t _dtb_node_test_string_list(const void *value, int size)
- {
- const char *str = value;
- const char *str_start, *str_end;
- if (size == 0)
- {
- return RT_FALSE;
- }
- /* string end with '\0' */
- if (str[size - 1] != '\0')
- {
- return RT_FALSE;
- }
- /* get string list end */
- str_end = str + size;
- while (str < str_end)
- {
- str_start = str;
- /* before string list end, not '\0' and a printable characters */
- while (str < str_end && *str && ((unsigned char)*str >= ' ' && (unsigned char)*str <= '~'))
- {
- ++str;
- }
- /* not zero, or not increased */
- if (*str != '\0' || str == str_start)
- {
- return RT_FALSE;
- }
- /* next string */
- ++str;
- }
- return RT_TRUE;
- }
- static void _dtb_node_printf_dtb_node_info(struct dtb_node *dtb_node)
- {
- static int depth = 0;
- struct dtb_property *dtb_property;
- while (dtb_node != NULL)
- {
- rt_kputs("\n");
- _dtb_node_printf_depth(depth);
- rt_kputs(dtb_node->name);
- rt_kputs(" {\n");
- ++depth;
- dtb_property = dtb_node->properties;
- while (dtb_property != NULL)
- {
- _dtb_node_printf_depth(depth);
- rt_kputs(dtb_property->name);
- if (dtb_property->size > 0)
- {
- int size = dtb_property->size;
- char *value = dtb_property->value;
- rt_kputs(" = ");
- if (_dtb_node_test_string_list(value, size) == RT_TRUE)
- {
- /* print string list */
- char *str = value;
- do
- {
- rt_kprintf("\"%s\"", str);
- str += strlen(str) + 1;
- rt_kputs(", ");
- } while (str < value + size);
- rt_kputs("\b\b");
- }
- else if ((size % 4) == 0)
- {
- /* print addr and size cell */
- int i;
- fdt32_t *cell = (fdt32_t *)value;
- rt_kputs("<");
- for (i = 0, size /= 4; i < size; ++i)
- {
- rt_kprintf("0x%x ", fdt32_to_cpu(cell[i]));
- }
- rt_kputs("\b>");
- }
- else
- {
- /* print bytes array */
- int i;
- uint8_t *byte = (uint8_t *)value;
- rt_kputs("[");
- for (i = 0; i < size; ++i)
- {
- rt_kprintf("%02x ", *byte++);
- }
- rt_kputs("\b]");
- }
- }
- rt_kputs(";\n");
- dtb_property = dtb_property->next;
- }
- _dtb_node_printf_dtb_node_info(dtb_node->child);
- dtb_node = dtb_node->sibling;
- --depth;
- _dtb_node_printf_depth(depth);
- rt_kputs("};\n");
- }
- }
- void dtb_node_get_dts_dump(struct dtb_node *dtb_node_head)
- {
- if (dtb_node_head != NULL)
- {
- int i = dtb_node_head->header->memreserve_sz;
- rt_kputs("/dts-v1/;\n");
- while (i --> 0)
- {
- rt_kprintf("\n/memreserve/\t0x%lx 0x%zx;", dtb_node_head->header->memreserve[i].address, dtb_node_head->header->memreserve[i].size);
- }
- _dtb_node_printf_dtb_node_info(dtb_node_head);
- }
- }
- static void _dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node, void (callback(struct dtb_node *dtb_node)))
- {
- while (dtb_node != NULL)
- {
- callback(dtb_node);
- _dtb_node_get_enum_dtb_node(dtb_node->child, callback);
- dtb_node = dtb_node->sibling;
- }
- }
- void dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node_head, void (callback(struct dtb_node *dtb_node)))
- {
- if (dtb_node_head == NULL || callback == NULL)
- {
- return;
- }
- _dtb_node_get_enum_dtb_node(dtb_node_head, callback);
- }
- struct dtb_node *dtb_node_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename)
- {
- struct dtb_node *dtb_node_child;
- while (dtb_node != NULL)
- {
- if (!strcmp(nodename, dtb_node->name))
- {
- return dtb_node;
- }
- dtb_node_child = dtb_node_get_dtb_node_by_name_DFS(dtb_node->child, nodename);
- if (dtb_node_child != NULL)
- {
- return dtb_node_child;
- }
- dtb_node = dtb_node->sibling;
- }
- return NULL;
- }
- struct dtb_node *dtb_node_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename)
- {
- if (dtb_node != NULL)
- {
- struct dtb_node *dtb_node_child, *dtb_node_head = dtb_node;
- while (dtb_node != NULL)
- {
- if (!strcmp(nodename, dtb_node->name))
- {
- return dtb_node;
- }
- dtb_node = dtb_node->sibling;
- }
- dtb_node = dtb_node_head;
- while (dtb_node != NULL)
- {
- dtb_node_child = dtb_node_get_dtb_node_by_name_BFS(dtb_node->child, nodename);
- if (dtb_node_child != NULL)
- {
- return dtb_node_child;
- }
- dtb_node = dtb_node->sibling;
- }
- }
- return NULL;
- }
- struct dtb_node *dtb_node_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname)
- {
- int i = 0;
- char *node_name;
- char *pathname_clone;
- int pathname_sz;
- if (pathname == NULL || dtb_node == NULL)
- {
- return NULL;
- }
- /* skip '/' */
- if (*pathname == '/')
- {
- ++pathname;
- }
- /* root not have sibling, so skip */
- if (dtb_node->parent == NULL || !strcmp(dtb_node->path, "/"))
- {
- dtb_node = dtb_node->child;
- }
- pathname_sz = strlen(pathname) + 1;
- pathname_clone = (char *)malloc(pathname_sz);
- if (pathname_clone == NULL)
- {
- return NULL;
- }
- strncpy(pathname_clone, pathname, pathname_sz);
- node_name = pathname_clone;
- while (pathname_clone[i])
- {
- if (pathname_clone[i] == '/')
- {
- /* set an end of name that can used to strcmp */
- pathname_clone[i] = '\0';
- while (dtb_node != NULL)
- {
- if (!strcmp(dtb_node->name, node_name))
- {
- break;
- }
- dtb_node = dtb_node->sibling;
- }
- if (dtb_node == NULL)
- {
- free(pathname_clone);
- return NULL;
- }
- dtb_node = dtb_node->child;
- node_name = &pathname_clone[i + 1];
- }
- ++i;
- }
- /*
- * found the end node and it's name:
- * (pathname[pathname_sz - 1]) is '\0'
- * (&pathname_clone[i] - node_name) is the node_name's length
- */
- node_name = &((char *)pathname)[(pathname_sz - 1) - (&pathname_clone[i] - node_name)];
- free(pathname_clone);
- while (dtb_node != NULL)
- {
- if (!strcmp(dtb_node->name, node_name))
- {
- return dtb_node;
- }
- dtb_node = dtb_node->sibling;
- }
- return NULL;
- }
- struct dtb_node *dtb_node_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle)
- {
- struct dtb_node *dtb_node_child;
- while (dtb_node != NULL)
- {
- if (dtb_node->handle == handle)
- {
- return dtb_node;
- }
- dtb_node_child = dtb_node_get_dtb_node_by_phandle_DFS(dtb_node->child, handle);
- if (dtb_node_child != NULL)
- {
- return dtb_node_child;
- }
- dtb_node = dtb_node->sibling;
- }
- return NULL;
- }
- struct dtb_node *dtb_node_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle)
- {
- if (dtb_node != NULL)
- {
- struct dtb_node *dtb_node_child, *dtb_node_head = dtb_node;
- while (dtb_node != NULL)
- {
- if (dtb_node->handle == handle)
- {
- return dtb_node;
- }
- dtb_node = dtb_node->sibling;
- }
- dtb_node = dtb_node_head;
- while (dtb_node != NULL)
- {
- dtb_node_child = dtb_node_get_dtb_node_by_phandle_BFS(dtb_node->child, handle);
- if (dtb_node_child != NULL)
- {
- return dtb_node_child;
- }
- dtb_node = dtb_node->sibling;
- }
- }
- return NULL;
- }
- void dtb_node_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells)
- {
- if (dtb_node != NULL && addr_cells != NULL && size_cells != NULL)
- {
- struct dtb_property *dtb_property;
- *addr_cells = -1;
- *size_cells = -1;
- /* if couldn't found, check parent */
- while ((dtb_node = dtb_node->parent) != NULL)
- {
- dtb_property = dtb_node->properties;
- while (dtb_property != NULL)
- {
- if (!strcmp(dtb_property->name, "#address-cells"))
- {
- *addr_cells = fdt32_to_cpu(*(int *)dtb_property->value);
- }
- else if (!strcmp(dtb_property->name, "#size-cells"))
- {
- *size_cells = fdt32_to_cpu(*(int *)dtb_property->value);
- }
- if (*addr_cells != -1 && *size_cells != -1)
- {
- return;
- }
- dtb_property = dtb_property->next;
- }
- }
- if (*addr_cells == -1)
- {
- *addr_cells = FDT_ROOT_ADDR_CELLS_DEFAULT;
- }
- if (*size_cells == -1)
- {
- *size_cells = FDT_ROOT_SIZE_CELLS_DEFAULT;
- }
- }
- }
- struct dtb_memreserve *dtb_node_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size)
- {
- if (dtb_node != NULL && memreserve_size != NULL)
- {
- struct dtb_node *dtb_node_root = dtb_node;
- while (dtb_node_root != NULL)
- {
- if (!strcmp(dtb_node_root->path, "/"))
- {
- break;
- }
- dtb_node_root = dtb_node_root->parent;
- }
- if(dtb_node_root == NULL) return NULL;
- *memreserve_size = dtb_node_root->header->memreserve_sz;
- return dtb_node_root->header->memreserve;
- }
- return NULL;
- }
- rt_bool_t dtb_node_get_dtb_node_status(const struct dtb_node *dtb_node)
- {
- if (dtb_node != NULL)
- {
- char *status = dtb_node_get_dtb_node_property_value(dtb_node, "status", NULL);
- if (status != NULL)
- {
- return (!strcmp(status, "okay") || !strcmp(status, "ok")) ? RT_TRUE : RT_FALSE;
- }
- return RT_TRUE;
- }
- return RT_FALSE;
- }
- rt_bool_t dtb_node_get_dtb_node_compatible_match(const struct dtb_node *dtb_node, const char *compatibles)
- {
- if (dtb_node != NULL)
- {
- if (compatibles != NULL)
- {
- char *str_ptr;
- int prop_sz;
- for_each_property_string(dtb_node, "compatible", str_ptr, prop_sz)
- {
- if (!strcmp(compatibles, str_ptr))
- {
- return RT_TRUE;
- }
- }
- }
- }
- return RT_FALSE;
- }
- char *dtb_node_get_dtb_string_list_value(void *value, int size, int index)
- {
- int i = 0;
- char *str = value;
- if (str != NULL)
- {
- do
- {
- if (i++ == index)
- {
- return str;
- }
- str += strlen(str) + 1;
- } while (str < (char *)value + size);
- }
- return NULL;
- }
- char *dtb_node_get_dtb_string_list_value_next(void *value, void *end)
- {
- char *str = value;
- if (str != NULL)
- {
- str += strlen(str) + 1;
- if (str < (char *)end)
- {
- return str;
- }
- }
- return NULL;
- }
- uint32_t dtb_node_get_dtb_cell_value(void *value)
- {
- return fdt32_to_cpu(*(fdt32_t *)value);
- }
- uint8_t dtb_node_get_dtb_byte_value(void *value)
- {
- return *(uint8_t *)value;
- }
|