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