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