Merge tag 'u-boot-imx-20191105' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[oweals/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 <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/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  * 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  */
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 /*
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, uintptr_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, uintptr_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, uintptr_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, uintptr_t);
431
432                 /* 5. arg - ptr to var where to put the len actually read */
433                 act_len_stor = (lbasize_t *)va_arg(ap, uintptr_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, uintptr_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, uintptr_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, uintptr_t)) == NULL)
474                 return API_EINVAL;
475         if ((value = (char **)va_arg(ap, uintptr_t)) == NULL)
476                 return API_EINVAL;
477
478         *value = env_get(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, uintptr_t)) == NULL)
497                 return API_EINVAL;
498         if ((value = (char *)va_arg(ap, uintptr_t)) == NULL)
499                 return API_EINVAL;
500
501         env_set(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, buflen;
516         char *last, **next, *s;
517         struct env_entry *match, search;
518         static char *var;
519
520         last = (char *)va_arg(ap, unsigned long);
521
522         if ((next = (char **)va_arg(ap, uintptr_t)) == NULL)
523                 return API_EINVAL;
524
525         if (last == NULL) {
526                 var = NULL;
527                 i = 0;
528         } else {
529                 var = strdup(last);
530                 s = strchr(var, '=');
531                 if (s != NULL)
532                         *s = 0;
533                 search.key = var;
534                 i = hsearch_r(search, ENV_FIND, &match, &env_htab, 0);
535                 if (i == 0) {
536                         i = API_EINVAL;
537                         goto done;
538                 }
539         }
540
541         /* match the next entry after i */
542         i = hmatch_r("", i, &match, &env_htab);
543         if (i == 0)
544                 goto done;
545         buflen = strlen(match->key) + strlen(match->data) + 2;
546         var = realloc(var, buflen);
547         snprintf(var, buflen, "%s=%s", match->key, match->data);
548         *next = var;
549         return 0;
550
551 done:
552         free(var);
553         var = NULL;
554         *next = NULL;
555         return i;
556 }
557
558 /*
559  * pseudo signature:
560  *
561  * int API_display_get_info(int type, struct display_info *di)
562  */
563 static int API_display_get_info(va_list ap)
564 {
565         int type;
566         struct display_info *di;
567
568         type = va_arg(ap, int);
569         di = va_arg(ap, struct display_info *);
570
571         return display_get_info(type, di);
572 }
573
574 /*
575  * pseudo signature:
576  *
577  * int API_display_draw_bitmap(ulong bitmap, int x, int y)
578  */
579 static int API_display_draw_bitmap(va_list ap)
580 {
581         ulong bitmap;
582         int x, y;
583
584         bitmap = va_arg(ap, ulong);
585         x = va_arg(ap, int);
586         y = va_arg(ap, int);
587
588         return display_draw_bitmap(bitmap, x, y);
589 }
590
591 /*
592  * pseudo signature:
593  *
594  * void API_display_clear(void)
595  */
596 static int API_display_clear(va_list ap)
597 {
598         display_clear();
599         return 0;
600 }
601
602 static cfp_t calls_table[API_MAXCALL] = { NULL, };
603
604 /*
605  * The main syscall entry point - this is not reentrant, only one call is
606  * serviced until finished.
607  *
608  * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
609  *
610  * call:        syscall number
611  *
612  * retval:      points to the return value placeholder, this is the place the
613  *              syscall puts its return value, if NULL the caller does not
614  *              expect a return value
615  *
616  * ...          syscall arguments (variable number)
617  *
618  * returns:     0 if the call not found, 1 if serviced
619  */
620 int syscall(int call, int *retval, ...)
621 {
622         va_list ap;
623         int rv;
624
625         if (call < 0 || call >= calls_no) {
626                 debugf("invalid call #%d\n", call);
627                 return 0;
628         }
629
630         if (calls_table[call] == NULL) {
631                 debugf("syscall #%d does not have a handler\n", call);
632                 return 0;
633         }
634
635         va_start(ap, retval);
636         rv = calls_table[call](ap);
637         if (retval != NULL)
638                 *retval = rv;
639
640         return 1;
641 }
642
643 void api_init(void)
644 {
645         struct api_signature *sig;
646
647         /* TODO put this into linker set one day... */
648         calls_table[API_RSVD] = NULL;
649         calls_table[API_GETC] = &API_getc;
650         calls_table[API_PUTC] = &API_putc;
651         calls_table[API_TSTC] = &API_tstc;
652         calls_table[API_PUTS] = &API_puts;
653         calls_table[API_RESET] = &API_reset;
654         calls_table[API_GET_SYS_INFO] = &API_get_sys_info;
655         calls_table[API_UDELAY] = &API_udelay;
656         calls_table[API_GET_TIMER] = &API_get_timer;
657         calls_table[API_DEV_ENUM] = &API_dev_enum;
658         calls_table[API_DEV_OPEN] = &API_dev_open;
659         calls_table[API_DEV_CLOSE] = &API_dev_close;
660         calls_table[API_DEV_READ] = &API_dev_read;
661         calls_table[API_DEV_WRITE] = &API_dev_write;
662         calls_table[API_ENV_GET] = &API_env_get;
663         calls_table[API_ENV_SET] = &API_env_set;
664         calls_table[API_ENV_ENUM] = &API_env_enum;
665         calls_table[API_DISPLAY_GET_INFO] = &API_display_get_info;
666         calls_table[API_DISPLAY_DRAW_BITMAP] = &API_display_draw_bitmap;
667         calls_table[API_DISPLAY_CLEAR] = &API_display_clear;
668         calls_no = API_MAXCALL;
669
670         debugf("API initialized with %d calls\n", calls_no);
671
672         dev_stor_init();
673
674         /*
675          * Produce the signature so the API consumers can find it
676          */
677         sig = malloc(sizeof(struct api_signature));
678         if (sig == NULL) {
679                 printf("API: could not allocate memory for the signature!\n");
680                 return;
681         }
682
683         env_set_hex("api_address", (unsigned long)sig);
684         debugf("API sig @ 0x%lX\n", (unsigned long)sig);
685         memcpy(sig->magic, API_SIG_MAGIC, 8);
686         sig->version = API_SIG_VERSION;
687         sig->syscall = &syscall;
688         sig->checksum = 0;
689         sig->checksum = crc32(0, (unsigned char *)sig,
690                               sizeof(struct api_signature));
691         debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall);
692 }
693
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 }