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> 7*1209e272SSimon Glass #include <errno.h> 8*1209e272SSimon 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 21*1209e272SSimon Glass static int state_ensure_space(int extra_size) 22*1209e272SSimon Glass { 23*1209e272SSimon Glass void *blob = state->state_fdt; 24*1209e272SSimon Glass int used, size, free; 25*1209e272SSimon Glass void *buf; 26*1209e272SSimon Glass int ret; 27*1209e272SSimon Glass 28*1209e272SSimon Glass used = fdt_off_dt_strings(blob) + fdt_size_dt_strings(blob); 29*1209e272SSimon Glass size = fdt_totalsize(blob); 30*1209e272SSimon Glass free = size - used; 31*1209e272SSimon Glass if (free > extra_size) 32*1209e272SSimon Glass return 0; 33*1209e272SSimon Glass 34*1209e272SSimon Glass size = used + extra_size; 35*1209e272SSimon Glass buf = os_malloc(size); 36*1209e272SSimon Glass if (!buf) 37*1209e272SSimon Glass return -ENOMEM; 38*1209e272SSimon Glass 39*1209e272SSimon Glass ret = fdt_open_into(blob, buf, size); 40*1209e272SSimon Glass if (ret) { 41*1209e272SSimon Glass os_free(buf); 42*1209e272SSimon Glass return -EIO; 43*1209e272SSimon Glass } 44*1209e272SSimon Glass 45*1209e272SSimon Glass os_free(blob); 46*1209e272SSimon Glass state->state_fdt = buf; 47*1209e272SSimon Glass return 0; 48*1209e272SSimon Glass } 49*1209e272SSimon Glass 50*1209e272SSimon Glass static int state_read_file(struct sandbox_state *state, const char *fname) 51*1209e272SSimon Glass { 52*1209e272SSimon Glass int size; 53*1209e272SSimon Glass int ret; 54*1209e272SSimon Glass int fd; 55*1209e272SSimon Glass 56*1209e272SSimon Glass size = os_get_filesize(fname); 57*1209e272SSimon Glass if (size < 0) { 58*1209e272SSimon Glass printf("Cannot find sandbox state file '%s'\n", fname); 59*1209e272SSimon Glass return -ENOENT; 60*1209e272SSimon Glass } 61*1209e272SSimon Glass state->state_fdt = os_malloc(size); 62*1209e272SSimon Glass if (!state->state_fdt) { 63*1209e272SSimon Glass puts("No memory to read sandbox state\n"); 64*1209e272SSimon Glass return -ENOMEM; 65*1209e272SSimon Glass } 66*1209e272SSimon Glass fd = os_open(fname, OS_O_RDONLY); 67*1209e272SSimon Glass if (fd < 0) { 68*1209e272SSimon Glass printf("Cannot open sandbox state file '%s'\n", fname); 69*1209e272SSimon Glass ret = -EPERM; 70*1209e272SSimon Glass goto err_open; 71*1209e272SSimon Glass } 72*1209e272SSimon Glass if (os_read(fd, state->state_fdt, size) != size) { 73*1209e272SSimon Glass printf("Cannot read sandbox state file '%s'\n", fname); 74*1209e272SSimon Glass ret = -EIO; 75*1209e272SSimon Glass goto err_read; 76*1209e272SSimon Glass } 77*1209e272SSimon Glass os_close(fd); 78*1209e272SSimon Glass 79*1209e272SSimon Glass return 0; 80*1209e272SSimon Glass err_read: 81*1209e272SSimon Glass os_close(fd); 82*1209e272SSimon Glass err_open: 83*1209e272SSimon Glass os_free(state->state_fdt); 84*1209e272SSimon Glass state->state_fdt = NULL; 85*1209e272SSimon Glass 86*1209e272SSimon Glass return ret; 87*1209e272SSimon Glass } 88*1209e272SSimon Glass 89*1209e272SSimon Glass /*** 90*1209e272SSimon Glass * sandbox_read_state_nodes() - Read state associated with a driver 91*1209e272SSimon Glass * 92*1209e272SSimon Glass * This looks through all compatible nodes and calls the read function on 93*1209e272SSimon Glass * each one, to read in the state. 94*1209e272SSimon Glass * 95*1209e272SSimon Glass * If nothing is found, it still calls the read function once, to set up a 96*1209e272SSimon Glass * single global state for that driver. 97*1209e272SSimon Glass * 98*1209e272SSimon Glass * @state: Sandbox state 99*1209e272SSimon Glass * @io: Method to use for reading state 100*1209e272SSimon Glass * @blob: FDT containing state 101*1209e272SSimon Glass * @return 0 if OK, -EINVAL if the read function returned failure 102*1209e272SSimon Glass */ 103*1209e272SSimon Glass int sandbox_read_state_nodes(struct sandbox_state *state, 104*1209e272SSimon Glass struct sandbox_state_io *io, const void *blob) 105*1209e272SSimon Glass { 106*1209e272SSimon Glass int count; 107*1209e272SSimon Glass int node; 108*1209e272SSimon Glass int ret; 109*1209e272SSimon Glass 110*1209e272SSimon Glass debug(" - read %s\n", io->name); 111*1209e272SSimon Glass if (!io->read) 112*1209e272SSimon Glass return 0; 113*1209e272SSimon Glass 114*1209e272SSimon Glass node = -1; 115*1209e272SSimon Glass count = 0; 116*1209e272SSimon Glass while (blob) { 117*1209e272SSimon Glass node = fdt_node_offset_by_compatible(blob, node, io->compat); 118*1209e272SSimon Glass if (node < 0) 119*1209e272SSimon Glass return 0; /* No more */ 120*1209e272SSimon Glass debug(" - read node '%s'\n", fdt_get_name(blob, node, NULL)); 121*1209e272SSimon Glass ret = io->read(blob, node); 122*1209e272SSimon Glass if (ret) { 123*1209e272SSimon Glass printf("Unable to read state for '%s'\n", io->compat); 124*1209e272SSimon Glass return -EINVAL; 125*1209e272SSimon Glass } 126*1209e272SSimon Glass count++; 127*1209e272SSimon Glass } 128*1209e272SSimon Glass 129*1209e272SSimon Glass /* 130*1209e272SSimon Glass * If we got no saved state, call the read function once without a 131*1209e272SSimon Glass * node, to set up the global state. 132*1209e272SSimon Glass */ 133*1209e272SSimon Glass if (count == 0) { 134*1209e272SSimon Glass debug(" - read global\n"); 135*1209e272SSimon Glass ret = io->read(NULL, -1); 136*1209e272SSimon Glass if (ret) { 137*1209e272SSimon Glass printf("Unable to read global state for '%s'\n", 138*1209e272SSimon Glass io->name); 139*1209e272SSimon Glass return -EINVAL; 140*1209e272SSimon Glass } 141*1209e272SSimon Glass } 142*1209e272SSimon Glass 143*1209e272SSimon Glass return 0; 144*1209e272SSimon Glass } 145*1209e272SSimon Glass 146*1209e272SSimon Glass int sandbox_read_state(struct sandbox_state *state, const char *fname) 147*1209e272SSimon Glass { 148*1209e272SSimon Glass struct sandbox_state_io *io; 149*1209e272SSimon Glass const void *blob; 150*1209e272SSimon Glass bool got_err; 151*1209e272SSimon Glass int ret; 152*1209e272SSimon Glass 153*1209e272SSimon Glass if (state->read_state && fname) { 154*1209e272SSimon Glass ret = state_read_file(state, fname); 155*1209e272SSimon Glass if (ret == -ENOENT && state->ignore_missing_state_on_read) 156*1209e272SSimon Glass ret = 0; 157*1209e272SSimon Glass if (ret) 158*1209e272SSimon Glass return ret; 159*1209e272SSimon Glass } 160*1209e272SSimon Glass 161*1209e272SSimon Glass /* Call all the state read funtcions */ 162*1209e272SSimon Glass got_err = false; 163*1209e272SSimon Glass blob = state->state_fdt; 164*1209e272SSimon Glass io = ll_entry_start(struct sandbox_state_io, state_io); 165*1209e272SSimon Glass for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) { 166*1209e272SSimon Glass ret = sandbox_read_state_nodes(state, io, blob); 167*1209e272SSimon Glass if (ret < 0) 168*1209e272SSimon Glass got_err = true; 169*1209e272SSimon Glass } 170*1209e272SSimon Glass 171*1209e272SSimon Glass if (state->read_state && fname) { 172*1209e272SSimon Glass debug("Read sandbox state from '%s'%s\n", fname, 173*1209e272SSimon Glass got_err ? " (with errors)" : ""); 174*1209e272SSimon Glass } 175*1209e272SSimon Glass 176*1209e272SSimon Glass return got_err ? -1 : 0; 177*1209e272SSimon Glass } 178*1209e272SSimon Glass 179*1209e272SSimon Glass /*** 180*1209e272SSimon Glass * sandbox_write_state_node() - Write state associated with a driver 181*1209e272SSimon Glass * 182*1209e272SSimon Glass * This calls the write function to write out global state for that driver. 183*1209e272SSimon Glass * 184*1209e272SSimon Glass * TODO(sjg@chromium.org): Support writing out state from multiple drivers 185*1209e272SSimon Glass * of the same time. We don't need this yet,and it will be much easier to 186*1209e272SSimon Glass * do when driver model is available. 187*1209e272SSimon Glass * 188*1209e272SSimon Glass * @state: Sandbox state 189*1209e272SSimon Glass * @io: Method to use for writing state 190*1209e272SSimon Glass * @return 0 if OK, -EIO if there is a fatal error (such as out of space 191*1209e272SSimon Glass * for adding the data), -EINVAL if the write function failed. 192*1209e272SSimon Glass */ 193*1209e272SSimon Glass int sandbox_write_state_node(struct sandbox_state *state, 194*1209e272SSimon Glass struct sandbox_state_io *io) 195*1209e272SSimon Glass { 196*1209e272SSimon Glass void *blob; 197*1209e272SSimon Glass int node; 198*1209e272SSimon Glass int ret; 199*1209e272SSimon Glass 200*1209e272SSimon Glass if (!io->write) 201*1209e272SSimon Glass return 0; 202*1209e272SSimon Glass 203*1209e272SSimon Glass ret = state_ensure_space(SANDBOX_STATE_MIN_SPACE); 204*1209e272SSimon Glass if (ret) { 205*1209e272SSimon Glass printf("Failed to add more space for state\n"); 206*1209e272SSimon Glass return -EIO; 207*1209e272SSimon Glass } 208*1209e272SSimon Glass 209*1209e272SSimon Glass /* The blob location can change when the size increases */ 210*1209e272SSimon Glass blob = state->state_fdt; 211*1209e272SSimon Glass node = fdt_node_offset_by_compatible(blob, -1, io->compat); 212*1209e272SSimon Glass if (node == -FDT_ERR_NOTFOUND) { 213*1209e272SSimon Glass node = fdt_add_subnode(blob, 0, io->name); 214*1209e272SSimon Glass if (node < 0) { 215*1209e272SSimon Glass printf("Cannot create node '%s': %s\n", io->name, 216*1209e272SSimon Glass fdt_strerror(node)); 217*1209e272SSimon Glass return -EIO; 218*1209e272SSimon Glass } 219*1209e272SSimon Glass 220*1209e272SSimon Glass if (fdt_setprop_string(blob, node, "compatible", io->compat)) { 221*1209e272SSimon Glass puts("Cannot set compatible\n"); 222*1209e272SSimon Glass return -EIO; 223*1209e272SSimon Glass } 224*1209e272SSimon Glass } else if (node < 0) { 225*1209e272SSimon Glass printf("Cannot access node '%s': %s\n", io->name, 226*1209e272SSimon Glass fdt_strerror(node)); 227*1209e272SSimon Glass return -EIO; 228*1209e272SSimon Glass } 229*1209e272SSimon Glass debug("Write state for '%s' to node %d\n", io->compat, node); 230*1209e272SSimon Glass ret = io->write(blob, node); 231*1209e272SSimon Glass if (ret) { 232*1209e272SSimon Glass printf("Unable to write state for '%s'\n", io->compat); 233*1209e272SSimon Glass return -EINVAL; 234*1209e272SSimon Glass } 235*1209e272SSimon Glass 236*1209e272SSimon Glass return 0; 237*1209e272SSimon Glass } 238*1209e272SSimon Glass 239*1209e272SSimon Glass int sandbox_write_state(struct sandbox_state *state, const char *fname) 240*1209e272SSimon Glass { 241*1209e272SSimon Glass struct sandbox_state_io *io; 242*1209e272SSimon Glass bool got_err; 243*1209e272SSimon Glass int size; 244*1209e272SSimon Glass int ret; 245*1209e272SSimon Glass int fd; 246*1209e272SSimon Glass 247*1209e272SSimon Glass /* Create a state FDT if we don't have one */ 248*1209e272SSimon Glass if (!state->state_fdt) { 249*1209e272SSimon Glass size = 0x4000; 250*1209e272SSimon Glass state->state_fdt = os_malloc(size); 251*1209e272SSimon Glass if (!state->state_fdt) { 252*1209e272SSimon Glass puts("No memory to create FDT\n"); 253*1209e272SSimon Glass return -ENOMEM; 254*1209e272SSimon Glass } 255*1209e272SSimon Glass ret = fdt_create_empty_tree(state->state_fdt, size); 256*1209e272SSimon Glass if (ret < 0) { 257*1209e272SSimon Glass printf("Cannot create empty state FDT: %s\n", 258*1209e272SSimon Glass fdt_strerror(ret)); 259*1209e272SSimon Glass ret = -EIO; 260*1209e272SSimon Glass goto err_create; 261*1209e272SSimon Glass } 262*1209e272SSimon Glass } 263*1209e272SSimon Glass 264*1209e272SSimon Glass /* Call all the state write funtcions */ 265*1209e272SSimon Glass got_err = false; 266*1209e272SSimon Glass io = ll_entry_start(struct sandbox_state_io, state_io); 267*1209e272SSimon Glass ret = 0; 268*1209e272SSimon Glass for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) { 269*1209e272SSimon Glass ret = sandbox_write_state_node(state, io); 270*1209e272SSimon Glass if (ret == -EIO) 271*1209e272SSimon Glass break; 272*1209e272SSimon Glass else if (ret) 273*1209e272SSimon Glass got_err = true; 274*1209e272SSimon Glass } 275*1209e272SSimon Glass 276*1209e272SSimon Glass if (ret == -EIO) { 277*1209e272SSimon Glass printf("Could not write sandbox state\n"); 278*1209e272SSimon Glass goto err_create; 279*1209e272SSimon Glass } 280*1209e272SSimon Glass 281*1209e272SSimon Glass ret = fdt_pack(state->state_fdt); 282*1209e272SSimon Glass if (ret < 0) { 283*1209e272SSimon Glass printf("Cannot pack state FDT: %s\n", fdt_strerror(ret)); 284*1209e272SSimon Glass ret = -EINVAL; 285*1209e272SSimon Glass goto err_create; 286*1209e272SSimon Glass } 287*1209e272SSimon Glass size = fdt_totalsize(state->state_fdt); 288*1209e272SSimon Glass fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT); 289*1209e272SSimon Glass if (fd < 0) { 290*1209e272SSimon Glass printf("Cannot open sandbox state file '%s'\n", fname); 291*1209e272SSimon Glass ret = -EIO; 292*1209e272SSimon Glass goto err_create; 293*1209e272SSimon Glass } 294*1209e272SSimon Glass if (os_write(fd, state->state_fdt, size) != size) { 295*1209e272SSimon Glass printf("Cannot write sandbox state file '%s'\n", fname); 296*1209e272SSimon Glass ret = -EIO; 297*1209e272SSimon Glass goto err_write; 298*1209e272SSimon Glass } 299*1209e272SSimon Glass os_close(fd); 300*1209e272SSimon Glass 301*1209e272SSimon Glass debug("Wrote sandbox state to '%s'%s\n", fname, 302*1209e272SSimon Glass got_err ? " (with errors)" : ""); 303*1209e272SSimon Glass 304*1209e272SSimon Glass return 0; 305*1209e272SSimon Glass err_write: 306*1209e272SSimon Glass os_close(fd); 307*1209e272SSimon Glass err_create: 308*1209e272SSimon Glass os_free(state->state_fdt); 309*1209e272SSimon Glass 310*1209e272SSimon Glass return ret; 311*1209e272SSimon Glass } 312*1209e272SSimon Glass 313*1209e272SSimon Glass int state_setprop(int node, const char *prop_name, const void *data, int size) 314*1209e272SSimon Glass { 315*1209e272SSimon Glass void *blob; 316*1209e272SSimon Glass int len; 317*1209e272SSimon Glass int ret; 318*1209e272SSimon Glass 319*1209e272SSimon Glass fdt_getprop(state->state_fdt, node, prop_name, &len); 320*1209e272SSimon Glass 321*1209e272SSimon Glass /* Add space for the new property, its name and some overhead */ 322*1209e272SSimon Glass ret = state_ensure_space(size - len + strlen(prop_name) + 32); 323*1209e272SSimon Glass if (ret) 324*1209e272SSimon Glass return ret; 325*1209e272SSimon Glass 326*1209e272SSimon Glass /* This should succeed, barring a mutiny */ 327*1209e272SSimon Glass blob = state->state_fdt; 328*1209e272SSimon Glass ret = fdt_setprop(blob, node, prop_name, data, size); 329*1209e272SSimon Glass if (ret) { 330*1209e272SSimon Glass printf("%s: Unable to set property '%s' in node '%s': %s\n", 331*1209e272SSimon Glass __func__, prop_name, fdt_get_name(blob, node, NULL), 332*1209e272SSimon Glass fdt_strerror(ret)); 333*1209e272SSimon Glass return -ENOSPC; 334*1209e272SSimon Glass } 335*1209e272SSimon Glass 336*1209e272SSimon Glass return 0; 337*1209e272SSimon Glass } 338*1209e272SSimon 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 3685c2859cdSSimon Glass if (state->write_ram_buf) { 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 376*1209e272SSimon Glass if (state->write_state) { 377*1209e272SSimon Glass if (sandbox_write_state(state, state->state_fname)) { 378*1209e272SSimon Glass printf("Failed to write sandbox state\n"); 379*1209e272SSimon Glass return -1; 380*1209e272SSimon Glass } 381*1209e272SSimon Glass } 382*1209e272SSimon Glass 383*1209e272SSimon Glass if (state->state_fdt) 384*1209e272SSimon Glass os_free(state->state_fdt); 385*1209e272SSimon Glass memset(state, '\0', sizeof(*state)); 386*1209e272SSimon Glass 3875c2859cdSSimon Glass return 0; 3885c2859cdSSimon Glass } 389