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