]> git.ipfire.org Git - thirdparty/u-boot.git/blob - api/api.c
Merge patch series "fs: fat: calculate FAT type based on cluster count"
[thirdparty/u-boot.git] / api / api.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2007 Semihalf
4 *
5 * Written by: Rafal Jaworowski <raj@semihalf.com>
6 */
7
8 #include <config.h>
9 #include <command.h>
10 #include <common.h>
11 #include <env.h>
12 #include <malloc.h>
13 #include <env_internal.h>
14 #include <linux/delay.h>
15 #include <linux/types.h>
16 #include <api_public.h>
17 #include <u-boot/crc.h>
18
19 #include "api_private.h"
20
21 #define DEBUG
22 #undef DEBUG
23
24 /*****************************************************************************
25 *
26 * This is the API core.
27 *
28 * API_ functions are part of U-Boot code and constitute the lowest level
29 * calls:
30 *
31 * - they know what values they need as arguments
32 * - their direct return value pertains to the API_ "shell" itself (0 on
33 * success, some error code otherwise)
34 * - if the call returns a value it is buried within arguments
35 *
36 ****************************************************************************/
37
38 #ifdef DEBUG
39 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
40 #else
41 #define debugf(fmt, args...)
42 #endif
43
44 typedef int (*cfp_t)(va_list argp);
45
46 static int calls_no;
47
48 /*
49 * pseudo signature:
50 *
51 * int API_getc(int *c)
52 */
53 static int API_getc(va_list ap)
54 {
55 int *c;
56
57 if ((c = (int *)va_arg(ap, uintptr_t)) == NULL)
58 return API_EINVAL;
59
60 *c = getchar();
61 return 0;
62 }
63
64 /*
65 * pseudo signature:
66 *
67 * int API_tstc(int *c)
68 */
69 static int API_tstc(va_list ap)
70 {
71 int *t;
72
73 if ((t = (int *)va_arg(ap, uintptr_t)) == NULL)
74 return API_EINVAL;
75
76 *t = tstc();
77 return 0;
78 }
79
80 /*
81 * pseudo signature:
82 *
83 * int API_putc(char *ch)
84 */
85 static int API_putc(va_list ap)
86 {
87 char *c;
88
89 if ((c = (char *)va_arg(ap, uintptr_t)) == NULL)
90 return API_EINVAL;
91
92 putc(*c);
93 return 0;
94 }
95
96 /*
97 * pseudo signature:
98 *
99 * int API_puts(char **s)
100 */
101 static int API_puts(va_list ap)
102 {
103 char *s;
104
105 if ((s = (char *)va_arg(ap, uintptr_t)) == NULL)
106 return API_EINVAL;
107
108 puts(s);
109 return 0;
110 }
111
112 /*
113 * pseudo signature:
114 *
115 * int API_reset(void)
116 */
117 static int API_reset(va_list ap)
118 {
119 do_reset(NULL, 0, 0, NULL);
120
121 /* NOT REACHED */
122 return 0;
123 }
124
125 /*
126 * pseudo signature:
127 *
128 * int API_get_sys_info(struct sys_info *si)
129 *
130 * fill out the sys_info struct containing selected parameters about the
131 * machine
132 */
133 static int API_get_sys_info(va_list ap)
134 {
135 struct sys_info *si;
136
137 si = (struct sys_info *)va_arg(ap, uintptr_t);
138 if (si == NULL)
139 return API_ENOMEM;
140
141 return (platform_sys_info(si)) ? 0 : API_ENODEV;
142 }
143
144 /*
145 * pseudo signature:
146 *
147 * int API_udelay(unsigned long *udelay)
148 */
149 static int API_udelay(va_list ap)
150 {
151 unsigned long *d;
152
153 if ((d = (unsigned long *)va_arg(ap, unsigned long)) == NULL)
154 return API_EINVAL;
155
156 udelay(*d);
157 return 0;
158 }
159
160 /*
161 * pseudo signature:
162 *
163 * int API_get_timer(unsigned long *current, unsigned long *base)
164 */
165 static int API_get_timer(va_list ap)
166 {
167 unsigned long *base, *cur;
168
169 cur = (unsigned long *)va_arg(ap, unsigned long);
170 if (cur == NULL)
171 return API_EINVAL;
172
173 base = (unsigned long *)va_arg(ap, unsigned long);
174 if (base == NULL)
175 return API_EINVAL;
176
177 *cur = get_timer(*base);
178 return 0;
179 }
180
181
182 /*****************************************************************************
183 *
184 * pseudo signature:
185 *
186 * int API_dev_enum(struct device_info *)
187 *
188 *
189 * cookies uniqely identify the previously enumerated device instance and
190 * provide a hint for what to inspect in current enum iteration:
191 *
192 * - net: &eth_device struct address from list pointed to by eth_devices
193 *
194 * - storage: struct blk_desc struct address from &ide_dev_desc[n],
195 * &scsi_dev_desc[n] and similar tables
196 *
197 ****************************************************************************/
198
199 static int API_dev_enum(va_list ap)
200 {
201 struct device_info *di;
202
203 /* arg is ptr to the device_info struct we are going to fill out */
204 di = (struct device_info *)va_arg(ap, uintptr_t);
205 if (di == NULL)
206 return API_EINVAL;
207
208 if (di->cookie == NULL) {
209 /* start over - clean up enumeration */
210 dev_enum_reset(); /* XXX shouldn't the name contain 'stor'? */
211 debugf("RESTART ENUM\n");
212
213 /* net device enumeration first */
214 if (dev_enum_net(di))
215 return 0;
216 }
217
218 /*
219 * The hidden assumption is there can only be one active network
220 * device and it is identified upon enumeration (re)start, so there's
221 * no point in trying to find network devices in other cases than the
222 * (re)start and hence the 'next' device can only be storage
223 */
224 if (!dev_enum_storage(di))
225 /* make sure we mark there are no more devices */
226 di->cookie = NULL;
227
228 return 0;
229 }
230
231
232 static int API_dev_open(va_list ap)
233 {
234 struct device_info *di;
235 int err = 0;
236
237 /* arg is ptr to the device_info struct */
238 di = (struct device_info *)va_arg(ap, uintptr_t);
239 if (di == NULL)
240 return API_EINVAL;
241
242 /* Allow only one consumer of the device at a time */
243 if (di->state == DEV_STA_OPEN)
244 return API_EBUSY;
245
246 if (di->cookie == NULL)
247 return API_ENODEV;
248
249 if (di->type & DEV_TYP_STOR)
250 err = dev_open_stor(di->cookie);
251
252 else if (di->type & DEV_TYP_NET)
253 err = dev_open_net(di->cookie);
254 else
255 err = API_ENODEV;
256
257 if (!err)
258 di->state = DEV_STA_OPEN;
259
260 return err;
261 }
262
263
264 static int API_dev_close(va_list ap)
265 {
266 struct device_info *di;
267 int err = 0;
268
269 /* arg is ptr to the device_info struct */
270 di = (struct device_info *)va_arg(ap, uintptr_t);
271 if (di == NULL)
272 return API_EINVAL;
273
274 if (di->state == DEV_STA_CLOSED)
275 return 0;
276
277 if (di->cookie == NULL)
278 return API_ENODEV;
279
280 if (di->type & DEV_TYP_STOR)
281 err = dev_close_stor(di->cookie);
282
283 else if (di->type & DEV_TYP_NET)
284 err = dev_close_net(di->cookie);
285 else
286 /*
287 * In case of unknown device we cannot change its state, so
288 * only return error code
289 */
290 err = API_ENODEV;
291
292 if (!err)
293 di->state = DEV_STA_CLOSED;
294
295 return err;
296 }
297
298
299 /*
300 * pseudo signature:
301 *
302 * int API_dev_write(
303 * struct device_info *di,
304 * void *buf,
305 * int *len,
306 * unsigned long *start
307 * )
308 *
309 * buf: ptr to buffer from where to get the data to send
310 *
311 * len: ptr to length to be read
312 * - network: len of packet to be sent (in bytes)
313 * - storage: # of blocks to write (can vary in size depending on define)
314 *
315 * start: ptr to start block (only used for storage devices, ignored for
316 * network)
317 */
318 static int API_dev_write(va_list ap)
319 {
320 struct device_info *di;
321 void *buf;
322 lbasize_t *len_stor, act_len_stor;
323 lbastart_t *start;
324 int *len_net;
325 int err = 0;
326
327 /* 1. arg is ptr to the device_info struct */
328 di = (struct device_info *)va_arg(ap, uintptr_t);
329 if (di == NULL)
330 return API_EINVAL;
331
332 /* XXX should we check if device is open? i.e. the ->state ? */
333
334 if (di->cookie == NULL)
335 return API_ENODEV;
336
337 /* 2. arg is ptr to buffer from where to get data to write */
338 buf = (void *)va_arg(ap, uintptr_t);
339 if (buf == NULL)
340 return API_EINVAL;
341
342 if (di->type & DEV_TYP_STOR) {
343 /* 3. arg - ptr to var with # of blocks to write */
344 len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
345 if (!len_stor)
346 return API_EINVAL;
347 if (*len_stor <= 0)
348 return API_EINVAL;
349
350 /* 4. arg - ptr to var with start block */
351 start = (lbastart_t *)va_arg(ap, uintptr_t);
352
353 act_len_stor = dev_write_stor(di->cookie, buf, *len_stor, *start);
354 if (act_len_stor != *len_stor) {
355 debugf("write @ %llu: done %llu out of %llu blocks",
356 (uint64_t)blk, (uint64_t)act_len_stor,
357 (uint64_t)len_stor);
358 return API_EIO;
359 }
360
361 } else if (di->type & DEV_TYP_NET) {
362 /* 3. arg points to the var with length of packet to write */
363 len_net = (int *)va_arg(ap, uintptr_t);
364 if (!len_net)
365 return API_EINVAL;
366 if (*len_net <= 0)
367 return API_EINVAL;
368
369 err = dev_write_net(di->cookie, buf, *len_net);
370
371 } else
372 err = API_ENODEV;
373
374 return err;
375 }
376
377
378 /*
379 * pseudo signature:
380 *
381 * int API_dev_read(
382 * struct device_info *di,
383 * void *buf,
384 * size_t *len,
385 * unsigned long *start
386 * size_t *act_len
387 * )
388 *
389 * buf: ptr to buffer where to put the read data
390 *
391 * len: ptr to length to be read
392 * - network: len of packet to read (in bytes)
393 * - storage: # of blocks to read (can vary in size depending on define)
394 *
395 * start: ptr to start block (only used for storage devices, ignored for
396 * network)
397 *
398 * act_len: ptr to where to put the len actually read
399 */
400 static int API_dev_read(va_list ap)
401 {
402 struct device_info *di;
403 void *buf;
404 lbasize_t *len_stor, *act_len_stor;
405 lbastart_t *start;
406 int *len_net, *act_len_net;
407
408 /* 1. arg is ptr to the device_info struct */
409 di = (struct device_info *)va_arg(ap, uintptr_t);
410 if (di == NULL)
411 return API_EINVAL;
412
413 /* XXX should we check if device is open? i.e. the ->state ? */
414
415 if (di->cookie == NULL)
416 return API_ENODEV;
417
418 /* 2. arg is ptr to buffer from where to put the read data */
419 buf = (void *)va_arg(ap, uintptr_t);
420 if (buf == NULL)
421 return API_EINVAL;
422
423 if (di->type & DEV_TYP_STOR) {
424 /* 3. arg - ptr to var with # of blocks to read */
425 len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
426 if (!len_stor)
427 return API_EINVAL;
428 if (*len_stor <= 0)
429 return API_EINVAL;
430
431 /* 4. arg - ptr to var with start block */
432 start = (lbastart_t *)va_arg(ap, uintptr_t);
433
434 /* 5. arg - ptr to var where to put the len actually read */
435 act_len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
436 if (!act_len_stor)
437 return API_EINVAL;
438
439 *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start);
440
441 } else if (di->type & DEV_TYP_NET) {
442
443 /* 3. arg points to the var with length of packet to read */
444 len_net = (int *)va_arg(ap, uintptr_t);
445 if (!len_net)
446 return API_EINVAL;
447 if (*len_net <= 0)
448 return API_EINVAL;
449
450 /* 4. - ptr to var where to put the len actually read */
451 act_len_net = (int *)va_arg(ap, uintptr_t);
452 if (!act_len_net)
453 return API_EINVAL;
454
455 *act_len_net = dev_read_net(di->cookie, buf, *len_net);
456
457 } else
458 return API_ENODEV;
459
460 return 0;
461 }
462
463
464 /*
465 * pseudo signature:
466 *
467 * int API_env_get(const char *name, char **value)
468 *
469 * name: ptr to name of env var
470 */
471 static int API_env_get(va_list ap)
472 {
473 char *name, **value;
474
475 if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
476 return API_EINVAL;
477 if ((value = (char **)va_arg(ap, uintptr_t)) == NULL)
478 return API_EINVAL;
479
480 *value = env_get(name);
481
482 return 0;
483 }
484
485 /*
486 * pseudo signature:
487 *
488 * int API_env_set(const char *name, const char *value)
489 *
490 * name: ptr to name of env var
491 *
492 * value: ptr to value to be set
493 */
494 static int API_env_set(va_list ap)
495 {
496 char *name, *value;
497
498 if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
499 return API_EINVAL;
500 if ((value = (char *)va_arg(ap, uintptr_t)) == NULL)
501 return API_EINVAL;
502
503 env_set(name, value);
504
505 return 0;
506 }
507
508 /*
509 * pseudo signature:
510 *
511 * int API_env_enum(const char *last, char **next)
512 *
513 * last: ptr to name of env var found in last iteration
514 */
515 static int API_env_enum(va_list ap)
516 {
517 int i, buflen;
518 char *last, **next, *s;
519 struct env_entry *match, search;
520 static char *var;
521
522 last = (char *)va_arg(ap, unsigned long);
523
524 if ((next = (char **)va_arg(ap, uintptr_t)) == NULL)
525 return API_EINVAL;
526
527 if (last == NULL) {
528 var = NULL;
529 i = 0;
530 } else {
531 var = strdup(last);
532 s = strchr(var, '=');
533 if (s != NULL)
534 *s = 0;
535 search.key = var;
536 i = hsearch_r(search, ENV_FIND, &match, &env_htab, 0);
537 if (i == 0) {
538 i = API_EINVAL;
539 goto done;
540 }
541 }
542
543 /* match the next entry after i */
544 i = hmatch_r("", i, &match, &env_htab);
545 if (i == 0)
546 goto done;
547 buflen = strlen(match->key) + strlen(match->data) + 2;
548 var = realloc(var, buflen);
549 snprintf(var, buflen, "%s=%s", match->key, match->data);
550 *next = var;
551 return 0;
552
553 done:
554 free(var);
555 var = NULL;
556 *next = NULL;
557 return i;
558 }
559
560 /*
561 * pseudo signature:
562 *
563 * int API_display_get_info(int type, struct display_info *di)
564 */
565 static int API_display_get_info(va_list ap)
566 {
567 int type;
568 struct display_info *di;
569
570 type = va_arg(ap, int);
571 di = va_arg(ap, struct display_info *);
572
573 return display_get_info(type, di);
574 }
575
576 /*
577 * pseudo signature:
578 *
579 * int API_display_draw_bitmap(ulong bitmap, int x, int y)
580 */
581 static int API_display_draw_bitmap(va_list ap)
582 {
583 ulong bitmap;
584 int x, y;
585
586 bitmap = va_arg(ap, ulong);
587 x = va_arg(ap, int);
588 y = va_arg(ap, int);
589
590 return display_draw_bitmap(bitmap, x, y);
591 }
592
593 /*
594 * pseudo signature:
595 *
596 * void API_display_clear(void)
597 */
598 static int API_display_clear(va_list ap)
599 {
600 display_clear();
601 return 0;
602 }
603
604 static cfp_t calls_table[API_MAXCALL] = { NULL, };
605
606 /*
607 * The main syscall entry point - this is not reentrant, only one call is
608 * serviced until finished.
609 *
610 * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
611 *
612 * call: syscall number
613 *
614 * retval: points to the return value placeholder, this is the place the
615 * syscall puts its return value, if NULL the caller does not
616 * expect a return value
617 *
618 * ... syscall arguments (variable number)
619 *
620 * returns: 0 if the call not found, 1 if serviced
621 */
622 int syscall(int call, int *retval, ...)
623 {
624 va_list ap;
625 int rv;
626
627 if (call < 0 || call >= calls_no) {
628 debugf("invalid call #%d\n", call);
629 return 0;
630 }
631
632 if (calls_table[call] == NULL) {
633 debugf("syscall #%d does not have a handler\n", call);
634 return 0;
635 }
636
637 va_start(ap, retval);
638 rv = calls_table[call](ap);
639 if (retval != NULL)
640 *retval = rv;
641
642 return 1;
643 }
644
645 int api_init(void)
646 {
647 struct api_signature *sig;
648
649 /* TODO put this into linker set one day... */
650 calls_table[API_RSVD] = NULL;
651 calls_table[API_GETC] = &API_getc;
652 calls_table[API_PUTC] = &API_putc;
653 calls_table[API_TSTC] = &API_tstc;
654 calls_table[API_PUTS] = &API_puts;
655 calls_table[API_RESET] = &API_reset;
656 calls_table[API_GET_SYS_INFO] = &API_get_sys_info;
657 calls_table[API_UDELAY] = &API_udelay;
658 calls_table[API_GET_TIMER] = &API_get_timer;
659 calls_table[API_DEV_ENUM] = &API_dev_enum;
660 calls_table[API_DEV_OPEN] = &API_dev_open;
661 calls_table[API_DEV_CLOSE] = &API_dev_close;
662 calls_table[API_DEV_READ] = &API_dev_read;
663 calls_table[API_DEV_WRITE] = &API_dev_write;
664 calls_table[API_ENV_GET] = &API_env_get;
665 calls_table[API_ENV_SET] = &API_env_set;
666 calls_table[API_ENV_ENUM] = &API_env_enum;
667 calls_table[API_DISPLAY_GET_INFO] = &API_display_get_info;
668 calls_table[API_DISPLAY_DRAW_BITMAP] = &API_display_draw_bitmap;
669 calls_table[API_DISPLAY_CLEAR] = &API_display_clear;
670 calls_no = API_MAXCALL;
671
672 debugf("API initialized with %d calls\n", calls_no);
673
674 dev_stor_init();
675
676 /*
677 * Produce the signature so the API consumers can find it
678 */
679 sig = malloc(sizeof(struct api_signature));
680 if (sig == NULL) {
681 printf("API: could not allocate memory for the signature!\n");
682 return -ENOMEM;
683 }
684
685 env_set_hex("api_address", (unsigned long)sig);
686 debugf("API sig @ 0x%lX\n", (unsigned long)sig);
687 memcpy(sig->magic, API_SIG_MAGIC, 8);
688 sig->version = API_SIG_VERSION;
689 sig->syscall = &syscall;
690 sig->checksum = 0;
691 sig->checksum = crc32(0, (unsigned char *)sig,
692 sizeof(struct api_signature));
693 debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall);
694
695 return 0;
696 }
697
698 void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
699 int flags)
700 {
701 int i;
702
703 if (!si->mr || !size || (flags == 0))
704 return;
705
706 /* find free slot */
707 for (i = 0; i < si->mr_no; i++)
708 if (si->mr[i].flags == 0) {
709 /* insert new mem region */
710 si->mr[i].start = start;
711 si->mr[i].size = size;
712 si->mr[i].flags = flags;
713 return;
714 }
715 }