Merge branch 'master' of https://gitlab.denx.de/u-boot/custodians/u-boot-samsung
[platform/kernel/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/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
44 typedef int (*cfp_t)(va_list argp);
45
46 static int calls_no;
47
48 /*
49  * pseudo signature:
50  *
51  * int API_getc(int *c)
52  */
53 static 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  */
69 static 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  */
85 static 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  */
101 static 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  */
117 static 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  */
133 static 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  */
149 static 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  */
165 static 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
199 static 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
232 static 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
264 static 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  */
318 static 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  */
400 static 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  */
471 static 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  */
494 static 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  */
515 static 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
553 done:
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  */
565 static 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  */
581 static 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  */
598 static int API_display_clear(va_list ap)
599 {
600         display_clear();
601         return 0;
602 }
603
604 static 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  */
622 int 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
645 void 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;
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
696 void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
697                         int flags)
698 {
699         int i;
700
701         if (!si->mr || !size || (flags == 0))
702                 return;
703
704         /* find free slot */
705         for (i = 0; i < si->mr_no; i++)
706                 if (si->mr[i].flags == 0) {
707                         /* insert new mem region */
708                         si->mr[i].start = start;
709                         si->mr[i].size = size;
710                         si->mr[i].flags = flags;
711                         return;
712                 }
713 }