uboot/arch/sandbox/cpu/state.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011-2012 The Chromium OS Authors.
   4 */
   5
   6#include <common.h>
   7#include <errno.h>
   8#include <fdtdec.h>
   9#include <log.h>
  10#include <os.h>
  11#include <asm/malloc.h>
  12#include <asm/state.h>
  13
  14/* Main state record for the sandbox */
  15static struct sandbox_state main_state;
  16static struct sandbox_state *state;     /* Pointer to current state record */
  17
  18static int state_ensure_space(int extra_size)
  19{
  20        void *blob = state->state_fdt;
  21        int used, size, free_bytes;
  22        void *buf;
  23        int ret;
  24
  25        used = fdt_off_dt_strings(blob) + fdt_size_dt_strings(blob);
  26        size = fdt_totalsize(blob);
  27        free_bytes = size - used;
  28        if (free_bytes > extra_size)
  29                return 0;
  30
  31        size = used + extra_size;
  32        buf = malloc(size);
  33        if (!buf)
  34                return -ENOMEM;
  35
  36        ret = fdt_open_into(blob, buf, size);
  37        if (ret) {
  38                free(buf);
  39                return -EIO;
  40        }
  41
  42        free(blob);
  43        state->state_fdt = buf;
  44        return 0;
  45}
  46
  47static int state_read_file(struct sandbox_state *state, const char *fname)
  48{
  49        loff_t size;
  50        int ret;
  51        int fd;
  52
  53        ret = os_get_filesize(fname, &size);
  54        if (ret < 0) {
  55                printf("Cannot find sandbox state file '%s'\n", fname);
  56                return -ENOENT;
  57        }
  58        state->state_fdt = malloc(size);
  59        if (!state->state_fdt) {
  60                puts("No memory to read sandbox state\n");
  61                return -ENOMEM;
  62        }
  63        fd = os_open(fname, OS_O_RDONLY);
  64        if (fd < 0) {
  65                printf("Cannot open sandbox state file '%s'\n", fname);
  66                ret = -EPERM;
  67                goto err_open;
  68        }
  69        if (os_read(fd, state->state_fdt, size) != size) {
  70                printf("Cannot read sandbox state file '%s'\n", fname);
  71                ret = -EIO;
  72                goto err_read;
  73        }
  74        os_close(fd);
  75
  76        return 0;
  77err_read:
  78        os_close(fd);
  79err_open:
  80        free(state->state_fdt);
  81        state->state_fdt = NULL;
  82
  83        return ret;
  84}
  85
  86/***
  87 * sandbox_read_state_nodes() - Read state associated with a driver
  88 *
  89 * This looks through all compatible nodes and calls the read function on
  90 * each one, to read in the state.
  91 *
  92 * If nothing is found, it still calls the read function once, to set up a
  93 * single global state for that driver.
  94 *
  95 * @state: Sandbox state
  96 * @io: Method to use for reading state
  97 * @blob: FDT containing state
  98 * @return 0 if OK, -EINVAL if the read function returned failure
  99 */
 100int sandbox_read_state_nodes(struct sandbox_state *state,
 101                             struct sandbox_state_io *io, const void *blob)
 102{
 103        int count;
 104        int node;
 105        int ret;
 106
 107        debug("   - read %s\n", io->name);
 108        if (!io->read)
 109                return 0;
 110
 111        node = -1;
 112        count = 0;
 113        while (blob) {
 114                node = fdt_node_offset_by_compatible(blob, node, io->compat);
 115                if (node < 0)
 116                        return 0;       /* No more */
 117                debug("   - read node '%s'\n", fdt_get_name(blob, node, NULL));
 118                ret = io->read(blob, node);
 119                if (ret) {
 120                        printf("Unable to read state for '%s'\n", io->compat);
 121                        return -EINVAL;
 122                }
 123                count++;
 124        }
 125
 126        /*
 127         * If we got no saved state, call the read function once without a
 128         * node, to set up the global state.
 129         */
 130        if (count == 0) {
 131                debug("   - read global\n");
 132                ret = io->read(NULL, -1);
 133                if (ret) {
 134                        printf("Unable to read global state for '%s'\n",
 135                               io->name);
 136                        return -EINVAL;
 137                }
 138        }
 139
 140        return 0;
 141}
 142
 143int sandbox_read_state(struct sandbox_state *state, const char *fname)
 144{
 145        struct sandbox_state_io *io;
 146        const void *blob;
 147        bool got_err;
 148        int ret;
 149
 150        if (state->read_state && fname) {
 151                ret = state_read_file(state, fname);
 152                if (ret == -ENOENT && state->ignore_missing_state_on_read)
 153                        ret = 0;
 154                if (ret)
 155                        return ret;
 156        }
 157
 158        /* Call all the state read functions */
 159        got_err = false;
 160        blob = state->state_fdt;
 161        io = ll_entry_start(struct sandbox_state_io, state_io);
 162        for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
 163                ret = sandbox_read_state_nodes(state, io, blob);
 164                if (ret < 0)
 165                        got_err = true;
 166        }
 167
 168        if (state->read_state && fname) {
 169                debug("Read sandbox state from '%s'%s\n", fname,
 170                      got_err ? " (with errors)" : "");
 171        }
 172
 173        return got_err ? -1 : 0;
 174}
 175
 176/***
 177 * sandbox_write_state_node() - Write state associated with a driver
 178 *
 179 * This calls the write function to write out global state for that driver.
 180 *
 181 * TODO(sjg@chromium.org): Support writing out state from multiple drivers
 182 * of the same time. We don't need this yet,and it will be much easier to
 183 * do when driver model is available.
 184 *
 185 * @state: Sandbox state
 186 * @io: Method to use for writing state
 187 * @return 0 if OK, -EIO if there is a fatal error (such as out of space
 188 * for adding the data), -EINVAL if the write function failed.
 189 */
 190int sandbox_write_state_node(struct sandbox_state *state,
 191                             struct sandbox_state_io *io)
 192{
 193        void *blob;
 194        int node;
 195        int ret;
 196
 197        if (!io->write)
 198                return 0;
 199
 200        ret = state_ensure_space(SANDBOX_STATE_MIN_SPACE);
 201        if (ret) {
 202                printf("Failed to add more space for state\n");
 203                return -EIO;
 204        }
 205
 206        /* The blob location can change when the size increases */
 207        blob = state->state_fdt;
 208        node = fdt_node_offset_by_compatible(blob, -1, io->compat);
 209        if (node == -FDT_ERR_NOTFOUND) {
 210                node = fdt_add_subnode(blob, 0, io->name);
 211                if (node < 0) {
 212                        printf("Cannot create node '%s': %s\n", io->name,
 213                               fdt_strerror(node));
 214                        return -EIO;
 215                }
 216
 217                if (fdt_setprop_string(blob, node, "compatible", io->compat)) {
 218                        puts("Cannot set compatible\n");
 219                        return -EIO;
 220                }
 221        } else if (node < 0) {
 222                printf("Cannot access node '%s': %s\n", io->name,
 223                       fdt_strerror(node));
 224                return -EIO;
 225        }
 226        debug("Write state for '%s' to node %d\n", io->compat, node);
 227        ret = io->write(blob, node);
 228        if (ret) {
 229                printf("Unable to write state for '%s'\n", io->compat);
 230                return -EINVAL;
 231        }
 232
 233        return 0;
 234}
 235
 236int sandbox_write_state(struct sandbox_state *state, const char *fname)
 237{
 238        struct sandbox_state_io *io;
 239        bool got_err;
 240        int size;
 241        int ret;
 242        int fd;
 243
 244        /* Create a state FDT if we don't have one */
 245        if (!state->state_fdt) {
 246                size = 0x4000;
 247                state->state_fdt = malloc(size);
 248                if (!state->state_fdt) {
 249                        puts("No memory to create FDT\n");
 250                        return -ENOMEM;
 251                }
 252                ret = fdt_create_empty_tree(state->state_fdt, size);
 253                if (ret < 0) {
 254                        printf("Cannot create empty state FDT: %s\n",
 255                               fdt_strerror(ret));
 256                        ret = -EIO;
 257                        goto err_create;
 258                }
 259        }
 260
 261        /* Call all the state write funtcions */
 262        got_err = false;
 263        io = ll_entry_start(struct sandbox_state_io, state_io);
 264        ret = 0;
 265        for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
 266                ret = sandbox_write_state_node(state, io);
 267                if (ret == -EIO)
 268                        break;
 269                else if (ret)
 270                        got_err = true;
 271        }
 272
 273        if (ret == -EIO) {
 274                printf("Could not write sandbox state\n");
 275                goto err_create;
 276        }
 277
 278        ret = fdt_pack(state->state_fdt);
 279        if (ret < 0) {
 280                printf("Cannot pack state FDT: %s\n", fdt_strerror(ret));
 281                ret = -EINVAL;
 282                goto err_create;
 283        }
 284        size = fdt_totalsize(state->state_fdt);
 285        fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT);
 286        if (fd < 0) {
 287                printf("Cannot open sandbox state file '%s'\n", fname);
 288                ret = -EIO;
 289                goto err_create;
 290        }
 291        if (os_write(fd, state->state_fdt, size) != size) {
 292                printf("Cannot write sandbox state file '%s'\n", fname);
 293                ret = -EIO;
 294                goto err_write;
 295        }
 296        os_close(fd);
 297
 298        debug("Wrote sandbox state to '%s'%s\n", fname,
 299              got_err ? " (with errors)" : "");
 300
 301        return 0;
 302err_write:
 303        os_close(fd);
 304err_create:
 305        free(state->state_fdt);
 306
 307        return ret;
 308}
 309
 310int state_setprop(int node, const char *prop_name, const void *data, int size)
 311{
 312        void *blob;
 313        int len;
 314        int ret;
 315
 316        fdt_getprop(state->state_fdt, node, prop_name, &len);
 317
 318        /* Add space for the new property, its name and some overhead */
 319        ret = state_ensure_space(size - len + strlen(prop_name) + 32);
 320        if (ret)
 321                return ret;
 322
 323        /* This should succeed, barring a mutiny */
 324        blob = state->state_fdt;
 325        ret = fdt_setprop(blob, node, prop_name, data, size);
 326        if (ret) {
 327                printf("%s: Unable to set property '%s' in node '%s': %s\n",
 328                       __func__, prop_name, fdt_get_name(blob, node, NULL),
 329                        fdt_strerror(ret));
 330                return -ENOSPC;
 331        }
 332
 333        return 0;
 334}
 335
 336struct sandbox_state *state_get_current(void)
 337{
 338        assert(state);
 339        return state;
 340}
 341
 342void state_set_skip_delays(bool skip_delays)
 343{
 344        struct sandbox_state *state = state_get_current();
 345
 346        state->skip_delays = skip_delays;
 347}
 348
 349bool state_get_skip_delays(void)
 350{
 351        struct sandbox_state *state = state_get_current();
 352
 353        return state->skip_delays;
 354}
 355
 356void state_reset_for_test(struct sandbox_state *state)
 357{
 358        /* No reset yet, so mark it as such. Always allow power reset */
 359        state->last_sysreset = SYSRESET_COUNT;
 360        state->sysreset_allowed[SYSRESET_POWER_OFF] = true;
 361        state->allow_memio = false;
 362
 363        memset(&state->wdt, '\0', sizeof(state->wdt));
 364        memset(state->spi, '\0', sizeof(state->spi));
 365
 366        /*
 367         * Set up the memory tag list. Use the top of emulated SDRAM for the
 368         * first tag number, since that address offset is outside the legal
 369         * range, and can be assumed to be a tag.
 370         */
 371        INIT_LIST_HEAD(&state->mapmem_head);
 372        state->next_tag = state->ram_size;
 373}
 374
 375int state_init(void)
 376{
 377        state = &main_state;
 378
 379        state->ram_size = CONFIG_SYS_SDRAM_SIZE;
 380        state->ram_buf = os_malloc(state->ram_size);
 381        if (!state->ram_buf) {
 382                printf("Out of memory\n");
 383                os_exit(1);
 384        }
 385
 386        state_reset_for_test(state);
 387        /*
 388         * Example of how to use GPIOs:
 389         *
 390         * sandbox_gpio_set_direction(170, 0);
 391         * sandbox_gpio_set_value(170, 0);
 392         */
 393        return 0;
 394}
 395
 396int state_uninit(void)
 397{
 398        int err;
 399
 400        state = &main_state;
 401
 402        if (state->write_ram_buf) {
 403                err = os_write_ram_buf(state->ram_buf_fname);
 404                if (err) {
 405                        printf("Failed to write RAM buffer\n");
 406                        return err;
 407                }
 408        }
 409
 410        if (state->write_state) {
 411                if (sandbox_write_state(state, state->state_fname)) {
 412                        printf("Failed to write sandbox state\n");
 413                        return -1;
 414                }
 415        }
 416
 417        /* Remove old memory file if required */
 418        if (state->ram_buf_rm && state->ram_buf_fname)
 419                os_unlink(state->ram_buf_fname);
 420
 421        /* Delete this at the last moment so as not to upset gdb too much */
 422        if (state->jumped_fname)
 423                os_unlink(state->jumped_fname);
 424
 425        if (state->state_fdt)
 426                free(state->state_fdt);
 427        memset(state, '\0', sizeof(*state));
 428
 429        return 0;
 430}
 431