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