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