This series of patches makes Xen pass a (somewhat) valid device tree to dom0. The device tree for dom0 is the same as the one supplied to Xen except the memory and chosen nodes are adjusted appropriately. We don''t yet make use of the device tree to map MMIO regions or setup interrupts for the guest and we still include the UART used for Xen''s console. Note that loading Linux using a vmlinux file is no longer supported and the kernel must support device tree (ATAGS are no longer provided by Xen). It is also possible to provide the Xen and dom0 command line via the device tree. This isn''t as useful as it seems as Xen still needs to be rebuilt to included the updated device tree. The instructions on the wiki[1] have been updated to reflect these changes. Changes since v1: - coding style - move libfdt headers - added myself as device tree maintainer - fix potential infinite loop when assigning mem - check dtb destination more carefully - minor updates for clarity David [1] http://wiki.xen.org/wiki/Xen_ARMv7_with_Virtualization_Extensions
David Vrabel
2012-Mar-19 17:51 UTC
[PATCH 01/11] libfdt: move headers to xen/include/xen/libfdt/
From: David Vrabel <david.vrabel@citrix.com> Move the public libfdt headers to xen/include/xen/libfdt/ so CFLAGS does need to be set to find them. This requires minor tweaks to one of the headers imported from upstream. Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- xen/common/Makefile | 2 - xen/common/device_tree.c | 3 +- xen/common/libfdt/Makefile | 2 +- xen/common/libfdt/fdt.h | 60 -- xen/common/libfdt/libfdt.h | 1235 ----------------------------------- xen/common/libfdt/libfdt_env.h | 16 - xen/include/xen/libfdt/fdt.h | 60 ++ xen/include/xen/libfdt/libfdt.h | 1235 +++++++++++++++++++++++++++++++++++ xen/include/xen/libfdt/libfdt_env.h | 16 + 9 files changed, 1313 insertions(+), 1316 deletions(-) delete mode 100644 xen/common/libfdt/fdt.h delete mode 100644 xen/common/libfdt/libfdt.h delete mode 100644 xen/common/libfdt/libfdt_env.h create mode 100644 xen/include/xen/libfdt/fdt.h create mode 100644 xen/include/xen/libfdt/libfdt.h create mode 100644 xen/include/xen/libfdt/libfdt_env.h diff --git a/xen/common/Makefile b/xen/common/Makefile index 372b259..9f2e0d6 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -61,5 +61,3 @@ subdir-$(ia64) += hvm subdir-y += libelf subdir-$(HAS_DEVICE_TREE) += libfdt - -CFLAGS += -Ilibfdt diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index d50cb9c..140d342 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -14,13 +14,12 @@ #include <xen/device_tree.h> #include <xen/kernel.h> #include <xen/lib.h> +#include <xen/libfdt/libfdt.h> #include <xen/mm.h> #include <xen/stdarg.h> #include <xen/string.h> #include <asm/early_printk.h> -#include <libfdt.h> - struct dt_early_info __initdata early_info; void *device_tree_flattened; diff --git a/xen/common/libfdt/Makefile b/xen/common/libfdt/Makefile index 0e65bc0..7578fe9 100644 --- a/xen/common/libfdt/Makefile +++ b/xen/common/libfdt/Makefile @@ -2,4 +2,4 @@ include Makefile.libfdt obj-y += $(LIBFDT_OBJS) -CFLAGS += -I. +CFLAGS += -I$(BASEDIR)/include/xen/libfdt/ diff --git a/xen/common/libfdt/fdt.h b/xen/common/libfdt/fdt.h deleted file mode 100644 index 48ccfd9..0000000 --- a/xen/common/libfdt/fdt.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _FDT_H -#define _FDT_H - -#ifndef __ASSEMBLY__ - -struct fdt_header { - uint32_t magic; /* magic word FDT_MAGIC */ - uint32_t totalsize; /* total size of DT block */ - uint32_t off_dt_struct; /* offset to structure */ - uint32_t off_dt_strings; /* offset to strings */ - uint32_t off_mem_rsvmap; /* offset to memory reserve map */ - uint32_t version; /* format version */ - uint32_t last_comp_version; /* last compatible version */ - - /* version 2 fields below */ - uint32_t boot_cpuid_phys; /* Which physical CPU id we''re - booting on */ - /* version 3 fields below */ - uint32_t size_dt_strings; /* size of the strings block */ - - /* version 17 fields below */ - uint32_t size_dt_struct; /* size of the structure block */ -}; - -struct fdt_reserve_entry { - uint64_t address; - uint64_t size; -}; - -struct fdt_node_header { - uint32_t tag; - char name[0]; -}; - -struct fdt_property { - uint32_t tag; - uint32_t len; - uint32_t nameoff; - char data[0]; -}; - -#endif /* !__ASSEMBLY */ - -#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ -#define FDT_TAGSIZE sizeof(uint32_t) - -#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ -#define FDT_END_NODE 0x2 /* End node */ -#define FDT_PROP 0x3 /* Property: name off, - size, content */ -#define FDT_NOP 0x4 /* nop */ -#define FDT_END 0x9 - -#define FDT_V1_SIZE (7*sizeof(uint32_t)) -#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) -#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) -#define FDT_V16_SIZE FDT_V3_SIZE -#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) - -#endif /* _FDT_H */ diff --git a/xen/common/libfdt/libfdt.h b/xen/common/libfdt/libfdt.h deleted file mode 100644 index 55f3eb3..0000000 --- a/xen/common/libfdt/libfdt.h +++ /dev/null @@ -1,1235 +0,0 @@ -#ifndef _LIBFDT_H -#define _LIBFDT_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * 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 <libfdt_env.h> -#include <fdt.h> - -#define FDT_FIRST_SUPPORTED_VERSION 0x10 -#define FDT_LAST_SUPPORTED_VERSION 0x11 - -/* Error codes: informative error codes */ -#define FDT_ERR_NOTFOUND 1 - /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ -#define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attemped to create a node or property which - * already exists */ -#define FDT_ERR_NOSPACE 3 - /* FDT_ERR_NOSPACE: Operation needed to expand the device - * tree, but its buffer did not have sufficient space to - * contain the expanded tree. Use fdt_open_into() to move the - * device tree to a buffer with more space. */ - -/* Error codes: codes for bad parameters */ -#define FDT_ERR_BADOFFSET 4 - /* FDT_ERR_BADOFFSET: Function was passed a structure block - * offset which is out-of-bounds, or which points to an - * unsuitable part of the structure for the operation. */ -#define FDT_ERR_BADPATH 5 - /* FDT_ERR_BADPATH: Function was passed a badly formatted path - * (e.g. missing a leading / for a function which requires an - * absolute path) */ -#define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle - * value. phandle values of 0 and -1 are not permitted. */ -#define FDT_ERR_BADSTATE 7 - /* FDT_ERR_BADSTATE: Function was passed an incomplete device - * tree created by the sequential-write functions, which is - * not sufficiently complete for the requested operation. */ - -/* Error codes: codes for bad device tree blobs */ -#define FDT_ERR_TRUNCATED 8 - /* FDT_ERR_TRUNCATED: Structure block of the given device tree - * ends without an FDT_END tag. */ -#define FDT_ERR_BADMAGIC 9 - /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a - * device tree at all - it is missing the flattened device - * tree magic number. */ -#define FDT_ERR_BADVERSION 10 - /* FDT_ERR_BADVERSION: Given device tree has a version which - * can''t be handled by the requested operation. For - * read-write functions, this may mean that fdt_open_into() is - * required to convert the tree to the expected version. */ -#define FDT_ERR_BADSTRUCTURE 11 - /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt - * structure block or other serious error (e.g. misnested - * nodes, or subnodes preceding properties). */ -#define FDT_ERR_BADLAYOUT 12 - /* FDT_ERR_BADLAYOUT: For read-write functions, the given - * device tree has it''s sub-blocks in an order that the - * function can''t handle (memory reserve map, then structure, - * then strings). Use fdt_open_into() to reorganize the tree - * into a form suitable for the read-write operations. */ - -/* "Can''t happen" error indicating a bug in libfdt */ -#define FDT_ERR_INTERNAL 13 - /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. - * Should never be returned, if it is, it indicates a bug in - * libfdt itself. */ - -#define FDT_ERR_MAX 13 - -/**********************************************************************/ -/* Low-level functions (you probably don''t need these) */ -/**********************************************************************/ - -const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); -static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) -{ - return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); -} - -uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); - -/**********************************************************************/ -/* Traversal functions */ -/**********************************************************************/ - -int fdt_next_node(const void *fdt, int offset, int *depth); - -/**********************************************************************/ -/* General functions */ -/**********************************************************************/ - -#define fdt_get_header(fdt, field) \ - (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) -#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) -#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) -#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) -#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) -#define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) -#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) - -#define __fdt_set_hdr(name) \ - static inline void fdt_set_##name(void *fdt, uint32_t val) \ - { \ - struct fdt_header *fdth = (struct fdt_header*)fdt; \ - fdth->name = cpu_to_fdt32(val); \ - } -__fdt_set_hdr(magic); -__fdt_set_hdr(totalsize); -__fdt_set_hdr(off_dt_struct); -__fdt_set_hdr(off_dt_strings); -__fdt_set_hdr(off_mem_rsvmap); -__fdt_set_hdr(version); -__fdt_set_hdr(last_comp_version); -__fdt_set_hdr(boot_cpuid_phys); -__fdt_set_hdr(size_dt_strings); -__fdt_set_hdr(size_dt_struct); -#undef __fdt_set_hdr - -/** - * fdt_check_header - sanity check a device tree or possible device tree - * @fdt: pointer to data which might be a flattened device tree - * - * fdt_check_header() checks that the given buffer contains what - * appears to be a flattened device tree with sane information in its - * header. - * - * returns: - * 0, if the buffer appears to contain a valid device tree - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings, as above - */ -int fdt_check_header(const void *fdt); - -/** - * fdt_move - move a device tree around in memory - * @fdt: pointer to the device tree to move - * @buf: pointer to memory where the device is to be moved - * @bufsize: size of the memory space at buf - * - * fdt_move() relocates, if possible, the device tree blob located at - * fdt to the buffer at buf of size bufsize. The buffer may overlap - * with the existing device tree blob at fdt. Therefore, - * fdt_move(fdt, fdt, fdt_totalsize(fdt)) - * should always succeed. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_move(const void *fdt, void *buf, int bufsize); - -/**********************************************************************/ -/* Read-only functions */ -/**********************************************************************/ - -/** - * fdt_string - retrieve a string from the strings block of a device tree - * @fdt: pointer to the device tree blob - * @stroffset: offset of the string within the strings block (native endian) - * - * fdt_string() retrieves a pointer to a single string from the - * strings block of the device tree blob at fdt. - * - * returns: - * a pointer to the string, on success - * NULL, if stroffset is out of bounds - */ -const char *fdt_string(const void *fdt, int stroffset); - -/** - * fdt_num_mem_rsv - retrieve the number of memory reserve map entries - * @fdt: pointer to the device tree blob - * - * Returns the number of entries in the device tree blob''s memory - * reservation map. This does not include the terminating 0,0 entry - * or any other (0,0) entries reserved for expansion. - * - * returns: - * the number of entries - */ -int fdt_num_mem_rsv(const void *fdt); - -/** - * fdt_get_mem_rsv - retrieve one memory reserve map entry - * @fdt: pointer to the device tree blob - * @address, @size: pointers to 64-bit variables - * - * On success, *address and *size will contain the address and size of - * the n-th reserve map entry from the device tree blob, in - * native-endian format. - * - * returns: - * 0, on success - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); - -/** - * fdt_subnode_offset_namelen - find a subnode based on substring - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * @namelen: number of characters of name to consider - * - * Identical to fdt_subnode_offset(), but only examine the first - * namelen characters of name for matching the subnode name. This is - * useful for finding subnodes based on a portion of a larger string, - * such as a full path. - */ -int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, - const char *name, int namelen); -/** - * fdt_subnode_offset - find a subnode of a given node - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_subnode_offset() finds a subnode of the node at structure block - * offset parentoffset with the given name. name may include a unit - * address, in which case fdt_subnode_offset() will find the subnode - * with that unit address, or the unit address may be omitted, in - * which case fdt_subnode_offset() will find an arbitrary subnode - * whose name excluding unit address matches the given name. - * - * returns: - * structure block offset of the requested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); - -/** - * fdt_path_offset - find a tree node by its full path - * @fdt: pointer to the device tree blob - * @path: full path of the node to locate - * - * fdt_path_offset() finds a node of a given path in the device tree. - * Each path component may omit the unit address portion, but the - * results of this are undefined if any such path component is - * ambiguous (that is if there are multiple nodes at the relevant - * level matching the given component, differentiated only by unit - * address). - * - * returns: - * structure block offset of the node with the requested path (>=0), on success - * -FDT_ERR_BADPATH, given path does not begin with ''/'' or is invalid - * -FDT_ERR_NOTFOUND, if the requested node does not exist - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_path_offset(const void *fdt, const char *path); - -/** - * fdt_get_name - retrieve the name of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of the starting node - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_name() retrieves the name (including unit address) of the - * device tree node at structure block offset nodeoffset. If lenp is - * non-NULL, the length of this name is also returned, in the integer - * pointed to by lenp. - * - * returns: - * pointer to the node''s name, on success - * If lenp is non-NULL, *lenp contains the length of that name (>=0) - * NULL, on error - * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); - -/** - * fdt_first_property_offset - find the offset of a node''s first property - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of a node - * - * fdt_first_property_offset() finds the first property of the node at - * the given structure block offset. - * - * returns: - * structure block offset of the property (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested node has no properties - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_first_property_offset(const void *fdt, int nodeoffset); - -/** - * fdt_next_property_offset - step through a node''s properties - * @fdt: pointer to the device tree blob - * @offset: structure block offset of a property - * - * fdt_next_property_offset() finds the property immediately after the - * one at the given structure block offset. This will be a property - * of the same node as the given property. - * - * returns: - * structure block offset of the next property (>=0), on success - * -FDT_ERR_NOTFOUND, if the given property is the last in its node - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_next_property_offset(const void *fdt, int offset); - -/** - * fdt_get_property_by_offset - retrieve the property at a given offset - * @fdt: pointer to the device tree blob - * @offset: offset of the property to retrieve - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_property_by_offset() retrieves a pointer to the - * fdt_property structure within the device tree blob at the given - * offset. If lenp is non-NULL, the length of the property value is - * also returned, in the integer pointed to by lenp. - * - * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp); - -/** - * fdt_get_property_namelen - find a property based on substring - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @namelen: number of characters of name to consider - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * Identical to fdt_get_property_namelen(), but only examine the first - * namelen characters of name for matching the property name. - */ -const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int nodeoffset, - const char *name, - int namelen, int *lenp); - -/** - * fdt_get_property - find a given property in a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_property() retrieves a pointer to the fdt_property - * structure within the device tree blob corresponding to the property - * named ''name'' of the node at offset nodeoffset. If lenp is - * non-NULL, the length of the property value is also returned, in the - * integer pointed to by lenp. - * - * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, - const char *name, int *lenp); -static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, - const char *name, - int *lenp) -{ - return (struct fdt_property *)(uintptr_t) - fdt_get_property(fdt, nodeoffset, name, lenp); -} - -/** - * fdt_getprop_by_offset - retrieve the value of a property at a given offset - * @fdt: pointer to the device tree blob - * @ffset: offset of the property to read - * @namep: pointer to a string variable (will be overwritten) or NULL - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_getprop_by_offset() retrieves a pointer to the value of the - * property at structure block offset ''offset'' (this will be a pointer - * to within the device blob itself, not a copy of the value). If - * lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. If namep is non-NULL, - * the property''s namne will also be returned in the char * pointed to - * by namep (this will be a pointer to within the device tree''s string - * block, not a new copy of the name). - * - * returns: - * pointer to the property''s value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * if namep is non-NULL *namep contiains a pointer to the property - * name. - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp); - -/** - * fdt_getprop_namelen - get property value based on substring - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @namelen: number of characters of name to consider - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * Identical to fdt_getprop(), but only examine the first namelen - * characters of name for matching the property name. - */ -const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp); - -/** - * fdt_getprop - retrieve the value of a given property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_getprop() retrieves a pointer to the value of the property - * named ''name'' of the node at offset nodeoffset (this will be a - * pointer to within the device blob itself, not a copy of the value). - * If lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. - * - * returns: - * pointer to the property''s value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp); -static inline void *fdt_getprop_w(void *fdt, int nodeoffset, - const char *name, int *lenp) -{ - return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); -} - -/** - * fdt_get_phandle - retrieve the phandle of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of the node - * - * fdt_get_phandle() retrieves the phandle of the device tree node at - * structure block offset nodeoffset. - * - * returns: - * the phandle of the node at nodeoffset, on success (!= 0, != -1) - * 0, if the node has no phandle, or another error occurs - */ -uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); - -/** - * fdt_get_alias_namelen - get alias based on substring - * @fdt: pointer to the device tree blob - * @name: name of the alias th look up - * @namelen: number of characters of name to consider - * - * Identical to fdt_get_alias(), but only examine the first namelen - * characters of name for matching the alias name. - */ -const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen); - -/** - * fdt_get_alias - retreive the path referenced by a given alias - * @fdt: pointer to the device tree blob - * @name: name of the alias th look up - * - * fdt_get_alias() retrieves the value of a given alias. That is, the - * value of the property named ''name'' in the node /aliases. - * - * returns: - * a pointer to the expansion of the alias named ''name'', of it exists - * NULL, if the given alias or the /aliases node does not exist - */ -const char *fdt_get_alias(const void *fdt, const char *name); - -/** - * fdt_get_path - determine the full path of a node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose path to find - * @buf: character buffer to contain the returned path (will be overwritten) - * @buflen: size of the character buffer at buf - * - * fdt_get_path() computes the full path of the node at offset - * nodeoffset, and records that path in the buffer at buf. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - * 0, on success - * buf contains the absolute path of the node at - * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) - * characters and will not fit in the given buffer. - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); - -/** - * fdt_supernode_atdepth_offset - find a specific ancestor of a node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * @supernodedepth: depth of the ancestor to find - * @nodedepth: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_supernode_atdepth_offset() finds an ancestor of the given node - * at a specific depth from the root (where the root itself has depth - * 0, its immediate subnodes depth 1 and so forth). So - * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); - * will always return 0, the offset of the root node. If the node at - * nodeoffset has depth D, then: - * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); - * will return nodeoffset itself. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - - * structure block offset of the node at node offset''s ancestor - * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag -* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth); - -/** - * fdt_node_depth - find the depth of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * - * fdt_node_depth() finds the depth of a given node. The root node - * has depth 0, its immediate subnodes depth 1 and so forth. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_depth(const void *fdt, int nodeoffset); - -/** - * fdt_parent_offset - find the parent of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * - * fdt_parent_offset() locates the parent node of a given node (that - * is, it finds the offset of the node which contains the node at - * nodeoffset as a subnode). - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset, *twice*. - * - * returns: - * structure block offset of the parent of the node at nodeoffset - * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_parent_offset(const void *fdt, int nodeoffset); - -/** - * fdt_node_offset_by_prop_value - find nodes with a given property value - * @fdt: pointer to the device tree blob - * @startoffset: only find nodes after this offset - * @propname: property name to check - * @propval: property value to search for - * @proplen: length of the value in propval - * - * fdt_node_offset_by_prop_value() returns the offset of the first - * node after startoffset, which has a property named propname whose - * value is of length proplen and has value equal to propval; or if - * startoffset is -1, the very first such node in the tree. - * - * To iterate through all nodes matching the criterion, the following - * idiom can be used: - * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, - * propval, proplen); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, - * propval, proplen); - * } - * - * Note the -1 in the first call to the function, if 0 is used here - * instead, the function will never locate the root node, even if it - * matches the criterion. - * - * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen); - -/** - * fdt_node_offset_by_phandle - find the node with a given phandle - * @fdt: pointer to the device tree blob - * @phandle: phandle value - * - * fdt_node_offset_by_phandle() returns the offset of the node - * which has the given phandle value. If there is more than one node - * in the tree with the given phandle (an invalid tree), results are - * undefined. - * - * returns: - * structure block offset of the located node (>= 0), on success - * -FDT_ERR_NOTFOUND, no node with that phandle exists - * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); - -/** - * fdt_node_check_compatible: check a node''s compatible property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of a tree node - * @compatible: string to match against - * - * - * fdt_node_check_compatible() returns 0 if the given node contains a - * ''compatible'' property with the given string as one of its elements, - * it returns non-zero otherwise, or on error. - * - * returns: - * 0, if the node has a ''compatible'' property listing the given string - * 1, if the node has a ''compatible'' property, but it does not list - * the given string - * -FDT_ERR_NOTFOUND, if the given node has no ''compatible'' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_check_compatible(const void *fdt, int nodeoffset, - const char *compatible); - -/** - * fdt_node_offset_by_compatible - find nodes with a given ''compatible'' value - * @fdt: pointer to the device tree blob - * @startoffset: only find nodes after this offset - * @compatible: ''compatible'' string to match against - * - * fdt_node_offset_by_compatible() returns the offset of the first - * node after startoffset, which has a ''compatible'' property which - * lists the given compatible string; or if startoffset is -1, the - * very first such node in the tree. - * - * To iterate through all nodes matching the criterion, the following - * idiom can be used: - * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); - * } - * - * Note the -1 in the first call to the function, if 0 is used here - * instead, the function will never locate the root node, even if it - * matches the criterion. - * - * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible); - -/**********************************************************************/ -/* Write-in-place functions */ -/**********************************************************************/ - -/** - * fdt_setprop_inplace - change a property''s value, but not its size - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: pointer to data to replace the property value with - * @len: length of the property value - * - * fdt_setprop_inplace() replaces the value of a given property with - * the data in val, of length len. This function cannot change the - * size of a property, and so will only work if len is equal to the - * current length of the property. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if len is not equal to the property''s current length - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_setprop_inplace_cell - change the value of a single-cell property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: cell (32-bit integer) value to replace the property with - * - * fdt_setprop_inplace_cell() replaces the value of a given property - * with the 32-bit integer cell value in val, converting val to - * big-endian if necessary. This function cannot change the size of a - * property, and so will only work if the property already exists and - * has length 4. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if the property''s length is not equal to 4 - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - val = cpu_to_fdt32(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); -} - -/** - * fdt_nop_property - replace a property with nop tags - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to nop - * @name: name of the property to nop - * - * fdt_nop_property() will replace a given property''s representation - * in the blob with FDT_NOP tags, effectively removing it from the - * tree. - * - * This function will alter only the bytes in the blob which contain - * the property, and will not alter or move any other part of the - * tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_nop_property(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_nop_node - replace a node (subtree) with nop tags - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node to nop - * - * fdt_nop_node() will replace a given node''s representation in the - * blob, including all its subnodes, if any, with FDT_NOP tags, - * effectively removing it from the tree. - * - * This function will alter only the bytes in the blob which contain - * the node and its properties and subnodes, and will not alter or - * move any other part of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_nop_node(void *fdt, int nodeoffset); - -/**********************************************************************/ -/* Sequential write functions */ -/**********************************************************************/ - -int fdt_create(void *buf, int bufsize); -int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); -int fdt_finish_reservemap(void *fdt); -int fdt_begin_node(void *fdt, const char *name); -int fdt_property(void *fdt, const char *name, const void *val, int len); -static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) -{ - val = cpu_to_fdt32(val); - return fdt_property(fdt, name, &val, sizeof(val)); -} -#define fdt_property_string(fdt, name, str) \ - fdt_property(fdt, name, str, strlen(str)+1) -int fdt_end_node(void *fdt); -int fdt_finish(void *fdt); - -/**********************************************************************/ -/* Read-write functions */ -/**********************************************************************/ - -int fdt_open_into(const void *fdt, void *buf, int bufsize); -int fdt_pack(void *fdt); - -/** - * fdt_add_mem_rsv - add one memory reserve map entry - * @fdt: pointer to the device tree blob - * @address, @size: 64-bit values (native endian) - * - * Adds a reserve map entry to the given blob reserving a region at - * address address of length size. - * - * This function will insert data into the reserve map and will - * therefore change the indexes of some entries in the table. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new reservation entry - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); - -/** - * fdt_del_mem_rsv - remove a memory reserve map entry - * @fdt: pointer to the device tree blob - * @n: entry to remove - * - * fdt_del_mem_rsv() removes the n-th memory reserve map entry from - * the blob. - * - * This function will delete data from the reservation table and will - * therefore change the indexes of some entries in the table. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there - * are less than n+1 reserve map entries) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_del_mem_rsv(void *fdt, int n); - -/** - * fdt_set_name - change the name of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of a node - * @name: name to give the node - * - * fdt_set_name() replaces the name (including unit address, if any) - * of the given node with the given string. NOTE: this function can''t - * efficiently check if the new name is unique amongst the given - * node''s siblings; results are undefined if this function is invoked - * with a name equal to one of the given node''s siblings. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob - * to contain the new name - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_set_name(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_setprop - create or change a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: pointer to data to set the property value to - * @len: length of the property value - * - * fdt_setprop() sets the value of the named property in the given - * node to the given value and length, creating the property if it - * does not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_setprop_cell - set a property to a single cell value - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 32-bit integer value for the property (native endian) - * - * fdt_setprop_cell() sets the value of the named property in the - * given node to the given cell value (converting to big-endian if - * necessary), or creates a new property with that value if it does - * not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, - uint32_t val) -{ - val = cpu_to_fdt32(val); - return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); -} - -/** - * fdt_setprop_string - set a property to a string value - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @str: string value for the property - * - * fdt_setprop_string() sets the value of the named property in the - * given node to the given string value (using the length of the - * string to determine the new length of the property), or creates a - * new property with that value if it does not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -#define fdt_setprop_string(fdt, nodeoffset, name, str) \ - fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) - -/** - * fdt_delprop - delete a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to nop - * @name: name of the property to nop - * - * fdt_del_property() will delete the given property. - * - * This function will delete data from the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_delprop(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_add_subnode_namelen - creates a new node based on substring - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * @namelen: number of characters of name to consider - * - * Identical to fdt_add_subnode(), but use only the first namelen - * characters of name as the name of the new node. This is useful for - * creating subnodes based on a portion of a larger string, such as a - * full path. - */ -int fdt_add_subnode_namelen(void *fdt, int parentoffset, - const char *name, int namelen); - -/** - * fdt_add_subnode - creates a new node - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_add_subnode() creates a new node as a subnode of the node at - * structure block offset parentoffset, with the given name (which - * should include the unit address, if any). - * - * This function will insert data into the blob, and will therefore - * change the offsets of some existing nodes. - - * returns: - * structure block offset of the created nodeequested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of - * the given name - * -FDT_ERR_NOSPACE, if there is insufficient free space in the - * blob to contain the new node - * -FDT_ERR_NOSPACE - * -FDT_ERR_BADLAYOUT - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_add_subnode(void *fdt, int parentoffset, const char *name); - -/** - * fdt_del_node - delete a node (subtree) - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node to nop - * - * fdt_del_node() will remove the given node, including all its - * subnodes if any, from the blob. - * - * This function will delete data from the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_del_node(void *fdt, int nodeoffset); - -/**********************************************************************/ -/* Debugging / informational functions */ -/**********************************************************************/ - -const char *fdt_strerror(int errval); - -#endif /* _LIBFDT_H */ diff --git a/xen/common/libfdt/libfdt_env.h b/xen/common/libfdt/libfdt_env.h deleted file mode 100644 index 8c0c030..0000000 --- a/xen/common/libfdt/libfdt_env.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _LIBFDT_ENV_H -#define _LIBFDT_ENV_H - -#include <xen/config.h> -#include <xen/types.h> -#include <xen/string.h> -#include <asm/byteorder.h> - -#define fdt16_to_cpu(x) be16_to_cpu(x) -#define cpu_to_fdt16(x) cpu_to_be16(x) -#define fdt32_to_cpu(x) be32_to_cpu(x) -#define cpu_to_fdt32(x) cpu_to_be32(x) -#define fdt64_to_cpu(x) be64_to_cpu(x) -#define cpu_to_fdt64(x) cpu_to_be64(x) - -#endif /* _LIBFDT_ENV_H */ diff --git a/xen/include/xen/libfdt/fdt.h b/xen/include/xen/libfdt/fdt.h new file mode 100644 index 0000000..48ccfd9 --- /dev/null +++ b/xen/include/xen/libfdt/fdt.h @@ -0,0 +1,60 @@ +#ifndef _FDT_H +#define _FDT_H + +#ifndef __ASSEMBLY__ + +struct fdt_header { + uint32_t magic; /* magic word FDT_MAGIC */ + uint32_t totalsize; /* total size of DT block */ + uint32_t off_dt_struct; /* offset to structure */ + uint32_t off_dt_strings; /* offset to strings */ + uint32_t off_mem_rsvmap; /* offset to memory reserve map */ + uint32_t version; /* format version */ + uint32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + uint32_t boot_cpuid_phys; /* Which physical CPU id we''re + booting on */ + /* version 3 fields below */ + uint32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + uint32_t size_dt_struct; /* size of the structure block */ +}; + +struct fdt_reserve_entry { + uint64_t address; + uint64_t size; +}; + +struct fdt_node_header { + uint32_t tag; + char name[0]; +}; + +struct fdt_property { + uint32_t tag; + uint32_t len; + uint32_t nameoff; + char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(uint32_t) + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, + size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +#define FDT_V1_SIZE (7*sizeof(uint32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) + +#endif /* _FDT_H */ diff --git a/xen/include/xen/libfdt/libfdt.h b/xen/include/xen/libfdt/libfdt.h new file mode 100644 index 0000000..6086047 --- /dev/null +++ b/xen/include/xen/libfdt/libfdt.h @@ -0,0 +1,1235 @@ +#ifndef _LIBFDT_H +#define _LIBFDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. 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. + * + * 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 <xen/libfdt/libfdt_env.h> +#include <xen/libfdt/fdt.h> + +#define FDT_FIRST_SUPPORTED_VERSION 0x10 +#define FDT_LAST_SUPPORTED_VERSION 0x11 + +/* Error codes: informative error codes */ +#define FDT_ERR_NOTFOUND 1 + /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ +#define FDT_ERR_EXISTS 2 + /* FDT_ERR_EXISTS: Attemped to create a node or property which + * already exists */ +#define FDT_ERR_NOSPACE 3 + /* FDT_ERR_NOSPACE: Operation needed to expand the device + * tree, but its buffer did not have sufficient space to + * contain the expanded tree. Use fdt_open_into() to move the + * device tree to a buffer with more space. */ + +/* Error codes: codes for bad parameters */ +#define FDT_ERR_BADOFFSET 4 + /* FDT_ERR_BADOFFSET: Function was passed a structure block + * offset which is out-of-bounds, or which points to an + * unsuitable part of the structure for the operation. */ +#define FDT_ERR_BADPATH 5 + /* FDT_ERR_BADPATH: Function was passed a badly formatted path + * (e.g. missing a leading / for a function which requires an + * absolute path) */ +#define FDT_ERR_BADPHANDLE 6 + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle + * value. phandle values of 0 and -1 are not permitted. */ +#define FDT_ERR_BADSTATE 7 + /* FDT_ERR_BADSTATE: Function was passed an incomplete device + * tree created by the sequential-write functions, which is + * not sufficiently complete for the requested operation. */ + +/* Error codes: codes for bad device tree blobs */ +#define FDT_ERR_TRUNCATED 8 + /* FDT_ERR_TRUNCATED: Structure block of the given device tree + * ends without an FDT_END tag. */ +#define FDT_ERR_BADMAGIC 9 + /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a + * device tree at all - it is missing the flattened device + * tree magic number. */ +#define FDT_ERR_BADVERSION 10 + /* FDT_ERR_BADVERSION: Given device tree has a version which + * can''t be handled by the requested operation. For + * read-write functions, this may mean that fdt_open_into() is + * required to convert the tree to the expected version. */ +#define FDT_ERR_BADSTRUCTURE 11 + /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt + * structure block or other serious error (e.g. misnested + * nodes, or subnodes preceding properties). */ +#define FDT_ERR_BADLAYOUT 12 + /* FDT_ERR_BADLAYOUT: For read-write functions, the given + * device tree has it''s sub-blocks in an order that the + * function can''t handle (memory reserve map, then structure, + * then strings). Use fdt_open_into() to reorganize the tree + * into a form suitable for the read-write operations. */ + +/* "Can''t happen" error indicating a bug in libfdt */ +#define FDT_ERR_INTERNAL 13 + /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. + * Should never be returned, if it is, it indicates a bug in + * libfdt itself. */ + +#define FDT_ERR_MAX 13 + +/**********************************************************************/ +/* Low-level functions (you probably don''t need these) */ +/**********************************************************************/ + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); +static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) +{ + return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); +} + +uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); + +/**********************************************************************/ +/* Traversal functions */ +/**********************************************************************/ + +int fdt_next_node(const void *fdt, int offset, int *depth); + +/**********************************************************************/ +/* General functions */ +/**********************************************************************/ + +#define fdt_get_header(fdt, field) \ + (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) +#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) +#define fdt_version(fdt) (fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + +#define __fdt_set_hdr(name) \ + static inline void fdt_set_##name(void *fdt, uint32_t val) \ + { \ + struct fdt_header *fdth = (struct fdt_header*)fdt; \ + fdth->name = cpu_to_fdt32(val); \ + } +__fdt_set_hdr(magic); +__fdt_set_hdr(totalsize); +__fdt_set_hdr(off_dt_struct); +__fdt_set_hdr(off_dt_strings); +__fdt_set_hdr(off_mem_rsvmap); +__fdt_set_hdr(version); +__fdt_set_hdr(last_comp_version); +__fdt_set_hdr(boot_cpuid_phys); +__fdt_set_hdr(size_dt_strings); +__fdt_set_hdr(size_dt_struct); +#undef __fdt_set_hdr + +/** + * fdt_check_header - sanity check a device tree or possible device tree + * @fdt: pointer to data which might be a flattened device tree + * + * fdt_check_header() checks that the given buffer contains what + * appears to be a flattened device tree with sane information in its + * header. + * + * returns: + * 0, if the buffer appears to contain a valid device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings, as above + */ +int fdt_check_header(const void *fdt); + +/** + * fdt_move - move a device tree around in memory + * @fdt: pointer to the device tree to move + * @buf: pointer to memory where the device is to be moved + * @bufsize: size of the memory space at buf + * + * fdt_move() relocates, if possible, the device tree blob located at + * fdt to the buffer at buf of size bufsize. The buffer may overlap + * with the existing device tree blob at fdt. Therefore, + * fdt_move(fdt, fdt, fdt_totalsize(fdt)) + * should always succeed. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_move(const void *fdt, void *buf, int bufsize); + +/**********************************************************************/ +/* Read-only functions */ +/**********************************************************************/ + +/** + * fdt_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * + * fdt_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt. + * + * returns: + * a pointer to the string, on success + * NULL, if stroffset is out of bounds + */ +const char *fdt_string(const void *fdt, int stroffset); + +/** + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries + * @fdt: pointer to the device tree blob + * + * Returns the number of entries in the device tree blob''s memory + * reservation map. This does not include the terminating 0,0 entry + * or any other (0,0) entries reserved for expansion. + * + * returns: + * the number of entries + */ +int fdt_num_mem_rsv(const void *fdt); + +/** + * fdt_get_mem_rsv - retrieve one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: pointers to 64-bit variables + * + * On success, *address and *size will contain the address and size of + * the n-th reserve map entry from the device tree blob, in + * native-endian format. + * + * returns: + * 0, on success + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); + +/** + * fdt_subnode_offset_namelen - find a subnode based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_subnode_offset(), but only examine the first + * namelen characters of name for matching the subnode name. This is + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + */ +int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + const char *name, int namelen); +/** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node at structure block + * offset parentoffset with the given name. name may include a unit + * address, in which case fdt_subnode_offset() will find the subnode + * with that unit address, or the unit address may be omitted, in + * which case fdt_subnode_offset() will find an arbitrary subnode + * whose name excluding unit address matches the given name. + * + * returns: + * structure block offset of the requested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + +/** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * + * fdt_path_offset() finds a node of a given path in the device tree. + * Each path component may omit the unit address portion, but the + * results of this are undefined if any such path component is + * ambiguous (that is if there are multiple nodes at the relevant + * level matching the given component, differentiated only by unit + * address). + * + * returns: + * structure block offset of the node with the requested path (>=0), on success + * -FDT_ERR_BADPATH, given path does not begin with ''/'' or is invalid + * -FDT_ERR_NOTFOUND, if the requested node does not exist + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_path_offset(const void *fdt, const char *path); + +/** + * fdt_get_name - retrieve the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the starting node + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_name() retrieves the name (including unit address) of the + * device tree node at structure block offset nodeoffset. If lenp is + * non-NULL, the length of this name is also returned, in the integer + * pointed to by lenp. + * + * returns: + * pointer to the node''s name, on success + * If lenp is non-NULL, *lenp contains the length of that name (>=0) + * NULL, on error + * if lenp is non-NULL *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); + +/** + * fdt_first_property_offset - find the offset of a node''s first property + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * + * fdt_first_property_offset() finds the first property of the node at + * the given structure block offset. + * + * returns: + * structure block offset of the property (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested node has no properties + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_first_property_offset(const void *fdt, int nodeoffset); + +/** + * fdt_next_property_offset - step through a node''s properties + * @fdt: pointer to the device tree blob + * @offset: structure block offset of a property + * + * fdt_next_property_offset() finds the property immediately after the + * one at the given structure block offset. This will be a property + * of the same node as the given property. + * + * returns: + * structure block offset of the next property (>=0), on success + * -FDT_ERR_NOTFOUND, if the given property is the last in its node + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_next_property_offset(const void *fdt, int offset); + +/** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to retrieve + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property_by_offset() retrieves a pointer to the + * fdt_property structure within the device tree blob at the given + * offset. If lenp is non-NULL, the length of the property value is + * also returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp); + +/** + * fdt_get_property_namelen - find a property based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_get_property_namelen(), but only examine the first + * namelen characters of name for matching the property name. + */ +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); + +/** + * fdt_get_property - find a given property in a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property() retrieves a pointer to the fdt_property + * structure within the device tree blob corresponding to the property + * named ''name'' of the node at offset nodeoffset. If lenp is + * non-NULL, the length of the property value is also returned, in the + * integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, + const char *name, + int *lenp) +{ + return (struct fdt_property *)(uintptr_t) + fdt_get_property(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_getprop_by_offset - retrieve the value of a property at a given offset + * @fdt: pointer to the device tree blob + * @ffset: offset of the property to read + * @namep: pointer to a string variable (will be overwritten) or NULL + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop_by_offset() retrieves a pointer to the value of the + * property at structure block offset ''offset'' (this will be a pointer + * to within the device blob itself, not a copy of the value). If + * lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. If namep is non-NULL, + * the property''s namne will also be returned in the char * pointed to + * by namep (this will be a pointer to within the device tree''s string + * block, not a new copy of the name). + * + * returns: + * pointer to the property''s value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * if namep is non-NULL *namep contiains a pointer to the property + * name. + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp); + +/** + * fdt_getprop_namelen - get property value based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + */ +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); + +/** + * fdt_getprop - retrieve the value of a given property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop() retrieves a pointer to the value of the property + * named ''name'' of the node at offset nodeoffset (this will be a + * pointer to within the device blob itself, not a copy of the value). + * If lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the property''s value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline void *fdt_getprop_w(void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_get_phandle - retrieve the phandle of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the node + * + * fdt_get_phandle() retrieves the phandle of the device tree node at + * structure block offset nodeoffset. + * + * returns: + * the phandle of the node at nodeoffset, on success (!= 0, != -1) + * 0, if the node has no phandle, or another error occurs + */ +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); + +/** + * fdt_get_alias_namelen - get alias based on substring + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * @namelen: number of characters of name to consider + * + * Identical to fdt_get_alias(), but only examine the first namelen + * characters of name for matching the alias name. + */ +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen); + +/** + * fdt_get_alias - retreive the path referenced by a given alias + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * + * fdt_get_alias() retrieves the value of a given alias. That is, the + * value of the property named ''name'' in the node /aliases. + * + * returns: + * a pointer to the expansion of the alias named ''name'', of it exists + * NULL, if the given alias or the /aliases node does not exist + */ +const char *fdt_get_alias(const void *fdt, const char *name); + +/** + * fdt_get_path - determine the full path of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose path to find + * @buf: character buffer to contain the returned path (will be overwritten) + * @buflen: size of the character buffer at buf + * + * fdt_get_path() computes the full path of the node at offset + * nodeoffset, and records that path in the buffer at buf. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * 0, on success + * buf contains the absolute path of the node at + * nodeoffset, as a NUL-terminated string. + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + * characters and will not fit in the given buffer. + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + +/** + * fdt_supernode_atdepth_offset - find a specific ancestor of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * @supernodedepth: depth of the ancestor to find + * @nodedepth: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_supernode_atdepth_offset() finds an ancestor of the given node + * at a specific depth from the root (where the root itself has depth + * 0, its immediate subnodes depth 1 and so forth). So + * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); + * will always return 0, the offset of the root node. If the node at + * nodeoffset has depth D, then: + * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); + * will return nodeoffset itself. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + + * structure block offset of the node at node offset''s ancestor + * of depth supernodedepth (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag +* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth); + +/** + * fdt_node_depth - find the depth of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_node_depth() finds the depth of a given node. The root node + * has depth 0, its immediate subnodes depth 1 and so forth. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * depth of the node at nodeoffset (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_depth(const void *fdt, int nodeoffset); + +/** + * fdt_parent_offset - find the parent of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_parent_offset() locates the parent node of a given node (that + * is, it finds the offset of the node which contains the node at + * nodeoffset as a subnode). + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset, *twice*. + * + * returns: + * structure block offset of the parent of the node at nodeoffset + * (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_parent_offset(const void *fdt, int nodeoffset); + +/** + * fdt_node_offset_by_prop_value - find nodes with a given property value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @propname: property name to check + * @propval: property value to search for + * @proplen: length of the value in propval + * + * fdt_node_offset_by_prop_value() returns the offset of the first + * node after startoffset, which has a property named propname whose + * value is of length proplen and has value equal to propval; or if + * startoffset is -1, the very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, + * propval, proplen); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + * propval, proplen); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen); + +/** + * fdt_node_offset_by_phandle - find the node with a given phandle + * @fdt: pointer to the device tree blob + * @phandle: phandle value + * + * fdt_node_offset_by_phandle() returns the offset of the node + * which has the given phandle value. If there is more than one node + * in the tree with the given phandle (an invalid tree), results are + * undefined. + * + * returns: + * structure block offset of the located node (>= 0), on success + * -FDT_ERR_NOTFOUND, no node with that phandle exists + * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); + +/** + * fdt_node_check_compatible: check a node''s compatible property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @compatible: string to match against + * + * + * fdt_node_check_compatible() returns 0 if the given node contains a + * ''compatible'' property with the given string as one of its elements, + * it returns non-zero otherwise, or on error. + * + * returns: + * 0, if the node has a ''compatible'' property listing the given string + * 1, if the node has a ''compatible'' property, but it does not list + * the given string + * -FDT_ERR_NOTFOUND, if the given node has no ''compatible'' property + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible); + +/** + * fdt_node_offset_by_compatible - find nodes with a given ''compatible'' value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @compatible: ''compatible'' string to match against + * + * fdt_node_offset_by_compatible() returns the offset of the first + * node after startoffset, which has a ''compatible'' property which + * lists the given compatible string; or if startoffset is -1, the + * very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible); + +/**********************************************************************/ +/* Write-in-place functions */ +/**********************************************************************/ + +/** + * fdt_setprop_inplace - change a property''s value, but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * fdt_setprop_inplace() replaces the value of a given property with + * the data in val, of length len. This function cannot change the + * size of a property, and so will only work if len is equal to the + * current length of the property. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if len is not equal to the property''s current length + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: cell (32-bit integer) value to replace the property with + * + * fdt_setprop_inplace_cell() replaces the value of a given property + * with the 32-bit integer cell value in val, converting val to + * big-endian if necessary. This function cannot change the size of a + * property, and so will only work if the property already exists and + * has length 4. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property''s length is not equal to 4 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + val = cpu_to_fdt32(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_nop_property - replace a property with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_nop_property() will replace a given property''s representation + * in the blob with FDT_NOP tags, effectively removing it from the + * tree. + * + * This function will alter only the bytes in the blob which contain + * the property, and will not alter or move any other part of the + * tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_property(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_nop_node - replace a node (subtree) with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_nop_node() will replace a given node''s representation in the + * blob, including all its subnodes, if any, with FDT_NOP tags, + * effectively removing it from the tree. + * + * This function will alter only the bytes in the blob which contain + * the node and its properties and subnodes, and will not alter or + * move any other part of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_node(void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Sequential write functions */ +/**********************************************************************/ + +int fdt_create(void *buf, int bufsize); +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); +int fdt_finish_reservemap(void *fdt); +int fdt_begin_node(void *fdt, const char *name); +int fdt_property(void *fdt, const char *name, const void *val, int len); +static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +{ + val = cpu_to_fdt32(val); + return fdt_property(fdt, name, &val, sizeof(val)); +} +#define fdt_property_string(fdt, name, str) \ + fdt_property(fdt, name, str, strlen(str)+1) +int fdt_end_node(void *fdt); +int fdt_finish(void *fdt); + +/**********************************************************************/ +/* Read-write functions */ +/**********************************************************************/ + +int fdt_open_into(const void *fdt, void *buf, int bufsize); +int fdt_pack(void *fdt); + +/** + * fdt_add_mem_rsv - add one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: 64-bit values (native endian) + * + * Adds a reserve map entry to the given blob reserving a region at + * address address of length size. + * + * This function will insert data into the reserve map and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new reservation entry + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); + +/** + * fdt_del_mem_rsv - remove a memory reserve map entry + * @fdt: pointer to the device tree blob + * @n: entry to remove + * + * fdt_del_mem_rsv() removes the n-th memory reserve map entry from + * the blob. + * + * This function will delete data from the reservation table and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there + * are less than n+1 reserve map entries) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_mem_rsv(void *fdt, int n); + +/** + * fdt_set_name - change the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * @name: name to give the node + * + * fdt_set_name() replaces the name (including unit address, if any) + * of the given node with the given string. NOTE: this function can''t + * efficiently check if the new name is unique amongst the given + * node''s siblings; results are undefined if this function is invoked + * with a name equal to one of the given node''s siblings. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob + * to contain the new name + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_set_name(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_setprop - create or change a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_setprop_cell - set a property to a single cell value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) + * + * fdt_setprop_cell() sets the value of the named property in the + * given node to the given cell value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + val = cpu_to_fdt32(val); + return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_setprop_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value for the property + * + * fdt_setprop_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_string(fdt, nodeoffset, name, str) \ + fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** + * fdt_delprop - delete a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_del_property() will delete the given property. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_delprop(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_add_subnode_namelen - creates a new node based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_add_subnode(), but use only the first namelen + * characters of name as the name of the new node. This is useful for + * creating subnodes based on a portion of a larger string, such as a + * full path. + */ +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen); + +/** + * fdt_add_subnode - creates a new node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_add_subnode() creates a new node as a subnode of the node at + * structure block offset parentoffset, with the given name (which + * should include the unit address, if any). + * + * This function will insert data into the blob, and will therefore + * change the offsets of some existing nodes. + + * returns: + * structure block offset of the created nodeequested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the + * blob to contain the new node + * -FDT_ERR_NOSPACE + * -FDT_ERR_BADLAYOUT + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_add_subnode(void *fdt, int parentoffset, const char *name); + +/** + * fdt_del_node - delete a node (subtree) + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_del_node() will remove the given node, including all its + * subnodes if any, from the blob. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_node(void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Debugging / informational functions */ +/**********************************************************************/ + +const char *fdt_strerror(int errval); + +#endif /* _LIBFDT_H */ diff --git a/xen/include/xen/libfdt/libfdt_env.h b/xen/include/xen/libfdt/libfdt_env.h new file mode 100644 index 0000000..8c0c030 --- /dev/null +++ b/xen/include/xen/libfdt/libfdt_env.h @@ -0,0 +1,16 @@ +#ifndef _LIBFDT_ENV_H +#define _LIBFDT_ENV_H + +#include <xen/config.h> +#include <xen/types.h> +#include <xen/string.h> +#include <asm/byteorder.h> + +#define fdt16_to_cpu(x) be16_to_cpu(x) +#define cpu_to_fdt16(x) cpu_to_be16(x) +#define fdt32_to_cpu(x) be32_to_cpu(x) +#define cpu_to_fdt32(x) cpu_to_be32(x) +#define fdt64_to_cpu(x) be64_to_cpu(x) +#define cpu_to_fdt64(x) cpu_to_be64(x) + +#endif /* _LIBFDT_ENV_H */ -- 1.7.2.5
From: David Vrabel <david.vrabel@citrix.com> Signed-off-by: David Vrabel <david.vrabel@citrix.com> Cc: Keir Fraser <keir@xen.org> --- MAINTAINERS | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index dfc76dd..c1d8696 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -111,6 +111,14 @@ M: Juergen Gross <juergen.gross@ts.fujitsu.com> S: Supported F: xen/common/cpupool.c +DEVICE TREE +M: David Vrabel <david.vrabel@citrix.com> +S: Supported +F: xen/common/libfdt/ +F: xen/common/device_tree.c +F: xen/include/xen/libfdt/ +F: xen/include/xen/device_tree.h + EFI M: Jan Beulich <jbeulich@suse.com> S: Supported -- 1.7.2.5
From: David Vrabel <david.vrabel@citrix.com> Only changes to the coding style, no functional changes. Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- xen/common/device_tree.c | 48 ++++++++++++++++++++++++++++----------------- 1 files changed, 30 insertions(+), 18 deletions(-) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 140d342..4a7166d 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -27,25 +27,28 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val) { *val = 0; - while (cells--) { + while ( cells-- ) + { *val <<= 32; *val |= fdt32_to_cpu(*(*cell)++); } } -static void __init get_register(const u32 **cell, u32 address_cells, u32 size_cells, +static void __init get_register(const u32 **cell, + u32 address_cells, u32 size_cells, u64 *start, u64 *size) { get_val(cell, address_cells, start); get_val(cell, size_cells, size); } -static u32 __init prop_by_name_u32(const void *fdt, int node, const char *prop_name) +static u32 __init prop_by_name_u32(const void *fdt, int node, + const char *prop_name) { const struct fdt_property *prop; prop = fdt_get_property(fdt, node, prop_name, NULL); - if (!prop || prop->len < sizeof(u32)) + if ( !prop || prop->len < sizeof(u32) ) return 0; /* default to 0 */ return fdt32_to_cpu(*(uint32_t*)prop->data); @@ -61,14 +64,16 @@ static void __init process_memory_node(const void *fdt, int node, const u32 *cell; paddr_t start, size; - if (address_cells < 1 || size_cells < 1) { + if ( address_cells < 1 || size_cells < 1 ) + { early_printk("fdt: node `%s'': invalid #address-cells or #size-cells", fdt_get_name(fdt, node, NULL)); return; } prop = fdt_get_property(fdt, node, "reg", NULL); - if (!prop) { + if ( !prop ) + { early_printk("fdt: node `%s'': missing `reg'' property\n", fdt_get_name(fdt, node, NULL)); return; @@ -78,7 +83,8 @@ static void __init process_memory_node(const void *fdt, int node, reg_cells = address_cells + size_cells; banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof(u32)); - for (i = 0; i < banks && early_info.mem.nr_banks < NR_MEM_BANKS; i++) { + for ( i = 0; i < banks && early_info.mem.nr_banks < NR_MEM_BANKS; i++ ) + { get_register(&cell, address_cells, size_cells, &start, &size); early_info.mem.bank[early_info.mem.nr_banks].start = start; early_info.mem.bank[early_info.mem.nr_banks].size = size; @@ -96,10 +102,12 @@ static void __init early_scan(const void *fdt) u32 address_cells[MAX_DEPTH]; u32 size_cells[MAX_DEPTH]; - for (node = 0; depth >= 0; node = fdt_next_node(fdt, node, &depth)) { + for ( node = 0; depth >= 0; node = fdt_next_node(fdt, node, &depth) ) + { name = fdt_get_name(fdt, node, NULL); - if (depth >= MAX_DEPTH) { + if ( depth >= MAX_DEPTH ) + { early_printk("fdt: node ''%s'': nested too deep\n", fdt_get_name(fdt, node, NULL)); continue; @@ -108,8 +116,9 @@ static void __init early_scan(const void *fdt) address_cells[depth] = prop_by_name_u32(fdt, node, "#address-cells"); size_cells[depth] = prop_by_name_u32(fdt, node, "#size-cells"); - if (strncmp(name, "memory", 6) == 0) - process_memory_node(fdt, node, address_cells[depth-1], size_cells[depth-1]); + if ( strncmp(name, "memory", 6) == 0 ) + process_memory_node(fdt, node, + address_cells[depth-1], size_cells[depth-1]); } } @@ -118,9 +127,10 @@ static void __init early_print_info(void) struct dt_mem_info *mi = &early_info.mem; int i; - for (i = 0; i < mi->nr_banks; i++) + for ( i = 0; i < mi->nr_banks; i++ ) early_printk("RAM: %016llx - %016llx\n", - mi->bank[i].start, mi->bank[i].start + mi->bank[i].size - 1); + mi->bank[i].start, + mi->bank[i].start + mi->bank[i].size - 1); } /** @@ -134,7 +144,7 @@ size_t __init device_tree_early_init(const void *fdt) int ret; ret = fdt_check_header(fdt); - if (ret < 0) + if ( ret < 0 ) early_panic("No valid device tree\n"); early_scan(fdt); @@ -159,15 +169,17 @@ paddr_t __init device_tree_get_xen_paddr(void) min_size = (_end - _start + (XEN_PADDR_ALIGN-1)) & ~(XEN_PADDR_ALIGN-1); /* Find the highest bank with enough space. */ - for (i = 0; i < mi->nr_banks; i++) { - if (mi->bank[i].size >= min_size) { + for ( i = 0; i < mi->nr_banks; i++ ) + { + if ( mi->bank[i].size >= min_size ) + { t = mi->bank[i].start + mi->bank[i].size - min_size; - if (t > paddr) + if ( t > paddr ) paddr = t; } } - if (!paddr) + if ( !paddr ) early_panic("Not enough memory to relocate Xen\n"); return paddr; -- 1.7.2.5
David Vrabel
2012-Mar-19 17:52 UTC
[PATCH 04/11] device tree: correctly ignore unit-address when matching nodes by name
From: David Vrabel <david.vrabel@citrix.com> When matching node by their name, correctly ignore the unit address (@...) part of the name. Previously, a "memory-controller" node would be incorrectly matched as a "memory" node. Signed-off-by: David Vrabel <david.vrabel@citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- xen/common/device_tree.c | 22 ++++++++++++++++------ 1 files changed, 16 insertions(+), 6 deletions(-) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 4a7166d..5329956 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -23,6 +23,20 @@ struct dt_early_info __initdata early_info; void *device_tree_flattened; +static bool_t __init node_matches(const void *fdt, int node, const char *match) +{ + const char *name; + size_t match_len; + + name = fdt_get_name(fdt, node, NULL); + match_len = strlen(match); + + /* Match both "match" and "match@..." patterns but not + "match-foo". */ + return strncmp(name, match, match_len) == 0 + && (name[match_len] == ''@'' || name[match_len] == ''\0''); +} + static void __init get_val(const u32 **cell, u32 cells, u64 *val) { *val = 0; @@ -98,14 +112,11 @@ static void __init early_scan(const void *fdt) { int node; int depth; - const char *name; u32 address_cells[MAX_DEPTH]; u32 size_cells[MAX_DEPTH]; for ( node = 0; depth >= 0; node = fdt_next_node(fdt, node, &depth) ) { - name = fdt_get_name(fdt, node, NULL); - if ( depth >= MAX_DEPTH ) { early_printk("fdt: node ''%s'': nested too deep\n", @@ -116,9 +127,8 @@ static void __init early_scan(const void *fdt) address_cells[depth] = prop_by_name_u32(fdt, node, "#address-cells"); size_cells[depth] = prop_by_name_u32(fdt, node, "#size-cells"); - if ( strncmp(name, "memory", 6) == 0 ) - process_memory_node(fdt, node, - address_cells[depth-1], size_cells[depth-1]); + if ( node_matches(fdt, node, "memory") ) + process_memory_node(fdt, node, address_cells[depth-1], size_cells[depth-1]); } } -- 1.7.2.5
David Vrabel
2012-Mar-19 17:52 UTC
[PATCH 05/11] device tree: add device_tree_for_each_node()
From: David Vrabel <david.vrabel@citrix.com> Add device_tree_for_each_node() to iterate over all nodes in a flat device tree. Use this in device_tree_early_init(). Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- xen/common/device_tree.c | 72 ++++++++++++++++++++++++++--------------- xen/include/xen/device_tree.h | 8 ++++ 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 5329956..8f5d899 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -68,7 +68,43 @@ static u32 __init prop_by_name_u32(const void *fdt, int node, return fdt32_to_cpu(*(uint32_t*)prop->data); } +#define MAX_DEPTH 16 + +/** + * device_tree_for_each_node - iterate over all device tree nodes + * @fdt: flat device tree. + * @func: function to call for each node. + * @data: data to pass to @func. + */ +int device_tree_for_each_node(const void *fdt, + device_tree_node_func func, void *data) +{ + int node; + int depth; + u32 address_cells[MAX_DEPTH]; + u32 size_cells[MAX_DEPTH]; + int ret; + + for ( node = 0, depth = 0; + node >=0 && depth >= 0; + node = fdt_next_node(fdt, node, &depth) ) + { + if ( depth >= MAX_DEPTH ) + continue; + + address_cells[depth] = prop_by_name_u32(fdt, node, "#address-cells"); + size_cells[depth] = prop_by_name_u32(fdt, node, "#size-cells"); + + ret = func(fdt, node, fdt_get_name(fdt, node, NULL), depth, + address_cells[depth-1], size_cells[depth-1], data); + if ( ret < 0 ) + return ret; + } + return 0; +} + static void __init process_memory_node(const void *fdt, int node, + const char *name, u32 address_cells, u32 size_cells) { const struct fdt_property *prop; @@ -81,15 +117,14 @@ static void __init process_memory_node(const void *fdt, int node, if ( address_cells < 1 || size_cells < 1 ) { early_printk("fdt: node `%s'': invalid #address-cells or #size-cells", - fdt_get_name(fdt, node, NULL)); + name); return; } prop = fdt_get_property(fdt, node, "reg", NULL); if ( !prop ) { - early_printk("fdt: node `%s'': missing `reg'' property\n", - fdt_get_name(fdt, node, NULL)); + early_printk("fdt: node `%s'': missing `reg'' property\n", name); return; } @@ -106,30 +141,15 @@ static void __init process_memory_node(const void *fdt, int node, } } -#define MAX_DEPTH 16 - -static void __init early_scan(const void *fdt) +static int __init early_scan_node(const void *fdt, + int node, const char *name, int depth, + u32 address_cells, u32 size_cells, + void *data) { - int node; - int depth; - u32 address_cells[MAX_DEPTH]; - u32 size_cells[MAX_DEPTH]; - - for ( node = 0; depth >= 0; node = fdt_next_node(fdt, node, &depth) ) - { - if ( depth >= MAX_DEPTH ) - { - early_printk("fdt: node ''%s'': nested too deep\n", - fdt_get_name(fdt, node, NULL)); - continue; - } + if ( node_matches(fdt, node, "memory") ) + process_memory_node(fdt, node, name, address_cells, size_cells); - address_cells[depth] = prop_by_name_u32(fdt, node, "#address-cells"); - size_cells[depth] = prop_by_name_u32(fdt, node, "#size-cells"); - - if ( node_matches(fdt, node, "memory") ) - process_memory_node(fdt, node, address_cells[depth-1], size_cells[depth-1]); - } + return 0; } static void __init early_print_info(void) @@ -157,7 +177,7 @@ size_t __init device_tree_early_init(const void *fdt) if ( ret < 0 ) early_panic("No valid device tree\n"); - early_scan(fdt); + device_tree_for_each_node((void *)fdt, early_scan_node, NULL); early_print_info(); return fdt_totalsize(fdt); diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 28a3dee..505f3e3 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -28,10 +28,18 @@ struct dt_early_info { struct dt_mem_info mem; }; +typedef int (*device_tree_node_func)(const void *fdt, + int node, const char *name, int depth, + u32 address_cells, u32 size_cells, + void *data); + extern struct dt_early_info early_info; extern void *device_tree_flattened; size_t device_tree_early_init(const void *fdt); paddr_t device_tree_get_xen_paddr(void); +int device_tree_for_each_node(const void *fdt, + device_tree_node_func func, void *data); + #endif -- 1.7.2.5
David Vrabel
2012-Mar-19 17:52 UTC
[PATCH 06/11] device tree: add device_tree_dump() to print a flat device tree
From: David Vrabel <david.vrabel@citrix.com> Add a device_tree_dump() function which prints to main structure and properties names of a flat device tree (but not the properties values yet). This will be useful for debugging problems with the device tree generated for dom0. Signed-off-by: David Vrabel <david.vrabel@citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- xen/common/device_tree.c | 38 ++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 1 + 2 files changed, 39 insertions(+), 0 deletions(-) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 8f5d899..d4b1556 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -103,6 +103,44 @@ int device_tree_for_each_node(const void *fdt, return 0; } +static int dump_node(const void *fdt, int node, const char *name, int depth, + u32 address_cells, u32 size_cells, void *data) +{ + char prefix[2*MAX_DEPTH + 1] = ""; + int i; + int prop; + + for ( i = 0; i < depth; i++ ) + safe_strcat(prefix, " "); + + if ( name[0] == ''\0'' ) + name = "/"; + printk("%s%s:\n", prefix, name); + + for ( prop = fdt_first_property_offset(fdt, node); + prop >= 0; + prop = fdt_next_property_offset(fdt, prop) ) + { + const struct fdt_property *p; + + p = fdt_get_property_by_offset(fdt, prop, NULL); + + printk("%s %s\n", prefix, fdt_string(fdt, fdt32_to_cpu(p->nameoff))); + } + + return 0; +} + +/** + * device_tree_dump - print a text representation of a device tree + * @fdt: flat device tree to print + */ +void device_tree_dump(const void *fdt) +{ + device_tree_for_each_node(fdt, dump_node, NULL); +} + + static void __init process_memory_node(const void *fdt, int node, const char *name, u32 address_cells, u32 size_cells) diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 505f3e3..b91b39f 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -41,5 +41,6 @@ paddr_t device_tree_get_xen_paddr(void); int device_tree_for_each_node(const void *fdt, device_tree_node_func func, void *data); +void device_tree_dump(const void *fdt); #endif -- 1.7.2.5
David Vrabel
2012-Mar-19 17:52 UTC
[PATCH 07/11] arm: remove the hack for loading vmlinux images
From: David Vrabel <david.vrabel@citrix.com> Don''t adjust the RAM location/size when loading an ELF for dom0. It was vmlinux specific and no longer needed because Linux can be loaded from a zImage. Support for loading ELF images is not removed as it may be useful for loading things other than the Linux kernel. This also makes preparing the device tree for dom0 easier. Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- xen/arch/arm/kernel.c | 11 ++--------- 1 files changed, 2 insertions(+), 9 deletions(-) diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index 71a204d..dd757e5 100644 --- a/xen/arch/arm/kernel.c +++ b/xen/arch/arm/kernel.c @@ -91,7 +91,6 @@ static void kernel_zimage_load(struct kernel_info *info) /** * Check the image is a zImage and return the load address and length - * (FIXME: including any appended DTB). */ static int kernel_try_zimage_prepare(struct kernel_info *info) { @@ -117,8 +116,6 @@ static int kernel_try_zimage_prepare(struct kernel_info *info) end += be32_to_cpu(dtb_hdr.total_size); } - /* FIXME: get RAM location from appended DTB (if there is one)? */ - /* * If start is zero, the zImage is position independent -- load it * at 32k from start of RAM. @@ -166,13 +163,9 @@ static int kernel_try_elf_prepare(struct kernel_info *info) return rc; /* - * FIXME: can the ELF header be used to find the physical address - * to load the image to? Instead of making virt == phys by - * relocating the guest''s RAM. + * TODO: can the ELF header be used to find the physical address + * to load the image to? Instead of assuming virt == phys. */ - info->ram_start = 0xc0000000; - info->ram_end = 0xc8000000; - info->entry = info->elf.parms.virt_entry; info->load = kernel_elf_load; -- 1.7.2.5
David Vrabel
2012-Mar-19 17:52 UTC
[PATCH 08/11] device tree, arm: supply a flat device tree to dom0
From: David Vrabel <david.vrabel@citrix.com> Build a flat device tree for dom0 based on the one supplied to Xen. The following changes are made: * In the /chosen node, the xen,dom0-bootargs parameter is renamed to bootargs. * In all memory nodes, the reg parameters are adjusted to reflect the amount of memory dom0 can use. The p2m is updated using this info. Support for passing ATAGS to dom0 is removed. Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- xen/arch/arm/Makefile | 2 + xen/arch/arm/domain_build.c | 253 ++++++++++++++++++++++++++++++++++------- xen/arch/arm/kernel.c | 2 +- xen/arch/arm/kernel.h | 8 +- xen/common/device_tree.c | 47 +++++--- xen/include/xen/device_tree.h | 8 ++ 6 files changed, 260 insertions(+), 60 deletions(-) diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index d5afb6b..8d6edf5 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -27,6 +27,8 @@ obj-y += vtimer.o #obj-bin-y += ....o +CFLAGS += -I../../common/libfdt + ifdef CONFIG_DTB_FILE obj-y += dtb.o AFLAGS += -DCONFIG_DTB_FILE=\"$(CONFIG_DTB_FILE)\" diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 15632f7..963f1cf 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -6,6 +6,10 @@ #include <xen/sched.h> #include <asm/irq.h> #include <asm/regs.h> +#include <xen/errno.h> +#include <xen/device_tree.h> +#include <xen/libfdt/libfdt.h> +#include <xen/guest_access.h> #include "gic.h" #include "kernel.h" @@ -13,6 +17,12 @@ static unsigned int __initdata opt_dom0_max_vcpus; integer_param("dom0_max_vcpus", opt_dom0_max_vcpus); +/* + * Amount of extra space required to dom0''s device tree. No new nodes + * are added (yet) so no additional space is needed. + */ +#define DOM0_FDT_EXTRA_SIZE 0 + struct vcpu *__init alloc_dom0_vcpu0(void) { if ( opt_dom0_max_vcpus == 0 ) @@ -28,43 +38,207 @@ struct vcpu *__init alloc_dom0_vcpu0(void) return alloc_vcpu(dom0, 0, 0); } -extern void guest_mode_entry(void); +static void set_memory_reg(struct domain *d, struct kernel_info *kinfo, + const void *fdt, + const u32 *cell, int address_cells, int size_cells, + u32 *new_cell, int *len) +{ + int reg_size = (address_cells + size_cells) * sizeof(*cell); + int l; + u64 start; + u64 size; + + l = *len; + + while ( kinfo->unassigned_mem > 0 && l >= reg_size + && kinfo->mem.nr_banks < NR_MEM_BANKS ) + { + device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); + if ( size > kinfo->unassigned_mem ) + size = kinfo->unassigned_mem; + + device_tree_set_reg(&new_cell, address_cells, size_cells, start, size); + + printk("Populate P2M %#llx->%#llx\n", start, start + size); + p2m_populate_ram(d, start, start + size); + kinfo->mem.bank[kinfo->mem.nr_banks].start = start; + kinfo->mem.bank[kinfo->mem.nr_banks].size = size; + kinfo->mem.nr_banks++; + kinfo->unassigned_mem -= size; + + l -= reg_size; + } + + *len -= l; +} + +static int write_properties(struct domain *d, struct kernel_info *kinfo, + const void *fdt, + int node, const char *name, int depth, + u32 address_cells, u32 size_cells) +{ + int prop; + + for ( prop = fdt_first_property_offset(fdt, node); + prop >= 0; + prop = fdt_next_property_offset(fdt, prop) ) + { + const struct fdt_property *p; + const char *prop_name; + const char *prop_data; + int prop_len; + char *new_data = NULL; + + p = fdt_get_property_by_offset(fdt, prop, NULL); + prop_name = fdt_string(fdt, fdt32_to_cpu(p->nameoff)); + prop_data = p->data; + prop_len = fdt32_to_cpu(p->len); + + /* + * In chosen node: replace bootargs with value from + * xen,dom0-bootargs. + */ + if ( device_tree_node_matches(fdt, node, "chosen") ) + { + if ( strcmp(prop_name, "bootargs") == 0 ) + continue; + if ( strcmp(prop_name, "xen,dom0-bootargs") == 0 ) + prop_name = "bootargs"; + } + /* + * In a memory node: adjust reg property. + */ + else if ( device_tree_node_matches(fdt, node, "memory") ) + { + if ( strcmp(prop_name, "reg") == 0 ) + { + new_data = xzalloc_bytes(prop_len); + if ( new_data == NULL ) + return -ENOMEM; + + set_memory_reg(d, kinfo, fdt, + (u32 *)prop_data, address_cells, size_cells, + (u32 *)new_data, &prop_len); + prop_data = new_data; + } + } + + /* + * TODO: Should call map_mmio_regions() for all devices in the + * tree that have a "reg" parameter (except cpus). This + * requires looking into the parent node''s "ranges" property + * to translate the bus address in the "reg" value into + * physical addresses. Regions also need to be rounded up to + * whole pages. + */ + + fdt_property(kinfo->fdt, prop_name, prop_data, prop_len); + + xfree(new_data); + } + + if ( prop == -FDT_ERR_NOTFOUND ) + return 0; + return prop; +} -static void setup_linux_atag(paddr_t tags, paddr_t ram_s, paddr_t ram_e) +static int write_nodes(struct domain *d, struct kernel_info *kinfo, + const void *fdt) { - paddr_t ma = gvirt_to_maddr(tags); - void *map = map_domain_page(ma>>PAGE_SHIFT); - void *p = map + (tags & (PAGE_SIZE - 1)); - char cmdline[] = "earlyprintk=xenboot console=ttyAMA1 root=/dev/mmcblk0 debug rw"; + int node; + int depth = 0, last_depth = -1; + u32 address_cells[DEVICE_TREE_MAX_DEPTH]; + u32 size_cells[DEVICE_TREE_MAX_DEPTH]; + int ret; - /* not enough room on this page for all the tags */ - BUG_ON(PAGE_SIZE - (tags & (PAGE_SIZE - 1)) < 8 * sizeof(uint32_t)); + for ( node = 0, depth = 0; + node >= 0 && depth >= 0; + node = fdt_next_node(fdt, node, &depth) ) + { + const char *name; -#define TAG(type, val) *(type*)p = val; p+= sizeof(type) + name = fdt_get_name(fdt, node, NULL); - /* ATAG_CORE */ - TAG(uint32_t, 2); - TAG(uint32_t, 0x54410001); + if ( depth >= DEVICE_TREE_MAX_DEPTH ) + { + printk("warning: node `%s'' is nested too deep\n", name); + continue; + } - /* ATAG_MEM */ - TAG(uint32_t, 4); - TAG(uint32_t, 0x54410002); - TAG(uint32_t, (ram_e - ram_s) & 0xFFFFFFFF); - TAG(uint32_t, ram_s & 0xFFFFFFFF); + while ( last_depth-- >= depth ) + fdt_end_node(kinfo->fdt); - /* ATAG_CMDLINE */ - TAG(uint32_t, 2 + ((strlen(cmdline) + 4) >> 2)); - TAG(uint32_t, 0x54410009); - memcpy(p, cmdline, strlen(cmdline) + 1); - p += ((strlen(cmdline) + 4) >> 2) << 2; + address_cells[depth] = device_tree_get_u32(fdt, node, "#address-cells"); + size_cells[depth] = device_tree_get_u32(fdt, node, "#size-cells"); - /* ATAG_NONE */ - TAG(uint32_t, 0); - TAG(uint32_t, 0); + fdt_begin_node(kinfo->fdt, name); -#undef TAG + ret = write_properties(d, kinfo, fdt, node, name, depth, + address_cells[depth-1], size_cells[depth-1]); + if ( ret < 0 ) + return ret; - unmap_domain_page(map); + last_depth = depth; + } + + while ( last_depth-- >= 0 ) + fdt_end_node(kinfo->fdt); + + return 0; +} + +static int prepare_dtb(struct domain *d, struct kernel_info *kinfo) +{ + void *fdt; + int new_size; + int ret; + + fdt = device_tree_flattened; + + new_size = fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; + kinfo->fdt = xmalloc_bytes(new_size); + if ( kinfo->fdt == NULL ) + return -ENOMEM; + + ret = fdt_create(kinfo->fdt, new_size); + if ( ret < 0 ) + goto err; + + fdt_finish_reservemap(kinfo->fdt); + + ret = write_nodes(d, kinfo, fdt); + if ( ret < 0 ) + goto err; + + fdt_finish(kinfo->fdt); + + device_tree_dump(kinfo->fdt); + + /* + * Put the device tree at the beginning of the first bank. It + * must be below 4 GiB. + */ + kinfo->dtb_paddr = kinfo->mem.bank[0].start + 0x100; + if ( kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt) > (1ull << 32) ) + { + printk("Not enough memory below 4 GiB for the device tree."); + ret = -EINVAL; + goto err; + } + + return 0; + + err: + xfree(kinfo->fdt); + return ret; +} + +static void dtb_load(struct kernel_info *kinfo) +{ + void * __user dtb_virt = (void *)(u32)kinfo->dtb_paddr; + + raw_copy_to_guest(dtb_virt, kinfo->fdt, fdt_totalsize(kinfo->fdt)); + xfree(kinfo->fdt); } int construct_dom0(struct domain *d) @@ -82,22 +256,20 @@ int construct_dom0(struct domain *d) printk("*** LOADING DOMAIN 0 ***\n"); - /* 128M at 2G physical */ - /* TODO size and location from DT. */ - kinfo.ram_start = 0x80000000; - kinfo.ram_end = 0x88000000; + d->max_pages = ~0U; - rc = kernel_prepare(&kinfo); - if (rc < 0) + if ( (rc = p2m_alloc_table(d)) != 0 ) return rc; - d->max_pages = ~0U; + kinfo.unassigned_mem = 0x08000000; /* XXX */ - if ( (rc = p2m_alloc_table(d)) != 0 ) + rc = prepare_dtb(d, &kinfo); + if ( rc < 0 ) return rc; - printk("Populate P2M %#llx->%#llx\n", kinfo.ram_start, kinfo.ram_end); - p2m_populate_ram(d, kinfo.ram_start, kinfo.ram_end); + rc = kernel_prepare(&kinfo); + if ( rc < 0 ) + return rc; printk("Map CS2 MMIO regions 1:1 in the P2M %#llx->%#llx\n", 0x18000000ULL, 0x1BFFFFFFULL); map_mmio_regions(d, 0x18000000, 0x1BFFFFFF, 0x18000000); @@ -125,13 +297,12 @@ int construct_dom0(struct domain *d) /* Enable second stage translation */ WRITE_CP32(READ_CP32(HCR) | HCR_VM, HCR); isb(); - /* The following load uses domain''s p2m */ + /* The following loads use the domain''s p2m */ p2m_load_VTTBR(d); + dtb_load(&kinfo); kernel_load(&kinfo); - setup_linux_atag(kinfo.ram_start + 0x100, kinfo.ram_start, kinfo.ram_end); - clear_bit(_VPF_down, &v->pause_flags); memset(regs, 0, sizeof(*regs)); @@ -153,7 +324,7 @@ int construct_dom0(struct domain *d) regs->r0 = 0; /* SBZ */ regs->r1 = 2272; /* Machine NR: Versatile Express */ - regs->r2 = kinfo.ram_start + 0x100; /* ATAGS */ + regs->r2 = kinfo.dtb_paddr; WRITE_CP32(SCTLR_BASE, SCTLR); diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index dd757e5..130d488 100644 --- a/xen/arch/arm/kernel.c +++ b/xen/arch/arm/kernel.c @@ -121,7 +121,7 @@ static int kernel_try_zimage_prepare(struct kernel_info *info) * at 32k from start of RAM. */ if (start == 0) - info->zimage.load_addr = info->ram_start + 0x8000; + info->zimage.load_addr = info->mem.bank[0].start + 0x8000; else info->zimage.load_addr = start; info->zimage.len = end - start; diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h index 5caebe5..4533568 100644 --- a/xen/arch/arm/kernel.h +++ b/xen/arch/arm/kernel.h @@ -7,11 +7,15 @@ #define __ARCH_ARM_KERNEL_H__ #include <xen/libelf.h> +#include <xen/device_tree.h> struct kernel_info { + void *fdt; /* flat device tree */ + paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */ + struct dt_mem_info mem; + + paddr_t dtb_paddr; paddr_t entry; - paddr_t ram_start; - paddr_t ram_end; void *kernel_img; unsigned kernel_order; diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index d4b1556..715fbf6 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -23,7 +23,7 @@ struct dt_early_info __initdata early_info; void *device_tree_flattened; -static bool_t __init node_matches(const void *fdt, int node, const char *match) +bool_t device_tree_node_matches(const void *fdt, int node, const char *match) { const char *name; size_t match_len; @@ -48,16 +48,33 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val) } } -static void __init get_register(const u32 **cell, - u32 address_cells, u32 size_cells, - u64 *start, u64 *size) +void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells, + u64 *start, u64 *size) { get_val(cell, address_cells, start); get_val(cell, size_cells, size); } -static u32 __init prop_by_name_u32(const void *fdt, int node, - const char *prop_name) +static void set_val(u32 **cell, u32 cells, u64 val) +{ + u32 c = cells; + + while ( c-- ) + { + (*cell)[c] = cpu_to_fdt32(val); + val >>= 32; + } + (*cell) += cells; +} + +void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells, + u64 start, u64 size) +{ + set_val(cell, address_cells, start); + set_val(cell, size_cells, size); +} + +u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name) { const struct fdt_property *prop; @@ -68,8 +85,6 @@ static u32 __init prop_by_name_u32(const void *fdt, int node, return fdt32_to_cpu(*(uint32_t*)prop->data); } -#define MAX_DEPTH 16 - /** * device_tree_for_each_node - iterate over all device tree nodes * @fdt: flat device tree. @@ -81,19 +96,19 @@ int device_tree_for_each_node(const void *fdt, { int node; int depth; - u32 address_cells[MAX_DEPTH]; - u32 size_cells[MAX_DEPTH]; + u32 address_cells[DEVICE_TREE_MAX_DEPTH]; + u32 size_cells[DEVICE_TREE_MAX_DEPTH]; int ret; for ( node = 0, depth = 0; node >=0 && depth >= 0; node = fdt_next_node(fdt, node, &depth) ) { - if ( depth >= MAX_DEPTH ) + if ( depth >= DEVICE_TREE_MAX_DEPTH ) continue; - address_cells[depth] = prop_by_name_u32(fdt, node, "#address-cells"); - size_cells[depth] = prop_by_name_u32(fdt, node, "#size-cells"); + address_cells[depth] = device_tree_get_u32(fdt, node, "#address-cells"); + size_cells[depth] = device_tree_get_u32(fdt, node, "#size-cells"); ret = func(fdt, node, fdt_get_name(fdt, node, NULL), depth, address_cells[depth-1], size_cells[depth-1], data); @@ -106,7 +121,7 @@ int device_tree_for_each_node(const void *fdt, static int dump_node(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, void *data) { - char prefix[2*MAX_DEPTH + 1] = ""; + char prefix[2*DEVICE_TREE_MAX_DEPTH + 1] = ""; int i; int prop; @@ -172,7 +187,7 @@ static void __init process_memory_node(const void *fdt, int node, for ( i = 0; i < banks && early_info.mem.nr_banks < NR_MEM_BANKS; i++ ) { - get_register(&cell, address_cells, size_cells, &start, &size); + device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); early_info.mem.bank[early_info.mem.nr_banks].start = start; early_info.mem.bank[early_info.mem.nr_banks].size = size; early_info.mem.nr_banks++; @@ -184,7 +199,7 @@ static int __init early_scan_node(const void *fdt, u32 address_cells, u32 size_cells, void *data) { - if ( node_matches(fdt, node, "memory") ) + if ( device_tree_node_matches(fdt, node, "memory") ) process_memory_node(fdt, node, name, address_cells, size_cells); return 0; diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index b91b39f..510b5b4 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -12,6 +12,8 @@ #include <xen/types.h> +#define DEVICE_TREE_MAX_DEPTH 16 + #define NR_MEM_BANKS 8 struct membank { @@ -39,6 +41,12 @@ extern void *device_tree_flattened; size_t device_tree_early_init(const void *fdt); paddr_t device_tree_get_xen_paddr(void); +void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells, + u64 *start, u64 *size); +void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells, + u64 start, u64 size); +u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name); +bool_t device_tree_node_matches(const void *fdt, int node, const char *match); int device_tree_for_each_node(const void *fdt, device_tree_node_func func, void *data); void device_tree_dump(const void *fdt); -- 1.7.2.5
David Vrabel
2012-Mar-19 17:52 UTC
[PATCH 09/11] Allow cmdline_parse() to be used with const strings
From: David Vrabel <david.vrabel@citrix.com> Signed-off-by: David Vrabel <david.vrabel@citrix.com> Cc: Keir Fraser <keir@xen.org> --- xen/common/kernel.c | 2 +- xen/include/xen/lib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 88984d2..145b0b6 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -46,7 +46,7 @@ static void __init assign_integer_param( } } -void __init cmdline_parse(char *cmdline) +void __init cmdline_parse(const char *cmdline) { char opt[100], *optval, *optkey, *q; const char *p = cmdline; diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h index d6f9182..36b4c7f 100644 --- a/xen/include/xen/lib.h +++ b/xen/include/xen/lib.h @@ -56,7 +56,7 @@ do { \ struct domain; -void cmdline_parse(char *cmdline); +void cmdline_parse(const char *cmdline); int parse_bool(const char *s); /*#define DEBUG_TRACE_DUMP*/ -- 1.7.2.5
From: David Vrabel <david.vrabel@citrix.com> Use the /chosen node''s bootargs parameter for the Xen command line. Parse it early on before the serial console is setup. Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- xen/arch/arm/setup.c | 2 ++ xen/common/device_tree.c | 20 ++++++++++++++++++++ xen/include/xen/device_tree.h | 1 + 3 files changed, 23 insertions(+), 0 deletions(-) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 777f8fb..f89a1f7 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -152,6 +152,8 @@ void __init start_xen(unsigned long boot_phys_offset, + (atag_paddr & ((1 << SECOND_SHIFT) - 1)); fdt_size = device_tree_early_init(fdt); + cmdline_parse(device_tree_bootargs(fdt)); + setup_pagetables(boot_phys_offset); #ifdef EARLY_UART_ADDRESS diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 715fbf6..8fb6d46 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -118,6 +118,26 @@ int device_tree_for_each_node(const void *fdt, return 0; } +/** + * device_tree_bootargs - return the bootargs (the Xen command line) + * @fdt flat device tree. + */ +const char *device_tree_bootargs(const void *fdt) +{ + int node; + const struct fdt_property *prop; + + node = fdt_path_offset(fdt, "/chosen"); + if ( node < 0 ) + return NULL; + + prop = fdt_get_property(fdt, node, "bootargs", NULL); + if ( prop == NULL ) + return NULL; + + return prop->data; +} + static int dump_node(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, void *data) { diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 510b5b4..8e1626c 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -49,6 +49,7 @@ u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name); bool_t device_tree_node_matches(const void *fdt, int node, const char *match); int device_tree_for_each_node(const void *fdt, device_tree_node_func func, void *data); +const char *device_tree_bootargs(const void *fdt); void device_tree_dump(const void *fdt); #endif -- 1.7.2.5
From: David Vrabel <david.vrabel@citrix.com> Add a simple dom0_mem command line argument. It''s not as flexible as the x86 equivalent (the ''max'' and ''min'' prefixes are not supported). Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- xen/arch/arm/domain_build.c | 15 +++++++++++++-- 1 files changed, 13 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 963f1cf..cefd693 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -17,6 +17,17 @@ static unsigned int __initdata opt_dom0_max_vcpus; integer_param("dom0_max_vcpus", opt_dom0_max_vcpus); +#define DOM0_MEM_DEFAULT 0x8000000 /* 128 MiB */ +static u64 __initdata dom0_mem = DOM0_MEM_DEFAULT; + +static void __init parse_dom0_mem(const char *s) +{ + dom0_mem = parse_size_and_unit(s, &s); + if ( dom0_mem == 0 ) + dom0_mem = DOM0_MEM_DEFAULT; +} +custom_param("dom0_mem", parse_dom0_mem); + /* * Amount of extra space required to dom0''s device tree. No new nodes * are added (yet) so no additional space is needed. @@ -193,6 +204,8 @@ static int prepare_dtb(struct domain *d, struct kernel_info *kinfo) int new_size; int ret; + kinfo->unassigned_mem = dom0_mem; + fdt = device_tree_flattened; new_size = fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; @@ -261,8 +274,6 @@ int construct_dom0(struct domain *d) if ( (rc = p2m_alloc_table(d)) != 0 ) return rc; - kinfo.unassigned_mem = 0x08000000; /* XXX */ - rc = prepare_dtb(d, &kinfo); if ( rc < 0 ) return rc; -- 1.7.2.5
Keir Fraser
2012-Mar-19 17:54 UTC
Re: [PATCH 09/11] Allow cmdline_parse() to be used with const strings
On 19/03/2012 17:52, "David Vrabel" <david.vrabel@citrix.com> wrote:> From: David Vrabel <david.vrabel@citrix.com> > > Signed-off-by: David Vrabel <david.vrabel@citrix.com> > Cc: Keir Fraser <keir@xen.org>Acked-by: Keir Fraser <keir@xen.org>> --- > xen/common/kernel.c | 2 +- > xen/include/xen/lib.h | 2 +- > 2 files changed, 2 insertions(+), 2 deletions(-) > > diff --git a/xen/common/kernel.c b/xen/common/kernel.c > index 88984d2..145b0b6 100644 > --- a/xen/common/kernel.c > +++ b/xen/common/kernel.c > @@ -46,7 +46,7 @@ static void __init assign_integer_param( > } > } > > -void __init cmdline_parse(char *cmdline) > +void __init cmdline_parse(const char *cmdline) > { > char opt[100], *optval, *optkey, *q; > const char *p = cmdline; > diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h > index d6f9182..36b4c7f 100644 > --- a/xen/include/xen/lib.h > +++ b/xen/include/xen/lib.h > @@ -56,7 +56,7 @@ do { > \ > > struct domain; > > -void cmdline_parse(char *cmdline); > +void cmdline_parse(const char *cmdline); > int parse_bool(const char *s); > > /*#define DEBUG_TRACE_DUMP*/
Keir Fraser
2012-Mar-19 17:54 UTC
Re: [PATCH 02/11] MAINTAINERS: add device tree maintainer
On 19/03/2012 17:52, "David Vrabel" <david.vrabel@citrix.com> wrote:> From: David Vrabel <david.vrabel@citrix.com> > > Signed-off-by: David Vrabel <david.vrabel@citrix.com> > Cc: Keir Fraser <keir@xen.org>Acked-by: Keir Fraser <keir@xen.org>> --- > MAINTAINERS | 8 ++++++++ > 1 files changed, 8 insertions(+), 0 deletions(-) > > diff --git a/MAINTAINERS b/MAINTAINERS > index dfc76dd..c1d8696 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -111,6 +111,14 @@ M: Juergen Gross <juergen.gross@ts.fujitsu.com> > S: Supported > F: xen/common/cpupool.c > > +DEVICE TREE > +M: David Vrabel <david.vrabel@citrix.com> > +S: Supported > +F: xen/common/libfdt/ > +F: xen/common/device_tree.c > +F: xen/include/xen/libfdt/ > +F: xen/include/xen/device_tree.h > + > EFI > M: Jan Beulich <jbeulich@suse.com> > S: Supported
David Vrabel
2012-Mar-19 17:58 UTC
Re: [PATCH 01/11] libfdt: move headers to xen/include/xen/libfdt/
On 19/03/12 17:51, David Vrabel wrote:> From: David Vrabel <david.vrabel@citrix.com> > > Move the public libfdt headers to xen/include/xen/libfdt/ so CFLAGS > does need to be set to find them. This requires minor tweaks to one > of the headers imported from upstream. > > Signed-off-by: David Vrabel <david.vrabel@citrix.com>Sorry, forgot the -M option when generating this. The real diff is much more modest. 8<-------------------- [PATCH] libfdt: move headers to xen/include/xen/libfdt/ Move the public libfdt headers to xen/include/xen/libfdt/ so CFLAGS does need to be set to find them. This requires minor tweaks to one of the headers imported from upstream. Signed-off-by: David Vrabel <david.vrabel@citrix.com> --- xen/common/Makefile | 2 -- xen/common/device_tree.c | 3 +-- xen/common/libfdt/Makefile | 2 +- xen/{common => include/xen}/libfdt/fdt.h | 0 xen/{common => include/xen}/libfdt/libfdt.h | 4 ++-- xen/{common => include/xen}/libfdt/libfdt_env.h | 0 6 files changed, 4 insertions(+), 7 deletions(-) rename xen/{common => include/xen}/libfdt/fdt.h (100%) rename xen/{common => include/xen}/libfdt/libfdt.h (99%) rename xen/{common => include/xen}/libfdt/libfdt_env.h (100%) diff --git a/xen/common/Makefile b/xen/common/Makefile index 372b259..9f2e0d6 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -61,5 +61,3 @@ subdir-$(ia64) += hvm subdir-y += libelf subdir-$(HAS_DEVICE_TREE) += libfdt - -CFLAGS += -Ilibfdt diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index d50cb9c..140d342 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -14,13 +14,12 @@ #include <xen/device_tree.h> #include <xen/kernel.h> #include <xen/lib.h> +#include <xen/libfdt/libfdt.h> #include <xen/mm.h> #include <xen/stdarg.h> #include <xen/string.h> #include <asm/early_printk.h> -#include <libfdt.h> - struct dt_early_info __initdata early_info; void *device_tree_flattened; diff --git a/xen/common/libfdt/Makefile b/xen/common/libfdt/Makefile index 0e65bc0..7578fe9 100644 --- a/xen/common/libfdt/Makefile +++ b/xen/common/libfdt/Makefile @@ -2,4 +2,4 @@ include Makefile.libfdt obj-y += $(LIBFDT_OBJS) -CFLAGS += -I. +CFLAGS += -I$(BASEDIR)/include/xen/libfdt/ diff --git a/xen/common/libfdt/fdt.h b/xen/include/xen/libfdt/fdt.h similarity index 100% rename from xen/common/libfdt/fdt.h rename to xen/include/xen/libfdt/fdt.h diff --git a/xen/common/libfdt/libfdt.h b/xen/include/xen/libfdt/libfdt.h similarity index 99% rename from xen/common/libfdt/libfdt.h rename to xen/include/xen/libfdt/libfdt.h index 55f3eb3..6086047 100644 --- a/xen/common/libfdt/libfdt.h +++ b/xen/include/xen/libfdt/libfdt.h @@ -51,8 +51,8 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <libfdt_env.h> -#include <fdt.h> +#include <xen/libfdt/libfdt_env.h> +#include <xen/libfdt/fdt.h> #define FDT_FIRST_SUPPORTED_VERSION 0x10 #define FDT_LAST_SUPPORTED_VERSION 0x11 diff --git a/xen/common/libfdt/libfdt_env.h b/xen/include/xen/libfdt/libfdt_env.h similarity index 100% rename from xen/common/libfdt/libfdt_env.h rename to xen/include/xen/libfdt/libfdt_env.h -- 1.7.2.5
David Vrabel
2012-Mar-20 10:43 UTC
Re: [PATCH 08/11] device tree, arm: supply a flat device tree to dom0
On 19/03/12 17:52, David Vrabel wrote:> > Build a flat device tree for dom0 based on the one supplied to Xen. > The following changes are made: > [...] > --- a/xen/arch/arm/Makefile > +++ b/xen/arch/arm/Makefile > @@ -27,6 +27,8 @@ obj-y += vtimer.o > > #obj-bin-y += ....o > > +CFLAGS += -I../../common/libfdt > + > ifdef CONFIG_DTB_FILE > obj-y += dtb.o > AFLAGS += -DCONFIG_DTB_FILE=\"$(CONFIG_DTB_FILE)\"I accidentally left this hunk in after moving the libfdt headers. Ian, can you drop this hunk or should I respin the series? David
Ian Campbell
2012-Mar-20 10:52 UTC
Re: [PATCH 08/11] device tree, arm: supply a flat device tree to dom0
On Tue, 2012-03-20 at 10:43 +0000, David Vrabel wrote:> On 19/03/12 17:52, David Vrabel wrote: > > > > Build a flat device tree for dom0 based on the one supplied to Xen. > > The following changes are made: > > [...] > > --- a/xen/arch/arm/Makefile > > +++ b/xen/arch/arm/Makefile > > @@ -27,6 +27,8 @@ obj-y += vtimer.o > > > > #obj-bin-y += ....o > > > > +CFLAGS += -I../../common/libfdt > > + > > ifdef CONFIG_DTB_FILE > > obj-y += dtb.o > > AFLAGS += -DCONFIG_DTB_FILE=\"$(CONFIG_DTB_FILE)\" > > I accidentally left this hunk in after moving the libfdt headers. Ian, > can you drop this hunk or should I respin the series?I''ll nuke it while applying. thanks.
Ian Campbell
2012-Mar-22 11:12 UTC
Re: [PATCH 05/11] device tree: add device_tree_for_each_node()
On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote:> + for ( node = 0, depth = 0; > + node >=0 && depth >= 0; > + node = fdt_next_node(fdt, node, &depth) ) > + { > + if ( depth >= MAX_DEPTH ) > + continue;Perhaps we should fail and return an error here (which the caller can log with whatever facilities are available, e.g. early_printk or printk)? Silently just not walking a bit of the tree seem liable to lead to odd errors... Ian.
David Vrabel
2012-Mar-22 12:47 UTC
Re: [PATCH 05/11] device tree: add device_tree_for_each_node()
On 22/03/12 11:12, Ian Campbell wrote:> On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote: >> + for ( node = 0, depth = 0; >> + node >=0 && depth >= 0; >> + node = fdt_next_node(fdt, node, &depth) ) >> + { >> + if ( depth >= MAX_DEPTH ) >> + continue; > > Perhaps we should fail and return an error here (which the caller can > log with whatever facilities are available, e.g. early_printk or > printk)? Silently just not walking a bit of the tree seem liable to lead > to odd errors...Not sure about making it an error. May be best to make it a warning as at least in the early scan we want to try as hard as possible to get the memory and console info so we have a better chance of printing a diagnostic. I''m post a separate patch for this later because: a) it''s unlikely a device tree will have a depth of more than 16 (the current device tree for the model is only 5 levels deep); and b) there is a test and a warning message when generating dom0''s device tree (so unless your console and memory is 16 nodes deep you''ll get a message). David
Ian Campbell
2012-Mar-22 14:06 UTC
Re: [PATCH 08/11] device tree, arm: supply a flat device tree to dom0
On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote:> From: David Vrabel <david.vrabel@citrix.com> > > Build a flat device tree for dom0 based on the one supplied to Xen. > The following changes are made: > > * In the /chosen node, the xen,dom0-bootargs parameter is renamed to > bootargs. > > * In all memory nodes, the reg parameters are adjusted to reflect > the amount of memory dom0 can use. The p2m is updated using this > info. > > Support for passing ATAGS to dom0 is removed.With the series applied up to and including this patch my dom0 kernel fails to boot with: [ 0.000000] Linux version 3.2.0-rc5-arm-native+ (ianc@drall) (gcc version 4.6.0 (GCC) ) #77 Thu Mar 22 13:58:33 GMT 2012 [ 0.000000] CPU: ARMv7 Processor [410fc0f0] revision 0 (ARMv7), cr=10c53c7d [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache [ 0.000000] Machine: ARM Versatile Express, model: V2P-AEMv7A [ 0.000000] bootconsole [earlycon0] enabled [ 0.000000] Memory policy: ECC disabled, Data cache writeback [ 0.000000] Kernel panic - not syncing: ERROR: Failed to allocate 0x1000 bytes below 0x0. [ 0.000000] [ 0.000000] [<c000d64c>] (unwind_backtrace+0x0/0xe0) from [<c0273558>] (panic+0x50/0x17c) [ 0.000000] [<c0273558>] (panic+0x50/0x17c) from [<c032ff04>] (memblock_alloc_base+0x2c/0x34) [ 0.000000] [<c032ff04>] (memblock_alloc_base+0x2c/0x34) from [<c0329f30>] (early_alloc.constprop.3+0x10/0x28) [ 0.000000] [<c0329f30>] (early_alloc.constprop.3+0x10/0x28) from [<c032a8c0>] (paging_init+0x48c/0x628) [ 0.000000] [<c032a8c0>] (paging_init+0x48c/0x628) from [<c0328678>] (setup_arch+0x508/0x7ac) [ 0.000000] [<c0328678>] (setup_arch+0x508/0x7ac) from [<c03254dc>] (start_kernel+0x6c/0x2c0) [ 0.000000] [<c03254dc>] (start_kernel+0x6c/0x2c0) from [<80008048>] (0x80008048) I''m guessing that the memory isn''t being passed in correctly?> > Signed-off-by: David Vrabel <david.vrabel@citrix.com> > --- > xen/arch/arm/Makefile | 2 + > xen/arch/arm/domain_build.c | 253 ++++++++++++++++++++++++++++++++++------- > xen/arch/arm/kernel.c | 2 +- > xen/arch/arm/kernel.h | 8 +- > xen/common/device_tree.c | 47 +++++--- > xen/include/xen/device_tree.h | 8 ++ > 6 files changed, 260 insertions(+), 60 deletions(-) > > diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile > index d5afb6b..8d6edf5 100644 > --- a/xen/arch/arm/Makefile > +++ b/xen/arch/arm/Makefile > @@ -27,6 +27,8 @@ obj-y += vtimer.o > > #obj-bin-y += ....o > > +CFLAGS += -I../../common/libfdt > + > ifdef CONFIG_DTB_FILE > obj-y += dtb.o > AFLAGS += -DCONFIG_DTB_FILE=\"$(CONFIG_DTB_FILE)\" > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > index 15632f7..963f1cf 100644 > --- a/xen/arch/arm/domain_build.c > +++ b/xen/arch/arm/domain_build.c > @@ -6,6 +6,10 @@ > #include <xen/sched.h> > #include <asm/irq.h> > #include <asm/regs.h> > +#include <xen/errno.h> > +#include <xen/device_tree.h> > +#include <xen/libfdt/libfdt.h> > +#include <xen/guest_access.h> > > #include "gic.h" > #include "kernel.h" > @@ -13,6 +17,12 @@ > static unsigned int __initdata opt_dom0_max_vcpus; > integer_param("dom0_max_vcpus", opt_dom0_max_vcpus); > > +/* > + * Amount of extra space required to dom0''s device tree. No new nodes > + * are added (yet) so no additional space is needed. > + */ > +#define DOM0_FDT_EXTRA_SIZE 0 > + > struct vcpu *__init alloc_dom0_vcpu0(void) > { > if ( opt_dom0_max_vcpus == 0 ) > @@ -28,43 +38,207 @@ struct vcpu *__init alloc_dom0_vcpu0(void) > return alloc_vcpu(dom0, 0, 0); > } > > -extern void guest_mode_entry(void); > +static void set_memory_reg(struct domain *d, struct kernel_info *kinfo, > + const void *fdt, > + const u32 *cell, int address_cells, int size_cells, > + u32 *new_cell, int *len) > +{ > + int reg_size = (address_cells + size_cells) * sizeof(*cell); > + int l; > + u64 start; > + u64 size; > + > + l = *len; > + > + while ( kinfo->unassigned_mem > 0 && l >= reg_size > + && kinfo->mem.nr_banks < NR_MEM_BANKS ) > + { > + device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); > + if ( size > kinfo->unassigned_mem ) > + size = kinfo->unassigned_mem; > + > + device_tree_set_reg(&new_cell, address_cells, size_cells, start, size); > + > + printk("Populate P2M %#llx->%#llx\n", start, start + size); > + p2m_populate_ram(d, start, start + size); > + kinfo->mem.bank[kinfo->mem.nr_banks].start = start; > + kinfo->mem.bank[kinfo->mem.nr_banks].size = size; > + kinfo->mem.nr_banks++; > + kinfo->unassigned_mem -= size; > + > + l -= reg_size; > + } > + > + *len -= l; > +} > + > +static int write_properties(struct domain *d, struct kernel_info *kinfo, > + const void *fdt, > + int node, const char *name, int depth, > + u32 address_cells, u32 size_cells) > +{ > + int prop; > + > + for ( prop = fdt_first_property_offset(fdt, node); > + prop >= 0; > + prop = fdt_next_property_offset(fdt, prop) ) > + { > + const struct fdt_property *p; > + const char *prop_name; > + const char *prop_data; > + int prop_len; > + char *new_data = NULL; > + > + p = fdt_get_property_by_offset(fdt, prop, NULL); > + prop_name = fdt_string(fdt, fdt32_to_cpu(p->nameoff)); > + prop_data = p->data; > + prop_len = fdt32_to_cpu(p->len); > + > + /* > + * In chosen node: replace bootargs with value from > + * xen,dom0-bootargs. > + */ > + if ( device_tree_node_matches(fdt, node, "chosen") ) > + { > + if ( strcmp(prop_name, "bootargs") == 0 ) > + continue; > + if ( strcmp(prop_name, "xen,dom0-bootargs") == 0 ) > + prop_name = "bootargs"; > + } > + /* > + * In a memory node: adjust reg property. > + */ > + else if ( device_tree_node_matches(fdt, node, "memory") ) > + { > + if ( strcmp(prop_name, "reg") == 0 ) > + { > + new_data = xzalloc_bytes(prop_len); > + if ( new_data == NULL ) > + return -ENOMEM; > + > + set_memory_reg(d, kinfo, fdt, > + (u32 *)prop_data, address_cells, size_cells, > + (u32 *)new_data, &prop_len); > + prop_data = new_data; > + } > + } > + > + /* > + * TODO: Should call map_mmio_regions() for all devices in the > + * tree that have a "reg" parameter (except cpus). This > + * requires looking into the parent node''s "ranges" property > + * to translate the bus address in the "reg" value into > + * physical addresses. Regions also need to be rounded up to > + * whole pages. > + */ > + > + fdt_property(kinfo->fdt, prop_name, prop_data, prop_len); > + > + xfree(new_data); > + } > + > + if ( prop == -FDT_ERR_NOTFOUND ) > + return 0; > + return prop; > +} > > -static void setup_linux_atag(paddr_t tags, paddr_t ram_s, paddr_t ram_e) > +static int write_nodes(struct domain *d, struct kernel_info *kinfo, > + const void *fdt) > { > - paddr_t ma = gvirt_to_maddr(tags); > - void *map = map_domain_page(ma>>PAGE_SHIFT); > - void *p = map + (tags & (PAGE_SIZE - 1)); > - char cmdline[] = "earlyprintk=xenboot console=ttyAMA1 root=/dev/mmcblk0 debug rw"; > + int node; > + int depth = 0, last_depth = -1; > + u32 address_cells[DEVICE_TREE_MAX_DEPTH]; > + u32 size_cells[DEVICE_TREE_MAX_DEPTH]; > + int ret; > > - /* not enough room on this page for all the tags */ > - BUG_ON(PAGE_SIZE - (tags & (PAGE_SIZE - 1)) < 8 * sizeof(uint32_t)); > + for ( node = 0, depth = 0; > + node >= 0 && depth >= 0; > + node = fdt_next_node(fdt, node, &depth) ) > + { > + const char *name; > > -#define TAG(type, val) *(type*)p = val; p+= sizeof(type) > + name = fdt_get_name(fdt, node, NULL); > > - /* ATAG_CORE */ > - TAG(uint32_t, 2); > - TAG(uint32_t, 0x54410001); > + if ( depth >= DEVICE_TREE_MAX_DEPTH ) > + { > + printk("warning: node `%s'' is nested too deep\n", name); > + continue; > + } > > - /* ATAG_MEM */ > - TAG(uint32_t, 4); > - TAG(uint32_t, 0x54410002); > - TAG(uint32_t, (ram_e - ram_s) & 0xFFFFFFFF); > - TAG(uint32_t, ram_s & 0xFFFFFFFF); > + while ( last_depth-- >= depth ) > + fdt_end_node(kinfo->fdt); > > - /* ATAG_CMDLINE */ > - TAG(uint32_t, 2 + ((strlen(cmdline) + 4) >> 2)); > - TAG(uint32_t, 0x54410009); > - memcpy(p, cmdline, strlen(cmdline) + 1); > - p += ((strlen(cmdline) + 4) >> 2) << 2; > + address_cells[depth] = device_tree_get_u32(fdt, node, "#address-cells"); > + size_cells[depth] = device_tree_get_u32(fdt, node, "#size-cells"); > > - /* ATAG_NONE */ > - TAG(uint32_t, 0); > - TAG(uint32_t, 0); > + fdt_begin_node(kinfo->fdt, name); > > -#undef TAG > + ret = write_properties(d, kinfo, fdt, node, name, depth, > + address_cells[depth-1], size_cells[depth-1]); > + if ( ret < 0 ) > + return ret; > > - unmap_domain_page(map); > + last_depth = depth; > + } > + > + while ( last_depth-- >= 0 ) > + fdt_end_node(kinfo->fdt); > + > + return 0; > +} > + > +static int prepare_dtb(struct domain *d, struct kernel_info *kinfo) > +{ > + void *fdt; > + int new_size; > + int ret; > + > + fdt = device_tree_flattened; > + > + new_size = fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; > + kinfo->fdt = xmalloc_bytes(new_size); > + if ( kinfo->fdt == NULL ) > + return -ENOMEM; > + > + ret = fdt_create(kinfo->fdt, new_size); > + if ( ret < 0 ) > + goto err; > + > + fdt_finish_reservemap(kinfo->fdt); > + > + ret = write_nodes(d, kinfo, fdt); > + if ( ret < 0 ) > + goto err; > + > + fdt_finish(kinfo->fdt); > + > + device_tree_dump(kinfo->fdt); > + > + /* > + * Put the device tree at the beginning of the first bank. It > + * must be below 4 GiB. > + */ > + kinfo->dtb_paddr = kinfo->mem.bank[0].start + 0x100; > + if ( kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt) > (1ull << 32) ) > + { > + printk("Not enough memory below 4 GiB for the device tree."); > + ret = -EINVAL; > + goto err; > + } > + > + return 0; > + > + err: > + xfree(kinfo->fdt); > + return ret; > +} > + > +static void dtb_load(struct kernel_info *kinfo) > +{ > + void * __user dtb_virt = (void *)(u32)kinfo->dtb_paddr; > + > + raw_copy_to_guest(dtb_virt, kinfo->fdt, fdt_totalsize(kinfo->fdt)); > + xfree(kinfo->fdt); > } > > int construct_dom0(struct domain *d) > @@ -82,22 +256,20 @@ int construct_dom0(struct domain *d) > > printk("*** LOADING DOMAIN 0 ***\n"); > > - /* 128M at 2G physical */ > - /* TODO size and location from DT. */ > - kinfo.ram_start = 0x80000000; > - kinfo.ram_end = 0x88000000; > + d->max_pages = ~0U; > > - rc = kernel_prepare(&kinfo); > - if (rc < 0) > + if ( (rc = p2m_alloc_table(d)) != 0 ) > return rc; > > - d->max_pages = ~0U; > + kinfo.unassigned_mem = 0x08000000; /* XXX */ > > - if ( (rc = p2m_alloc_table(d)) != 0 ) > + rc = prepare_dtb(d, &kinfo); > + if ( rc < 0 ) > return rc; > > - printk("Populate P2M %#llx->%#llx\n", kinfo.ram_start, kinfo.ram_end); > - p2m_populate_ram(d, kinfo.ram_start, kinfo.ram_end); > + rc = kernel_prepare(&kinfo); > + if ( rc < 0 ) > + return rc; > > printk("Map CS2 MMIO regions 1:1 in the P2M %#llx->%#llx\n", 0x18000000ULL, 0x1BFFFFFFULL); > map_mmio_regions(d, 0x18000000, 0x1BFFFFFF, 0x18000000); > @@ -125,13 +297,12 @@ int construct_dom0(struct domain *d) > /* Enable second stage translation */ > WRITE_CP32(READ_CP32(HCR) | HCR_VM, HCR); isb(); > > - /* The following load uses domain''s p2m */ > + /* The following loads use the domain''s p2m */ > p2m_load_VTTBR(d); > > + dtb_load(&kinfo); > kernel_load(&kinfo); > > - setup_linux_atag(kinfo.ram_start + 0x100, kinfo.ram_start, kinfo.ram_end); > - > clear_bit(_VPF_down, &v->pause_flags); > > memset(regs, 0, sizeof(*regs)); > @@ -153,7 +324,7 @@ int construct_dom0(struct domain *d) > > regs->r0 = 0; /* SBZ */ > regs->r1 = 2272; /* Machine NR: Versatile Express */ > - regs->r2 = kinfo.ram_start + 0x100; /* ATAGS */ > + regs->r2 = kinfo.dtb_paddr; > > WRITE_CP32(SCTLR_BASE, SCTLR); > > diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c > index dd757e5..130d488 100644 > --- a/xen/arch/arm/kernel.c > +++ b/xen/arch/arm/kernel.c > @@ -121,7 +121,7 @@ static int kernel_try_zimage_prepare(struct kernel_info *info) > * at 32k from start of RAM. > */ > if (start == 0) > - info->zimage.load_addr = info->ram_start + 0x8000; > + info->zimage.load_addr = info->mem.bank[0].start + 0x8000; > else > info->zimage.load_addr = start; > info->zimage.len = end - start; > diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h > index 5caebe5..4533568 100644 > --- a/xen/arch/arm/kernel.h > +++ b/xen/arch/arm/kernel.h > @@ -7,11 +7,15 @@ > #define __ARCH_ARM_KERNEL_H__ > > #include <xen/libelf.h> > +#include <xen/device_tree.h> > > struct kernel_info { > + void *fdt; /* flat device tree */ > + paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */ > + struct dt_mem_info mem; > + > + paddr_t dtb_paddr; > paddr_t entry; > - paddr_t ram_start; > - paddr_t ram_end; > > void *kernel_img; > unsigned kernel_order; > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > index d4b1556..715fbf6 100644 > --- a/xen/common/device_tree.c > +++ b/xen/common/device_tree.c > @@ -23,7 +23,7 @@ > struct dt_early_info __initdata early_info; > void *device_tree_flattened; > > -static bool_t __init node_matches(const void *fdt, int node, const char *match) > +bool_t device_tree_node_matches(const void *fdt, int node, const char *match) > { > const char *name; > size_t match_len; > @@ -48,16 +48,33 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val) > } > } > > -static void __init get_register(const u32 **cell, > - u32 address_cells, u32 size_cells, > - u64 *start, u64 *size) > +void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells, > + u64 *start, u64 *size) > { > get_val(cell, address_cells, start); > get_val(cell, size_cells, size); > } > > -static u32 __init prop_by_name_u32(const void *fdt, int node, > - const char *prop_name) > +static void set_val(u32 **cell, u32 cells, u64 val) > +{ > + u32 c = cells; > + > + while ( c-- ) > + { > + (*cell)[c] = cpu_to_fdt32(val); > + val >>= 32; > + } > + (*cell) += cells; > +} > + > +void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells, > + u64 start, u64 size) > +{ > + set_val(cell, address_cells, start); > + set_val(cell, size_cells, size); > +} > + > +u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name) > { > const struct fdt_property *prop; > > @@ -68,8 +85,6 @@ static u32 __init prop_by_name_u32(const void *fdt, int node, > return fdt32_to_cpu(*(uint32_t*)prop->data); > } > > -#define MAX_DEPTH 16 > - > /** > * device_tree_for_each_node - iterate over all device tree nodes > * @fdt: flat device tree. > @@ -81,19 +96,19 @@ int device_tree_for_each_node(const void *fdt, > { > int node; > int depth; > - u32 address_cells[MAX_DEPTH]; > - u32 size_cells[MAX_DEPTH]; > + u32 address_cells[DEVICE_TREE_MAX_DEPTH]; > + u32 size_cells[DEVICE_TREE_MAX_DEPTH]; > int ret; > > for ( node = 0, depth = 0; > node >=0 && depth >= 0; > node = fdt_next_node(fdt, node, &depth) ) > { > - if ( depth >= MAX_DEPTH ) > + if ( depth >= DEVICE_TREE_MAX_DEPTH ) > continue; > > - address_cells[depth] = prop_by_name_u32(fdt, node, "#address-cells"); > - size_cells[depth] = prop_by_name_u32(fdt, node, "#size-cells"); > + address_cells[depth] = device_tree_get_u32(fdt, node, "#address-cells"); > + size_cells[depth] = device_tree_get_u32(fdt, node, "#size-cells"); > > ret = func(fdt, node, fdt_get_name(fdt, node, NULL), depth, > address_cells[depth-1], size_cells[depth-1], data); > @@ -106,7 +121,7 @@ int device_tree_for_each_node(const void *fdt, > static int dump_node(const void *fdt, int node, const char *name, int depth, > u32 address_cells, u32 size_cells, void *data) > { > - char prefix[2*MAX_DEPTH + 1] = ""; > + char prefix[2*DEVICE_TREE_MAX_DEPTH + 1] = ""; > int i; > int prop; > > @@ -172,7 +187,7 @@ static void __init process_memory_node(const void *fdt, int node, > > for ( i = 0; i < banks && early_info.mem.nr_banks < NR_MEM_BANKS; i++ ) > { > - get_register(&cell, address_cells, size_cells, &start, &size); > + device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); > early_info.mem.bank[early_info.mem.nr_banks].start = start; > early_info.mem.bank[early_info.mem.nr_banks].size = size; > early_info.mem.nr_banks++; > @@ -184,7 +199,7 @@ static int __init early_scan_node(const void *fdt, > u32 address_cells, u32 size_cells, > void *data) > { > - if ( node_matches(fdt, node, "memory") ) > + if ( device_tree_node_matches(fdt, node, "memory") ) > process_memory_node(fdt, node, name, address_cells, size_cells); > > return 0; > diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h > index b91b39f..510b5b4 100644 > --- a/xen/include/xen/device_tree.h > +++ b/xen/include/xen/device_tree.h > @@ -12,6 +12,8 @@ > > #include <xen/types.h> > > +#define DEVICE_TREE_MAX_DEPTH 16 > + > #define NR_MEM_BANKS 8 > > struct membank { > @@ -39,6 +41,12 @@ extern void *device_tree_flattened; > size_t device_tree_early_init(const void *fdt); > paddr_t device_tree_get_xen_paddr(void); > > +void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells, > + u64 *start, u64 *size); > +void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells, > + u64 start, u64 size); > +u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name); > +bool_t device_tree_node_matches(const void *fdt, int node, const char *match); > int device_tree_for_each_node(const void *fdt, > device_tree_node_func func, void *data); > void device_tree_dump(const void *fdt); > -- > 1.7.2.5 >
Ian Campbell
2012-Mar-22 14:22 UTC
Re: [PATCH 10/11] arm: use bootargs for the command line
On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote:> From: David Vrabel <david.vrabel@citrix.com> > > Use the /chosen node''s bootargs parameter for the Xen command line. > Parse it early on before the serial console is setup. > > Signed-off-by: David Vrabel <david.vrabel@citrix.com>With this my hypervisor hangs after: - UART enabled - - CPU 00000000 booting - - Started in Secure state - - Entering Hyp mode - - Setting up control registers - - Turning on paging - - Ready - RAM: 0000000080000000 - 00000000ffffffff I''m going to try and apply 1..7 and 9. Skipping 8, 10 and 11. Ian.
David Vrabel
2012-Mar-22 14:27 UTC
Re: [PATCH 08/11] device tree, arm: supply a flat device tree to dom0
On 22/03/12 14:06, Ian Campbell wrote:> On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote: >> From: David Vrabel <david.vrabel@citrix.com> >> >> Build a flat device tree for dom0 based on the one supplied to Xen. >> The following changes are made: >> >> * In the /chosen node, the xen,dom0-bootargs parameter is renamed to >> bootargs. >> >> * In all memory nodes, the reg parameters are adjusted to reflect >> the amount of memory dom0 can use. The p2m is updated using this >> info. >> >> Support for passing ATAGS to dom0 is removed. > > With the series applied up to and including this patch my dom0 kernel > fails to boot with: > [ 0.000000] Linux version 3.2.0-rc5-arm-native+ (ianc@drall) (gcc version 4.6.0 (GCC) ) #77 Thu Mar 22 13:58:33 GMT 2012 > [ 0.000000] CPU: ARMv7 Processor [410fc0f0] revision 0 (ARMv7), cr=10c53c7d > [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache > [ 0.000000] Machine: ARM Versatile Express, model: V2P-AEMv7A > [ 0.000000] bootconsole [earlycon0] enabled > [ 0.000000] Memory policy: ECC disabled, Data cache writeback > [ 0.000000] Kernel panic - not syncing: ERROR: Failed to allocate 0x1000 bytes below 0x0. > [ 0.000000] > [ 0.000000] [<c000d64c>] (unwind_backtrace+0x0/0xe0) from [<c0273558>] (panic+0x50/0x17c) > [ 0.000000] [<c0273558>] (panic+0x50/0x17c) from [<c032ff04>] (memblock_alloc_base+0x2c/0x34) > [ 0.000000] [<c032ff04>] (memblock_alloc_base+0x2c/0x34) from [<c0329f30>] (early_alloc.constprop.3+0x10/0x28) > [ 0.000000] [<c0329f30>] (early_alloc.constprop.3+0x10/0x28) from [<c032a8c0>] (paging_init+0x48c/0x628) > [ 0.000000] [<c032a8c0>] (paging_init+0x48c/0x628) from [<c0328678>] (setup_arch+0x508/0x7ac) > [ 0.000000] [<c0328678>] (setup_arch+0x508/0x7ac) from [<c03254dc>] (start_kernel+0x6c/0x2c0) > [ 0.000000] [<c03254dc>] (start_kernel+0x6c/0x2c0) from [<80008048>] (0x80008048) > > I''m guessing that the memory isn''t being passed in correctly?This was with a kernel with ARM_DTB_APPENDED and ARM_ATAG_DTB_COMPAT enabled. I would have thought it ought to work but the kernel must be getting confused and mangling the device tree someone. I''ll look into it. David
Ian Campbell
2012-Mar-22 14:30 UTC
Re: [PATCH 10/11] arm: use bootargs for the command line
On Thu, 2012-03-22 at 14:22 +0000, Ian Campbell wrote:> On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote: > > From: David Vrabel <david.vrabel@citrix.com> > > > > Use the /chosen node''s bootargs parameter for the Xen command line. > > Parse it early on before the serial console is setup. > > > > Signed-off-by: David Vrabel <david.vrabel@citrix.com> > > With this my hypervisor hangs after: > - UART enabled - > - CPU 00000000 booting - > - Started in Secure state - > - Entering Hyp mode - > - Setting up control registers - > - Turning on paging - > - Ready - > RAM: 0000000080000000 - 00000000ffffffff > > I''m going to try and apply 1..7 and 9. Skipping 8, 10 and 11.Which I''ve now done and pushed. Ian.
David Vrabel
2012-Mar-22 15:03 UTC
Re: [PATCH 10/11] arm: use bootargs for the command line
On 22/03/12 14:22, Ian Campbell wrote:> On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote: >> From: David Vrabel <david.vrabel@citrix.com> >> >> Use the /chosen node''s bootargs parameter for the Xen command line. >> Parse it early on before the serial console is setup. >> >> Signed-off-by: David Vrabel <david.vrabel@citrix.com> > > With this my hypervisor hangs after: > - UART enabled - > - CPU 00000000 booting - > - Started in Secure state - > - Entering Hyp mode - > - Setting up control registers - > - Turning on paging - > - Ready - > RAM: 0000000080000000 - 00000000ffffffff > > I''m going to try and apply 1..7 and 9. Skipping 8, 10 and 11.#This happens with the device tree from the kernel, but not the device tree from git://xenbits.xen.org/people/dvrabel/device-trees.git I happens when either the /chosen node is missing or bootargs is missing. This is easy to fix. However, the kernel fails to boot because it doesn''t get the device tree which is odd. I''ll look into it some more. David
David Vrabel
2012-Mar-22 17:12 UTC
Re: [PATCH 08/11] device tree, arm: supply a flat device tree to dom0
On 22/03/12 14:06, Ian Campbell wrote:> On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote: >> From: David Vrabel <david.vrabel@citrix.com> >> >> Build a flat device tree for dom0 based on the one supplied to Xen. >> The following changes are made: >> >> * In the /chosen node, the xen,dom0-bootargs parameter is renamed to >> bootargs. >> >> * In all memory nodes, the reg parameters are adjusted to reflect >> the amount of memory dom0 can use. The p2m is updated using this >> info. >> >> Support for passing ATAGS to dom0 is removed. > > With the series applied up to and including this patch my dom0 kernel > fails to boot with: > [ 0.000000] Linux version 3.2.0-rc5-arm-native+ (ianc@drall) (gcc version 4.6.0 (GCC) ) #77 Thu Mar 22 13:58:33 GMT 2012 > [ 0.000000] CPU: ARMv7 Processor [410fc0f0] revision 0 (ARMv7), cr=10c53c7d > [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache > [ 0.000000] Machine: ARM Versatile Express, model: V2P-AEMv7A > [ 0.000000] bootconsole [earlycon0] enabled > [ 0.000000] Memory policy: ECC disabled, Data cache writeback > [ 0.000000] Kernel panic - not syncing: ERROR: Failed to allocate 0x1000 bytes below 0x0. > [ 0.000000] > [ 0.000000] [<c000d64c>] (unwind_backtrace+0x0/0xe0) from [<c0273558>] (panic+0x50/0x17c) > [ 0.000000] [<c0273558>] (panic+0x50/0x17c) from [<c032ff04>] (memblock_alloc_base+0x2c/0x34) > [ 0.000000] [<c032ff04>] (memblock_alloc_base+0x2c/0x34) from [<c0329f30>] (early_alloc.constprop.3+0x10/0x28) > [ 0.000000] [<c0329f30>] (early_alloc.constprop.3+0x10/0x28) from [<c032a8c0>] (paging_init+0x48c/0x628) > [ 0.000000] [<c032a8c0>] (paging_init+0x48c/0x628) from [<c0328678>] (setup_arch+0x508/0x7ac) > [ 0.000000] [<c0328678>] (setup_arch+0x508/0x7ac) from [<c03254dc>] (start_kernel+0x6c/0x2c0) > [ 0.000000] [<c03254dc>] (start_kernel+0x6c/0x2c0) from [<80008048>] (0x80008048)This is really a bug in the memblock allocator. You have ARM_APPENDED_DTB enabled and you have actually appended a DTB. The appended DTB takes precedence over the one passed from the bootloader and DTB in the Linux tree has 2 GiB of memory @ 2 GiB. It looks like the memblock allocator adds start + size, overflows and ends up with the end of the region at 0. You can either: a) disable ARM_APPENDED_DTB; b) not append a DTB; or c) ensure the appended DTB''s memory regions match that supplied by Xen. David
Reasonably Related Threads
- [PATCH v6 00/16] xen: arm: 64-bit guest support and domU FDT autogeneration
- [PATCH v2 00/14] xen: arm: 64-bit guest support and domU FDT autogeneration
- [PATCH] arm: allocate top level p2m page for all non-idle VCPUs
- [PATCH 00/45] initial arm v8 (64-bit) support
- [PATCH v7 0/5] xen: ARM HDLCD video driver