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 <fdt_support.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 void *fdt; 27 28 static int ut_fdt_getprop_u32_by_index(void *fdt, const char *path, 29 const char *name, int index, 30 u32 *out) 31 { 32 const fdt32_t *val; 33 int node_off; 34 int len; 35 36 node_off = fdt_path_offset(fdt, path); 37 if (node_off < 0) 38 return node_off; 39 40 val = fdt_getprop(fdt, node_off, name, &len); 41 if (!val || (len < (sizeof(uint32_t) * (index + 1)))) 42 return -FDT_ERR_NOTFOUND; 43 44 *out = fdt32_to_cpu(*(val + index)); 45 46 return 0; 47 } 48 49 static int ut_fdt_getprop_u32(void *fdt, const char *path, const char *name, 50 u32 *out) 51 { 52 return ut_fdt_getprop_u32_by_index(fdt, path, name, 0, out); 53 } 54 55 static int fdt_getprop_str(void *fdt, const char *path, const char *name, 56 const char **out) 57 { 58 int node_off; 59 int len; 60 61 node_off = fdt_path_offset(fdt, path); 62 if (node_off < 0) 63 return node_off; 64 65 *out = fdt_stringlist_get(fdt, node_off, name, 0, &len); 66 67 return len < 0 ? len : 0; 68 } 69 70 static int fdt_overlay_change_int_property(struct unit_test_state *uts) 71 { 72 u32 val = 0; 73 74 ut_assertok(ut_fdt_getprop_u32(fdt, "/test-node", "test-int-property", 75 &val)); 76 ut_asserteq(43, val); 77 78 return CMD_RET_SUCCESS; 79 } 80 OVERLAY_TEST(fdt_overlay_change_int_property, 0); 81 82 static int fdt_overlay_change_str_property(struct unit_test_state *uts) 83 { 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 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 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 int off; 122 123 off = fdt_path_offset(fdt, "/new-node"); 124 ut_assert(off >= 0); 125 126 ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL)); 127 128 return CMD_RET_SUCCESS; 129 } 130 OVERLAY_TEST(fdt_overlay_add_node_by_path, 0); 131 132 static int fdt_overlay_add_subnode_property(struct unit_test_state *uts) 133 { 134 int off; 135 136 off = fdt_path_offset(fdt, "/test-node/sub-test-node"); 137 ut_assert(off >= 0); 138 139 ut_assertnonnull(fdt_getprop(fdt, off, "sub-test-property", NULL)); 140 ut_assertnonnull(fdt_getprop(fdt, off, "new-sub-test-property", NULL)); 141 142 return CMD_RET_SUCCESS; 143 } 144 OVERLAY_TEST(fdt_overlay_add_subnode_property, 0); 145 146 static int fdt_overlay_local_phandle(struct unit_test_state *uts) 147 { 148 uint32_t local_phandle; 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(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle", 159 0, &val)); 160 ut_asserteq(local_phandle, val); 161 162 ut_assertok(ut_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 u32 val = 0; 174 int off; 175 176 off = fdt_path_offset(fdt, "/new-local-node"); 177 ut_assert(off >= 0); 178 179 local_phandle = fdt_get_phandle(fdt, off); 180 ut_assert(local_phandle); 181 182 off = fdt_path_offset(fdt, "/test-node"); 183 ut_assert(off >= 0); 184 185 test_phandle = fdt_get_phandle(fdt, off); 186 ut_assert(test_phandle); 187 188 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0, 189 &val)); 190 ut_asserteq(test_phandle, val); 191 192 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1, 193 &val)); 194 ut_asserteq(local_phandle, val); 195 196 return CMD_RET_SUCCESS; 197 } 198 OVERLAY_TEST(fdt_overlay_local_phandles, 0); 199 200 static int fdt_overlay_stacked(struct unit_test_state *uts) 201 { 202 u32 val = 0; 203 204 ut_assertok(ut_fdt_getprop_u32(fdt, "/new-local-node", 205 "stacked-test-int-property", &val)); 206 ut_asserteq(43, val); 207 208 return CMD_RET_SUCCESS; 209 } 210 OVERLAY_TEST(fdt_overlay_stacked, 0); 211 212 int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 213 { 214 struct unit_test *tests = ll_entry_start(struct unit_test, 215 overlay_test); 216 const int n_ents = ll_entry_count(struct unit_test, overlay_test); 217 struct unit_test_state *uts; 218 void *fdt_base = &__dtb_test_fdt_base_begin; 219 void *fdt_overlay = &__dtb_test_fdt_overlay_begin; 220 void *fdt_overlay_stacked = &__dtb_test_fdt_overlay_stacked_begin; 221 void *fdt_overlay_copy, *fdt_overlay_stacked_copy; 222 int ret = -ENOMEM; 223 224 uts = calloc(1, sizeof(*uts)); 225 if (!uts) 226 return -ENOMEM; 227 228 ut_assertok(fdt_check_header(fdt_base)); 229 ut_assertok(fdt_check_header(fdt_overlay)); 230 231 fdt = malloc(FDT_COPY_SIZE); 232 if (!fdt) 233 goto err1; 234 235 fdt_overlay_copy = malloc(FDT_COPY_SIZE); 236 if (!fdt_overlay_copy) 237 goto err2; 238 239 fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE); 240 if (!fdt_overlay_stacked_copy) 241 goto err3; 242 243 /* 244 * Resize the FDT to 4k so that we have room to operate on 245 * 246 * (and relocate it since the memory might be mapped 247 * read-only) 248 */ 249 ut_assertok(fdt_open_into(fdt_base, fdt, FDT_COPY_SIZE)); 250 251 /* 252 * Resize the overlay 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_overlay, fdt_overlay_copy, 258 FDT_COPY_SIZE)); 259 260 /* 261 * Resize the stacked overlay to 4k so that we have room to operate on 262 * 263 * (and relocate it since the memory might be mapped 264 * read-only) 265 */ 266 ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy, 267 FDT_COPY_SIZE)); 268 269 /* Apply the overlay */ 270 ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_copy)); 271 272 /* Apply the stacked overlay */ 273 ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_stacked_copy)); 274 275 ret = cmd_ut_category("overlay", tests, n_ents, argc, argv); 276 277 free(fdt_overlay_stacked_copy); 278 err3: 279 free(fdt_overlay_copy); 280 err2: 281 free(fdt); 282 err1: 283 return ret; 284 } 285