applications: instead of using (PPC-specific) system calls we now use a jump table; please see doc/README.standalone for details * Patch by Dave Westwood, 24 Jul 2003: added support for Unity OS (a proprietary OS)master
parent
2535d60277
commit
27b207fd0a
@ -0,0 +1,31 @@ |
||||
#include <common.h> |
||||
#include <exports.h> |
||||
|
||||
static void dummy(void) |
||||
{ |
||||
} |
||||
|
||||
unsigned long get_version(void) |
||||
{ |
||||
return XF_VERSION; |
||||
} |
||||
|
||||
void jumptable_init (void) |
||||
{ |
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
int i; |
||||
|
||||
gd->jt = (void **) malloc (XF_MAX * sizeof (void *)); |
||||
for (i = 0; i < XF_MAX; i++) |
||||
gd->jt[i] = (void *) dummy; |
||||
|
||||
gd->jt[XF_get_version] = (void *) get_version; |
||||
gd->jt[XF_malloc] = (void *) malloc; |
||||
gd->jt[XF_free] = (void *) free; |
||||
gd->jt[XF_get_timer] = (void *)get_timer; |
||||
gd->jt[XF_udelay] = (void *)udelay; |
||||
#if defined(CONFIG_I386) || defined(CONFIG_PPC) |
||||
gd->jt[XF_install_hdlr] = (void *) irq_install_handler; |
||||
gd->jt[XF_free_hdlr] = (void *) irq_free_handler; |
||||
#endif |
||||
} |
@ -0,0 +1,156 @@ |
||||
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: |
||||
|
||||
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 |
||||
=> go 0x40004 |
||||
|
||||
[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 |
@ -0,0 +1,56 @@ |
||||
/* |
||||
* (C) Copyright 2003 |
||||
* Wolfgang Denk Engineering, <wd@denx.de> |
||||
* |
||||
* 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 |
||||
*/ |
||||
|
||||
/* |
||||
OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips") |
||||
*/ |
||||
OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips") |
||||
OUTPUT_ARCH(mips) |
||||
SECTIONS |
||||
{ |
||||
.text : |
||||
{ |
||||
*(.text) |
||||
} |
||||
|
||||
. = ALIGN(4); |
||||
.rodata : { *(.rodata) } |
||||
|
||||
. = ALIGN(4); |
||||
.data : { *(.data) } |
||||
|
||||
. = ALIGN(4); |
||||
.sdata : { *(.sdata) } |
||||
|
||||
_gp = ALIGN(16); |
||||
|
||||
__got_start = .; |
||||
.got : { *(.got) } |
||||
__got_end = .; |
||||
|
||||
.sdata : { *(.sdata) } |
||||
|
||||
. = ALIGN(4); |
||||
.sbss : { *(.sbss) } |
||||
.bss : { *(.bss) } |
||||
} |
@ -0,0 +1,87 @@ |
||||
#include <exports.h> |
||||
|
||||
#if defined(CONFIG_I386) |
||||
/*
|
||||
* x86 does not have a dedicated register to store the pointer to |
||||
* the global_data. Thus the jump table address is stored in a |
||||
* global variable, but such approach does not allow for execution |
||||
* from flash memory. The global_data address is passed as argv[-1] |
||||
* to the application program. |
||||
*/ |
||||
static void **jt; |
||||
|
||||
#define EXPORT_FUNC(x) \ |
||||
asm volatile ( \
|
||||
" .globl " #x "\n" \
|
||||
#x ":\n" \ |
||||
" movl %0, %%eax\n" \
|
||||
" movl jt, %%ecx\n" \
|
||||
" jmp *(%%ecx, %%eax)\n" \
|
||||
: : "i"(XF_ ## x * sizeof(void *)) : "eax", "ecx"); |
||||
#elif defined(CONFIG_PPC) |
||||
/*
|
||||
* r29 holds the pointer to the global_data, r11 is a call-clobbered |
||||
* register |
||||
*/ |
||||
#define EXPORT_FUNC(x) \ |
||||
asm volatile ( \
|
||||
" .globl " #x "\n" \
|
||||
#x ":\n" \ |
||||
" lwz %%r11, %0(%%r29)\n" \
|
||||
" lwz %%r11, %1(%%r11)\n" \
|
||||
" mtctr %%r11\n" \
|
||||
" bctr\n" \
|
||||
: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r11"); |
||||
#elif defined(CONFIG_ARM) |
||||
/*
|
||||
* r8 holds the pointer to the global_data, ip is a call-clobbered |
||||
* register |
||||
*/ |
||||
#define EXPORT_FUNC(x) \ |
||||
asm volatile ( \
|
||||
" .globl " #x "\n" \
|
||||
#x ":\n" \ |
||||
" ldr ip, [r8, %0]\n" \
|
||||
" ldr pc, [ip, %1]\n" \
|
||||
: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "ip"); |
||||
#elif defined(CONFIG_MIPS) |
||||
/*
|
||||
* k0 ($26) holds the pointer to the global_data; t9 ($25) is a call- |
||||
* clobbered register that is also used to set gp ($26). Note that the |
||||
* jr instruction also executes the instruction immediately following |
||||
* it; however, GCC/mips generates an additional `nop' after each asm |
||||
* statement |
||||
*/ |
||||
#define EXPORT_FUNC(x) \ |
||||
asm volatile ( \
|
||||
" .globl " #x "\n" \
|
||||
#x ":\n" \ |
||||
" lw $25, %0($26)\n" \
|
||||
" lw $25, %1($25)\n" \
|
||||
" jr $25\n" \
|
||||
: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "t9"); |
||||
#else |
||||
#error stubs definition missing for this architecture |
||||
#endif |
||||
|
||||
/* This function is necessary to prevent the compiler from
|
||||
* generating prologue/epilogue, preparing stack frame etc. |
||||
* The stub functions are special, they do not use the stack |
||||
* frame passed to them, but pass it intact to the actual |
||||
* implementation. On the other hand, asm() statements with |
||||
* arguments can be used only inside the functions (gcc limitation) |
||||
*/ |
||||
static void __attribute__((unused)) dummy(void) |
||||
{ |
||||
#include <_exports.h> |
||||
} |
||||
|
||||
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; |
||||
#endif |
||||
} |
||||
|
||||
#undef EXPORT_FUNC |
@ -1,114 +0,0 @@ |
||||
#include <ppc_asm.tmpl> |
||||
#include <ppc_defs.h> |
||||
#include <syscall.h> |
||||
|
||||
#ifdef CONFIG_ARM /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ |
||||
#warning ARM version not implemented yet /* XXXXXXXXXXXXXXXXXXXXXXXXXXXX */ |
||||
.global mon_getc
|
||||
.type mon_getc,function |
||||
mon_getc: |
||||
.global mon_tstc
|
||||
.type mon_tstc,function |
||||
mon_tstc: |
||||
.global mon_putc
|
||||
.type mon_putc,function |
||||
mon_putc: |
||||
.global mon_puts
|
||||
.type mon_puts,function |
||||
mon_puts: |
||||
.global mon_printf
|
||||
.type mon_printf,function |
||||
mon_printf: |
||||
.global mon_install_hdlr
|
||||
.type mon_install_hdlr,function |
||||
mon_install_hdlr: |
||||
.global mon_free_hdlr
|
||||
.type mon_free_hdlr,function |
||||
mon_free_hdlr: |
||||
.global mon_malloc
|
||||
.type mon_malloc,function |
||||
mon_malloc: |
||||
.global mon_free
|
||||
.type mon_free,function |
||||
mon_free: |
||||
@ args = 0, pretend = 0, frame = 0
|
||||
@ frame_needed = 1, current_function_anonymous_args = 0
|
||||
mov ip, sp |
||||
stmfd sp!, {fp, ip, lr, pc} |
||||
sub fp, ip, #4 |
||||
ldmea fp, {fp, sp, pc} |
||||
#elif defined(CONFIG_MIPS)/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ |
||||
#warning MIPS version not implemented yet |
||||
.global mon_getc
|
||||
.type mon_getc,function |
||||
mon_getc: |
||||
.global mon_tstc
|
||||
.type mon_tstc,function |
||||
mon_tstc: |
||||
.global mon_putc
|
||||
.type mon_putc,function |
||||
mon_putc: |
||||
.global mon_puts
|
||||
.type mon_puts,function |
||||
mon_puts: |
||||
.global mon_printf
|
||||
.type mon_printf,function |
||||
mon_printf: |
||||
.global mon_install_hdlr
|
||||
.type mon_install_hdlr,function |
||||
mon_install_hdlr: |
||||
.global mon_free_hdlr
|
||||
.type mon_free_hdlr,function |
||||
mon_free_hdlr: |
||||
.global mon_malloc
|
||||
.type mon_malloc,function |
||||
mon_malloc: |
||||
.global mon_free
|
||||
.type mon_free,function |
||||
mon_free: |
||||
|
||||
#else |
||||
|
||||
#ifdef CONFIG_I386 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ |
||||
#define SYMBOL_NAME(X) X |
||||
#define SYMBOL_NAME_LABEL(X) X##: |
||||
|
||||
#define SYSCALL(name,n) \ |
||||
.globl SYMBOL_NAME(name) ; \
|
||||
SYMBOL_NAME_LABEL(name) ; \
|
||||
movl $n, %eax ;\
|
||||
pushl %ebx; \
|
||||
pushl %ecx; \
|
||||
int $0x40 ;\
|
||||
|
||||
|
||||
#endif /* CONFIG_I386 */ |
||||
|
||||
#ifdef CONFIG_PPC |
||||
#define SYSCALL(name,n) \ |
||||
.globl name ; \
|
||||
name: ; \
|
||||
li r0,n ; \
|
||||
sc ; \
|
||||
blr |
||||
#endif /* CONFIG_PPC */ |
||||
|
||||
.text |
||||
|
||||
/* |
||||
* Make sure these functions are in the same order as they |
||||
* appear in the "include/syscall.h" header file !!! |
||||
*/ |
||||
|
||||
SYSCALL(mon_getc,SYSCALL_GETC) |
||||
SYSCALL(mon_tstc,SYSCALL_TSTC) |
||||
SYSCALL(mon_putc,SYSCALL_PUTC) |
||||
SYSCALL(mon_puts,SYSCALL_PUTS) |
||||
SYSCALL(mon_printf,SYSCALL_PRINTF) |
||||
SYSCALL(mon_install_hdlr,SYSCALL_INSTALL_HDLR) |
||||
SYSCALL(mon_free_hdlr,SYSCALL_FREE_HDLR) |
||||
SYSCALL(mon_malloc,SYSCALL_MALLOC) |
||||
SYSCALL(mon_free,SYSCALL_FREE) |
||||
SYSCALL(mon_udelay,SYSCALL_UDELAY) |
||||
SYSCALL(mon_get_timer,SYSCALL_GET_TIMER) |
||||
#endif /* CONFIG_ARM XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ |
@ -0,0 +1,12 @@ |
||||
EXPORT_FUNC(get_version) |
||||
EXPORT_FUNC(getc) |
||||
EXPORT_FUNC(tstc) |
||||
EXPORT_FUNC(putc) |
||||
EXPORT_FUNC(puts) |
||||
EXPORT_FUNC(printf) |
||||
EXPORT_FUNC(install_hdlr) |
||||
EXPORT_FUNC(free_hdlr) |
||||
EXPORT_FUNC(malloc) |
||||
EXPORT_FUNC(free) |
||||
EXPORT_FUNC(udelay) |
||||
EXPORT_FUNC(get_timer) |
@ -0,0 +1,36 @@ |
||||
#ifndef __MON_SYS_CALL_H__ |
||||
#define __MON_SYS_CALL_H__ |
||||
|
||||
#ifndef __ASSEMBLY__ |
||||
|
||||
#include <common.h> |
||||
|
||||
/* These are declarations of exported functions available in C code */ |
||||
unsigned long get_version(void); |
||||
int getc(void); |
||||
int tstc(void); |
||||
void putc(const char); |
||||
void puts(const char*); |
||||
void printf(const char* fmt, ...); |
||||
void install_hdlr(int, interrupt_handler_t*, void*); |
||||
void free_hdlr(int); |
||||
void *malloc(size_t); |
||||
void free(void*); |
||||
void udelay(unsigned long); |
||||
unsigned long get_timer(unsigned long); |
||||
|
||||
void app_startup(char **); |
||||
|
||||
#endif /* ifndef __ASSEMBLY__ */ |
||||
|
||||
enum { |
||||
#define EXPORT_FUNC(x) XF_ ## x , |
||||
#include <_exports.h> |
||||
#undef EXPORT_FUNC |
||||
|
||||
XF_MAX |
||||
}; |
||||
|
||||
#define XF_VERSION 1 |
||||
|
||||
#endif |
@ -1,42 +0,0 @@ |
||||
#ifndef __MON_SYS_CALL_H__ |
||||
#define __MON_SYS_CALL_H__ |
||||
|
||||
#ifndef __ASSEMBLY__ |
||||
|
||||
#include <common.h> |
||||
|
||||
/* These are declarations of system calls available in C code */ |
||||
int mon_getc(void); |
||||
int mon_tstc(void); |
||||
void mon_putc(const char); |
||||
void mon_puts(const char*); |
||||
void mon_printf(const char* fmt, ...); |
||||
void mon_install_hdlr(int, interrupt_handler_t*, void*); |
||||
void mon_free_hdlr(int); |
||||
void *mon_malloc(size_t); |
||||
void mon_free(void*); |
||||
void mon_udelay(unsigned long); |
||||
unsigned long mon_get_timer(unsigned long); |
||||
|
||||
#endif /* ifndef __ASSEMBLY__ */ |
||||
|
||||
#define NR_SYSCALLS 11 /* number of syscalls */ |
||||
|
||||
|
||||
/*
|
||||
* Make sure these functions are in the same order as they |
||||
* appear in the "examples/syscall.S" file !!! |
||||
*/ |
||||
#define SYSCALL_GETC 0 |
||||
#define SYSCALL_TSTC 1 |
||||
#define SYSCALL_PUTC 2 |
||||
#define SYSCALL_PUTS 3 |
||||
#define SYSCALL_PRINTF 4 |
||||
#define SYSCALL_INSTALL_HDLR 5 |
||||
#define SYSCALL_FREE_HDLR 6 |
||||
#define SYSCALL_MALLOC 7 |
||||
#define SYSCALL_FREE 8 |
||||
#define SYSCALL_UDELAY 9 |
||||
#define SYSCALL_GET_TIMER 10 |
||||
|
||||
#endif |
Loading…
Reference in new issue