16fb62078SSimon Glass /* 26fb62078SSimon Glass * Copyright (c) 2011-2012 The Chromium OS Authors. 31a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 46fb62078SSimon Glass */ 56fb62078SSimon Glass 66fb62078SSimon Glass #include <common.h> 71209e272SSimon Glass #include <errno.h> 81209e272SSimon Glass #include <fdtdec.h> 95c2859cdSSimon Glass #include <os.h> 106fb62078SSimon Glass #include <asm/state.h> 116fb62078SSimon Glass 126fb62078SSimon Glass /* Main state record for the sandbox */ 136fb62078SSimon Glass static struct sandbox_state main_state; 146fb62078SSimon Glass static struct sandbox_state *state; /* Pointer to current state record */ 156fb62078SSimon Glass 161209e272SSimon Glass static int state_ensure_space(int extra_size) 171209e272SSimon Glass { 181209e272SSimon Glass void *blob = state->state_fdt; 191209e272SSimon Glass int used, size, free; 201209e272SSimon Glass void *buf; 211209e272SSimon Glass int ret; 221209e272SSimon Glass 231209e272SSimon Glass used = fdt_off_dt_strings(blob) + fdt_size_dt_strings(blob); 241209e272SSimon Glass size = fdt_totalsize(blob); 251209e272SSimon Glass free = size - used; 261209e272SSimon Glass if (free > extra_size) 271209e272SSimon Glass return 0; 281209e272SSimon Glass 291209e272SSimon Glass size = used + extra_size; 301209e272SSimon Glass buf = os_malloc(size); 311209e272SSimon Glass if (!buf) 321209e272SSimon Glass return -ENOMEM; 331209e272SSimon Glass 341209e272SSimon Glass ret = fdt_open_into(blob, buf, size); 351209e272SSimon Glass if (ret) { 361209e272SSimon Glass os_free(buf); 371209e272SSimon Glass return -EIO; 381209e272SSimon Glass } 391209e272SSimon Glass 401209e272SSimon Glass os_free(blob); 411209e272SSimon Glass state->state_fdt = buf; 421209e272SSimon Glass return 0; 431209e272SSimon Glass } 441209e272SSimon Glass 451209e272SSimon Glass static int state_read_file(struct sandbox_state *state, const char *fname) 461209e272SSimon Glass { 4796b1046dSSuriyan Ramasami loff_t size; 481209e272SSimon Glass int ret; 491209e272SSimon Glass int fd; 501209e272SSimon Glass 5196b1046dSSuriyan Ramasami ret = os_get_filesize(fname, &size); 5296b1046dSSuriyan Ramasami if (ret < 0) { 531209e272SSimon Glass printf("Cannot find sandbox state file '%s'\n", fname); 54*d73125cbSSimon Glass return -ENOENT; 551209e272SSimon Glass } 561209e272SSimon Glass state->state_fdt = os_malloc(size); 571209e272SSimon Glass if (!state->state_fdt) { 581209e272SSimon Glass puts("No memory to read sandbox state\n"); 591209e272SSimon Glass return -ENOMEM; 601209e272SSimon Glass } 611209e272SSimon Glass fd = os_open(fname, OS_O_RDONLY); 621209e272SSimon Glass if (fd < 0) { 631209e272SSimon Glass printf("Cannot open sandbox state file '%s'\n", fname); 641209e272SSimon Glass ret = -EPERM; 651209e272SSimon Glass goto err_open; 661209e272SSimon Glass } 671209e272SSimon Glass if (os_read(fd, state->state_fdt, size) != size) { 681209e272SSimon Glass printf("Cannot read sandbox state file '%s'\n", fname); 691209e272SSimon Glass ret = -EIO; 701209e272SSimon Glass goto err_read; 711209e272SSimon Glass } 721209e272SSimon Glass os_close(fd); 731209e272SSimon Glass 741209e272SSimon Glass return 0; 751209e272SSimon Glass err_read: 761209e272SSimon Glass os_close(fd); 771209e272SSimon Glass err_open: 781209e272SSimon Glass os_free(state->state_fdt); 791209e272SSimon Glass state->state_fdt = NULL; 801209e272SSimon Glass 811209e272SSimon Glass return ret; 821209e272SSimon Glass } 831209e272SSimon Glass 841209e272SSimon Glass /*** 851209e272SSimon Glass * sandbox_read_state_nodes() - Read state associated with a driver 861209e272SSimon Glass * 871209e272SSimon Glass * This looks through all compatible nodes and calls the read function on 881209e272SSimon Glass * each one, to read in the state. 891209e272SSimon Glass * 901209e272SSimon Glass * If nothing is found, it still calls the read function once, to set up a 911209e272SSimon Glass * single global state for that driver. 921209e272SSimon Glass * 931209e272SSimon Glass * @state: Sandbox state 941209e272SSimon Glass * @io: Method to use for reading state 951209e272SSimon Glass * @blob: FDT containing state 961209e272SSimon Glass * @return 0 if OK, -EINVAL if the read function returned failure 971209e272SSimon Glass */ 981209e272SSimon Glass int sandbox_read_state_nodes(struct sandbox_state *state, 991209e272SSimon Glass struct sandbox_state_io *io, const void *blob) 1001209e272SSimon Glass { 1011209e272SSimon Glass int count; 1021209e272SSimon Glass int node; 1031209e272SSimon Glass int ret; 1041209e272SSimon Glass 1051209e272SSimon Glass debug(" - read %s\n", io->name); 1061209e272SSimon Glass if (!io->read) 1071209e272SSimon Glass return 0; 1081209e272SSimon Glass 1091209e272SSimon Glass node = -1; 1101209e272SSimon Glass count = 0; 1111209e272SSimon Glass while (blob) { 1121209e272SSimon Glass node = fdt_node_offset_by_compatible(blob, node, io->compat); 1131209e272SSimon Glass if (node < 0) 1141209e272SSimon Glass return 0; /* No more */ 1151209e272SSimon Glass debug(" - read node '%s'\n", fdt_get_name(blob, node, NULL)); 1161209e272SSimon Glass ret = io->read(blob, node); 1171209e272SSimon Glass if (ret) { 1181209e272SSimon Glass printf("Unable to read state for '%s'\n", io->compat); 1191209e272SSimon Glass return -EINVAL; 1201209e272SSimon Glass } 1211209e272SSimon Glass count++; 1221209e272SSimon Glass } 1231209e272SSimon Glass 1241209e272SSimon Glass /* 1251209e272SSimon Glass * If we got no saved state, call the read function once without a 1261209e272SSimon Glass * node, to set up the global state. 1271209e272SSimon Glass */ 1281209e272SSimon Glass if (count == 0) { 1291209e272SSimon Glass debug(" - read global\n"); 1301209e272SSimon Glass ret = io->read(NULL, -1); 1311209e272SSimon Glass if (ret) { 1321209e272SSimon Glass printf("Unable to read global state for '%s'\n", 1331209e272SSimon Glass io->name); 1341209e272SSimon Glass return -EINVAL; 1351209e272SSimon Glass } 1361209e272SSimon Glass } 1371209e272SSimon Glass 1381209e272SSimon Glass return 0; 1391209e272SSimon Glass } 1401209e272SSimon Glass 1411209e272SSimon Glass int sandbox_read_state(struct sandbox_state *state, const char *fname) 1421209e272SSimon Glass { 1431209e272SSimon Glass struct sandbox_state_io *io; 1441209e272SSimon Glass const void *blob; 1451209e272SSimon Glass bool got_err; 1461209e272SSimon Glass int ret; 1471209e272SSimon Glass 1481209e272SSimon Glass if (state->read_state && fname) { 1491209e272SSimon Glass ret = state_read_file(state, fname); 1501209e272SSimon Glass if (ret == -ENOENT && state->ignore_missing_state_on_read) 1511209e272SSimon Glass ret = 0; 1521209e272SSimon Glass if (ret) 1531209e272SSimon Glass return ret; 1541209e272SSimon Glass } 1551209e272SSimon Glass 1561209e272SSimon Glass /* Call all the state read funtcions */ 1571209e272SSimon Glass got_err = false; 1581209e272SSimon Glass blob = state->state_fdt; 1591209e272SSimon Glass io = ll_entry_start(struct sandbox_state_io, state_io); 1601209e272SSimon Glass for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) { 1611209e272SSimon Glass ret = sandbox_read_state_nodes(state, io, blob); 1621209e272SSimon Glass if (ret < 0) 1631209e272SSimon Glass got_err = true; 1641209e272SSimon Glass } 1651209e272SSimon Glass 1661209e272SSimon Glass if (state->read_state && fname) { 1671209e272SSimon Glass debug("Read sandbox state from '%s'%s\n", fname, 1681209e272SSimon Glass got_err ? " (with errors)" : ""); 1691209e272SSimon Glass } 1701209e272SSimon Glass 1711209e272SSimon Glass return got_err ? -1 : 0; 1721209e272SSimon Glass } 1731209e272SSimon Glass 1741209e272SSimon Glass /*** 1751209e272SSimon Glass * sandbox_write_state_node() - Write state associated with a driver 1761209e272SSimon Glass * 1771209e272SSimon Glass * This calls the write function to write out global state for that driver. 1781209e272SSimon Glass * 1791209e272SSimon Glass * TODO(sjg@chromium.org): Support writing out state from multiple drivers 1801209e272SSimon Glass * of the same time. We don't need this yet,and it will be much easier to 1811209e272SSimon Glass * do when driver model is available. 1821209e272SSimon Glass * 1831209e272SSimon Glass * @state: Sandbox state 1841209e272SSimon Glass * @io: Method to use for writing state 1851209e272SSimon Glass * @return 0 if OK, -EIO if there is a fatal error (such as out of space 1861209e272SSimon Glass * for adding the data), -EINVAL if the write function failed. 1871209e272SSimon Glass */ 1881209e272SSimon Glass int sandbox_write_state_node(struct sandbox_state *state, 1891209e272SSimon Glass struct sandbox_state_io *io) 1901209e272SSimon Glass { 1911209e272SSimon Glass void *blob; 1921209e272SSimon Glass int node; 1931209e272SSimon Glass int ret; 1941209e272SSimon Glass 1951209e272SSimon Glass if (!io->write) 1961209e272SSimon Glass return 0; 1971209e272SSimon Glass 1981209e272SSimon Glass ret = state_ensure_space(SANDBOX_STATE_MIN_SPACE); 1991209e272SSimon Glass if (ret) { 2001209e272SSimon Glass printf("Failed to add more space for state\n"); 2011209e272SSimon Glass return -EIO; 2021209e272SSimon Glass } 2031209e272SSimon Glass 2041209e272SSimon Glass /* The blob location can change when the size increases */ 2051209e272SSimon Glass blob = state->state_fdt; 2061209e272SSimon Glass node = fdt_node_offset_by_compatible(blob, -1, io->compat); 2071209e272SSimon Glass if (node == -FDT_ERR_NOTFOUND) { 2081209e272SSimon Glass node = fdt_add_subnode(blob, 0, io->name); 2091209e272SSimon Glass if (node < 0) { 2101209e272SSimon Glass printf("Cannot create node '%s': %s\n", io->name, 2111209e272SSimon Glass fdt_strerror(node)); 2121209e272SSimon Glass return -EIO; 2131209e272SSimon Glass } 2141209e272SSimon Glass 2151209e272SSimon Glass if (fdt_setprop_string(blob, node, "compatible", io->compat)) { 2161209e272SSimon Glass puts("Cannot set compatible\n"); 2171209e272SSimon Glass return -EIO; 2181209e272SSimon Glass } 2191209e272SSimon Glass } else if (node < 0) { 2201209e272SSimon Glass printf("Cannot access node '%s': %s\n", io->name, 2211209e272SSimon Glass fdt_strerror(node)); 2221209e272SSimon Glass return -EIO; 2231209e272SSimon Glass } 2241209e272SSimon Glass debug("Write state for '%s' to node %d\n", io->compat, node); 2251209e272SSimon Glass ret = io->write(blob, node); 2261209e272SSimon Glass if (ret) { 2271209e272SSimon Glass printf("Unable to write state for '%s'\n", io->compat); 2281209e272SSimon Glass return -EINVAL; 2291209e272SSimon Glass } 2301209e272SSimon Glass 2311209e272SSimon Glass return 0; 2321209e272SSimon Glass } 2331209e272SSimon Glass 2341209e272SSimon Glass int sandbox_write_state(struct sandbox_state *state, const char *fname) 2351209e272SSimon Glass { 2361209e272SSimon Glass struct sandbox_state_io *io; 2371209e272SSimon Glass bool got_err; 2381209e272SSimon Glass int size; 2391209e272SSimon Glass int ret; 2401209e272SSimon Glass int fd; 2411209e272SSimon Glass 2421209e272SSimon Glass /* Create a state FDT if we don't have one */ 2431209e272SSimon Glass if (!state->state_fdt) { 2441209e272SSimon Glass size = 0x4000; 2451209e272SSimon Glass state->state_fdt = os_malloc(size); 2461209e272SSimon Glass if (!state->state_fdt) { 2471209e272SSimon Glass puts("No memory to create FDT\n"); 2481209e272SSimon Glass return -ENOMEM; 2491209e272SSimon Glass } 2501209e272SSimon Glass ret = fdt_create_empty_tree(state->state_fdt, size); 2511209e272SSimon Glass if (ret < 0) { 2521209e272SSimon Glass printf("Cannot create empty state FDT: %s\n", 2531209e272SSimon Glass fdt_strerror(ret)); 2541209e272SSimon Glass ret = -EIO; 2551209e272SSimon Glass goto err_create; 2561209e272SSimon Glass } 2571209e272SSimon Glass } 2581209e272SSimon Glass 2591209e272SSimon Glass /* Call all the state write funtcions */ 2601209e272SSimon Glass got_err = false; 2611209e272SSimon Glass io = ll_entry_start(struct sandbox_state_io, state_io); 2621209e272SSimon Glass ret = 0; 2631209e272SSimon Glass for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) { 2641209e272SSimon Glass ret = sandbox_write_state_node(state, io); 2651209e272SSimon Glass if (ret == -EIO) 2661209e272SSimon Glass break; 2671209e272SSimon Glass else if (ret) 2681209e272SSimon Glass got_err = true; 2691209e272SSimon Glass } 2701209e272SSimon Glass 2711209e272SSimon Glass if (ret == -EIO) { 2721209e272SSimon Glass printf("Could not write sandbox state\n"); 2731209e272SSimon Glass goto err_create; 2741209e272SSimon Glass } 2751209e272SSimon Glass 2761209e272SSimon Glass ret = fdt_pack(state->state_fdt); 2771209e272SSimon Glass if (ret < 0) { 2781209e272SSimon Glass printf("Cannot pack state FDT: %s\n", fdt_strerror(ret)); 2791209e272SSimon Glass ret = -EINVAL; 2801209e272SSimon Glass goto err_create; 2811209e272SSimon Glass } 2821209e272SSimon Glass size = fdt_totalsize(state->state_fdt); 2831209e272SSimon Glass fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT); 2841209e272SSimon Glass if (fd < 0) { 2851209e272SSimon Glass printf("Cannot open sandbox state file '%s'\n", fname); 2861209e272SSimon Glass ret = -EIO; 2871209e272SSimon Glass goto err_create; 2881209e272SSimon Glass } 2891209e272SSimon Glass if (os_write(fd, state->state_fdt, size) != size) { 2901209e272SSimon Glass printf("Cannot write sandbox state file '%s'\n", fname); 2911209e272SSimon Glass ret = -EIO; 2921209e272SSimon Glass goto err_write; 2931209e272SSimon Glass } 2941209e272SSimon Glass os_close(fd); 2951209e272SSimon Glass 2961209e272SSimon Glass debug("Wrote sandbox state to '%s'%s\n", fname, 2971209e272SSimon Glass got_err ? " (with errors)" : ""); 2981209e272SSimon Glass 2991209e272SSimon Glass return 0; 3001209e272SSimon Glass err_write: 3011209e272SSimon Glass os_close(fd); 3021209e272SSimon Glass err_create: 3031209e272SSimon Glass os_free(state->state_fdt); 3041209e272SSimon Glass 3051209e272SSimon Glass return ret; 3061209e272SSimon Glass } 3071209e272SSimon Glass 3081209e272SSimon Glass int state_setprop(int node, const char *prop_name, const void *data, int size) 3091209e272SSimon Glass { 3101209e272SSimon Glass void *blob; 3111209e272SSimon Glass int len; 3121209e272SSimon Glass int ret; 3131209e272SSimon Glass 3141209e272SSimon Glass fdt_getprop(state->state_fdt, node, prop_name, &len); 3151209e272SSimon Glass 3161209e272SSimon Glass /* Add space for the new property, its name and some overhead */ 3171209e272SSimon Glass ret = state_ensure_space(size - len + strlen(prop_name) + 32); 3181209e272SSimon Glass if (ret) 3191209e272SSimon Glass return ret; 3201209e272SSimon Glass 3211209e272SSimon Glass /* This should succeed, barring a mutiny */ 3221209e272SSimon Glass blob = state->state_fdt; 3231209e272SSimon Glass ret = fdt_setprop(blob, node, prop_name, data, size); 3241209e272SSimon Glass if (ret) { 3251209e272SSimon Glass printf("%s: Unable to set property '%s' in node '%s': %s\n", 3261209e272SSimon Glass __func__, prop_name, fdt_get_name(blob, node, NULL), 3271209e272SSimon Glass fdt_strerror(ret)); 3281209e272SSimon Glass return -ENOSPC; 3291209e272SSimon Glass } 3301209e272SSimon Glass 3311209e272SSimon Glass return 0; 3321209e272SSimon Glass } 3331209e272SSimon Glass 3346fb62078SSimon Glass struct sandbox_state *state_get_current(void) 3356fb62078SSimon Glass { 3366fb62078SSimon Glass assert(state); 3376fb62078SSimon Glass return state; 3386fb62078SSimon Glass } 3396fb62078SSimon Glass 3406fb62078SSimon Glass int state_init(void) 3416fb62078SSimon Glass { 3426fb62078SSimon Glass state = &main_state; 3436fb62078SSimon Glass 3445c2859cdSSimon Glass state->ram_size = CONFIG_SYS_SDRAM_SIZE; 3455c2859cdSSimon Glass state->ram_buf = os_malloc(state->ram_size); 3465c2859cdSSimon Glass assert(state->ram_buf); 3475c2859cdSSimon Glass 3486fb62078SSimon Glass /* 3496fb62078SSimon Glass * Example of how to use GPIOs: 3506fb62078SSimon Glass * 3516fb62078SSimon Glass * sandbox_gpio_set_direction(170, 0); 3526fb62078SSimon Glass * sandbox_gpio_set_value(170, 0); 3536fb62078SSimon Glass */ 3546fb62078SSimon Glass return 0; 3556fb62078SSimon Glass } 3565c2859cdSSimon Glass 3575c2859cdSSimon Glass int state_uninit(void) 3585c2859cdSSimon Glass { 3595c2859cdSSimon Glass int err; 3605c2859cdSSimon Glass 3615c2859cdSSimon Glass state = &main_state; 3625c2859cdSSimon Glass 363ab839dc3SSimon Glass if (state->write_ram_buf && !state->ram_buf_rm) { 3645c2859cdSSimon Glass err = os_write_ram_buf(state->ram_buf_fname); 3655c2859cdSSimon Glass if (err) { 3665c2859cdSSimon Glass printf("Failed to write RAM buffer\n"); 3675c2859cdSSimon Glass return err; 3685c2859cdSSimon Glass } 3695c2859cdSSimon Glass } 3705c2859cdSSimon Glass 3711209e272SSimon Glass if (state->write_state) { 3721209e272SSimon Glass if (sandbox_write_state(state, state->state_fname)) { 3731209e272SSimon Glass printf("Failed to write sandbox state\n"); 3741209e272SSimon Glass return -1; 3751209e272SSimon Glass } 3761209e272SSimon Glass } 3771209e272SSimon Glass 378ab839dc3SSimon Glass /* Delete this at the last moment so as not to upset gdb too much */ 379ab839dc3SSimon Glass if (state->jumped_fname) 380ab839dc3SSimon Glass os_unlink(state->jumped_fname); 381ab839dc3SSimon Glass 3821209e272SSimon Glass if (state->state_fdt) 3831209e272SSimon Glass os_free(state->state_fdt); 3841209e272SSimon Glass memset(state, '\0', sizeof(*state)); 3851209e272SSimon Glass 3865c2859cdSSimon Glass return 0; 3875c2859cdSSimon Glass } 388