Home | History | Annotate | Download | only in tests
      1 /*
      2  * libfdt - Flat Device Tree manipulation
      3  *	Testcase for DT overlays()
      4  * Copyright (C) 2016 Free Electrons
      5  * Copyright (C) 2016 NextThing Co.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Lesser General Public License
      9  * as published by the Free Software Foundation; either version 2.1 of
     10  * the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful, but
     13  * WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Lesser General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Lesser General Public
     18  * License along with this library; if not, write to the Free Software
     19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
     20  */
     21 
     22 #include <stdio.h>
     23 
     24 #include <libfdt.h>
     25 
     26 #include "tests.h"
     27 
     28 #define CHECK(code) \
     29 	{ \
     30 		int err = (code); \
     31 		if (err) \
     32 			FAIL(#code ": %s", fdt_strerror(err)); \
     33 	}
     34 
     35 /* 4k ought to be enough for anybody */
     36 #define FDT_COPY_SIZE	(4 * 1024)
     37 
     38 static int fdt_getprop_u32_by_poffset(void *fdt, const char *path,
     39 				      const char *name, int poffset,
     40 				      unsigned long *out)
     41 {
     42 	const fdt32_t *val;
     43 	int node_off;
     44 	int len;
     45 
     46 	node_off = fdt_path_offset(fdt, path);
     47 	if (node_off < 0)
     48 		return node_off;
     49 
     50 	val = fdt_getprop(fdt, node_off, name, &len);
     51 	if (!val || (len < (sizeof(uint32_t) * (poffset + 1))))
     52 		return -FDT_ERR_NOTFOUND;
     53 
     54 	*out = fdt32_to_cpu(*(val + poffset));
     55 
     56 	return 0;
     57 }
     58 
     59 static int check_getprop_string_by_name(void *fdt, const char *path,
     60 					const char *name, const char *val)
     61 {
     62 	int node_off;
     63 
     64 	node_off = fdt_path_offset(fdt, path);
     65 	if (node_off < 0)
     66 		return node_off;
     67 
     68 	check_getprop_string(fdt, node_off, name, val);
     69 
     70 	return 0;
     71 }
     72 
     73 static int check_getprop_u32_by_name(void *fdt, const char *path,
     74 				     const char *name, uint32_t val)
     75 {
     76 	int node_off;
     77 
     78 	node_off = fdt_path_offset(fdt, path);
     79 	CHECK(node_off < 0);
     80 
     81 	check_getprop_cell(fdt, node_off, name, val);
     82 
     83 	return 0;
     84 }
     85 
     86 static int check_getprop_null_by_name(void *fdt, const char *path,
     87 				      const char *name)
     88 {
     89 	int node_off;
     90 
     91 	node_off = fdt_path_offset(fdt, path);
     92 	CHECK(node_off < 0);
     93 
     94 	check_property(fdt, node_off, name, 0, NULL);
     95 
     96 	return 0;
     97 }
     98 
     99 static int fdt_overlay_change_int_property(void *fdt)
    100 {
    101 	return check_getprop_u32_by_name(fdt, "/test-node", "test-int-property",
    102 					 43);
    103 }
    104 
    105 static int fdt_overlay_change_str_property(void *fdt)
    106 {
    107 	return check_getprop_string_by_name(fdt, "/test-node",
    108 					    "test-str-property", "foobar");
    109 }
    110 
    111 static int fdt_overlay_add_str_property(void *fdt)
    112 {
    113 	return check_getprop_string_by_name(fdt, "/test-node",
    114 					    "test-str-property-2", "foobar2");
    115 }
    116 
    117 static int fdt_overlay_add_node(void *fdt)
    118 {
    119 	return check_getprop_null_by_name(fdt, "/test-node/new-node",
    120 					  "new-property");
    121 }
    122 
    123 static int fdt_overlay_add_subnode_property(void *fdt)
    124 {
    125 	check_getprop_null_by_name(fdt, "/test-node/sub-test-node",
    126 				   "sub-test-property");
    127 	check_getprop_null_by_name(fdt, "/test-node/sub-test-node",
    128 				   "new-sub-test-property");
    129 
    130 	return 0;
    131 }
    132 
    133 static int fdt_overlay_local_phandle(void *fdt)
    134 {
    135 	uint32_t local_phandle;
    136 	unsigned long val = 0;
    137 	int off;
    138 
    139 	off = fdt_path_offset(fdt, "/test-node/new-local-node");
    140 	CHECK(off < 0);
    141 
    142 	local_phandle = fdt_get_phandle(fdt, off);
    143 	CHECK(!local_phandle);
    144 
    145 	CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node",
    146 					 "test-several-phandle",
    147 					 0, &val));
    148 	CHECK(val != local_phandle);
    149 
    150 	CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node",
    151 					 "test-several-phandle",
    152 					 1, &val));
    153 	CHECK(val != local_phandle);
    154 
    155 	return 0;
    156 }
    157 
    158 static int fdt_overlay_local_phandles(void *fdt)
    159 {
    160 	uint32_t local_phandle, test_phandle;
    161 	unsigned long val = 0;
    162 	int off;
    163 
    164 	off = fdt_path_offset(fdt, "/test-node/new-local-node");
    165 	CHECK(off < 0);
    166 
    167 	local_phandle = fdt_get_phandle(fdt, off);
    168 	CHECK(!local_phandle);
    169 
    170 	off = fdt_path_offset(fdt, "/test-node");
    171 	CHECK(off < 0);
    172 
    173 	test_phandle = fdt_get_phandle(fdt, off);
    174 	CHECK(!test_phandle);
    175 
    176 	CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node",
    177 					 "test-phandle", 0, &val));
    178 	CHECK(test_phandle != val);
    179 
    180 	CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node",
    181 					 "test-phandle", 1, &val));
    182 	CHECK(local_phandle != val);
    183 
    184 	return 0;
    185 }
    186 
    187 static void *open_dt(char *path)
    188 {
    189 	void *dt, *copy;
    190 
    191 	dt = load_blob(path);
    192 	copy = xmalloc(FDT_COPY_SIZE);
    193 
    194 	/*
    195 	 * Resize our DTs to 4k so that we have room to operate on
    196 	 */
    197 	CHECK(fdt_open_into(dt, copy, FDT_COPY_SIZE));
    198 
    199 	return copy;
    200 }
    201 
    202 int main(int argc, char *argv[])
    203 {
    204 	void *fdt_base, *fdt_overlay;
    205 
    206 	test_init(argc, argv);
    207 	if (argc != 3)
    208 		CONFIG("Usage: %s <base dtb> <overlay dtb>", argv[0]);
    209 
    210 	fdt_base = open_dt(argv[1]);
    211 	fdt_overlay = open_dt(argv[2]);
    212 
    213 	/* Apply the overlay */
    214 	CHECK(fdt_overlay_apply(fdt_base, fdt_overlay));
    215 
    216 	fdt_overlay_change_int_property(fdt_base);
    217 	fdt_overlay_change_str_property(fdt_base);
    218 	fdt_overlay_add_str_property(fdt_base);
    219 	fdt_overlay_add_node(fdt_base);
    220 	fdt_overlay_add_subnode_property(fdt_base);
    221 
    222 	/*
    223 	 * If the base tree has a __symbols__ node, do the tests that
    224 	 * are only successful with a proper phandle support, and thus
    225 	 * dtc -@
    226 	 */
    227 	if (fdt_path_offset(fdt_base, "/__symbols__") >= 0) {
    228 		fdt_overlay_local_phandle(fdt_base);
    229 		fdt_overlay_local_phandles(fdt_base);
    230 	}
    231 
    232 	PASS();
    233 }
    234