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
44typedef	int (*cfp_t)(va_list argp);
45
46static int calls_no;
47
48/*
49 * pseudo signature:
50 *
51 * int API_getc(int *c)
52 */
53static 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 */
69static 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 */
85static 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 */
101static 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 */
117static 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 */
133static 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 */
149static 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 */
165static 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
199static 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
232static 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
264static 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 */
318static 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 */
400static 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 */
471static 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 */
494static 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 */
515static 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
553done:
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 */
565static 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 */
581static 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 */
598static int API_display_clear(va_list ap)
599{
600	display_clear();
601	return 0;
602}
603
604static 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 */
622int 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
645int 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
698void 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}
716