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