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