]>
git.ipfire.org Git - thirdparty/u-boot.git/blob - api/api.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2007 Semihalf
5 * Written by: Rafal Jaworowski <raj@semihalf.com>
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>
19 #include "api_private.h"
24 /*****************************************************************************
26 * This is the API core.
28 * API_ functions are part of U-Boot code and constitute the lowest level
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
36 ****************************************************************************/
39 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
41 #define debugf(fmt, args...)
44 typedef int (*cfp_t
)(va_list argp
);
51 * int API_getc(int *c)
53 static int API_getc(va_list ap
)
57 if ((c
= (int *)va_arg(ap
, uintptr_t)) == NULL
)
67 * int API_tstc(int *c)
69 static int API_tstc(va_list ap
)
73 if ((t
= (int *)va_arg(ap
, uintptr_t)) == NULL
)
83 * int API_putc(char *ch)
85 static int API_putc(va_list ap
)
89 if ((c
= (char *)va_arg(ap
, uintptr_t)) == NULL
)
99 * int API_puts(char **s)
101 static int API_puts(va_list ap
)
105 if ((s
= (char *)va_arg(ap
, uintptr_t)) == NULL
)
115 * int API_reset(void)
117 static int API_reset(va_list ap
)
119 do_reset(NULL
, 0, 0, NULL
);
128 * int API_get_sys_info(struct sys_info *si)
130 * fill out the sys_info struct containing selected parameters about the
133 static int API_get_sys_info(va_list ap
)
137 si
= (struct sys_info
*)va_arg(ap
, uintptr_t);
141 return (platform_sys_info(si
)) ? 0 : API_ENODEV
;
147 * int API_udelay(unsigned long *udelay)
149 static int API_udelay(va_list ap
)
153 if ((d
= (unsigned long *)va_arg(ap
, unsigned long)) == NULL
)
163 * int API_get_timer(unsigned long *current, unsigned long *base)
165 static int API_get_timer(va_list ap
)
167 unsigned long *base
, *cur
;
169 cur
= (unsigned long *)va_arg(ap
, unsigned long);
173 base
= (unsigned long *)va_arg(ap
, unsigned long);
177 *cur
= get_timer(*base
);
182 /*****************************************************************************
186 * int API_dev_enum(struct device_info *)
189 * cookies uniqely identify the previously enumerated device instance and
190 * provide a hint for what to inspect in current enum iteration:
192 * - net: ð_device struct address from list pointed to by eth_devices
194 * - storage: struct blk_desc struct address from &ide_dev_desc[n],
195 * &scsi_dev_desc[n] and similar tables
197 ****************************************************************************/
199 static int API_dev_enum(va_list ap
)
201 struct device_info
*di
;
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);
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");
213 /* net device enumeration first */
214 if (dev_enum_net(di
))
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
224 if (!dev_enum_storage(di
))
225 /* make sure we mark there are no more devices */
232 static int API_dev_open(va_list ap
)
234 struct device_info
*di
;
237 /* arg is ptr to the device_info struct */
238 di
= (struct device_info
*)va_arg(ap
, uintptr_t);
242 /* Allow only one consumer of the device at a time */
243 if (di
->state
== DEV_STA_OPEN
)
246 if (di
->cookie
== NULL
)
249 if (di
->type
& DEV_TYP_STOR
)
250 err
= dev_open_stor(di
->cookie
);
252 else if (di
->type
& DEV_TYP_NET
)
253 err
= dev_open_net(di
->cookie
);
258 di
->state
= DEV_STA_OPEN
;
264 static int API_dev_close(va_list ap
)
266 struct device_info
*di
;
269 /* arg is ptr to the device_info struct */
270 di
= (struct device_info
*)va_arg(ap
, uintptr_t);
274 if (di
->state
== DEV_STA_CLOSED
)
277 if (di
->cookie
== NULL
)
280 if (di
->type
& DEV_TYP_STOR
)
281 err
= dev_close_stor(di
->cookie
);
283 else if (di
->type
& DEV_TYP_NET
)
284 err
= dev_close_net(di
->cookie
);
287 * In case of unknown device we cannot change its state, so
288 * only return error code
293 di
->state
= DEV_STA_CLOSED
;
303 * struct device_info *di,
306 * unsigned long *start
309 * buf: ptr to buffer from where to get the data to send
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)
315 * start: ptr to start block (only used for storage devices, ignored for
318 static int API_dev_write(va_list ap
)
320 struct device_info
*di
;
322 lbasize_t
*len_stor
, act_len_stor
;
327 /* 1. arg is ptr to the device_info struct */
328 di
= (struct device_info
*)va_arg(ap
, uintptr_t);
332 /* XXX should we check if device is open? i.e. the ->state ? */
334 if (di
->cookie
== NULL
)
337 /* 2. arg is ptr to buffer from where to get data to write */
338 buf
= (void *)va_arg(ap
, uintptr_t);
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);
350 /* 4. arg - ptr to var with start block */
351 start
= (lbastart_t
*)va_arg(ap
, uintptr_t);
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
,
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);
369 err
= dev_write_net(di
->cookie
, buf
, *len_net
);
382 * struct device_info *di,
385 * unsigned long *start
389 * buf: ptr to buffer where to put the read data
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)
395 * start: ptr to start block (only used for storage devices, ignored for
398 * act_len: ptr to where to put the len actually read
400 static int API_dev_read(va_list ap
)
402 struct device_info
*di
;
404 lbasize_t
*len_stor
, *act_len_stor
;
406 int *len_net
, *act_len_net
;
408 /* 1. arg is ptr to the device_info struct */
409 di
= (struct device_info
*)va_arg(ap
, uintptr_t);
413 /* XXX should we check if device is open? i.e. the ->state ? */
415 if (di
->cookie
== NULL
)
418 /* 2. arg is ptr to buffer from where to put the read data */
419 buf
= (void *)va_arg(ap
, uintptr_t);
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);
431 /* 4. arg - ptr to var with start block */
432 start
= (lbastart_t
*)va_arg(ap
, uintptr_t);
434 /* 5. arg - ptr to var where to put the len actually read */
435 act_len_stor
= (lbasize_t
*)va_arg(ap
, uintptr_t);
439 *act_len_stor
= dev_read_stor(di
->cookie
, buf
, *len_stor
, *start
);
441 } else if (di
->type
& DEV_TYP_NET
) {
443 /* 3. arg points to the var with length of packet to read */
444 len_net
= (int *)va_arg(ap
, uintptr_t);
450 /* 4. - ptr to var where to put the len actually read */
451 act_len_net
= (int *)va_arg(ap
, uintptr_t);
455 *act_len_net
= dev_read_net(di
->cookie
, buf
, *len_net
);
467 * int API_env_get(const char *name, char **value)
469 * name: ptr to name of env var
471 static int API_env_get(va_list ap
)
475 if ((name
= (char *)va_arg(ap
, uintptr_t)) == NULL
)
477 if ((value
= (char **)va_arg(ap
, uintptr_t)) == NULL
)
480 *value
= env_get(name
);
488 * int API_env_set(const char *name, const char *value)
490 * name: ptr to name of env var
492 * value: ptr to value to be set
494 static int API_env_set(va_list ap
)
498 if ((name
= (char *)va_arg(ap
, uintptr_t)) == NULL
)
500 if ((value
= (char *)va_arg(ap
, uintptr_t)) == NULL
)
503 env_set(name
, value
);
511 * int API_env_enum(const char *last, char **next)
513 * last: ptr to name of env var found in last iteration
515 static int API_env_enum(va_list ap
)
518 char *last
, **next
, *s
;
519 struct env_entry
*match
, search
;
522 last
= (char *)va_arg(ap
, unsigned long);
524 if ((next
= (char **)va_arg(ap
, uintptr_t)) == NULL
)
532 s
= strchr(var
, '=');
536 i
= hsearch_r(search
, ENV_FIND
, &match
, &env_htab
, 0);
543 /* match the next entry after i */
544 i
= hmatch_r("", i
, &match
, &env_htab
);
547 buflen
= strlen(match
->key
) + strlen(match
->data
) + 2;
548 var
= realloc(var
, buflen
);
549 snprintf(var
, buflen
, "%s=%s", match
->key
, match
->data
);
563 * int API_display_get_info(int type, struct display_info *di)
565 static int API_display_get_info(va_list ap
)
568 struct display_info
*di
;
570 type
= va_arg(ap
, int);
571 di
= va_arg(ap
, struct display_info
*);
573 return display_get_info(type
, di
);
579 * int API_display_draw_bitmap(ulong bitmap, int x, int y)
581 static int API_display_draw_bitmap(va_list ap
)
586 bitmap
= va_arg(ap
, ulong
);
590 return display_draw_bitmap(bitmap
, x
, y
);
596 * void API_display_clear(void)
598 static int API_display_clear(va_list ap
)
604 static cfp_t calls_table
[API_MAXCALL
] = { NULL
, };
607 * The main syscall entry point - this is not reentrant, only one call is
608 * serviced until finished.
610 * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
612 * call: syscall number
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
618 * ... syscall arguments (variable number)
620 * returns: 0 if the call not found, 1 if serviced
622 int syscall(int call
, int *retval
, ...)
627 if (call
< 0 || call
>= calls_no
) {
628 debugf("invalid call #%d\n", call
);
632 if (calls_table
[call
] == NULL
) {
633 debugf("syscall #%d does not have a handler\n", call
);
637 va_start(ap
, retval
);
638 rv
= calls_table
[call
](ap
);
647 struct api_signature
*sig
;
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
;
672 debugf("API initialized with %d calls\n", calls_no
);
677 * Produce the signature so the API consumers can find it
679 sig
= malloc(sizeof(struct api_signature
));
681 printf("API: could not allocate memory for the signature!\n");
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
;
691 sig
->checksum
= crc32(0, (unsigned char *)sig
,
692 sizeof(struct api_signature
));
693 debugf("syscall entry: 0x%lX\n", (unsigned long)sig
->syscall
);
698 void platform_set_mr(struct sys_info
*si
, unsigned long start
, unsigned long size
,
703 if (!si
->mr
|| !size
|| (flags
== 0))
707 for (i
= 0; i
< si
->mr_no
; i
++)
708 if (si
->mr
[i
].flags
== 0) {
709 /* insert new mem region */
710 si
->mr
[i
].start
= start
;
711 si
->mr
[i
].size
= size
;
712 si
->mr
[i
].flags
= flags
;