]> Git Repo - u-boot.git/blob - api/api.c
Merge patch series "Add AM64x Support to PRUSS and PRU_RPROC driver"
[u-boot.git] / api / api.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2007 Semihalf
4  *
5  * Written by: Rafal Jaworowski <[email protected]>
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  *
186  * pseudo signature:
187  *
188  * int API_dev_enum(struct device_info *)
189  *
190  *
191  * cookies uniqely identify the previously enumerated device instance and
192  * provide a hint for what to inspect in current enum iteration:
193  *
194  *   - net: &eth_device struct address from list pointed to by eth_devices
195  *
196  *   - storage: struct blk_desc struct address from &ide_dev_desc[n],
197  *     &scsi_dev_desc[n] and similar tables
198  *
199  ****************************************************************************/
200
201 static int API_dev_enum(va_list ap)
202 {
203         struct device_info *di;
204
205         /* arg is ptr to the device_info struct we are going to fill out */
206         di = (struct device_info *)va_arg(ap, uintptr_t);
207         if (di == NULL)
208                 return API_EINVAL;
209
210         if (di->cookie == NULL) {
211                 /* start over - clean up enumeration */
212                 dev_enum_reset();       /* XXX shouldn't the name contain 'stor'? */
213                 debugf("RESTART ENUM\n");
214
215                 /* net device enumeration first */
216                 if (dev_enum_net(di))
217                         return 0;
218         }
219
220         /*
221          * The hidden assumption is there can only be one active network
222          * device and it is identified upon enumeration (re)start, so there's
223          * no point in trying to find network devices in other cases than the
224          * (re)start and hence the 'next' device can only be storage
225          */
226         if (!dev_enum_storage(di))
227                 /* make sure we mark there are no more devices */
228                 di->cookie = NULL;
229
230         return 0;
231 }
232
233
234 static int API_dev_open(va_list ap)
235 {
236         struct device_info *di;
237         int err = 0;
238
239         /* arg is ptr to the device_info struct */
240         di = (struct device_info *)va_arg(ap, uintptr_t);
241         if (di == NULL)
242                 return API_EINVAL;
243
244         /* Allow only one consumer of the device at a time */
245         if (di->state == DEV_STA_OPEN)
246                 return API_EBUSY;
247
248         if (di->cookie == NULL)
249                 return API_ENODEV;
250
251         if (di->type & DEV_TYP_STOR)
252                 err = dev_open_stor(di->cookie);
253
254         else if (di->type & DEV_TYP_NET)
255                 err = dev_open_net(di->cookie);
256         else
257                 err = API_ENODEV;
258
259         if (!err)
260                 di->state = DEV_STA_OPEN;
261
262         return err;
263 }
264
265
266 static int API_dev_close(va_list ap)
267 {
268         struct device_info *di;
269         int err = 0;
270
271         /* arg is ptr to the device_info struct */
272         di = (struct device_info *)va_arg(ap, uintptr_t);
273         if (di == NULL)
274                 return API_EINVAL;
275
276         if (di->state == DEV_STA_CLOSED)
277                 return 0;
278
279         if (di->cookie == NULL)
280                 return API_ENODEV;
281
282         if (di->type & DEV_TYP_STOR)
283                 err = dev_close_stor(di->cookie);
284
285         else if (di->type & DEV_TYP_NET)
286                 err = dev_close_net(di->cookie);
287         else
288                 /*
289                  * In case of unknown device we cannot change its state, so
290                  * only return error code
291                  */
292                 err = API_ENODEV;
293
294         if (!err)
295                 di->state = DEV_STA_CLOSED;
296
297         return err;
298 }
299
300
301 /*
302  * pseudo signature:
303  *
304  * int API_dev_write(
305  *      struct device_info *di,
306  *      void *buf,
307  *      int *len,
308  *      unsigned long *start
309  * )
310  *
311  * buf: ptr to buffer from where to get the data to send
312  *
313  * len: ptr to length to be read
314  *      - network: len of packet to be sent (in bytes)
315  *      - storage: # of blocks to write (can vary in size depending on define)
316  *
317  * start: ptr to start block (only used for storage devices, ignored for
318  *        network)
319  */
320 static int API_dev_write(va_list ap)
321 {
322         struct device_info *di;
323         void *buf;
324         lbasize_t *len_stor, act_len_stor;
325         lbastart_t *start;
326         int *len_net;
327         int err = 0;
328
329         /* 1. arg is ptr to the device_info struct */
330         di = (struct device_info *)va_arg(ap, uintptr_t);
331         if (di == NULL)
332                 return API_EINVAL;
333
334         /* XXX should we check if device is open? i.e. the ->state ? */
335
336         if (di->cookie == NULL)
337                 return API_ENODEV;
338
339         /* 2. arg is ptr to buffer from where to get data to write */
340         buf = (void *)va_arg(ap, uintptr_t);
341         if (buf == NULL)
342                 return API_EINVAL;
343
344         if (di->type & DEV_TYP_STOR) {
345                 /* 3. arg - ptr to var with # of blocks to write */
346                 len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
347                 if (!len_stor)
348                         return API_EINVAL;
349                 if (*len_stor <= 0)
350                         return API_EINVAL;
351
352                 /* 4. arg - ptr to var with start block */
353                 start = (lbastart_t *)va_arg(ap, uintptr_t);
354
355                 act_len_stor = dev_write_stor(di->cookie, buf, *len_stor, *start);
356                 if (act_len_stor != *len_stor) {
357                         debugf("write @ %llu: done %llu out of %llu blocks",
358                                    (uint64_t)blk, (uint64_t)act_len_stor,
359                                    (uint64_t)len_stor);
360                         return API_EIO;
361                 }
362
363         } else if (di->type & DEV_TYP_NET) {
364                 /* 3. arg points to the var with length of packet to write */
365                 len_net = (int *)va_arg(ap, uintptr_t);
366                 if (!len_net)
367                         return API_EINVAL;
368                 if (*len_net <= 0)
369                         return API_EINVAL;
370
371                 err = dev_write_net(di->cookie, buf, *len_net);
372
373         } else
374                 err = API_ENODEV;
375
376         return err;
377 }
378
379
380 /*
381  * pseudo signature:
382  *
383  * int API_dev_read(
384  *      struct device_info *di,
385  *      void *buf,
386  *      size_t *len,
387  *      unsigned long *start
388  *      size_t *act_len
389  * )
390  *
391  * buf: ptr to buffer where to put the read data
392  *
393  * len: ptr to length to be read
394  *      - network: len of packet to read (in bytes)
395  *      - storage: # of blocks to read (can vary in size depending on define)
396  *
397  * start: ptr to start block (only used for storage devices, ignored for
398  *        network)
399  *
400  * act_len: ptr to where to put the len actually read
401  */
402 static int API_dev_read(va_list ap)
403 {
404         struct device_info *di;
405         void *buf;
406         lbasize_t *len_stor, *act_len_stor;
407         lbastart_t *start;
408         int *len_net, *act_len_net;
409
410         /* 1. arg is ptr to the device_info struct */
411         di = (struct device_info *)va_arg(ap, uintptr_t);
412         if (di == NULL)
413                 return API_EINVAL;
414
415         /* XXX should we check if device is open? i.e. the ->state ? */
416
417         if (di->cookie == NULL)
418                 return API_ENODEV;
419
420         /* 2. arg is ptr to buffer from where to put the read data */
421         buf = (void *)va_arg(ap, uintptr_t);
422         if (buf == NULL)
423                 return API_EINVAL;
424
425         if (di->type & DEV_TYP_STOR) {
426                 /* 3. arg - ptr to var with # of blocks to read */
427                 len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
428                 if (!len_stor)
429                         return API_EINVAL;
430                 if (*len_stor <= 0)
431                         return API_EINVAL;
432
433                 /* 4. arg - ptr to var with start block */
434                 start = (lbastart_t *)va_arg(ap, uintptr_t);
435
436                 /* 5. arg - ptr to var where to put the len actually read */
437                 act_len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
438                 if (!act_len_stor)
439                         return API_EINVAL;
440
441                 *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start);
442
443         } else if (di->type & DEV_TYP_NET) {
444
445                 /* 3. arg points to the var with length of packet to read */
446                 len_net = (int *)va_arg(ap, uintptr_t);
447                 if (!len_net)
448                         return API_EINVAL;
449                 if (*len_net <= 0)
450                         return API_EINVAL;
451
452                 /* 4. - ptr to var where to put the len actually read */
453                 act_len_net = (int *)va_arg(ap, uintptr_t);
454                 if (!act_len_net)
455                         return API_EINVAL;
456
457                 *act_len_net = dev_read_net(di->cookie, buf, *len_net);
458
459         } else
460                 return API_ENODEV;
461
462         return 0;
463 }
464
465
466 /*
467  * pseudo signature:
468  *
469  * int API_env_get(const char *name, char **value)
470  *
471  * name: ptr to name of env var
472  */
473 static int API_env_get(va_list ap)
474 {
475         char *name, **value;
476
477         if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
478                 return API_EINVAL;
479         if ((value = (char **)va_arg(ap, uintptr_t)) == NULL)
480                 return API_EINVAL;
481
482         *value = env_get(name);
483
484         return 0;
485 }
486
487 /*
488  * pseudo signature:
489  *
490  * int API_env_set(const char *name, const char *value)
491  *
492  * name: ptr to name of env var
493  *
494  * value: ptr to value to be set
495  */
496 static int API_env_set(va_list ap)
497 {
498         char *name, *value;
499
500         if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
501                 return API_EINVAL;
502         if ((value = (char *)va_arg(ap, uintptr_t)) == NULL)
503                 return API_EINVAL;
504
505         env_set(name, value);
506
507         return 0;
508 }
509
510 /*
511  * pseudo signature:
512  *
513  * int API_env_enum(const char *last, char **next)
514  *
515  * last: ptr to name of env var found in last iteration
516  */
517 static int API_env_enum(va_list ap)
518 {
519         int i, buflen;
520         char *last, **next, *s;
521         struct env_entry *match, search;
522         static char *var;
523
524         last = (char *)va_arg(ap, unsigned long);
525
526         if ((next = (char **)va_arg(ap, uintptr_t)) == NULL)
527                 return API_EINVAL;
528
529         if (last == NULL) {
530                 var = NULL;
531                 i = 0;
532         } else {
533                 var = strdup(last);
534                 s = strchr(var, '=');
535                 if (s != NULL)
536                         *s = 0;
537                 search.key = var;
538                 i = hsearch_r(search, ENV_FIND, &match, &env_htab, 0);
539                 if (i == 0) {
540                         i = API_EINVAL;
541                         goto done;
542                 }
543         }
544
545         /* match the next entry after i */
546         i = hmatch_r("", i, &match, &env_htab);
547         if (i == 0)
548                 goto done;
549         buflen = strlen(match->key) + strlen(match->data) + 2;
550         var = realloc(var, buflen);
551         snprintf(var, buflen, "%s=%s", match->key, match->data);
552         *next = var;
553         return 0;
554
555 done:
556         free(var);
557         var = NULL;
558         *next = NULL;
559         return i;
560 }
561
562 /*
563  * pseudo signature:
564  *
565  * int API_display_get_info(int type, struct display_info *di)
566  */
567 static int API_display_get_info(va_list ap)
568 {
569         int type;
570         struct display_info *di;
571
572         type = va_arg(ap, int);
573         di = va_arg(ap, struct display_info *);
574
575         return display_get_info(type, di);
576 }
577
578 /*
579  * pseudo signature:
580  *
581  * int API_display_draw_bitmap(ulong bitmap, int x, int y)
582  */
583 static int API_display_draw_bitmap(va_list ap)
584 {
585         ulong bitmap;
586         int x, y;
587
588         bitmap = va_arg(ap, ulong);
589         x = va_arg(ap, int);
590         y = va_arg(ap, int);
591
592         return display_draw_bitmap(bitmap, x, y);
593 }
594
595 /*
596  * pseudo signature:
597  *
598  * void API_display_clear(void)
599  */
600 static int API_display_clear(va_list ap)
601 {
602         display_clear();
603         return 0;
604 }
605
606 static cfp_t calls_table[API_MAXCALL] = { NULL, };
607
608 /*
609  * The main syscall entry point - this is not reentrant, only one call is
610  * serviced until finished.
611  *
612  * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
613  *
614  * call:        syscall number
615  *
616  * retval:      points to the return value placeholder, this is the place the
617  *              syscall puts its return value, if NULL the caller does not
618  *              expect a return value
619  *
620  * ...          syscall arguments (variable number)
621  *
622  * returns:     0 if the call not found, 1 if serviced
623  */
624 int syscall(int call, int *retval, ...)
625 {
626         va_list ap;
627         int rv;
628
629         if (call < 0 || call >= calls_no) {
630                 debugf("invalid call #%d\n", call);
631                 return 0;
632         }
633
634         if (calls_table[call] == NULL) {
635                 debugf("syscall #%d does not have a handler\n", call);
636                 return 0;
637         }
638
639         va_start(ap, retval);
640         rv = calls_table[call](ap);
641         if (retval != NULL)
642                 *retval = rv;
643
644         return 1;
645 }
646
647 int api_init(void)
648 {
649         struct api_signature *sig;
650
651         /* TODO put this into linker set one day... */
652         calls_table[API_RSVD] = NULL;
653         calls_table[API_GETC] = &API_getc;
654         calls_table[API_PUTC] = &API_putc;
655         calls_table[API_TSTC] = &API_tstc;
656         calls_table[API_PUTS] = &API_puts;
657         calls_table[API_RESET] = &API_reset;
658         calls_table[API_GET_SYS_INFO] = &API_get_sys_info;
659         calls_table[API_UDELAY] = &API_udelay;
660         calls_table[API_GET_TIMER] = &API_get_timer;
661         calls_table[API_DEV_ENUM] = &API_dev_enum;
662         calls_table[API_DEV_OPEN] = &API_dev_open;
663         calls_table[API_DEV_CLOSE] = &API_dev_close;
664         calls_table[API_DEV_READ] = &API_dev_read;
665         calls_table[API_DEV_WRITE] = &API_dev_write;
666         calls_table[API_ENV_GET] = &API_env_get;
667         calls_table[API_ENV_SET] = &API_env_set;
668         calls_table[API_ENV_ENUM] = &API_env_enum;
669         calls_table[API_DISPLAY_GET_INFO] = &API_display_get_info;
670         calls_table[API_DISPLAY_DRAW_BITMAP] = &API_display_draw_bitmap;
671         calls_table[API_DISPLAY_CLEAR] = &API_display_clear;
672         calls_no = API_MAXCALL;
673
674         debugf("API initialized with %d calls\n", calls_no);
675
676         dev_stor_init();
677
678         /*
679          * Produce the signature so the API consumers can find it
680          */
681         sig = malloc(sizeof(struct api_signature));
682         if (sig == NULL) {
683                 printf("API: could not allocate memory for the signature!\n");
684                 return -ENOMEM;
685         }
686
687         env_set_hex("api_address", (unsigned long)sig);
688         debugf("API sig @ 0x%lX\n", (unsigned long)sig);
689         memcpy(sig->magic, API_SIG_MAGIC, 8);
690         sig->version = API_SIG_VERSION;
691         sig->syscall = &syscall;
692         sig->checksum = 0;
693         sig->checksum = crc32(0, (unsigned char *)sig,
694                               sizeof(struct api_signature));
695         debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall);
696
697         return 0;
698 }
699
700 void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
701                         int flags)
702 {
703         int i;
704
705         if (!si->mr || !size || (flags == 0))
706                 return;
707
708         /* find free slot */
709         for (i = 0; i < si->mr_no; i++)
710                 if (si->mr[i].flags == 0) {
711                         /* insert new mem region */
712                         si->mr[i].start = start;
713                         si->mr[i].size = size;
714                         si->mr[i].flags = flags;
715                         return;
716                 }
717 }
This page took 0.065146 seconds and 4 git commands to generate.