* Allow crc32 to be used at address 0x000

* Provide consistent interface to standalone applications to access
  the 'global_data' structure
  Provide a doc/README.standalone more useful to users/developers.

* Make IceCube MGT5100 FEC driver work
This commit is contained in:
wdenk 2003-07-26 08:08:08 +00:00
parent 27b207fd0a
commit 7784674852
10 changed files with 237 additions and 188 deletions

View File

@ -2,6 +2,14 @@
Changes for U-Boot 0.4.5:
======================================================================
* Allow crc32 to be used at address 0x000
* Provide consistent interface to standalone applications to access
the 'global_data' structure
Provide a doc/README.standalone more useful to users/developers.
* Make IceCube MGT5100 FEC driver work
* Implement new mechanism to export U-Boot's functions to standalone
applications: instead of using (PPC-specific) system calls we now
use a jump table; please see doc/README.standalone for details

View File

@ -14,7 +14,7 @@
#include "sdma.h"
#include "fec.h"
#define DEBUG 0x8
/* #define DEBUG 0x28 */
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
defined(CONFIG_MPC5XXX_FEC)
@ -28,25 +28,33 @@ static void rfifo_print(mpc5xxx_fec_priv *fec);
static uint32 local_crc32(char *string, unsigned int crc_value, int len);
#endif
typedef struct {
uint8 data[1500]; /* actual data */
int length; /* actual length */
int used; /* buffer in use or not */
uint8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */
} NBUF;
/********************************************************************/
static int mpc5xxx_fec_rbd_init(mpc5xxx_fec_priv *fec)
{
int ix;
char *data;
static int once = 0;
/*
* the receive ring is located right after the transmit one
*/
for (ix = 0; ix < FEC_RBD_NUM; ix++) {
data = (char *)malloc(FEC_MAX_PKT_SIZE);
if (data == NULL) {
printf ("RBD INIT FAILED\n");
return -1;
if (!once) {
data = (char *)malloc(FEC_MAX_PKT_SIZE);
if (data == NULL) {
printf ("RBD INIT FAILED\n");
return -1;
}
fec->rbdBase[ix].dataPointer = (uint32)data;
}
fec->rbdBase[ix].status = FEC_RBD_EMPTY;
fec->rbdBase[ix].dataLength = 0;
fec->rbdBase[ix].dataPointer = (uint32)data;
}
once ++;
/*
* have the last RBD to close the ring
@ -335,11 +343,6 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
*/
SDMA_CLEAR_IEVENT(FEC_RECV_TASK_NO);
/*
* Set SmartDMA intMask register to enable SmartDMA task interrupts
*/
SDMA_INT_ENABLE(FEC_RECV_TASK_NO);
/*
* Initialize SmartDMA parameters stored in SRAM
*/
@ -494,8 +497,10 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
/********************************************************************/
static void mpc5xxx_fec_halt(struct eth_device *dev)
{
mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
#if defined(CONFIG_MPC5200)
struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
#endif
mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
int counter = 0xffff;
#if (DEBUG & 0x2)
@ -530,8 +535,6 @@ static void mpc5xxx_fec_halt(struct eth_device *dev)
*/
while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ;
SDMA_INT_DISABLE (FEC_RECV_TASK_NO);
/*
* Disable SmartDMA tasks
*/
@ -671,7 +674,7 @@ static int mpc5xxx_fec_send(struct eth_device *dev, volatile void *eth_data,
pTbd = &fec->tbdBase[fec->tbdIndex];
pTbd->dataLength = data_length;
pTbd->dataPointer = (uint32)eth_data;
pTbd->status |= FEC_TBD_READY;
pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
#if (DEBUG & 0x100)
@ -729,8 +732,9 @@ static int mpc5xxx_fec_recv(struct eth_device *dev)
mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
unsigned long ievent;
int frame_length;
char *frame;
int frame_length, len = 0;
NBUF *frame;
char buff[FEC_MAX_PKT_SIZE];
#if (DEBUG & 0x1)
printf ("mpc5xxx_fec_recv %d Start...\n", fec->rbdIndex);
@ -763,41 +767,40 @@ static int mpc5xxx_fec_recv(struct eth_device *dev)
}
}
/*
* Do we have data in Rx FIFO?
*/
if ((pRbd->status & FEC_RBD_EMPTY) || !(pRbd->status & FEC_RBD_LAST)){
return 0;
}
if (!(pRbd->status & FEC_RBD_EMPTY)) {
if ((pRbd->status & FEC_RBD_LAST) && !(pRbd->status & FEC_RBD_ERR) &&
((pRbd->dataLength - 4) > 14)) {
/*
* Pass the packet up only if reception was Ok
*/
if ((pRbd->dataLength <= 14) || (pRbd->status & FEC_RBD_ERR)) {
mpc5xxx_fec_rbd_clean(fec, pRbd);
#if (DEBUG & 0x8)
printf( "X0" );
/*
* Get buffer address and size
*/
frame = (NBUF *)pRbd->dataPointer;
frame_length = pRbd->dataLength - 4;
#if (DEBUG & 0x20)
{
int i;
printf("recv data hdr:");
for (i = 0; i < 14; i++)
printf("%x ", *(frame->head + i));
printf("\n");
}
#endif
return 0;
/*
* Fill the buffer and pass it to upper layers
*/
memcpy(buff, frame->head, 14);
memcpy(buff + 14, frame->data, frame_length);
NetReceive(buff, frame_length);
len = frame_length;
}
/*
* Reset buffer descriptor as empty
*/
mpc5xxx_fec_rbd_clean(fec, pRbd);
}
/*
* Get buffer address and size
*/
frame = (char *)pRbd->dataPointer;
frame_length = pRbd->dataLength;
/*
* Pass the buffer to upper layers
*/
NetReceive(frame, frame_length);
/*
* Reset buffer descriptor as empty
*/
mpc5xxx_fec_rbd_clean(fec, pRbd);
return frame_length;
SDMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
return len;
}
@ -824,6 +827,7 @@ int mpc5xxx_fec_initialize(bd_t * bis)
dev->send = mpc5xxx_fec_send;
dev->recv = mpc5xxx_fec_recv;
sprintf(dev->name, "FEC ETHERNET");
eth_register(dev);
return 1;

View File

@ -1,156 +1,96 @@
Design Notes on Exporting U-Boot Functions to Standalone Applications:
======================================================================
1. Add a field to the global_data structure, the pointer to a jump
table.
1. The functions are exported by U-Boot via a jump table. The jump
table is allocated and initialized in the jumptable_init() routine
(common/exports.c). Other routines may also modify the jump table,
however. The jump table can be accessed as the 'jt' field of the
'global_data' structure. The slot numbers for the jump table are
defined in the <include/exports.h> header. E.g., to substitute the
malloc() and free() functions that will be available to standalone
applications, one should do the following:
2. Jump table itself is allocated and filled in the same way as the
syscall table is (allocated with malloc() after the code has been
relocated to RAM); a special function, fixed to the table element
number 0, will be added which returns the ABI version so
applications can check for compatibility issues.
DECLARE_GLOBAL_DATA_PTR;
3. It is application's responsibility to check the ABI version and
act accordingly.
gd->jt[XF_malloc] = my_malloc;
gd->jt[XF_free] = my_free;
4. Pointer to the global_data is passed to the application in the
dedicated register that is used in the U-Boot to hold this
pointer. This assumes that the application is built with the same
register- allocation flags as the U-Boot itself. (Actually, this
is a requirement even now, as the 'go' command does not perform
any actions to protect this register against being clobbered by
the application).
Note that the pointers to the functions all have 'void *' type and
thus the compiler cannot perform type checks on these assignments.
This approach won't work on the x86 architecture. See below.
2. The pointer to the jump table is passed to the application in a
machine-dependent way. PowerPC, ARM and MIPS architectures use a
dedicated register to hold the pointer to the 'global_data'
structure: r29 on PowerPC, r8 on ARM and k0 on MIPS. The x86
architecture does not use such a register; instead, the pointer to
the 'global_data' structure is passed as 'argv[-1]' pointer.
5. Application now calls standard library functions like printf()
instead of specially prefixed names like mon_printf() as it did
before. Present implementation of these functions (using the
system calls mechanism) will be replaced with jump stubs.
The application can access the 'global_data' structure in the same
way as U-Boot does:
6. To export additional functions, the following steps will have to be
taken:
DECLARE_GLOBAL_DATA_PTR;
- Add the xxx() U-Boot function to the EXPORT_FUNC list
- Add initialization of the appropriate slot in the jump table
printf("U-Boot relocation offset: %x\n", gd->reloc_off);
7. To port to a new architecture, the appropriate stub code should be
provided. No other machine-dependent code is used. Once the stub
template is available, no additional coding is needed when
exporting new U-Boot functions. A pre-processor macro will be used
to automatically instantiate the stub definition for each exported
function.
3. The application should call the app_startup() function before any
call to the exported functions. Also, implementor of the
application may want to check the version of the ABI provided by
U-Boot. To facilitate this, a get_version() function is exported
that returns the ABI version of the running U-Boot. I.e., a
typical application startup may look like this:
Note the following:
int my_app (int argc, char *argv[])
{
app_startup (argv);
if (get_version () != XF_VERSION)
return 1;
}
- This approach uses a jump table with fixed slot allocation. That
said, to retain the ABI compatibility, no table reordering,
inserting new functions in the middle of the list or deleting
functions from the list is allowed. Any such action will break the
ABI compatibility.
4. The default load and start addresses of the applications are as
follows:
- The x86 architecture does not use a dedicated register to store the
pointer to the global_data structure. There are the following
approaches available:
Load address Start address
x86 0x00040000 0x00040000
PowerPC 0x00040000 0x00040004
ARM 0x0c100000 0x0c100000
MIPS 0x80200000 0x80200000
* Pass the global_data pointer to the application in a register or
as an additional argument. This requires special machine-
dependent startup code to be compiled into the application.
For example, the "hello world" application may be loaded and
executed on a PowerPC board with the following commands:
* Make the x86 consistent with the rest of architectures and use a
dedicated register. This renders one register unusable in the
rest of the U-Boot code and thus increases the size of the U-Boot
binary and decreases it performance.
The following changes will be made:
- The syscall handling code will be removed.
- The include/_exports.h file will be introduced, containing the list
of the exported functions in the following form:
EXPORT_FUNC(getc)
EXPORT_FUNC(tstc)
...
This list will be used to assign the slot numbers in the jump
table, to determine the size of the jump table and to generate the
code for the stub functions.
- The include/exports.h file will be introduced, containing the
prototypes of the exported functions and the assigned slot numbers.
- The examples/stubs.c file will be introduced, containing the code
for the jump stubs for each of the exported functions.
Implementation Notes on Exporting U-Boot Functions:
===================================================
1. The patch was applied against TOT as of 7/24 12:50 MEST; the
resulting images were tested on the following boards:
* lwmon (PowerPC)
* trab (ARM)
* inca (MIPS)
The hello_world application was loaded and executed then:
[lwmon]
=> tftp 0x40000 /tftpboot/LWMON/hello_world.bin-avn
=> tftp 0x40000 hello_world.bin
=> go 0x40004
[trab]
TRAB # tftp 0xc100000 /tftpboot/TRAB/hello_world.bin-avn
TRAB # go 0xc100000
5. To export some additional function foobar(), the following steps
should be undertaken:
[inca]
INCA-IP # tftp 0x80200000 /tftpboot/INCA/hello_world.bin-avn
INCA-IP # go 0x80200000
- Append the following line at the end of the include/_exports.h
file:
2. As neither of supported x86 boards can be built from the TOT
sources currently, the patch build was verified by manually
running the following command in the U-Boot top directory:
EXPORT_FUNC(foobar)
> make -C examples TOPDIR=`pwd` ARCH=i386 CROSS_COMPILE=
- Add the prototype for this function to the include/exports.h
file:
The rest of the code is mostly machine-independent and was not
verified.
void foobar(void);
3. To test the x86 assembly code, a small standalone application was
written. It was built and run on the RedHat Linux 8.0 (x86). The
application performs a jump using a pointer to jump table and a
function's index in it.
- Add the initialization of the jump table slot wherever
appropriate (most likely, to the jumptable_init() function):
4. For the MIPS architecture, the linker script is also provided for
linking applications. The default linker script places the .text
and .data sections too far from each other so that the resulting
.bin files span about 256Mb in size.
gd->jt[XF_foobar] = foobar;
5. Several example applications required updating for the new API.
These applications relied upon the bd_t pointer being passed as
the 1st argument to the main function; this had changed when the
system calls were introduced, but apparently, these applications
weren't fixed at that moment. This is fixed now.
- Increase the XF_VERSION value by one in the include/exports.h
file
6. GCC issues warnings for the 'sched' application. Since now the
mon_printf() function is renamed to printf(), GCC applies its
knowledge of the format specifiers to check the arguments,
complaining about ints passed as longs and vice versa. This is not
fixed yet.
6. The code for exporting the U-Boot functions to applications is
mostly machine-independent. The only places written in assembly
language are stub functions that perform the jump through the jump
table. That said, to port this code to a new architecture, the
only thing to be provided is the code in the examples/stubs.c
file. If this architecture, however, uses some uncommon method of
passing the 'global_data' pointer (like x86 does), one should add
the respective code to the app_startup() function in that file.
7. Only the hello_world example application was modified to make use
of the newly supplied get_version() function. The application now
prints two ABI versions, the one that the application was compiled
for and the other, actual ABI version.
8. The following new files were added:
common/exports.c
examples/mips.lds
examples/stubs.c
include/_exports.h
include/exports.h
doc/README.standalone
The following files are no longer used and will be removed:
examples/syscall.S
include/syscall.h
Note that these functions may only use call-clobbered registers;
those registers that are used to pass the function's arguments,
the stack contents and the return address should be left intact.

View File

@ -9,6 +9,7 @@
* to the application program.
*/
static void **jt;
gd_t *global_data;
#define EXPORT_FUNC(x) \
asm volatile ( \
@ -80,7 +81,8 @@ void app_startup(char **argv)
{
#if defined(CONFIG_I386)
/* x86 does not have a dedicated register for passing global_data */
jt = ((gd_t *)argv[-1])->jt;
global_data = (gd_t *)argv[-1];
jt = global_data->jt;
#endif
}

87
examples/x86-testapp.c Normal file
View File

@ -0,0 +1,87 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
void *func[8], **pfunc;
typedef struct xxx xxx_t;
struct xxx {
int dummy;
void **pfunc;
} q;
#define XF_strcpy 3
#define XF_printf 4
#define LABEL(x) \
asm volatile ( \
#if defined(__i386__)
#define EXPORT_FUNC(x) \
asm volatile ( \
" .globl mon_" #x "\n" \
"mon_" #x ":\n" \
" movl %0, %%eax\n" \
" movl pfunc, %%ecx\n" \
" jmp *(%%ecx,%%eax)\n" \
: : "i"(XF_ ## x * sizeof(void *)) : "eax", "ecx");
#elif defined(__powerpc__)
#define EXPORT_FUNC(x) \
asm volatile ( \
" .globl mon_" #x "\n" \
"mon_" #x ":\n" \
" lwz %%r11, %0(%%r29)\n" \
" lwz %%r11, %1(%%r11)\n" \
" mtctr %%r11\n" \
" bctr\n" \
: : "i"(offsetof(xxx_t, pfunc)), "i"(XF_ ## x * sizeof(void *)) : "r11", "r29");
#elif defined(__arm__)
#define EXPORT_FUNC(x) \
asm volatile ( \
" .globl mon_" #x "\n" \
"mon_" #x ":\n" \
" ldr ip, [r8, %0]\n" \
" ldr pc, [ip, %1]\n" \
: : "i"(offsetof(xxx_t, pfunc)), "i"(XF_ ## x * sizeof(void *)) : "ip");
#elif defined(__mips__)
#define EXPORT_FUNC(x) \
asm volatile ( \
" .globl mon_" #x "\n" \
"mon_" #x ":\n" \
" lw $25, %0($26)\n" \
" lw $25, %1($25)\n" \
" jr $25\n" \
: : "i"(offsetof(xxx_t, pfunc)), "i"(XF_ ## x * sizeof(void *)) : "t9");
#else
#error [No stub code for this arch]
#endif
void dummy(void)
{
EXPORT_FUNC(printf)
EXPORT_FUNC(strcpy)
}
int main(void)
{
#if defined(__i386__)
xxx_t *pq;
#elif defined(__powerpc__)
register volatile xxx_t *pq asm("r29");
#elif defined(__arm__)
register volatile xxx_t *pq asm("r8");
#elif defined(__mips__)
register volatile xxx_t *pq asm("k0");
#endif
char buf[32];
func[XF_strcpy] = strcpy;
func[XF_printf] = printf;
pq = &q;
pq->pfunc = pfunc = func;
mon_strcpy(buf, "test");
mon_printf("hi %s %d z\n", buf, 444);
return 0;
}

View File

@ -52,7 +52,7 @@
/*
* Supported commands
*/
#define CONFIG_COMMANDS (CONFIG_CMD_DFL & ~(CFG_CMD_NET))
#define CONFIG_COMMANDS CONFIG_CMD_DFL
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
@ -122,10 +122,7 @@
/*
* Ethernet configuration
*/
#if 0
#define CONFIG_NET_MULTI 1
#define CONFIG_MPC5XXX_FEC 1
#endif
/*
* GPIO configuration

View File

@ -33,4 +33,8 @@ enum {
#define XF_VERSION 1
#if defined(CONFIG_I386)
extern gd_t *global_data;
#endif
#endif

View File

@ -21,6 +21,14 @@
# endif
#endif /* CONFIG_8xx */
#if defined(CONFIG_MPC5XXX)
# if !defined(CONFIG_NET_MULTI)
# if defined(CONFIG_MPC5XXX_FEC)
# define CONFIG_NET_MULTI
# endif
# endif
#endif /* CONFIG_MPC5XXX */
#if !defined(CONFIG_NET_MULTI) && defined(CONFIG_8260)
#include <config.h>
#if defined(CONFIG_ETHER_ON_FCC)

View File

@ -231,7 +231,7 @@ void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
setup_ramdisk_tag(bd);
#endif
#if defined (CONFIG_VFD)
setup_videolfb_tag(gd);
setup_videolfb_tag((gd_t *)gd);
#endif
setup_end_tag(bd);
#endif

View File

@ -155,7 +155,6 @@ uLong ZEXPORT crc32(crc, buf, len)
const Bytef *buf;
uInt len;
{
if (buf == Z_NULL) return 0L;
#ifdef DYNAMIC_CRC_TABLE
if (crc_table_empty)
make_crc_table();