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