1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2007 Semihalf
5 * Written by: Rafal Jaworowski <raj@semihalf.com>
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>
19 #include "api_private.h"
24 /*****************************************************************************
26 * This is the API core.
28 * API_ functions are part of U-Boot code and constitute the lowest level
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
36 ****************************************************************************/
39 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
41 #define debugf(fmt, args...)
44 typedef int (*cfp_t)(va_list argp);
51 * int API_getc(int *c)
53 static int API_getc(va_list ap)
57 if ((c = (int *)va_arg(ap, uintptr_t)) == NULL)
67 * int API_tstc(int *c)
69 static int API_tstc(va_list ap)
73 if ((t = (int *)va_arg(ap, uintptr_t)) == NULL)
83 * int API_putc(char *ch)
85 static int API_putc(va_list ap)
89 if ((c = (char *)va_arg(ap, uintptr_t)) == NULL)
99 * int API_puts(char **s)
101 static int API_puts(va_list ap)
105 if ((s = (char *)va_arg(ap, uintptr_t)) == NULL)
115 * int API_reset(void)
117 static int API_reset(va_list ap)
119 do_reset(NULL, 0, 0, NULL);
128 * int API_get_sys_info(struct sys_info *si)
130 * fill out the sys_info struct containing selected parameters about the
133 static int API_get_sys_info(va_list ap)
137 si = (struct sys_info *)va_arg(ap, uintptr_t);
141 return (platform_sys_info(si)) ? 0 : API_ENODEV;
147 * int API_udelay(unsigned long *udelay)
149 static int API_udelay(va_list ap)
153 if ((d = (unsigned long *)va_arg(ap, unsigned long)) == NULL)
163 * int API_get_timer(unsigned long *current, unsigned long *base)
165 static int API_get_timer(va_list ap)
167 unsigned long *base, *cur;
169 cur = (unsigned long *)va_arg(ap, unsigned long);
173 base = (unsigned long *)va_arg(ap, unsigned long);
177 *cur = get_timer(*base);
182 /*****************************************************************************
186 * int API_dev_enum(struct device_info *)
189 * cookies uniqely identify the previously enumerated device instance and
190 * provide a hint for what to inspect in current enum iteration:
192 * - net: ð_device struct address from list pointed to by eth_devices
194 * - storage: struct blk_desc struct address from &ide_dev_desc[n],
195 * &scsi_dev_desc[n] and similar tables
197 ****************************************************************************/
199 static int API_dev_enum(va_list ap)
201 struct device_info *di;
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);
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");
213 /* net device enumeration first */
214 if (dev_enum_net(di))
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
224 if (!dev_enum_storage(di))
225 /* make sure we mark there are no more devices */
232 static int API_dev_open(va_list ap)
234 struct device_info *di;
237 /* arg is ptr to the device_info struct */
238 di = (struct device_info *)va_arg(ap, uintptr_t);
242 /* Allow only one consumer of the device at a time */
243 if (di->state == DEV_STA_OPEN)
246 if (di->cookie == NULL)
249 if (di->type & DEV_TYP_STOR)
250 err = dev_open_stor(di->cookie);
252 else if (di->type & DEV_TYP_NET)
253 err = dev_open_net(di->cookie);
258 di->state = DEV_STA_OPEN;
264 static int API_dev_close(va_list ap)
266 struct device_info *di;
269 /* arg is ptr to the device_info struct */
270 di = (struct device_info *)va_arg(ap, uintptr_t);
274 if (di->state == DEV_STA_CLOSED)
277 if (di->cookie == NULL)
280 if (di->type & DEV_TYP_STOR)
281 err = dev_close_stor(di->cookie);
283 else if (di->type & DEV_TYP_NET)
284 err = dev_close_net(di->cookie);
287 * In case of unknown device we cannot change its state, so
288 * only return error code
293 di->state = DEV_STA_CLOSED;
303 * struct device_info *di,
306 * unsigned long *start
309 * buf: ptr to buffer from where to get the data to send
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)
315 * start: ptr to start block (only used for storage devices, ignored for
318 static int API_dev_write(va_list ap)
320 struct device_info *di;
322 lbasize_t *len_stor, act_len_stor;
327 /* 1. arg is ptr to the device_info struct */
328 di = (struct device_info *)va_arg(ap, uintptr_t);
332 /* XXX should we check if device is open? i.e. the ->state ? */
334 if (di->cookie == NULL)
337 /* 2. arg is ptr to buffer from where to get data to write */
338 buf = (void *)va_arg(ap, uintptr_t);
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);
350 /* 4. arg - ptr to var with start block */
351 start = (lbastart_t *)va_arg(ap, uintptr_t);
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,
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);
369 err = dev_write_net(di->cookie, buf, *len_net);
382 * struct device_info *di,
385 * unsigned long *start
389 * buf: ptr to buffer where to put the read data
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)
395 * start: ptr to start block (only used for storage devices, ignored for
398 * act_len: ptr to where to put the len actually read
400 static int API_dev_read(va_list ap)
402 struct device_info *di;
404 lbasize_t *len_stor, *act_len_stor;
406 int *len_net, *act_len_net;
408 /* 1. arg is ptr to the device_info struct */
409 di = (struct device_info *)va_arg(ap, uintptr_t);
413 /* XXX should we check if device is open? i.e. the ->state ? */
415 if (di->cookie == NULL)
418 /* 2. arg is ptr to buffer from where to put the read data */
419 buf = (void *)va_arg(ap, uintptr_t);
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);
431 /* 4. arg - ptr to var with start block */
432 start = (lbastart_t *)va_arg(ap, uintptr_t);
434 /* 5. arg - ptr to var where to put the len actually read */
435 act_len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
439 *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start);
441 } else if (di->type & DEV_TYP_NET) {
443 /* 3. arg points to the var with length of packet to read */
444 len_net = (int *)va_arg(ap, uintptr_t);
450 /* 4. - ptr to var where to put the len actually read */
451 act_len_net = (int *)va_arg(ap, uintptr_t);
455 *act_len_net = dev_read_net(di->cookie, buf, *len_net);
467 * int API_env_get(const char *name, char **value)
469 * name: ptr to name of env var
471 static int API_env_get(va_list ap)
475 if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
477 if ((value = (char **)va_arg(ap, uintptr_t)) == NULL)
480 *value = env_get(name);
488 * int API_env_set(const char *name, const char *value)
490 * name: ptr to name of env var
492 * value: ptr to value to be set
494 static int API_env_set(va_list ap)
498 if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
500 if ((value = (char *)va_arg(ap, uintptr_t)) == NULL)
503 env_set(name, value);
511 * int API_env_enum(const char *last, char **next)
513 * last: ptr to name of env var found in last iteration
515 static int API_env_enum(va_list ap)
518 char *last, **next, *s;
519 struct env_entry *match, search;
522 last = (char *)va_arg(ap, unsigned long);
524 if ((next = (char **)va_arg(ap, uintptr_t)) == NULL)
532 s = strchr(var, '=');
536 i = hsearch_r(search, ENV_FIND, &match, &env_htab, 0);
543 /* match the next entry after i */
544 i = hmatch_r("", i, &match, &env_htab);
547 buflen = strlen(match->key) + strlen(match->data) + 2;
548 var = realloc(var, buflen);
549 snprintf(var, buflen, "%s=%s", match->key, match->data);
563 * int API_display_get_info(int type, struct display_info *di)
565 static int API_display_get_info(va_list ap)
568 struct display_info *di;
570 type = va_arg(ap, int);
571 di = va_arg(ap, struct display_info *);
573 return display_get_info(type, di);
579 * int API_display_draw_bitmap(ulong bitmap, int x, int y)
581 static int API_display_draw_bitmap(va_list ap)
586 bitmap = va_arg(ap, ulong);
590 return display_draw_bitmap(bitmap, x, y);
596 * void API_display_clear(void)
598 static int API_display_clear(va_list ap)
604 static cfp_t calls_table[API_MAXCALL] = { NULL, };
607 * The main syscall entry point - this is not reentrant, only one call is
608 * serviced until finished.
610 * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
612 * call: syscall number
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
618 * ... syscall arguments (variable number)
620 * returns: 0 if the call not found, 1 if serviced
622 int syscall(int call, int *retval, ...)
627 if (call < 0 || call >= calls_no) {
628 debugf("invalid call #%d\n", call);
632 if (calls_table[call] == NULL) {
633 debugf("syscall #%d does not have a handler\n", call);
637 va_start(ap, retval);
638 rv = calls_table[call](ap);
647 struct api_signature *sig;
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;
672 debugf("API initialized with %d calls\n", calls_no);
677 * Produce the signature so the API consumers can find it
679 sig = malloc(sizeof(struct api_signature));
681 printf("API: could not allocate memory for the signature!\n");
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;
691 sig->checksum = crc32(0, (unsigned char *)sig,
692 sizeof(struct api_signature));
693 debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall);
696 void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
701 if (!si->mr || !size || (flags == 0))
705 for (i = 0; i < si->mr_no; i++)
706 if (si->mr[i].flags == 0) {
707 /* insert new mem region */
708 si->mr[i].start = start;
709 si->mr[i].size = size;
710 si->mr[i].flags = flags;