"post/board/$(BOARDDIR)/libpost$(BOARD).a"; fi)
LIBS += common/libcommon.a
LIBS += libfdt/libfdt.a
+ifeq ($(CONFIG_API),y)
+LIBS += api/libapi.a
+endif
LIBS := $(addprefix $(obj),$(LIBS))
.PHONY : $(LIBS)
SUBDIRS = tools \
examples
+ifeq ($(CONFIG_API),y)
+SUBDIRS += api_examples
+endif
+
.PHONY : $(SUBDIRS)
ifeq ($(CONFIG_NAND_U_BOOT),y)
rm -f $(obj)board/bf537-stamp/u-boot.lds $(obj)board/bf561-ezkit/u-boot.lds
rm -f $(obj)include/bmp_logo.h
rm -f $(obj)nand_spl/u-boot-spl $(obj)nand_spl/u-boot-spl.map
+ rm -f $(obj)api_examples/demo
clobber: clean
find $(OBJTREE) -type f \( -name .depend \
rm -f $(obj)tools/inca-swap-bytes $(obj)cpu/mpc824x/bedbug_603e.c
rm -f $(obj)include/asm/proc $(obj)include/asm/arch $(obj)include/asm
[ ! -d $(OBJTREE)/nand_spl ] || find $(obj)nand_spl -lname "*" -print | xargs rm -f
+ find $(obj)api_examples -lname "*" -print | xargs rm -f
+ rm -f $(obj)api_examples/demo
ifeq ($(OBJTREE),$(SRCTREE))
mrproper \
--- /dev/null
+#
+# (C) Copyright 2007 Semihalf
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundatio; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)libapi.a
+
+COBJS = api.o api_net.o api_storage.o api_platform-$(ARCH).o
+
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
--- /dev/null
+U-Boot machine/arch independent API for external apps
+=====================================================
+
+1. Main assumptions
+
+ - there is a single entry point (syscall) to the API
+
+ - per current design the syscall is a C-callable function in the U-Boot
+ text, which might evolve into a real syscall using machine exception trap
+ once this initial version proves functional
+
+ - the consumer app is responsible for producing appropriate context (call
+ number and arguments)
+
+ - upon entry, the syscall dispatches the call to other (existing) U-Boot
+ functional areas like networking or storage operations
+
+ - consumer application will recognize the API is available by searching
+ a specified (assumed by convention) range of address space for the
+ signature
+
+ - the U-Boot integral part of the API is meant to be thin and non-intrusive,
+ leaving as much processing as possible on the consumer application side,
+ for example it doesn't keep states, but relies on hints from the app and
+ so on
+
+ - optional (CONFIG_API)
+
+
+2. Calls
+
+ - console related (getc, putc, tstc etc.)
+ - system (reset, platform info)
+ - time (delay, current)
+ - env vars (enumerate all, get, set)
+ - devices (enumerate all, open, close, read, write); currently two classes
+ of devices are recognized and supported: network and storage (ide, scsi,
+ usb etc.)
+
+
+3. Structure overview
+
+ - core API, integral part of U-Boot, mandatory
+ - implements the single entry point (mimics UNIX syscall)
+
+ - glue
+ - entry point at the consumer side, allows to make syscall, mandatory
+ part
+
+ - helper conveniency wrappers so that consumer app does not have to use
+ the syscall directly, but in a more friendly manner (a la libc calls),
+ optional part
+
+ - consumer application
+ - calls directly, or leverages the provided glue mid-layer
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_API)
+
+#include <command.h>
+#include <common.h>
+#include <malloc.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+#include "api_private.h"
+
+#define DEBUG
+#undef DEBUG
+
+/* U-Boot routines needed */
+extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+extern uchar (*env_get_char)(int);
+extern uchar *env_get_addr(int);
+
+/*****************************************************************************
+ *
+ * This is the API core.
+ *
+ * API_ functions are part of U-Boot code and constitute the lowest level
+ * calls:
+ *
+ * - they know what values they need as arguments
+ * - their direct return value pertains to the API_ "shell" itself (0 on
+ * success, some error code otherwise)
+ * - if the call returns a value it is buried within arguments
+ *
+ ****************************************************************************/
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+typedef int (*cfp_t)(va_list argp);
+
+static int calls_no;
+
+/*
+ * pseudo signature:
+ *
+ * int API_getc(int *c)
+ */
+static int API_getc(va_list ap)
+{
+ int *c;
+
+ if ((c = (int *)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+
+ *c = getc();
+ return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_tstc(int *c)
+ */
+static int API_tstc(va_list ap)
+{
+ int *t;
+
+ if ((t = (int *)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+
+ *t = tstc();
+ return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_putc(char *ch)
+ */
+static int API_putc(va_list ap)
+{
+ char *c;
+
+ if ((c = (char *)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+
+ putc(*c);
+ return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_puts(char **s)
+ */
+static int API_puts(va_list ap)
+{
+ char *s;
+
+ if ((s = (char *)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+
+ puts(s);
+ return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_reset(void)
+ */
+static int API_reset(va_list ap)
+{
+ do_reset(NULL, 0, 0, NULL);
+
+ /* NOT REACHED */
+ return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_get_sys_info(struct sys_info *si)
+ *
+ * fill out the sys_info struct containing selected parameters about the
+ * machine
+ */
+static int API_get_sys_info(va_list ap)
+{
+ struct sys_info *si;
+
+ si = (struct sys_info *)va_arg(ap, u_int32_t);
+ if (si == NULL)
+ return API_ENOMEM;
+
+ return (platform_sys_info(si)) ? 0 : API_ENODEV;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_udelay(unsigned long *udelay)
+ */
+static int API_udelay(va_list ap)
+{
+ unsigned long *d;
+
+ if ((d = (unsigned long *)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+
+ udelay(*d);
+ return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_get_timer(unsigned long *current, unsigned long *base)
+ */
+static int API_get_timer(va_list ap)
+{
+ unsigned long *base, *cur;
+
+ cur = (unsigned long *)va_arg(ap, u_int32_t);
+ if (cur == NULL)
+ return API_EINVAL;
+
+ base = (unsigned long *)va_arg(ap, u_int32_t);
+ if (base == NULL)
+ return API_EINVAL;
+
+ *cur = get_timer(*base);
+ return 0;
+}
+
+
+/*****************************************************************************
+ *
+ * pseudo signature:
+ *
+ * int API_dev_enum(struct device_info *)
+ *
+ *
+ * cookies uniqely identify the previously enumerated device instance and
+ * provide a hint for what to inspect in current enum iteration:
+ *
+ * - net: ð_device struct address from list pointed to by eth_devices
+ *
+ * - storage: block_dev_desc_t struct address from &ide_dev_desc[n],
+ * &scsi_dev_desc[n] and similar tables
+ *
+ ****************************************************************************/
+
+static int API_dev_enum(va_list ap)
+{
+ struct device_info *di;
+
+ /* arg is ptr to the device_info struct we are going to fill out */
+ di = (struct device_info *)va_arg(ap, u_int32_t);
+ if (di == NULL)
+ return API_EINVAL;
+
+ if (di->cookie == NULL) {
+ /* start over - clean up enumeration */
+ dev_enum_reset(); /* XXX shouldn't the name contain 'stor'? */
+ debugf("RESTART ENUM\n");
+
+ /* net device enumeration first */
+ if (dev_enum_net(di))
+ return 0;
+ }
+
+ /*
+ * The hidden assumption is there can only be one active network
+ * device and it is identified upon enumeration (re)start, so there's
+ * no point in trying to find network devices in other cases than the
+ * (re)start and hence the 'next' device can only be storage
+ */
+ if (!dev_enum_storage(di))
+ /* make sure we mark there are no more devices */
+ di->cookie = NULL;
+
+ return 0;
+}
+
+
+static int API_dev_open(va_list ap)
+{
+ struct device_info *di;
+ int err = 0;
+
+ /* arg is ptr to the device_info struct */
+ di = (struct device_info *)va_arg(ap, u_int32_t);
+ if (di == NULL)
+ return API_EINVAL;
+
+ /* Allow only one consumer of the device at a time */
+ if (di->state == DEV_STA_OPEN)
+ return API_EBUSY;
+
+ if (di->cookie == NULL)
+ return API_ENODEV;
+
+ if (di->type & DEV_TYP_STOR)
+ err = dev_open_stor(di->cookie);
+
+ else if (di->type & DEV_TYP_NET)
+ err = dev_open_net(di->cookie);
+ else
+ err = API_ENODEV;
+
+ if (!err)
+ di->state = DEV_STA_OPEN;
+
+ return err;
+}
+
+
+static int API_dev_close(va_list ap)
+{
+ struct device_info *di;
+ int err = 0;
+
+ /* arg is ptr to the device_info struct */
+ di = (struct device_info *)va_arg(ap, u_int32_t);
+ if (di == NULL)
+ return API_EINVAL;
+
+ if (di->state == DEV_STA_CLOSED)
+ return 0;
+
+ if (di->cookie == NULL)
+ return API_ENODEV;
+
+ if (di->type & DEV_TYP_STOR)
+ err = dev_close_stor(di->cookie);
+
+ else if (di->type & DEV_TYP_NET)
+ err = dev_close_net(di->cookie);
+ else
+ /*
+ * In case of unknown device we cannot change its state, so
+ * only return error code
+ */
+ err = API_ENODEV;
+
+ if (!err)
+ di->state = DEV_STA_CLOSED;
+
+ return err;
+}
+
+
+/*
+ * Notice: this is for sending network packets only, as U-Boot does not
+ * support writing to storage at the moment (12.2007)
+ *
+ * pseudo signature:
+ *
+ * int API_dev_write(
+ * struct device_info *di,
+ * void *buf,
+ * int *len
+ * )
+ *
+ * buf: ptr to buffer from where to get the data to send
+ *
+ * len: length of packet to be sent (in bytes)
+ *
+ */
+static int API_dev_write(va_list ap)
+{
+ struct device_info *di;
+ void *buf;
+ int *len;
+ int err = 0;
+
+ /* 1. arg is ptr to the device_info struct */
+ di = (struct device_info *)va_arg(ap, u_int32_t);
+ if (di == NULL)
+ return API_EINVAL;
+
+ /* XXX should we check if device is open? i.e. the ->state ? */
+
+ if (di->cookie == NULL)
+ return API_ENODEV;
+
+ /* 2. arg is ptr to buffer from where to get data to write */
+ buf = (void *)va_arg(ap, u_int32_t);
+ if (buf == NULL)
+ return API_EINVAL;
+
+ /* 3. arg is length of buffer */
+ len = (int *)va_arg(ap, u_int32_t);
+ if (len == NULL)
+ return API_EINVAL;
+ if (*len <= 0)
+ return API_EINVAL;
+
+ if (di->type & DEV_TYP_STOR)
+ /*
+ * write to storage is currently not supported by U-Boot:
+ * no storage device implements block_write() method
+ */
+ return API_ENODEV;
+
+ else if (di->type & DEV_TYP_NET)
+ err = dev_write_net(di->cookie, buf, *len);
+ else
+ err = API_ENODEV;
+
+ return err;
+}
+
+
+/*
+ * pseudo signature:
+ *
+ * int API_dev_read(
+ * struct device_info *di,
+ * void *buf,
+ * size_t *len,
+ * unsigned long *start
+ * size_t *act_len
+ * )
+ *
+ * buf: ptr to buffer where to put the read data
+ *
+ * len: ptr to length to be read
+ * - network: len of packet to read (in bytes)
+ * - storage: # of blocks to read (can vary in size depending on define)
+ *
+ * start: ptr to start block (only used for storage devices, ignored for
+ * network)
+ *
+ * act_len: ptr to where to put the len actually read
+ */
+static int API_dev_read(va_list ap)
+{
+ struct device_info *di;
+ void *buf;
+ lbasize_t *len_stor, *act_len_stor;
+ lbastart_t *start;
+ int *len_net, *act_len_net;
+
+ /* 1. arg is ptr to the device_info struct */
+ di = (struct device_info *)va_arg(ap, u_int32_t);
+ if (di == NULL)
+ return API_EINVAL;
+
+ /* XXX should we check if device is open? i.e. the ->state ? */
+
+ if (di->cookie == NULL)
+ return API_ENODEV;
+
+ /* 2. arg is ptr to buffer from where to put the read data */
+ buf = (void *)va_arg(ap, u_int32_t);
+ if (buf == NULL)
+ return API_EINVAL;
+
+ if (di->type & DEV_TYP_STOR) {
+ /* 3. arg - ptr to var with # of blocks to read */
+ len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
+ if (!len_stor)
+ return API_EINVAL;
+ if (*len_stor <= 0)
+ return API_EINVAL;
+
+ /* 4. arg - ptr to var with start block */
+ start = (lbastart_t *)va_arg(ap, u_int32_t);
+
+ /* 5. arg - ptr to var where to put the len actually read */
+ act_len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
+ if (!act_len_stor)
+ return API_EINVAL;
+
+ *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start);
+
+ } else if (di->type & DEV_TYP_NET) {
+
+ /* 3. arg points to the var with length of packet to read */
+ len_net = (int *)va_arg(ap, u_int32_t);
+ if (!len_net)
+ return API_EINVAL;
+ if (*len_net <= 0)
+ return API_EINVAL;
+
+ /* 4. - ptr to var where to put the len actually read */
+ act_len_net = (int *)va_arg(ap, u_int32_t);
+ if (!act_len_net)
+ return API_EINVAL;
+
+ *act_len_net = dev_read_net(di->cookie, buf, *len_net);
+
+ } else
+ return API_ENODEV;
+
+ return 0;
+}
+
+
+/*
+ * pseudo signature:
+ *
+ * int API_env_get(const char *name, char **value)
+ *
+ * name: ptr to name of env var
+ */
+static int API_env_get(va_list ap)
+{
+ char *name, **value;
+
+ if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+ if ((value = (char **)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+
+ *value = getenv(name);
+
+ return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_env_set(const char *name, const char *value)
+ *
+ * name: ptr to name of env var
+ *
+ * value: ptr to value to be set
+ */
+static int API_env_set(va_list ap)
+{
+ char *name, *value;
+
+ if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+ if ((value = (char *)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+
+ setenv(name, value);
+
+ return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_env_enum(const char *last, char **next)
+ *
+ * last: ptr to name of env var found in last iteration
+ */
+static int API_env_enum(va_list ap)
+{
+ int i, n;
+ char *last, **next;
+
+ last = (char *)va_arg(ap, u_int32_t);
+
+ if ((next = (char **)va_arg(ap, u_int32_t)) == NULL)
+ return API_EINVAL;
+
+ if (last == NULL)
+ /* start over */
+ *next = ((char *)env_get_addr(0));
+ else {
+ *next = last;
+
+ for (i = 0; env_get_char(i) != '\0'; i = n + 1) {
+ for (n = i; env_get_char(n) != '\0'; ++n) {
+ if (n >= CFG_ENV_SIZE) {
+ /* XXX shouldn't we set *next = NULL?? */
+ return 0;
+ }
+ }
+
+ if (envmatch((uchar *)last, i) < 0)
+ continue;
+
+ /* try to get next name */
+ i = n + 1;
+ if (env_get_char(i) == '\0') {
+ /* no more left */
+ *next = NULL;
+ return 0;
+ }
+
+ *next = ((char *)env_get_addr(i));
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static cfp_t calls_table[API_MAXCALL] = { NULL, };
+
+/*
+ * The main syscall entry point - this is not reentrant, only one call is
+ * serviced until finished.
+ *
+ * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
+ *
+ * call: syscall number
+ *
+ * retval: points to the return value placeholder, this is the place the
+ * syscall puts its return value, if NULL the caller does not
+ * expect a return value
+ *
+ * ... syscall arguments (variable number)
+ *
+ * returns: 0 if the call not found, 1 if serviced
+ */
+int syscall(int call, int *retval, ...)
+{
+ va_list ap;
+ int rv;
+
+ if (call < 0 || call >= calls_no || calls_table[call] == NULL) {
+ debugf("invalid call #%d\n", call);
+ return 0;
+ }
+
+ if (calls_table[call] == NULL) {
+ debugf("syscall #%d does not have a handler\n", call);
+ return 0;
+ }
+
+ va_start(ap, retval);
+ rv = calls_table[call](ap);
+ if (retval != NULL)
+ *retval = rv;
+
+ return 1;
+}
+
+void api_init(void)
+{
+ struct api_signature *sig = NULL;
+
+ /* TODO put this into linker set one day... */
+ calls_table[API_RSVD] = NULL;
+ calls_table[API_GETC] = &API_getc;
+ calls_table[API_PUTC] = &API_putc;
+ calls_table[API_TSTC] = &API_tstc;
+ calls_table[API_PUTS] = &API_puts;
+ calls_table[API_RESET] = &API_reset;
+ calls_table[API_GET_SYS_INFO] = &API_get_sys_info;
+ calls_table[API_UDELAY] = &API_udelay;
+ calls_table[API_GET_TIMER] = &API_get_timer;
+ calls_table[API_DEV_ENUM] = &API_dev_enum;
+ calls_table[API_DEV_OPEN] = &API_dev_open;
+ calls_table[API_DEV_CLOSE] = &API_dev_close;
+ calls_table[API_DEV_READ] = &API_dev_read;
+ calls_table[API_DEV_WRITE] = &API_dev_write;
+ calls_table[API_ENV_GET] = &API_env_get;
+ calls_table[API_ENV_SET] = &API_env_set;
+ calls_table[API_ENV_ENUM] = &API_env_enum;
+ calls_no = API_MAXCALL;
+
+ debugf("API initialized with %d calls\n", calls_no);
+
+ dev_stor_init();
+
+ /*
+ * Produce the signature so the API consumers can find it
+ */
+ sig = malloc(sizeof(struct api_signature));
+ if (sig == NULL) {
+ printf("API: could not allocate memory for the signature!\n");
+ return;
+ }
+
+ debugf("API sig @ 0x%08x\n", sig);
+ memcpy(sig->magic, API_SIG_MAGIC, 8);
+ sig->version = API_SIG_VERSION;
+ sig->syscall = &syscall;
+ sig->checksum = 0;
+ sig->checksum = crc32(0, (unsigned char *)sig,
+ sizeof(struct api_signature));
+ debugf("syscall entry: 0x%08x\n", sig->syscall);
+}
+
+void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
+ int flags)
+{
+ int i;
+
+ if (!si->mr || !size || (flags == 0))
+ return;
+
+ /* find free slot */
+ for (i = 0; i < si->mr_no; i++)
+ if (si->mr[i].flags == 0) {
+ /* insert new mem region */
+ si->mr[i].start = start;
+ si->mr[i].size = size;
+ si->mr[i].flags = flags;
+ return;
+ }
+}
+
+#endif /* CONFIG_API */
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_API)
+
+#include <common.h>
+#include <net.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DEBUG
+#undef DEBUG
+
+#if !defined(CONFIG_NET_MULTI)
+#error "API/net is currently only available for platforms with CONFIG_NET_MULTI"
+#endif
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
+
+
+static int dev_valid_net(void *cookie)
+{
+ return ((void *)eth_get_dev() == cookie) ? 1 : 0;
+}
+
+int dev_open_net(void *cookie)
+{
+ if (!dev_valid_net(cookie))
+ return API_ENODEV;
+
+ if (eth_init(gd->bd) < 0)
+ return API_EIO;
+
+ return 0;
+}
+
+int dev_close_net(void *cookie)
+{
+ if (!dev_valid_net(cookie))
+ return API_ENODEV;
+
+ eth_halt();
+ return 0;
+}
+
+/*
+ * There can only be one active eth interface at a time - use what is
+ * currently set to eth_current
+ */
+int dev_enum_net(struct device_info *di)
+{
+ struct eth_device *eth_current = eth_get_dev();
+
+ di->type = DEV_TYP_NET;
+ di->cookie = (void *)eth_current;
+ if (di->cookie == NULL)
+ return 0;
+
+ memcpy(di->di_net.hwaddr, eth_current->enetaddr, 6);
+
+ debugf("device found, returning cookie 0x%08x\n",
+ (u_int32_t)di->cookie);
+
+ return 1;
+}
+
+int dev_write_net(void *cookie, void *buf, int len)
+{
+ /* XXX verify that cookie points to a valid net device??? */
+
+ return eth_send(buf, len);
+}
+
+int dev_read_net(void *cookie, void *buf, int len)
+{
+ /* XXX verify that cookie points to a valid net device??? */
+
+ return eth_receive(buf, len);
+}
+
+#endif /* CONFIG_API */
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * This file contains routines that fetch data from ARM-dependent sources
+ * (bd_info etc.)
+ *
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_API)
+
+#include <linux/types.h>
+#include <api_public.h>
+
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#include "api_private.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Important notice: handling of individual fields MUST be kept in sync with
+ * include/asm-arm/u-boot.h and include/asm-arm/global_data.h, so any changes
+ * need to reflect their current state and layout of structures involved!
+ */
+int platform_sys_info(struct sys_info *si)
+{
+ int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
+ platform_set_mr(si, gd->bd->bi_dram[i].start,
+ gd->bd->bi_dram[i].size, MR_ATTR_DRAM);
+
+ return 1;
+}
+
+#endif /* CONFIG_API */
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * This file contains routines that fetch data from PowerPC-dependent sources
+ * (bd_info etc.)
+ *
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_API)
+
+#include <linux/types.h>
+#include <api_public.h>
+
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#include "api_private.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Important notice: handling of individual fields MUST be kept in sync with
+ * include/asm-ppc/u-boot.h and include/asm-ppc/global_data.h, so any changes
+ * need to reflect their current state and layout of structures involved!
+ */
+int platform_sys_info(struct sys_info *si)
+{
+ si->clk_bus = gd->bus_clk;
+ si->clk_cpu = gd->cpu_clk;
+
+#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) || \
+ defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
+#define bi_bar bi_immr_base
+#elif defined(CONFIG_MPC5xxx)
+#define bi_bar bi_mbar_base
+#elif defined(CONFIG_MPC83XX)
+#define bi_bar bi_immrbar
+#elif defined(CONFIG_MPC8220)
+#define bi_bar bi_mbar_base
+#endif
+
+#if defined(bi_bar)
+ si->bar = gd->bd->bi_bar;
+#undef bi_bar
+#else
+ si->bar = NULL;
+#endif
+
+ platform_set_mr(si, gd->bd->bi_memstart, gd->bd->bi_memsize, MR_ATTR_DRAM);
+ platform_set_mr(si, gd->bd->bi_flashstart, gd->bd->bi_flashsize, MR_ATTR_FLASH);
+ platform_set_mr(si, gd->bd->bi_sramstart, gd->bd->bi_sramsize, MR_ATTR_SRAM);
+
+ return 1;
+}
+
+#endif /* CONFIG_API */
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef _API_PRIVATE_H_
+#define _API_PRIVATE_H_
+
+void api_init(void);
+void platform_set_mr(struct sys_info *, unsigned long, unsigned long, int);
+int platform_sys_info(struct sys_info *);
+
+void dev_enum_reset(void);
+int dev_enum_storage(struct device_info *);
+int dev_enum_net(struct device_info *);
+
+int dev_open_stor(void *);
+int dev_open_net(void *);
+int dev_close_stor(void *);
+int dev_close_net(void *);
+
+lbasize_t dev_read_stor(void *, void *, lbasize_t, lbastart_t);
+int dev_read_net(void *, void *, int);
+int dev_write_net(void *, void *, int);
+
+void dev_stor_init(void);
+
+#endif /* _API_PRIVATE_H_ */
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_API)
+
+#include <common.h>
+#include <api_public.h>
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
+
+
+#define ENUM_IDE 0
+#define ENUM_USB 1
+#define ENUM_SCSI 2
+#define ENUM_MMC 3
+#define ENUM_MAX 4
+
+struct stor_spec {
+ int max_dev;
+ int enum_started;
+ int enum_ended;
+ int type; /* "external" type: DT_STOR_{IDE,USB,etc} */
+ char name[4];
+};
+
+static struct stor_spec specs[ENUM_MAX] = { { 0, 0, 0, 0, "" }, };
+
+
+void dev_stor_init(void)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_IDE)
+ specs[ENUM_IDE].max_dev = CFG_IDE_MAXDEVICE;
+ specs[ENUM_IDE].enum_started = 0;
+ specs[ENUM_IDE].enum_ended = 0;
+ specs[ENUM_IDE].type = DEV_TYP_STOR | DT_STOR_IDE;
+ specs[ENUM_IDE].name = "ide";
+#endif
+#if (CONFIG_COMMANDS & CFG_CMD_USB)
+ specs[ENUM_USB].max_dev = USB_MAX_STOR_DEV;
+ specs[ENUM_USB].enum_started = 0;
+ specs[ENUM_USB].enum_ended = 0;
+ specs[ENUM_USB].type = DEV_TYP_STOR | DT_STOR_USB;
+ specs[ENUM_USB].name = "usb";
+#endif
+#if (CONFIG_COMMANDS & CFG_CMD_SCSI)
+ specs[ENUM_SCSI].max_dev = CFG_SCSI_MAX_DEVICE;
+ specs[ENUM_SCSI].enum_started = 0;
+ specs[ENUM_SCSI].enum_ended = 0;
+ specs[ENUM_SCSI].type = DEV_TYP_STOR | DT_STOR_SCSI;
+ specs[ENUM_SCSI].name = "scsi";
+#endif
+}
+
+/*
+ * Finds next available device in the storage group
+ *
+ * type: storage group type - ENUM_IDE, ENUM_SCSI etc.
+ *
+ * first: if 1 the first device in the storage group is returned (if
+ * exists), if 0 the next available device is searched
+ *
+ * more: returns 0/1 depending if there are more devices in this group
+ * available (for future iterations)
+ *
+ * returns: 0/1 depending if device found in this iteration
+ */
+static int dev_stor_get(int type, int first, int *more, struct device_info *di)
+{
+ int found = 0;
+ *more = 0;
+
+ int i;
+
+ block_dev_desc_t *dd;
+
+ if (first) {
+ di->cookie = (void *)get_dev(specs[type].name, 0);
+ found = 1;
+
+ } else {
+ for (i = 0; i < specs[type].max_dev; i++)
+ if (di->cookie == (void *)get_dev(specs[type].name, i)) {
+ /* previous cookie found -- advance to the
+ * next device, if possible */
+
+ if (++i >= specs[type].max_dev) {
+ /* out of range, no more to enum */
+ di->cookie = NULL;
+ break;
+ }
+
+ di->cookie = (void *)get_dev(specs[type].name, i);
+ found = 1;
+
+ /* provide hint if there are more devices in
+ * this group to enumerate */
+ if ((i + 1) < specs[type].max_dev)
+ *more = 1;
+
+ break;
+ }
+ }
+
+ if (found) {
+ di->type = specs[type].type;
+
+ if (di->cookie != NULL) {
+ dd = (block_dev_desc_t *)di->cookie;
+ if (dd->type == DEV_TYPE_UNKNOWN) {
+ debugf("device instance exists, but is not active..");
+ found = 0;
+ } else {
+ di->di_stor.block_count = dd->lba;
+ di->di_stor.block_size = dd->blksz;
+ }
+ }
+
+ } else
+ di->cookie = NULL;
+
+ return found;
+}
+
+
+/*
+ * returns: ENUM_IDE, ENUM_USB etc. based on block_dev_desc_t
+ */
+static int dev_stor_type(block_dev_desc_t *dd)
+{
+ int i, j;
+
+ for (i = ENUM_IDE; i < ENUM_MAX; i++)
+ for (j = 0; j < specs[i].max_dev; j++)
+ if (dd == get_dev(specs[i].name, j))
+ return i;
+
+ return ENUM_MAX;
+}
+
+
+/*
+ * returns: 0/1 whether cookie points to some device in this group
+ */
+static int dev_is_stor(int type, struct device_info *di)
+{
+ return (dev_stor_type(di->cookie) == type) ? 1 : 0;
+}
+
+
+static int dev_enum_stor(int type, struct device_info *di)
+{
+ int found = 0, more = 0;
+
+ debugf("called, type %d\n", type);
+
+ /*
+ * Formulae for enumerating storage devices:
+ * 1. if cookie (hint from previous enum call) is NULL we start again
+ * with enumeration, so return the first available device, done.
+ *
+ * 2. if cookie is not NULL, check if it identifies some device in
+ * this group:
+ *
+ * 2a. if cookie is a storage device from our group (IDE, USB etc.),
+ * return next available (if exists) in this group
+ *
+ * 2b. if it isn't device from our group, check if such devices were
+ * ever enumerated before:
+ * - if not, return the first available device from this group
+ * - else return 0
+ */
+
+ if (di->cookie == NULL) {
+
+ debugf("group%d - enum restart\n", type);
+
+ /*
+ * 1. Enumeration (re-)started: take the first available
+ * device, if exists
+ */
+ found = dev_stor_get(type, 1, &more, di);
+ specs[type].enum_started = 1;
+
+ } else if (dev_is_stor(type, di)) {
+
+ debugf("group%d - enum continued for the next device\n", type);
+
+ if (specs[type].enum_ended) {
+ debugf("group%d - nothing more to enum!\n", type);
+ return 0;
+ }
+
+ /* 2a. Attempt to take a next available device in the group */
+ found = dev_stor_get(type, 0, &more, di);
+
+ } else {
+
+ if (specs[type].enum_ended) {
+ debugf("group %d - already enumerated, skipping\n", type);
+ return 0;
+ }
+
+ debugf("group%d - first time enum\n", type);
+
+ if (specs[type].enum_started == 0) {
+ /*
+ * 2b. If enumerating devices in this group did not
+ * happen before, it means the cookie pointed to a
+ * device frome some other group (another storage
+ * group, or network); in this case try to take the
+ * first available device from our group
+ */
+ specs[type].enum_started = 1;
+
+ /*
+ * Attempt to take the first device in this group:
+ *'first element' flag is set
+ */
+ found = dev_stor_get(type, 1, &more, di);
+
+ } else {
+ errf("group%d - out of order iteration\n", type);
+ found = 0;
+ more = 0;
+ }
+ }
+
+ /*
+ * If there are no more devices in this group, consider its
+ * enumeration finished
+ */
+ specs[type].enum_ended = (!more) ? 1 : 0;
+
+ if (found)
+ debugf("device found, returning cookie 0x%08x\n",
+ (u_int32_t)di->cookie);
+ else
+ debugf("no device found\n");
+
+ return found;
+}
+
+void dev_enum_reset(void)
+{
+ int i;
+
+ for (i = 0; i < ENUM_MAX; i ++) {
+ specs[i].enum_started = 0;
+ specs[i].enum_ended = 0;
+ }
+}
+
+int dev_enum_storage(struct device_info *di)
+{
+ int i;
+
+ /*
+ * check: ide, usb, scsi, mmc
+ */
+ for (i = ENUM_IDE; i < ENUM_MAX; i ++) {
+ if (dev_enum_stor(i, di))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int dev_stor_is_valid(int type, block_dev_desc_t *dd)
+{
+ int i;
+
+ for (i = 0; i < specs[type].max_dev; i++)
+ if (dd == get_dev(specs[type].name, i))
+ if (dd->type != DEV_TYPE_UNKNOWN)
+ return 1;
+
+ return 0;
+}
+
+
+int dev_open_stor(void *cookie)
+{
+ int type = dev_stor_type(cookie);
+
+ if (type == ENUM_MAX)
+ return API_ENODEV;
+
+ if (dev_stor_is_valid(type, (block_dev_desc_t *)cookie))
+ return 0;
+
+ return API_ENODEV;
+}
+
+
+int dev_close_stor(void *cookie)
+{
+ /*
+ * Not much to do as we actually do not alter storage devices upon
+ * close
+ */
+ return 0;
+}
+
+
+static int dev_stor_index(block_dev_desc_t *dd)
+{
+ int i, type;
+
+ type = dev_stor_type(dd);
+ for (i = 0; i < specs[type].max_dev; i++)
+ if (dd == get_dev(specs[type].name, i))
+ return i;
+
+ return (specs[type].max_dev);
+}
+
+
+lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start)
+{
+ int type;
+ block_dev_desc_t *dd = (block_dev_desc_t *)cookie;
+
+ if ((type = dev_stor_type(dd)) == ENUM_MAX)
+ return 0;
+
+ if (!dev_stor_is_valid(type, dd))
+ return 0;
+
+ if ((dd->block_read) == NULL) {
+ debugf("no block_read() for device 0x%08x\n");
+ return 0;
+ }
+
+ return (dd->block_read(dev_stor_index(dd), start, len, buf));
+}
+
+#endif /* CONFIG_API */
--- /dev/null
+#
+# (C) Copyright 2007 Semihalf
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundatio; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+ifeq ($(ARCH),ppc)
+LOAD_ADDR = 0x40000
+endif
+
+#ifeq ($(ARCH),arm)
+#LOAD_ADDR = 0xc100000
+#endif
+
+include $(TOPDIR)/config.mk
+
+ELF += demo
+BIN += demo.bin
+
+#CFLAGS += -v
+
+COBJS := $(ELF:=.o)
+SOBJS := crt0.o
+ifeq ($(ARCH),ppc)
+SOBJS += ppcstring.o
+endif
+
+LIB = $(obj)libglue.a
+LIBCOBJS= glue.o crc32.o ctype.o string.o vsprintf.o libgenwrap.o
+
+LIBOBJS = $(addprefix $(obj),$(SOBJS) $(LIBCOBJS))
+
+SRCS := $(COBJS:.o=.c) $(LIBCOBJS:.o=.c) $(SOBJS:.o=.S)
+OBJS := $(addprefix $(obj),$(COBJS))
+ELF := $(addprefix $(obj),$(ELF))
+BIN := $(addprefix $(obj),$(BIN))
+
+gcclibdir := $(shell dirname `$(CC) -print-libgcc-file-name`)
+
+CPPFLAGS += -I..
+
+all: $(obj).depend $(OBJS) $(LIB) $(BIN) $(ELF)
+
+#########################################################################
+$(LIB): $(obj).depend $(LIBOBJS)
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+
+$(ELF):
+$(obj)%: $(obj)%.o $(LIB)
+ $(LD) $(obj)crt0.o -Ttext $(LOAD_ADDR) \
+ -o $@ $< $(LIB) \
+ -L$(gcclibdir) -lgcc
+
+$(BIN):
+$(obj)%.bin: $(obj)%
+ $(OBJCOPY) -O binary $< $@ 2>/dev/null
+
+$(obj)crc32.c:
+ @rm -f $(obj)crc32.c
+ ln -s $(src)../lib_generic/crc32.c $(obj)crc32.c
+
+$(obj)ctype.c:
+ @rm -f $(obj)ctype.c
+ ln -s $(src)../lib_generic/ctype.c $(obj)ctype.c
+
+$(obj)string.c:
+ @rm -f $(obj)string.c
+ ln -s $(src)../lib_generic/string.c $(obj)string.c
+
+$(obj)vsprintf.c:
+ @rm -f $(obj)vsprintf.c
+ ln -s $(src)../lib_generic/vsprintf.c $(obj)vsprintf.c
+
+ifeq ($(ARCH),ppc)
+$(obj)ppcstring.S:
+ @rm -f $(obj)ppcstring.S
+ ln -s $(src)../lib_ppc/ppcstring.S $(obj)ppcstring.S
+endif
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#if defined(CONFIG_PPC)
+
+ .text
+
+ .globl _start
+_start:
+ b main
+
+
+ .globl syscall
+syscall:
+ lis %r11, syscall_ptr@ha
+ addi %r11, %r11, syscall_ptr@l
+ lwz %r11, 0(%r11)
+ mtctr %r11
+ bctr
+
+
+ .globl syscall_ptr
+syscall_ptr:
+ .align 4
+ .long 0
+#else
+#error No support for this arch!
+#endif
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+#include "glue.h"
+
+#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
+
+void test_dump_si(struct sys_info *);
+void test_dump_di(int);
+void test_dump_sig(struct api_signature *);
+
+char buf[2048];
+
+#define WAIT_SECS 5
+
+int main(int argc, char *argv[])
+{
+ int rv = 0;
+ int h, i, j;
+ int devs_no;
+ struct api_signature *sig = NULL;
+ ulong start, now;
+ struct device_info *di;
+
+ if (!api_search_sig(&sig))
+ return -1;
+
+ syscall_ptr = sig->syscall;
+ if (syscall_ptr == NULL)
+ return -2;
+
+ if (sig->version > API_SIG_VERSION)
+ return -3;
+
+ printf("API signature found @%x\n", sig);
+ test_dump_sig(sig);
+
+ printf("\n*** Consumer API test ***\n");
+ printf("syscall ptr 0x%08x@%08x\n", syscall_ptr, &syscall_ptr);
+
+ /* console activities */
+ ub_putc('B');
+
+ printf("*** Press any key to continue ***\n");
+ printf("got char 0x%x\n", ub_getc());
+
+ /* system info */
+ test_dump_si(ub_get_sys_info());
+
+ /* timing */
+ printf("\n*** Timing - wait a couple of secs ***\n");
+ start = ub_get_timer(0);
+ printf("\ntime: start %lu\n\n", start);
+ for (i = 0; i < WAIT_SECS; i++)
+ for (j = 0; j < 1000; j++)
+ ub_udelay(1000); /* wait 1 ms */
+
+ /* this is the number of milliseconds that passed from ub_get_timer(0) */
+ now = ub_get_timer(start);
+ printf("\ntime: now %lu\n\n", now);
+
+ /* enumerate devices */
+ printf("\n*** Enumerate devices ***\n");
+ devs_no = ub_dev_enum();
+
+ printf("Number of devices found: %d\n", devs_no);
+ if (devs_no == 0)
+ return -1;
+
+
+ printf("\n*** Show devices ***\n");
+ for (i = 0; i < devs_no; i++) {
+ test_dump_di(i);
+ printf("\n");
+ }
+
+ printf("\n*** Operations on devices ***\n");
+
+ /* test opening a device already opened */
+ h = 0;
+ if ((rv = ub_dev_open(h)) != 0) {
+ errf("open device %d error %d\n", h, rv);
+ return -1;
+ }
+ if ((rv = ub_dev_open(h)) != 0)
+ errf("open device %d error %d\n", h, rv);
+
+ ub_dev_close(h);
+
+ /* test storage */
+ printf("Trying storage devices...\n");
+ for (i = 0; i < devs_no; i++) {
+ di = ub_dev_get(i);
+
+ if (di->type & DEV_TYP_STOR)
+ break;
+
+ }
+ if (i == devs_no)
+ printf("No storage devices available\n");
+ else {
+ if ((rv = ub_dev_open(i)) != 0)
+ errf("open device %d error %d\n", i, rv);
+ else if ((rv = ub_dev_read(i, &buf, 200, 20)) != 0)
+ errf("could not read from device %d, error %d\n", i, rv);
+
+ ub_dev_close(i);
+ }
+
+ /* test networking */
+ printf("Trying network devices...\n");
+ for (i = 0; i < devs_no; i++) {
+ di = ub_dev_get(i);
+
+ if (di->type == DEV_TYP_NET)
+ break;
+
+ }
+ if (i == devs_no)
+ printf("No network devices available\n");
+ else {
+ if ((rv = ub_dev_open(i)) != 0)
+ errf("open device %d error %d\n", i, rv);
+ else if ((rv = ub_dev_send(i, &buf, 2048)) != 0)
+ errf("could not send to device %d, error %d\n", i, rv);
+
+ ub_dev_close(i);
+ }
+
+ if (ub_dev_close(h) != 0)
+ errf("could not close device %d\n", h);
+
+ printf("\n*** Env vars ***\n");
+
+ printf("ethact = %s\n", ub_env_get("ethact"));
+ printf("old fileaddr = %s\n", ub_env_get("fileaddr"));
+ ub_env_set("fileaddr", "deadbeef");
+ printf("new fileaddr = %s\n", ub_env_get("fileaddr"));
+
+ const char *env = NULL;
+
+ while ((env = ub_env_enum(env)) != NULL)
+ printf("%s = %s\n", env, ub_env_get(env));
+
+ /* reset */
+ ub_reset();
+ printf("\nHmm, reset returned...?!\n");
+
+ return rv;
+}
+
+void test_dump_sig(struct api_signature *sig)
+{
+ printf("signature:\n");
+ printf(" version\t= %d\n", sig->version);
+ printf(" checksum\t= 0x%08x\n", sig->checksum);
+ printf(" sc entry\t= 0x%08x\n", sig->syscall);
+}
+
+void test_dump_si(struct sys_info *si)
+{
+ int i;
+
+ printf("sys info:\n");
+ printf(" clkbus\t= 0x%08x\n", si->clk_bus);
+ printf(" clkcpu\t= 0x%08x\n", si->clk_cpu);
+ printf(" bar\t\t= 0x%08x\n", si->bar);
+
+ printf("---\n");
+ for (i = 0; i < si->mr_no; i++) {
+ if (si->mr[i].flags == 0)
+ break;
+
+ printf(" start\t= 0x%08lx\n", si->mr[i].start);
+ printf(" size\t= 0x%08lx\n", si->mr[i].size);
+
+ switch(si->mr[i].flags & 0x000F) {
+ case MR_ATTR_FLASH:
+ printf(" type FLASH\n");
+ break;
+ case MR_ATTR_DRAM:
+ printf(" type DRAM\n");
+ break;
+ case MR_ATTR_SRAM:
+ printf(" type SRAM\n");
+ break;
+ default:
+ printf(" type UNKNOWN\n");
+ }
+ printf("---\n");
+ }
+}
+
+static char * test_stor_typ(int type)
+{
+ if (type & DT_STOR_IDE)
+ return "IDE";
+
+ if (type & DT_STOR_SCSI)
+ return "SCSI";
+
+ if (type & DT_STOR_USB)
+ return "USB";
+
+ if (type & DT_STOR_MMC);
+ return "MMC";
+
+ return "Unknown";
+}
+
+void test_dump_di(int handle)
+{
+ int i;
+ struct device_info *di = ub_dev_get(handle);
+
+ printf("device info (%d):\n", handle);
+ printf(" cookie\t= 0x%08x\n", (uint32_t)di->cookie);
+ printf(" type\t\t= 0x%08x\n", di->type);
+
+ if (di->type == DEV_TYP_NET) {
+ printf(" hwaddr\t= ");
+ for (i = 0; i < 6; i++)
+ printf("%02x ", di->di_net.hwaddr[i]);
+
+ printf("\n");
+
+ } else if (di->type & DEV_TYP_STOR) {
+ printf(" type\t\t= %s\n", test_stor_typ(di->type));
+ printf(" blk size\t\t= %d\n", di->di_stor.block_size);
+ printf(" blk count\t\t= %d\n", di->di_stor.block_count);
+ }
+}
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+#include "glue.h"
+
+static int valid_sig(struct api_signature *sig)
+{
+ uint32_t checksum;
+ struct api_signature s;
+
+ if (sig == NULL)
+ return 0;
+ /*
+ * Clear the checksum field (in the local copy) so as to calculate the
+ * CRC with the same initial contents as at the time when the sig was
+ * produced
+ */
+ s = *sig;
+ s.checksum = 0;
+
+ checksum = crc32(0, (unsigned char *)&s, sizeof(struct api_signature));
+
+ if (checksum != sig->checksum)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Searches for the U-Boot API signature
+ *
+ * returns 1/0 depending on found/not found result
+ */
+int api_search_sig(struct api_signature **sig) {
+
+ unsigned char *sp;
+
+ if (sig == NULL)
+ return 0;
+
+ sp = (unsigned char *)API_SEARCH_START;
+
+ while ((sp + (int)API_SIG_MAGLEN) < (unsigned char *)API_SEARCH_END) {
+ if (!memcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
+ *sig = (struct api_signature *)sp;
+ if (valid_sig(*sig))
+ return 1;
+ }
+ sp += API_SIG_MAGLEN;
+ }
+
+ *sig = NULL;
+ return 0;
+}
+
+/****************************************
+ *
+ * console
+ *
+ ****************************************/
+
+int ub_getc(void)
+{
+ int c;
+
+ if (!syscall(API_GETC, NULL, (uint32_t)&c))
+ return -1;
+
+ return c;
+}
+
+int ub_tstc(void)
+{
+ int t;
+
+ if (!syscall(API_TSTC, NULL, (uint32_t)&t))
+ return -1;
+
+ return t;
+}
+
+void ub_putc(char c)
+{
+ syscall(API_PUTC, NULL, (uint32_t)&c);
+}
+
+void ub_puts(const char *s)
+{
+ syscall(API_PUTS, NULL, (uint32_t)s);
+}
+
+/****************************************
+ *
+ * system
+ *
+ ****************************************/
+
+void ub_reset(void)
+{
+ syscall(API_RESET, NULL);
+}
+
+#define MR_MAX 5
+static struct mem_region mr[MR_MAX];
+static struct sys_info si;
+
+struct sys_info * ub_get_sys_info(void)
+{
+ int err = 0;
+
+ memset(&si, 0, sizeof(struct sys_info));
+ si.mr = mr;
+ si.mr_no = MR_MAX;
+ memset(&mr, 0, sizeof(mr));
+
+ if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
+ return NULL;
+
+ return ((err) ? NULL : &si);
+}
+
+/****************************************
+ *
+ * timing
+ *
+ ****************************************/
+
+void ub_udelay(unsigned long usec)
+{
+ syscall(API_UDELAY, NULL, &usec);
+}
+
+unsigned long ub_get_timer(unsigned long base)
+{
+ unsigned long cur;
+
+ if (!syscall(API_GET_TIMER, NULL, &cur, &base))
+ return 0;
+
+ return cur;
+}
+
+
+/****************************************************************************
+ *
+ * devices
+ *
+ * Devices are identified by handles: numbers 0, 1, 2, ..., MAX_DEVS-1
+ *
+ ***************************************************************************/
+
+#define MAX_DEVS 6
+
+static struct device_info devices[MAX_DEVS];
+
+struct device_info * ub_dev_get(int i)
+{
+ return ((i < 0 || i >= MAX_DEVS) ? NULL : &devices[i]);
+}
+
+/*
+ * Enumerates the devices: fills out device_info elements in the devices[]
+ * array.
+ *
+ * returns: number of devices found
+ */
+int ub_dev_enum(void)
+{
+ struct device_info *di;
+ int n = 0;
+
+ memset(&devices, 0, sizeof(struct device_info) * MAX_DEVS);
+ di = &devices[0];
+
+ if (!syscall(API_DEV_ENUM, NULL, di))
+ return 0;
+
+ while (di->cookie != NULL) {
+
+ if (++n >= MAX_DEVS)
+ break;
+
+ /* take another device_info */
+ di++;
+
+ /* pass on the previous cookie */
+ di->cookie = devices[n - 1].cookie;
+
+ if (!syscall(API_DEV_ENUM, NULL, di))
+ return 0;
+ }
+
+ return n;
+}
+
+/*
+ * handle: 0-based id of the device
+ *
+ * returns: 0 when OK, err otherwise
+ */
+int ub_dev_open(int handle)
+{
+ struct device_info *di;
+ int err = 0;
+
+ if (handle < 0 || handle >= MAX_DEVS)
+ return API_EINVAL;
+
+ di = &devices[handle];
+
+ if (!syscall(API_DEV_OPEN, &err, di))
+ return -1;
+
+ return err;
+}
+
+int ub_dev_close(int handle)
+{
+ struct device_info *di;
+
+ if (handle < 0 || handle >= MAX_DEVS)
+ return API_EINVAL;
+
+ di = &devices[handle];
+ if (!syscall(API_DEV_CLOSE, NULL, di))
+ return -1;
+
+ return 0;
+}
+
+/*
+ *
+ * Validates device for read/write, it has to:
+ *
+ * - have sane handle
+ * - be opened
+ *
+ * returns: 0/1 accordingly
+ */
+static int dev_valid(int handle)
+{
+ if (handle < 0 || handle >= MAX_DEVS)
+ return 0;
+
+ if (devices[handle].state != DEV_STA_OPEN)
+ return 0;
+
+ return 1;
+}
+
+static int dev_stor_valid(int handle)
+{
+ if (!dev_valid(handle))
+ return 0;
+
+ if (!(devices[handle].type & DEV_TYP_STOR))
+ return 0;
+
+ return 1;
+}
+
+int ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start)
+{
+ struct device_info *di;
+ lbasize_t act_len;
+ int err = 0;
+
+ if (!dev_stor_valid(handle))
+ return API_ENODEV;
+
+ di = &devices[handle];
+ if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
+ return -1;
+
+ if (err)
+ return err;
+
+ if (act_len != len)
+ return API_EIO;
+
+ return 0;
+}
+
+static int dev_net_valid(int handle)
+{
+ if (!dev_valid(handle))
+ return 0;
+
+ if (devices[handle].type != DEV_TYP_NET)
+ return 0;
+
+ return 1;
+}
+
+int ub_dev_recv(int handle, void *buf, int len)
+{
+ struct device_info *di;
+ int err = 0, act_len;
+
+ if (!dev_net_valid(handle))
+ return API_ENODEV;
+
+ di = &devices[handle];
+ if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
+ return -1;
+
+ if (err)
+ return -1;
+
+ return act_len;
+}
+
+int ub_dev_send(int handle, void *buf, int len)
+{
+ struct device_info *di;
+ int err = 0;
+
+ if (!dev_net_valid(handle))
+ return API_ENODEV;
+
+ di = &devices[handle];
+ if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
+ return -1;
+
+ return err;
+}
+
+/****************************************
+ *
+ * env vars
+ *
+ ****************************************/
+
+char * ub_env_get(const char *name)
+{
+ char *value;
+
+ if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value))
+ return NULL;
+
+ return value;
+}
+
+void ub_env_set(const char *name, char *value)
+{
+ syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value);
+}
+
+
+static char env_name[256];
+
+const char * ub_env_enum(const char *last)
+{
+ const char *env, *str;
+ int i;
+
+ env = NULL;
+
+ /*
+ * It's OK to pass only the name piece as last (and not the whole
+ * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
+ * internally, which handles such case
+ */
+ if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env))
+ return NULL;
+
+ if (!env)
+ /* no more env. variables to enumerate */
+ return NULL;
+
+ /* next enumerated env var */
+ memset(env_name, 0, 256);
+ for (i = 0, str = env; *str != '=' && *str != '\0';)
+ env_name[i++] = *str++;
+
+ env_name[i] = '\0';
+
+ return env_name;
+}
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * This is the header file for conveniency wrapper routines (API glue)
+ */
+
+#ifndef _API_GLUE_H_
+#define _API_GLUE_H_
+
+#define API_SEARCH_START (255 * 1024 * 1024) /* start at 1MB below top RAM */
+#define API_SEARCH_END (256 * 1024 * 1024 - 1) /* ...and search to the end */
+
+int syscall(int, int *, ...);
+void * syscall_ptr;
+
+int api_search_sig(struct api_signature **sig);
+
+/*
+ * ub_ library calls are part of the application, not U-Boot code! They are
+ * front-end wrappers that are used by the consumer application: they prepare
+ * arguments for particular syscall and jump to the low level syscall()
+ */
+
+/* console */
+int ub_getc(void);
+int ub_tstc(void);
+void ub_putc(char c);
+void ub_puts(const char *s);
+
+/* system */
+void ub_reset(void);
+struct sys_info * ub_get_sys_info(void);
+
+/* time */
+void ub_udelay(unsigned long);
+unsigned long ub_get_timer(unsigned long);
+
+/* env vars */
+char * ub_env_get(const char *name);
+void ub_env_set(const char *name, char *value);
+const char * ub_env_enum(const char *last);
+
+/* devices */
+int ub_dev_enum(void);
+int ub_dev_open(int handle);
+int ub_dev_close(int handle);
+int ub_dev_read(int handle, void *buf,
+ lbasize_t len, lbastart_t start);
+int ub_dev_send(int handle, void *buf, int len);
+int ub_dev_recv(int handle, void *buf, int len);
+struct device_info * ub_dev_get(int);
+
+#endif /* _API_GLUE_H_ */
--- /dev/null
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * This is is a set of wrappers/stubs that allow to use certain routines from
+ * U-Boot's lib_generic in the standalone app. This way way we can re-use
+ * existing code e.g. operations on strings and similar.
+ *
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+#include "glue.h"
+
+/*
+ * printf() and vprintf() are stolen from u-boot/common/console.c
+ */
+void printf (const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[256];
+
+ va_start (args, fmt);
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vsprintf (printbuffer, fmt, args);
+ va_end (args);
+
+ /* Print the string */
+ ub_puts (printbuffer);
+}
+
+void vprintf (const char *fmt, va_list args)
+{
+ uint i;
+ char printbuffer[256];
+
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ i = vsprintf (printbuffer, fmt, args);
+
+ /* Print the string */
+ ub_puts (printbuffer);
+}
+
+void putc (const char c)
+{
+ ub_putc(c);
+}
+
+void udelay(unsigned long usec)
+{
+ ub_udelay(usec);
+}
+
+void do_reset (void)
+{
+ ub_reset();
+}
+
+void *malloc(size_t len)
+{
+ return NULL;
+}
--- /dev/null
+#ifndef _API_PUBLIC_H_
+#define _API_PUBLIC_H_
+
+#define API_EINVAL 1 /* invalid argument(s) */
+#define API_ENODEV 2 /* no device */
+#define API_ENOMEM 3 /* no memory */
+#define API_EBUSY 4 /* busy, occupied etc. */
+#define API_EIO 5 /* I/O error */
+
+typedef int (*scp_t)(int, int *, ...);
+
+#define API_SIG_VERSION 1
+#define API_SIG_MAGIC "UBootAPI"
+#define API_SIG_MAGLEN 8
+
+struct api_signature {
+ char magic[API_SIG_MAGLEN]; /* magic string */
+ uint16_t version; /* API version */
+ uint32_t checksum; /* checksum of this sig struct */
+ scp_t syscall; /* entry point to the API */
+};
+
+enum {
+ API_RSVD = 0,
+ API_GETC,
+ API_PUTC,
+ API_TSTC,
+ API_PUTS,
+ API_RESET,
+ API_GET_SYS_INFO,
+ API_UDELAY,
+ API_GET_TIMER,
+ API_DEV_ENUM,
+ API_DEV_OPEN,
+ API_DEV_CLOSE,
+ API_DEV_READ,
+ API_DEV_WRITE,
+ API_ENV_ENUM,
+ API_ENV_GET,
+ API_ENV_SET,
+ API_MAXCALL
+};
+
+#define MR_ATTR_FLASH 0x0001
+#define MR_ATTR_DRAM 0x0002
+#define MR_ATTR_SRAM 0x0003
+
+struct mem_region {
+ unsigned long start;
+ unsigned long size;
+ int flags;
+};
+
+struct sys_info {
+ unsigned long clk_bus;
+ unsigned long clk_cpu;
+ unsigned long bar;
+ struct mem_region *mr;
+ int mr_no; /* number of memory regions */
+};
+
+#undef CFG_64BIT_LBA
+#ifdef CFG_64BIT_LBA
+typedef u_int64_t lbasize_t;
+#else
+typedef unsigned long lbasize_t;
+#endif
+typedef unsigned long lbastart_t;
+
+#define DEV_TYP_NONE 0x0000
+#define DEV_TYP_NET 0x0001
+
+#define DEV_TYP_STOR 0x0002
+#define DT_STOR_IDE 0x0010
+#define DT_STOR_SCSI 0x0020
+#define DT_STOR_USB 0x0040
+#define DT_STOR_MMC 0x0080
+
+#define DEV_STA_CLOSED 0x0000 /* invalid, closed */
+#define DEV_STA_OPEN 0x0001 /* open i.e. active */
+
+struct device_info {
+ int type;
+ void *cookie;
+
+ union {
+ struct {
+ lbasize_t block_count; /* no of blocks */
+ unsigned long block_size; /* size of one block */
+ } storage;
+
+ struct {
+ unsigned char hwaddr[6];
+ } net;
+ } info;
+#define di_stor info.storage
+#define di_net info.net
+
+ int state;
+};
+
+#endif /* _API_PUBLIC_H_ */
/* common/exports.c */
void jumptable_init(void);
+/* api/api.c */
+void api_init (void);
+
/* common/memsize.c */
long get_ram_size (volatile long *, long);
/* Initialize the jump table for applications */
jumptable_init ();
+#if defined(CONFIG_API)
+ /* Initialize API */
+ api_init ();
+#endif
+
/* Initialize the console (after the relocation and devices init) */
console_init_r ();