From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from wes1-so2.wedos.net (wes1-so2.wedos.net [46.28.106.16]) by dpdk.org (Postfix) with ESMTP id AA43B5A31 for ; Sat, 26 Mar 2016 02:12:34 +0100 (CET) Received: from pcviktorin.fit.vutbr.cz (pcviktorin.fit.vutbr.cz [147.229.13.147]) by wes1-so2.wedos.net (Postfix) with ESMTPSA id 3qX2GB2VLJzqF; Sat, 26 Mar 2016 02:12:34 +0100 (CET) From: Jan Viktorin To: dev@dpdk.org Cc: Thomas Monjalon , Stephen Hemminger , Keith Wiles , david.marchand@6wind.com, jianbo.liu@linaro.org, jerin.jacob@caviumnetworks.com, bruce.richardson@intel.com, Jan Viktorin Date: Sat, 26 Mar 2016 02:12:34 +0100 Message-Id: <1458954760-2333-3-git-send-email-viktorin@rehivetech.com> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1458954760-2333-1-git-send-email-viktorin@rehivetech.com> References: <1458954760-2333-1-git-send-email-viktorin@rehivetech.com> Subject: [dpdk-dev] [RFC 2/6] eal/fdt: implement FDT API for Linux X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 26 Mar 2016 01:12:35 -0000 The Linux FDT API implementation reads the /proc/device-tree structure. Each FDT entry is represented by a file or directory there. Signed-off-by: Jan Viktorin --- lib/librte_eal/common/eal_common_fdt.c | 317 +++++++++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/Makefile | 3 + lib/librte_eal/linuxapp/eal/eal_fdt.c | 336 +++++++++++++++++++++++++++++++++ 3 files changed, 656 insertions(+) create mode 100644 lib/librte_eal/common/eal_common_fdt.c create mode 100644 lib/librte_eal/linuxapp/eal/eal_fdt.c diff --git a/lib/librte_eal/common/eal_common_fdt.c b/lib/librte_eal/common/eal_common_fdt.c new file mode 100644 index 0000000..29d08c1 --- /dev/null +++ b/lib/librte_eal/common/eal_common_fdt.c @@ -0,0 +1,317 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 RehiveTech. All rights reserved. + * All rights reserved. + * + * Redistribution and use 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 RehiveTech nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + */ + +#include +#include +#include + +#include +#include + +bool rte_fdt_path_is_valid(const char *name) +{ + size_t i; + size_t len = 0; + + if (name == NULL) + return 0; + + len = strlen(name); + if (len == 0) + return 0; + + if (!strcmp(name, ".")) + return 0; + if (!strcmp(name, "..")) + return 0; + + for (i = 0; i < len; ++i) { + if (strchr("/\\", name[i])) + return 0; + } + + return 1; +} + +struct rte_fdt_path *rte_fdt_path_pushs(struct rte_fdt_path *base, + const char *top) +{ + struct rte_fdt_path *path; + size_t toplen; + + RTE_VERIFY(top != NULL); + RTE_VERIFY(rte_fdt_path_is_valid(top)); + + toplen = strlen(top); + + path = malloc(sizeof(*path) + toplen + 1); + if (path == NULL) + return NULL; + + path->name = (char *) (path + 1); + memcpy(path->name, top, toplen); + path->name[toplen] = '\0'; + + path->base = base; + if (base != NULL) + base->top = path; + + path->top = NULL; + return path; +} + +struct rte_fdt_path *rte_fdt_path_pop(struct rte_fdt_path *path) +{ + struct rte_fdt_path *base; + RTE_VERIFY(path != NULL); + + base = path->base; + free(path); + + if (base != NULL) + base->top = NULL; + + return base; +} + +struct rte_fdt_path *rte_fdt_path_dup(const struct rte_fdt_path *path) +{ + struct rte_fdt_path *copy = NULL; + struct rte_fdt_path *tmp = NULL; + const struct rte_fdt_path *cur = path; + + if (cur == NULL) + return NULL; + + while (cur->base != NULL) + cur = cur->base; + + /* copy all but the top most path component */ + while (cur != path) { + tmp = rte_fdt_path_pushs(copy, cur->name); + if (tmp == NULL) { + rte_fdt_path_free(copy); + return NULL; + } + + copy = tmp; + cur = cur->top; + } + + /* copy the top most path component */ + tmp = rte_fdt_path_pushs(copy, path->name); + if (tmp == NULL) { + rte_fdt_path_free(copy); + return NULL; + } + + copy = tmp; + return copy; +} + +struct rte_fdt_path *rte_fdt_path_free(struct rte_fdt_path *path) +{ + while (path != NULL) + path = rte_fdt_path_pop(path); + + return NULL; +} + +int rte_fdt_path_parse(struct rte_fdt_path **p, const char *path) +{ + const char *cur; + const char *end; + size_t pathlen; + struct rte_fdt_path *base = NULL; + struct rte_fdt_path *tmp = NULL; + char name[PATH_MAX]; + + if (path == NULL) { + errno = EINVAL; + return -1; + } + + pathlen = strlen(path); + if (pathlen == 0) { + errno = EINVAL; + return -2; + } + + cur = path; + + if (cur[0] != '/') { + errno = EINVAL; + return -3; + } + + /* root "/" */ + if (cur[1] == '\0') { + *p = NULL; + return 0; + } + cur += 1; + + do { + end = strchr(cur, '/'); + if (end == NULL) + end = path + pathlen; + + if (end - cur == 0) + break; /* strip the ending '/' */ + + RTE_VERIFY(end >= cur); + RTE_VERIFY(end - cur < PATH_MAX); + memcpy(name, cur, end - cur); + name[end - cur] = '\0'; + + if (!strcmp(name, ".")) + goto next_cur; + + if (!strcmp(name, "..")) { + if (base) + base = rte_fdt_path_pop(base); + goto next_cur; + } + + if (!rte_fdt_path_is_valid(name)) + goto name_invalid; + + tmp = rte_fdt_path_pushs(base, name); + if (tmp == NULL) + goto push_failed; + + base = tmp; +next_cur: + if (*end == '\0') + break; + + cur = end + 1; + } while(end != '\0'); + + *p = base; + return 0; + +name_invalid: + errno = EINVAL; + return -4; +push_failed: + rte_fdt_path_free(base); + return -5; +} + +/** + * Compute the length of the base using the delimiter '/'. An optional new top + * can be specified. If the top is NULL, only the base is examined. The NUL + * character is included. + */ +static size_t fdt_path_length(const struct rte_fdt_path *base, const char *top) +{ + size_t len = 0; + + if (base == NULL && top == NULL) + return strlen("/") + 1; + + while (base != NULL) { + RTE_VERIFY(base->name != NULL); + /* '/' + */ + len += 1 + strlen(base->name); + base = base->base; + } + + if (top != NULL) { + /* '/' + */ + len += 1 + strlen(top); + } + + return len + 1; /* append NUL */ +} + +char *rte_fdt_path_tostr(const struct rte_fdt_path *base, const char *top) +{ + const size_t len = fdt_path_length(base, top); + const struct rte_fdt_path *cur = base; + char *s; + char *p; + + if (base == NULL && top == NULL) + return strdup("/"); + + s = malloc(len); + if (s == NULL) + return NULL; + + if (base == NULL /* && top != NULL */) { + memcpy(s + 1, top, len - 2); + s[0] = '/'; + s[len] = '\0'; + return s; + } + + /* find the bottom, the root component of the path */ + while (cur->base != NULL) + cur = cur->base; + + p = s; + + /* copy the base from the bottom into the target string */ + while (cur != NULL) { + size_t curlen = strlen(cur->name); + + RTE_VERIFY(p - s + curlen + 1 < len); + + p[0] = '/'; + memcpy(p + 1, cur->name, curlen); + p += curlen + 1; + + if (cur == base) + break; + + cur = cur->top; + } + + /* append top if exists */ + if (top != NULL) { + size_t toplen = strlen(top); + + RTE_VERIFY(p - s + toplen + 1 < len); + + p[0] = '/'; + memcpy(p + 1, top, toplen); + p += toplen + 1; + } + + RTE_VERIFY(p - s + 1 == (off_t) len); + p[0] = '\0'; + + return s; +} diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile index e109361..e4b33b5 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -61,6 +61,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_memory.c ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y) SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_xen_memory.c endif +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_fdt.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_thread.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_log.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_pci.c @@ -82,6 +83,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_timer.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memzone.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_log.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_launch.c +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_fdt.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_pci.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_pci_uio.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memory.c @@ -113,6 +115,7 @@ CFLAGS_eal_lcore.o := -D_GNU_SOURCE CFLAGS_eal_thread.o := -D_GNU_SOURCE CFLAGS_eal_log.o := -D_GNU_SOURCE CFLAGS_eal_common_log.o := -D_GNU_SOURCE +CFLAGS_eal_fdt.o := -D_GNU_SOURCE CFLAGS_eal_hugepage_info.o := -D_GNU_SOURCE CFLAGS_eal_pci.o := -D_GNU_SOURCE CFLAGS_eal_pci_uio.o := -D_GNU_SOURCE diff --git a/lib/librte_eal/linuxapp/eal/eal_fdt.c b/lib/librte_eal/linuxapp/eal/eal_fdt.c new file mode 100644 index 0000000..48c6b52 --- /dev/null +++ b/lib/librte_eal/linuxapp/eal/eal_fdt.c @@ -0,0 +1,336 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 RehiveTech. All rights reserved. + * All rights reserved. + * + * Redistribution and use 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 RehiveTech nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct rte_fdt { + char *path; +}; + +struct rte_fdt *rte_fdt_open(const char *path) +{ + struct rte_fdt *fdt; + size_t pathlen; + + if (path == NULL) { + path = "/proc/device-tree"; + pathlen = strlen("/proc/device-tree"); + } else { + pathlen = strlen(path); + } + + fdt = malloc(sizeof(*fdt) + pathlen + 1); + if (fdt == NULL) + return NULL; + + fdt->path = (char *) (fdt + 1); + memcpy(fdt->path, path, pathlen); + fdt->path[pathlen] = '\0'; + + return fdt; +} + +void rte_fdt_close(struct rte_fdt *fdt) +{ + RTE_VERIFY(fdt != NULL); + + fdt->path = NULL; + free(fdt); +} + +static int concat_and_abspath(char path[PATH_MAX], + const char *p1, size_t p1len, + const char *p2, size_t p2len) +{ + char *tmppath; + + tmppath = malloc(p1len + 1 + p2len + 1); + if (tmppath == NULL) { + RTE_LOG(ERR, EAL, "%s(): failed to malloc %zu B\n", __func__, + p1len + 1 + p2len + 1); + return -1; + } + + memcpy(tmppath, p1, p1len); + tmppath[p1len] = '/'; + memcpy(tmppath + p1len + 1, p2, p2len); + tmppath[p1len + p2len + 1] = '\0'; + + if (realpath(tmppath, path) == NULL) { + long _e = errno; + RTE_LOG(ERR, EAL, "%s(): realpath has failed for '%s'\n", + __func__, tmppath); + RTE_LOG(ERR, EAL, "reason: '%s'\n", strerror(_e)); + free(tmppath); + return -2; + } + + free(tmppath); + return 0; +} + +static int fdt_path_open(struct rte_fdt *fdt, const struct rte_fdt_path *base, + const char *top) +{ + char *relpath = rte_fdt_path_tostr(base, top); + char path[PATH_MAX]; + char root[PATH_MAX]; + int fd; + + RTE_VERIFY(fdt != NULL); + RTE_VERIFY(relpath[0] == '/'); + + if (relpath == NULL) { + RTE_LOG(ERR, EAL, "%s(): failed to convert " + "base path to string\n", __func__); + errno = ENOMEM; + return -1; + } + + if (concat_and_abspath(path, fdt->path, strlen(fdt->path), + relpath + 1, strlen(relpath + 1))) { + RTE_LOG(ERR, EAL, "%s(): failed to derive absolute path from " + "the root ('%s') and the FDT path ('%s')\n", + __func__, fdt->path, relpath); + free(relpath); + errno = ENOMEM; + return -2; + } + free(relpath); /* not needed anymore */ + + /* ensure we have the fdt->path as a real and absolute path */ + if (realpath(fdt->path, root) == NULL) { + long _e = errno; + RTE_LOG(ERR, EAL, "%s(): realpath of '%s' has failed", + __func__, fdt->path); + errno = _e; + return -3; + } + + if (strstr(path, root) != path) { + /* We are out of the fdt->path */ + RTE_LOG(ERR, EAL, "%s(): attempt to access out " + "of the root path: '%s'\n", __func__, path); + errno = EACCES; + return -4; + } + + if ((fd = open(path, O_RDONLY)) < 0) { + RTE_LOG(ERR, EAL, "%s(): failed to open the FDT path '%s'\n", + __func__, path); + return -5; + } + + return fd; +} + +static ssize_t read_all(int fd, char *b, size_t bmax) +{ + size_t total = 0; + + while (total < bmax) { + ssize_t rlen = read(fd, b + total, bmax - total); + if (rlen < 0) + return -1; + + total += rlen; + } + + return total; +} + +static ssize_t fdt_path_read(struct rte_fdt *fdt, + const struct rte_fdt_path *base, const char *top, + void *b, size_t bmax) +{ + int fd; + struct stat st; + size_t goal; + ssize_t ret; + + if ((fd = fdt_path_open(fdt, base, top)) < 0) + return -1; + + if (fstat(fd, &st) < 0) { + close(fd); + return -2; + } + + goal = st.st_size; + ret = read_all(fd, b, bmax > goal? goal : bmax); + + close(fd); + return ret; +} + +static ssize_t fdt_path_readx(struct rte_fdt *fdt, + const struct rte_fdt_path *base, const char *top, + void *v, size_t vmax, size_t vsize) +{ + size_t bmax = vmax * vsize; + ssize_t ret; + + ret = fdt_path_read(fdt, base, top, v, bmax); + if (ret < 0) + return -1; + + return ret / vsize; +} + +ssize_t rte_fdt_path_read(struct rte_fdt *fdt, + const struct rte_fdt_path *base, + const char *top, char *b, size_t blen) +{ + return fdt_path_read(fdt, base, top, b, blen); +} + +ssize_t rte_fdt_path_read32(struct rte_fdt *fdt, + const struct rte_fdt_path *base, const char *top, + uint32_t *v, size_t vmax) +{ + ssize_t ret; + ssize_t i; + + ret = fdt_path_readx(fdt, base, top, (void *) v, vmax, sizeof(*v)); + if (ret <= 0) + return ret; + + for (i = 0; i < ret; ++i) + v[i] = rte_be_to_cpu_32(v[i]); + + return ret; +} + +ssize_t rte_fdt_path_read64(struct rte_fdt *fdt, + const struct rte_fdt_path *base, const char *top, + uint64_t *v, size_t vmax) +{ + ssize_t ret; + ssize_t i; + + ret = fdt_path_readx(fdt, base, top, (void *) v, vmax, sizeof(*v)); + if (ret <= 0) + return ret; + + for (i = 0; i < ret; ++i) + v[i] = rte_be_to_cpu_64(v[i]); + + return ret; + +} + +ssize_t rte_fdt_path_reads(struct rte_fdt *fdt, + const struct rte_fdt_path *base, + const char *top, char **s) +{ + int fd; + struct stat st; + size_t goal; + ssize_t ret; + char *b; + + if ((fd = fdt_path_open(fdt, base, top)) < 0) + return -1; + + if (fstat(fd, &st) < 0) { + close(fd); + return -2; + } + + goal = st.st_size; + + b = malloc(goal + 1); + if (b == NULL) { + close(fd); + return -3; + } + + + if ((ret = read_all(fd, b, goal)) < 0) { + free(b); + close(fd); + return -4; + } + + b[goal] = '\0'; + + close(fd); + *s = b; + return ret; +} + +int rte_fdt_path_walk(struct rte_fdt *fdt, const struct rte_fdt_path *base, + int (*f)(struct rte_fdt *, const struct rte_fdt_path *, + const char *, void *), void *context) +{ + int fd; + DIR *dir; + struct dirent entry; + struct dirent *cur = NULL; + int ret = 0; + + RTE_VERIFY(f != NULL); + + if ((fd = fdt_path_open(fdt, base, NULL)) < 0) + return -1; + + dir = fdopendir(fd); + if (dir == NULL) { + close(fd); + return -2; + } + + while ((readdir_r(dir, &entry, &cur)) == 0 && cur != NULL) { + if (!rte_fdt_path_is_valid(cur->d_name)) + continue; + + ret = f(fdt, base, cur->d_name, context); + if (ret != 0) + break; + } + + closedir(dir); /* calls close() */ + return ret; +} -- 2.7.0