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