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