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