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