Skip to contentSkip to conversation

API for external applications

PATCH New Rafal Jaworowski 3 participants 12 messages Oct 3, 2007 – Oct 4, 2007 Networking

lore
Share & tools
lore
#0 lore raw

cover API for external applications

Hi,

This patchset attempts to implement an API for external applications, where the existing jumptable mechanism is too simplified. We needed a more robust and generic interface to access U-Boot resources for FreeBSD loader and came up with this approach.

Patches 1-3 are changes in U-Boot infrastructure needed for the API purposes, 4-6 are bulk of this implementation, 7 is just enabling it for the MPC8555CDS target (primary test platform).

- integrated with 1.3.0-rc2

- tested on PowerPC, but easily adaptable to other archs (only minor asm piece in the glue needs to be provided)

- devices: only tested networking on real target, storage code considered complete and exercised with test code, but needs more testing

- tested and integrated with FreeBSD native loader which runs on top of U-Boot as a stand-alone app (and in turn passes control to the kernel)

- API layer comes for the 8.5 KB increase in U-Boot's raw binary footprint

A couple of design notes:

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

Let me hear about comments on these patches; next I'd like to put them into my FreeBSD-support custodian repo.

kind regards,
Rafal

#1 lore raw

PATCH 1/7 eth_receive() for standalone receiving Ethernet frame

net/eth.c +52 -0
index c8f92a5..032c926 100644
@@ -59,8 +59,15 @@ extern int npe_initialize(bd_t *);
 extern int uec_initialize(int);
 extern int bfin_EMAC_initialize(bd_t *);
 extern int atstk1000_eth_initialize(bd_t *);
+extern void (*push_packet)(volatile void *, int);
+
+static struct {
+	uchar data[PKTSIZE];
+	int length;
+} eth_rcv_bufs[PKTBUFSRX];
 
 static struct eth_device *eth_devices, *eth_current;
+static unsigned int eth_rcv_current = 0, eth_rcv_last = 0;
 
 struct eth_device *eth_get_dev(void)
 {
@@ -404,6 +411,51 @@ int eth_rx(void)
 	return eth_current->recv(eth_current);
 }
 
