* 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 workmaster
parent
27b207fd0a
commit
7784674852
@ -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. |
||||
|
||||
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. |
||||
|
||||
3. It is application's responsibility to check the ABI version and |
||||
act accordingly. |
||||
|
||||
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). |
||||
|
||||
This approach won't work on the x86 architecture. See below. |
||||
|
||||
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. |
||||
|
||||
6. To export additional functions, the following steps will have to be |
||||
taken: |
||||
|
||||
- Add the xxx() U-Boot function to the EXPORT_FUNC list |
||||
- Add initialization of the appropriate slot in the jump table |
||||
|
||||
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. |
||||
|
||||
Note the following: |
||||
|
||||
- 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. |
||||
|
||||
- The x86 architecture does not use a dedicated register to store the |
||||
pointer to the global_data structure. There are the following |
||||
approaches available: |
||||
|
||||
* 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. |
||||
|
||||
* 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: |
||||
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: |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
gd->jt[XF_malloc] = my_malloc; |
||||
gd->jt[XF_free] = my_free; |
||||
|
||||
Note that the pointers to the functions all have 'void *' type and |
||||
thus the compiler cannot perform type checks on these assignments. |
||||
|
||||
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. |
||||
|
||||
The application can access the 'global_data' structure in the same |
||||
way as U-Boot does: |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
printf("U-Boot relocation offset: %x\n", gd->reloc_off); |
||||
|
||||
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: |
||||
|
||||
int my_app (int argc, char *argv[]) |
||||
{ |
||||
app_startup (argv); |
||||
if (get_version () != XF_VERSION) |
||||
return 1; |
||||
} |
||||
|
||||
4. The default load and start addresses of the applications are as |
||||
follows: |
||||
|
||||
Load address Start address |
||||
x86 0x00040000 0x00040000 |
||||
PowerPC 0x00040000 0x00040004 |
||||
ARM 0x0c100000 0x0c100000 |
||||
MIPS 0x80200000 0x80200000 |
||||
|
||||
For example, the "hello world" application may be loaded and |
||||
executed on a PowerPC board with the following commands: |
||||
|
||||
=> tftp 0x40000 hello_world.bin |
||||
=> go 0x40004 |
||||
|
||||
EXPORT_FUNC(getc) |
||||
EXPORT_FUNC(tstc) |
||||
... |
||||
5. To export some additional function foobar(), the following steps |
||||
should be undertaken: |
||||
|
||||
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. |
||||
- Append the following line at the end of the include/_exports.h |
||||
file: |
||||
|
||||
- The include/exports.h file will be introduced, containing the |
||||
prototypes of the exported functions and the assigned slot numbers. |
||||
EXPORT_FUNC(foobar) |
||||
|
||||
- The examples/stubs.c file will be introduced, containing the code |
||||
for the jump stubs for each of the exported functions. |
||||
- Add the prototype for this function to the include/exports.h |
||||
file: |
||||
|
||||
Implementation Notes on Exporting U-Boot Functions: |
||||
=================================================== |
||||
void foobar(void); |
||||
|
||||
1. The patch was applied against TOT as of 7/24 12:50 MEST; the |
||||
resulting images were tested on the following boards: |
||||
- Add the initialization of the jump table slot wherever |
||||
appropriate (most likely, to the jumptable_init() function): |
||||
|
||||
* lwmon (PowerPC) |
||||
* trab (ARM) |
||||
* inca (MIPS) |
||||
gd->jt[XF_foobar] = foobar; |
||||
|
||||
The hello_world application was loaded and executed then: |
||||
- Increase the XF_VERSION value by one in the include/exports.h |
||||
file |
||||
|
||||
[lwmon] |
||||
=> tftp 0x40000 /tftpboot/LWMON/hello_world.bin-avn |
||||
=> go 0x40004 |
||||
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. |
||||
|
||||
[trab] |
||||
TRAB # tftp 0xc100000 /tftpboot/TRAB/hello_world.bin-avn |
||||
TRAB # go 0xc100000 |
||||
|
||||
[inca] |
||||
INCA-IP # tftp 0x80200000 /tftpboot/INCA/hello_world.bin-avn |
||||
INCA-IP # go 0x80200000 |
||||
|
||||
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: |
||||
|
||||
> make -C examples TOPDIR=`pwd` ARCH=i386 CROSS_COMPILE= |
||||
|
||||
The rest of the code is mostly machine-independent and was not |
||||
verified. |
||||
|
||||
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. |
||||
|
||||
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. |
||||
|
||||
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. |
||||
|
||||
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. |
||||
|
||||
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. |
||||
|
@ -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; |
||||
} |
Loading…
Reference in new issue