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