1 /* 2 * Copyright (c) 2016 NextThing Co 3 * Copyright (c) 2016 Free Electrons 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <command.h> 10 #include <errno.h> 11 #include <malloc.h> 12 13 #include <linux/sizes.h> 14 15 #include <test/ut.h> 16 #include <test/overlay.h> 17 #include <test/suites.h> 18 19 /* 4k ought to be enough for anybody */ 20 #define FDT_COPY_SIZE (4 * SZ_1K) 21 22 extern u32 __dtb_test_fdt_base_begin; 23 extern u32 __dtb_test_fdt_overlay_begin; 24 extern u32 __dtb_test_fdt_overlay_stacked_begin; 25 26 static int ut_fdt_getprop_u32_by_index(void *fdt, const char *path, 27 const char *name, int index, 28 u32 *out) 29 { 30 const fdt32_t *val; 31 int node_off; 32 int len; 33 34 node_off = fdt_path_offset(fdt, path); 35 if (node_off < 0) 36 return node_off; 37 38 val = fdt_getprop(fdt, node_off, name, &len); 39 if (!val || (len < (sizeof(uint32_t) * (index + 1)))) 40 return -FDT_ERR_NOTFOUND; 41 42 *out = fdt32_to_cpu(*(val + index)); 43 44 return 0; 45 } 46 47 static int ut_fdt_getprop_u32(void *fdt, const char *path, const char *name, 48 u32 *out) 49 { 50 return ut_fdt_getprop_u32_by_index(fdt, path, name, 0, out); 51 } 52 53 static int fdt_getprop_str(void *fdt, const char *path, const char *name, 54 const char **out) 55 { 56 int node_off; 57 int len; 58 59 node_off = fdt_path_offset(fdt, path); 60 if (node_off < 0) 61 return node_off; 62 63 *out = fdt_stringlist_get(fdt, node_off, name, 0, &len); 64 65 return len < 0 ? len : 0; 66 } 67 68 static int fdt_overlay_change_int_property(struct unit_test_state *uts) 69 { 70 void *fdt = uts->priv; 71 u32 val = 0; 72 73 ut_assertok(ut_fdt_getprop_u32(fdt, "/test-node", "test-int-property", 74 &val)); 75 ut_asserteq(43, val); 76 77 return CMD_RET_SUCCESS; 78 } 79 OVERLAY_TEST(fdt_overlay_change_int_property, 0); 80 81 static int fdt_overlay_change_str_property(struct unit_test_state *uts) 82 { 83 void *fdt = uts->priv; 84 const char *val = NULL; 85 86 ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property", 87 &val)); 88 ut_asserteq_str("foobar", val); 89 90 return CMD_RET_SUCCESS; 91 } 92 OVERLAY_TEST(fdt_overlay_change_str_property, 0); 93 94 static int fdt_overlay_add_str_property(struct unit_test_state *uts) 95 { 96 void *fdt = uts->priv; 97 const char *val = NULL; 98 99 ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property-2", 100 &val)); 101 ut_asserteq_str("foobar2", val); 102 103 return CMD_RET_SUCCESS; 104 } 105 OVERLAY_TEST(fdt_overlay_add_str_property, 0); 106 107 static int fdt_overlay_add_node_by_phandle(struct unit_test_state *uts) 108 { 109 void *fdt = uts->priv; 110 int off; 111 112 off = fdt_path_offset(fdt, "/test-node/new-node"); 113 ut_assert(off >= 0); 114 115 ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL)); 116 117 return CMD_RET_SUCCESS; 118 } 119 OVERLAY_TEST(fdt_overlay_add_node_by_phandle, 0); 120 121 static int fdt_overlay_add_node_by_path(struct unit_test_state *uts) 122 { 123 void *fdt = uts->priv; 124 int off; 125 126 off = fdt_path_offset(fdt, "/new-node"); 127 ut_assert(off >= 0); 128 129 ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL)); 130 131 return CMD_RET_SUCCESS; 132 } 133 OVERLAY_TEST(fdt_overlay_add_node_by_path, 0); 134 135 static int fdt_overlay_add_subnode_property(struct unit_test_state *uts) 136 { 137 void *fdt = uts->priv; 138 int off; 139 140 off = fdt_path_offset(fdt, "/test-node/sub-test-node"); 141 ut_assert(off >= 0); 142 143 ut_assertnonnull(fdt_getprop(fdt, off, "sub-test-property", NULL)); 144 ut_assertnonnull(fdt_getprop(fdt, off, "new-sub-test-property", NULL)); 145 146 return CMD_RET_SUCCESS; 147 } 148 OVERLAY_TEST(fdt_overlay_add_subnode_property, 0); 149 150 static int fdt_overlay_local_phandle(struct unit_test_state *uts) 151 { 152 uint32_t local_phandle; 153 void *fdt = uts->priv; 154 u32 val = 0; 155 int off; 156 157 off = fdt_path_offset(fdt, "/new-local-node"); 158 ut_assert(off >= 0); 159 160 local_phandle = fdt_get_phandle(fdt, off); 161 ut_assert(local_phandle); 162 163 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle", 164 0, &val)); 165 ut_asserteq(local_phandle, val); 166 167 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle", 168 1, &val)); 169 ut_asserteq(local_phandle, val); 170 171 return CMD_RET_SUCCESS; 172 } 173 OVERLAY_TEST(fdt_overlay_local_phandle, 0); 174 175 static int fdt_overlay_local_phandles(struct unit_test_state *uts) 176 { 177 uint32_t local_phandle, test_phandle; 178 void *fdt = uts->priv; 179 u32 val = 0; 180 int off; 181 182 off = fdt_path_offset(fdt, "/new-local-node"); 183 ut_assert(off >= 0); 184 185 local_phandle = fdt_get_phandle(fdt, off); 186 ut_assert(local_phandle); 187 188 off = fdt_path_offset(fdt, "/test-node"); 189 ut_assert(off >= 0); 190 191 test_phandle = fdt_get_phandle(fdt, off); 192 ut_assert(test_phandle); 193 194 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0, 195 &val)); 196 ut_asserteq(test_phandle, val); 197 198 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1, 199 &val)); 200 ut_asserteq(local_phandle, val); 201 202 return CMD_RET_SUCCESS; 203 } 204 OVERLAY_TEST(fdt_overlay_local_phandles, 0); 205 206 static int fdt_overlay_stacked(struct unit_test_state *uts) 207 { 208 void *fdt = uts->priv; 209 u32 val = 0; 210 211 ut_assertok(ut_fdt_getprop_u32(fdt, "/new-local-node", 212 "stacked-test-int-property", &val)); 213 ut_asserteq(43, val); 214 215 return CMD_RET_SUCCESS; 216 } 217 OVERLAY_TEST(fdt_overlay_stacked, 0); 218 219 int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 220 { 221 struct unit_test *tests = ll_entry_start(struct unit_test, 222 overlay_test); 223 const int n_ents = ll_entry_count(struct unit_test, overlay_test); 224 struct unit_test_state *uts; 225 void *fdt_base = &__dtb_test_fdt_base_begin; 226 void *fdt_overlay = &__dtb_test_fdt_overlay_begin; 227 void *fdt_overlay_stacked = &__dtb_test_fdt_overlay_stacked_begin; 228 void *fdt_base_copy, *fdt_overlay_copy, *fdt_overlay_stacked_copy; 229 int ret = -ENOMEM; 230 231 uts = calloc(1, sizeof(*uts)); 232 if (!uts) 233 return -ENOMEM; 234 235 ut_assertok(fdt_check_header(fdt_base)); 236 ut_assertok(fdt_check_header(fdt_overlay)); 237 238 fdt_base_copy = malloc(FDT_COPY_SIZE); 239 if (!fdt_base_copy) 240 goto err1; 241 uts->priv = fdt_base_copy; 242 243 fdt_overlay_copy = malloc(FDT_COPY_SIZE); 244 if (!fdt_overlay_copy) 245 goto err2; 246 247 fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE); 248 if (!fdt_overlay_stacked_copy) 249 goto err3; 250 251 /* 252 * Resize the FDT to 4k so that we have room to operate on 253 * 254 * (and relocate it since the memory might be mapped 255 * read-only) 256 */ 257 ut_assertok(fdt_open_into(fdt_base, fdt_base_copy, FDT_COPY_SIZE)); 258 259 /* 260 * Resize the overlay to 4k so that we have room to operate on 261 * 262 * (and relocate it since the memory might be mapped 263 * read-only) 264 */ 265 ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy, 266 FDT_COPY_SIZE)); 267 268 /* 269 * Resize the stacked overlay to 4k so that we have room to operate on 270 * 271 * (and relocate it since the memory might be mapped 272 * read-only) 273 */ 274 ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy, 275 FDT_COPY_SIZE)); 276 277 /* Apply the overlay */ 278 ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_copy)); 279 280 /* Apply the stacked overlay */ 281 ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_stacked_copy)); 282 283 ret = cmd_ut_category("overlay", tests, n_ents, argc, argv); 284 285 free(fdt_overlay_stacked_copy); 286 err3: 287 free(fdt_overlay_copy); 288 err2: 289 free(fdt_base_copy); 290 err1: 291 free(uts); 292 293 return ret; 294 } 295