+static void eth_save_packet(volatile void *packet, int length)
+{
+	volatile char *p = packet;
+	int i;
+
+	if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
+		return;
+
+	if (PKTSIZE < length)
+		return;
+
+	for (i = 0; i < length; i++)
+		eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
+
+	eth_rcv_bufs[eth_rcv_last].length = length;
+	eth_rcv_last = (eth_rcv_last+1) % PKTBUFSRX;
+}
+
+int eth_receive(volatile void *packet, int length)
+{
+	volatile char *p = packet;
+	void *pp = push_packet;
+	int i;
+
+	if (eth_rcv_current == eth_rcv_last) {
+		push_packet = eth_save_packet;
+		eth_rx();
+		push_packet = pp;
+
+		if (eth_rcv_current == eth_rcv_last)
+			return -1;
+	}
+
+	if (length < eth_rcv_bufs[eth_rcv_current].length)
+		return -1;
+
+	length = eth_rcv_bufs[eth_rcv_current].length;
+
+	for (i = 0; i < length; i++)
+		p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
+
+	eth_rcv_current = (eth_rcv_current+1) % PKTBUFSRX;
+	return length;
+}
+
 void eth_try_another(int first_restart)
 {
 	static struct eth_device *first_failed = NULL;
net/net.c +6 -0
index e9d7757..ae7c372 100644
@@ -133,6 +133,7 @@ uchar		NetBcastAddr[6] =	/* Ethernet bcast address		*/
 			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 uchar		NetEtherNullAddr[6] =
 			{ 0, 0, 0, 0, 0, 0 };
+void		(*push_packet)(volatile void *, int len) = 0;
 #if defined(CONFIG_CMD_CDP)
 uchar		NetCDPAddr[6] =		/* Ethernet bcast address		*/
 			{ 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
@@ -1157,6 +1158,11 @@ NetReceive(volatile uchar * inpkt, int len)
 	if (len < ETHER_HDR_SIZE)
 		return;
 
+	if (push_packet) {
+		(*push_packet)(inpkt, len);
+		return;
+	}
+
 #if defined(CONFIG_CMD_CDP)
 	/* keep track if packet is CDP */
 	iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
#3 lore raw

PATCH 2/7 Simplify base address handling in bd_info

In reply to Rafal Jaworowski
include/asm-ppc/u-boot.h +6 -11
index 464f6b5..cc9f013 100644
@@ -36,6 +36,10 @@
 
 #ifndef __ASSEMBLY__
 
+#define bi_immr_base	bi_bar
+#define bi_mbar_base	bi_bar
+#define bi_immrbar	bi_bar
+
 typedef struct bd_info {
 	unsigned long	bi_memstart;	/* start of DRAM memory */
 	unsigned long	bi_memsize;	/* size	 of DRAM memory in bytes */
@@ -44,18 +48,9 @@ typedef struct bd_info {
 	unsigned long	bi_flashoffset; /* reserved area for startup monitor */
 	unsigned long	bi_sramstart;	/* start of SRAM memory */
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
-#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
-	|| defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
-	unsigned long	bi_immr_base;	/* base of IMMR register */
-#endif
-#if defined(CONFIG_MPC5xxx)
-	unsigned long	bi_mbar_base;	/* base of internal registers */
-#endif
-#if defined(CONFIG_MPC83XX)
-	unsigned long	bi_immrbar;
-#endif
+	unsigned long	bi_bar;		/* base addr of internal registers */
+
 #if defined(CONFIG_MPC8220)
-	unsigned long	bi_mbar_base;	/* base of internal registers */
 	unsigned long   bi_inpfreq;     /* Input Freq, In MHz */
 	unsigned long   bi_pcifreq;     /* PCI Freq, in MHz */
 	unsigned long   bi_pevfreq;     /* PEV Freq, in MHz */
#4 lore raw

PATCH 3/7 Globalize envmatch()

In reply to Rafal Jaworowski
common/cmd_nvedit.c +2 -3
index 1db0fc3..e539e2c 100644
@@ -80,7 +80,7 @@ extern void env_crc_update (void);
 /************************************************************************
 ************************************************************************/
 
-static int envmatch (uchar *, int);
+int envmatch (uchar *, int);
 
 /*
  * Table with supported baudrates (defined in config_xyz.h)
@@ -574,8 +574,7 @@ int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
  * If the names match, return the index for the value2, else NULL.
  */
 
-static int
-envmatch (uchar *s1, int i2)
+int envmatch (uchar *s1, int i2)
 {
 
 	while (*s1 == env_get_char(i2++))
#5 lore raw

PATCH 4/7 API header file

In reply to Rafal Jaworowski
include/api_public.h renamed from src/u-boot/include/api_public.h +102 -0
diff -upr --new-file --exclude=.git /src/u-boot/include/api_public.h u-boot/include/api_public.h
@@ -0,0 +1,102 @@
+#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_ */
#6 lore raw

PATCH 5/7 Core API (U-Boot side)

In reply to Rafal Jaworowski
api/api.c renamed from src/u-boot/api/api.c +670 -0
diff -upr --new-file --exclude=.git /src/u-boot/api/api.c u-boot/api/api.c
@@ -0,0 +1,670 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <[email protected]>
+ *
+ * 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>
+
+#undef DEBUG
+#define DEBUG
+
+void api_init(void);
+
+extern void dev_enum_reset(void);
+extern int dev_enum_storage(struct device_info *);
+extern int dev_enum_net(struct device_info *);
+
+extern int dev_open_stor(void *);
+extern int dev_open_net(void *);
+extern int dev_close_stor(void *);
+extern int dev_close_net(void *);
+
+extern lbasize_t dev_read_stor(void *, void *, lbasize_t, lbastart_t);
+extern int dev_read_net(void *, void *, int);
+
+extern int dev_write_net(void *, void *, int);
+
+extern void dev_stor_init(void);
+extern int platform_sys_info(struct sys_info *);
+
+/* 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);
+extern int envmatch(uchar*, 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: &eth_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 (07.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);
+}
+
+#endif /* CONFIG_API */
api/api_net.c renamed from src/u-boot/api/api_net.c +114 -0

114 lines not on this page · raw message

api/api_platform.c renamed from src/u-boot/api/api_platform.c +74 -0

74 lines not on this page · raw message

api/api_storage.c renamed from src/u-boot/api/api_storage.c +370 -0

370 lines not on this page · raw message

api/Makefile renamed from src/u-boot/api/Makefile +40 -0
diff -upr --new-file --exclude=.git /src/u-boot/api/Makefile u-boot/api/Makefile
@@ -0,0 +1,40 @@
+#
+# (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.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
#7 lore raw

PATCH 6/7 External application demo

In reply to Rafal Jaworowski
api_examples/crt0.S renamed from src/u-boot/api_examples/crt0.S +49 -0
diff -upr --new-file --exclude=.git /src/u-boot/api_examples/crt0.S u-boot/api_examples/crt0.S
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <[email protected]>
+ *
+ * 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 at ha
+	addi	%r11, %r11, syscall_ptr at l
+	lwz	%r11, 0(%r11)
+	mtctr	%r11
+	bctr
+
+
+	.globl syscall_ptr
+syscall_ptr:
+	.long	0
+#else
+#error No support for this arch!
+#endif
api_examples/demo.c renamed from src/u-boot/api_examples/demo.c +294 -0

294 lines not on this page · raw message

api_examples/glue.c renamed from src/u-boot/api_examples/glue.c +460 -0

460 lines not on this page · raw message

api_examples/libgenwrap.c renamed from src/u-boot/api_examples/libgenwrap.c +96 -0

96 lines not on this page · raw message

api_examples/Makefile renamed from src/u-boot/api_examples/Makefile +103 -0

103 lines not on this page · raw message

#8 lore raw

PATCH 7/7 Enable API_CONFIG for MPC8555CDS

In reply to Rafal Jaworowski
include/configs/MPC8555CDS.h +4 -0
index a3025bd..0a32b53 100644
@@ -29,6 +29,9 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
+
+#define CONFIG_API			/* API support */
+
 /* High Level Configuration Options */
 #define CONFIG_BOOKE		1	/* BOOKE */
 #define CONFIG_E500		1	/* BOOKE e500 family */
@@ -418,6 +421,7 @@ extern unsigned long get_clock_freq(void);
 #define CONFIG_CMD_PING
 #define CONFIG_CMD_I2C
 #define CONFIG_CMD_MII
+#define CONFIG_CMD_ELF
 
 #if defined(CONFIG_PCI)
     #define CONFIG_CMD_PCI
#2 lore raw

PATCH 1/7 eth_receive() for standalone receiving Ethernet frame

In reply to Rafal Jaworowski
net/eth.c +52 -0
index c8f92a5..032c926 100644
@@ -59,8 +59,15 @@ extern int npe_initialize(bd_t *);
 extern int uec_initialize(int);
 extern int bfin_EMAC_initialize(bd_t *);
 extern int atstk1000_eth_initialize(bd_t *);
+extern void (*push_packet)(volatile void *, int);
+
+static struct {
+	uchar data[PKTSIZE];
+	int length;
+} eth_rcv_bufs[PKTBUFSRX];
 
 static struct eth_device *eth_devices, *eth_current;
+static unsigned int eth_rcv_current = 0, eth_rcv_last = 0;
 
 struct eth_device *eth_get_dev(void)
 {
@@ -404,6 +411,51 @@ int eth_rx(void)
 	return eth_current->recv(eth_current);
 }
 
+static void eth_save_packet(volatile void *packet, int length)
+{
+	volatile char *p = packet;
+	int i;
+
+	if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
+		return;
+
+	if (PKTSIZE < length)
+		return;
+
+	for (i = 0; i < length; i++)
+		eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
+
+	eth_rcv_bufs[eth_rcv_last].length = length;
+	eth_rcv_last = (eth_rcv_last+1) % PKTBUFSRX;
+}
+
+int eth_receive(volatile void *packet, int length)
+{
+	volatile char *p = packet;
+	void *pp = push_packet;
+	int i;
+
+	if (eth_rcv_current == eth_rcv_last) {
+		push_packet = eth_save_packet;
+		eth_rx();
+		push_packet = pp;
+
+		if (eth_rcv_current == eth_rcv_last)
+			return -1;
+	}
+
+	if (length < eth_rcv_bufs[eth_rcv_current].length)
+		return -1;
+
+	length = eth_rcv_bufs[eth_rcv_current].length;
+
+	for (i = 0; i < length; i++)
+		p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
+
+	eth_rcv_current = (eth_rcv_current+1) % PKTBUFSRX;
+	return length;
+}
+
 void eth_try_another(int first_restart)
 {
 	static struct eth_device *first_failed = NULL;
net/net.c +6 -0
index e9d7757..ae7c372 100644
@@ -133,6 +133,7 @@ uchar		NetBcastAddr[6] =	/* Ethernet bcast address		*/
 			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 uchar		NetEtherNullAddr[6] =
 			{ 0, 0, 0, 0, 0, 0 };
+void		(*push_packet)(volatile void *, int len) = 0;
 #if defined(CONFIG_CMD_CDP)
 uchar		NetCDPAddr[6] =		/* Ethernet bcast address		*/
 			{ 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
@@ -1157,6 +1158,11 @@ NetReceive(volatile uchar * inpkt, int len)
 	if (len < ETHER_HDR_SIZE)
 		return;
 
+	if (push_packet) {
+		(*push_packet)(inpkt, len);
+		return;
+	}
+
 #if defined(CONFIG_CMD_CDP)
 	/* keep track if packet is CDP */
 	iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
#9 lore raw

cover API for external applications

In reply to Rafal Jaworowski
Quoted 3 lines · Rafal Jaworowski

- devices: only tested networking on real target, storage code considered
complete and exercised with test code, but needs more testing

*snip*

Quoted 5 lines

- devices (enumerate all, open, close, read, write); currently
two classes
of devices are recognized and supported: network and storage
(ide, scsi,
usb etc.)

Rafal,

We can test storage devices at Juniper. We can also test the extensibility of the device handling in the API, because we're going to need to add LCD for front-panel status information :-)

BTW: Great work!

Signature · 2 lines
Marcel Moolenaar
xcllnt at mac.com
#10 lore raw

cover API for external applications

In reply to Rafal Jaworowski
Quoted 4 lines · On Wed, 3 Oct 2007 12:01:28 +0200 Rafal Jaworowski <[email protected]> wrote:

This patchset attempts to implement an API for external applications, where the existing jumptable mechanism is too simplified. We needed a more robust and generic interface to access U-Boot resources for FreeBSD loader and came up with this approach.

Since nobody else has asked yet: Why? Can't you just pass the parameters you need through a boot protocol like everyone else does?

Quoted 2 lines

- API layer comes for the 8.5 KB increase in U-Boot's raw binary footprint

That's pretty large for a layer that doesn't really add any new functionality...

Haavard

#11 lore raw

cover API for external applications

Quoted 10 lines · Haavard Skinnemoen
Quoted 4 lines · On Wed, 3 Oct 2007 12:01:28 +0200 Rafal Jaworowski <[email protected]> wrote:

This patchset attempts to implement an API for external applications, where the existing jumptable mechanism is too simplified. We needed a more robust and generic interface to access U-Boot resources for FreeBSD loader and came up with this approach.

Since nobody else has asked yet: Why? Can't you just pass the parameters you need through a boot protocol like everyone else does?

It's not just passing of parameters. It's an interface to expose services to code ran under U-Boot. Those services include console functionality, networking, etc.

The reason for a separate API is that both the global data structure as well as the jump table are heavily dependent on how U-Boot is configured. This is made worse (from a stable API point of view) by having the jump table at the end of the global data. So, besides principle argument that there's no separation that way, you would also need to "configure" the application in the same way you configure U-Boot in order for that application to use the internals of U-Boot. This is not useful.

A stable API, optionally added to U-Boot, allows any code to run under U-Boot without having that code worry about the detailed differences of the hardware and thus U-Boot and as such provides the same basic functionality a firmware would typically do.

FYI,

Signature · 2 lines
Marcel Moolenaar
xcllnt at mac.com