uboot/test/overlay/cmd_ut_overlay.c
<<
>>
Prefs
   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
  21extern u32 __dtb_test_fdt_base_begin;
  22extern u32 __dtb_test_fdt_overlay_begin;
  23extern u32 __dtb_test_fdt_overlay_stacked_begin;
  24
  25static 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
  46static 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
  52static 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
  67static 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}
  78OVERLAY_TEST(fdt_overlay_change_int_property, 0);
  79
  80static 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}
  91OVERLAY_TEST(fdt_overlay_change_str_property, 0);
  92
  93static 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}
 104OVERLAY_TEST(fdt_overlay_add_str_property, 0);
 105
 106static 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}
 118OVERLAY_TEST(fdt_overlay_add_node_by_phandle, 0);
 119
 120static 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}
 132OVERLAY_TEST(fdt_overlay_add_node_by_path, 0);
 133
 134static 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}
 147OVERLAY_TEST(fdt_overlay_add_subnode_property, 0);
 148
 149static 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}
 172OVERLAY_TEST(fdt_overlay_local_phandle, 0);
 173
 174static 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}
 203OVERLAY_TEST(fdt_overlay_local_phandles, 0);
 204
 205static 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}
 216OVERLAY_TEST(fdt_overlay_stacked, 0);
 217
 218int 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);
 285err3:
 286        free(fdt_overlay_copy);
 287err2:
 288        free(fdt_base_copy);
 289err1:
 290        free(uts);
 291
 292        return ret;
 293}
 294