forked from Imagelibrary/rtems
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e91901303 | ||
|
|
09cbe713ff | ||
|
|
d2e31f70c1 | ||
|
|
d51538bdbe | ||
|
|
89164c67bc | ||
|
|
4c4869f483 | ||
|
|
7011f26061 | ||
|
|
49eb6061ec | ||
|
|
5ed41a6d82 | ||
|
|
58e8131184 | ||
|
|
565b1a57b7 | ||
|
|
ad3a744ac4 | ||
|
|
201f3797b3 | ||
|
|
c38f1fcf8f | ||
|
|
21d7154b07 | ||
|
|
f08c71339c | ||
|
|
2ea436a167 | ||
|
|
a27128c5dc | ||
|
|
0e8d205559 | ||
|
|
35a3d81581 | ||
|
|
17f81ee3cb | ||
|
|
6ec60de37d | ||
|
|
7e0a02a70f | ||
|
|
5b5ef4e479 | ||
|
|
04684cbc43 | ||
|
|
69ae534cbb | ||
|
|
af9143fba5 | ||
|
|
d46a65d052 |
@@ -14,7 +14,7 @@ EXTRA_DIST += config-ml.in
|
|||||||
EXTRA_DIST += ampolish3
|
EXTRA_DIST += ampolish3
|
||||||
|
|
||||||
dist-hook:
|
dist-hook:
|
||||||
@files=`(cd $(srcdir); find doc cpukit c testsuites tools \
|
@files=`(cd $(srcdir); find cpukit c testsuites tools \
|
||||||
-name configure.ac -print | sed 's,/configure.ac,,' | sort)`; \
|
-name configure.ac -print | sed 's,/configure.ac,,' | sort)`; \
|
||||||
for i in $$files; do \
|
for i in $$files; do \
|
||||||
if test -f $(distdir)/$$i/configure.ac; then : ; \
|
if test -f $(distdir)/$$i/configure.ac; then : ; \
|
||||||
|
|||||||
@@ -54,15 +54,6 @@ rtems-$(rtems_version)/stamp.export.$(rtems_tag)$(TAG_SUFFIX):
|
|||||||
rtems-$(rtems_version)$(TAG_SUFFIX).tar.bz2: rtems-$(rtems_version)/stamp.autofiles \
|
rtems-$(rtems_version)$(TAG_SUFFIX).tar.bz2: rtems-$(rtems_version)/stamp.autofiles \
|
||||||
rtems-$(rtems_version)/excludes \
|
rtems-$(rtems_version)/excludes \
|
||||||
rtems-$(rtems_version)/TOOL_VERSIONS
|
rtems-$(rtems_version)/TOOL_VERSIONS
|
||||||
cd rtems-$(rtems_version) ; \
|
|
||||||
touch doc/ada_user/ada_user.texi doc/bsp_howto/bsp_howto.texi \
|
|
||||||
doc/cpu_supplement/cpu_supplement.texi \
|
|
||||||
doc/develenv/develenv.texi doc/filesystem/filesystem.texi \
|
|
||||||
doc/networking/networking.texi \
|
|
||||||
doc/new_chapters/new_chapters.texi \
|
|
||||||
doc/porting/porting.texi doc/posix1003.1/posix1003_1.texi \
|
|
||||||
doc/posix_users/posix_users.texi doc/relnotes/relnotes.texi \
|
|
||||||
doc/started/started.texi doc/user/c_user.texi
|
|
||||||
tar -cj -X rtems-$(rtems_version)/excludes \
|
tar -cj -X rtems-$(rtems_version)/excludes \
|
||||||
-f rtems-$(rtems_version)$(TAG_SUFFIX).tar.bz2 rtems-$(rtems_version)
|
-f rtems-$(rtems_version)$(TAG_SUFFIX).tar.bz2 rtems-$(rtems_version)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
AC_DEFUN([RTEMS_VERSIONING],
|
AC_DEFUN([RTEMS_VERSIONING],
|
||||||
m4_define([_RTEMS_VERSION],[4.10.99.0]))
|
m4_define([_RTEMS_VERSION],[4.11.1.99]))
|
||||||
|
|
||||||
m4_define([_RTEMS_API],[4.11])
|
m4_define([_RTEMS_API],[4.11])
|
||||||
|
|||||||
@@ -223,7 +223,6 @@ clean)
|
|||||||
needles="$needles install-sh"
|
needles="$needles install-sh"
|
||||||
needles="$needles missing"
|
needles="$needles missing"
|
||||||
needles="$needles mdate-sh"
|
needles="$needles mdate-sh"
|
||||||
needles="$needles texinfo.tex"
|
|
||||||
fi
|
fi
|
||||||
for j in $needles; do
|
for j in $needles; do
|
||||||
files=`find . -name "$j" -print`
|
files=`find . -name "$j" -print`
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
AC_DEFUN([RTEMS_VERSIONING],
|
AC_DEFUN([RTEMS_VERSIONING],
|
||||||
m4_define([_RTEMS_VERSION],[4.10.99.0]))
|
m4_define([_RTEMS_VERSION],[4.11.1.99]))
|
||||||
|
|
||||||
m4_define([_RTEMS_API],[4.11])
|
m4_define([_RTEMS_API],[4.11])
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ extern "C" {
|
|||||||
#define GIC_ID_TO_ONE_BIT_REG_BIT(id) (1U << ((id) & 0x1fU))
|
#define GIC_ID_TO_ONE_BIT_REG_BIT(id) (1U << ((id) & 0x1fU))
|
||||||
|
|
||||||
#define GIC_ID_TO_TWO_BITS_REG_INDEX(id) ((id) >> 4)
|
#define GIC_ID_TO_TWO_BITS_REG_INDEX(id) ((id) >> 4)
|
||||||
#define GIC_ID_TO_TWO_BITS_REG_OFFSET(id) ((id) & 0xfU)
|
#define GIC_ID_TO_TWO_BITS_REG_OFFSET(id) (((id) & 0xfU) << 1)
|
||||||
|
|
||||||
static inline bool gic_id_is_enabled(volatile gic_dist *dist, uint32_t id)
|
static inline bool gic_id_is_enabled(volatile gic_dist *dist, uint32_t id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ static void greth_interrupt (void *arg)
|
|||||||
|
|
||||||
/* Send the event(s) */
|
/* Send the event(s) */
|
||||||
if ( events )
|
if ( events )
|
||||||
rtems_event_send (greth->daemonTid, events);
|
rtems_bsdnet_event_send(greth->daemonTid, events);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t read_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr)
|
static uint32_t read_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr)
|
||||||
|
|||||||
@@ -30,10 +30,6 @@ RTEMS_ENABLE_MULTILIB
|
|||||||
RTEMS_ENABLE_PARAVIRT
|
RTEMS_ENABLE_PARAVIRT
|
||||||
RTEMS_ENABLE_DRVMGR
|
RTEMS_ENABLE_DRVMGR
|
||||||
|
|
||||||
AC_ARG_ENABLE([docs],
|
|
||||||
[AS_HELP_STRING([--enable-docs],[enable building documentation
|
|
||||||
(default:disabled)])])
|
|
||||||
|
|
||||||
## NOTES:
|
## NOTES:
|
||||||
## * tools/build are host-native tools to be installed on the host.
|
## * tools/build are host-native tools to be installed on the host.
|
||||||
## * tools/cpu are host-native or host-cross-target-tools
|
## * tools/cpu are host-native or host-cross-target-tools
|
||||||
@@ -52,9 +48,6 @@ AS_IF([test $host != $build],[
|
|||||||
RTEMS_HOST_CONFIG_SUBDIRS([tools/build])
|
RTEMS_HOST_CONFIG_SUBDIRS([tools/build])
|
||||||
])
|
])
|
||||||
|
|
||||||
AS_IF([test x"${enable_docs}" = x"yes"],
|
|
||||||
[RTEMS_BUILD_CONFIG_SUBDIRS([doc])])
|
|
||||||
|
|
||||||
AS_IF([test x"$enable_multilib" = x"yes"],[
|
AS_IF([test x"$enable_multilib" = x"yes"],[
|
||||||
RTEMS_TARGET_CONFIG_SUBDIRS([cpukit])
|
RTEMS_TARGET_CONFIG_SUBDIRS([cpukit])
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ include_rtems_rtl_HEADERS += libdl/dlfcn-shell.h
|
|||||||
include_rtems_rtl_HEADERS += libdl/rtl.h libdl/rtl-allocator.h libdl/rtl-obj-fwd.h
|
include_rtems_rtl_HEADERS += libdl/rtl.h libdl/rtl-allocator.h libdl/rtl-obj-fwd.h
|
||||||
include_rtems_rtl_HEADERS += libdl/rtl-fwd.h libdl/rtl-obj.h libdl/rtl-obj-cache.h
|
include_rtems_rtl_HEADERS += libdl/rtl-fwd.h libdl/rtl-obj.h libdl/rtl-obj-cache.h
|
||||||
include_rtems_rtl_HEADERS += libdl/rtl-obj-comp.h libdl/rtl-unresolved.h
|
include_rtems_rtl_HEADERS += libdl/rtl-obj-comp.h libdl/rtl-unresolved.h
|
||||||
include_rtems_rtl_HEADERS += libdl/rtl-indirect-ptr.h libdl/rtl-sym.h
|
include_rtems_rtl_HEADERS += libdl/rtl-indirect-ptr.h libdl/rtl-sym.h libdl/rtl-trace.h
|
||||||
include_rtems_rtl_HEADERS += libdl/rap.h libdl/rap-shell.h
|
include_rtems_rtl_HEADERS += libdl/rap.h libdl/rap-shell.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
AC_DEFUN([RTEMS_VERSIONING],
|
AC_DEFUN([RTEMS_VERSIONING],
|
||||||
m4_define([_RTEMS_VERSION],[4.10.99.0]))
|
m4_define([_RTEMS_VERSION],[4.11.1.99]))
|
||||||
|
|
||||||
m4_define([_RTEMS_API],[4.11])
|
m4_define([_RTEMS_API],[4.11])
|
||||||
|
|||||||
@@ -507,11 +507,14 @@ rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain(
|
|||||||
* deferred. The next obtain call will do the actual release.
|
* deferred. The next obtain call will do the actual release.
|
||||||
*
|
*
|
||||||
* @param[in] global_loc The global file system location. It must not be NULL.
|
* @param[in] global_loc The global file system location. It must not be NULL.
|
||||||
|
* @param[in] deferred If true, then do a deferred release, otherwise release
|
||||||
|
* it immediately.
|
||||||
*
|
*
|
||||||
* @see rtems_filesystem_global_location_obtain().
|
* @see rtems_filesystem_global_location_obtain().
|
||||||
*/
|
*/
|
||||||
void rtems_filesystem_global_location_release(
|
void rtems_filesystem_global_location_release(
|
||||||
rtems_filesystem_global_location_t *global_loc
|
rtems_filesystem_global_location_t *global_loc,
|
||||||
|
bool deferred
|
||||||
);
|
);
|
||||||
|
|
||||||
void rtems_filesystem_location_detach(
|
void rtems_filesystem_location_detach(
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ int rtems_filesystem_chdir( rtems_filesystem_location_info_t *loc )
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
rtems_filesystem_location_error( &global_loc->location, ENOTDIR );
|
rtems_filesystem_location_error( &global_loc->location, ENOTDIR );
|
||||||
rtems_filesystem_global_location_release( global_loc );
|
rtems_filesystem_global_location_release( global_loc, true );
|
||||||
rv = -1;
|
rv = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ int chroot( const char *path )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( rv != 0 ) {
|
if ( rv != 0 ) {
|
||||||
rtems_filesystem_global_location_release( new_root_loc );
|
rtems_filesystem_global_location_release( new_root_loc, true );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rv = -1;
|
rv = -1;
|
||||||
@@ -89,7 +89,7 @@ int chroot( const char *path )
|
|||||||
rtems_filesystem_eval_path_cleanup( &ctx );
|
rtems_filesystem_eval_path_cleanup( &ctx );
|
||||||
|
|
||||||
if ( rv != 0 ) {
|
if ( rv != 0 ) {
|
||||||
rtems_filesystem_global_location_release( new_current_loc );
|
rtems_filesystem_global_location_release( new_current_loc, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ static int register_subordinate_file_system(
|
|||||||
);
|
);
|
||||||
rtems_filesystem_mt_unlock();
|
rtems_filesystem_mt_unlock();
|
||||||
} else {
|
} else {
|
||||||
rtems_filesystem_global_location_release( mt_point_node );
|
rtems_filesystem_global_location_release( mt_point_node, true );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rtems_filesystem_eval_path_error( &ctx, EBUSY );
|
rtems_filesystem_eval_path_error( &ctx, EBUSY );
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ void rtems_libio_free_user_env(void *arg)
|
|||||||
bool uses_global_env = env == &rtems_global_user_env;
|
bool uses_global_env = env == &rtems_global_user_env;
|
||||||
|
|
||||||
if (!uses_global_env) {
|
if (!uses_global_env) {
|
||||||
rtems_filesystem_global_location_release(env->current_directory);
|
rtems_filesystem_global_location_release(env->current_directory, false);
|
||||||
rtems_filesystem_global_location_release(env->root_directory);
|
rtems_filesystem_global_location_release(env->root_directory, false);
|
||||||
free(env);
|
free(env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,8 +301,8 @@ void rtems_filesystem_eval_path_cleanup(
|
|||||||
{
|
{
|
||||||
free_location(&ctx->currentloc);
|
free_location(&ctx->currentloc);
|
||||||
rtems_filesystem_instance_unlock(&ctx->startloc->location);
|
rtems_filesystem_instance_unlock(&ctx->startloc->location);
|
||||||
rtems_filesystem_global_location_release(ctx->startloc);
|
rtems_filesystem_global_location_release(ctx->startloc, false);
|
||||||
rtems_filesystem_global_location_release(ctx->rootloc);
|
rtems_filesystem_global_location_release(ctx->rootloc, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtems_filesystem_eval_path_cleanup_with_parent(
|
void rtems_filesystem_eval_path_cleanup_with_parent(
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ void rtems_filesystem_global_location_assign(
|
|||||||
*lhs_global_loc_ptr = rhs_global_loc;
|
*lhs_global_loc_ptr = rhs_global_loc;
|
||||||
rtems_filesystem_mt_entry_unlock(lock_context);
|
rtems_filesystem_mt_entry_unlock(lock_context);
|
||||||
|
|
||||||
rtems_filesystem_global_location_release(lhs_global_loc);
|
rtems_filesystem_global_location_release(lhs_global_loc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void release_with_count(
|
static void release_with_count(
|
||||||
@@ -183,10 +183,11 @@ rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void rtems_filesystem_global_location_release(
|
void rtems_filesystem_global_location_release(
|
||||||
rtems_filesystem_global_location_t *global_loc
|
rtems_filesystem_global_location_t *global_loc,
|
||||||
|
bool deferred
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (_Thread_Dispatch_is_enabled()) {
|
if (!deferred) {
|
||||||
release_with_count(global_loc, 1);
|
release_with_count(global_loc, 1);
|
||||||
} else {
|
} else {
|
||||||
rtems_interrupt_lock_context lock_context;
|
rtems_interrupt_lock_context lock_context;
|
||||||
@@ -232,7 +233,7 @@ void rtems_filesystem_do_unmount(
|
|||||||
rtems_filesystem_mt_lock();
|
rtems_filesystem_mt_lock();
|
||||||
rtems_chain_extract_unprotected(&mt_entry->mt_node);
|
rtems_chain_extract_unprotected(&mt_entry->mt_node);
|
||||||
rtems_filesystem_mt_unlock();
|
rtems_filesystem_mt_unlock();
|
||||||
rtems_filesystem_global_location_release(mt_entry->mt_point_node);
|
rtems_filesystem_global_location_release(mt_entry->mt_point_node, false);
|
||||||
(*mt_entry->ops->fsunmount_me_h)(mt_entry);
|
(*mt_entry->ops->fsunmount_me_h)(mt_entry);
|
||||||
|
|
||||||
if (mt_entry->unmount_task != 0) {
|
if (mt_entry->unmount_task != 0) {
|
||||||
|
|||||||
@@ -1402,7 +1402,7 @@ siproc (unsigned char c, struct rtems_termios_tty *tty)
|
|||||||
/*
|
/*
|
||||||
* Fill the input buffer by polling the device
|
* Fill the input buffer by polling the device
|
||||||
*/
|
*/
|
||||||
static rtems_status_code
|
static void
|
||||||
fillBufferPoll (struct rtems_termios_tty *tty)
|
fillBufferPoll (struct rtems_termios_tty *tty)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
@@ -1449,23 +1449,27 @@ fillBufferPoll (struct rtems_termios_tty *tty)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill the input buffer from the raw input queue
|
* Fill the input buffer from the raw input queue
|
||||||
*/
|
*/
|
||||||
static rtems_status_code
|
static void
|
||||||
fillBufferQueue (struct rtems_termios_tty *tty)
|
fillBufferQueue (struct rtems_termios_tty *tty)
|
||||||
{
|
{
|
||||||
|
rtems_termios_device_context *ctx = tty->device_context;
|
||||||
rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
|
rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
|
||||||
rtems_status_code sc;
|
bool wait = true;
|
||||||
int wait = 1;
|
|
||||||
|
|
||||||
while ( wait ) {
|
while ( wait ) {
|
||||||
|
rtems_interrupt_lock_context lock_context;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process characters read from raw queue
|
* Process characters read from raw queue
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
rtems_termios_device_lock_acquire (ctx, &lock_context);
|
||||||
|
|
||||||
while ((tty->rawInBuf.Head != tty->rawInBuf.Tail) &&
|
while ((tty->rawInBuf.Head != tty->rawInBuf.Tail) &&
|
||||||
(tty->ccount < (CBUFSIZE-1))) {
|
(tty->ccount < (CBUFSIZE-1))) {
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
@@ -1474,6 +1478,7 @@ fillBufferQueue (struct rtems_termios_tty *tty)
|
|||||||
newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
|
newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
|
||||||
c = tty->rawInBuf.theBuf[newHead];
|
c = tty->rawInBuf.theBuf[newHead];
|
||||||
tty->rawInBuf.Head = newHead;
|
tty->rawInBuf.Head = newHead;
|
||||||
|
|
||||||
if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
|
if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
|
||||||
% tty->rawInBuf.Size)
|
% tty->rawInBuf.Size)
|
||||||
< tty->lowwater) {
|
< tty->lowwater) {
|
||||||
@@ -1495,29 +1500,40 @@ fillBufferQueue (struct rtems_termios_tty *tty)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||||
|
|
||||||
/* continue processing new character */
|
/* continue processing new character */
|
||||||
if (tty->termios.c_lflag & ICANON) {
|
if (tty->termios.c_lflag & ICANON) {
|
||||||
if (siproc (c, tty))
|
if (siproc (c, tty))
|
||||||
wait = 0;
|
wait = false;
|
||||||
} else {
|
} else {
|
||||||
siproc (c, tty);
|
siproc (c, tty);
|
||||||
if (tty->ccount >= tty->termios.c_cc[VMIN])
|
if (tty->ccount >= tty->termios.c_cc[VMIN])
|
||||||
wait = 0;
|
wait = false;
|
||||||
}
|
}
|
||||||
timeout = tty->rawInBufSemaphoreTimeout;
|
timeout = tty->rawInBufSemaphoreTimeout;
|
||||||
|
|
||||||
|
rtems_termios_device_lock_acquire (ctx, &lock_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for characters
|
* Wait for characters
|
||||||
*/
|
*/
|
||||||
if ( wait ) {
|
if (wait) {
|
||||||
sc = rtems_semaphore_obtain(
|
if (tty->ccount < CBUFSIZE - 1) {
|
||||||
tty->rawInBuf.Semaphore, tty->rawInBufSemaphoreOptions, timeout);
|
rtems_status_code sc;
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
|
||||||
|
sc = rtems_semaphore_obtain(
|
||||||
|
tty->rawInBuf.Semaphore, tty->rawInBufSemaphoreOptions, timeout);
|
||||||
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_status_code
|
rtems_status_code
|
||||||
@@ -1544,12 +1560,9 @@ rtems_termios_read (void *arg)
|
|||||||
tty->cindex = tty->ccount = 0;
|
tty->cindex = tty->ccount = 0;
|
||||||
tty->read_start_column = tty->column;
|
tty->read_start_column = tty->column;
|
||||||
if (tty->handler.poll_read != NULL && tty->handler.mode == TERMIOS_POLLED)
|
if (tty->handler.poll_read != NULL && tty->handler.mode == TERMIOS_POLLED)
|
||||||
sc = fillBufferPoll (tty);
|
fillBufferPoll (tty);
|
||||||
else
|
else
|
||||||
sc = fillBufferQueue (tty);
|
fillBufferQueue (tty);
|
||||||
|
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
|
||||||
tty->cindex = tty->ccount = 0;
|
|
||||||
}
|
}
|
||||||
while (count && (tty->cindex < tty->ccount)) {
|
while (count && (tty->cindex < tty->ccount)) {
|
||||||
*buffer++ = tty->cbuf[tty->cindex++];
|
*buffer++ = tty->cbuf[tty->cindex++];
|
||||||
@@ -1584,7 +1597,6 @@ int
|
|||||||
rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
|
rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
|
||||||
{
|
{
|
||||||
struct rtems_termios_tty *tty = ttyp;
|
struct rtems_termios_tty *tty = ttyp;
|
||||||
unsigned int newTail;
|
|
||||||
char c;
|
char c;
|
||||||
int dropped = 0;
|
int dropped = 0;
|
||||||
bool flow_rcv = false; /* true, if flow control char received */
|
bool flow_rcv = false; /* true, if flow control char received */
|
||||||
@@ -1649,12 +1661,19 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
|
|||||||
rtems_termios_device_lock_release (ctx, &lock_context);
|
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
|
unsigned int head;
|
||||||
/* if chars_in_buffer > highwater */
|
unsigned int oldTail;
|
||||||
|
unsigned int newTail;
|
||||||
|
|
||||||
rtems_termios_device_lock_acquire (ctx, &lock_context);
|
rtems_termios_device_lock_acquire (ctx, &lock_context);
|
||||||
if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
|
|
||||||
% tty->rawInBuf.Size) > tty->highwater) &&
|
head = tty->rawInBuf.Head;
|
||||||
!(tty->flow_ctrl & FL_IREQXOF)) {
|
oldTail = tty->rawInBuf.Tail;
|
||||||
|
newTail = (oldTail + 1) % tty->rawInBuf.Size;
|
||||||
|
|
||||||
|
/* if chars_in_buffer > highwater */
|
||||||
|
if ((tty->flow_ctrl & FL_IREQXOF) != 0 && (((newTail - head
|
||||||
|
+ tty->rawInBuf.Size) % tty->rawInBuf.Size) > tty->highwater)) {
|
||||||
/* incoming data stream should be stopped */
|
/* incoming data stream should be stopped */
|
||||||
tty->flow_ctrl |= FL_IREQXOF;
|
tty->flow_ctrl |= FL_IREQXOF;
|
||||||
if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
|
if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
|
||||||
@@ -1676,15 +1695,12 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reenable interrupts */
|
if (newTail != head) {
|
||||||
rtems_termios_device_lock_release (ctx, &lock_context);
|
|
||||||
|
|
||||||
if (newTail == tty->rawInBuf.Head) {
|
|
||||||
dropped++;
|
|
||||||
} else {
|
|
||||||
tty->rawInBuf.theBuf[newTail] = c;
|
tty->rawInBuf.theBuf[newTail] = c;
|
||||||
tty->rawInBuf.Tail = newTail;
|
tty->rawInBuf.Tail = newTail;
|
||||||
|
|
||||||
|
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check to see if rcv wakeup callback was set
|
* check to see if rcv wakeup callback was set
|
||||||
*/
|
*/
|
||||||
@@ -1692,6 +1708,9 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
|
|||||||
(*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);
|
(*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);
|
||||||
tty->tty_rcvwakeup = 1;
|
tty->tty_rcvwakeup = 1;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
++dropped;
|
||||||
|
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ libdl_a_SOURCES = \
|
|||||||
rtl-string.c \
|
rtl-string.c \
|
||||||
rtl-sym.c \
|
rtl-sym.c \
|
||||||
rtl-trace.c \
|
rtl-trace.c \
|
||||||
|
rtl-unwind-dw2.c \
|
||||||
rtl-unresolved.c
|
rtl-unresolved.c
|
||||||
|
|
||||||
libdl_a_SOURCES += rtl-mdreloc-@RTEMS_CPU@.c
|
libdl_a_SOURCES += rtl-mdreloc-@RTEMS_CPU@.c
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ dlerror (void)
|
|||||||
{
|
{
|
||||||
static char msg[64];
|
static char msg[64];
|
||||||
rtems_rtl_get_error (msg, sizeof (msg));
|
rtems_rtl_get_error (msg, sizeof (msg));
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -80,7 +80,8 @@
|
|||||||
#define R_ARM_ALU_SBREL_19_12 36
|
#define R_ARM_ALU_SBREL_19_12 36
|
||||||
#define R_ARM_ALU_SBREL_27_20 37
|
#define R_ARM_ALU_SBREL_27_20 37
|
||||||
#define R_ARM_V4BX 40
|
#define R_ARM_V4BX 40
|
||||||
#define R_ARM_PREL31 41
|
#define R_ARM_TARGET2 41
|
||||||
|
#define R_ARM_PREL31 42
|
||||||
|
|
||||||
#define R_ARM_MOVW_ABS_NC 43
|
#define R_ARM_MOVW_ABS_NC 43
|
||||||
#define R_ARM_MOVT_ABS 44
|
#define R_ARM_MOVT_ABS 44
|
||||||
|
|||||||
@@ -459,6 +459,10 @@ typedef struct {
|
|||||||
#define SHF_WRITE 0x1 /* Section contains writable data */
|
#define SHF_WRITE 0x1 /* Section contains writable data */
|
||||||
#define SHF_ALLOC 0x2 /* Section occupies memory */
|
#define SHF_ALLOC 0x2 /* Section occupies memory */
|
||||||
#define SHF_EXECINSTR 0x4 /* Section contains executable insns */
|
#define SHF_EXECINSTR 0x4 /* Section contains executable insns */
|
||||||
|
#define SHF_MERGE 0x10 /* Section contains data that can be merged */
|
||||||
|
#define SHF_STRINGS 0x20 /* Section contains null-terminated strings */
|
||||||
|
#define SHF_INFO_LINK 0x40 /* Section header's sh_info holds table index */
|
||||||
|
#define SHF_LINK_ORDER 0x80 /* Section has special ordering requirements */
|
||||||
|
|
||||||
#define SHF_MASKOS 0x0f000000 /* Operating system specific values */
|
#define SHF_MASKOS 0x0f000000 /* Operating system specific values */
|
||||||
#define SHF_MASKPROC 0xf0000000 /* Processor-specific values */
|
#define SHF_MASKPROC 0xf0000000 /* Processor-specific values */
|
||||||
@@ -949,13 +953,13 @@ typedef struct {
|
|||||||
#define SYMINFO_NUM 2
|
#define SYMINFO_NUM 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These constants are used for Elf32_Verdef struct's version number.
|
* These constants are used for Elf32_Verdef struct's version number.
|
||||||
*/
|
*/
|
||||||
#define VER_DEF_NONE 0
|
#define VER_DEF_NONE 0
|
||||||
#define VER_DEF_CURRENT 1
|
#define VER_DEF_CURRENT 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These constants are used for Elf32_Verdef struct's vd_flags.
|
* These constants are used for Elf32_Verdef struct's vd_flags.
|
||||||
*/
|
*/
|
||||||
#define VER_FLG_BASE 0x1
|
#define VER_FLG_BASE 0x1
|
||||||
#define VER_FLG_WEAK 0x2
|
#define VER_FLG_WEAK 0x2
|
||||||
@@ -967,7 +971,7 @@ typedef struct {
|
|||||||
#define VER_NDX_GLOBAL 1
|
#define VER_NDX_GLOBAL 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These constants are used for Elf32_Verneed struct's version number.
|
* These constants are used for Elf32_Verneed struct's version number.
|
||||||
*/
|
*/
|
||||||
#define VER_NEED_NONE 0
|
#define VER_NEED_NONE 0
|
||||||
#define VER_NEED_CURRENT 1
|
#define VER_NEED_CURRENT 1
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag,
|
|||||||
bool
|
bool
|
||||||
rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
||||||
void** const_base, size_t const_size,
|
void** const_base, size_t const_size,
|
||||||
|
void** eh_base, size_t eh_size,
|
||||||
void** data_base, size_t data_size,
|
void** data_base, size_t data_size,
|
||||||
void** bss_base, size_t bss_size)
|
void** bss_base, size_t bss_size)
|
||||||
{
|
{
|
||||||
@@ -173,7 +174,20 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
|||||||
const_size, false);
|
const_size, false);
|
||||||
if (!*const_base)
|
if (!*const_base)
|
||||||
{
|
{
|
||||||
rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
|
rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
|
||||||
|
data_base, bss_base);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eh_size)
|
||||||
|
{
|
||||||
|
*eh_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ,
|
||||||
|
eh_size, false);
|
||||||
|
if (!*eh_base)
|
||||||
|
{
|
||||||
|
rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
|
||||||
|
data_base, bss_base);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,7 +198,8 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
|||||||
data_size, false);
|
data_size, false);
|
||||||
if (!*data_base)
|
if (!*data_base)
|
||||||
{
|
{
|
||||||
rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
|
rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
|
||||||
|
data_base, bss_base);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,7 +210,8 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
|||||||
bss_size, false);
|
bss_size, false);
|
||||||
if (!*bss_base)
|
if (!*bss_base)
|
||||||
{
|
{
|
||||||
rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
|
rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
|
||||||
|
data_base, bss_base);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,12 +222,14 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
|||||||
void
|
void
|
||||||
rtems_rtl_alloc_module_del (void** text_base,
|
rtems_rtl_alloc_module_del (void** text_base,
|
||||||
void** const_base,
|
void** const_base,
|
||||||
|
void** eh_base,
|
||||||
void** data_base,
|
void** data_base,
|
||||||
void** bss_base)
|
void** bss_base)
|
||||||
{
|
{
|
||||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *bss_base);
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *bss_base);
|
||||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *data_base);
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *data_base);
|
||||||
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *eh_base);
|
||||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *const_base);
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *const_base);
|
||||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_EXEC, *text_base);
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_EXEC, *text_base);
|
||||||
*text_base = *const_base = *data_base = *bss_base = NULL;
|
*text_base = *const_base = *eh_base = *data_base = *bss_base = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,6 +146,8 @@ void rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag,
|
|||||||
* @param text_size The size of the read/exec section.
|
* @param text_size The size of the read/exec section.
|
||||||
* @param const_base Pointer to the const base pointer.
|
* @param const_base Pointer to the const base pointer.
|
||||||
* @param const_size The size of the read only section.
|
* @param const_size The size of the read only section.
|
||||||
|
* @param eh_base Pointer to the eh base pointer.
|
||||||
|
* @param eh_size The size of the eh section.
|
||||||
* @param data_base Pointer to the data base pointer.
|
* @param data_base Pointer to the data base pointer.
|
||||||
* @param data_size The size of the read/write secton.
|
* @param data_size The size of the read/write secton.
|
||||||
* @param bss_base Pointer to the bss base pointer.
|
* @param bss_base Pointer to the bss base pointer.
|
||||||
@@ -155,6 +157,7 @@ void rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag,
|
|||||||
*/
|
*/
|
||||||
bool rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
bool rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
||||||
void** const_base, size_t const_size,
|
void** const_base, size_t const_size,
|
||||||
|
void** eh_base, size_t eh_size,
|
||||||
void** data_base, size_t data_size,
|
void** data_base, size_t data_size,
|
||||||
void** bss_base, size_t bss_size);
|
void** bss_base, size_t bss_size);
|
||||||
|
|
||||||
@@ -163,11 +166,13 @@ bool rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
|||||||
*
|
*
|
||||||
* @param text_base Pointer to the text base pointer.
|
* @param text_base Pointer to the text base pointer.
|
||||||
* @param const_base Pointer to the const base pointer.
|
* @param const_base Pointer to the const base pointer.
|
||||||
|
* @param eh_base Pointer to the eh base pointer.
|
||||||
* @param data_base Pointer to the data base pointer.
|
* @param data_base Pointer to the data base pointer.
|
||||||
* @param bss_base Pointer to the bss base pointer.
|
* @param bss_base Pointer to the bss base pointer.
|
||||||
*/
|
*/
|
||||||
void rtems_rtl_alloc_module_del (void** text_base, void** const_base,
|
void rtems_rtl_alloc_module_del (void** text_base, void** const_base,
|
||||||
void** data_base, void** bss_base);
|
void** eh_base, void** data_base,
|
||||||
|
void** bss_base);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ _rtld_debug_state (void)
|
|||||||
int
|
int
|
||||||
_rtld_linkmap_add (rtems_rtl_obj_t* obj)
|
_rtld_linkmap_add (rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
struct link_map* l = (struct link_map*)obj->detail;
|
struct link_map* l = obj->linkmap;
|
||||||
struct link_map* prev;
|
struct link_map* prev;
|
||||||
uint32_t obj_num = obj->obj_num;
|
uint32_t obj_num = obj->obj_num;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||||
printf ("rtl: linkmap_add\n");
|
printf ("rtl: linkmap_add\n");
|
||||||
@@ -78,8 +78,10 @@ _rtld_linkmap_add (rtems_rtl_obj_t* obj)
|
|||||||
void
|
void
|
||||||
_rtld_linkmap_delete (rtems_rtl_obj_t* obj)
|
_rtld_linkmap_delete (rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
struct link_map* l = (struct link_map*)obj->detail;
|
struct link_map* l = obj->linkmap;
|
||||||
/* link_maps are allocated together if not 1 */
|
/*
|
||||||
|
* link_maps are allocated together if not 1
|
||||||
|
*/
|
||||||
struct link_map* e = l + obj->obj_num - 1;
|
struct link_map* e = l + obj->obj_num - 1;
|
||||||
|
|
||||||
while (e && e->l_next) e = e->l_next;
|
while (e && e->l_next) e = e->l_next;
|
||||||
@@ -90,7 +92,7 @@ _rtld_linkmap_delete (rtems_rtl_obj_t* obj)
|
|||||||
e->l_next->l_prev = NULL;
|
e->l_next->l_prev = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((l->l_prev->l_next = e->l_next) != NULL)
|
if ((l->l_prev->l_next = e->l_next) != NULL)
|
||||||
e->l_next->l_prev = l->l_prev;
|
e->l_next->l_prev = l->l_prev;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
#include "rtl-unresolved.h"
|
#include "rtl-unresolved.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,6 +170,9 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
|
|||||||
&relbuf[0], reloc_size))
|
&relbuf[0], reloc_size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the symbol details.
|
||||||
|
*/
|
||||||
if (is_rela)
|
if (is_rela)
|
||||||
off = (obj->ooffset + symsect->offset +
|
off = (obj->ooffset + symsect->offset +
|
||||||
(ELF_R_SYM (rela->r_info) * sizeof (sym)));
|
(ELF_R_SYM (rela->r_info) * sizeof (sym)));
|
||||||
@@ -246,7 +250,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
|
|||||||
if (is_rela)
|
if (is_rela)
|
||||||
{
|
{
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||||
printf ("rtl: rela: sym:%s(%-2d)=%08lx type:%-2d off:%08lx addend:%d\n",
|
printf ("rtl: rela: sym:%s(%d)=%08lx type:%d off:%08lx addend:%d\n",
|
||||||
symname, (int) ELF_R_SYM (rela->r_info), symvalue,
|
symname, (int) ELF_R_SYM (rela->r_info), symvalue,
|
||||||
(int) ELF_R_TYPE (rela->r_info), rela->r_offset, (int) rela->r_addend);
|
(int) ELF_R_TYPE (rela->r_info), rela->r_offset, (int) rela->r_addend);
|
||||||
if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
|
if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
|
||||||
@@ -256,7 +260,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||||
printf ("rtl: rel: sym:%s(%-2d)=%08lx type:%-2d off:%08lx\n",
|
printf ("rtl: rel: sym:%s(%d)=%08lx type:%d off:%08lx\n",
|
||||||
symname, (int) ELF_R_SYM (rel->r_info), symvalue,
|
symname, (int) ELF_R_SYM (rel->r_info), symvalue,
|
||||||
(int) ELF_R_TYPE (rel->r_info), rel->r_offset);
|
(int) ELF_R_TYPE (rel->r_info), rel->r_offset);
|
||||||
if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect,
|
if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect,
|
||||||
@@ -300,7 +304,7 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc,
|
|||||||
rela.r_info = reloc->rel[REL_R_INFO];
|
rela.r_info = reloc->rel[REL_R_INFO];
|
||||||
rela.r_addend = reloc->rel[REL_R_ADDEND];
|
rela.r_addend = reloc->rel[REL_R_ADDEND];
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||||
printf ("rtl: rela: sym:%-2d type:%-2d off:%08lx addend:%d\n",
|
printf ("rtl: rela: sym:%d type:%d off:%08lx addend:%d\n",
|
||||||
(int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info),
|
(int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info),
|
||||||
rela.r_offset, (int) rela.r_addend);
|
rela.r_offset, (int) rela.r_addend);
|
||||||
if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect,
|
if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect,
|
||||||
@@ -313,7 +317,7 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc,
|
|||||||
rel.r_offset = reloc->rel[REL_R_OFFSET];
|
rel.r_offset = reloc->rel[REL_R_OFFSET];
|
||||||
rel.r_info = reloc->rel[REL_R_INFO];
|
rel.r_info = reloc->rel[REL_R_INFO];
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||||
printf ("rtl: rel: sym:%-2d type:%-2d off:%08lx\n",
|
printf ("rtl: rel: sym:%d type:%d off:%08lx\n",
|
||||||
(int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info),
|
(int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info),
|
||||||
rel.r_offset);
|
rel.r_offset);
|
||||||
if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect,
|
if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect,
|
||||||
@@ -652,6 +656,11 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
|||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
|
||||||
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||||
|
printf ("rtl: section: %2d: type=%d flags=%08x link=%d info=%d\n",
|
||||||
|
section, (int) shdr.sh_type, (unsigned int) shdr.sh_flags,
|
||||||
|
(int) shdr.sh_link, (int) shdr.sh_info);
|
||||||
|
|
||||||
switch (shdr.sh_type)
|
switch (shdr.sh_type)
|
||||||
{
|
{
|
||||||
case SHT_NULL:
|
case SHT_NULL:
|
||||||
@@ -707,9 +716,16 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
|
/*
|
||||||
printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
|
* See if there are architecture specific flags?
|
||||||
section, (int) shdr.sh_type, (int) shdr.sh_flags);
|
*/
|
||||||
|
flags = rtems_rtl_elf_section_flags (obj, &shdr);
|
||||||
|
if (flags == 0)
|
||||||
|
{
|
||||||
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
|
||||||
|
printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
|
||||||
|
section, (int) shdr.sh_type, (int) shdr.sh_flags);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,6 +734,13 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
|||||||
char* name;
|
char* name;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If link ordering this section must appear in the same order in memory
|
||||||
|
* as the linked-to section relative to the sections it loads with.
|
||||||
|
*/
|
||||||
|
if ((shdr.sh_flags & SHF_LINK_ORDER) != 0)
|
||||||
|
flags |= RTEMS_RTL_OBJ_SECT_LINK;
|
||||||
|
|
||||||
len = RTEMS_RTL_ELF_STRING_MAX;
|
len = RTEMS_RTL_ELF_STRING_MAX;
|
||||||
if (!rtems_rtl_obj_cache_read (strings, fd,
|
if (!rtems_rtl_obj_cache_read (strings, fd,
|
||||||
sectstroff + shdr.sh_name,
|
sectstroff + shdr.sh_name,
|
||||||
@@ -729,6 +752,12 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
|||||||
if (strcmp (".dtors", name) == 0)
|
if (strcmp (".dtors", name) == 0)
|
||||||
flags |= RTEMS_RTL_OBJ_SECT_DTOR;
|
flags |= RTEMS_RTL_OBJ_SECT_DTOR;
|
||||||
|
|
||||||
|
if (rtems_rtl_elf_unwind_parse (obj, name, flags))
|
||||||
|
{
|
||||||
|
flags &= ~(RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST);
|
||||||
|
flags |= RTEMS_RTL_OBJ_SECT_EH;
|
||||||
|
}
|
||||||
|
|
||||||
if (!rtems_rtl_obj_add_section (obj, section, name,
|
if (!rtems_rtl_obj_add_section (obj, section, name,
|
||||||
shdr.sh_size, shdr.sh_offset,
|
shdr.sh_size, shdr.sh_offset,
|
||||||
shdr.sh_addralign, shdr.sh_link,
|
shdr.sh_addralign, shdr.sh_link,
|
||||||
@@ -771,16 +800,19 @@ rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj)
|
static bool
|
||||||
|
rtems_rtl_elf_load_linkmap (rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
rtems_chain_control* sections = NULL;
|
rtems_chain_control* sections = NULL;
|
||||||
rtems_chain_node* node = NULL;
|
rtems_chain_node* node = NULL;
|
||||||
size_t mask = 0;
|
size_t mask = 0;
|
||||||
struct link_map* l = NULL;
|
|
||||||
int sec_num = 0;
|
int sec_num = 0;
|
||||||
|
section_detail* sd;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
/* caculate the size of sections' name. */
|
/*
|
||||||
|
* Caculate the size of sections' name.
|
||||||
|
*/
|
||||||
|
|
||||||
for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
|
for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
|
||||||
mask <= RTEMS_RTL_OBJ_SECT_BSS;
|
mask <= RTEMS_RTL_OBJ_SECT_BSS;
|
||||||
@@ -791,7 +823,6 @@ bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj)
|
|||||||
while (!rtems_chain_is_tail (sections, node))
|
while (!rtems_chain_is_tail (sections, node))
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||||
|
|
||||||
if ((sect->size != 0) && ((sect->flags & mask) != 0))
|
if ((sect->size != 0) && ((sect->flags & mask) != 0))
|
||||||
{
|
{
|
||||||
++sec_num;
|
++sec_num;
|
||||||
@@ -801,32 +832,31 @@ bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
obj->obj_num = 1;
|
obj->obj_num = 1;
|
||||||
obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
obj->linkmap = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||||
sizeof(struct link_map) +
|
sizeof(struct link_map) +
|
||||||
sec_num * sizeof (section_detail), true);
|
sec_num * sizeof (section_detail), true);
|
||||||
if (!obj->detail)
|
if (!obj->linkmap)
|
||||||
{
|
{
|
||||||
rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
|
rtems_rtl_set_error (ENOMEM, "no memory for obj linkmap");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
l = (struct link_map*) obj->detail;
|
obj->linkmap->name = obj->oname;
|
||||||
l->name = obj->oname;
|
obj->linkmap->sec_num = sec_num;
|
||||||
l->sec_num = sec_num;
|
obj->linkmap->sec_detail = (section_detail*) (obj->linkmap + 1);
|
||||||
l->sec_detail = (section_detail*) (l + 1);
|
obj->linkmap->rpathlen = 0;
|
||||||
l->rpathlen = 0;
|
obj->linkmap->rpath = NULL;
|
||||||
l->rpath = NULL;
|
obj->linkmap->l_next = NULL;
|
||||||
l->l_next = NULL;
|
obj->linkmap->l_prev = NULL;
|
||||||
l->l_prev = NULL;
|
obj->linkmap->sec_addr[rap_text] = obj->text_base;
|
||||||
l->sec_addr[rap_text] = obj->text_base;
|
obj->linkmap->sec_addr[rap_const] = obj->const_base;
|
||||||
l->sec_addr[rap_const] = obj->const_base;
|
obj->linkmap->sec_addr[rap_data] = obj->data_base;
|
||||||
l->sec_addr[rap_data] = obj->data_base;
|
obj->linkmap->sec_addr[rap_bss] = obj->bss_base;
|
||||||
l->sec_addr[rap_bss] = obj->bss_base;
|
|
||||||
|
|
||||||
|
sd = obj->linkmap->sec_detail;
|
||||||
section_detail* sd = l->sec_detail;
|
|
||||||
sections = &obj->sections;
|
sections = &obj->sections;
|
||||||
node = rtems_chain_first (sections);
|
node = rtems_chain_first (sections);
|
||||||
|
|
||||||
for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
|
for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
|
||||||
mask <= RTEMS_RTL_OBJ_SECT_BSS;
|
mask <= RTEMS_RTL_OBJ_SECT_BSS;
|
||||||
mask <<= 1)
|
mask <<= 1)
|
||||||
@@ -948,11 +978,23 @@ rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd)
|
|||||||
|
|
||||||
rtems_rtl_symbol_obj_erase_local (obj);
|
rtems_rtl_symbol_obj_erase_local (obj);
|
||||||
|
|
||||||
if (!rtems_rtl_elf_load_details (obj))
|
if (!rtems_rtl_elf_load_linkmap (obj))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!rtems_rtl_elf_unwind_register (obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_file_unload (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
rtems_rtl_elf_unwind_deregister (obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,18 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define RTEMS_RTL_ELF_STRING_MAX (256)
|
#define RTEMS_RTL_ELF_STRING_MAX (256)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Architecture specific handler to translate unknown section flags to RTL
|
||||||
|
* section flags.
|
||||||
|
*
|
||||||
|
* @param obj The object file being relocated.
|
||||||
|
* @param shdr The ELF section header.
|
||||||
|
* @retval 0 Unknown or unsupported flags.
|
||||||
|
* @retval uint32_t RTL object file flags.
|
||||||
|
*/
|
||||||
|
uint32_t rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Architecture specific handler to check is a relocation record's type is
|
* Architecture specific handler to check is a relocation record's type is
|
||||||
* required to resolve a symbol.
|
* required to resolve a symbol.
|
||||||
@@ -136,13 +148,6 @@ bool rtems_rtl_elf_find_symbol (rtems_rtl_obj_t* obj,
|
|||||||
*/
|
*/
|
||||||
bool rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd);
|
bool rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd);
|
||||||
|
|
||||||
/**
|
|
||||||
* The ELF file details handler.
|
|
||||||
*
|
|
||||||
* @param obj Load the details of the obj.
|
|
||||||
*/
|
|
||||||
bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ELF format load handler.
|
* The ELF format load handler.
|
||||||
*
|
*
|
||||||
@@ -151,6 +156,13 @@ bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj);
|
|||||||
*/
|
*/
|
||||||
bool rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd);
|
bool rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ELF format unload handler.
|
||||||
|
*
|
||||||
|
* @param obj The object to unload.
|
||||||
|
*/
|
||||||
|
bool rtems_rtl_elf_file_unload (rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ELF format signature handler.
|
* The ELF format signature handler.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
@@ -39,9 +40,15 @@ int
|
|||||||
rtems_rtl_get_error (char* message, size_t max_message)
|
rtems_rtl_get_error (char* message, size_t max_message)
|
||||||
{
|
{
|
||||||
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
||||||
int last_errno = rtl->last_errno;
|
if (rtl != NULL)
|
||||||
strncpy (message, rtl->last_error, sizeof (rtl->last_error));
|
{
|
||||||
rtems_rtl_unlock ();
|
int last_errno = rtl->last_errno;
|
||||||
return last_errno;
|
strncpy (message, rtl->last_error, sizeof (rtl->last_error));
|
||||||
}
|
rtems_rtl_unlock ();
|
||||||
|
return last_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(message, "RTL init error", max_message);
|
||||||
|
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,11 +10,14 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <unwind.h>
|
||||||
|
#include <unwind-arm-common.h>
|
||||||
|
|
||||||
#include <rtems/rtl/rtl.h>
|
#include <rtems/rtl/rtl.h>
|
||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It is possible for the compiler to emit relocations for unaligned data.
|
* It is possible for the compiler to emit relocations for unaligned data.
|
||||||
@@ -23,6 +26,8 @@
|
|||||||
#define RELOC_ALIGNED_P(x) \
|
#define RELOC_ALIGNED_P(x) \
|
||||||
(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
|
(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
|
||||||
|
|
||||||
|
#define SHT_ARM_EXIDX 0x70000001 /* Section holds ARM unwind info. */
|
||||||
|
|
||||||
static inline Elf_Addr
|
static inline Elf_Addr
|
||||||
load_ptr(void *where)
|
load_ptr(void *where)
|
||||||
{
|
{
|
||||||
@@ -52,6 +57,24 @@ isThumb(Elf_Word symvalue)
|
|||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Elf_SOff
|
||||||
|
sign_extend31(Elf_Addr val)
|
||||||
|
{
|
||||||
|
if (0x40000000 & val)
|
||||||
|
val = ~((Elf_Addr)0x7fffffff) | (0x7fffffff & val);
|
||||||
|
return 0x7fffffff & val;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
uint32_t flags = 0;
|
||||||
|
if (shdr->sh_type == SHT_ARM_EXIDX)
|
||||||
|
flags = RTEMS_RTL_OBJ_SECT_EH | RTEMS_RTL_OBJ_SECT_LOAD;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
{
|
{
|
||||||
@@ -87,8 +110,11 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
where = (Elf_Addr *)(sect->base + rel->r_offset);
|
where = (Elf_Addr *)(sect->base + rel->r_offset);
|
||||||
|
|
||||||
switch (ELF_R_TYPE(rel->r_info)) {
|
switch (ELF_R_TYPE(rel->r_info)) {
|
||||||
case R_TYPE(NONE):
|
case R_TYPE(NONE):
|
||||||
break;
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
|
||||||
|
printf ("rtl: NONE %p in %s\n", where, rtems_rtl_obj_oname (obj));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case R_TYPE(CALL): /* BL/BLX */
|
case R_TYPE(CALL): /* BL/BLX */
|
||||||
case R_TYPE(JUMP24): /* B/BL<cond> */
|
case R_TYPE(JUMP24): /* B/BL<cond> */
|
||||||
@@ -165,24 +191,32 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
case R_TYPE(REL32): /* word32 (S + A) | T - P */
|
case R_TYPE(REL32): /* word32 (S + A) | T - P */
|
||||||
case R_TYPE(ABS32): /* word32 (S + A) | T */
|
case R_TYPE(ABS32): /* word32 (S + A) | T */
|
||||||
case R_TYPE(GLOB_DAT): /* word32 (S + A) | T */
|
case R_TYPE(GLOB_DAT): /* word32 (S + A) | T */
|
||||||
|
case R_TYPE(PREL31): /* word32 (S + A) | T - P */
|
||||||
|
case R_TYPE(TARGET2): /* Equivalent to REL32 */
|
||||||
if (__predict_true(RELOC_ALIGNED_P(where))) {
|
if (__predict_true(RELOC_ALIGNED_P(where))) {
|
||||||
tmp = *where + symvalue;
|
tmp = *where + symvalue;
|
||||||
if (isThumb(symvalue))
|
if (isThumb(symvalue))
|
||||||
tmp |= 1;
|
tmp |= 1;
|
||||||
if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32))
|
if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32) ||
|
||||||
|
ELF_R_TYPE(rel->r_info) == R_TYPE(TARGET2))
|
||||||
tmp -= (Elf_Addr)where;
|
tmp -= (Elf_Addr)where;
|
||||||
|
else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
|
||||||
|
tmp = sign_extend31(tmp - (Elf_Addr)where);
|
||||||
*where = tmp;
|
*where = tmp;
|
||||||
} else {
|
} else {
|
||||||
tmp = load_ptr(where) + symvalue;
|
tmp = load_ptr(where) + symvalue;
|
||||||
if (isThumb(symvalue))
|
if (isThumb(symvalue))
|
||||||
tmp |= 1;
|
tmp |= 1;
|
||||||
if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32))
|
if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32) ||
|
||||||
|
ELF_R_TYPE(rel->r_info) == R_TYPE(TARGET2))
|
||||||
tmp -= (Elf_Addr)where;
|
tmp -= (Elf_Addr)where;
|
||||||
|
else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
|
||||||
|
tmp = sign_extend31(tmp - (Elf_Addr)where);
|
||||||
store_ptr(where, tmp);
|
store_ptr(where, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||||
printf ("rtl: REL32/ABS32/GLOB_DAT %p @ %p in %s",
|
printf ("rtl: REL32/ABS32/GLOB_DAT/PREL31/TARGET2 %p @ %p in %s\n",
|
||||||
(void *)tmp, where, rtems_rtl_obj_oname (obj));
|
(void *)tmp, where, rtems_rtl_obj_oname (obj));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -306,7 +340,7 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
(void *)*where, where, rtems_rtl_obj_oname (obj));
|
(void *)*where, where, rtems_rtl_obj_oname (obj));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
|
printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
|
||||||
"contents = %p\n",
|
"contents = %p\n",
|
||||||
ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
|
ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
|
||||||
@@ -315,9 +349,83 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
"%s: Unsupported relocation type %ld "
|
"%s: Unsupported relocation type %ld "
|
||||||
"in non-PLT relocations",
|
"in non-PLT relocations",
|
||||||
sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
|
sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We location the EH sections in section flags.
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
obj->loader = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* An exception index table entry. */
|
||||||
|
typedef struct __EIT_entry
|
||||||
|
{
|
||||||
|
_uw fnoffset;
|
||||||
|
_uw content;
|
||||||
|
} __EIT_entry;
|
||||||
|
|
||||||
|
/* The exception index table location in the base module */
|
||||||
|
extern __EIT_entry __exidx_start;
|
||||||
|
extern __EIT_entry __exidx_end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A weak reference is in libgcc, provide a real version and provide a way to
|
||||||
|
* manage loaded modules.
|
||||||
|
*
|
||||||
|
* Passed in the return address and a reference to the number of records
|
||||||
|
* found. We set the start of the exidx data and the number of records.
|
||||||
|
*/
|
||||||
|
_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address,
|
||||||
|
int* nrec) __attribute__ ((__noinline__,
|
||||||
|
__used__,
|
||||||
|
__noclone__));
|
||||||
|
|
||||||
|
_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address,
|
||||||
|
int* nrec)
|
||||||
|
{
|
||||||
|
rtems_rtl_data_t* rtl;
|
||||||
|
rtems_chain_node* node;
|
||||||
|
__EIT_entry* exidx_start = &__exidx_start;
|
||||||
|
__EIT_entry* exidx_end = &__exidx_end;
|
||||||
|
|
||||||
|
rtl = rtems_rtl_lock ();
|
||||||
|
|
||||||
|
node = rtems_chain_first (&rtl->objects);
|
||||||
|
while (!rtems_chain_is_tail (&rtl->objects, node)) {
|
||||||
|
rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node;
|
||||||
|
if (rtems_rtl_obj_text_inside (obj, (void*) return_address)) {
|
||||||
|
exidx_start = (__EIT_entry*) obj->eh_base;
|
||||||
|
exidx_end = (__EIT_entry*) (obj->eh_base + obj->eh_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = rtems_chain_next (node);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtems_rtl_unlock ();
|
||||||
|
|
||||||
|
*nrec = exidx_end - exidx_start;
|
||||||
|
|
||||||
|
return (_Unwind_Ptr) exidx_start;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,15 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
@@ -113,3 +122,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,15 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
@@ -99,3 +108,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,15 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
@@ -101,3 +110,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,15 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
@@ -118,3 +127,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
rtems_rtl_set_error (EINVAL, "rela type record not supported");
|
rtems_rtl_set_error (EINVAL, "rela type record not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
static inline int overflow_8_check(int value)
|
static inline int overflow_8_check(int value)
|
||||||
{
|
{
|
||||||
@@ -30,6 +32,13 @@ static inline int overflow_16_check(int value)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
{
|
{
|
||||||
@@ -146,3 +155,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,15 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
@@ -188,3 +197,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,15 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
@@ -86,3 +95,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,11 +15,19 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
#define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
|
#define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
|
||||||
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
|
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
|
||||||
#define l(x) ((u_int32_t)(x) & 0xffff)
|
#define l(x) ((u_int32_t)(x) & 0xffff)
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
@@ -158,6 +166,22 @@ rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj,
|
|||||||
(void *)*where, where, rtems_rtl_obj_oname (obj));
|
(void *)*where, where, rtems_rtl_obj_oname (obj));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case R_TYPE(SDAREL16):
|
||||||
|
/*
|
||||||
|
* A sign-extended 16 bit value relative to _SDA_BASE_, for use with
|
||||||
|
* small data items.
|
||||||
|
*/
|
||||||
|
mask = 0xffff;
|
||||||
|
tmp = *((Elf32_Half*) where);
|
||||||
|
tmp &= ~mask;
|
||||||
|
tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask;
|
||||||
|
*((Elf32_Half*) where) = tmp;
|
||||||
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||||
|
printf ("rtl: SDAREL16 %p @ %p in %s\n",
|
||||||
|
(void *) (uintptr_t) *((Elf32_Half*) where),
|
||||||
|
where, rtems_rtl_obj_oname (obj));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
|
printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
|
||||||
"contents = %p\n",
|
"contents = %p\n",
|
||||||
@@ -183,3 +207,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
printf ("rtl: rel type record not supported; please report\n");
|
printf ("rtl: rel type record not supported; please report\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following table holds for each relocation type:
|
* The following table holds for each relocation type:
|
||||||
@@ -128,6 +130,13 @@ static const int reloc_target_bitmask[] = {
|
|||||||
};
|
};
|
||||||
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
|
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
{
|
{
|
||||||
@@ -144,6 +153,7 @@ rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj,
|
|||||||
{
|
{
|
||||||
Elf_Addr *where;
|
Elf_Addr *where;
|
||||||
Elf_Word type, value, mask;
|
Elf_Word type, value, mask;
|
||||||
|
Elf_Addr tmp = 0;
|
||||||
|
|
||||||
where = (Elf_Addr *) (sect->base + rela->r_offset);
|
where = (Elf_Addr *) (sect->base + rela->r_offset);
|
||||||
|
|
||||||
@@ -219,31 +229,32 @@ rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj,
|
|||||||
value &= mask;
|
value &= mask;
|
||||||
|
|
||||||
if (RELOC_UNALIGNED(type)) {
|
if (RELOC_UNALIGNED(type)) {
|
||||||
/* Handle unaligned relocations. */
|
/*
|
||||||
Elf_Addr tmp = 0;
|
* Handle unaligned relocations.
|
||||||
char *ptr = (char *)where;
|
*/
|
||||||
|
char *ptr = (char*) where;
|
||||||
int i, size = RELOC_TARGET_SIZE (type) / 8;
|
int i, size = RELOC_TARGET_SIZE (type) / 8;
|
||||||
|
|
||||||
/* Read it in one byte at a time. */
|
/* Read it in one byte at a time. */
|
||||||
for (i=0; i<size; i++)
|
for (i = size - 1; i >= 0; i--)
|
||||||
tmp = (tmp << 8) | ptr[i];
|
tmp = (tmp << 8) | ptr[i];
|
||||||
|
|
||||||
tmp &= ~mask;
|
tmp &= ~mask;
|
||||||
tmp |= value;
|
tmp |= value;
|
||||||
|
|
||||||
/* Write it back out. */
|
/* Write it back out. */
|
||||||
for (i=0; i<size; i++)
|
for (i = size - 1; i >= 0; i--, tmp >>= 8)
|
||||||
ptr[i] = ((tmp >> (8*i)) & 0xff);
|
ptr[i] = tmp & 0xff;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
*where &= ~mask;
|
*where &= ~mask;
|
||||||
*where |= value;
|
*where |= value;
|
||||||
|
tmp = *where;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||||
printf ("rtl: %s %p @ %p in %s\n",
|
printf ("rtl: %s %p @ %p in %s\n",
|
||||||
reloc_names[type], (void *)*where, where, rtems_rtl_obj_oname (obj));
|
reloc_names[ELF_R_TYPE(rela->r_info)],
|
||||||
|
(void *)tmp, where, rtems_rtl_obj_oname (obj));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -259,3 +270,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
printf ("rtl: rel type record not supported; please report\n");
|
printf ("rtl: rel type record not supported; please report\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,15 @@
|
|||||||
#include "rtl-elf.h"
|
#include "rtl-elf.h"
|
||||||
#include "rtl-error.h"
|
#include "rtl-error.h"
|
||||||
#include "rtl-trace.h"
|
#include "rtl-trace.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||||
|
const Elf_Shdr* shdr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
|
||||||
@@ -95,3 +104,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
|||||||
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
rtems_rtl_set_error (EINVAL, "rel type record not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_register (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_elf_unwind_dw2_deregister (obj);
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,14 +49,21 @@
|
|||||||
/**
|
/**
|
||||||
* The table of supported loader formats.
|
* The table of supported loader formats.
|
||||||
*/
|
*/
|
||||||
static rtems_rtl_loader_table_t loaders[RTEMS_RTL_ELF_LOADER_COUNT +
|
#define RTEMS_RTL_LOADERS (RTEMS_RTL_ELF_LOADER_COUNT + RTEMS_RTL_RAP_LOADER_COUNT)
|
||||||
RTEMS_RTL_RAP_LOADER_COUNT] =
|
static const rtems_rtl_loader_table_t loaders[RTEMS_RTL_LOADERS] =
|
||||||
{
|
{
|
||||||
#if RTEMS_RTL_RAP_LOADER
|
#if RTEMS_RTL_RAP_LOADER
|
||||||
{ rtems_rtl_rap_file_check, rtems_rtl_rap_file_load, rtems_rtl_rap_file_sig },
|
{ .check = rtems_rtl_rap_file_check,
|
||||||
|
.load = rtems_rtl_rap_file_load,
|
||||||
|
.unload = rtems_rtl_rap_file_unload,
|
||||||
|
.unload = rtems_rtl_rap_file_unload,
|
||||||
|
.signature = rtems_rtl_rap_file_sig },
|
||||||
#endif
|
#endif
|
||||||
#if RTEMS_RTL_ELF_LOADER
|
#if RTEMS_RTL_ELF_LOADER
|
||||||
{ rtems_rtl_elf_file_check, rtems_rtl_elf_file_load, rtems_rtl_elf_file_sig },
|
{ .check = rtems_rtl_elf_file_check,
|
||||||
|
.load = rtems_rtl_elf_file_load,
|
||||||
|
.unload = rtems_rtl_elf_file_unload,
|
||||||
|
.signature = rtems_rtl_elf_file_sig },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,6 +79,10 @@ rtems_rtl_obj_alloc (void)
|
|||||||
* Initialise the chains.
|
* Initialise the chains.
|
||||||
*/
|
*/
|
||||||
rtems_chain_initialize_empty (&obj->sections);
|
rtems_chain_initialize_empty (&obj->sections);
|
||||||
|
/*
|
||||||
|
* No valid format.
|
||||||
|
*/
|
||||||
|
obj->format = -1;
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@@ -97,14 +108,14 @@ rtems_rtl_obj_free (rtems_rtl_obj_t* obj)
|
|||||||
}
|
}
|
||||||
if (!rtems_chain_is_node_off_chain (&obj->link))
|
if (!rtems_chain_is_node_off_chain (&obj->link))
|
||||||
rtems_chain_extract (&obj->link);
|
rtems_chain_extract (&obj->link);
|
||||||
rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
|
rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->eh_base,
|
||||||
&obj->data_base, &obj->bss_base);
|
&obj->data_base, &obj->bss_base);
|
||||||
rtems_rtl_symbol_obj_erase (obj);
|
rtems_rtl_symbol_obj_erase (obj);
|
||||||
rtems_rtl_obj_free_names (obj);
|
rtems_rtl_obj_free_names (obj);
|
||||||
if (obj->sec_num)
|
if (obj->sec_num)
|
||||||
free (obj->sec_num);
|
free (obj->sec_num);
|
||||||
if (obj->detail)
|
if (obj->linkmap)
|
||||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*)obj->detail);
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->linkmap);
|
||||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -238,7 +249,7 @@ rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
|
|||||||
static size_t
|
static size_t
|
||||||
rtems_rtl_sect_align (size_t offset, uint32_t alignment)
|
rtems_rtl_sect_align (size_t offset, uint32_t alignment)
|
||||||
{
|
{
|
||||||
if ((alignment > 1) && ((offset & ~alignment) != 0))
|
if ((alignment > 1) && ((offset & (alignment - 1)) != 0))
|
||||||
offset = (offset + alignment) & ~(alignment - 1);
|
offset = (offset + alignment) & ~(alignment - 1);
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
@@ -264,12 +275,12 @@ rtems_rtl_obj_sect_summer (rtems_chain_node* node, void* data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
rtems_rtl_obj_section_size (rtems_rtl_obj_t* obj, uint32_t mask)
|
rtems_rtl_obj_section_size (const rtems_rtl_obj_t* obj, uint32_t mask)
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_summer_t summer;
|
rtems_rtl_obj_sect_summer_t summer;
|
||||||
summer.mask = mask;
|
summer.mask = mask;
|
||||||
summer.size = 0;
|
summer.size = 0;
|
||||||
rtems_rtl_chain_iterate (&obj->sections,
|
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
|
||||||
rtems_rtl_obj_sect_summer,
|
rtems_rtl_obj_sect_summer,
|
||||||
&summer);
|
&summer);
|
||||||
return summer.size;
|
return summer.size;
|
||||||
@@ -302,12 +313,12 @@ rtems_rtl_obj_sect_aligner (rtems_chain_node* node, void* data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
rtems_rtl_obj_section_alignment (rtems_rtl_obj_t* obj, uint32_t mask)
|
rtems_rtl_obj_section_alignment (const rtems_rtl_obj_t* obj, uint32_t mask)
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_aligner_t aligner;
|
rtems_rtl_obj_sect_aligner_t aligner;
|
||||||
aligner.mask = mask;
|
aligner.mask = mask;
|
||||||
aligner.alignment = 0;
|
aligner.alignment = 0;
|
||||||
rtems_rtl_chain_iterate (&obj->sections,
|
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
|
||||||
rtems_rtl_obj_sect_aligner,
|
rtems_rtl_obj_sect_aligner,
|
||||||
&aligner);
|
&aligner);
|
||||||
return aligner.alignment;
|
return aligner.alignment;
|
||||||
@@ -401,26 +412,30 @@ rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj,
|
|||||||
int info,
|
int info,
|
||||||
uint32_t flags)
|
uint32_t flags)
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
if (size > 0)
|
||||||
sizeof (rtems_rtl_obj_sect_t), true);
|
|
||||||
if (!sect)
|
|
||||||
{
|
{
|
||||||
rtems_rtl_set_error (ENOMEM, "adding allocated section");
|
rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||||
return false;
|
sizeof (rtems_rtl_obj_sect_t),
|
||||||
}
|
true);
|
||||||
sect->section = section;
|
if (!sect)
|
||||||
sect->name = rtems_rtl_strdup (name);
|
{
|
||||||
sect->size = size;
|
rtems_rtl_set_error (ENOMEM, "adding allocated section");
|
||||||
sect->offset = offset;
|
return false;
|
||||||
sect->alignment = alignment;
|
}
|
||||||
sect->link = link;
|
sect->section = section;
|
||||||
sect->info = info;
|
sect->name = rtems_rtl_strdup (name);
|
||||||
sect->flags = flags;
|
sect->size = size;
|
||||||
sect->base = NULL;
|
sect->offset = offset;
|
||||||
rtems_chain_append (&obj->sections, §->node);
|
sect->alignment = alignment;
|
||||||
|
sect->link = link;
|
||||||
|
sect->info = info;
|
||||||
|
sect->flags = flags;
|
||||||
|
sect->base = NULL;
|
||||||
|
rtems_chain_append (&obj->sections, §->node);
|
||||||
|
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
|
||||||
printf ("rtl: sect: %-2d: %s\n", section, name);
|
printf ("rtl: sect: %-2d: %s (%zu)\n", section, name, size);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -464,12 +479,13 @@ rtems_rtl_obj_sect_match_name (rtems_chain_node* node, void* data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
rtems_rtl_obj_sect_t*
|
rtems_rtl_obj_sect_t*
|
||||||
rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj, const char* name)
|
rtems_rtl_obj_find_section (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name)
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_finder_t match;
|
rtems_rtl_obj_sect_finder_t match;
|
||||||
match.sect = NULL;
|
match.sect = NULL;
|
||||||
match.name = name;
|
match.name = name;
|
||||||
rtems_rtl_chain_iterate (&obj->sections,
|
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
|
||||||
rtems_rtl_obj_sect_match_name,
|
rtems_rtl_obj_sect_match_name,
|
||||||
&match);
|
&match);
|
||||||
return match.sect;
|
return match.sect;
|
||||||
@@ -489,61 +505,74 @@ rtems_rtl_obj_sect_match_index (rtems_chain_node* node, void* data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
rtems_rtl_obj_sect_t*
|
rtems_rtl_obj_sect_t*
|
||||||
rtems_rtl_obj_find_section_by_index (rtems_rtl_obj_t* obj, int index)
|
rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj_t* obj,
|
||||||
|
int index)
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_finder_t match;
|
rtems_rtl_obj_sect_finder_t match;
|
||||||
match.sect = NULL;
|
match.sect = NULL;
|
||||||
match.index = index;
|
match.index = index;
|
||||||
rtems_rtl_chain_iterate (&obj->sections,
|
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
|
||||||
rtems_rtl_obj_sect_match_index,
|
rtems_rtl_obj_sect_match_index,
|
||||||
&match);
|
&match);
|
||||||
return match.sect;
|
return match.sect;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_text_size (const rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_TEXT);
|
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
rtems_rtl_obj_text_alignment (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_text_alignment (const rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_TEXT);
|
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_const_size (const rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_CONST);
|
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_CONST);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
rtems_rtl_obj_const_alignment (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_eh_alignment (const rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_EH);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
rtems_rtl_obj_eh_size (const rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_EH);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
rtems_rtl_obj_const_alignment (const rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_CONST);
|
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_CONST);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_data_size (const rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_DATA);
|
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
rtems_rtl_obj_data_alignment (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_data_alignment (const rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_DATA);
|
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_bss_size (const rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_BSS);
|
return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_BSS);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
rtems_rtl_obj_bss_alignment (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_bss_alignment (const rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_BSS);
|
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_BSS);
|
||||||
}
|
}
|
||||||
@@ -572,21 +601,25 @@ typedef struct
|
|||||||
static bool
|
static bool
|
||||||
rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
|
rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||||
rtems_rtl_obj_sect_sync_ctx_t* sync_ctx = data;
|
rtems_rtl_obj_sect_sync_ctx_t* sync_ctx = data;
|
||||||
uintptr_t old_end;
|
uintptr_t old_end;
|
||||||
uintptr_t new_start;
|
uintptr_t new_start;
|
||||||
|
|
||||||
if ( !(sect->flags & sync_ctx->mask) || !sect->size)
|
if ((sect->flags & sync_ctx->mask) == 0 || sect->size == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (sync_ctx->end_va == sync_ctx->start_va) {
|
if (sync_ctx->end_va == sync_ctx->start_va)
|
||||||
|
{
|
||||||
sync_ctx->start_va = sect->base;
|
sync_ctx->start_va = sect->base;
|
||||||
} else {
|
}
|
||||||
old_end = (uintptr_t)sync_ctx->end_va & ~(sync_ctx->cache_line_size - 1);
|
else
|
||||||
new_start = (uintptr_t)sect->base & ~(sync_ctx->cache_line_size - 1);
|
{
|
||||||
if ( (sect->base < sync_ctx->start_va) ||
|
old_end = (uintptr_t) sync_ctx->end_va & ~(sync_ctx->cache_line_size - 1);
|
||||||
(new_start - old_end > sync_ctx->cache_line_size) ) {
|
new_start = (uintptr_t) sect->base & ~(sync_ctx->cache_line_size - 1);
|
||||||
|
if ((sect->base < sync_ctx->start_va) ||
|
||||||
|
(new_start - old_end > sync_ctx->cache_line_size))
|
||||||
|
{
|
||||||
rtems_cache_instruction_sync_after_code_change(sync_ctx->start_va,
|
rtems_cache_instruction_sync_after_code_change(sync_ctx->start_va,
|
||||||
sync_ctx->end_va - sync_ctx->start_va + 1);
|
sync_ctx->end_va - sync_ctx->start_va + 1);
|
||||||
sync_ctx->start_va = sect->base;
|
sync_ctx->start_va = sect->base;
|
||||||
@@ -599,7 +632,7 @@ rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_sync_ctx_t sync_ctx;
|
rtems_rtl_obj_sect_sync_ctx_t sync_ctx;
|
||||||
|
|
||||||
@@ -610,7 +643,7 @@ rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj)
|
|||||||
|
|
||||||
sync_ctx.mask = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST |
|
sync_ctx.mask = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST |
|
||||||
RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_BSS |
|
RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_BSS |
|
||||||
RTEMS_RTL_OBJ_SECT_EXEC;
|
RTEMS_RTL_OBJ_SECT_EH | RTEMS_RTL_OBJ_SECT_EXEC;
|
||||||
|
|
||||||
sync_ctx.start_va = 0;
|
sync_ctx.start_va = 0;
|
||||||
sync_ctx.end_va = sync_ctx.start_va;
|
sync_ctx.end_va = sync_ctx.start_va;
|
||||||
@@ -634,6 +667,87 @@ rtems_rtl_obj_load_symbols (rtems_rtl_obj_t* obj,
|
|||||||
return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
|
return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rtems_rtl_obj_sections_linked_to_order (rtems_rtl_obj_t* obj,
|
||||||
|
int section,
|
||||||
|
uint32_t visited_mask)
|
||||||
|
{
|
||||||
|
rtems_chain_control* sections = &obj->sections;
|
||||||
|
rtems_chain_node* node = rtems_chain_first (sections);
|
||||||
|
/*
|
||||||
|
* Find the section being linked-to. If the linked-to link field is 0 we have
|
||||||
|
* the end and the section's order is the position we are after.
|
||||||
|
*/
|
||||||
|
while (!rtems_chain_is_tail (sections, node))
|
||||||
|
{
|
||||||
|
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||||
|
if (sect->section == section)
|
||||||
|
{
|
||||||
|
const uint32_t mask = sect->flags & RTEMS_RTL_OBJ_SECT_TYPES;
|
||||||
|
int order = 0;
|
||||||
|
if (sect->link != 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Have we already visited this type of section? Avoid nesting for
|
||||||
|
* ever.
|
||||||
|
*/
|
||||||
|
if ((sect->flags & visited_mask) != 0)
|
||||||
|
{
|
||||||
|
rtems_rtl_set_error (errno, "section link loop");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return rtems_rtl_obj_sections_linked_to_order (obj,
|
||||||
|
sect->link,
|
||||||
|
visited_mask | mask);
|
||||||
|
}
|
||||||
|
node = rtems_chain_first (sections);
|
||||||
|
while (!rtems_chain_is_tail (sections, node))
|
||||||
|
{
|
||||||
|
sect = (rtems_rtl_obj_sect_t*) node;
|
||||||
|
if ((sect->flags & mask) == mask)
|
||||||
|
{
|
||||||
|
if (sect->section == section)
|
||||||
|
return order;
|
||||||
|
++order;
|
||||||
|
}
|
||||||
|
node = rtems_chain_next (node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = rtems_chain_next (node);
|
||||||
|
}
|
||||||
|
rtems_rtl_set_error (errno, "section link not found");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rtems_rtl_obj_sections_link_order (uint32_t mask, rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
rtems_chain_control* sections = &obj->sections;
|
||||||
|
rtems_chain_node* node = rtems_chain_first (sections);
|
||||||
|
int order = 0;
|
||||||
|
while (!rtems_chain_is_tail (sections, node))
|
||||||
|
{
|
||||||
|
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||||
|
if ((sect->flags & mask) == mask)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the section is linked in order find the linked-to section's order
|
||||||
|
* and move the section in the section list to
|
||||||
|
*/
|
||||||
|
if (sect->link == 0)
|
||||||
|
sect->load_order = order++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sect->load_order =
|
||||||
|
rtems_rtl_obj_sections_linked_to_order (obj,
|
||||||
|
sect->link,
|
||||||
|
mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = rtems_chain_next (node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
rtems_rtl_obj_sections_loader (uint32_t mask,
|
rtems_rtl_obj_sections_loader (uint32_t mask,
|
||||||
rtems_rtl_obj_t* obj,
|
rtems_rtl_obj_t* obj,
|
||||||
@@ -646,42 +760,54 @@ rtems_rtl_obj_sections_loader (uint32_t mask,
|
|||||||
rtems_chain_node* node = rtems_chain_first (sections);
|
rtems_chain_node* node = rtems_chain_first (sections);
|
||||||
size_t base_offset = 0;
|
size_t base_offset = 0;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
int order = 0;
|
||||||
|
|
||||||
while (!rtems_chain_is_tail (sections, node))
|
while (!rtems_chain_is_tail (sections, node))
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||||
|
|
||||||
if ((sect->size != 0) && ((sect->flags & mask) != 0))
|
if ((sect->size != 0) && ((sect->flags & mask) != 0))
|
||||||
{
|
{
|
||||||
if (!first)
|
if (sect->load_order == order)
|
||||||
base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
|
|
||||||
|
|
||||||
sect->base = base + base_offset;
|
|
||||||
|
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
|
|
||||||
printf ("rtl: loading: %s -> %8p (%zi)\n",
|
|
||||||
sect->name, sect->base, sect->size);
|
|
||||||
|
|
||||||
if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
|
|
||||||
{
|
{
|
||||||
if (!handler (obj, fd, sect, data))
|
if (!first)
|
||||||
|
base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
sect->base = base + base_offset;
|
||||||
|
|
||||||
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
|
||||||
|
printf ("rtl: loading:%2d: %s -> %8p (s:%zi f:%04lx a:%lu l:%02d)\n",
|
||||||
|
order, sect->name, sect->base, sect->size,
|
||||||
|
sect->flags, sect->alignment, sect->link);
|
||||||
|
|
||||||
|
if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
|
||||||
|
{
|
||||||
|
if (!handler (obj, fd, sect, data))
|
||||||
|
{
|
||||||
|
sect->base = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
|
||||||
|
{
|
||||||
|
memset (base + base_offset, 0, sect->size);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
sect->base = 0;
|
sect->base = 0;
|
||||||
|
rtems_rtl_set_error (errno, "section has no load/clear op");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
|
|
||||||
{
|
|
||||||
memset (base + base_offset, 0, sect->size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sect->base = 0;
|
|
||||||
rtems_rtl_set_error (errno, "section has no load op");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
base_offset += sect->size;
|
base_offset += sect->size;
|
||||||
first = false;
|
|
||||||
|
++order;
|
||||||
|
|
||||||
|
node = rtems_chain_first (sections);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node = rtems_chain_next (node);
|
node = rtems_chain_next (node);
|
||||||
@@ -698,20 +824,30 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj,
|
|||||||
{
|
{
|
||||||
size_t text_size;
|
size_t text_size;
|
||||||
size_t const_size;
|
size_t const_size;
|
||||||
|
size_t eh_size;
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
size_t bss_size;
|
size_t bss_size;
|
||||||
|
|
||||||
text_size = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj);
|
text_size = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj);
|
||||||
const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_data_alignment (obj);
|
const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_eh_alignment (obj);
|
||||||
|
eh_size = rtems_rtl_obj_eh_size (obj) + rtems_rtl_obj_data_alignment (obj);
|
||||||
data_size = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj);
|
data_size = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj);
|
||||||
bss_size = rtems_rtl_obj_bss_size (obj);
|
bss_size = rtems_rtl_obj_bss_size (obj);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the sizes held in the object data. We need this for a fast reference.
|
||||||
|
*/
|
||||||
|
obj->text_size = text_size;
|
||||||
|
obj->eh_size = eh_size;
|
||||||
|
obj->bss_size = bss_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let the allocator manage the actual allocation. The user can use the
|
* Let the allocator manage the actual allocation. The user can use the
|
||||||
* standard heap or provide a specific allocator with memory protection.
|
* standard heap or provide a specific allocator with memory protection.
|
||||||
*/
|
*/
|
||||||
if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size,
|
if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size,
|
||||||
&obj->const_base, const_size,
|
&obj->const_base, const_size,
|
||||||
|
&obj->eh_base, eh_size,
|
||||||
&obj->data_base, data_size,
|
&obj->data_base, data_size,
|
||||||
&obj->bss_base, bss_size))
|
&obj->bss_base, bss_size))
|
||||||
{
|
{
|
||||||
@@ -720,7 +856,7 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj->exec_size = text_size + const_size + data_size + bss_size;
|
obj->exec_size = text_size + const_size + eh_size + data_size + bss_size;
|
||||||
|
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
|
||||||
{
|
{
|
||||||
@@ -728,12 +864,22 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj,
|
|||||||
obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj));
|
obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj));
|
||||||
printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n",
|
printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n",
|
||||||
obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj));
|
obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj));
|
||||||
|
printf ("rtl: load sect: eh - b:%p s:%zi a:%" PRIu32 "\n",
|
||||||
|
obj->eh_base, eh_size, rtems_rtl_obj_eh_alignment (obj));
|
||||||
printf ("rtl: load sect: data - b:%p s:%zi a:%" PRIu32 "\n",
|
printf ("rtl: load sect: data - b:%p s:%zi a:%" PRIu32 "\n",
|
||||||
obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj));
|
obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj));
|
||||||
printf ("rtl: load sect: bss - b:%p s:%zi a:%" PRIu32 "\n",
|
printf ("rtl: load sect: bss - b:%p s:%zi a:%" PRIu32 "\n",
|
||||||
obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj));
|
obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the load order.
|
||||||
|
*/
|
||||||
|
rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_TEXT, obj);
|
||||||
|
rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_CONST, obj);
|
||||||
|
rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_EH, obj);
|
||||||
|
rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_DATA, obj);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load all text then data then bss sections in seperate operations so each
|
* Load all text then data then bss sections in seperate operations so each
|
||||||
* type of section is grouped together.
|
* type of section is grouped together.
|
||||||
@@ -742,12 +888,14 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj,
|
|||||||
obj, fd, obj->text_base, handler, data) ||
|
obj, fd, obj->text_base, handler, data) ||
|
||||||
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST,
|
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST,
|
||||||
obj, fd, obj->const_base, handler, data) ||
|
obj, fd, obj->const_base, handler, data) ||
|
||||||
|
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_EH,
|
||||||
|
obj, fd, obj->eh_base, handler, data) ||
|
||||||
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA,
|
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA,
|
||||||
obj, fd, obj->data_base, handler, data) ||
|
obj, fd, obj->data_base, handler, data) ||
|
||||||
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS,
|
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS,
|
||||||
obj, fd, obj->bss_base, handler, data))
|
obj, fd, obj->bss_base, handler, data))
|
||||||
{
|
{
|
||||||
rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
|
rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->eh_base,
|
||||||
&obj->data_base, &obj->bss_base);
|
&obj->data_base, &obj->bss_base);
|
||||||
obj->exec_size = 0;
|
obj->exec_size = 0;
|
||||||
return false;
|
return false;
|
||||||
@@ -972,7 +1120,7 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
|
|||||||
* name from the table and compare with the name we are after.
|
* name from the table and compare with the name we are after.
|
||||||
*/
|
*/
|
||||||
#define RTEMS_RTL_MAX_FILE_SIZE (256)
|
#define RTEMS_RTL_MAX_FILE_SIZE (256)
|
||||||
char name[RTEMS_RTL_MAX_FILE_SIZE];
|
char name[RTEMS_RTL_MAX_FILE_SIZE];
|
||||||
|
|
||||||
if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off,
|
if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off,
|
||||||
RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0]))
|
RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0]))
|
||||||
@@ -1016,7 +1164,7 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
|
rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
|
||||||
{
|
{
|
||||||
int l;
|
int l;
|
||||||
@@ -1024,13 +1172,24 @@ rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
|
|||||||
for (l = 0; l < (sizeof (loaders) / sizeof (rtems_rtl_loader_table_t)); ++l)
|
for (l = 0; l < (sizeof (loaders) / sizeof (rtems_rtl_loader_table_t)); ++l)
|
||||||
{
|
{
|
||||||
if (loaders[l].check (obj, fd))
|
if (loaders[l].check (obj, fd))
|
||||||
|
{
|
||||||
|
obj->format = l;
|
||||||
return loaders[l].load (obj, fd);
|
return loaders[l].load (obj, fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_rtl_set_error (ENOENT, "no format loader found");
|
rtems_rtl_set_error (ENOENT, "no format loader found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
rtems_rtl_obj_file_unload (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS)
|
||||||
|
return loaders[obj->format].unload (obj);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
@@ -1057,20 +1216,16 @@ rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
|
|||||||
{
|
{
|
||||||
if (!rtems_rtl_obj_archive_find (obj, fd))
|
if (!rtems_rtl_obj_archive_find (obj, fd))
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_caches_flush ();
|
|
||||||
close (fd);
|
close (fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call the format specific loader. Currently this is a call to the ELF
|
* Call the format specific loader.
|
||||||
* loader. This call could be changed to allow probes then calls if more than
|
|
||||||
* one format is supported.
|
|
||||||
*/
|
*/
|
||||||
if (!rtems_rtl_obj_file_load (obj, fd))
|
if (!rtems_rtl_obj_file_load (obj, fd))
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_caches_flush ();
|
|
||||||
close (fd);
|
close (fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1081,8 +1236,6 @@ rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_rtl_obj_caches_flush ();
|
|
||||||
|
|
||||||
close (fd);
|
close (fd);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1092,6 +1245,6 @@ bool
|
|||||||
rtems_rtl_obj_unload (rtems_rtl_obj_t* obj)
|
rtems_rtl_obj_unload (rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
_rtld_linkmap_delete(obj);
|
_rtld_linkmap_delete(obj);
|
||||||
rtems_rtl_symbol_obj_erase (obj);
|
rtems_rtl_obj_file_unload (obj);
|
||||||
return rtems_rtl_obj_free (obj);
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,14 +56,20 @@ typedef struct rtems_rtl_loader_format_s
|
|||||||
typedef bool (*rtems_rtl_loader_check) (rtems_rtl_obj_t* obj, int fd);
|
typedef bool (*rtems_rtl_loader_check) (rtems_rtl_obj_t* obj, int fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the format loader handler. This handler loads the specific
|
* The type of the format loader load handler. This handler loads the specific
|
||||||
* format.
|
* format.
|
||||||
*/
|
*/
|
||||||
typedef bool (*rtems_rtl_loader_load) (rtems_rtl_obj_t* obj, int fd);
|
typedef bool (*rtems_rtl_loader_load) (rtems_rtl_obj_t* obj, int fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the format loader handler. This handler loads the specific
|
* The type of the format loader unload handler. This handler unloads the
|
||||||
* format.
|
* specific format.
|
||||||
|
*/
|
||||||
|
typedef bool (*rtems_rtl_loader_unload) (rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the format loader signature handler. This handler checks the
|
||||||
|
* format signature.
|
||||||
*/
|
*/
|
||||||
typedef rtems_rtl_loader_format_t* (*rtems_rtl_loader_sig) (void);
|
typedef rtems_rtl_loader_format_t* (*rtems_rtl_loader_sig) (void);
|
||||||
|
|
||||||
@@ -72,9 +78,10 @@ typedef rtems_rtl_loader_format_t* (*rtems_rtl_loader_sig) (void);
|
|||||||
*/
|
*/
|
||||||
typedef struct rtems_rtl_loader_table_s
|
typedef struct rtems_rtl_loader_table_s
|
||||||
{
|
{
|
||||||
rtems_rtl_loader_check check; /**< The check handler. */
|
rtems_rtl_loader_check check; /**< The check handler. */
|
||||||
rtems_rtl_loader_load load; /**< The loader. */
|
rtems_rtl_loader_load load; /**< The loader. */
|
||||||
rtems_rtl_loader_sig signature; /**< The loader's signature. */
|
rtems_rtl_loader_unload unload; /**< The unloader. */
|
||||||
|
rtems_rtl_loader_sig signature; /**< The loader's signature. */
|
||||||
} rtems_rtl_loader_table_t;
|
} rtems_rtl_loader_table_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,18 +91,30 @@ typedef struct rtems_rtl_loader_table_s
|
|||||||
#define RTEMS_RTL_OBJ_SECT_CONST (1 << 1) /**< Section holds program text. */
|
#define RTEMS_RTL_OBJ_SECT_CONST (1 << 1) /**< Section holds program text. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_DATA (1 << 2) /**< Section holds program data. */
|
#define RTEMS_RTL_OBJ_SECT_DATA (1 << 2) /**< Section holds program data. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_BSS (1 << 3) /**< Section holds program bss. */
|
#define RTEMS_RTL_OBJ_SECT_BSS (1 << 3) /**< Section holds program bss. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_REL (1 << 4) /**< Section holds relocation records. */
|
#define RTEMS_RTL_OBJ_SECT_EH (1 << 4) /**< Section holds exception data. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_RELA (1 << 5) /**< Section holds relocation addend
|
#define RTEMS_RTL_OBJ_SECT_REL (1 << 5) /**< Section holds relocation records. */
|
||||||
|
#define RTEMS_RTL_OBJ_SECT_RELA (1 << 6) /**< Section holds relocation addend
|
||||||
* records. */
|
* records. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_SYM (1 << 6) /**< Section holds symbols. */
|
#define RTEMS_RTL_OBJ_SECT_SYM (1 << 7) /**< Section holds symbols. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_STR (1 << 7) /**< Section holds strings. */
|
#define RTEMS_RTL_OBJ_SECT_STR (1 << 8) /**< Section holds strings. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 8) /**< Section allocates runtime memory. */
|
#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 9) /**< Section allocates runtime memory. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_LOAD (1 << 9) /**< Section is loaded from object file. */
|
#define RTEMS_RTL_OBJ_SECT_LOAD (1 << 10) /**< Section is loaded from object file. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 10) /**< Section is writable, ie data. */
|
#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 11) /**< Section is writable, ie data. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_EXEC (1 << 11) /**< Section is executable. */
|
#define RTEMS_RTL_OBJ_SECT_EXEC (1 << 12) /**< Section is executable. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_ZERO (1 << 12) /**< Section is preset to zero. */
|
#define RTEMS_RTL_OBJ_SECT_ZERO (1 << 13) /**< Section is preset to zero. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_CTOR (1 << 13) /**< Section contains constructors. */
|
#define RTEMS_RTL_OBJ_SECT_LINK (1 << 14) /**< Section is link-ordered. */
|
||||||
#define RTEMS_RTL_OBJ_SECT_DTOR (1 << 14) /**< Section contains destructors. */
|
#define RTEMS_RTL_OBJ_SECT_CTOR (1 << 15) /**< Section contains constructors. */
|
||||||
|
#define RTEMS_RTL_OBJ_SECT_DTOR (1 << 16) /**< Section contains destructors. */
|
||||||
|
#define RTEMS_RTL_OBJ_SECT_LOCD (1 << 17) /**< Section has been located. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Section types mask.
|
||||||
|
*/
|
||||||
|
#define RTEMS_RTL_OBJ_SECT_TYPES (RTEMS_RTL_OBJ_SECT_TEXT | \
|
||||||
|
RTEMS_RTL_OBJ_SECT_CONST | \
|
||||||
|
RTEMS_RTL_OBJ_SECT_DATA | \
|
||||||
|
RTEMS_RTL_OBJ_SECT_BSS | \
|
||||||
|
RTEMS_RTL_OBJ_SECT_EH)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object file is made up of sections and the can be more than
|
* An object file is made up of sections and the can be more than
|
||||||
@@ -109,13 +128,14 @@ struct rtems_rtl_obj_sect_s
|
|||||||
const char* name; /**< The section's name. */
|
const char* name; /**< The section's name. */
|
||||||
size_t size; /**< The size of the section in memory. */
|
size_t size; /**< The size of the section in memory. */
|
||||||
off_t offset; /**< Offset into the object file. Relative to
|
off_t offset; /**< Offset into the object file. Relative to
|
||||||
* the start of the object file. */
|
* the start of the object file. */
|
||||||
uint32_t alignment; /**< Alignment of this section. */
|
uint32_t alignment; /**< Alignment of this section. */
|
||||||
int link; /**< Section link field. */
|
int link; /**< Section link field. */
|
||||||
int info; /**< Secfion info field. */
|
int info; /**< Secfion info field. */
|
||||||
uint32_t flags; /**< The section's flags. */
|
uint32_t flags; /**< The section's flags. */
|
||||||
void* base; /**< The base address of the section in
|
void* base; /**< The base address of the section in
|
||||||
* memory. */
|
* memory. */
|
||||||
|
int load_order; /**< Order we load sections. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,6 +155,7 @@ struct rtems_rtl_obj_s
|
|||||||
rtems_chain_node link; /**< The node's link in the chain. */
|
rtems_chain_node link; /**< The node's link in the chain. */
|
||||||
uint32_t flags; /**< The status of the object file. */
|
uint32_t flags; /**< The status of the object file. */
|
||||||
uint32_t users; /**< References to the object file. */
|
uint32_t users; /**< References to the object file. */
|
||||||
|
int format; /**< The format of the object file. */
|
||||||
const char* fname; /**< The file name for the object. */
|
const char* fname; /**< The file name for the object. */
|
||||||
const char* oname; /**< The object file name. Can be
|
const char* oname; /**< The object file name. Can be
|
||||||
* relative. */
|
* relative. */
|
||||||
@@ -153,26 +174,27 @@ struct rtems_rtl_obj_s
|
|||||||
size_t global_size; /**< Global symbol memory usage. */
|
size_t global_size; /**< Global symbol memory usage. */
|
||||||
uint32_t unresolved; /**< The number of unresolved relocations. */
|
uint32_t unresolved; /**< The number of unresolved relocations. */
|
||||||
void* text_base; /**< The base address of the text section
|
void* text_base; /**< The base address of the text section
|
||||||
* in memory. */
|
* in memory. */
|
||||||
|
size_t text_size; /**< The size of the text section. */
|
||||||
void* const_base; /**< The base address of the const section
|
void* const_base; /**< The base address of the const section
|
||||||
* in memory. */
|
* in memory. */
|
||||||
|
void* eh_base; /**< The base address of the eh section
|
||||||
|
* in memory. */
|
||||||
|
size_t eh_size; /**< The size of the eh section. */
|
||||||
void* data_base; /**< The base address of the data section
|
void* data_base; /**< The base address of the data section
|
||||||
* in memory. */
|
* in memory. */
|
||||||
void* bss_base; /**< The base address of the bss section
|
void* bss_base; /**< The base address of the bss section
|
||||||
* in memory. */
|
* in memory. */
|
||||||
size_t bss_size; /**< The size of the bss section. */
|
size_t bss_size; /**< The size of the bss section. */
|
||||||
size_t exec_size; /**< The amount of executable memory
|
size_t exec_size; /**< The amount of executable memory
|
||||||
* allocated */
|
* allocated */
|
||||||
void* entry; /**< The entry point of the module. */
|
void* entry; /**< The entry point of the module. */
|
||||||
uint32_t checksum; /**< The checksum of the text sections. A
|
uint32_t checksum; /**< The checksum of the text sections. A
|
||||||
* zero means do not checksum. */
|
* zero means do not checksum. */
|
||||||
void* detail; /**< The file details. It contains the elf file
|
|
||||||
* detail, mainly including elf file name,
|
|
||||||
* section offset, section size, which
|
|
||||||
* elf this section belongs to.*/
|
|
||||||
uint32_t* sec_num; /**< The sec nums of each obj. */
|
uint32_t* sec_num; /**< The sec nums of each obj. */
|
||||||
uint32_t obj_num; /**< The count of elf files in an rtl obj. */
|
uint32_t obj_num; /**< The count of elf files in an rtl obj. */
|
||||||
struct link_map* linkmap; /**< For GDB. */
|
struct link_map* linkmap; /**< For GDB. */
|
||||||
|
void* loader; /**< The file details specific to a loader. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -257,6 +279,20 @@ static inline bool rtems_rtl_obj_aname_valid (const rtems_rtl_obj_t* obj)
|
|||||||
return obj->aname;
|
return obj->aname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the address inside the text section?
|
||||||
|
*
|
||||||
|
* @param obj The object file.
|
||||||
|
* @return bool There is an archive name
|
||||||
|
*/
|
||||||
|
static inline bool rtems_rtl_obj_text_inside (const rtems_rtl_obj_t* obj,
|
||||||
|
const void* address)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(address >= obj->text_base) &&
|
||||||
|
(address < (obj->text_base + obj->text_size));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate an object structure on the heap.
|
* Allocate an object structure on the heap.
|
||||||
*
|
*
|
||||||
@@ -299,18 +335,6 @@ bool rtems_rtl_parse_name (const char* name,
|
|||||||
const char** oname,
|
const char** oname,
|
||||||
off_t* ooffset);
|
off_t* ooffset);
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the object file.
|
|
||||||
*
|
|
||||||
* @param obj The object file's descriptor.
|
|
||||||
* @param fd The file descriptor.
|
|
||||||
* @param load_syms Load symbols.
|
|
||||||
* @param load_dep Load dependent object files.
|
|
||||||
* @retval true The load was successful.
|
|
||||||
* @retval false The load failed. The RTL error has been set.
|
|
||||||
*/
|
|
||||||
bool rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check of the name matches the object file's object name.
|
* Check of the name matches the object file's object name.
|
||||||
*
|
*
|
||||||
@@ -371,8 +395,8 @@ void rtems_rtl_obj_erase_sections (rtems_rtl_obj_t* obj);
|
|||||||
* @retval NULL The section was not found.
|
* @retval NULL The section was not found.
|
||||||
* @return rtems_rtl_obj_sect_t* The named section.
|
* @return rtems_rtl_obj_sect_t* The named section.
|
||||||
*/
|
*/
|
||||||
rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj,
|
rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (const rtems_rtl_obj_t* obj,
|
||||||
const char* name);
|
const char* name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a section given a section's index number.
|
* Find a section given a section's index number.
|
||||||
@@ -382,21 +406,21 @@ rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj,
|
|||||||
* @retval NULL The section was not found.
|
* @retval NULL The section was not found.
|
||||||
* @return rtems_rtl_obj_sect_t* The found section.
|
* @return rtems_rtl_obj_sect_t* The found section.
|
||||||
*/
|
*/
|
||||||
rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section_by_index (rtems_rtl_obj_t* obj,
|
rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj_t* obj,
|
||||||
int index);
|
int index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The text size of the object file. Only use once all the sections has been
|
* The text section size. Only use once all the sections has been added. It
|
||||||
* added. It includes alignments between sections that are part of the object's
|
* includes alignments between sections that are part of the object's text
|
||||||
* text area. The consts sections are included in this section.
|
* area. The consts sections are included in this section.
|
||||||
*
|
*
|
||||||
* @param obj The object file's descriptor.
|
* @param obj The object file's descriptor.
|
||||||
* @return size_t The size of the text area of the object file.
|
* @return size_t The size of the text area of the object file.
|
||||||
*/
|
*/
|
||||||
size_t rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj);
|
size_t rtems_rtl_obj_text_size (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The text section alignment of the object file. Only use once all the
|
* The text section alignment for the object file. Only use once all the
|
||||||
* sections has been added. The section alignment is the alignment of the first
|
* sections has been added. The section alignment is the alignment of the first
|
||||||
* text type section loaded the text section.
|
* text type section loaded the text section.
|
||||||
*
|
*
|
||||||
@@ -406,20 +430,20 @@ size_t rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj);
|
|||||||
* @param obj The object file's descriptor.
|
* @param obj The object file's descriptor.
|
||||||
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
||||||
*/
|
*/
|
||||||
uint32_t rtems_rtl_obj_text_alignment (rtems_rtl_obj_t* obj);
|
uint32_t rtems_rtl_obj_text_alignment (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The const size of the object file. Only use once all the sections has been
|
* The const section size. Only use once all the sections has been added. It
|
||||||
* added. It includes alignments between sections that are part of the object's
|
* includes alignments between sections that are part of the object's const
|
||||||
* const area. The consts sections are included in this section.
|
* area. The consts sections are included in this section.
|
||||||
*
|
*
|
||||||
* @param obj The object file's descriptor.
|
* @param obj The object file's descriptor.
|
||||||
* @return size_t The size of the const area of the object file.
|
* @return size_t The size of the const area of the object file.
|
||||||
*/
|
*/
|
||||||
size_t rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj);
|
size_t rtems_rtl_obj_const_size (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The const section alignment of the object file. Only use once all the
|
* The const section alignment for the object file. Only use once all the
|
||||||
* sections has been added. The section alignment is the alignment of the first
|
* sections has been added. The section alignment is the alignment of the first
|
||||||
* const type section loaded the const section.
|
* const type section loaded the const section.
|
||||||
*
|
*
|
||||||
@@ -429,20 +453,42 @@ size_t rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj);
|
|||||||
* @param obj The object file's descriptor.
|
* @param obj The object file's descriptor.
|
||||||
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
||||||
*/
|
*/
|
||||||
uint32_t rtems_rtl_obj_const_alignment (rtems_rtl_obj_t* obj);
|
uint32_t rtems_rtl_obj_const_alignment (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data size of the object file. Only use once all the sections has been
|
* The eh section size. Only use once all the sections has been added. It
|
||||||
* added. It includes alignments between sections that are part of the object's
|
* includes alignments between sections that are part of the object's bss area.
|
||||||
* data area.
|
*
|
||||||
|
* @param obj The object file's descriptor.
|
||||||
|
* @return size_t The size of the bss area of the object file.
|
||||||
|
*/
|
||||||
|
size_t rtems_rtl_obj_eh_size (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The eh section alignment for the object file. Only use once all the sections
|
||||||
|
* has been added. The section alignment is the alignment of the first bss type
|
||||||
|
* section loaded the bss section.
|
||||||
|
*
|
||||||
|
* You can assume the alignment is a positive integral power of 2 if not 0 or
|
||||||
|
* 1. If 0 or 1 then there is no alignment.
|
||||||
|
*
|
||||||
|
* @param obj The object file's descriptor.
|
||||||
|
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
||||||
|
*/
|
||||||
|
uint32_t rtems_rtl_obj_eh_alignment (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data section size. Only use once all the sections has been added. It
|
||||||
|
* includes alignments between sections that are part of the object's data
|
||||||
|
* area.
|
||||||
*
|
*
|
||||||
* @param obj The object file's descriptor.
|
* @param obj The object file's descriptor.
|
||||||
* @return size_t The size of the data area of the object file.
|
* @return size_t The size of the data area of the object file.
|
||||||
*/
|
*/
|
||||||
size_t rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj);
|
size_t rtems_rtl_obj_data_size (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data section alignment of the object file. Only use once all the
|
* The data section alignment for the object file. Only use once all the
|
||||||
* sections has been added. The section alignment is the alignment of the first
|
* sections has been added. The section alignment is the alignment of the first
|
||||||
* data type section loaded the data section.
|
* data type section loaded the data section.
|
||||||
*
|
*
|
||||||
@@ -452,20 +498,19 @@ size_t rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj);
|
|||||||
* @param obj The object file's descriptor.
|
* @param obj The object file's descriptor.
|
||||||
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
||||||
*/
|
*/
|
||||||
uint32_t rtems_rtl_obj_data_alignment (rtems_rtl_obj_t* obj);
|
uint32_t rtems_rtl_obj_data_alignment (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The bss size of the object file. Only use once all the sections has been
|
* The bss section size. Only use once all the sections has been added. It
|
||||||
* added. It includes alignments between sections that are part of the object's
|
* includes alignments between sections that are part of the object's bss area.
|
||||||
* bss area.
|
|
||||||
*
|
*
|
||||||
* @param obj The object file's descriptor.
|
* @param obj The object file's descriptor.
|
||||||
* @return size_t The size of the bss area of the object file.
|
* @return size_t The size of the bss area of the object file.
|
||||||
*/
|
*/
|
||||||
size_t rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj);
|
size_t rtems_rtl_obj_bss_size (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The bss section alignment of the object file. Only use once all the
|
* The bss section alignment for the object file. Only use once all the
|
||||||
* sections has been added. The section alignment is the alignment of the first
|
* sections has been added. The section alignment is the alignment of the first
|
||||||
* bss type section loaded the bss section.
|
* bss type section loaded the bss section.
|
||||||
*
|
*
|
||||||
@@ -475,7 +520,7 @@ size_t rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj);
|
|||||||
* @param obj The object file's descriptor.
|
* @param obj The object file's descriptor.
|
||||||
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
* @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
|
||||||
*/
|
*/
|
||||||
uint32_t rtems_rtl_obj_bss_alignment (rtems_rtl_obj_t* obj);
|
uint32_t rtems_rtl_obj_bss_alignment (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Relocate the object file. The object file's section are parsed for any
|
* Relocate the object file. The object file's section are parsed for any
|
||||||
|
|||||||
@@ -427,20 +427,22 @@ rtems_rtl_rap_relocate (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The structure of obj->detail is
|
* The structure of obj->linkmap is:
|
||||||
*
|
*
|
||||||
* |object_detail(0..obj_num)|section_detail(0..sec_num[0..obj_num])|
|
* |object_detail(0..obj_num)|section_detail(0..sec_num[0..obj_num])|
|
||||||
* obj_name(0..obj_num)|section_name(0..sec_num[0..obj_num])
|
* obj_name(0..obj_num)|section_name(0..sec_num[0..obj_num])
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
|
rtems_rtl_rap_load_linkmap (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
|
||||||
{
|
{
|
||||||
|
void* detail;
|
||||||
struct link_map* tmp1;
|
struct link_map* tmp1;
|
||||||
section_detail* tmp2;
|
section_detail* tmp2;
|
||||||
uint32_t obj_detail_size;
|
uint32_t obj_detail_size;
|
||||||
uint32_t pos = 0;
|
uint32_t pos = 0;
|
||||||
int i,j;
|
int i;
|
||||||
|
int j;
|
||||||
|
|
||||||
obj_detail_size = sizeof (struct link_map) * obj->obj_num;
|
obj_detail_size = sizeof (struct link_map) * obj->obj_num;
|
||||||
|
|
||||||
@@ -449,26 +451,31 @@ rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
|
|||||||
obj_detail_size += (obj->sec_num[i] * sizeof (section_detail));
|
obj_detail_size += (obj->sec_num[i] * sizeof (section_detail));
|
||||||
}
|
}
|
||||||
|
|
||||||
obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||||
obj_detail_size + rap->strtable_size, true);
|
obj_detail_size + rap->strtable_size, true);
|
||||||
|
|
||||||
if (!obj->detail)
|
if (!detail)
|
||||||
{
|
{
|
||||||
rap->strtable_size = 0;
|
rap->strtable_size = 0;
|
||||||
rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
|
rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rap->strtable = obj->detail + obj_detail_size;
|
rap->strtable = detail + obj_detail_size;
|
||||||
|
|
||||||
/* Read the obj names and section names */
|
/*
|
||||||
if (!rtems_rtl_obj_comp_read (rap->decomp, rap->strtable,
|
* Read the obj names and section names
|
||||||
|
*/
|
||||||
|
if (!rtems_rtl_obj_comp_read (rap->decomp,
|
||||||
|
rap->strtable,
|
||||||
rap->strtable_size))
|
rap->strtable_size))
|
||||||
{
|
{
|
||||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj->detail);
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, detail);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj->linkmap = (struct link_map*) detail;
|
||||||
|
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||||
{
|
{
|
||||||
if (rap->rpathlen > 0)
|
if (rap->rpathlen > 0)
|
||||||
@@ -489,7 +496,7 @@ rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
|
|||||||
|
|
||||||
for (i = 0; i < obj->obj_num; ++i)
|
for (i = 0; i < obj->obj_num; ++i)
|
||||||
{
|
{
|
||||||
tmp1 = (struct link_map*) (obj->detail) + i;
|
tmp1 = obj->linkmap + i;
|
||||||
tmp1->name = rap->strtable + pos;
|
tmp1->name = rap->strtable + pos;
|
||||||
tmp1->sec_num = obj->sec_num[i];
|
tmp1->sec_num = obj->sec_num[i];
|
||||||
tmp1->rpathlen = rap->rpathlen;
|
tmp1->rpathlen = rap->rpathlen;
|
||||||
@@ -509,17 +516,17 @@ rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp2 =(section_detail*) ((struct link_map*) (obj->detail) + obj->obj_num);
|
tmp2 = (section_detail*) (obj->linkmap + obj->obj_num);
|
||||||
|
|
||||||
for (i = 0; i < obj->obj_num; ++i)
|
for (i = 0; i < obj->obj_num; ++i)
|
||||||
{
|
{
|
||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||||
{
|
{
|
||||||
printf ("File %d: %s\n", i, ((struct link_map*) obj->detail + i)->name);
|
printf ("File %d: %s\n", i, (obj->linkmap + i)->name);
|
||||||
printf ("Section: %d sections\n",(unsigned int) obj->sec_num[i]);
|
printf ("Section: %d sections\n", (unsigned int) obj->sec_num[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
((struct link_map*)obj->detail + i)->sec_detail = tmp2;
|
obj->linkmap[i].sec_detail = tmp2;
|
||||||
|
|
||||||
for (j = 0; j < obj->sec_num[i]; ++j)
|
for (j = 0; j < obj->sec_num[i]; ++j)
|
||||||
{
|
{
|
||||||
@@ -532,7 +539,8 @@ rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
|
|||||||
!rtems_rtl_rap_read_uint32 (rap->decomp, &offset) ||
|
!rtems_rtl_rap_read_uint32 (rap->decomp, &offset) ||
|
||||||
!rtems_rtl_rap_read_uint32 (rap->decomp, &size))
|
!rtems_rtl_rap_read_uint32 (rap->decomp, &size))
|
||||||
{
|
{
|
||||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->detail);
|
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->linkmap);
|
||||||
|
obj->linkmap = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,7 +915,7 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
|
|||||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||||
printf ("rtl: rap: details: obj_num=%lu\n", obj->obj_num);
|
printf ("rtl: rap: details: obj_num=%lu\n", obj->obj_num);
|
||||||
|
|
||||||
if (!rtems_rtl_rap_load_details (&rap, obj))
|
if (!rtems_rtl_rap_load_linkmap (&rap, obj))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,6 +983,13 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_rap_file_unload (rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
(void) obj;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
rtems_rtl_loader_format_t*
|
rtems_rtl_loader_format_t*
|
||||||
rtems_rtl_rap_file_sig (void)
|
rtems_rtl_rap_file_sig (void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ bool rtems_rtl_rap_file_check (rtems_rtl_obj_t* obj, int fd);
|
|||||||
*/
|
*/
|
||||||
bool rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd);
|
bool rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The RAP format unload handler.
|
||||||
|
*
|
||||||
|
* @param obj The object to unload.
|
||||||
|
*/
|
||||||
|
bool rtems_rtl_rap_file_unload (rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The RAP format signature handler.
|
* The RAP format signature handler.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
* Flag the targets where off_t is 32 bits. This is not a compiler type
|
* Flag the targets where off_t is 32 bits. This is not a compiler type
|
||||||
* so we can't rely on prerdefines.
|
* so we can't rely on prerdefines.
|
||||||
*/
|
*/
|
||||||
#if defined(__m32r__) || defined(__moxie__)
|
#if defined(__moxie__)
|
||||||
#define PRIdoff_t PRIo32
|
#define PRIdoff_t PRIo32
|
||||||
#else
|
#else
|
||||||
#define PRIdoff_t PRIo64
|
#define PRIdoff_t PRIo64
|
||||||
|
|||||||
71
cpukit/libdl/rtl-unwind-dw2.c
Normal file
71
cpukit/libdl/rtl-unwind-dw2.c
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* COPYRIGHT (c) 2012-2016 Chris Johns <chrisj@rtems.org>
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.rtems.org/license/LICENSE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @ingroup rtems_rtld
|
||||||
|
*
|
||||||
|
* @brief RTEMS Run-Time Link Editor
|
||||||
|
*
|
||||||
|
* This is the RTL implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <rtems/rtl/rtl.h>
|
||||||
|
#include "rtl-elf.h"
|
||||||
|
#include "rtl-error.h"
|
||||||
|
#include "rtl-unwind.h"
|
||||||
|
#include "rtl-unwind-dw2.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These interfaces are not exported outside the GCC source.
|
||||||
|
*/
|
||||||
|
void __register_frame (void *begin);
|
||||||
|
void __deregister_frame (void *begin);
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_dw2_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
((flags & RTEMS_RTL_OBJ_SECT_CONST) != 0) &&
|
||||||
|
((strcmp(name, ".eh_frame") == 0) ||
|
||||||
|
(strncmp(name, ".gcc_except_table.", sizeof (".gcc_except_table.") - 1) == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
rtems_rtl_elf_unwind_dw2_register (const rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
rtems_rtl_obj_sect_t* sect = rtems_rtl_obj_find_section (obj, ".eh_frame");
|
||||||
|
|
||||||
|
if (sect != NULL && sect->size > 0 && sect->base != NULL)
|
||||||
|
{
|
||||||
|
__register_frame (sect->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rtems_rtl_elf_unwind_dw2_deregister (const rtems_rtl_obj_t* obj)
|
||||||
|
{
|
||||||
|
rtems_rtl_obj_sect_t* sect = rtems_rtl_obj_find_section (obj, ".eh_frame");
|
||||||
|
|
||||||
|
if (sect != NULL && sect->size > 0 && sect->base != NULL)
|
||||||
|
{
|
||||||
|
__deregister_frame (sect->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
83
cpukit/libdl/rtl-unwind-dw2.h
Normal file
83
cpukit/libdl/rtl-unwind-dw2.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* COPYRIGHT (c) 2016 Chris Johns <chrisj@rtems.org>
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.rtems.org/license/LICENSE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @ingroup rtems_rtl
|
||||||
|
*
|
||||||
|
* @brief RTEMS Run-Time Linker Unwind DWARF Support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined (_RTEMS_RTL_UNWIND_DW2_H_)
|
||||||
|
#define _RTEMS_RTL_UNWIND_DW2_H_
|
||||||
|
|
||||||
|
#include "rtl-elf.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#if __SIZEOF_LONG__ >= __SIZEOF_POINTER__
|
||||||
|
typedef long rtems_rtl_elf_unwind_dw2_sleb128;
|
||||||
|
typedef unsigned long rtems_rtl_elf_unwind_dw2_uleb128;
|
||||||
|
#elif __SIZEOF_LONG_LONG__ >= __SIZEOF_POINTER__
|
||||||
|
typedef long long rtems_rtl_elf_unwind_dw2_sleb128;
|
||||||
|
typedef unsigned long long rtems_rtl_elf_unwind_dw2_uleb128;
|
||||||
|
#else
|
||||||
|
#error No DW2 type available.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Architecture specific handler to check if a section contains exception
|
||||||
|
* handler data..
|
||||||
|
*
|
||||||
|
* @param obj The object file.
|
||||||
|
* @param name The section's name.
|
||||||
|
* @param uint32 flags The object file's flags.
|
||||||
|
* @retval true The section contains unwind information.
|
||||||
|
* @retval false The section does not contain unwind information.
|
||||||
|
*/
|
||||||
|
bool rtems_rtl_elf_unwind_dw2_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Architecture specific handler to add an object file's unwind information to
|
||||||
|
* the base image.
|
||||||
|
*
|
||||||
|
* @param obj The object file.
|
||||||
|
* @retval true The unwind information has been registered.
|
||||||
|
* @retval false The unwind information could not be registered.
|
||||||
|
*/
|
||||||
|
bool rtems_rtl_elf_unwind_dw2_register (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Architecture specific handler to remove an object file's unwind information
|
||||||
|
* from the base image.
|
||||||
|
*
|
||||||
|
* @param obj The object file.
|
||||||
|
* @retval true The unwind information has been deregistered.
|
||||||
|
* @retval false The unwind information could not be deregistered.
|
||||||
|
*/
|
||||||
|
bool rtems_rtl_elf_unwind_dw2_deregister (const rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read signed and unsigned LEB128 values.
|
||||||
|
*/
|
||||||
|
const uint8_t* rtems_rtl_elf_unwind_dw2_read_uleb128 (const uint8_t* data,
|
||||||
|
rtems_rtl_elf_unwind_dw2_uleb128* val);
|
||||||
|
const uint8_t* rtems_rtl_elf_unwind_dw2_read_sleb128 (const uint8_t* data,
|
||||||
|
rtems_rtl_elf_unwind_dw2_sleb128* val);
|
||||||
|
|
||||||
|
bool rtems_rtl_elf_unwind_dw2_relocate (const Elf_Addr* where, Elf_Word value, Elf_Word mask);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
63
cpukit/libdl/rtl-unwind.h
Normal file
63
cpukit/libdl/rtl-unwind.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* COPYRIGHT (c) 2016 Chris Johns <chrisj@rtems.org>
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.rtems.org/license/LICENSE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @ingroup rtems_rtl
|
||||||
|
*
|
||||||
|
* @brief RTEMS Run-Time Linker Unwind Support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined (_RTEMS_RTL_UNWIND_H_)
|
||||||
|
#define _RTEMS_RTL_UNWIND_H_
|
||||||
|
|
||||||
|
#include "rtl-elf.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Architecture specific handler to check if a section contains exception
|
||||||
|
* handler data..
|
||||||
|
*
|
||||||
|
* @param obj The object file.
|
||||||
|
* @param name The section's name.
|
||||||
|
* @param uint32 flags The object file's flags.
|
||||||
|
* @retval true The section contains unwind information.
|
||||||
|
* @retval false The section does not contain unwind information.
|
||||||
|
*/
|
||||||
|
bool rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
|
||||||
|
const char* name,
|
||||||
|
uint32_t flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Architecture specific handler to add an object file's unwind information to
|
||||||
|
* the base image.
|
||||||
|
*
|
||||||
|
* @param obj The object file.
|
||||||
|
* @retval true The unwind information has been registered.
|
||||||
|
* @retval false The unwind information could not be registered.
|
||||||
|
*/
|
||||||
|
bool rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Architecture specific handler to remove an object file's unwind information
|
||||||
|
* from the base image.
|
||||||
|
*
|
||||||
|
* @param obj The object file.
|
||||||
|
* @retval true The unwind information has been deregistered.
|
||||||
|
* @retval false The unwind information could not be deregistered.
|
||||||
|
*/
|
||||||
|
bool rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -62,6 +62,7 @@
|
|||||||
* Static RTL data is returned to the user when the linker is locked.
|
* Static RTL data is returned to the user when the linker is locked.
|
||||||
*/
|
*/
|
||||||
static rtems_rtl_data_t* rtl;
|
static rtems_rtl_data_t* rtl;
|
||||||
|
static bool rtl_data_init;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a default base global symbol loader function that is weak
|
* Define a default base global symbol loader function that is weak
|
||||||
@@ -94,12 +95,26 @@ rtems_rtl_data_init (void)
|
|||||||
rtems_status_code sc;
|
rtems_status_code sc;
|
||||||
rtems_id lock;
|
rtems_id lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We cannot set an error in this code because there is no RTL data to
|
||||||
|
* hold it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (rtl_data_init)
|
||||||
|
{
|
||||||
|
rtems_libio_unlock ();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtl_data_init = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Always in the heap.
|
* Always in the heap.
|
||||||
*/
|
*/
|
||||||
rtl = malloc (sizeof (rtems_rtl_data_t));
|
rtl = malloc (sizeof (rtems_rtl_data_t));
|
||||||
if (!rtl)
|
if (!rtl)
|
||||||
{
|
{
|
||||||
|
rtems_libio_unlock ();
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -120,6 +135,7 @@ rtems_rtl_data_init (void)
|
|||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
{
|
{
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +144,7 @@ rtems_rtl_data_init (void)
|
|||||||
{
|
{
|
||||||
rtems_semaphore_delete (lock);
|
rtems_semaphore_delete (lock);
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +160,7 @@ rtems_rtl_data_init (void)
|
|||||||
{
|
{
|
||||||
rtems_semaphore_delete (lock);
|
rtems_semaphore_delete (lock);
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +170,7 @@ rtems_rtl_data_init (void)
|
|||||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||||
rtems_semaphore_delete (lock);
|
rtems_semaphore_delete (lock);
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +181,7 @@ rtems_rtl_data_init (void)
|
|||||||
rtems_rtl_unresolved_table_close (&rtl->unresolved);
|
rtems_rtl_unresolved_table_close (&rtl->unresolved);
|
||||||
rtems_semaphore_delete (lock);
|
rtems_semaphore_delete (lock);
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +193,7 @@ rtems_rtl_data_init (void)
|
|||||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||||
rtems_semaphore_delete (lock);
|
rtems_semaphore_delete (lock);
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +206,7 @@ rtems_rtl_data_init (void)
|
|||||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||||
rtems_semaphore_delete (lock);
|
rtems_semaphore_delete (lock);
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +220,7 @@ rtems_rtl_data_init (void)
|
|||||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||||
rtems_semaphore_delete (lock);
|
rtems_semaphore_delete (lock);
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +235,7 @@ rtems_rtl_data_init (void)
|
|||||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||||
rtems_semaphore_delete (lock);
|
rtems_semaphore_delete (lock);
|
||||||
free (rtl);
|
free (rtl);
|
||||||
|
rtems_libio_unlock ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +312,7 @@ rtems_rtl_obj_caches (rtems_rtl_obj_cache_t** symbols,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rtems_rtl_obj_caches_flush ()
|
rtems_rtl_obj_caches_flush (void)
|
||||||
{
|
{
|
||||||
if (rtl)
|
if (rtl)
|
||||||
{
|
{
|
||||||
@@ -438,6 +462,7 @@ rtems_rtl_load_object (const char* name, int mode)
|
|||||||
if (!rtems_rtl_obj_find_file (obj, name))
|
if (!rtems_rtl_obj_find_file (obj, name))
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_free (obj);
|
rtems_rtl_obj_free (obj);
|
||||||
|
rtems_rtl_obj_caches_flush ();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,9 +471,12 @@ rtems_rtl_load_object (const char* name, int mode)
|
|||||||
if (!rtems_rtl_obj_load (obj))
|
if (!rtems_rtl_obj_load (obj))
|
||||||
{
|
{
|
||||||
rtems_rtl_obj_free (obj);
|
rtems_rtl_obj_free (obj);
|
||||||
|
rtems_rtl_obj_caches_flush ();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtems_rtl_obj_caches_flush ();
|
||||||
|
|
||||||
rtems_rtl_unresolved_resolve ();
|
rtems_rtl_unresolved_resolve ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,6 +542,9 @@ rtems_rtl_unload_object (rtems_rtl_obj_t* obj)
|
|||||||
obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
|
obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
|
||||||
|
|
||||||
ok = rtems_rtl_obj_unload (obj);
|
ok = rtems_rtl_obj_unload (obj);
|
||||||
|
|
||||||
|
rtems_rtl_obj_free (obj);
|
||||||
|
rtems_rtl_obj_caches_flush ();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ struct rtems_rtl_data_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the RTL data with out locking. This call assmes the RTL is locked.
|
* Get the RTL data with out locking. This call assumes the RTL is locked.
|
||||||
*
|
*
|
||||||
* @return rtems_rtl_data_t* The RTL data after being locked.
|
* @return rtems_rtl_data_t* The RTL data after being locked.
|
||||||
* @retval NULL The RTL data is not initialised.
|
* @retval NULL The RTL data is not initialised.
|
||||||
|
|||||||
@@ -200,13 +200,12 @@ _fat_block_read(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
fat_block_write(
|
fat_block_write(
|
||||||
fat_fs_info_t *fs_info,
|
fat_fs_info_t *fs_info,
|
||||||
const uint32_t start_blk,
|
const uint32_t start_blk,
|
||||||
const uint32_t offset,
|
const uint32_t offset,
|
||||||
const uint32_t count,
|
const uint32_t count,
|
||||||
const void *buf,
|
const void *buf)
|
||||||
const bool overwrite_block)
|
|
||||||
{
|
{
|
||||||
int rc = RC_OK;
|
int rc = RC_OK;
|
||||||
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bytes_per_block - offset));
|
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bytes_per_block - offset));
|
||||||
@@ -215,8 +214,7 @@ static ssize_t
|
|||||||
|
|
||||||
if (0 < bytes_to_write)
|
if (0 < bytes_to_write)
|
||||||
{
|
{
|
||||||
if ( overwrite_block
|
if (bytes_to_write == fs_info->vol.bytes_per_block)
|
||||||
|| (bytes_to_write == fs_info->vol.bytes_per_block))
|
|
||||||
{
|
{
|
||||||
rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &blk_buf);
|
rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &blk_buf);
|
||||||
}
|
}
|
||||||
@@ -399,7 +397,6 @@ _fat_block_release(fat_fs_info_t *fs_info)
|
|||||||
* offset - offset inside cluster 'start'
|
* offset - offset inside cluster 'start'
|
||||||
* count - count of bytes to write
|
* count - count of bytes to write
|
||||||
* buff - buffer provided by user
|
* buff - buffer provided by user
|
||||||
* overwrite_cluster - true if cluster can get overwritten, false if cluster content must be kept
|
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
* bytes written on success, or -1 if error occured
|
* bytes written on success, or -1 if error occured
|
||||||
@@ -411,8 +408,7 @@ fat_cluster_write(
|
|||||||
const uint32_t start_cln,
|
const uint32_t start_cln,
|
||||||
const uint32_t offset,
|
const uint32_t offset,
|
||||||
const uint32_t count,
|
const uint32_t count,
|
||||||
const void *buff,
|
const void *buff)
|
||||||
const bool overwrite_cluster)
|
|
||||||
{
|
{
|
||||||
ssize_t rc = RC_OK;
|
ssize_t rc = RC_OK;
|
||||||
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bpc - offset));
|
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bpc - offset));
|
||||||
@@ -436,8 +432,7 @@ fat_cluster_write(
|
|||||||
cur_blk,
|
cur_blk,
|
||||||
ofs_blk,
|
ofs_blk,
|
||||||
c,
|
c,
|
||||||
&buffer[bytes_written],
|
&buffer[bytes_written]);
|
||||||
overwrite_cluster);
|
|
||||||
if (c != ret)
|
if (c != ret)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -511,8 +511,7 @@ fat_cluster_write(fat_fs_info_t *fs_info,
|
|||||||
uint32_t start_cln,
|
uint32_t start_cln,
|
||||||
uint32_t offset,
|
uint32_t offset,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
const void *buff,
|
const void *buff);
|
||||||
bool overwrite_cluster);
|
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
fat_sector_write(fat_fs_info_t *fs_info,
|
fat_sector_write(fat_fs_info_t *fs_info,
|
||||||
|
|||||||
@@ -110,12 +110,10 @@ fat_file_open(
|
|||||||
/* access "removed-but-still-open" hash table */
|
/* access "removed-but-still-open" hash table */
|
||||||
rc = _hash_search(fs_info, fs_info->rhash, key, key, &lfat_fd);
|
rc = _hash_search(fs_info, fs_info->rhash, key, key, &lfat_fd);
|
||||||
|
|
||||||
lfat_fd = (*fat_fd) = (fat_file_fd_t*)malloc(sizeof(fat_file_fd_t));
|
lfat_fd = (*fat_fd) = (fat_file_fd_t*)calloc(1, sizeof(fat_file_fd_t));
|
||||||
if ( lfat_fd == NULL )
|
if ( lfat_fd == NULL )
|
||||||
rtems_set_errno_and_return_minus_one( ENOMEM );
|
rtems_set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
memset(lfat_fd, 0, sizeof(fat_file_fd_t));
|
|
||||||
|
|
||||||
lfat_fd->links_num = 1;
|
lfat_fd->links_num = 1;
|
||||||
lfat_fd->flags &= ~FAT_FILE_REMOVED;
|
lfat_fd->flags &= ~FAT_FILE_REMOVED;
|
||||||
lfat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
|
lfat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
|
||||||
@@ -403,20 +401,18 @@ static bool
|
|||||||
* start - offset(in bytes) to write from
|
* start - offset(in bytes) to write from
|
||||||
* count - count
|
* count - count
|
||||||
* buf - buffer provided by user
|
* buf - buffer provided by user
|
||||||
* file_cln_initial - initial current cluster number of the file
|
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
* number of bytes actually written to the file on success, or -1 if
|
* number of bytes actually written to the file on success, or -1 if
|
||||||
* error occured (errno set appropriately)
|
* error occured (errno set appropriately)
|
||||||
*/
|
*/
|
||||||
static ssize_t
|
static ssize_t
|
||||||
fat_file_write_fat32_or_non_root_dir(
|
fat_file_write_fat32_or_non_root_dir(
|
||||||
fat_fs_info_t *fs_info,
|
fat_fs_info_t *fs_info,
|
||||||
fat_file_fd_t *fat_fd,
|
fat_file_fd_t *fat_fd,
|
||||||
const uint32_t start,
|
const uint32_t start,
|
||||||
const uint32_t count,
|
const uint32_t count,
|
||||||
const uint8_t *buf,
|
const uint8_t *buf)
|
||||||
const uint32_t file_cln_initial)
|
|
||||||
{
|
{
|
||||||
int rc = RC_OK;
|
int rc = RC_OK;
|
||||||
uint32_t cmpltd = 0;
|
uint32_t cmpltd = 0;
|
||||||
@@ -426,35 +422,27 @@ static ssize_t
|
|||||||
uint32_t ofs_cln = start - (start_cln << fs_info->vol.bpc_log2);
|
uint32_t ofs_cln = start - (start_cln << fs_info->vol.bpc_log2);
|
||||||
uint32_t ofs_cln_save = ofs_cln;
|
uint32_t ofs_cln_save = ofs_cln;
|
||||||
uint32_t bytes_to_write = count;
|
uint32_t bytes_to_write = count;
|
||||||
uint32_t file_cln_cnt;
|
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
uint32_t c;
|
uint32_t c;
|
||||||
bool overwrite_cluster = false;
|
|
||||||
|
|
||||||
rc = fat_file_lseek(fs_info, fat_fd, start_cln, &cur_cln);
|
rc = fat_file_lseek(fs_info, fat_fd, start_cln, &cur_cln);
|
||||||
if (RC_OK == rc)
|
if (RC_OK == rc)
|
||||||
{
|
{
|
||||||
file_cln_cnt = cur_cln - fat_fd->cln;
|
|
||||||
while ( (RC_OK == rc)
|
while ( (RC_OK == rc)
|
||||||
&& (bytes_to_write > 0))
|
&& (bytes_to_write > 0))
|
||||||
{
|
{
|
||||||
c = MIN(bytes_to_write, (fs_info->vol.bpc - ofs_cln));
|
c = MIN(bytes_to_write, (fs_info->vol.bpc - ofs_cln));
|
||||||
|
|
||||||
if (file_cln_initial < file_cln_cnt)
|
|
||||||
overwrite_cluster = true;
|
|
||||||
|
|
||||||
ret = fat_cluster_write(fs_info,
|
ret = fat_cluster_write(fs_info,
|
||||||
cur_cln,
|
cur_cln,
|
||||||
ofs_cln,
|
ofs_cln,
|
||||||
c,
|
c,
|
||||||
&buf[cmpltd],
|
&buf[cmpltd]);
|
||||||
overwrite_cluster);
|
|
||||||
if (0 > ret)
|
if (0 > ret)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
|
|
||||||
if (RC_OK == rc)
|
if (RC_OK == rc)
|
||||||
{
|
{
|
||||||
++file_cln_cnt;
|
|
||||||
bytes_to_write -= ret;
|
bytes_to_write -= ret;
|
||||||
cmpltd += ret;
|
cmpltd += ret;
|
||||||
save_cln = cur_cln;
|
save_cln = cur_cln;
|
||||||
@@ -509,7 +497,6 @@ fat_file_write(
|
|||||||
uint32_t byte;
|
uint32_t byte;
|
||||||
uint32_t c = 0;
|
uint32_t c = 0;
|
||||||
bool zero_fill = start > fat_fd->fat_file_size;
|
bool zero_fill = start > fat_fd->fat_file_size;
|
||||||
uint32_t file_cln_initial = fat_fd->map.file_cln;
|
|
||||||
uint32_t cln;
|
uint32_t cln;
|
||||||
|
|
||||||
|
|
||||||
@@ -543,8 +530,7 @@ fat_file_write(
|
|||||||
cln,
|
cln,
|
||||||
byte,
|
byte,
|
||||||
count,
|
count,
|
||||||
buf,
|
buf);
|
||||||
false);
|
|
||||||
if (0 > ret)
|
if (0 > ret)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else
|
||||||
@@ -556,8 +542,7 @@ fat_file_write(
|
|||||||
fat_fd,
|
fat_fd,
|
||||||
start,
|
start,
|
||||||
count,
|
count,
|
||||||
buf,
|
buf);
|
||||||
file_cln_initial);
|
|
||||||
if (0 > ret)
|
if (0 > ret)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -482,6 +482,8 @@ int msdos_get_dotdot_dir_info_cluster_num_and_offset(
|
|||||||
|
|
||||||
int msdos_sync(rtems_libio_t *iop);
|
int msdos_sync(rtems_libio_t *iop);
|
||||||
|
|
||||||
|
uint8_t msdos_lfn_checksum(const void *entry);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -288,7 +288,13 @@ msdos_get_valid_utf16_filename_character (const uint16_t utf16_character)
|
|||||||
static char
|
static char
|
||||||
msdos_get_valid_codepage_filename_character (const uint8_t character)
|
msdos_get_valid_codepage_filename_character (const uint8_t character)
|
||||||
{
|
{
|
||||||
return codepage_valid_char_map[(unsigned int)character];
|
char c = codepage_valid_char_map[character];
|
||||||
|
|
||||||
|
if (c == 0) {
|
||||||
|
c = '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
@@ -556,7 +562,6 @@ msdos_filename_utf8_to_short_name_for_save (
|
|||||||
size_t name_size = utf8_name_size;
|
size_t name_size = utf8_name_size;
|
||||||
char *dest_ptr = (char*)short_name;
|
char *dest_ptr = (char*)short_name;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
char c;
|
|
||||||
size_t name_size_tmp;
|
size_t name_size_tmp;
|
||||||
char name_to_format_buf[MSDOS_SHORT_NAME_LEN +1];
|
char name_to_format_buf[MSDOS_SHORT_NAME_LEN +1];
|
||||||
|
|
||||||
@@ -606,10 +611,8 @@ msdos_filename_utf8_to_short_name_for_save (
|
|||||||
dest_ptr[0] = '_';
|
dest_ptr[0] = '_';
|
||||||
else if ( 0xE5 == *name_ptr )
|
else if ( 0xE5 == *name_ptr )
|
||||||
dest_ptr[0] = 0x05;
|
dest_ptr[0] = 0x05;
|
||||||
else if (0 != (c = msdos_get_valid_codepage_filename_character( *name_ptr ) ) )
|
|
||||||
dest_ptr[0] = c;
|
|
||||||
else
|
else
|
||||||
dest_ptr[0] = '_';
|
dest_ptr[0] = msdos_get_valid_codepage_filename_character(*name_ptr);
|
||||||
++name_ptr;
|
++name_ptr;
|
||||||
++returned_size;
|
++returned_size;
|
||||||
--name_size;
|
--name_size;
|
||||||
@@ -617,11 +620,7 @@ msdos_filename_utf8_to_short_name_for_save (
|
|||||||
* Validate and assign all other characters of the name part
|
* Validate and assign all other characters of the name part
|
||||||
*/
|
*/
|
||||||
for (i = 1; i <= 7 && name_size && *name_ptr != '.'; ++i) {
|
for (i = 1; i <= 7 && name_size && *name_ptr != '.'; ++i) {
|
||||||
c = msdos_get_valid_codepage_filename_character ( *name_ptr );
|
dest_ptr[i] = msdos_get_valid_codepage_filename_character(*name_ptr);
|
||||||
if (c != 0)
|
|
||||||
dest_ptr[i] = c;
|
|
||||||
else
|
|
||||||
dest_ptr[i] = '_';
|
|
||||||
++name_ptr;
|
++name_ptr;
|
||||||
++returned_size;
|
++returned_size;
|
||||||
--name_size;
|
--name_size;
|
||||||
@@ -644,11 +643,7 @@ msdos_filename_utf8_to_short_name_for_save (
|
|||||||
* Copy in the extension part of the name, if any.
|
* Copy in the extension part of the name, if any.
|
||||||
*/
|
*/
|
||||||
for (; i <= 10 && name_size ; i++) {
|
for (; i <= 10 && name_size ; i++) {
|
||||||
c = msdos_get_valid_codepage_filename_character ( *name_ptr);
|
dest_ptr[i] = msdos_get_valid_codepage_filename_character(*name_ptr);
|
||||||
if (c != 0)
|
|
||||||
dest_ptr[i] = c;
|
|
||||||
else
|
|
||||||
dest_ptr[i] = '_';
|
|
||||||
++name_ptr;
|
++name_ptr;
|
||||||
++returned_size;
|
++returned_size;
|
||||||
name_size--;
|
name_size--;
|
||||||
|
|||||||
@@ -222,10 +222,10 @@ static int msdos_utf8_normalize_and_fold(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ( result >= 0 ) {
|
if ( result >= 0 ) {
|
||||||
if ( result < unicode_buf_size ) {
|
if ( result <= unicode_buf_size ) {
|
||||||
unicodes_to_reencode = result;
|
unicodes_to_reencode = result;
|
||||||
} else {
|
} else {
|
||||||
unicodes_to_reencode = unicode_buf_size - 1;
|
unicodes_to_reencode = unicode_buf_size;
|
||||||
eno = ENOMEM;
|
eno = ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -179,6 +179,8 @@ msdos_creat_node(const rtems_filesystem_location_info_t *parent_loc,
|
|||||||
*/
|
*/
|
||||||
if (type == FAT_DIRECTORY)
|
if (type == FAT_DIRECTORY)
|
||||||
{
|
{
|
||||||
|
uint32_t unused;
|
||||||
|
|
||||||
/* open new directory as fat-file */
|
/* open new directory as fat-file */
|
||||||
rc = fat_file_open(&fs_info->fat, &dir_pos, &fat_fd);
|
rc = fat_file_open(&fs_info->fat, &dir_pos, &fat_fd);
|
||||||
if (rc != RC_OK)
|
if (rc != RC_OK)
|
||||||
@@ -188,11 +190,19 @@ msdos_creat_node(const rtems_filesystem_location_info_t *parent_loc,
|
|||||||
* we opened fat-file for node we just created, so initialize fat-file
|
* we opened fat-file for node we just created, so initialize fat-file
|
||||||
* descritor
|
* descritor
|
||||||
*/
|
*/
|
||||||
fat_fd->fat_file_size = 0;
|
|
||||||
fat_fd->fat_file_type = FAT_DIRECTORY;
|
fat_fd->fat_file_type = FAT_DIRECTORY;
|
||||||
fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
|
fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
|
||||||
fat_file_set_ctime_mtime(fat_fd, now);
|
fat_file_set_ctime_mtime(fat_fd, now);
|
||||||
|
|
||||||
|
/* extend it to contain exactly one cluster */
|
||||||
|
rc = fat_file_extend(&fs_info->fat,
|
||||||
|
fat_fd,
|
||||||
|
true,
|
||||||
|
fs_info->fat.vol.bpc,
|
||||||
|
&unused);
|
||||||
|
if (rc != RC_OK)
|
||||||
|
goto err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dot and dotdot entries are identical to new node except the
|
* dot and dotdot entries are identical to new node except the
|
||||||
* names
|
* names
|
||||||
@@ -226,33 +236,16 @@ msdos_creat_node(const rtems_filesystem_location_info_t *parent_loc,
|
|||||||
CT_LE_W((uint16_t )(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
|
CT_LE_W((uint16_t )(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* write dot and dotdot entries to new fat-file: currently fat-file
|
|
||||||
* correspondes to a new node is zero length, so it will be extended
|
|
||||||
* by one cluster and entries will be written
|
|
||||||
*/
|
|
||||||
ret = fat_file_write(&fs_info->fat, fat_fd, 0,
|
|
||||||
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
|
|
||||||
(uint8_t *)dot_dotdot);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
rc = -1;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* increment fat-file size by cluster size */
|
|
||||||
fat_fd->fat_file_size += fs_info->fat.vol.bpc;
|
|
||||||
|
|
||||||
/* set up cluster num for dot entry */
|
/* set up cluster num for dot entry */
|
||||||
*MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
|
*MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
|
||||||
CT_LE_W((uint16_t )((fat_fd->cln) & 0x0000FFFF));
|
CT_LE_W((uint16_t )((fat_fd->cln) & 0x0000FFFF));
|
||||||
*MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
|
*MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
|
||||||
CT_LE_W((uint16_t )(((fat_fd->cln) & 0xFFFF0000) >> 16));
|
CT_LE_W((uint16_t )(((fat_fd->cln) & 0xFFFF0000) >> 16));
|
||||||
|
|
||||||
/* rewrite dot entry */
|
/* write dot and dotdot entries */
|
||||||
ret = fat_file_write(&fs_info->fat, fat_fd, 0,
|
ret = fat_file_write(&fs_info->fat, fat_fd, 0,
|
||||||
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
|
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
|
||||||
(uint8_t *)DOT_NODE_P(dot_dotdot));
|
(uint8_t *)dot_dotdot);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
rc = -1;
|
rc = -1;
|
||||||
|
|||||||
@@ -88,6 +88,11 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
|||||||
size_t string_size = sizeof(tmp_dirent.d_name);
|
size_t string_size = sizeof(tmp_dirent.d_name);
|
||||||
bool is_first_entry;
|
bool is_first_entry;
|
||||||
|
|
||||||
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
||||||
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
||||||
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
|
rtems_set_errno_and_return_minus_one(EIO);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cast start and count - protect against using sizes that are not exact
|
* cast start and count - protect against using sizes that are not exact
|
||||||
* multiples of the -dirent- size. These could result in unexpected
|
* multiples of the -dirent- size. These could result in unexpected
|
||||||
@@ -107,11 +112,6 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
|||||||
fat_fd->fat_file_size :
|
fat_fd->fat_file_size :
|
||||||
fs_info->fat.vol.bpc;
|
fs_info->fat.vol.bpc;
|
||||||
|
|
||||||
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
||||||
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
|
||||||
rtems_set_errno_and_return_minus_one(EIO);
|
|
||||||
|
|
||||||
while (count > 0 && cmpltd >= 0)
|
while (count > 0 && cmpltd >= 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -281,14 +281,8 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
|||||||
*/
|
*/
|
||||||
if (lfn_start != FAT_FILE_SHORT_NAME)
|
if (lfn_start != FAT_FILE_SHORT_NAME)
|
||||||
{
|
{
|
||||||
uint8_t cs = 0;
|
if (lfn_entries ||
|
||||||
uint8_t* p = (uint8_t*) entry;
|
lfn_checksum != msdos_lfn_checksum(entry))
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 11; i++, p++)
|
|
||||||
cs = ((cs & 1) ? 0x80 : 0) + (cs >> 1) + *p;
|
|
||||||
|
|
||||||
if (lfn_entries || (lfn_checksum != cs))
|
|
||||||
lfn_start = FAT_FILE_SHORT_NAME;
|
lfn_start = FAT_FILE_SHORT_NAME;
|
||||||
|
|
||||||
eno = (*convert_handler->utf16_to_utf8) (
|
eno = (*convert_handler->utf16_to_utf8) (
|
||||||
|
|||||||
@@ -1204,8 +1204,8 @@ int msdos_format
|
|||||||
case FAT_FAT32:
|
case FAT_FAT32:
|
||||||
/* FAT entry 0: 0xffffff00|media_type */
|
/* FAT entry 0: 0xffffff00|media_type */
|
||||||
FAT_SET_VAL32(tmp_sec,0,0xffffff00|fmt_params.media_code);
|
FAT_SET_VAL32(tmp_sec,0,0xffffff00|fmt_params.media_code);
|
||||||
/* FAT entry 1: EOC */
|
/* FAT entry 1: Not dirty, no IO error, EOC */
|
||||||
FAT_SET_VAL32(tmp_sec,4,FAT_FAT32_EOC);
|
FAT_SET_VAL32(tmp_sec,4,0xc0000000|FAT_FAT32_EOC);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -55,6 +55,23 @@
|
|||||||
const char *const MSDOS_DOT_NAME = ". ";
|
const char *const MSDOS_DOT_NAME = ". ";
|
||||||
const char *const MSDOS_DOTDOT_NAME = ".. ";
|
const char *const MSDOS_DOTDOT_NAME = ".. ";
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
msdos_lfn_checksum(const void *entry)
|
||||||
|
{
|
||||||
|
const uint8_t *name;
|
||||||
|
uint8_t cs;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
name = (const uint8_t *) MSDOS_DIR_NAME(entry);
|
||||||
|
cs = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < MSDOS_SHORT_NAME_LEN; ++i) {
|
||||||
|
cs = ((cs & 1) ? 0x80 : 0) + (cs >> 1) + name[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
|
|
||||||
/* msdos_is_valid_name_char --
|
/* msdos_is_valid_name_char --
|
||||||
* Routine to check the character in a file or directory name.
|
* Routine to check the character in a file or directory name.
|
||||||
* The characters support in the short file name are letters,
|
* The characters support in the short file name are letters,
|
||||||
@@ -99,7 +116,7 @@ msdos_is_valid_name_char(const char ch)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
msdos_short_name_hex(char* sfn, int num)
|
msdos_short_name_hex(char* sfn, uint32_t num)
|
||||||
{
|
{
|
||||||
static const char* hex = "0123456789ABCDEF";
|
static const char* hex = "0123456789ABCDEF";
|
||||||
char* c = MSDOS_DIR_NAME(sfn);
|
char* c = MSDOS_DIR_NAME(sfn);
|
||||||
@@ -820,7 +837,12 @@ fat_file_write_file_size(
|
|||||||
sec += (fat_fd->dir_pos.sname.ofs >> fs_info->vol.sec_log2);
|
sec += (fat_fd->dir_pos.sname.ofs >> fs_info->vol.sec_log2);
|
||||||
byte = (fat_fd->dir_pos.sname.ofs & (fs_info->vol.bps - 1));
|
byte = (fat_fd->dir_pos.sname.ofs & (fs_info->vol.bps - 1));
|
||||||
|
|
||||||
le_new_length = CT_LE_L((fat_fd->fat_file_size));
|
if (fat_fd->fat_file_type == FAT_DIRECTORY) {
|
||||||
|
le_new_length = CT_LE_L(0);
|
||||||
|
} else {
|
||||||
|
le_new_length = CT_LE_L(fat_fd->fat_file_size);
|
||||||
|
}
|
||||||
|
|
||||||
ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
|
ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
|
||||||
(char *)(&le_new_length));
|
(char *)(&le_new_length));
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
@@ -997,7 +1019,7 @@ msdos_on_entry_found (
|
|||||||
char *name_dir_entry,
|
char *name_dir_entry,
|
||||||
char *entry,
|
char *entry,
|
||||||
fat_dir_pos_t *dir_pos,
|
fat_dir_pos_t *dir_pos,
|
||||||
uint32_t *dir_offset,
|
uint32_t dir_offset,
|
||||||
const uint32_t dir_entry,
|
const uint32_t dir_entry,
|
||||||
const fat_pos_t *lfn_start
|
const fat_pos_t *lfn_start
|
||||||
)
|
)
|
||||||
@@ -1013,7 +1035,7 @@ msdos_on_entry_found (
|
|||||||
rc = fat_file_ioctl(&fs_info->fat,
|
rc = fat_file_ioctl(&fs_info->fat,
|
||||||
fat_fd,
|
fat_fd,
|
||||||
F_CLU_NUM,
|
F_CLU_NUM,
|
||||||
*dir_offset * bts2rd,
|
dir_offset * bts2rd,
|
||||||
&dir_pos->sname.cln);
|
&dir_pos->sname.cln);
|
||||||
if (rc == RC_OK) {
|
if (rc == RC_OK) {
|
||||||
dir_pos->sname.ofs = dir_entry;
|
dir_pos->sname.ofs = dir_entry;
|
||||||
@@ -1275,13 +1297,11 @@ msdos_find_file_in_directory (
|
|||||||
fat_file_fd_t *fat_fd,
|
fat_file_fd_t *fat_fd,
|
||||||
const uint32_t bts2rd,
|
const uint32_t bts2rd,
|
||||||
const bool create_node,
|
const bool create_node,
|
||||||
const unsigned int fat_entries,
|
const unsigned int lfn_entries,
|
||||||
char *name_dir_entry,
|
char *name_dir_entry,
|
||||||
fat_dir_pos_t *dir_pos,
|
fat_dir_pos_t *dir_pos,
|
||||||
uint32_t *dir_offset,
|
uint32_t *empty_file_offset,
|
||||||
uint32_t *empty_space_offset,
|
uint32_t *empty_entry_count)
|
||||||
uint32_t *empty_space_entry,
|
|
||||||
uint32_t *empty_space_count)
|
|
||||||
{
|
{
|
||||||
int rc = RC_OK;
|
int rc = RC_OK;
|
||||||
ssize_t bytes_read;
|
ssize_t bytes_read;
|
||||||
@@ -1297,6 +1317,7 @@ msdos_find_file_in_directory (
|
|||||||
bool filename_matched = false;
|
bool filename_matched = false;
|
||||||
ssize_t filename_size_remaining = name_len_for_compare;
|
ssize_t filename_size_remaining = name_len_for_compare;
|
||||||
rtems_dosfs_convert_control *converter = fs_info->converter;
|
rtems_dosfs_convert_control *converter = fs_info->converter;
|
||||||
|
uint32_t dir_offset = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the directory seeing if the file is present. While
|
* Scan the directory seeing if the file is present. While
|
||||||
@@ -1306,13 +1327,13 @@ msdos_find_file_in_directory (
|
|||||||
|
|
||||||
lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
|
lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
|
||||||
|
|
||||||
while ( (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (*dir_offset * bts2rd),
|
while ( (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (dir_offset * bts2rd),
|
||||||
bts2rd, fs_info->cl_buf)) != FAT_EOF
|
bts2rd, fs_info->cl_buf)) != FAT_EOF
|
||||||
&& rc == RC_OK)
|
&& rc == RC_OK)
|
||||||
{
|
{
|
||||||
bool remainder_empty = false;
|
bool remainder_empty = false;
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ("MSFS:[2] dir_offset:%li\n", *dir_offset);
|
printf ("MSFS:[2] dir_offset:%li\n", dir_offset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (bytes_read < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
|
if (bytes_read < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
|
||||||
@@ -1337,20 +1358,19 @@ msdos_find_file_in_directory (
|
|||||||
MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY);
|
MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY);
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n",
|
printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n",
|
||||||
remainder_empty, entry_empty, *dir_offset,
|
remainder_empty, entry_empty, dir_offset,
|
||||||
dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE));
|
dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE));
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* Remember where the we are, ie the start, so we can come back
|
* Remember where the we are, ie the start, so we can come back
|
||||||
* to here and write the long file name if this is the start of
|
* to here and write the long file name if this is the start of
|
||||||
* a series of empty entries. If empty_space_count is 0 then
|
* a series of empty entries. If empty_entry_count is 0 then
|
||||||
* we are currently not inside an empty series of entries. It
|
* we are currently not inside an empty series of entries. It
|
||||||
* is a count of empty entries.
|
* is a count of empty entries.
|
||||||
*/
|
*/
|
||||||
if (*empty_space_count == 0)
|
if (*empty_entry_count == 0)
|
||||||
{
|
{
|
||||||
*empty_space_entry = dir_entry;
|
*empty_file_offset = dir_offset * bts2rd + dir_entry;
|
||||||
*empty_space_offset = *dir_offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainder_empty)
|
if (remainder_empty)
|
||||||
@@ -1374,11 +1394,11 @@ msdos_find_file_in_directory (
|
|||||||
if ( !empty_space_found
|
if ( !empty_space_found
|
||||||
&& rc == RC_OK )
|
&& rc == RC_OK )
|
||||||
{
|
{
|
||||||
*empty_space_count +=
|
*empty_entry_count +=
|
||||||
entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
|
entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
|
||||||
empty_space_found = true;
|
empty_space_found = true;
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_space_count );
|
printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_entry_count );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1390,14 +1410,14 @@ msdos_find_file_in_directory (
|
|||||||
/*
|
/*
|
||||||
* Remainder is not empty so is this entry empty ?
|
* Remainder is not empty so is this entry empty ?
|
||||||
*/
|
*/
|
||||||
(*empty_space_count)++;
|
(*empty_entry_count)++;
|
||||||
|
|
||||||
if (*empty_space_count == (fat_entries + 1))
|
if (*empty_entry_count == (lfn_entries + 1))
|
||||||
empty_space_found = true;
|
empty_space_found = true;
|
||||||
}
|
}
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ("MSFS:[4.1] esc:%li esf:%i\n",
|
printf ("MSFS:[4.1] esc:%li esf:%i\n",
|
||||||
*empty_space_count, empty_space_found);
|
*empty_entry_count, empty_space_found);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1410,8 +1430,8 @@ msdos_find_file_in_directory (
|
|||||||
*/
|
*/
|
||||||
if (create_node && !empty_space_found)
|
if (create_node && !empty_space_found)
|
||||||
{
|
{
|
||||||
*empty_space_entry = 0;
|
*empty_file_offset = 0;
|
||||||
*empty_space_count = 0;
|
*empty_entry_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1421,6 +1441,9 @@ msdos_find_file_in_directory (
|
|||||||
if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
|
if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
|
||||||
MSDOS_ATTR_LFN)
|
MSDOS_ATTR_LFN)
|
||||||
{
|
{
|
||||||
|
bool is_first_lfn_entry =
|
||||||
|
(lfn_start.cln == FAT_FILE_SHORT_NAME);
|
||||||
|
|
||||||
/* int o;*/
|
/* int o;*/
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
|
printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
|
||||||
@@ -1432,7 +1455,7 @@ msdos_find_file_in_directory (
|
|||||||
* If we are not already processing a LFN see if this is
|
* If we are not already processing a LFN see if this is
|
||||||
* the first entry of a LFN ?
|
* the first entry of a LFN ?
|
||||||
*/
|
*/
|
||||||
if (lfn_start.cln == FAT_FILE_SHORT_NAME)
|
if (is_first_lfn_entry)
|
||||||
{
|
{
|
||||||
entry_matched = false;
|
entry_matched = false;
|
||||||
|
|
||||||
@@ -1444,23 +1467,10 @@ msdos_find_file_in_directory (
|
|||||||
MSDOS_LAST_LONG_ENTRY) == 0)
|
MSDOS_LAST_LONG_ENTRY) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
lfn_start.cln = dir_offset;
|
||||||
* Does the number of entries in the LFN directory
|
|
||||||
* entry match the number we expect for this
|
|
||||||
* file name. Note we do not know the number of
|
|
||||||
* characters in the entry so this is check further
|
|
||||||
* on when the characters are checked.
|
|
||||||
*/
|
|
||||||
if (fat_entries != (*MSDOS_DIR_ENTRY_TYPE(entry) &
|
|
||||||
MSDOS_LAST_LONG_ENTRY_MASK))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the checksum of the short entry.
|
|
||||||
*/
|
|
||||||
lfn_start.cln = *dir_offset;
|
|
||||||
lfn_start.ofs = dir_entry;
|
lfn_start.ofs = dir_entry;
|
||||||
lfn_entry = fat_entries;
|
lfn_entry = (*MSDOS_DIR_ENTRY_TYPE(entry)
|
||||||
|
& MSDOS_LAST_LONG_ENTRY_MASK);
|
||||||
lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
|
lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
|
||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
@@ -1493,7 +1503,7 @@ msdos_find_file_in_directory (
|
|||||||
bytes_in_entry = msdos_long_entry_to_utf8_name (
|
bytes_in_entry = msdos_long_entry_to_utf8_name (
|
||||||
converter,
|
converter,
|
||||||
entry,
|
entry,
|
||||||
(lfn_entry + 1) == fat_entries,
|
is_first_lfn_entry,
|
||||||
&entry_utf8_normalized[0],
|
&entry_utf8_normalized[0],
|
||||||
sizeof (entry_utf8_normalized));
|
sizeof (entry_utf8_normalized));
|
||||||
if (bytes_in_entry > 0) {
|
if (bytes_in_entry > 0) {
|
||||||
@@ -1530,16 +1540,10 @@ msdos_find_file_in_directory (
|
|||||||
*/
|
*/
|
||||||
if (entry_matched)
|
if (entry_matched)
|
||||||
{
|
{
|
||||||
uint8_t cs = 0;
|
if (lfn_entry ||
|
||||||
uint8_t* p = (uint8_t*) MSDOS_DIR_NAME(entry);
|
lfn_checksum != msdos_lfn_checksum(entry))
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MSDOS_SHORT_NAME_LEN; i++, p++)
|
|
||||||
cs = ((cs & 1) ? 0x80 : 0) + (cs >> 1) + *p;
|
|
||||||
|
|
||||||
if (lfn_entry || (lfn_checksum != cs))
|
|
||||||
entry_matched = false;
|
entry_matched = false;
|
||||||
else {
|
else if (filename_size_remaining == 0) {
|
||||||
filename_matched = true;
|
filename_matched = true;
|
||||||
rc = msdos_on_entry_found (
|
rc = msdos_on_entry_found (
|
||||||
fs_info,
|
fs_info,
|
||||||
@@ -1556,7 +1560,7 @@ msdos_find_file_in_directory (
|
|||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ("MSFS:[9.2] checksum, entry_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
|
printf ("MSFS:[9.2] checksum, entry_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
|
||||||
entry_matched, lfn_entry, lfn_checksum, cs);
|
entry_matched, lfn_entry, lfn_checksum, msdos_lfn_checksum(entry));
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
bytes_in_entry = MSDOS_SHORT_NAME_LEN + 1;
|
bytes_in_entry = MSDOS_SHORT_NAME_LEN + 1;
|
||||||
@@ -1605,7 +1609,7 @@ msdos_find_file_in_directory (
|
|||||||
if (filename_matched || remainder_empty)
|
if (filename_matched || remainder_empty)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
(*dir_offset)++;
|
dir_offset++;
|
||||||
}
|
}
|
||||||
if ( ! filename_matched ) {
|
if ( ! filename_matched ) {
|
||||||
/*
|
/*
|
||||||
@@ -1615,14 +1619,28 @@ msdos_find_file_in_directory (
|
|||||||
rc = MSDOS_NAME_NOT_FOUND_ERR;
|
rc = MSDOS_NAME_NOT_FOUND_ERR;
|
||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" eso:%"PRIu32" ese:%"PRIu32"\n",
|
printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" efo:%"PRIu32"\n",
|
||||||
*dir_offset, *empty_space_count, *empty_space_offset, *empty_space_entry );
|
dir_offset, *empty_entry_count, *empty_file_offset );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
msdos_get_pos(
|
||||||
|
msdos_fs_info_t *fs_info,
|
||||||
|
fat_file_fd_t *fat_fd,
|
||||||
|
uint32_t bts2rd,
|
||||||
|
uint32_t file_offset,
|
||||||
|
fat_pos_t *pos
|
||||||
|
)
|
||||||
|
{
|
||||||
|
pos->ofs = file_offset & (bts2rd - 1);
|
||||||
|
return fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
|
||||||
|
file_offset, &pos->cln);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
msdos_add_file (
|
msdos_add_file (
|
||||||
const char *name_converted,
|
const char *name_converted,
|
||||||
@@ -1630,263 +1648,161 @@ msdos_add_file (
|
|||||||
msdos_fs_info_t *fs_info,
|
msdos_fs_info_t *fs_info,
|
||||||
fat_file_fd_t *fat_fd,
|
fat_file_fd_t *fat_fd,
|
||||||
const uint32_t bts2rd,
|
const uint32_t bts2rd,
|
||||||
const unsigned int fat_entries,
|
const unsigned int lfn_entries,
|
||||||
const char *name_dir_entry,
|
const char *name_dir_entry,
|
||||||
fat_dir_pos_t *dir_pos,
|
fat_dir_pos_t *dir_pos,
|
||||||
const uint32_t dir_offset,
|
uint32_t empty_file_offset,
|
||||||
const uint32_t empty_space_offset_param,
|
const uint32_t empty_entry_count
|
||||||
const uint32_t empty_space_entry_param,
|
|
||||||
const uint32_t empty_space_count
|
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret;
|
||||||
ssize_t bytes_written = 0;
|
ssize_t bytes_written;
|
||||||
uint8_t lfn_checksum = 0;
|
uint8_t lfn_checksum;
|
||||||
uint32_t empty_space_offset = empty_space_offset_param;
|
int lfn_entry;
|
||||||
uint32_t empty_space_entry = empty_space_entry_param;
|
uint8_t *entry;
|
||||||
bool read_cluster = false;
|
uint32_t short_file_offset;
|
||||||
int lfn_entry = 0;
|
uint32_t length;
|
||||||
fat_pos_t lfn_start;
|
|
||||||
uint32_t dir_entry;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a long file name calculate the checksum of the short file name
|
* If there is not enough space available then extend the file.
|
||||||
* data to place in each long file name entry. First set the short
|
|
||||||
* file name to the slot of the SFN entry. This will mean no clashes
|
|
||||||
* in this directory.
|
|
||||||
*/
|
*/
|
||||||
|
if (empty_entry_count < lfn_entries + 1)
|
||||||
|
{
|
||||||
|
uint32_t unused;
|
||||||
|
|
||||||
|
empty_file_offset = fat_fd->fat_file_size -
|
||||||
|
empty_entry_count * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
|
||||||
|
|
||||||
|
ret = fat_file_extend(&fs_info->fat,
|
||||||
|
fat_fd,
|
||||||
|
true,
|
||||||
|
fat_fd->fat_file_size + fs_info->fat.vol.bpc,
|
||||||
|
&unused);
|
||||||
|
if (ret != RC_OK)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (name_type == MSDOS_NAME_LONG)
|
if (name_type == MSDOS_NAME_LONG)
|
||||||
{
|
{
|
||||||
int slot = (((empty_space_offset * bts2rd) + empty_space_entry) /
|
uint32_t slot;
|
||||||
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + fat_entries + 1;
|
|
||||||
|
/*
|
||||||
|
* If a long file name calculate the checksum of the short file name
|
||||||
|
* data to place in each long file name entry. First set the short
|
||||||
|
* file name to the slot of the SFN entry. This will mean no clashes
|
||||||
|
* in this directory.
|
||||||
|
*/
|
||||||
|
slot = (empty_file_offset /
|
||||||
|
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + lfn_entries + 1;
|
||||||
msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot);
|
msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot);
|
||||||
|
|
||||||
|
lfn_checksum = msdos_lfn_checksum(name_dir_entry);
|
||||||
|
|
||||||
|
short_file_offset = empty_file_offset + lfn_entries
|
||||||
|
* MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
|
||||||
|
|
||||||
|
/* Get position of first long file name entry */
|
||||||
|
ret = msdos_get_pos(fs_info, fat_fd, bts2rd, empty_file_offset,
|
||||||
|
&dir_pos->lname);
|
||||||
|
if (ret != RC_OK)
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
lfn_checksum = 0;
|
||||||
|
short_file_offset = empty_file_offset;
|
||||||
|
dir_pos->lname.cln = FAT_FILE_SHORT_NAME;
|
||||||
|
dir_pos->lname.ofs = FAT_FILE_SHORT_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fat_entries)
|
/* Get position of short file name entry */
|
||||||
{
|
ret = msdos_get_pos(fs_info, fat_fd, bts2rd, short_file_offset,
|
||||||
uint8_t* p = (uint8_t*) MSDOS_DIR_NAME(name_dir_entry);
|
&dir_pos->sname);
|
||||||
int i;
|
|
||||||
for (i = 0; i < 11; i++, p++)
|
|
||||||
lfn_checksum =
|
|
||||||
((lfn_checksum & 1) ? 0x80 : 0) + (lfn_checksum >> 1) + *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there is no space available then extend the file. The
|
|
||||||
* empty_space_count is a count of empty entries in the currently
|
|
||||||
* read cluster so if 0 there is no space. Note, dir_offset will
|
|
||||||
* be at the next cluster so we can just make empty_space_offset
|
|
||||||
* that value.
|
|
||||||
*/
|
|
||||||
if (empty_space_count == 0)
|
|
||||||
{
|
|
||||||
read_cluster = true;
|
|
||||||
empty_space_offset = dir_offset;
|
|
||||||
empty_space_entry = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Have we read past the empty block ? If so go back and read it again.
|
|
||||||
*/
|
|
||||||
if (dir_offset != empty_space_offset)
|
|
||||||
read_cluster = true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle the entry writes.
|
* Handle the entry writes.
|
||||||
*/
|
*/
|
||||||
lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
|
entry = fs_info->cl_buf;
|
||||||
lfn_entry = 0;
|
|
||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ("MSFS:[9] read_cluster:%d eso:%ld ese:%ld\n",
|
printf ("MSFS:[9] read_cluster:%d efo:%ld ese:%ld\n",
|
||||||
read_cluster, empty_space_offset, empty_space_entry);
|
read_cluster, empty_file_offset, empty_space_entry);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/* Long file name entries */
|
||||||
* The one more is the short entry.
|
for (lfn_entry = 0; lfn_entry < lfn_entries; ++lfn_entry) {
|
||||||
*/
|
uint8_t *p;
|
||||||
while (lfn_entry < (fat_entries + 1))
|
const uint8_t *n;
|
||||||
{
|
int i;
|
||||||
int length = 0;
|
uint8_t fill = 0;
|
||||||
|
|
||||||
if (read_cluster)
|
/*
|
||||||
|
* Clear the entry before loading the data.
|
||||||
|
*/
|
||||||
|
memset (entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
|
||||||
|
|
||||||
|
*MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum;
|
||||||
|
|
||||||
|
p = entry + 1;
|
||||||
|
n = (const uint8_t *) name_converted +
|
||||||
|
(lfn_entries - lfn_entry - 1) * MSDOS_LFN_ENTRY_SIZE;
|
||||||
|
|
||||||
|
#if MSDOS_FIND_PRINT
|
||||||
|
printf ("MSFS:[11] ");
|
||||||
|
#endif
|
||||||
|
for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
|
||||||
{
|
{
|
||||||
uint32_t new_length;
|
if (*n != 0 || *(n + 1) != 0)
|
||||||
#if MSDOS_FIND_PRINT
|
|
||||||
printf ("MSFS:[9.1] eso:%li\n", empty_space_offset);
|
|
||||||
#endif
|
|
||||||
ret = fat_file_read(&fs_info->fat, fat_fd,
|
|
||||||
(empty_space_offset * bts2rd), bts2rd,
|
|
||||||
fs_info->cl_buf);
|
|
||||||
|
|
||||||
if (ret != bts2rd)
|
|
||||||
{
|
{
|
||||||
if (ret != FAT_EOF)
|
*p = *n;
|
||||||
rtems_set_errno_and_return_minus_one(EIO);
|
*(p + 1) = *(n + 1);
|
||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
|
||||||
printf ("MSFS:[9.2] extending file:%li\n", empty_space_offset);
|
|
||||||
#endif
|
|
||||||
ret = fat_file_extend (&fs_info->fat, fat_fd, false,
|
|
||||||
empty_space_offset * bts2rd, &new_length);
|
|
||||||
|
|
||||||
if (ret != RC_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
|
||||||
printf ("MSFS:[9.3] extended: %"PRIu32" <-> %"PRIu32"\n", new_length, empty_space_offset * bts2rd);
|
|
||||||
#endif
|
|
||||||
if (new_length != (empty_space_offset * bts2rd))
|
|
||||||
rtems_set_errno_and_return_minus_one(EIO);
|
|
||||||
|
|
||||||
memset(fs_info->cl_buf, 0, bts2rd);
|
|
||||||
|
|
||||||
bytes_written = fat_file_write(&fs_info->fat, fat_fd,
|
|
||||||
empty_space_offset * bts2rd,
|
|
||||||
bts2rd, fs_info->cl_buf);
|
|
||||||
#if MSDOS_FIND_PRINT
|
|
||||||
printf ("MSFS:[9.4] clear write: %d\n", ret);
|
|
||||||
#endif
|
|
||||||
if (bytes_written == -1)
|
|
||||||
return -1;
|
|
||||||
else if (bytes_written != bts2rd)
|
|
||||||
rtems_set_errno_and_return_minus_one(EIO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
|
||||||
printf ("MSFS:[10] eso:%li\n", empty_space_offset);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (dir_entry = empty_space_entry;
|
|
||||||
dir_entry < bts2rd;
|
|
||||||
dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
|
|
||||||
{
|
|
||||||
char* entry = (char*) fs_info->cl_buf + dir_entry;
|
|
||||||
char* p;
|
|
||||||
const char* n;
|
|
||||||
int i;
|
|
||||||
char fill = 0;
|
|
||||||
|
|
||||||
length += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
|
|
||||||
lfn_entry++;
|
|
||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
|
||||||
printf ("MSFS:[10] de:%li(%li) length:%i lfn_entry:%i\n",
|
|
||||||
dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE),
|
|
||||||
length, lfn_entry);
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* Time to write the short file name entry.
|
|
||||||
*/
|
|
||||||
if (lfn_entry == (fat_entries + 1))
|
|
||||||
{
|
|
||||||
/* get current cluster number */
|
|
||||||
ret = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
|
|
||||||
empty_space_offset * bts2rd,
|
|
||||||
&dir_pos->sname.cln);
|
|
||||||
if (ret != RC_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
dir_pos->sname.ofs = dir_entry;
|
|
||||||
|
|
||||||
if (lfn_start.cln != FAT_FILE_SHORT_NAME)
|
|
||||||
{
|
|
||||||
ret = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
|
|
||||||
lfn_start.cln * bts2rd,
|
|
||||||
&lfn_start.cln);
|
|
||||||
if (ret != RC_OK)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
dir_pos->lname.cln = lfn_start.cln;
|
|
||||||
dir_pos->lname.ofs = lfn_start.ofs;
|
|
||||||
|
|
||||||
/* write new node entry */
|
|
||||||
memcpy (entry, (uint8_t *) name_dir_entry,
|
|
||||||
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a long file name and we need to write
|
|
||||||
* a long file name entry. See if this is the
|
|
||||||
* first entry written and if so remember the
|
|
||||||
* the location of the long file name.
|
|
||||||
*/
|
|
||||||
if (lfn_start.cln == FAT_FILE_SHORT_NAME)
|
|
||||||
{
|
|
||||||
lfn_start.cln = empty_space_offset;
|
|
||||||
lfn_start.ofs = dir_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clear the entry before loading the data.
|
|
||||||
*/
|
|
||||||
memset (entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
|
|
||||||
|
|
||||||
*MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum;
|
|
||||||
|
|
||||||
p = entry + 1;
|
|
||||||
n = name_converted + (fat_entries - lfn_entry) * MSDOS_LFN_ENTRY_SIZE;
|
|
||||||
|
|
||||||
#if MSDOS_FIND_PRINT
|
|
||||||
printf ("MSFS:[11] ");
|
|
||||||
#endif
|
|
||||||
for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
|
|
||||||
{
|
|
||||||
if (!(*n == 0 && *(n+1) == 0))
|
|
||||||
{
|
|
||||||
*p = *n;
|
|
||||||
*(p+1) = *(n+1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p [0] = fill;
|
|
||||||
p [1] = fill;
|
|
||||||
fill = 0xff;
|
|
||||||
}
|
|
||||||
n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
|
n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
|
||||||
#if MSDOS_FIND_PRINT
|
}
|
||||||
printf ( "'%c''%c'", *p, *(p+1) );
|
else
|
||||||
#endif
|
{
|
||||||
|
p [0] = fill;
|
||||||
switch (i)
|
p [1] = fill;
|
||||||
{
|
fill = 0xff;
|
||||||
case 4:
|
|
||||||
p += 5;
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
p += 4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
p += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#if MSDOS_FIND_PRINT
|
#if MSDOS_FIND_PRINT
|
||||||
printf ( "\n" );
|
printf ( "'%c''%c'", *p, *(p+1) );
|
||||||
#endif
|
#endif
|
||||||
*MSDOS_DIR_ENTRY_TYPE(entry) = (fat_entries - lfn_entry) + 1;
|
|
||||||
if (lfn_entry == 1)
|
switch (i)
|
||||||
*MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
|
{
|
||||||
*MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
|
case 4:
|
||||||
|
p += 5;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
p += 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
p += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#if MSDOS_FIND_PRINT
|
||||||
|
printf ( "\n" );
|
||||||
|
#endif
|
||||||
|
*MSDOS_DIR_ENTRY_TYPE(entry) = lfn_entries - lfn_entry;
|
||||||
|
if (lfn_entry == 0)
|
||||||
|
*MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
|
||||||
|
*MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
|
||||||
|
|
||||||
bytes_written = fat_file_write(&fs_info->fat, fat_fd,
|
entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
|
||||||
(empty_space_offset * bts2rd) + empty_space_entry,
|
|
||||||
length, fs_info->cl_buf + empty_space_entry);
|
|
||||||
if (bytes_written == -1)
|
|
||||||
return -1;
|
|
||||||
else if (bytes_written != length)
|
|
||||||
rtems_set_errno_and_return_minus_one(EIO);
|
|
||||||
|
|
||||||
empty_space_offset++;
|
|
||||||
empty_space_entry = 0;
|
|
||||||
read_cluster = true;
|
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
/* Short file name entry */
|
||||||
|
memcpy(entry, name_dir_entry, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
|
||||||
|
|
||||||
|
length = (lfn_entries + 1) * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
|
||||||
|
bytes_written = fat_file_write(&fs_info->fat, fat_fd,
|
||||||
|
empty_file_offset,
|
||||||
|
length, fs_info->cl_buf);
|
||||||
|
if (bytes_written == (ssize_t) length)
|
||||||
|
return 0;
|
||||||
|
else if (bytes_written == -1)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
rtems_set_errno_and_return_minus_one(EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -1905,11 +1821,9 @@ msdos_find_name_in_fat_file (
|
|||||||
ssize_t name_len_for_save;
|
ssize_t name_len_for_save;
|
||||||
ssize_t name_len_for_compare;
|
ssize_t name_len_for_compare;
|
||||||
uint32_t bts2rd = 0;
|
uint32_t bts2rd = 0;
|
||||||
uint32_t empty_space_offset = 0;
|
uint32_t empty_file_offset = 0;
|
||||||
uint32_t empty_space_entry = 0;
|
uint32_t empty_entry_count = 0;
|
||||||
uint32_t empty_space_count = 0;
|
unsigned int lfn_entries;
|
||||||
uint32_t dir_offset = 0;
|
|
||||||
unsigned int fat_entries;
|
|
||||||
rtems_dosfs_convert_control *converter = fs_info->converter;
|
rtems_dosfs_convert_control *converter = fs_info->converter;
|
||||||
void *buffer = converter->buffer.data;
|
void *buffer = converter->buffer.data;
|
||||||
size_t buffer_size = converter->buffer.size;
|
size_t buffer_size = converter->buffer.size;
|
||||||
@@ -1935,7 +1849,7 @@ msdos_find_name_in_fat_file (
|
|||||||
buffer,
|
buffer,
|
||||||
MSDOS_SHORT_NAME_LEN);
|
MSDOS_SHORT_NAME_LEN);
|
||||||
if (name_len_for_compare > 0) {
|
if (name_len_for_compare > 0) {
|
||||||
fat_entries = 0;
|
lfn_entries = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
retval = -1;
|
retval = -1;
|
||||||
@@ -1948,7 +1862,7 @@ msdos_find_name_in_fat_file (
|
|||||||
buffer,
|
buffer,
|
||||||
buffer_size);
|
buffer_size);
|
||||||
if (name_len_for_save > 0) {
|
if (name_len_for_save > 0) {
|
||||||
fat_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
|
lfn_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
|
||||||
/ MSDOS_LFN_ENTRY_SIZE;
|
/ MSDOS_LFN_ENTRY_SIZE;
|
||||||
name_len_for_compare = msdos_filename_utf8_to_long_name_for_compare (
|
name_len_for_compare = msdos_filename_utf8_to_long_name_for_compare (
|
||||||
converter,
|
converter,
|
||||||
@@ -1979,13 +1893,11 @@ msdos_find_name_in_fat_file (
|
|||||||
fat_fd,
|
fat_fd,
|
||||||
bts2rd,
|
bts2rd,
|
||||||
create_node,
|
create_node,
|
||||||
fat_entries,
|
lfn_entries,
|
||||||
name_dir_entry,
|
name_dir_entry,
|
||||||
dir_pos,
|
dir_pos,
|
||||||
&dir_offset,
|
&empty_file_offset,
|
||||||
&empty_space_offset,
|
&empty_entry_count);
|
||||||
&empty_space_entry,
|
|
||||||
&empty_space_count);
|
|
||||||
}
|
}
|
||||||
/* Create a non-existing file/directory if requested */
|
/* Create a non-existing file/directory if requested */
|
||||||
if ( retval == RC_OK
|
if ( retval == RC_OK
|
||||||
@@ -1999,7 +1911,7 @@ msdos_find_name_in_fat_file (
|
|||||||
buffer,
|
buffer,
|
||||||
MSDOS_SHORT_NAME_LEN);
|
MSDOS_SHORT_NAME_LEN);
|
||||||
if (name_len_for_save > 0 ) {
|
if (name_len_for_save > 0 ) {
|
||||||
fat_entries = 0;
|
lfn_entries = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
retval = -1;
|
retval = -1;
|
||||||
@@ -2012,7 +1924,7 @@ msdos_find_name_in_fat_file (
|
|||||||
buffer,
|
buffer,
|
||||||
buffer_size);
|
buffer_size);
|
||||||
if (name_len_for_save > 0) {
|
if (name_len_for_save > 0) {
|
||||||
fat_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
|
lfn_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
|
||||||
/ MSDOS_LFN_ENTRY_SIZE;
|
/ MSDOS_LFN_ENTRY_SIZE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2031,13 +1943,11 @@ msdos_find_name_in_fat_file (
|
|||||||
fs_info,
|
fs_info,
|
||||||
fat_fd,
|
fat_fd,
|
||||||
bts2rd,
|
bts2rd,
|
||||||
fat_entries,
|
lfn_entries,
|
||||||
name_dir_entry,
|
name_dir_entry,
|
||||||
dir_pos,
|
dir_pos,
|
||||||
dir_offset,
|
empty_file_offset,
|
||||||
empty_space_offset,
|
empty_entry_count
|
||||||
empty_space_entry,
|
|
||||||
empty_space_count
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1019,7 +1019,7 @@ rtems_status_code status;
|
|||||||
initialised = 1;
|
initialised = 1;
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"RTEMS-NFS $Release$, " \
|
"RTEMS-NFS, " \
|
||||||
"Till Straumann, Stanford/SLAC/SSRL 2002, " \
|
"Till Straumann, Stanford/SLAC/SSRL 2002, " \
|
||||||
"See LICENSE file for licensing info.\n");
|
"See LICENSE file for licensing info.\n");
|
||||||
|
|
||||||
|
|||||||
@@ -958,7 +958,7 @@ int noblock = 1;
|
|||||||
struct sockwakeup wkup;
|
struct sockwakeup wkup;
|
||||||
|
|
||||||
if (ourSock < 0) {
|
if (ourSock < 0) {
|
||||||
fprintf(stderr,"RTEMS-RPCIOD $Release$, " \
|
fprintf(stderr,"RTEMS-RPCIOD, " \
|
||||||
"Till Straumann, Stanford/SLAC/SSRL 2002, " \
|
"Till Straumann, Stanford/SLAC/SSRL 2002, " \
|
||||||
"See LICENSE file for licensing info.\n");
|
"See LICENSE file for licensing info.\n");
|
||||||
|
|
||||||
|
|||||||
@@ -212,6 +212,10 @@ $(PROJECT_INCLUDE)/rtems/rtl/rtl-sym.h: libdl/rtl-sym.h $(PROJECT_INCLUDE)/rtems
|
|||||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-sym.h
|
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-sym.h
|
||||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-sym.h
|
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-sym.h
|
||||||
|
|
||||||
|
$(PROJECT_INCLUDE)/rtems/rtl/rtl-trace.h: libdl/rtl-trace.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
|
||||||
|
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rtl-trace.h
|
||||||
|
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rtl-trace.h
|
||||||
|
|
||||||
$(PROJECT_INCLUDE)/rtems/rtl/rap.h: libdl/rap.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
|
$(PROJECT_INCLUDE)/rtems/rtl/rap.h: libdl/rap.h $(PROJECT_INCLUDE)/rtems/rtl/$(dirstamp)
|
||||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rap.h
|
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rap.h
|
||||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rap.h
|
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rap.h
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ void __attribute__((naked)) _ARMV7M_Exception_default( void )
|
|||||||
"mov r2, lr\n"
|
"mov r2, lr\n"
|
||||||
"mrs r1, msp\n"
|
"mrs r1, msp\n"
|
||||||
"mrs r0, psp\n"
|
"mrs r0, psp\n"
|
||||||
"cmn r2, #3\n"
|
"tst lr, #4\n"
|
||||||
"itt ne\n"
|
"itt eq\n"
|
||||||
"movne r0, r1\n"
|
"moveq r0, r1\n"
|
||||||
"addne r0, %[cpufsz]\n"
|
"addeq r0, %[cpufsz]\n"
|
||||||
"add r2, r0, %[v7mlroff]\n"
|
"add r2, r0, %[v7mlroff]\n"
|
||||||
"add r1, sp, %[cpulroff]\n"
|
"add r1, sp, %[cpulroff]\n"
|
||||||
"ldm r2, {r3-r5}\n"
|
"ldm r2, {r3-r5}\n"
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2014 Sebastian Huber. All rights reserved.
|
* Copyright (c) 2011, 2017 Sebastian Huber. All rights reserved.
|
||||||
*
|
*
|
||||||
* embedded brains GmbH
|
* embedded brains GmbH
|
||||||
* Obere Lagerstr. 30
|
* Dornierstr. 4
|
||||||
* 82178 Puchheim
|
* 82178 Puchheim
|
||||||
* Germany
|
* Germany
|
||||||
* <rtems@embedded-brains.de>
|
* <rtems@embedded-brains.de>
|
||||||
@@ -48,29 +48,42 @@ static void _ARMV7M_Trigger_lazy_floating_point_context_save( void )
|
|||||||
|
|
||||||
void _ARMV7M_Pendable_service_call( void )
|
void _ARMV7M_Pendable_service_call( void )
|
||||||
{
|
{
|
||||||
ARMV7M_Exception_frame *ef;
|
Per_CPU_Control *cpu_self = _Per_CPU_Get();
|
||||||
|
|
||||||
_ISR_Nest_level = 1;
|
|
||||||
|
|
||||||
_ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVCLR;
|
|
||||||
_ARMV7M_Trigger_lazy_floating_point_context_save();
|
|
||||||
|
|
||||||
ef = (ARMV7M_Exception_frame *) _ARMV7M_Get_PSP();
|
|
||||||
--ef;
|
|
||||||
_ARMV7M_Set_PSP( (uint32_t) ef );
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to "ARMv7-M Architecture Reference Manual" section B1.5.6
|
* We must check here if a thread dispatch is allowed. Right after a
|
||||||
* "Exception entry behavior" the return address is half-word aligned.
|
* "msr basepri_max, %[basepri]" instruction an interrupt service may still
|
||||||
|
* take place. However, pendable service calls that are activated during
|
||||||
|
* this interrupt service may be delayed until interrupts are enable again.
|
||||||
*/
|
*/
|
||||||
ef->register_pc = (void *)
|
if (
|
||||||
((uintptr_t) _ARMV7M_Thread_dispatch & ~((uintptr_t) 1));
|
( cpu_self->isr_nest_level | cpu_self->thread_dispatch_disable_level ) == 0
|
||||||
|
) {
|
||||||
|
ARMV7M_Exception_frame *ef;
|
||||||
|
|
||||||
ef->register_xpsr = 0x01000000U;
|
cpu_self->isr_nest_level = 1;
|
||||||
|
|
||||||
|
_ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVCLR;
|
||||||
|
_ARMV7M_Trigger_lazy_floating_point_context_save();
|
||||||
|
|
||||||
|
ef = (ARMV7M_Exception_frame *) _ARMV7M_Get_PSP();
|
||||||
|
--ef;
|
||||||
|
_ARMV7M_Set_PSP( (uint32_t) ef );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to "ARMv7-M Architecture Reference Manual" section B1.5.6
|
||||||
|
* "Exception entry behavior" the return address is half-word aligned.
|
||||||
|
*/
|
||||||
|
ef->register_pc = (void *)
|
||||||
|
((uintptr_t) _ARMV7M_Thread_dispatch & ~((uintptr_t) 1));
|
||||||
|
|
||||||
|
ef->register_xpsr = 0x01000000U;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _ARMV7M_Supervisor_call( void )
|
void _ARMV7M_Supervisor_call( void )
|
||||||
{
|
{
|
||||||
|
Per_CPU_Control *cpu_self = _Per_CPU_Get();
|
||||||
ARMV7M_Exception_frame *ef;
|
ARMV7M_Exception_frame *ef;
|
||||||
|
|
||||||
_ARMV7M_Trigger_lazy_floating_point_context_save();
|
_ARMV7M_Trigger_lazy_floating_point_context_save();
|
||||||
@@ -79,10 +92,9 @@ void _ARMV7M_Supervisor_call( void )
|
|||||||
++ef;
|
++ef;
|
||||||
_ARMV7M_Set_PSP( (uint32_t) ef );
|
_ARMV7M_Set_PSP( (uint32_t) ef );
|
||||||
|
|
||||||
_ISR_Nest_level = 0;
|
cpu_self->isr_nest_level = 0;
|
||||||
RTEMS_COMPILER_MEMORY_BARRIER();
|
|
||||||
|
|
||||||
if ( _Thread_Dispatch_necessary ) {
|
if ( cpu_self->dispatch_necessary ) {
|
||||||
_ARMV7M_Pendable_service_call();
|
_ARMV7M_Pendable_service_call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011 Sebastian Huber. All rights reserved.
|
* Copyright (c) 2011, 2017 Sebastian Huber. All rights reserved.
|
||||||
*
|
*
|
||||||
* embedded brains GmbH
|
* embedded brains GmbH
|
||||||
* Obere Lagerstr. 30
|
* Dornierstr. 4
|
||||||
* 82178 Puchheim
|
* 82178 Puchheim
|
||||||
* Germany
|
* Germany
|
||||||
* <rtems@embedded-brains.de>
|
* <rtems@embedded-brains.de>
|
||||||
@@ -30,19 +30,25 @@
|
|||||||
|
|
||||||
void _ARMV7M_Interrupt_service_enter( void )
|
void _ARMV7M_Interrupt_service_enter( void )
|
||||||
{
|
{
|
||||||
++_Thread_Dispatch_disable_level;
|
Per_CPU_Control *cpu_self = _Per_CPU_Get();
|
||||||
++_ISR_Nest_level;
|
|
||||||
|
++cpu_self->thread_dispatch_disable_level;
|
||||||
|
++cpu_self->isr_nest_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _ARMV7M_Interrupt_service_leave( void )
|
void _ARMV7M_Interrupt_service_leave( void )
|
||||||
{
|
{
|
||||||
--_ISR_Nest_level;
|
Per_CPU_Control *cpu_self = _Per_CPU_Get();
|
||||||
--_Thread_Dispatch_disable_level;
|
|
||||||
if (
|
--cpu_self->thread_dispatch_disable_level;
|
||||||
_ISR_Nest_level == 0
|
--cpu_self->isr_nest_level;
|
||||||
&& _Thread_Dispatch_disable_level == 0
|
|
||||||
&& _Thread_Dispatch_necessary
|
/*
|
||||||
) {
|
* Optimistically activate a pendable service call if a thread dispatch is
|
||||||
|
* necessary. The _ARMV7M_Pendable_service_call() will check that a thread
|
||||||
|
* dispatch is allowed.
|
||||||
|
*/
|
||||||
|
if ( cpu_self->dispatch_necessary ) {
|
||||||
_ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVSET;
|
_ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVSET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
ACLOCAL_AMFLAGS = -I ../aclocal
|
|
||||||
|
|
||||||
# NOTE: The order of the directories is essential.
|
|
||||||
# + tools, common and images are shared across many documents
|
|
||||||
|
|
||||||
SUBDIRS = tools started user bsp_howto porting develenv posix_users \
|
|
||||||
posix1003.1 filesystem networking ada_user \
|
|
||||||
new_chapters relnotes cpu_supplement shell
|
|
||||||
|
|
||||||
if USE_HTML
|
|
||||||
html_DATA = index.html
|
|
||||||
endif
|
|
||||||
|
|
||||||
EXTRA_DIST = common/cpright.texi common/setup.texi \
|
|
||||||
common/treedef.tex common/rtems.texi.in
|
|
||||||
|
|
||||||
if USE_HTML
|
|
||||||
html_imagesdir = $(htmldir)/images
|
|
||||||
endif
|
|
||||||
|
|
||||||
HTML_IMAGES = images/dir-arrow.gif images/dvi.gif images/missing-arrow.gif \
|
|
||||||
images/next-arrow.gif images/oaronly.jpg images/pdf.gif images/pdf1.gif \
|
|
||||||
images/rtems_logo.jpg images/prev-arrow.gif images/ps.gif \
|
|
||||||
images/up-arrow.gif
|
|
||||||
|
|
||||||
if USE_HTML
|
|
||||||
html_images_DATA = $(HTML_IMAGES)
|
|
||||||
endif
|
|
||||||
|
|
||||||
EXTRA_DIST += $(HTML_IMAGES)
|
|
||||||
|
|
||||||
CLEANFILES = common/rtems.texi
|
|
||||||
DISTCLEANFILES = common/rtems.sed
|
|
||||||
|
|
||||||
# HACK: This should not be here, but it makes "make distcheck" work.
|
|
||||||
EXTRA_DIST += ../scripts/setup.def ../COPYING
|
|
||||||
48
doc/README
48
doc/README
@@ -1,48 +0,0 @@
|
|||||||
Tools Required
|
|
||||||
==============
|
|
||||||
The following tools are used in the production of this documentation:
|
|
||||||
|
|
||||||
TeX
|
|
||||||
texi2html 1.82
|
|
||||||
texinfo-tex 4.13a
|
|
||||||
|
|
||||||
texi2html will be deprecated in the upcomine texinfo release. At that point,
|
|
||||||
we will need to provide support for texi2any.pl as an alternative means to
|
|
||||||
produce html output.
|
|
||||||
|
|
||||||
This was used by the authors to generate the directory tree figure
|
|
||||||
in the texinfo printed version:
|
|
||||||
|
|
||||||
tree (from the CTAN Archives -- see http://jasper.ora.com/ctan.html)
|
|
||||||
|
|
||||||
Changing the Version Number and Timestamp
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
RTEMS Version number is in configure.in. Edit that file and run bootstrap.
|
|
||||||
|
|
||||||
Documentation date is in common/setup.texi.in and also must be modified
|
|
||||||
by hand. bootstrap does not have to be run after modifying this file.
|
|
||||||
|
|
||||||
Making the Documentation
|
|
||||||
========================
|
|
||||||
|
|
||||||
cd rtems-XXX/doc
|
|
||||||
../bootstrap
|
|
||||||
./configure --enable-maintainer-mode
|
|
||||||
make all
|
|
||||||
make install
|
|
||||||
|
|
||||||
Cleaning
|
|
||||||
========
|
|
||||||
|
|
||||||
make clean
|
|
||||||
make distclean
|
|
||||||
make maintainer-clean
|
|
||||||
|
|
||||||
Making a Source Distribution
|
|
||||||
============================
|
|
||||||
This generates a rtems-<version>.tar.gz in the toplevel directory.
|
|
||||||
|
|
||||||
Making a Preformatted Distribution
|
|
||||||
==================================
|
|
||||||
Install and tar it up. :)
|
|
||||||
91
doc/TODO
91
doc/TODO
@@ -1,91 +0,0 @@
|
|||||||
This is a collection of things which need to be done to the various
|
|
||||||
manuals.
|
|
||||||
|
|
||||||
General Issues
|
|
||||||
==============
|
|
||||||
May need a Documentation Roadmap - for now, the "Where to
|
|
||||||
go from here" chapter in Getting Started is it.
|
|
||||||
|
|
||||||
Need a description of hello world and writing an application.
|
|
||||||
|
|
||||||
More automatic handling of version, date, revision, release, etc.
|
|
||||||
|
|
||||||
Eliminate use of gifs. [NOTE: ps, pdf, and dvi.gif are from
|
|
||||||
http://www.cit.gu.edu.au/images and the various arrow and
|
|
||||||
bookshelf icons came with texi2www.]
|
|
||||||
|
|
||||||
Redraw pictures as appropriate in open source tools.
|
|
||||||
|
|
||||||
|
|
||||||
Getting Started (C and Ada versions)
|
|
||||||
====================================
|
|
||||||
Switch back to using @url{} when pdf generation error is fixed.
|
|
||||||
|
|
||||||
Classic Users Guide
|
|
||||||
===================
|
|
||||||
May need to enhance descriptions in Primitive Data Types Chapter
|
|
||||||
|
|
||||||
POSIX User Notes
|
|
||||||
================
|
|
||||||
|
|
||||||
Add pages for network services.
|
|
||||||
|
|
||||||
Add timer() services if we have any.
|
|
||||||
|
|
||||||
|
|
||||||
Development Environment Guide
|
|
||||||
=============================
|
|
||||||
Either rename to "A Tour of the RTEMS Source Tree" or include
|
|
||||||
more information on the GNU tools.
|
|
||||||
|
|
||||||
The "C Suites" section is oddly named and the directory
|
|
||||||
tree included is wrong in that make is no longer under
|
|
||||||
the c directory. I think the build-tools make have
|
|
||||||
moved as well.
|
|
||||||
|
|
||||||
All the paths should be provided as relative paths
|
|
||||||
from the top of the RTEMS source tree. It wastes
|
|
||||||
valuable screen space to do otherwise.
|
|
||||||
|
|
||||||
The last paragraph of "C Suites" is vague and could
|
|
||||||
be written better. It should include the subdirectory
|
|
||||||
names as part of the textual description.
|
|
||||||
|
|
||||||
Should this documentation even use the phrase "C Implementation"
|
|
||||||
any longer?
|
|
||||||
|
|
||||||
Directory names should be in @code -- not "quoted".
|
|
||||||
|
|
||||||
In "Support Library Source Directory", look for "which installed"
|
|
||||||
|
|
||||||
In the latter part of the "libbsp" paragraph in "Support
|
|
||||||
Library Source Directory", there is reference to the
|
|
||||||
stubdr directory which is no longer there.
|
|
||||||
|
|
||||||
Update this section to include discussion of the shared
|
|
||||||
subdirectory and its relationship to the BSPs. Write this
|
|
||||||
in such a way that it can be passed on to Geoffroy Montel.
|
|
||||||
|
|
||||||
In the section, "Test Suite Source Directory", there is a
|
|
||||||
numeric count of the number of tests in each suite. This
|
|
||||||
should be eliminated for maintenance purposes.
|
|
||||||
|
|
||||||
The psxtest directory is not mentioned. Check that no others
|
|
||||||
have been forgotten.
|
|
||||||
|
|
||||||
There should probably be no reference to the Ada sample
|
|
||||||
applications. This document used to cover both implementations.
|
|
||||||
This now seems inappropriate.
|
|
||||||
|
|
||||||
The hello world sample test discussion mentions that it provides
|
|
||||||
a rudiementary test of the BSP startup code and the "RTEMS
|
|
||||||
C Library". This should be rewritten to tell mroe about what
|
|
||||||
this test shows (actually a lot). It should mention that this
|
|
||||||
test tries to avoid using interrupts.
|
|
||||||
|
|
||||||
The ticker test should mention that in contrast to hello, it
|
|
||||||
does use interrupts. :) It can be used to tune the clock
|
|
||||||
tick.
|
|
||||||
|
|
||||||
The ticker test documentation says it calls "tm_get" -- jeez
|
|
||||||
how old is this manual.
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
## _RTEMS_UPDATE_CONDITIONAL(FINAL,TMP)
|
|
||||||
AC_DEFUN([_RTEMS_UPDATE_CONDITIONAL],[
|
|
||||||
AS_IF([test -f $1],[
|
|
||||||
AS_IF([cmp -s $1 $2 2>/dev/null],
|
|
||||||
[
|
|
||||||
AC_MSG_NOTICE([$1 is unchanged])
|
|
||||||
rm -f $$2
|
|
||||||
],[
|
|
||||||
AC_MSG_NOTICE([creating $1])
|
|
||||||
rm -f $1
|
|
||||||
mv $2 $1
|
|
||||||
])
|
|
||||||
],[
|
|
||||||
AC_MSG_NOTICE([creating $1])
|
|
||||||
rm -f $1
|
|
||||||
mv $2 $1
|
|
||||||
])
|
|
||||||
])
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
#
|
|
||||||
# COPYRIGHT (c) 1988-2002.
|
|
||||||
# On-Line Applications Research Corporation (OAR).
|
|
||||||
# All rights reserved.
|
|
||||||
|
|
||||||
PROJECT = ada_user
|
|
||||||
|
|
||||||
include $(top_srcdir)/project.am
|
|
||||||
include $(top_srcdir)/main.am
|
|
||||||
|
|
||||||
COMMON_FILES += \
|
|
||||||
$(top_builddir)/user/barrier.texi $(top_builddir)/user/bsp.texi \
|
|
||||||
$(top_builddir)/user/clock.texi $(top_builddir)/user/concepts.texi \
|
|
||||||
$(top_builddir)/user/datatypes.texi $(top_builddir)/user/conf.texi \
|
|
||||||
$(top_builddir)/user/dirstat.texi $(top_builddir)/user/dpmem.texi \
|
|
||||||
$(top_builddir)/user/event.texi $(top_builddir)/user/fatal.texi \
|
|
||||||
$(top_builddir)/user/glossary.texi $(top_builddir)/user/init.texi \
|
|
||||||
$(top_builddir)/user/intr.texi $(top_builddir)/user/io.texi \
|
|
||||||
$(top_builddir)/user/libpci.texi \
|
|
||||||
$(top_builddir)/user/mp.texi $(top_builddir)/user/msg.texi \
|
|
||||||
$(top_builddir)/user/overview.texi $(top_builddir)/user/part.texi \
|
|
||||||
$(top_builddir)/user/preface.texi $(top_builddir)/user/region.texi \
|
|
||||||
$(top_builddir)/user/rtmon.texi $(top_builddir)/user/schedule.texi \
|
|
||||||
$(top_builddir)/user/sem.texi $(top_builddir)/user/signal.texi \
|
|
||||||
$(top_builddir)/user/task.texi $(top_builddir)/user/timer.texi \
|
|
||||||
$(top_builddir)/user/userext.texi $(top_builddir)/user/stackchk.texi \
|
|
||||||
$(top_builddir)/user/cpuuse.texi $(top_srcdir)/common/cpright.texi \
|
|
||||||
$(top_builddir)/user/object.texi $(top_builddir)/user/cbs.texi \
|
|
||||||
$(top_builddir)/user/smp.texi
|
|
||||||
|
|
||||||
FILES = example.texi
|
|
||||||
|
|
||||||
ObjectId-16Bits.eps: $(top_srcdir)/user/ObjectId-16Bits.eps
|
|
||||||
$(LN_S) $<
|
|
||||||
ObjectId-32Bits.eps: $(top_srcdir)/user/ObjectId-32Bits.eps
|
|
||||||
$(LN_S) $<
|
|
||||||
rtemspie.eps: $(top_srcdir)/user/rtemspie.eps
|
|
||||||
$(LN_S) $<
|
|
||||||
semaphore_attributes.eps: $(top_srcdir)/user/semaphore_attributes.eps
|
|
||||||
$(LN_S) $<
|
|
||||||
states.eps: $(top_srcdir)/user/states.eps
|
|
||||||
$(LN_S) $<
|
|
||||||
CLEANFILES += ObjectId-16Bits.eps ObjectId-32Bits.eps rtemspie.eps semaphore_attributes.eps states.eps
|
|
||||||
|
|
||||||
ObjectId-16Bits.png: $(top_srcdir)/user/ObjectId-16Bits.png
|
|
||||||
$(LN_S) $<
|
|
||||||
ObjectId-32Bits.png: $(top_srcdir)/user/ObjectId-32Bits.png
|
|
||||||
$(LN_S) $<
|
|
||||||
rtemsarc.png: $(top_srcdir)/user/rtemsarc.png
|
|
||||||
$(LN_S) $<
|
|
||||||
rtemspie.png: $(top_srcdir)/user/rtemspie.png
|
|
||||||
$(LN_S) $<
|
|
||||||
semaphore_attributes.png: $(top_srcdir)/user/semaphore_attributes.png
|
|
||||||
$(LN_S) $<
|
|
||||||
states.png: $(top_srcdir)/user/states.png
|
|
||||||
$(LN_S) $<
|
|
||||||
CLEANFILES += ObjectId-16Bits.png ObjectId-32Bits.png rtemsarc.png rtemspie.png semaphore_attributes.png states.png
|
|
||||||
|
|
||||||
info_TEXINFOS = ada_user.texi
|
|
||||||
ada_user_TEXINFOS = $(FILES) $(COMMON_FILES)
|
|
||||||
|
|
||||||
if USE_HTML
|
|
||||||
html_project_DATA += rtemsarc.png rtemspie.png states.png \
|
|
||||||
ObjectId-16Bits.png ObjectId-32Bits.png semaphore_attributes.png
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(PROJECT).dvi: rtemspie.eps states.eps ObjectId-16Bits.eps \
|
|
||||||
ObjectId-32Bits.eps semaphore_attributes.eps
|
|
||||||
PDF_IMAGES = rtemspie.pdf states.pdf ObjectId-16Bits.pdf \
|
|
||||||
ObjectId-32Bits.pdf semaphore_attributes.pdf
|
|
||||||
|
|
||||||
CLEANFILES += ada_user.info ada_user.info-? ada_user.info-??
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
\input texinfo @c -*-texinfo-*-
|
|
||||||
@c %**start of header
|
|
||||||
@setfilename ada_user.info
|
|
||||||
@setcontentsaftertitlepage
|
|
||||||
@syncodeindex vr fn
|
|
||||||
@synindex ky cp
|
|
||||||
@paragraphindent 0
|
|
||||||
@c %**end of header
|
|
||||||
|
|
||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1989-2014.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@c
|
|
||||||
@c Master file for the Ada User's Guide
|
|
||||||
@c
|
|
||||||
|
|
||||||
@c Joel's Questions
|
|
||||||
@c
|
|
||||||
@c 1. Why does paragraphindent only impact makeinfo?
|
|
||||||
@c 2. Why does paragraphindent show up in HTML?
|
|
||||||
@c
|
|
||||||
|
|
||||||
@include version.texi
|
|
||||||
@include common/setup.texi
|
|
||||||
@include common/rtems.texi
|
|
||||||
|
|
||||||
@ifset use-ascii
|
|
||||||
@dircategory RTEMS On-Line Manual
|
|
||||||
@direntry
|
|
||||||
* RTEMS Ada User: (ada_user). The Ada User's Guide
|
|
||||||
@end direntry
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
|
|
||||||
@c variable substitution info:
|
|
||||||
@c
|
|
||||||
@clear is-C
|
|
||||||
@set is-Ada
|
|
||||||
@set LANGUAGE Ada
|
|
||||||
@set STRUCTURE record
|
|
||||||
@set ROUTINE subprogram
|
|
||||||
@set OR or
|
|
||||||
@set RPREFIX RTEMS.
|
|
||||||
@set DIRPREFIX rtems.
|
|
||||||
@c the language is @value{LANGUAGE}
|
|
||||||
@c NOTE: don't use underscore in the name
|
|
||||||
@c
|
|
||||||
|
|
||||||
@c
|
|
||||||
@c Title Page Stuff
|
|
||||||
@c
|
|
||||||
|
|
||||||
@c
|
|
||||||
@c I don't really like having a short title page. --joel
|
|
||||||
@c
|
|
||||||
@c @shorttitlepage RTEMS Applications Ada User's Guide
|
|
||||||
|
|
||||||
@setchapternewpage odd
|
|
||||||
@settitle RTEMS Ada User's Guide
|
|
||||||
@titlepage
|
|
||||||
@finalout
|
|
||||||
|
|
||||||
@title RTEMS Applications Ada User's Guide
|
|
||||||
@subtitle Edition @value{EDITION}, for RTEMS @value{VERSION}
|
|
||||||
@sp 1
|
|
||||||
@subtitle @value{UPDATED}
|
|
||||||
@author On-Line Applications Research Corporation
|
|
||||||
@page
|
|
||||||
@include common/cpright.texi
|
|
||||||
@end titlepage
|
|
||||||
|
|
||||||
@c This prevents a black box from being printed on "overflow" lines.
|
|
||||||
@c The alternative is to rework a sentence to avoid this problem.
|
|
||||||
|
|
||||||
@contents
|
|
||||||
|
|
||||||
@ifnottex
|
|
||||||
@node Top, List of Figures, (dir), (dir)
|
|
||||||
@top RTEMS Applications Ada User's Guide
|
|
||||||
|
|
||||||
@menu
|
|
||||||
* List of Figures::
|
|
||||||
* Preface::
|
|
||||||
* Overview::
|
|
||||||
* Key Concepts::
|
|
||||||
* RTEMS Data Types::
|
|
||||||
* Initialization Manager::
|
|
||||||
* Task Manager::
|
|
||||||
* Interrupt Manager::
|
|
||||||
* Clock Manager::
|
|
||||||
* Timer Manager::
|
|
||||||
* Semaphore Manager::
|
|
||||||
* Message Manager::
|
|
||||||
* Event Manager::
|
|
||||||
* Signal Manager::
|
|
||||||
* Partition Manager::
|
|
||||||
* Region Manager::
|
|
||||||
* Dual-Ported Memory Manager::
|
|
||||||
* I/O Manager::
|
|
||||||
* Fatal Error Manager::
|
|
||||||
* Scheduling Concepts::
|
|
||||||
* Rate Monotonic Manager::
|
|
||||||
* Barrier Manager::
|
|
||||||
* Board Support Packages::
|
|
||||||
* User Extensions Manager::
|
|
||||||
* Configuring a System::
|
|
||||||
* Multiprocessing Manager::
|
|
||||||
* Symmetric Multiprocessing Services::
|
|
||||||
* PCI Library::
|
|
||||||
* Stack Bounds Checker::
|
|
||||||
* CPU Usage Statistics::
|
|
||||||
* Object Services::
|
|
||||||
* Chains::
|
|
||||||
* Red-Black Trees::
|
|
||||||
* Timespec Helpers::
|
|
||||||
* Constant Bandwidth Server Scheduler API::
|
|
||||||
* Directive Status Codes::
|
|
||||||
* Example Application::
|
|
||||||
* Glossary::
|
|
||||||
* Command and Variable Index::
|
|
||||||
* Concept Index::
|
|
||||||
@end menu
|
|
||||||
@end ifnottex
|
|
||||||
|
|
||||||
@node List of Figures, Preface, Top, Top
|
|
||||||
@unnumbered List of Figures
|
|
||||||
@listoffloats Figure
|
|
||||||
|
|
||||||
@include user/preface.texi
|
|
||||||
@include user/overview.texi
|
|
||||||
@include user/concepts.texi
|
|
||||||
@include user/datatypes.texi
|
|
||||||
@include user/init.texi
|
|
||||||
@include user/task.texi
|
|
||||||
@include user/intr.texi
|
|
||||||
@include user/clock.texi
|
|
||||||
@include user/timer.texi
|
|
||||||
@include user/sem.texi
|
|
||||||
@include user/msg.texi
|
|
||||||
@include user/event.texi
|
|
||||||
@include user/signal.texi
|
|
||||||
@include user/part.texi
|
|
||||||
@include user/region.texi
|
|
||||||
@include user/dpmem.texi
|
|
||||||
@include user/io.texi
|
|
||||||
@include user/fatal.texi
|
|
||||||
@include user/schedule.texi
|
|
||||||
@include user/rtmon.texi
|
|
||||||
@include user/barrier.texi
|
|
||||||
@include user/bsp.texi
|
|
||||||
@include user/userext.texi
|
|
||||||
@include user/conf.texi
|
|
||||||
@include user/mp.texi
|
|
||||||
@include user/smp.texi
|
|
||||||
@include user/libpci.texi
|
|
||||||
@include user/stackchk.texi
|
|
||||||
@include user/cpuuse.texi
|
|
||||||
@include user/object.texi
|
|
||||||
@include user/chains.texi
|
|
||||||
@include user/rbtree.texi
|
|
||||||
@include user/timespec.texi
|
|
||||||
@include user/cbs.texi
|
|
||||||
@include user/dirstat.texi
|
|
||||||
@include example.texi
|
|
||||||
@include user/glossary.texi
|
|
||||||
|
|
||||||
@node Command and Variable Index, Concept Index, Glossary, Top
|
|
||||||
@unnumbered Command and Variable Index
|
|
||||||
|
|
||||||
@c There are currently no Command and Variable Index entries.
|
|
||||||
|
|
||||||
@printindex fn
|
|
||||||
|
|
||||||
@node Concept Index, , Command and Variable Index, Top
|
|
||||||
@unnumbered Concept Index
|
|
||||||
|
|
||||||
@c There are currently no Concept Index entries.
|
|
||||||
@printindex cp
|
|
||||||
|
|
||||||
@bye
|
|
||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1989-2014.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@node Example Application, Glossary, Directive Status Codes STATUS_TEXT - Returns the enumeration name for a status code, Top
|
|
||||||
@chapter Example Application
|
|
||||||
|
|
||||||
@example
|
|
||||||
|
|
||||||
Currently there is no example Ada application provided.
|
|
||||||
|
|
||||||
@end example
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
@set UPDATED 24 February 2013
|
|
||||||
@set UPDATED-MONTH February 2013
|
|
||||||
@set EDITION 4.10.99.0
|
|
||||||
@set VERSION 4.10.99.0
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
@set UPDATED 17 July 2015
|
|
||||||
@set UPDATED-MONTH July 2015
|
|
||||||
@set EDITION 4.10.99.0
|
|
||||||
@set VERSION 4.10.99.0
|
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB |
@@ -1,135 +0,0 @@
|
|||||||
#
|
|
||||||
# COPYRIGHT (c) 1988-2002.
|
|
||||||
# On-Line Applications Research Corporation (OAR).
|
|
||||||
# All rights reserved.
|
|
||||||
|
|
||||||
PROJECT = bsp_howto
|
|
||||||
|
|
||||||
include $(top_srcdir)/project.am
|
|
||||||
include $(top_srcdir)/main.am
|
|
||||||
|
|
||||||
GENERATED_FILES = intro.texi target.texi makefiles.texi linkcmds.texi \
|
|
||||||
support.texi adaintr.texi init.texi console.texi clock.texi timer.texi \
|
|
||||||
rtc.texi ata.texi ide-ctrl.texi nvmem.texi network.texi shmsupp.texi \
|
|
||||||
framebuffer.texi analog.texi discrete.texi
|
|
||||||
|
|
||||||
COMMON_FILES += $(top_srcdir)/common/cpright.texi
|
|
||||||
|
|
||||||
PNG_FILES = Developer-User-Timeline.png BSPInitFlowchart-49.png \
|
|
||||||
TERMIOSFlow.png
|
|
||||||
|
|
||||||
if USE_HTML
|
|
||||||
html_project_DATA += $(PNG_FILES)
|
|
||||||
endif
|
|
||||||
|
|
||||||
FILES =
|
|
||||||
|
|
||||||
info_TEXINFOS = bsp_howto.texi
|
|
||||||
bsp_howto_TEXINFOS = $(FILES) $(COMMON_FILES) $(GENERATED_FILES)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process Automatically Generated Files
|
|
||||||
#
|
|
||||||
|
|
||||||
intro.texi: intro.t
|
|
||||||
$(BMENU2) -p "Top" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "Target Dependent Files" < $< > $@
|
|
||||||
|
|
||||||
target.texi: target.t
|
|
||||||
$(BMENU2) -p "Introduction" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "Makefiles" < $< > $@
|
|
||||||
|
|
||||||
makefiles.texi: makefiles.t
|
|
||||||
$(BMENU2) -p "Target Dependent Files Board Support Package Structure" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "Linker Script" < $< > $@
|
|
||||||
|
|
||||||
linkcmds.texi: linkcmds.t
|
|
||||||
$(BMENU2) -p "Makefiles Creating a New BSP Make Customization File" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "Ada95 Interrupt Support" < $< > $@
|
|
||||||
|
|
||||||
adaintr.texi: adaintr.t
|
|
||||||
$(BMENU2) -p "Linker Script Initialized Data" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "Miscellaneous Support Files" < $< > $@
|
|
||||||
|
|
||||||
support.texi: support.t
|
|
||||||
$(BMENU2) -p "Ada95 Interrupt Support Version Requirements" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
init.texi: init.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
console.texi: console.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
clock.texi: clock.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
timer.texi: timer.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
rtc.texi: rtc.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
ata.texi: ata.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
ide-ctrl.texi: ide-ctrl.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
nvmem.texi: nvmem.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
#
|
|
||||||
# Grab the chapter on writing a network device driver.
|
|
||||||
#
|
|
||||||
network.texi: ../networking/driver.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
shmsupp.texi: shmsupp.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
framebuffer.texi: framebuffer.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
analog.texi: analog.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
discrete.texi: discrete.t
|
|
||||||
$(BMENU2) -p "" \
|
|
||||||
-u "Top" \
|
|
||||||
-n "" < $< > $@
|
|
||||||
|
|
||||||
CLEANFILES += bsp_howto.info bsp_howto.info-?
|
|
||||||
|
|
||||||
EXTRA_DIST = adaintr.t analog.t ata.t clock.t console.t discrete.t \
|
|
||||||
ide-ctrl.t init.t intro.t linkcmds.t makefiles.t nvmem.t rtc.t shmsupp.t \
|
|
||||||
support.t target.t timer.t $(PNG_FILES) $(EPS_IMAGES)
|
|
||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB |
@@ -1,78 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Ada95 Interrupt Support
|
|
||||||
|
|
||||||
@section Introduction
|
|
||||||
|
|
||||||
This chapter describes what is required to enable Ada interrupt
|
|
||||||
and error exception handling when using GNAT over RTEMS.
|
|
||||||
|
|
||||||
The GNAT Ada95 interrupt support RTEMS was developed by
|
|
||||||
Jiri Gaisler <jgais@@ws.estec.esa.nl> who also wrote this
|
|
||||||
chapter.
|
|
||||||
|
|
||||||
@section Mapping Interrupts to POSIX Signals
|
|
||||||
|
|
||||||
In Ada95, interrupts can be attached with the interrupt_attach pragma.
|
|
||||||
For most systems, the gnat run-time will use POSIX signal to implement
|
|
||||||
the interrupt handling, mapping one signal per interrupt. For interrupts
|
|
||||||
to be propagated to the attached Ada handler, the corresponding signal
|
|
||||||
must be raised when the interrupt occurs.
|
|
||||||
|
|
||||||
The same mechanism is used to generate Ada error exceptions.
|
|
||||||
Three error exceptions are defined: program, constraint and storage
|
|
||||||
error. These are generated by raising the predefined signals: SIGILL,
|
|
||||||
SIGFPE and SIGSEGV. These signals should be raised when a spurious
|
|
||||||
or erroneous trap occurs.
|
|
||||||
|
|
||||||
To enable gnat interrupt and error exception support for a particular
|
|
||||||
BSP, the following has to be done:
|
|
||||||
|
|
||||||
@enumerate
|
|
||||||
|
|
||||||
@item Write an interrupt/trap handler that will raise the corresponding
|
|
||||||
signal depending on the interrupt/trap number.
|
|
||||||
|
|
||||||
@item Install the interrupt handler for all interrupts/traps that will be
|
|
||||||
handled by gnat (including spurious).
|
|
||||||
|
|
||||||
@item At startup, gnat calls @code{__gnat_install_handler()}. The BSP
|
|
||||||
must provide this function which installs the interrupt/trap handlers.
|
|
||||||
|
|
||||||
@end enumerate
|
|
||||||
|
|
||||||
Which CPU-interrupt will generate which signal is implementation
|
|
||||||
defined. There are 32 POSIX signals (1 - 32), and all except the
|
|
||||||
three error signals (SIGILL, SIGFPE and SIGSEGV) can be used. I
|
|
||||||
would suggest to use the upper 16 (17 - 32) which do not
|
|
||||||
have an assigned POSIX name.
|
|
||||||
|
|
||||||
Note that the pragma interrupt_attach will only bind a signal
|
|
||||||
to a particular Ada handler - it will not unmask the
|
|
||||||
interrupt or do any other things to enable it. This have to be
|
|
||||||
done separately, typically by writing various device register.
|
|
||||||
|
|
||||||
@section Example Ada95 Interrupt Program
|
|
||||||
|
|
||||||
An example program (@code{irq_test}) is included in the
|
|
||||||
Ada examples package to show how interrupts can be handled
|
|
||||||
in Ada95. Note that generation of the test interrupt
|
|
||||||
(@code{irqforce.c}) is BSP specific and must be edited.
|
|
||||||
|
|
||||||
NOTE: The @code{irq_test} example was written for the SPARC/ERC32
|
|
||||||
BSP.
|
|
||||||
|
|
||||||
@section Version Requirements
|
|
||||||
|
|
||||||
With RTEMS 4.0, a patch was required to psignal.c in RTEMS
|
|
||||||
sources (to correct a bug associated to the default action of
|
|
||||||
signals 15-32). The SPARC/ERC32 RTEMS BSP includes the
|
|
||||||
@code{gnatsupp} subdirectory that can be used as an example
|
|
||||||
for other BSPs.
|
|
||||||
|
|
||||||
With GNAT 3.11p, a patch is required for @code{a-init.c} to invoke
|
|
||||||
the BSP specific routine that installs the exception handlers.
|
|
||||||
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Analog Driver
|
|
||||||
|
|
||||||
The Analog driver is responsible for providing an
|
|
||||||
interface to Digital to Analog Converters (DACs) and
|
|
||||||
Analog to Digital Converters (ADCs). The capabilities provided
|
|
||||||
by this class of device driver are:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item Initialize an Analog Board
|
|
||||||
@item Open a Particular Analog
|
|
||||||
@item Close a Particular Analog
|
|
||||||
@item Read from a Particular Analog
|
|
||||||
@item Write to a Particular Analog
|
|
||||||
@item Reset DACs
|
|
||||||
@item Reinitialize DACS
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
Most analog devices are found on I/O cards that support multiple
|
|
||||||
DACs or ADCs on a single card.
|
|
||||||
|
|
||||||
There are currently no analog device drivers included in the
|
|
||||||
RTEMS source tree. The information provided in this chapter
|
|
||||||
is based on drivers developed for applications using RTEMS.
|
|
||||||
It is hoped that this driver model information can form the
|
|
||||||
basis for a standard analog driver model that can be supported
|
|
||||||
in future RTEMS distribution.
|
|
||||||
|
|
||||||
@section Major and Minor Numbers
|
|
||||||
|
|
||||||
The @b{major} number of a device driver is its index in the
|
|
||||||
RTEMS Device Address Table.
|
|
||||||
|
|
||||||
A @b{minor} number is associated with each device instance
|
|
||||||
managed by a particular device driver. An RTEMS minor number
|
|
||||||
is an @code{unsigned32} entity. Convention calls
|
|
||||||
dividing the bits in the minor number down into categories
|
|
||||||
like the following:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item @b{board} - indicates the board a particular device is located on
|
|
||||||
@item @b{port} - indicates the particular device on a board.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
From the above, it should be clear that a single device driver
|
|
||||||
can support multiple copies of the same board in a single system.
|
|
||||||
The minor number is used to distinguish the devices.
|
|
||||||
|
|
||||||
@section Analog Driver Configuration
|
|
||||||
|
|
||||||
There is not a standard analog driver configuration table but some
|
|
||||||
fields are common across different drivers. The analog driver
|
|
||||||
configuration table is typically an array of structures with each
|
|
||||||
structure containing the information for a particular board.
|
|
||||||
The following is a list of the type of information normally required
|
|
||||||
to configure an analog board:
|
|
||||||
|
|
||||||
@table @b
|
|
||||||
@item board_offset
|
|
||||||
is the base address of a board.
|
|
||||||
|
|
||||||
@item DAC_initial_values
|
|
||||||
is an array of the voltages that should be written to each DAC
|
|
||||||
during initialization. This allows the driver to start the board
|
|
||||||
in a known state.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@section Initialize an Analog Board
|
|
||||||
|
|
||||||
At system initialization, the analog driver's initialization entry point
|
|
||||||
will be invoked. As part of initialization, the driver will perform
|
|
||||||
whatever board initialization is required and then set all
|
|
||||||
outputs to their configured initial state.
|
|
||||||
|
|
||||||
The analog driver may register a device name for each DAC and ADC in
|
|
||||||
the system.
|
|
||||||
|
|
||||||
@section Open a Particular Analog
|
|
||||||
|
|
||||||
This is the driver open call. Usually this call does nothing other than
|
|
||||||
validate the minor number.
|
|
||||||
|
|
||||||
With some drivers, it may be necessary to allocate memory when a particular
|
|
||||||
device is opened. If that is the case, then this is often the place
|
|
||||||
to do this operation.
|
|
||||||
|
|
||||||
@section Close a Particular Analog
|
|
||||||
|
|
||||||
This is the driver close call. Usually this call does nothing.
|
|
||||||
|
|
||||||
With some drivers, it may be necessary to allocate memory when a particular
|
|
||||||
device is opened. If that is the case, then this is the place
|
|
||||||
where that memory should be deallocated.
|
|
||||||
|
|
||||||
@section Read from a Particular Analog
|
|
||||||
|
|
||||||
This corresponds to the driver read call. After validating the minor
|
|
||||||
number and arguments, this call reads the indicated device. Most analog
|
|
||||||
devices store the last value written to a DAC. Since DACs are output
|
|
||||||
only devices, saving the last written value gives the appearance that
|
|
||||||
DACs can be read from also. If the device is an ADC, then it is sampled.
|
|
||||||
|
|
||||||
@b{NOTE:} Many boards have multiple analog inputs but only one ADC. On
|
|
||||||
these boards, it will be necessary to provide some type of mutual exclusion
|
|
||||||
during reads. On these boards, there is a MUX which must be switched
|
|
||||||
before sampling the ADC. After the MUX is switched, the driver must
|
|
||||||
delay some short period of time (usually microseconds) before the
|
|
||||||
signal is stable and can be sampled. To make matters worse, some ADCs
|
|
||||||
cannot respond to wide voltage swings in a single sample. On these
|
|
||||||
ADCs, one must do two samples when the voltage swing is too large.
|
|
||||||
On a practical basis, this means that the driver usually ends up
|
|
||||||
double sampling the ADC on these systems.
|
|
||||||
|
|
||||||
The value returned is a single precision floating point number
|
|
||||||
representing the voltage read. This value is stored in the
|
|
||||||
@code{argument_block} passed in to the call. By returning the
|
|
||||||
voltage, the caller is freed from having to know the number of
|
|
||||||
bits in the analog and board dependent conversion algorithm.
|
|
||||||
|
|
||||||
@section Write to a Particular Analog
|
|
||||||
|
|
||||||
This corresponds to the driver write call. After validating the minor
|
|
||||||
number and arguments, this call writes the indicated device. If the
|
|
||||||
specified device is an ADC, then an error is usually returned.
|
|
||||||
|
|
||||||
The value written is a single precision floating point number
|
|
||||||
representing the voltage to be written to the specified DAC.
|
|
||||||
This value is stored in the @code{argument_block} passed in to the
|
|
||||||
call. By passing the voltage to the device driver, the caller is
|
|
||||||
freed from having to know the number of bits in the analog
|
|
||||||
and board dependent conversion algorithm.
|
|
||||||
|
|
||||||
@section Reset DACs
|
|
||||||
|
|
||||||
This is one of the IOCTL functions supported by the I/O control
|
|
||||||
device driver entry point. When this IOCTL function is invoked,
|
|
||||||
all of the DACs are written to 0.0 volts.
|
|
||||||
|
|
||||||
@section Reinitialize DACS
|
|
||||||
|
|
||||||
This is one of the IOCTL functions supported by the I/O control
|
|
||||||
device driver entry point. When this IOCTL function is invoked,
|
|
||||||
all of the DACs are written with the initial value configured
|
|
||||||
for this device.
|
|
||||||
|
|
||||||
@section Get Last Written Values
|
|
||||||
|
|
||||||
This is one of the IOCTL functions supported by the I/O control
|
|
||||||
device driver entry point. When this IOCTL function is invoked,
|
|
||||||
the following information is returned to the caller:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item last value written to the specified DAC
|
|
||||||
@item timestamp of when the last write was performed
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter ATA Driver
|
|
||||||
|
|
||||||
@section Terms
|
|
||||||
|
|
||||||
ATA device - physical device attached to an IDE controller
|
|
||||||
|
|
||||||
@section Introduction
|
|
||||||
|
|
||||||
ATA driver provides generic interface to an ATA device. ATA driver is
|
|
||||||
hardware independent implementation of ATA standard defined in working draft
|
|
||||||
"AT Attachment Interface with Extensions (ATA-2)" X3T10/0948D revision 4c,
|
|
||||||
March 18, 1996. ATA Driver based on IDE Controller Driver and may be used for
|
|
||||||
computer systems with single IDE controller and with multiple as well. Although
|
|
||||||
current implementation has several restrictions detailed below ATA driver
|
|
||||||
architecture allows easily extend the driver. Current restrictions are:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item Only mandatory (see draft p.29) and two optional (READ/WRITE MULTIPLE)
|
|
||||||
commands are implemented
|
|
||||||
@item Only PIO mode is supported but both poll and interrupt driven
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
The reference implementation for ATA driver can be found in
|
|
||||||
@code{cpukit/libblock/src/ata.c}.
|
|
||||||
|
|
||||||
@section Initialization
|
|
||||||
|
|
||||||
The @code{ata_initialize} routine is responsible for ATA driver
|
|
||||||
initialization. The main goal of the initialization is to detect and
|
|
||||||
register in the system all ATA devices attached to IDE controllers
|
|
||||||
successfully initialized by the IDE Controller driver.
|
|
||||||
|
|
||||||
In the implementation of the driver, the following actions are performed:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver ata_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
initialize internal ATA driver data structure
|
|
||||||
|
|
||||||
for each IDE controller successfully initialized by the IDE Controller
|
|
||||||
driver
|
|
||||||
if the controller is interrupt driven
|
|
||||||
set up interrupt handler
|
|
||||||
|
|
||||||
obtain information about ATA devices attached to the controller
|
|
||||||
with help of EXECUTE DEVICE DIAGNOSTIC command
|
|
||||||
|
|
||||||
for each ATA device detected on the controller
|
|
||||||
obtain device parameters with help of DEVICE IDENTIFY command
|
|
||||||
|
|
||||||
register new ATA device as new block device in the system
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
Special processing of ATA commands is required because of absence of
|
|
||||||
multitasking environment during the driver initialization.
|
|
||||||
|
|
||||||
Detected ATA devices are registered in the system as physical block devices
|
|
||||||
(see libblock library description). Device names are formed based on IDE
|
|
||||||
controller minor number device is attached to and device number on the
|
|
||||||
controller (0 - Master, 1 - Slave). In current implementation 64 minor
|
|
||||||
numbers are reserved for each ATA device which allows to support up to 63
|
|
||||||
logical partitions per device.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
controller minor device number device name ata device minor
|
|
||||||
0 0 hda 0
|
|
||||||
0 1 hdb 64
|
|
||||||
1 0 hdc 128
|
|
||||||
1 1 hdd 172
|
|
||||||
... ... ...
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section ATA Driver Architecture
|
|
||||||
|
|
||||||
@subsection ATA Driver Main Internal Data Structures
|
|
||||||
|
|
||||||
ATA driver works with ATA requests. ATA request is described by the
|
|
||||||
following structure:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
/* ATA request */
|
|
||||||
typedef struct ata_req_s @{
|
|
||||||
Chain_Node link; /* link in requests chain */
|
|
||||||
char type; /* request type */
|
|
||||||
ata_registers_t regs; /* ATA command */
|
|
||||||
uint32_t cnt; /* Number of sectors to be exchanged */
|
|
||||||
uint32_t cbuf; /* number of current buffer from breq in use */
|
|
||||||
uint32_t pos; /* current position in 'cbuf' */
|
|
||||||
blkdev_request *breq; /* blkdev_request which corresponds to the
|
|
||||||
* ata request
|
|
||||||
*/
|
|
||||||
rtems_id sema; /* semaphore which is used if synchronous
|
|
||||||
* processing of the ata request is required
|
|
||||||
*/
|
|
||||||
rtems_status_code status; /* status of ata request processing */
|
|
||||||
int error; /* error code */
|
|
||||||
@} ata_req_t;
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
ATA driver supports separate ATA requests queues for each IDE
|
|
||||||
controller (one queue per controller). The following structure contains
|
|
||||||
information about controller's queue and devices attached to the controller:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
/*
|
|
||||||
* This structure describes controller state, devices configuration on the
|
|
||||||
* controller and chain of ATA requests to the controller.
|
|
||||||
*/
|
|
||||||
typedef struct ata_ide_ctrl_s @{
|
|
||||||
bool present; /* controller state */
|
|
||||||
ata_dev_t device[2]; /* ata devices description */
|
|
||||||
Chain_Control reqs; /* requests chain */
|
|
||||||
@} ata_ide_ctrl_t;
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
Driver uses array of the structures indexed by the controllers minor
|
|
||||||
number.
|
|
||||||
|
|
||||||
The following structure allows to map an ATA device to the pair (IDE
|
|
||||||
controller minor number device is attached to, device number
|
|
||||||
on the controller):
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
/*
|
|
||||||
* Mapping of rtems ATA devices to the following pairs:
|
|
||||||
* (IDE controller number served the device, device number on the controller)
|
|
||||||
*/
|
|
||||||
typedef struct ata_ide_dev_s @{
|
|
||||||
int ctrl_minor;/* minor number of IDE controller serves rtems ATA device */
|
|
||||||
int device; /* device number on IDE controller (0 or 1) */
|
|
||||||
@} ata_ide_dev_t;
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
Driver uses array of the structures indexed by the ATA devices minor
|
|
||||||
number.
|
|
||||||
|
|
||||||
ATA driver defines the following internal events:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
/* ATA driver events */
|
|
||||||
typedef enum ata_msg_type_s @{
|
|
||||||
ATA_MSG_GEN_EVT = 1, /* general event */
|
|
||||||
ATA_MSG_SUCCESS_EVT, /* success event */
|
|
||||||
ATA_MSG_ERROR_EVT, /* error event */
|
|
||||||
ATA_MSG_PROCESS_NEXT_EVT /* process next ata request event */
|
|
||||||
@} ata_msg_type_t;
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Brief ATA Driver Core Overview
|
|
||||||
|
|
||||||
All ATA driver functionality is available via ATA driver ioctl. Current
|
|
||||||
implementation supports only two ioctls: BLKIO_REQUEST and
|
|
||||||
ATAIO_SET_MULTIPLE_MODE. Each ATA driver ioctl() call generates an
|
|
||||||
ATA request which is appended to the appropriate controller queue depending
|
|
||||||
on ATA device the request belongs to. If appended request is single request in
|
|
||||||
the controller's queue then ATA driver event is generated.
|
|
||||||
|
|
||||||
ATA driver task which manages queue of ATA driver events is core of ATA
|
|
||||||
driver. In current driver version queue of ATA driver events implemented
|
|
||||||
as RTEMS message queue. Each message contains event type, IDE controller
|
|
||||||
minor number on which event happened and error if an error occurred. Events
|
|
||||||
may be generated either by ATA driver ioctl call or by ATA driver task itself.
|
|
||||||
Each time ATA driver task receives an event it gets controller minor number
|
|
||||||
from event, takes first ATA request from controller queue and processes it
|
|
||||||
depending on request and event types. An ATA request processing may also
|
|
||||||
includes sending of several events. If ATA request processing is finished
|
|
||||||
the ATA request is removed from the controller queue. Note, that in current
|
|
||||||
implementation maximum one event per controller may be queued at any moment
|
|
||||||
of the time.
|
|
||||||
|
|
||||||
(This part seems not very clear, hope I rewrite it soon)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
\input texinfo @c -*-texinfo-*-
|
|
||||||
@c %**start of header
|
|
||||||
@setfilename bsp_howto.info
|
|
||||||
@setcontentsaftertitlepage
|
|
||||||
@syncodeindex vr fn
|
|
||||||
@synindex ky cp
|
|
||||||
@paragraphindent 0
|
|
||||||
@c %**end of header
|
|
||||||
|
|
||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1989-2013.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@c
|
|
||||||
@c Master file for the Getting Started (C) Guide
|
|
||||||
@c
|
|
||||||
|
|
||||||
@include version.texi
|
|
||||||
@include common/setup.texi
|
|
||||||
@include common/rtems.texi
|
|
||||||
|
|
||||||
@ifset use-ascii
|
|
||||||
@dircategory RTEMS On-Line Manual
|
|
||||||
@direntry
|
|
||||||
* RTEMS BSP-Howto: (bsp_howto). BSP and Device Driver Development Guide.
|
|
||||||
@end direntry
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
@c
|
|
||||||
@c Title Page Stuff
|
|
||||||
@c
|
|
||||||
|
|
||||||
@c
|
|
||||||
@c I don't really like having a short title page. --joel
|
|
||||||
@c
|
|
||||||
@c @shorttitlepage BSP and Device Driver Development Guide
|
|
||||||
|
|
||||||
@setchapternewpage odd
|
|
||||||
@settitle BSP and Device Driver Development Guide
|
|
||||||
@titlepage
|
|
||||||
@finalout
|
|
||||||
|
|
||||||
@title BSP and Device Driver Development Guide
|
|
||||||
@subtitle Edition @value{EDITION}, for @value{VERSION}
|
|
||||||
@sp 1
|
|
||||||
@subtitle @value{UPDATED}
|
|
||||||
@author On-Line Applications Research Corporation
|
|
||||||
@page
|
|
||||||
@include common/cpright.texi
|
|
||||||
@end titlepage
|
|
||||||
|
|
||||||
@c This prevents a black box from being printed on "overflow" lines.
|
|
||||||
@c The alternative is to rework a sentence to avoid this problem.
|
|
||||||
|
|
||||||
@contents
|
|
||||||
|
|
||||||
@ifnottex
|
|
||||||
@node Top, Introduction, (dir), (dir)
|
|
||||||
@top RTEMS BSP and Device Driver Development Guide
|
|
||||||
|
|
||||||
@menu
|
|
||||||
* Introduction::
|
|
||||||
* Target Dependent Files::
|
|
||||||
* Makefiles::
|
|
||||||
* Linker Script::
|
|
||||||
* Miscellaneous Support Files::
|
|
||||||
* Ada95 Interrupt Support::
|
|
||||||
* Initialization Code::
|
|
||||||
* Console Driver::
|
|
||||||
* Clock Driver::
|
|
||||||
* Timer Driver::
|
|
||||||
* Real-Time Clock Driver::
|
|
||||||
* ATA Driver::
|
|
||||||
* IDE Controller Driver::
|
|
||||||
* Networking Driver::
|
|
||||||
* Non-Volatile Memory Driver::
|
|
||||||
* Shared Memory Support Driver::
|
|
||||||
* Frame Buffer Driver::
|
|
||||||
* Analog Driver::
|
|
||||||
* Discrete Driver::
|
|
||||||
* Command and Variable Index::
|
|
||||||
* Concept Index::
|
|
||||||
@end menu
|
|
||||||
@end ifnottex
|
|
||||||
|
|
||||||
@include intro.texi
|
|
||||||
@include target.texi
|
|
||||||
@include makefiles.texi
|
|
||||||
@include linkcmds.texi
|
|
||||||
@include support.texi
|
|
||||||
@include adaintr.texi
|
|
||||||
@include init.texi
|
|
||||||
@include console.texi
|
|
||||||
@include clock.texi
|
|
||||||
@include timer.texi
|
|
||||||
@include rtc.texi
|
|
||||||
@include ata.texi
|
|
||||||
@include ide-ctrl.texi
|
|
||||||
@include nvmem.texi
|
|
||||||
@include network.texi
|
|
||||||
@include shmsupp.texi
|
|
||||||
@include framebuffer.texi
|
|
||||||
@include analog.texi
|
|
||||||
@include discrete.texi
|
|
||||||
|
|
||||||
@node Command and Variable Index, Concept Index, , Top
|
|
||||||
@unnumbered Command and Variable Index
|
|
||||||
|
|
||||||
There are currently no Command and Variable Index entries.
|
|
||||||
|
|
||||||
@c @printindex fn
|
|
||||||
|
|
||||||
@node Concept Index, , Command and Variable Index, Top
|
|
||||||
@unnumbered Concept Index
|
|
||||||
|
|
||||||
There are currently no Concept Index entries.
|
|
||||||
@c @printindex cp
|
|
||||||
|
|
||||||
@bye
|
|
||||||
|
|
||||||
@@ -1,299 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Clock Driver
|
|
||||||
|
|
||||||
@section Introduction
|
|
||||||
|
|
||||||
The purpose of the clock driver is to provide two services for the operating
|
|
||||||
system.
|
|
||||||
@itemize @bullet
|
|
||||||
@item A steady time basis to the kernel, so that the RTEMS primitives that need
|
|
||||||
a clock tick work properly. See the @cite{Clock Manager} chapter of the
|
|
||||||
@cite{RTEMS Application C User's Guide} for more details.
|
|
||||||
@item An optional time counter to generate timestamps of the uptime and wall
|
|
||||||
clock time.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
The clock driver is usually located in the @file{clock} directory of the BSP.
|
|
||||||
Clock drivers should use the @dfn{Clock Driver Shell} available via the
|
|
||||||
@file{clockdrv_shell.h} include file.
|
|
||||||
|
|
||||||
@section Clock Driver Shell
|
|
||||||
|
|
||||||
The @dfn{Clock Driver Shell} include file defines the clock driver functions
|
|
||||||
declared in @code{#include <rtems/clockdrv.h>} which are used by RTEMS
|
|
||||||
configuration file @code{#include <rtems/confdefs.h>}. In case the application
|
|
||||||
configuration defines @code{#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER},
|
|
||||||
then the clock driver is registered and should provide its services to the
|
|
||||||
operating system. A hardware specific clock driver must provide some
|
|
||||||
functions, defines and macros for the @dfn{Clock Driver Shell} which are
|
|
||||||
explained here step by step. A clock driver file looks in general like this.
|
|
||||||
|
|
||||||
@example
|
|
||||||
/*
|
|
||||||
* A section with functions, defines and macros to provide hardware specific
|
|
||||||
* functions for the Clock Driver Shell.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../../../shared/clockdrv_shell.h"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Initialization
|
|
||||||
|
|
||||||
Depending on the hardware capabilities one out of three clock driver variants
|
|
||||||
must be selected.
|
|
||||||
@itemize @bullet
|
|
||||||
@item The most basic clock driver provides only a periodic interrupt service
|
|
||||||
routine which calls @code{rtems_clock_tick()}. The interval is determined by
|
|
||||||
the application configuration via @code{#define
|
|
||||||
CONFIGURE_MICROSECONDS_PER_TICK} and can be obtained via
|
|
||||||
@code{rtems_configuration_get_microseconds_per_tick()}. The timestamp
|
|
||||||
resolution is limited to the clock tick interval.
|
|
||||||
@item In case the hardware lacks support for a free running counter, then the
|
|
||||||
module used for the clock tick may provide support for timestamps with a
|
|
||||||
resolution below the clock tick interval. For this so called simple
|
|
||||||
timecounters can be used.
|
|
||||||
@item The desired variant uses a free running counter to provide accurate
|
|
||||||
timestamps. This variant is mandatory on SMP configurations.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@subsubsection Clock Tick Only Variant
|
|
||||||
|
|
||||||
@example
|
|
||||||
static void some_support_initialize_hardware( void )
|
|
||||||
@{
|
|
||||||
/* Initialize hardware */
|
|
||||||
@}
|
|
||||||
|
|
||||||
#define Clock_driver_support_initialize_hardware() \
|
|
||||||
some_support_initialize_hardware()
|
|
||||||
|
|
||||||
/* Indicate that this clock driver lacks a proper timecounter in hardware */
|
|
||||||
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
|
|
||||||
|
|
||||||
#include "../../../shared/clockdrv_shell.h"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsubsection Simple Timecounter Variant
|
|
||||||
|
|
||||||
@example
|
|
||||||
#include <rtems/timecounter.h>
|
|
||||||
|
|
||||||
static rtems_timecounter_simple some_tc;
|
|
||||||
|
|
||||||
static uint32_t some_tc_get( rtems_timecounter_simple *tc )
|
|
||||||
@{
|
|
||||||
return some.counter;
|
|
||||||
@}
|
|
||||||
|
|
||||||
static void some_tc_at_tick( rtems_timecounter_simple *tc )
|
|
||||||
@{
|
|
||||||
/*
|
|
||||||
* Do work necessary at the clock tick interrupt, e.g. clear a pending flag.
|
|
||||||
*/
|
|
||||||
@}
|
|
||||||
|
|
||||||
static bool some_tc_is_pending( rtems_timecounter_simple *tc )
|
|
||||||
@{
|
|
||||||
return some.is_pending;
|
|
||||||
@}
|
|
||||||
|
|
||||||
static uint32_t some_tc_get_timecount( struct timecounter *tc )
|
|
||||||
@{
|
|
||||||
return rtems_timecounter_simple_downcounter_get(
|
|
||||||
tc,
|
|
||||||
some_tc_get,
|
|
||||||
some_tc_is_pending
|
|
||||||
);
|
|
||||||
@}
|
|
||||||
|
|
||||||
static void some_tc_tick( void )
|
|
||||||
@{
|
|
||||||
rtems_timecounter_simple_downcounter_tick(
|
|
||||||
&some_tc,
|
|
||||||
some_tc_get,
|
|
||||||
some_tc_at_tick
|
|
||||||
);
|
|
||||||
@}
|
|
||||||
|
|
||||||
static void some_support_initialize_hardware( void )
|
|
||||||
@{
|
|
||||||
uint32_t frequency = 123456;
|
|
||||||
uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
|
|
||||||
uint32_t timecounter_ticks_per_clock_tick =
|
|
||||||
( frequency * us_per_tick ) / 1000000;
|
|
||||||
|
|
||||||
/* Initialize hardware */
|
|
||||||
|
|
||||||
rtems_timecounter_simple_install(
|
|
||||||
&some_tc,
|
|
||||||
frequency,
|
|
||||||
timecounter_ticks_per_clock_tick,
|
|
||||||
some_tc_get_timecount
|
|
||||||
);
|
|
||||||
@}
|
|
||||||
|
|
||||||
#define Clock_driver_support_initialize_hardware() \
|
|
||||||
some_support_initialize_hardware()
|
|
||||||
|
|
||||||
#define Clock_driver_timecounter_tick() \
|
|
||||||
some_tc_tick()
|
|
||||||
|
|
||||||
#include "../../../shared/clockdrv_shell.h"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsubsection Timecounter Variant
|
|
||||||
|
|
||||||
This variant is preferred since it is the most efficient and yields the most
|
|
||||||
accurate timestamps. It is also mandatory on SMP configurations to obtain
|
|
||||||
valid timestamps. The hardware must provide a periodic interrupt to service
|
|
||||||
the clock tick and a free running counter for the timecounter. The free
|
|
||||||
running counter must have a power of two period. The @code{tc_counter_mask}
|
|
||||||
must be initialized to the free running counter period minus one, e.g. for a
|
|
||||||
32-bit counter this is 0xffffffff. The @code{tc_get_timecount} function must
|
|
||||||
return the current counter value (the counter values must increase, so if the
|
|
||||||
counter counts down, a conversion is necessary). Use
|
|
||||||
@code{RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER} for the @code{tc_quality}. Set
|
|
||||||
@code{tc_frequency} to the frequency of the free running counter in Hz. All
|
|
||||||
other fields of the @code{struct timecounter} must be zero initialized.
|
|
||||||
Install the initialized timecounter via @code{rtems_timecounter_install()}.
|
|
||||||
|
|
||||||
@example
|
|
||||||
#include <rtems/timecounter.h>
|
|
||||||
|
|
||||||
static struct timecounter some_tc;
|
|
||||||
|
|
||||||
static uint32_t some_tc_get_timecount( struct timecounter *tc )
|
|
||||||
@{
|
|
||||||
some.free_running_counter;
|
|
||||||
@}
|
|
||||||
|
|
||||||
static void some_support_initialize_hardware( void )
|
|
||||||
@{
|
|
||||||
uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
|
|
||||||
uint32_t frequency = 123456;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The multiplication must be done in 64-bit arithmetic to avoid an integer
|
|
||||||
* overflow on targets with a high enough counter frequency.
|
|
||||||
*/
|
|
||||||
uint32_t interval = (uint32_t) ( ( frequency * us_per_tick ) / 1000000 );
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize hardware and set up a periodic interrupt for the configuration
|
|
||||||
* based interval.
|
|
||||||
*/
|
|
||||||
|
|
||||||
some_tc.tc_get_timecount = some_tc_get_timecount;
|
|
||||||
some_tc.tc_counter_mask = 0xffffffff;
|
|
||||||
some_tc.tc_frequency = frequency;
|
|
||||||
some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
|
|
||||||
rtems_timecounter_install( &some_tc );
|
|
||||||
@}
|
|
||||||
|
|
||||||
#define Clock_driver_support_initialize_hardware() \
|
|
||||||
some_support_initialize_hardware()
|
|
||||||
|
|
||||||
#include "../../../shared/clockdrv_shell.h"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Install Clock Tick Interrupt Service Routine
|
|
||||||
|
|
||||||
The clock driver must provide a function to install the clock tick interrupt
|
|
||||||
service routine via @code{Clock_driver_support_install_isr()}.
|
|
||||||
|
|
||||||
@example
|
|
||||||
#include <bsp/irq.h>
|
|
||||||
#include <bsp/fatal.h>
|
|
||||||
|
|
||||||
static void some_support_install_isr( rtems_interrupt_handler isr )
|
|
||||||
@{
|
|
||||||
rtems_status_code sc;
|
|
||||||
|
|
||||||
sc = rtems_interrupt_handler_install(
|
|
||||||
SOME_IRQ,
|
|
||||||
"Clock",
|
|
||||||
RTEMS_INTERRUPT_UNIQUE,
|
|
||||||
isr,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
if ( sc != RTEMS_SUCCESSFUL ) @{
|
|
||||||
bsp_fatal( SOME_FATAL_IRQ_INSTALL );
|
|
||||||
@}
|
|
||||||
@}
|
|
||||||
|
|
||||||
#define Clock_driver_support_install_isr( isr, old ) \
|
|
||||||
some_support_install_isr( isr )
|
|
||||||
|
|
||||||
#include "../../../shared/clockdrv_shell.h"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Support At Tick
|
|
||||||
|
|
||||||
The hardware specific support at tick is specified by
|
|
||||||
@code{Clock_driver_support_at_tick()}.
|
|
||||||
|
|
||||||
@example
|
|
||||||
static void some_support_at_tick( void )
|
|
||||||
@{
|
|
||||||
/* Clear interrupt */
|
|
||||||
@}
|
|
||||||
|
|
||||||
#define Clock_driver_support_at_tick() \
|
|
||||||
some_support_at_tick()
|
|
||||||
|
|
||||||
#include "../../../shared/clockdrv_shell.h"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection System Shutdown Support
|
|
||||||
|
|
||||||
The @dfn{Clock Driver Shell} provides the routine @code{Clock_exit()} that is
|
|
||||||
scheduled to be run during system shutdown via the @code{atexit()} routine.
|
|
||||||
The hardware specific shutdown support is specified by
|
|
||||||
@code{Clock_driver_support_shutdown_hardware()} which is used by
|
|
||||||
@code{Clock_exit()}. It should disable the clock tick source if it was
|
|
||||||
enabled. This can be used to prevent clock ticks after the system is shutdown.
|
|
||||||
|
|
||||||
@example
|
|
||||||
static void some_support_shutdown_hardware( void )
|
|
||||||
@{
|
|
||||||
/* Shutdown hardware */
|
|
||||||
@}
|
|
||||||
|
|
||||||
#define Clock_driver_support_shutdown_hardware() \
|
|
||||||
some_support_shutdown_hardware()
|
|
||||||
|
|
||||||
#include "../../../shared/clockdrv_shell.h"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Multiple Clock Driver Ticks Per Clock Tick
|
|
||||||
|
|
||||||
In case the hardware needs more than one clock driver tick per clock tick (e.g.
|
|
||||||
due to a limited range of the hardware timer), then this can be specified with
|
|
||||||
the optional @code{#define CLOCK_DRIVER_ISRS_PER_TICK} and @code{#define
|
|
||||||
CLOCK_DRIVER_ISRS_PER_TICK_VALUE} defines. This is currently used only for x86
|
|
||||||
and it hopefully remains that way.
|
|
||||||
|
|
||||||
@example
|
|
||||||
/* Enable multiple clock driver ticks per clock tick */
|
|
||||||
#define CLOCK_DRIVER_ISRS_PER_TICK 1
|
|
||||||
|
|
||||||
/* Specifiy the clock driver ticks per clock tick value */
|
|
||||||
#define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123
|
|
||||||
|
|
||||||
#include "../../../shared/clockdrv_shell.h"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Clock Driver Ticks Counter
|
|
||||||
|
|
||||||
The @dfn{Clock Driver Shell} provide a global variable that is simply a count
|
|
||||||
of the number of clock driver interrupt service routines that have occurred.
|
|
||||||
This information is valuable when debugging a system. This variable is
|
|
||||||
declared as follows:
|
|
||||||
|
|
||||||
@example
|
|
||||||
volatile uint32_t Clock_driver_ticks;
|
|
||||||
@end example
|
|
||||||
@@ -1,645 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2008.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Console Driver
|
|
||||||
|
|
||||||
@section Introduction
|
|
||||||
|
|
||||||
This chapter describes the operation of a console driver using
|
|
||||||
the RTEMS POSIX Termios support. Traditionally RTEMS has referred
|
|
||||||
to all serial device drivers as console device drivers. A
|
|
||||||
console driver can be used to do raw data processing in addition
|
|
||||||
to the "normal" standard input and output device functions required
|
|
||||||
of a console.
|
|
||||||
|
|
||||||
The serial driver may be called as the consequence of a C Library
|
|
||||||
call such as @code{printf} or @code{scanf} or directly via the
|
|
||||||
@code{read} or @code{write} system calls.
|
|
||||||
There are two main functioning modes:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item console: formatted input/output, with special characters (end of
|
|
||||||
line, tabulations, etc.) recognition and processing,
|
|
||||||
|
|
||||||
@item raw: permits raw data processing.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
One may think that two serial drivers are needed to handle these two types
|
|
||||||
of data, but Termios permits having only one driver.
|
|
||||||
|
|
||||||
@section Termios
|
|
||||||
|
|
||||||
Termios is a standard for terminal management, included in the POSIX
|
|
||||||
1003.1b standard. As part of the POSIX and Open Group Single UNIX
|
|
||||||
Specification, is commonly provided on UNIX implementations. The
|
|
||||||
Open Group has the termios portion of the POSIX standard online
|
|
||||||
at @uref{http://opengroup.org/onlinepubs/007908775/xbd/termios.html
|
|
||||||
,http://opengroup.org/onlinepubs/007908775/xbd/termios.html}.
|
|
||||||
The requirements for the @code{<termios.h>} file are also provided
|
|
||||||
and are at @uref{http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html,
|
|
||||||
http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html}.
|
|
||||||
|
|
||||||
Having RTEMS support for Termios is beneficial because:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item from the user's side because it provides standard primitive operations
|
|
||||||
to access the terminal and change configuration settings. These operations
|
|
||||||
are the same under UNIX and RTEMS.
|
|
||||||
|
|
||||||
@item from the BSP developer's side because it frees the
|
|
||||||
developer from dealing with buffer states and mutual exclusions on them.
|
|
||||||
Early RTEMS console device drivers also did their own special
|
|
||||||
character processing.
|
|
||||||
|
|
||||||
@item it is part of an internationally recognized standard.
|
|
||||||
|
|
||||||
@item it makes porting code from other environments easier.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
Termios support includes:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item raw and console handling,
|
|
||||||
|
|
||||||
@item blocking or non-blocking characters receive, with or without
|
|
||||||
Timeout.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
At this time, RTEMS documentation does not include a thorough discussion
|
|
||||||
of the Termios functionality. For more information on Termios,
|
|
||||||
type @code{man termios} on a Unix box or point a web browser
|
|
||||||
at
|
|
||||||
@uref{http://www.freebsd.org/cgi/man.cgi}.
|
|
||||||
|
|
||||||
@section Driver Functioning Modes
|
|
||||||
|
|
||||||
There are generally three main functioning modes for an UART (Universal
|
|
||||||
Asynchronous Receiver-Transmitter, i.e. the serial chip):
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item polled mode
|
|
||||||
@item interrupt driven mode
|
|
||||||
@item task driven mode
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
In polled mode, the processor blocks on sending/receiving characters.
|
|
||||||
This mode is not the most efficient way to utilize the UART. But
|
|
||||||
polled mode is usually necessary when one wants to print an
|
|
||||||
error message in the event of a fatal error such as a fatal error
|
|
||||||
in the BSP. This is also the simplest mode to
|
|
||||||
program. Polled mode is generally preferred if the serial port is
|
|
||||||
to be used primarily as a debug console. In a simple polled driver,
|
|
||||||
the software will continuously check the status of the UART when
|
|
||||||
it is reading or writing to the UART. Termios improves on this
|
|
||||||
by delaying the caller for 1 clock tick between successive checks
|
|
||||||
of the UART on a read operation.
|
|
||||||
|
|
||||||
In interrupt driven mode, the processor does not block on sending/receiving
|
|
||||||
characters. Data is buffered between the interrupt service routine
|
|
||||||
and application code. Two buffers are used to insulate the application
|
|
||||||
from the relative slowness of the serial device. One of the buffers is
|
|
||||||
used for incoming characters, while the other is used for outgoing characters.
|
|
||||||
|
|
||||||
An interrupt is raised when a character is received by the UART.
|
|
||||||
The interrupt subroutine places the incoming character at the end
|
|
||||||
of the input buffer. When an application asks for input,
|
|
||||||
the characters at the front of the buffer are returned.
|
|
||||||
|
|
||||||
When the application prints to the serial device, the outgoing characters
|
|
||||||
are placed at the end of the output buffer. The driver will place
|
|
||||||
one or more characters in the UART (the exact number depends on the UART)
|
|
||||||
An interrupt will be raised when all the characters have been transmitted.
|
|
||||||
The interrupt service routine has to send the characters
|
|
||||||
remaining in the output buffer the same way. When the transmitting side
|
|
||||||
of the UART is idle, it is typically necessary to prime the transmitter
|
|
||||||
before the first interrupt will occur.
|
|
||||||
|
|
||||||
The task driven mode is similar to interrupt driven mode, but the actual data
|
|
||||||
processing is done in dedicated tasks instead of interrupt routines.
|
|
||||||
|
|
||||||
@section Serial Driver Functioning Overview
|
|
||||||
|
|
||||||
The following Figure shows how a Termios driven serial driver works:
|
|
||||||
|
|
||||||
@ifset use-ascii
|
|
||||||
@center Figure not included in ASCII version
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
@ifset use-tex
|
|
||||||
@sp1
|
|
||||||
@center{@image{TERMIOSFlow,,6in}}
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
@ifset use-html
|
|
||||||
@html
|
|
||||||
<P ALIGN="center"><IMG SRC="TERMIOSFlow.png" ALT="Termios Flow"></P>
|
|
||||||
@end html
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
The following list describes the basic flow.
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item the application programmer uses standard C library call (printf,
|
|
||||||
scanf, read, write, etc.),
|
|
||||||
|
|
||||||
@item C library (ctx.g. RedHat (formerly Cygnus) Newlib) calls
|
|
||||||
the RTEMS system call interface. This code can be found in the
|
|
||||||
@file{cpukit/libcsupport/src} directory.
|
|
||||||
|
|
||||||
@item Glue code calls the serial driver entry routines.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@subsection Basics
|
|
||||||
|
|
||||||
The low-level driver API changed between RTEMS 4.10 and RTEMS 4.11. The legacy
|
|
||||||
callback API is still supported, but its use is discouraged. The following
|
|
||||||
functions are deprecated:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item @code{rtems_termios_open()} - use @code{rtems_termios_device_open()} in
|
|
||||||
combination with @code{rtems_termios_device_install()} instead.
|
|
||||||
|
|
||||||
@item @code{rtems_termios_close()} - use @code{rtems_termios_device_close()}
|
|
||||||
instead.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
This manual describes the new API. A new console driver should consist of
|
|
||||||
three parts.
|
|
||||||
|
|
||||||
@enumerate
|
|
||||||
|
|
||||||
@item The basic console driver functions using the Termios support. Add this
|
|
||||||
the BSPs Makefile.am:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
[...]
|
|
||||||
libbsp_a_SOURCES += ../../shared/console-termios.c
|
|
||||||
[...]
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@item A general serial module specific low-level driver providing the handler
|
|
||||||
table for the Termios @code{rtems_termios_device_install()} function. This
|
|
||||||
low-level driver could be used for more than one BSP.
|
|
||||||
|
|
||||||
@item A BSP specific initialization routine @code{console_initialize()}, that
|
|
||||||
calls @code{rtems_termios_device_install()} providing a low-level driver
|
|
||||||
context for each installed device.
|
|
||||||
|
|
||||||
@end enumerate
|
|
||||||
|
|
||||||
You need to provide a device handler structure for the Termios device
|
|
||||||
interface. The functions are described later in this chapter. The first open
|
|
||||||
and set attributes handler return a boolean status to indicate success (true)
|
|
||||||
or failure (false). The polled read function returns an unsigned character in
|
|
||||||
case one is available or minus one otherwise.
|
|
||||||
|
|
||||||
If you want to use polled IO it should look like the following. Termios must
|
|
||||||
be told the addresses of the handler that are to be used for simple character
|
|
||||||
IO, i.e. pointers to the @code{my_driver_poll_read()} and
|
|
||||||
@code{my_driver_poll_write()} functions described later in @ref{Console Driver
|
|
||||||
Termios and Polled IO}.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
const rtems_termios_handler my_driver_handler_polled = @{
|
|
||||||
.first_open = my_driver_first_open,
|
|
||||||
.last_close = my_driver_last_close,
|
|
||||||
.poll_read = my_driver_poll_read,
|
|
||||||
.write = my_driver_poll_write,
|
|
||||||
.set_attributes = my_driver_set_attributes,
|
|
||||||
.stop_remote_tx = NULL,
|
|
||||||
.start_remote_tx = NULL,
|
|
||||||
.mode = TERMIOS_POLLED
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
For an interrupt driven implementation you need the following. The driver
|
|
||||||
functioning is quite different in this mode. There is no device driver read
|
|
||||||
handler to be passed to Termios. Indeed a @code{console_read()} call returns the
|
|
||||||
contents of Termios input buffer. This buffer is filled in the driver
|
|
||||||
interrupt subroutine, see also @ref{Console Driver Termios and Interrupt Driven
|
|
||||||
IO}. The driver is responsible for providing a pointer to the
|
|
||||||
@code{my_driver_interrupt_write()} function.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
const rtems_termios_handler my_driver_handler_interrupt = @{
|
|
||||||
.first_open = my_driver_first_open,
|
|
||||||
.last_close = my_driver_last_close,
|
|
||||||
.poll_read = NULL,
|
|
||||||
.write = my_driver_interrupt_write,
|
|
||||||
.set_attributes = my_driver_set_attributes,
|
|
||||||
.stopRemoteTx = NULL,
|
|
||||||
.stop_remote_tx = NULL,
|
|
||||||
.start_remote_tx = NULL,
|
|
||||||
.mode = TERMIOS_IRQ_DRIVEN
|
|
||||||
@};
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
You can also provide hander for remote transmission control. This
|
|
||||||
is not covered in this manual, so they are set to @code{NULL} in the above
|
|
||||||
examples.
|
|
||||||
|
|
||||||
The low-level driver should provide a data structure for its device context.
|
|
||||||
The initialization routine must provide a context for each installed device via
|
|
||||||
@code{rtems_termios_device_install()}. For simplicity of the console
|
|
||||||
initialization example the device name is also present. Her is an example header file.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
#ifndef MY_DRIVER_H
|
|
||||||
#define MY_DRIVER_H
|
|
||||||
|
|
||||||
#include <rtems/termiostypes.h>
|
|
||||||
|
|
||||||
#include <some-chip-header.h>
|
|
||||||
|
|
||||||
/* Low-level driver specific data structure */
|
|
||||||
typedef struct @{
|
|
||||||
rtems_termios_device_context base;
|
|
||||||
const char *device_name;
|
|
||||||
volatile module_register_block *regs;
|
|
||||||
/* More stuff */
|
|
||||||
@} my_driver_context;
|
|
||||||
|
|
||||||
extern const rtems_termios_handler my_driver_handler_polled;
|
|
||||||
|
|
||||||
extern const rtems_termios_handler my_driver_handler_interrupt;
|
|
||||||
|
|
||||||
#endif /* MY_DRIVER_H */
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Termios and Polled IO
|
|
||||||
|
|
||||||
The following handler are provided by the low-level driver and invoked by
|
|
||||||
Termios for simple character IO.
|
|
||||||
|
|
||||||
The @code{my_driver_poll_write()} routine is responsible for writing @code{n}
|
|
||||||
characters from @code{buf} to the serial device specified by @code{tty}.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
static void my_driver_poll_write(
|
|
||||||
rtems_termios_device_context *base,
|
|
||||||
const char *buf,
|
|
||||||
size_t n
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
my_driver_context *ctx = (my_driver_context *) base;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* Write */
|
|
||||||
for (i = 0; i < n; ++i) @{
|
|
||||||
my_driver_write_char(ctx, buf[i]);
|
|
||||||
@}
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The @code{my_driver_poll_read} routine is responsible for reading a single
|
|
||||||
character from the serial device specified by @code{tty}. If no character is
|
|
||||||
available, then the routine should return minus one.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
static int my_driver_poll_read(rtems_termios_device_context *base)
|
|
||||||
@{
|
|
||||||
my_driver_context *ctx = (my_driver_context *) base;
|
|
||||||
|
|
||||||
/* Check if a character is available */
|
|
||||||
if (my_driver_can_read_char(ctx)) @{
|
|
||||||
/* Return the character */
|
|
||||||
return my_driver_read_char(ctx);
|
|
||||||
@} else @{
|
|
||||||
/* Return an error status */
|
|
||||||
return -1;
|
|
||||||
@}
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Termios and Interrupt Driven IO
|
|
||||||
|
|
||||||
The UART generally generates interrupts when it is ready to accept or to emit a
|
|
||||||
number of characters. In this mode, the interrupt subroutine is the core of
|
|
||||||
the driver.
|
|
||||||
|
|
||||||
The @code{my_driver_interrupt_handler()} is responsible for processing
|
|
||||||
asynchronous interrupts from the UART. There may be multiple interrupt
|
|
||||||
handlers for a single UART. Some UARTs can generate a unique interrupt vector
|
|
||||||
for each interrupt source such as a character has been received or the
|
|
||||||
transmitter is ready for another character.
|
|
||||||
|
|
||||||
In the simplest case, the @code{my_driver_interrupt_handler()} will have to check
|
|
||||||
the status of the UART and determine what caused the interrupt. The following
|
|
||||||
describes the operation of an @code{my_driver_interrupt_handler} which has to
|
|
||||||
do this:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
static void my_driver_interrupt_handler(
|
|
||||||
rtems_vector_number vector,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
rtems_termios_tty *tty = arg;
|
|
||||||
my_driver_context *ctx = rtems_termios_get_device_context(tty);
|
|
||||||
char buf[N];
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if we have received something. The function reads the
|
|
||||||
* received characters from the device and stores them in the
|
|
||||||
* buffer. It returns the number of read characters.
|
|
||||||
*/
|
|
||||||
n = my_driver_read_received_chars(ctx, buf, N);
|
|
||||||
if (n > 0) @{
|
|
||||||
/* Hand the data over to the Termios infrastructure */
|
|
||||||
rtems_termios_enqueue_raw_characters(tty, buf, n);
|
|
||||||
@}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if we have something transmitted. The functions returns
|
|
||||||
* the number of transmitted characters since the last write to the
|
|
||||||
* device.
|
|
||||||
*/
|
|
||||||
n = my_driver_transmitted_chars(ctx);
|
|
||||||
if (n > 0) @{
|
|
||||||
/*
|
|
||||||
* Notify Termios that we have transmitted some characters. It
|
|
||||||
* will call now the interrupt write function if more characters
|
|
||||||
* are ready for transmission.
|
|
||||||
*/
|
|
||||||
rtems_termios_dequeue_characters(tty, n);
|
|
||||||
@}
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The @code{my_driver_interrupt_write()} function is responsible for telling the
|
|
||||||
device that the @code{n} characters at @code{buf} are to be transmitted. It
|
|
||||||
the value @code{n} is zero to indicate that no more characters are to send.
|
|
||||||
The driver can disable the transmit interrupts now. This routine is invoked
|
|
||||||
either from task context with disabled interrupts to start a new transmission
|
|
||||||
process with exactly one character in case of an idle output state or from the
|
|
||||||
interrupt handler to refill the transmitter. If the routine is invoked to
|
|
||||||
start the transmit process the output state will become busy and Termios starts
|
|
||||||
to fill the output buffer. If the transmit interrupt arises before Termios was
|
|
||||||
able to fill the transmit buffer you will end up with one interrupt per
|
|
||||||
character.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
static void my_driver_interrupt_write(
|
|
||||||
rtems_termios_device_context *base,
|
|
||||||
const char *buf,
|
|
||||||
size_t n
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
my_driver_context *ctx = (my_driver_context *) base;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tell the device to transmit some characters from buf (less than
|
|
||||||
* or equal to n). When the device is finished it should raise an
|
|
||||||
* interrupt. The interrupt handler will notify Termios that these
|
|
||||||
* characters have been transmitted and this may trigger this write
|
|
||||||
* function again. You may have to store the number of outstanding
|
|
||||||
* characters in the device data structure.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Termios will set n to zero to indicate that the transmitter is
|
|
||||||
* now inactive. The output buffer is empty in this case. The
|
|
||||||
* driver may disable the transmit interrupts now.
|
|
||||||
*/
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Initialization
|
|
||||||
|
|
||||||
The BSP specific driver initialization is called once during the RTEMS
|
|
||||||
initialization process.
|
|
||||||
|
|
||||||
The @code{console_initialize()} function may look like this:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
#include <my-driver.h>
|
|
||||||
#include <rtems/console.h>
|
|
||||||
#include <bsp.h>
|
|
||||||
#include <bsp/fatal.h>
|
|
||||||
|
|
||||||
static my_driver_context driver_context_table[M] = @{ /* Some values */ @};
|
|
||||||
|
|
||||||
rtems_device_driver console_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
rtems_status_code sc;
|
|
||||||
#ifdef SOME_BSP_USE_INTERRUPTS
|
|
||||||
const rtems_termios_handler *handler = &my_driver_handler_interrupt;
|
|
||||||
#else
|
|
||||||
const rtems_termios_handler *handler = &my_driver_handler_polled;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize the Termios infrastructure. If Termios has already
|
|
||||||
* been initialized by another device driver, then this call will
|
|
||||||
* have no effect.
|
|
||||||
*/
|
|
||||||
rtems_termios_initialize();
|
|
||||||
|
|
||||||
/* Initialize each device */
|
|
||||||
for (
|
|
||||||
minor = 0;
|
|
||||||
minor < RTEMS_ARRAY_SIZE(driver_context_table);
|
|
||||||
++minor
|
|
||||||
) @{
|
|
||||||
my_driver_context *ctx = &driver_context_table[minor];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Install this device in the file system and Termios. In order
|
|
||||||
* to use the console (i.e. being able to do printf, scanf etc.
|
|
||||||
* on stdin, stdout and stderr), one device must be registered as
|
|
||||||
* "/dev/console" (CONSOLE_DEVICE_NAME).
|
|
||||||
*/
|
|
||||||
sc = rtems_termios_device_install(
|
|
||||||
ctx->device_name,
|
|
||||||
major,
|
|
||||||
minor,
|
|
||||||
handler,
|
|
||||||
NULL,
|
|
||||||
ctx
|
|
||||||
);
|
|
||||||
if (sc != RTEMS_SUCCESSFUL) @{
|
|
||||||
bsp_fatal(SOME_BSP_FATAL_CONSOLE_DEVICE_INSTALL);
|
|
||||||
@}
|
|
||||||
@}
|
|
||||||
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Opening a serial device
|
|
||||||
|
|
||||||
The @code{console_open()} function provided by @file{console-termios.c} is
|
|
||||||
called whenever a serial device is opened. The device registered as
|
|
||||||
@code{"/dev/console"} (@code{CONSOLE_DEVICE_NAME}) is opened automatically
|
|
||||||
during RTEMS initialization. For instance, if UART channel 2 is registered as
|
|
||||||
@code{"/dev/tty1"}, the @code{console_open()} entry point will be called as the
|
|
||||||
result of an @code{fopen("/dev/tty1", mode)} in the application.
|
|
||||||
|
|
||||||
During the first open of the device Termios will call the
|
|
||||||
@code{my_driver_first_open()} handler.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
static bool my_driver_first_open(
|
|
||||||
rtems_termios_tty *tty,
|
|
||||||
rtems_termios_device_context *base,
|
|
||||||
struct termios *term,
|
|
||||||
rtems_libio_open_close_args_t *args
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
my_driver_context *ctx = (my_driver_context *) base;
|
|
||||||
rtems_status_code sc;
|
|
||||||
bool ok;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* You may add some initialization code here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sets the initial baud rate. This should be set to the value of
|
|
||||||
* the boot loader. This function accepts only exact Termios baud
|
|
||||||
* values.
|
|
||||||
*/
|
|
||||||
sc = rtems_termios_set_initial_baud(tty, MY_DRIVER_BAUD_RATE);
|
|
||||||
if (sc != RTEMS_SUCCESSFUL) @{
|
|
||||||
/* Not a valid Termios baud */
|
|
||||||
@}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Alternatively you can set the best baud.
|
|
||||||
*/
|
|
||||||
rtems_termios_set_best_baud(term, MY_DRIVER_BAUD_RATE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To propagate the initial Termios attributes to the device use
|
|
||||||
* this.
|
|
||||||
*/
|
|
||||||
ok = my_driver_set_attributes(base, term);
|
|
||||||
if (!ok) @{
|
|
||||||
/* This is bad */
|
|
||||||
@}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return true to indicate a successful set attributes, and false
|
|
||||||
* otherwise.
|
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Closing a Serial Device
|
|
||||||
|
|
||||||
The @code{console_close()} provided by @file{console-termios.c} is invoked when
|
|
||||||
the serial device is to be closed. This entry point corresponds to the device
|
|
||||||
driver close entry point.
|
|
||||||
|
|
||||||
Termios will call the @code{my_driver_last_close()} handler if the last close
|
|
||||||
happens on the device.
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
static void my_driver_last_close(
|
|
||||||
rtems_termios_tty *tty,
|
|
||||||
rtems_termios_device_context *base,
|
|
||||||
rtems_libio_open_close_args_t *args
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
my_driver_context *ctx = (my_driver_context *) base;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The driver may do some cleanup here.
|
|
||||||
*/
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Reading Characters from a Serial Device
|
|
||||||
|
|
||||||
The @code{console_read()} provided by @file{console-termios.c} is invoked when
|
|
||||||
the serial device is to be read from. This entry point corresponds to the
|
|
||||||
device driver read entry point.
|
|
||||||
|
|
||||||
@subsection Writing Characters to a Serial Device
|
|
||||||
|
|
||||||
The @code{console_write()} provided by @file{console-termios.c} is invoked when
|
|
||||||
the serial device is to be written to. This entry point corresponds to the
|
|
||||||
device driver write entry point.
|
|
||||||
|
|
||||||
@subsection Changing Serial Line Parameters
|
|
||||||
|
|
||||||
The @code{console_control()} provided by @file{console-termios.c} is invoked
|
|
||||||
when the line parameters for a particular serial device are to be changed.
|
|
||||||
This entry point corresponds to the device driver IO control entry point.
|
|
||||||
|
|
||||||
The application writer is able to control the serial line configuration with
|
|
||||||
Termios calls (such as the @code{ioctl()} command, see the Termios
|
|
||||||
documentation for more details). If the driver is to support dynamic
|
|
||||||
configuration, then it must have the @code{console_control()} piece of code.
|
|
||||||
Basically @code{ioctl()} commands call @code{console_control()} with the serial
|
|
||||||
line configuration in a Termios defined data structure.
|
|
||||||
|
|
||||||
The driver is responsible for reinitializing the device with the correct
|
|
||||||
settings. For this purpose Termios calls the @code{my_driver_set_attributes()}
|
|
||||||
handler.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
static bool my_driver_set_attributes(
|
|
||||||
rtems_termios_device_context *base,
|
|
||||||
const struct termios *term
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
my_driver_context *ctx = (my_driver_context *) base;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inspect the termios data structure and configure the device
|
|
||||||
* appropriately. The driver should only be concerned with the
|
|
||||||
* parts of the structure that specify hardware setting for the
|
|
||||||
* communications channel such as baud, character size, etc.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return true to indicate a successful set attributes, and false
|
|
||||||
* otherwise.
|
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Discrete Driver
|
|
||||||
|
|
||||||
The Discrete driver is responsible for providing an
|
|
||||||
interface to Discrete Input/Outputs. The capabilities provided
|
|
||||||
by this class of device driver are:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item Initialize a Discrete I/O Board
|
|
||||||
@item Open a Particular Discrete Bitfield
|
|
||||||
@item Close a Particular Discrete Bitfield
|
|
||||||
@item Read from a Particular Discrete Bitfield
|
|
||||||
@item Write to a Particular Discrete Bitfield
|
|
||||||
@item Reset DACs
|
|
||||||
@item Reinitialize DACS
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
Most discrete I/O devices are found on I/O cards that support many
|
|
||||||
bits of discrete I/O on a single card. This driver model is centered
|
|
||||||
on the notion of reading bitfields from the card.
|
|
||||||
|
|
||||||
There are currently no discrete I/O device drivers included in the
|
|
||||||
RTEMS source tree. The information provided in this chapter
|
|
||||||
is based on drivers developed for applications using RTEMS.
|
|
||||||
It is hoped that this driver model information can form the
|
|
||||||
discrete I/O driver model that can be supported in future RTEMS
|
|
||||||
distribution.
|
|
||||||
|
|
||||||
@section Major and Minor Numbers
|
|
||||||
|
|
||||||
The @b{major} number of a device driver is its index in the
|
|
||||||
RTEMS Device Address Table.
|
|
||||||
|
|
||||||
A @b{minor} number is associated with each device instance
|
|
||||||
managed by a particular device driver. An RTEMS minor number
|
|
||||||
is an @code{unsigned32} entity. Convention calls for
|
|
||||||
dividing the bits in the minor number down into categories
|
|
||||||
that specify a particular bitfield. This results in categories
|
|
||||||
like the following:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item @b{board} - indicates the board a particular bitfield is located on
|
|
||||||
@item @b{word} - indicates the particular word of discrete bits the
|
|
||||||
bitfield is located within
|
|
||||||
@item @b{start} - indicates the starting bit of the bitfield
|
|
||||||
@item @b{width} - indicates the width of the bitfield
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
From the above, it should be clear that a single device driver
|
|
||||||
can support multiple copies of the same board in a single system.
|
|
||||||
The minor number is used to distinguish the devices.
|
|
||||||
|
|
||||||
By providing a way to easily access a particular bitfield from
|
|
||||||
the device driver, the application is insulated with knowing how
|
|
||||||
to mask fields in and out of a discrete I/O.
|
|
||||||
|
|
||||||
@section Discrete I/O Driver Configuration
|
|
||||||
|
|
||||||
There is not a standard discrete I/O driver configuration table but some
|
|
||||||
fields are common across different drivers. The discrete I/O driver
|
|
||||||
configuration table is typically an array of structures with each
|
|
||||||
structure containing the information for a particular board.
|
|
||||||
The following is a list of the type of information normally required
|
|
||||||
to configure an discrete I/O board:
|
|
||||||
|
|
||||||
@table @b
|
|
||||||
@item board_offset
|
|
||||||
is the base address of a board.
|
|
||||||
|
|
||||||
@item relay_initial_values
|
|
||||||
is an array of the values that should be written to each output
|
|
||||||
word on the board during initialization. This allows the driver
|
|
||||||
to start with the board's output in a known state.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@section Initialize a Discrete I/O Board
|
|
||||||
|
|
||||||
At system initialization, the discrete I/O driver's initialization entry point
|
|
||||||
will be invoked. As part of initialization, the driver will perform
|
|
||||||
whatever board initializatin is required and then set all
|
|
||||||
outputs to their configured initial state.
|
|
||||||
|
|
||||||
The discrete I/O driver may register a device name for bitfields of
|
|
||||||
particular interest to the system. Normally this will be restricted
|
|
||||||
to the names of each word and, if the driver supports it, an "all words".
|
|
||||||
|
|
||||||
@section Open a Particular Discrete Bitfield
|
|
||||||
|
|
||||||
This is the driver open call. Usually this call does nothing other than
|
|
||||||
validate the minor number.
|
|
||||||
|
|
||||||
With some drivers, it may be necessary to allocate memory when a particular
|
|
||||||
device is opened. If that is the case, then this is often the place
|
|
||||||
to do this operation.
|
|
||||||
|
|
||||||
@section Close a Particular Discrete Bitfield
|
|
||||||
|
|
||||||
This is the driver close call. Usually this call does nothing.
|
|
||||||
|
|
||||||
With some drivers, it may be necessary to allocate memory when a particular
|
|
||||||
device is opened. If that is the case, then this is the place
|
|
||||||
where that memory should be deallocated.
|
|
||||||
|
|
||||||
@section Read from a Particular Discrete Bitfield
|
|
||||||
|
|
||||||
This corresponds to the driver read call. After validating the minor
|
|
||||||
number and arguments, this call reads the indicated bitfield. A
|
|
||||||
discrete I/O devices may have to store the last value written to
|
|
||||||
a discrete output. If the bitfield is output only, saving the last
|
|
||||||
written value gives the appearance that it can be read from also.
|
|
||||||
If the bitfield is input, then it is sampled.
|
|
||||||
|
|
||||||
@b{NOTE:} Many discrete inputs have a tendency to bounce. The application
|
|
||||||
may have to take account for bounces.
|
|
||||||
|
|
||||||
The value returned is an @code{unsigned32} number
|
|
||||||
representing the bitfield read. This value is stored in the
|
|
||||||
@code{argument_block} passed in to the call.
|
|
||||||
|
|
||||||
@b{NOTE:} Some discrete I/O drivers have a special minor number
|
|
||||||
used to access all discrete I/O bits on the board. If this special
|
|
||||||
minor is used, then the area pointed to by @code{argument_block} must
|
|
||||||
be the correct size.
|
|
||||||
|
|
||||||
@section Write to a Particular Discrete Bitfield
|
|
||||||
|
|
||||||
This corresponds to the driver write call. After validating the minor
|
|
||||||
number and arguments, this call writes the indicated device. If the
|
|
||||||
specified device is an ADC, then an error is usually returned.
|
|
||||||
|
|
||||||
The value written is an @code{unsigned32} number
|
|
||||||
representing the value to be written to the specified
|
|
||||||
bitfield. This value is stored in the
|
|
||||||
@code{argument_block} passed in to the call.
|
|
||||||
|
|
||||||
@b{NOTE:} Some discrete I/O drivers have a special minor number
|
|
||||||
used to access all discrete I/O bits on the board. If this special
|
|
||||||
minor is used, then the area pointed to by @code{argument_block} must
|
|
||||||
be the correct size.
|
|
||||||
|
|
||||||
@section Disable Discrete Outputs
|
|
||||||
|
|
||||||
This is one of the IOCTL functions supported by the I/O control
|
|
||||||
device driver entry point. When this IOCTL function is invoked,
|
|
||||||
the discrete outputs are disabled.
|
|
||||||
|
|
||||||
@b{NOTE:} It may not be possible to disable/enable discrete output on all
|
|
||||||
discrete I/O boards.
|
|
||||||
|
|
||||||
@section Enable Discrete Outputs
|
|
||||||
|
|
||||||
This is one of the IOCTL functions supported by the I/O control
|
|
||||||
device driver entry point. When this IOCTL function is invoked,
|
|
||||||
the discrete outputs are enabled.
|
|
||||||
|
|
||||||
@b{NOTE:} It may not be possible to disable/enable discrete output on all
|
|
||||||
discrete I/O boards.
|
|
||||||
|
|
||||||
@section Reinitialize Outputs
|
|
||||||
|
|
||||||
This is one of the IOCTL functions supported by the I/O control
|
|
||||||
device driver entry point. When this IOCTL function is invoked,
|
|
||||||
the discrete outputs are rewritten with the configured initial
|
|
||||||
output values.
|
|
||||||
|
|
||||||
@section Get Last Written Values
|
|
||||||
|
|
||||||
This is one of the IOCTL functions supported by the I/O control
|
|
||||||
device driver entry point. When this IOCTL function is invoked,
|
|
||||||
the following information is returned to the caller:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item last value written to the specified output word
|
|
||||||
@item timestamp of when the last write was performed
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2009.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Frame Buffer Driver
|
|
||||||
|
|
||||||
In this chapter, we present the basic functionality implemented by a
|
|
||||||
frame buffer driver: @code{frame_buffer_initialize()}, @code{frame_buffer_open()},
|
|
||||||
@code{frame_buffer_close()}, @code{frame_buffer_read()}, @code{frame_buffer_write()}
|
|
||||||
and @code{frame_buffer_control()}.
|
|
||||||
|
|
||||||
@section Introduction
|
|
||||||
|
|
||||||
The purpose of the frame buffer driver is to provide an abstraction for
|
|
||||||
graphics hardware.
|
|
||||||
By using the frame buffer interface, an application can display graphics
|
|
||||||
without knowing anything about the low-level details of interfacing to a
|
|
||||||
particular graphics adapter. The parameters governing the mapping of
|
|
||||||
memory to displayed pixels (planar or linear, bit depth, etc) is still
|
|
||||||
implementation-specific, but device-independent methods are provided to
|
|
||||||
determine and potentially modify these parameters.
|
|
||||||
|
|
||||||
The frame buffer driver is commonly located in the @code{console}
|
|
||||||
directory of the BSP and registered by the name @b{/dev/fb0}.
|
|
||||||
Additional frame buffers (if available) are named @b{/dev/fb1},
|
|
||||||
@b{/dev/fb2}, etc.
|
|
||||||
|
|
||||||
To work with the frame buffer, the following operation sequence is used:
|
|
||||||
@code{open()}, @code{ioctls()} to get the frame buffer info, @code{read()} and/or
|
|
||||||
@code{write()}, and @code{close()}.
|
|
||||||
|
|
||||||
@section Driver Function Overview
|
|
||||||
|
|
||||||
@subsection Initialization
|
|
||||||
|
|
||||||
The driver initialization is called once during the RTEMS initialization
|
|
||||||
process and returns RTEMS_SUCCESSFUL when the device driver is successfully
|
|
||||||
initialized. During the initialization, a name is assigned to the frame
|
|
||||||
buffer device. If the graphics hardware supports console text output,
|
|
||||||
as is the case with the pc386 VGA hardware, initialization into graphics
|
|
||||||
mode may be deferred until the device is @code{open()}ed.
|
|
||||||
|
|
||||||
The @code{frame_buffer_initialize()} function may look like this:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver frame_buffer_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg)
|
|
||||||
@{
|
|
||||||
rtems_status_code status;
|
|
||||||
|
|
||||||
printk( "frame buffer driver initializing..\n" );
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Register the device
|
|
||||||
*/
|
|
||||||
status = rtems_io_register_name("/dev/fb0", major, 0);
|
|
||||||
if (status != RTEMS_SUCCESSFUL)
|
|
||||||
@{
|
|
||||||
printk("Error registering frame buffer device!\n");
|
|
||||||
rtems_fatal_error_occurred( status );
|
|
||||||
@}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* graphics hardware initialization goes here for non-console
|
|
||||||
* devices
|
|
||||||
*/
|
|
||||||
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Opening the Frame Buffer Device
|
|
||||||
|
|
||||||
The @code{frame_buffer_open()} function is called whenever a frame buffer device is opened.
|
|
||||||
If the frame buffer is registered as "/dev/fb0", the @code{frame_buffer_open} entry point
|
|
||||||
will be called as the result of an @code{open("/dev/fb0", mode)} in the application.
|
|
||||||
|
|
||||||
Thread safety of the frame buffer driver is implementation-dependent.
|
|
||||||
The VGA driver shown below uses a mutex to prevent multiple open()
|
|
||||||
operations of the frame buffer device.
|
|
||||||
|
|
||||||
The @code{frame_buffer_open()} function returns RTEMS_SUCCESSFUL when the device driver
|
|
||||||
is successfully opened, and RTEMS_UNSATISFIED if the device is already open:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver frame_buffer_close(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
if (pthread_mutex_unlock(&mutex) == 0)@{
|
|
||||||
/* restore previous state. for VGA this means return to text mode.
|
|
||||||
* leave out if graphics hardware has been initialized in
|
|
||||||
* frame_buffer_initialize() */
|
|
||||||
ega_hwterm();
|
|
||||||
printk( "FBVGA close called.\n" );
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
@}
|
|
||||||
|
|
||||||
return RTEMS_UNSATISFIED;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
In the previous example, the function @code{ega_hwinit()} takes care of
|
|
||||||
hardware-specific initialization.
|
|
||||||
|
|
||||||
@subsection Closing the Frame Buffer Device
|
|
||||||
|
|
||||||
The @code{frame_buffer_close()} is invoked when the frame buffer device
|
|
||||||
is closed. It frees up any resources allocated in
|
|
||||||
@code{frame_buffer_open()}, and should restore previous hardware state.
|
|
||||||
The entry point corresponds to the device driver close entry point.
|
|
||||||
|
|
||||||
Returns RTEMS_SUCCESSFUL when the device driver is successfully closed:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver frame_buffer_close(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg)
|
|
||||||
@{
|
|
||||||
pthread_mutex_unlock(&mutex);
|
|
||||||
/* TODO check mutex return value, RTEMS_UNSATISFIED if it failed. we
|
|
||||||
* don't want to unconditionally call ega_hwterm()... */
|
|
||||||
/* restore previous state. for VGA this means return to text mode.
|
|
||||||
* leave out if graphics hardware has been initialized in
|
|
||||||
* frame_buffer_initialize() */
|
|
||||||
ega_hwterm();
|
|
||||||
printk( "frame buffer close called.\n" );
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
@}
|
|
||||||
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
|
|
||||||
@subsection Reading from the Frame Buffer Device
|
|
||||||
|
|
||||||
The @code{frame_buffer_read()} is invoked from a @code{read()} operation
|
|
||||||
on the frame buffer device.
|
|
||||||
Read functions should allow normal and partial reading at the end of frame buffer memory.
|
|
||||||
This method returns RTEMS_SUCCESSFUL when the device is successfully read from:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver frame_buffer_read(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
|
|
||||||
rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count;
|
|
||||||
memcpy(rw_args->buffer, (const void *) (fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved);
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Writing to the Frame Buffer Device
|
|
||||||
|
|
||||||
The @code{frame_buffer_write()} is invoked from a @code{write()}
|
|
||||||
operation on the frame buffer device.
|
|
||||||
The frame buffer write function is similar to the read function, and
|
|
||||||
should handle similar cases involving partial writes.
|
|
||||||
|
|
||||||
This method returns RTEMS_SUCCESSFUL when the device is successfully
|
|
||||||
written to:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver frame_buffer_write(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
|
|
||||||
rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count;
|
|
||||||
memcpy( (void *) (fb_fix.smem_start + rw_args->offset), rw_args->buffer, rw_args->bytes_moved);
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
|
|
||||||
@subsection Frame Buffer IO Control
|
|
||||||
|
|
||||||
The frame buffer driver allows several ioctls, partially compatible with
|
|
||||||
the Linux kernel,
|
|
||||||
to obtain information about the hardware.
|
|
||||||
|
|
||||||
All @code{ioctl()} operations on the frame buffer device invoke
|
|
||||||
@code{frame_buffer_control()}.
|
|
||||||
|
|
||||||
Ioctls supported:
|
|
||||||
@itemize @bullet
|
|
||||||
@item ioctls to get the frame buffer screen info (fixed and variable).
|
|
||||||
@item ioctl to set and get palette.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver frame_buffer_control(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
rtems_libio_ioctl_args_t *args = arg;
|
|
||||||
|
|
||||||
printk( "FBVGA ioctl called, cmd=%x\n", args->command );
|
|
||||||
|
|
||||||
switch( args->command ) @{
|
|
||||||
case FBIOGET_FSCREENINFO:
|
|
||||||
args->ioctl_return = get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer );
|
|
||||||
break;
|
|
||||||
case FBIOGET_VSCREENINFO:
|
|
||||||
args->ioctl_return = get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer );
|
|
||||||
break;
|
|
||||||
case FBIOPUT_VSCREENINFO:
|
|
||||||
/* not implemented yet*/
|
|
||||||
args->ioctl_return = -1;
|
|
||||||
return RTEMS_UNSATISFIED;
|
|
||||||
case FBIOGETCMAP:
|
|
||||||
args->ioctl_return = get_palette( ( struct fb_cmap * ) args->buffer );
|
|
||||||
break;
|
|
||||||
case FBIOPUTCMAP:
|
|
||||||
args->ioctl_return = set_palette( ( struct fb_cmap * ) args->buffer );
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
args->ioctl_return = 0;
|
|
||||||
break;
|
|
||||||
@}
|
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
See @code{rtems/fb.h} for more information on the list of ioctls and
|
|
||||||
data structures they work with.
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter IDE Controller Driver
|
|
||||||
|
|
||||||
@section Introduction
|
|
||||||
|
|
||||||
The IDE Controller driver is responsible for providing an
|
|
||||||
interface to an IDE Controller. The capabilities provided by this
|
|
||||||
driver are:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item Read IDE Controller register
|
|
||||||
@item Write IDE Controller register
|
|
||||||
@item Read data block through IDE Controller Data Register
|
|
||||||
@item Write data block through IDE Controller Data Register
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
The reference implementation for an IDE Controller driver can
|
|
||||||
be found in @code{$RTEMS_SRC_ROOT/c/src/libchip/ide}. This driver
|
|
||||||
is based on the libchip concept and allows to work with any of the IDE
|
|
||||||
Controller chips simply by appropriate configuration of BSP. Drivers for a
|
|
||||||
particular IDE Controller chips locate in the following directories: drivers
|
|
||||||
for well-known IDE Controller chips locate into
|
|
||||||
@code{$RTEMS_SRC_ROOT/c/src/libchip/ide}, drivers for IDE Controller chips
|
|
||||||
integrated with CPU locate into
|
|
||||||
@code{$RTEMS_SRC_ROOT/c/src/lib/libcpu/myCPU} and
|
|
||||||
drivers for custom IDE Controller chips (for example, implemented on FPGA)
|
|
||||||
locate into @code{$RTEMS_SRC_ROOT/c/src/lib/libbsp/myBSP}.
|
|
||||||
There is a README file in these directories for each supported
|
|
||||||
IDE Controller chip. Each of these README explains how to configure a BSP
|
|
||||||
for that particular IDE Controller chip.
|
|
||||||
|
|
||||||
@section Initialization
|
|
||||||
|
|
||||||
IDE Controller chips used by a BSP are statically configured into
|
|
||||||
@code{IDE_Controller_Table}. The @code{ide_controller_initialize} routine is
|
|
||||||
responsible for initialization of all configured IDE controller chips.
|
|
||||||
Initialization order of the chips based on the order the chips are defined in
|
|
||||||
the @code{IDE_Controller_Table}.
|
|
||||||
|
|
||||||
The following actions are performed by the IDE Controller driver
|
|
||||||
initialization routine:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver ide_controller_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor_arg,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
for each IDE Controller chip configured in IDE_Controller_Table
|
|
||||||
if (BSP dependent probe(if exists) AND device probe for this IDE chip
|
|
||||||
indicates it is present)
|
|
||||||
perform initialization of the particular chip
|
|
||||||
register device with configured name for this chip
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section Read IDE Controller Register
|
|
||||||
|
|
||||||
The @code{ide_controller_read_register} routine reads the content of the IDE
|
|
||||||
Controller chip register. IDE Controller chip is selected via the minor
|
|
||||||
number. This routine is not allowed to be called from an application.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void ide_controller_read_register(rtems_device_minor_number minor,
|
|
||||||
unsigned32 reg, unsigned32 *value)
|
|
||||||
@{
|
|
||||||
get IDE Controller chip configuration information from
|
|
||||||
IDE_Controller_Table by minor number
|
|
||||||
|
|
||||||
invoke read register routine for the chip
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section Write IDE Controller Register
|
|
||||||
|
|
||||||
The @code{ide_controller_write_register} routine writes IDE Controller chip
|
|
||||||
register with specified value. IDE Controller chip is selected via the minor
|
|
||||||
number. This routine is not allowed to be called from an application.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void ide_controller_write_register(rtems_device_minor_number minor,
|
|
||||||
unsigned32 reg, unsigned32 value)
|
|
||||||
@{
|
|
||||||
get IDE Controller chip configuration information from
|
|
||||||
IDE_Controller_Table by minor number
|
|
||||||
|
|
||||||
invoke write register routine for the chip
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section Read Data Block Through IDE Controller Data Register
|
|
||||||
|
|
||||||
The @code{ide_controller_read_data_block} provides multiple consequent read
|
|
||||||
of the IDE Controller Data Register. IDE Controller chip is selected via the
|
|
||||||
minor number. The same functionality may be achieved via separate multiple
|
|
||||||
calls of @code{ide_controller_read_register} routine but
|
|
||||||
@code{ide_controller_read_data_block} allows to escape functions call
|
|
||||||
overhead. This routine is not allowed to be called from an application.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void ide_controller_read_data_block(
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
unsigned16 block_size,
|
|
||||||
blkdev_sg_buffer *bufs,
|
|
||||||
uint32_t *cbuf,
|
|
||||||
uint32_t *pos
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
get IDE Controller chip configuration information from
|
|
||||||
IDE_Controller_Table by minor number
|
|
||||||
|
|
||||||
invoke read data block routine for the chip
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section Write Data Block Through IDE Controller Data Register
|
|
||||||
|
|
||||||
The @code{ide_controller_write_data_block} provides multiple consequent write
|
|
||||||
into the IDE Controller Data Register. IDE Controller chip is selected via the
|
|
||||||
minor number. The same functionality may be achieved via separate multiple
|
|
||||||
calls of @code{ide_controller_write_register} routine but
|
|
||||||
@code{ide_controller_write_data_block} allows to escape functions call
|
|
||||||
overhead. This routine is not allowed to be called from an application.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void ide_controller_write_data_block(
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
unsigned16 block_size,
|
|
||||||
blkdev_sg_buffer *bufs,
|
|
||||||
uint32_t *cbuf,
|
|
||||||
uint32_t *pos
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
get IDE Controller chip configuration information from
|
|
||||||
IDE_Controller_Table by minor number
|
|
||||||
|
|
||||||
invoke write data block routine for the chip
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
@@ -1,425 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2008.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Initialization Code
|
|
||||||
|
|
||||||
@section Introduction
|
|
||||||
|
|
||||||
The initialization code is the first piece of code executed when there's a
|
|
||||||
reset/reboot. Its purpose is to initialize the board for the application.
|
|
||||||
This chapter contains a narrative description of the initialization
|
|
||||||
process followed by a description of each of the files and routines
|
|
||||||
commonly found in the BSP related to initialization. The remainder of
|
|
||||||
this chapter covers special issues which require attention such
|
|
||||||
as interrupt vector table and chip select initialization.
|
|
||||||
|
|
||||||
Most of the examples in this chapter will be based on the SPARC/ERC32 and
|
|
||||||
m68k/gen68340 BSP initialization code. Like most BSPs, the initialization
|
|
||||||
for these BSP is divided into two subdirectories under the BSP source
|
|
||||||
directory. The BSP source code for these BSPs is in the following
|
|
||||||
directories:
|
|
||||||
|
|
||||||
@example
|
|
||||||
c/src/lib/libbsp/m68k/gen68340
|
|
||||||
c/src/lib/libbsp/sparc/erc32
|
|
||||||
@end example
|
|
||||||
|
|
||||||
Both BSPs contain startup code written in assembly language and C.
|
|
||||||
The gen68340 BSP has its early initialization start code in the
|
|
||||||
@code{start340} subdirectory and its C startup code in the @code{startup}
|
|
||||||
directory. In the @code{start340} directory are two source files.
|
|
||||||
The file @code{startfor340only.s} is the simpler of these files as it only
|
|
||||||
has initialization code for a MC68340 board. The file @code{start340.s}
|
|
||||||
contains initialization for a 68349 based board as well.
|
|
||||||
|
|
||||||
Similarly, the ERC32 BSP has startup code written in assembly language
|
|
||||||
and C. However, this BSP shares this code with other SPARC BSPs.
|
|
||||||
Thus the @code{Makefile.am} explicitly references the following files
|
|
||||||
for this functionality.
|
|
||||||
|
|
||||||
@example
|
|
||||||
../../sparc/shared/start.S
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@b{NOTE:} In most BSPs, the directory named @code{start340} in the
|
|
||||||
gen68340 BSP would be simply named @code{start} or start followed by a
|
|
||||||
BSP designation.
|
|
||||||
|
|
||||||
@section Required Global Variables
|
|
||||||
|
|
||||||
Although not strictly part of initialization, there are a few global
|
|
||||||
variables assumed to exist by reusable device drivers. These global
|
|
||||||
variables should only defined by the BSP when using one of these device
|
|
||||||
drivers.
|
|
||||||
|
|
||||||
The BSP author probably should be aware of the @code{Configuration}
|
|
||||||
Table structure generated by @code{<rtems/confdefs.h>} during debug but
|
|
||||||
should not explicitly reference it in the source code. There are helper
|
|
||||||
routines provided by RTEMS to access individual fields.
|
|
||||||
|
|
||||||
In older RTEMS versions, the BSP included a number of required global
|
|
||||||
variables. We have made every attempt to eliminate these in the interest
|
|
||||||
of simplicity.
|
|
||||||
|
|
||||||
@section Board Initialization
|
|
||||||
|
|
||||||
This section describes the steps an application goes through from the
|
|
||||||
time the first BSP code is executed until the first application task
|
|
||||||
executes. The following figure illustrates the program flow during
|
|
||||||
this sequence:
|
|
||||||
|
|
||||||
@ifset use-ascii
|
|
||||||
IMAGE NOT AVAILABLE IN ASCII VERSION
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
@ifset use-tex
|
|
||||||
@image{BSPInitFlowchart-49,6in,,Initialization Sequence,.png}
|
|
||||||
@c @image{FILENAME[, WIDTH[, HEIGHT[, ALTTEXT[, EXTENSION]]]]}
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
@ifset use-html
|
|
||||||
@html
|
|
||||||
<center>
|
|
||||||
<IMG SRC="BSPInitFlowchart-49.png" WIDTH=800 ALT="Initialization Sequence">
|
|
||||||
</center>
|
|
||||||
@end html
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
The above figure illustrates the flow from assembly language start code
|
|
||||||
to the shared @code{bootcard.c} framework then through the C Library,
|
|
||||||
RTEMS, device driver initialization phases, and the context switch
|
|
||||||
to the first application task. After this, the application executes
|
|
||||||
until it calls @code{exit}, @code{rtems_shutdown_executive}, or some
|
|
||||||
other normal termination initiating routine and a fatal system state is
|
|
||||||
reached. The optional @code{bsp_fatal_extension} initial extension can perform
|
|
||||||
BSP specific system termination.
|
|
||||||
|
|
||||||
The routines invoked during this will be discussed and their location
|
|
||||||
in the RTEMS source tree pointed out as we discuss each.
|
|
||||||
|
|
||||||
@subsection Start Code - Assembly Language Initialization
|
|
||||||
|
|
||||||
The assembly language code in the directory @code{start} is the first part
|
|
||||||
of the application to execute. It is responsible for initializing the
|
|
||||||
processor and board enough to execute the rest of the BSP. This includes:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item initializing the stack
|
|
||||||
@item zeroing out the uninitialized data section @code{.bss}
|
|
||||||
@item disabling external interrupts
|
|
||||||
@item copy the initialized data from ROM to RAM
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
The general rule of thumb is that the start code in assembly should
|
|
||||||
do the minimum necessary to allow C code to execute to complete the
|
|
||||||
initialization sequence.
|
|
||||||
|
|
||||||
The initial assembly language start code completes its execution by
|
|
||||||
invoking the shared routine @code{boot_card()}.
|
|
||||||
|
|
||||||
The label (symbolic name) associated with the starting address of the
|
|
||||||
program is typically called @code{start}. The start object file is the
|
|
||||||
first object file linked into the program image so it is ensured that
|
|
||||||
the start code is at offset 0 in the @code{.text} section. It is the
|
|
||||||
responsibility of the linker script in conjunction with the compiler
|
|
||||||
specifications file to put the start code in the correct location in
|
|
||||||
the application image.
|
|
||||||
|
|
||||||
@subsection boot_card() - Boot the Card
|
|
||||||
|
|
||||||
The @code{boot_card()} is the first C code invoked. This file is the
|
|
||||||
core component in the RTEMS BSP Initialization Framework and provides
|
|
||||||
the proper sequencing of initialization steps for the BSP, RTEMS and
|
|
||||||
device drivers. All BSPs use the same shared version of @code{boot_card()}
|
|
||||||
which is located in the following file:
|
|
||||||
|
|
||||||
@example
|
|
||||||
c/src/lib/libbsp/shared/bootcard.c
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The @code{boot_card()} routine performs the following functions:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item It disables processor interrupts.
|
|
||||||
|
|
||||||
@item It sets the command line argument variables
|
|
||||||
for later use by the application.
|
|
||||||
|
|
||||||
@item It invokes the BSP specific routine @code{bsp_start()} which is
|
|
||||||
written in C and thus able to perform more advanced initialization.
|
|
||||||
Often MMU and bus initialization occurs here.
|
|
||||||
|
|
||||||
@item It invokes the BSP specific routine @code{bsp_work_area_initialize()}
|
|
||||||
which is supposed to initialize the RTEMS Workspace and the C Program Heap.
|
|
||||||
Usually the default implementation in
|
|
||||||
@code{c/src/lib/libbsp/shared/bspgetworkarea.c} should be sufficient. Custom
|
|
||||||
implementations can use @code{bsp_work_area_initialize_default()} or
|
|
||||||
@code{bsp_work_area_initialize_with_table()} available as inline functions from
|
|
||||||
@code{#include <bsp/bootcard.h>}.
|
|
||||||
|
|
||||||
@item It invokes the RTEMS directive
|
|
||||||
@code{rtems_initialize_data_structures()} to initialize the RTEMS
|
|
||||||
executive to a state where objects can be created but tasking is not
|
|
||||||
enabled.
|
|
||||||
|
|
||||||
@item It invokes the BSP specific routine @code{bsp_libc_init()} to initialize
|
|
||||||
the C Library. Usually the default implementation in
|
|
||||||
@code{c/src/lib/libbsp/shared/bsplibc.c} should be sufficient.
|
|
||||||
|
|
||||||
@item It invokes the BSP specific routine @code{bsp_pretasking_hook}. On
|
|
||||||
most BSPs which utilize the framework, this routine does nothing.
|
|
||||||
|
|
||||||
@item If @code{RTEMS_DEBUG} is enabled, then the RTEMS debug mask level
|
|
||||||
is inialized appropriately.
|
|
||||||
|
|
||||||
@item It invokes the RTEMS directive
|
|
||||||
@code{rtems_initialize_before_drivers()} to initialize the MPCI Server
|
|
||||||
thread in a multiprocessor configuration and execute API specific
|
|
||||||
extensions.
|
|
||||||
|
|
||||||
@item It invokes the BSP specific routine @code{bsp_predriver_hook}. For
|
|
||||||
most BSPs, the implementation of this routine does nothing.
|
|
||||||
|
|
||||||
@item It invokes the RTEMS directive
|
|
||||||
@code{rtems_initialize_device_drivers()} to initialize the statically
|
|
||||||
configured set of device drivers in the order they were specified in
|
|
||||||
the Configuration Table.
|
|
||||||
|
|
||||||
@item It invokes the BSP specific routine @code{bsp_postdriver_hook}. For
|
|
||||||
most BSPs, the implementation of this routine does nothing. However, some
|
|
||||||
BSPs use this hook and perform some initialization which must be done at
|
|
||||||
this point in the initialization sequence. This is the last opportunity
|
|
||||||
for the BSP to insert BSP specific code into the initialization sequence.
|
|
||||||
|
|
||||||
@item It invokes the RTEMS directive
|
|
||||||
@code{rtems_initialize_start_multitasking()}
|
|
||||||
which initiates multitasking and performs a context switch to the
|
|
||||||
first user application task and may enable interrupts as a side-effect of
|
|
||||||
that context switch. The context switch saves the executing context. The
|
|
||||||
application runs now. The directive rtems_shutdown_executive() will return
|
|
||||||
to the saved context. The exit() function will use this directive.
|
|
||||||
|
|
||||||
After a return to the saved context a fatal system state is reached. The
|
|
||||||
fatal source is RTEMS_FATAL_SOURCE_EXIT with a fatal code set to the value
|
|
||||||
passed to rtems_shutdown_executive().
|
|
||||||
|
|
||||||
The enabling of interrupts during the first context switch is often the source
|
|
||||||
for fatal errors during BSP development because the BSP did not clear and/or
|
|
||||||
disable all interrupt sources and a spurious interrupt will occur.
|
|
||||||
|
|
||||||
When in the context of the first task but before its body has been
|
|
||||||
entered, any C++ Global Constructors will be invoked.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
That's it. We just went through the entire sequence.
|
|
||||||
|
|
||||||
@subsection bsp_start() - BSP Specific Initialization
|
|
||||||
|
|
||||||
This is the first BSP specific C routine to execute during system
|
|
||||||
initialization. This routine often performs required fundamental
|
|
||||||
hardware initialization such as setting bus controller registers
|
|
||||||
that do not have a direct impact on whether or not C code can execute.
|
|
||||||
The source code for this routine is usually found in the following
|
|
||||||
file:
|
|
||||||
|
|
||||||
@example
|
|
||||||
c/src/lib/libbsp/CPU/BSP/startup/bspstart.c
|
|
||||||
@end example
|
|
||||||
|
|
||||||
On older BSPs not using @code{boot_card()}'s support for allocating memory
|
|
||||||
to the C Program Heap and RTEMS Workspace, one of the most important
|
|
||||||
functions performed by this routine is determining where the RTEMS
|
|
||||||
Workspace is to be located in memory. All RTEMS objects and task stacks
|
|
||||||
will be allocated from this Workspace. The RTEMS Workspace is distinct
|
|
||||||
from the application heap used for @code{malloc()}. Many BSPs place
|
|
||||||
the RTEMS Workspace area at the end of RAM although this is certainly
|
|
||||||
not a requirement.
|
|
||||||
|
|
||||||
After completing execution, this routine returns to the @code{boot_card()}
|
|
||||||
routine.
|
|
||||||
|
|
||||||
@subsection RTEMS Pretasking Callback
|
|
||||||
|
|
||||||
The method @code{bsp_pretasking_hook()} is the BSP specific routine invoked
|
|
||||||
once RTEMS API initialization is complete but before interrupts and tasking are
|
|
||||||
enabled. The idle thread exists at this time. The pretasking hook is optional
|
|
||||||
and the user may use the shared version.
|
|
||||||
|
|
||||||
The @code{bsp_pretasking_hook()} routine is the appropriate place to initialize
|
|
||||||
any BSP specific support components which depend on the RTEMS APIs.
|
|
||||||
|
|
||||||
@subsection RTEMS Predriver Callback
|
|
||||||
|
|
||||||
The @code{bsp_predriver_hook()} method is the BSP specific routine that
|
|
||||||
is is invoked immediately before the the device drivers and MPCI are
|
|
||||||
initialized. RTEMS initialization is complete but interrupts and tasking
|
|
||||||
are disabled.
|
|
||||||
|
|
||||||
The BSP may use the shared version of this routine which is empty.
|
|
||||||
Most BSPs do not provide a specific implementation of this callback.
|
|
||||||
|
|
||||||
@subsection Device Driver Initialization
|
|
||||||
|
|
||||||
At this point in the initialization sequence, the initialization
|
|
||||||
routines for all of the device drivers specified in the Device
|
|
||||||
Driver Table are invoked. The initialization routines are invoked
|
|
||||||
in the order they appear in the Device Driver Table.
|
|
||||||
|
|
||||||
The Driver Address Table is part of the RTEMS Configuration Table. It
|
|
||||||
defines device drivers entry points (initialization, open, close, read,
|
|
||||||
write, and control). For more information about this table, please
|
|
||||||
refer to the @b{Configuring a System} chapter in the
|
|
||||||
@b{RTEMS Application C User's Guide}.
|
|
||||||
|
|
||||||
The RTEMS initialization procedure calls the initialization function for
|
|
||||||
every driver defined in the RTEMS Configuration Table (this allows
|
|
||||||
one to include only the drivers needed by the application).
|
|
||||||
|
|
||||||
All these primitives have a major and a minor number as arguments:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item the major number refers to the driver type,
|
|
||||||
|
|
||||||
@item the minor number is used to control two peripherals with the same
|
|
||||||
driver (for instance, we define only one major number for the serial
|
|
||||||
driver, but two minor numbers for channel A and B if there are two
|
|
||||||
channels in the UART).
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@subsection RTEMS Postdriver Callback
|
|
||||||
|
|
||||||
The @code{bsp_postdriver_hook()} BSP specific routine is invoked
|
|
||||||
immediately after the the device drivers and MPCI are initialized.
|
|
||||||
Interrupts and tasking are disabled.
|
|
||||||
|
|
||||||
Most BSPs use the shared implementation of this routine which is responsible for opening the device @code{/dev/console} for standard input, output and error if the application has configured the Console Device Driver. This file is located at:
|
|
||||||
|
|
||||||
@example
|
|
||||||
c/src/lib/libbsp/shared/bsppost.c
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section The Interrupt Vector Table
|
|
||||||
|
|
||||||
The Interrupt Vector Table is called different things on different
|
|
||||||
processor families but the basic functionality is the same. Each
|
|
||||||
entry in the Table corresponds to the handler routine for a particular
|
|
||||||
interrupt source. When an interrupt from that source occurs, the
|
|
||||||
specified handler routine is invoked. Some context information is
|
|
||||||
saved by the processor automatically when this happens. RTEMS saves
|
|
||||||
enough context information so that an interrupt service routine
|
|
||||||
can be implemented in a high level language.
|
|
||||||
|
|
||||||
On some processors, the Interrupt Vector Table is at a fixed address. If
|
|
||||||
this address is in RAM, then usually the BSP only has to initialize
|
|
||||||
it to contain pointers to default handlers. If the table is in ROM,
|
|
||||||
then the application developer will have to take special steps to
|
|
||||||
fill in the table.
|
|
||||||
|
|
||||||
If the base address of the Interrupt Vector Table can be dynamically
|
|
||||||
changed to an arbitrary address, then the RTEMS port to that processor
|
|
||||||
family will usually allocate its own table and install it. For example,
|
|
||||||
on some members of the Motorola MC68xxx family, the Vector Base Register
|
|
||||||
(@code{vbr}) contains this base address.
|
|
||||||
|
|
||||||
@subsection Interrupt Vector Table on the gen68340 BSP
|
|
||||||
|
|
||||||
The gen68340 BSP provides a default Interrupt Vector Table in the
|
|
||||||
file @code{$BSP_ROOT/start340/start340.s}. After the @code{entry}
|
|
||||||
label is the definition of space reserved for the table of
|
|
||||||
interrupts vectors. This space is assigned the symbolic name
|
|
||||||
of @code{__uhoh} in the @code{gen68340} BSP.
|
|
||||||
|
|
||||||
At @code{__uhoh} label is the default interrupt handler routine. This
|
|
||||||
routine is only called when an unexpected interrupts is raised. One can
|
|
||||||
add their own routine there (in that case there's a call to a routine -
|
|
||||||
$BSP_ROOT/startup/dumpanic.c - that prints which address caused the
|
|
||||||
interrupt and the contents of the registers, stack, etc.), but this should
|
|
||||||
not return.
|
|
||||||
|
|
||||||
@section Chip Select Initialization
|
|
||||||
|
|
||||||
When the microprocessor accesses a memory area, address decoding is
|
|
||||||
handled by an address decoder, so that the microprocessor knows which
|
|
||||||
memory chip(s) to access. The following figure illustrates this:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
+-------------------+
|
|
||||||
------------| |
|
|
||||||
------------| |------------
|
|
||||||
------------| Address |------------
|
|
||||||
------------| Decoder |------------
|
|
||||||
------------| |------------
|
|
||||||
------------| |
|
|
||||||
+-------------------+
|
|
||||||
CPU Bus Chip Select
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
|
|
||||||
The Chip Select registers must be programmed such that they match
|
|
||||||
the @code{linkcmds} settings. In the gen68340 BSP, ROM and RAM
|
|
||||||
addresses can be found in both the @code{linkcmds} and initialization
|
|
||||||
code, but this is not a great way to do this. It is better to
|
|
||||||
define addresses in the linker script.
|
|
||||||
|
|
||||||
@section Integrated Processor Registers Initialization
|
|
||||||
|
|
||||||
The CPUs used in many embedded systems are highly complex devices
|
|
||||||
with multiple peripherals on the CPU itself. For these devices,
|
|
||||||
there are always some specific integrated processor registers
|
|
||||||
that must be initialized. Refer to the processors' manuals for
|
|
||||||
details on these registers and be VERY careful programming them.
|
|
||||||
|
|
||||||
@section Data Section Recopy
|
|
||||||
|
|
||||||
The next initialization part can be found in
|
|
||||||
@code{$BSP340_ROOT/start340/init68340.c}. First the Interrupt
|
|
||||||
Vector Table is copied into RAM, then the data section recopy is initiated
|
|
||||||
(_CopyDataClearBSSAndStart in @code{$BSP340_ROOT/start340/startfor340only.s}).
|
|
||||||
|
|
||||||
This code performs the following actions:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item copies the .data section from ROM to its location reserved in RAM
|
|
||||||
(see @ref{Linker Script Initialized Data} for more details about this copy),
|
|
||||||
|
|
||||||
@item clear @code{.bss} section (all the non-initialized
|
|
||||||
data will take value 0).
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@section The RTEMS Configuration Table
|
|
||||||
|
|
||||||
The RTEMS configuration table contains the maximum number of objects RTEMS
|
|
||||||
can handle during the application (e.g. maximum number of tasks,
|
|
||||||
semaphores, etc.). It's used to allocate the size for the RTEMS inner data
|
|
||||||
structures.
|
|
||||||
|
|
||||||
The RTEMS configuration table is application dependent, which means that
|
|
||||||
one has to provide one per application. It is usually defined by defining
|
|
||||||
macros and including the header file @code{<rtems/confdefs.h>}. In simple
|
|
||||||
applications such as the tests provided with RTEMS, it is commonly found
|
|
||||||
in the main module of the application. For more complex applications,
|
|
||||||
it may be in a file by itself.
|
|
||||||
|
|
||||||
The header file @code{<rtems/confdefs.h>} defines a constant table
|
|
||||||
named @code{Configuration}. With RTEMS 4.8 and older, it was accepted
|
|
||||||
practice for the BSP to copy this table into a modifiable copy named
|
|
||||||
@code{BSP_Configuration}. This copy of the table was modified to define
|
|
||||||
the base address of the RTEMS Executive Workspace as well as to reflect
|
|
||||||
any BSP and device driver requirements not automatically handled by the
|
|
||||||
application. In 4.9 and newer, we have eliminated the BSP copies of the
|
|
||||||
configuration tables and are making efforts to make the configuration
|
|
||||||
information generated by @code{<rtems/confdefs.h>} constant and read only.
|
|
||||||
|
|
||||||
For more information on the RTEMS Configuration Table, refer to the
|
|
||||||
@b{RTEMS Application C User's Guide}.
|
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Introduction
|
|
||||||
|
|
||||||
Before reading this documentation, it is strongly advised to read the
|
|
||||||
RTEMS Development Environment Guide to get acquainted with the RTEMS
|
|
||||||
directory structure. This document describes how to do a RTEMS Board
|
|
||||||
Support Package, i.e. how to port RTEMS on a new target board. Discussions
|
|
||||||
are provided for the following topics:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item RTEMS Board Support Package Organization
|
|
||||||
|
|
||||||
@item Makefiles and the Linker Command Script
|
|
||||||
|
|
||||||
@item Board Initialization Sequence
|
|
||||||
|
|
||||||
@item Device Drivers Including:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item Console Driver
|
|
||||||
|
|
||||||
@item Clock Driver
|
|
||||||
|
|
||||||
@item Timer Driver
|
|
||||||
|
|
||||||
@item Real-Time Clock Driver
|
|
||||||
|
|
||||||
@item Non-Volatile Memory Driver
|
|
||||||
|
|
||||||
@item Networking Driver
|
|
||||||
|
|
||||||
@item Shared Memory Support Driver
|
|
||||||
|
|
||||||
@item Analog Driver
|
|
||||||
|
|
||||||
@item Discrete Driver
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
The original version of this manual was written by Geoffroy Montel
|
|
||||||
<g_montel@@yahoo.com>. When he started development of the gen68340
|
|
||||||
BSP, this manual did not exist. He wrote the initial version of
|
|
||||||
this manual as the result of his experiences. At that time, this
|
|
||||||
document was viewed internally as the most important "missing manual"
|
|
||||||
in the RTEMS documentation set.
|
|
||||||
|
|
||||||
The gen68340 BSP is a good example of the life of an RTEMS BSP. It is
|
|
||||||
based upon a part not recommended for new designs and none of the core RTEMS
|
|
||||||
Project team members have one of these boards. Thus we are unlikely to
|
|
||||||
perform major updates on this BSP. So as long as it compiles and links all
|
|
||||||
tests, it will be available.
|
|
||||||
|
|
||||||
The RTEMS Project team members are always trying to identify common
|
|
||||||
code across BSPs and refactoring the code into shared routines.
|
|
||||||
As part of this effort, the we will enhance the common BSP Framework.
|
|
||||||
Not surprisingly, not every BSP takes advantage of every feature in
|
|
||||||
the framework. The gen68340 does not take advantage of as many features
|
|
||||||
as the ERC32 BSP does. So in many ways, the ERC32 is a better example
|
|
||||||
BSP at this point. But even the ERC32 BSP does not include examples
|
|
||||||
of every driver template and framework available to the BSP author.
|
|
||||||
So in this guide we will try to point out good examples from other BSPs.
|
|
||||||
|
|
||||||
Our goal is for you to be able to reuse as much code as possible and
|
|
||||||
write as little board specific code as possible.
|
|
||||||
|
|
||||||
@@ -1,429 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Linker Script
|
|
||||||
|
|
||||||
@section What is a "linkcmds" file?
|
|
||||||
|
|
||||||
The @code{linkcmds} file is a script which is passed to the linker at linking
|
|
||||||
time. This file describes the memory configuration of the board as needed
|
|
||||||
to link the program. Specifically it specifies where the code and data
|
|
||||||
for the application will reside in memory.
|
|
||||||
|
|
||||||
The format of the linker script is defined by the GNU Loader @code{ld}
|
|
||||||
which is included as a component of the GNU Binary Utilities. If you
|
|
||||||
are using GNU/Linux, then you probably have the documentation installed
|
|
||||||
already and are using these same tools configured for @b{native} use.
|
|
||||||
Please visit the Binutils project @uref{http://sourceware.org/binutils/}
|
|
||||||
if you need more information.
|
|
||||||
|
|
||||||
@section Program Sections
|
|
||||||
|
|
||||||
An embedded systems programmer must be much more aware of the
|
|
||||||
placement of their executable image in memory than the average
|
|
||||||
applications programmer. A program destined to be embedded as well
|
|
||||||
as the target system have some specific properties that must be
|
|
||||||
taken into account. Embedded machines often mean average performances
|
|
||||||
and small memory usage. It is the memory usage that concerns us
|
|
||||||
when examining the linker command file.
|
|
||||||
|
|
||||||
Two types of memories have to be distinguished:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item RAM - volatile offering read and write access
|
|
||||||
@item ROM - non-volatile but read only
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
Even though RAM and ROM can be found in every personal computer,
|
|
||||||
one generally doesn't care about them. In a personal computer,
|
|
||||||
a program is nearly always stored on disk and executed in RAM. Things
|
|
||||||
are a bit different for embedded targets: the target will execute the
|
|
||||||
program each time it is rebooted or switched on. The application
|
|
||||||
program is stored in non-volatile memory such as ROM, PROM, EEPROM,
|
|
||||||
or Flash. On the other hand, data processing occurs in RAM.
|
|
||||||
|
|
||||||
This leads us to the structure of an embedded program. In rough terms,
|
|
||||||
an embedded program is made of sections. It is the responsibility of
|
|
||||||
the application programmer to place these sections in the appropriate
|
|
||||||
place in target memory. To make this clearer, if using the COFF
|
|
||||||
object file format on the Motorola m68k family of microprocessors,
|
|
||||||
the following sections will be present:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item @b{code (@code{.text}) section}:
|
|
||||||
is the program's code and it should not be modified.
|
|
||||||
This section may be placed in ROM.
|
|
||||||
|
|
||||||
@item @b{non-initialized data (@code{.bss}) section}:
|
|
||||||
holds uninitialized variables of the program. It can stay in RAM.
|
|
||||||
|
|
||||||
@item @b{initialized data (@code{.data}) section}:
|
|
||||||
holds the initialized program data which may be modified during the
|
|
||||||
program's life. This means they have to be in RAM.
|
|
||||||
On the other hand, these variables must be set to predefined values, and
|
|
||||||
those predefined values have to be stored in ROM.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@b{NOTE:} Many programs and support libraries unknowingly assume that the
|
|
||||||
@code{.bss} section and, possibly, the application heap are initialized
|
|
||||||
to zero at program start. This is not required by the ISO/ANSI C Standard
|
|
||||||
but is such a common requirement that most BSPs do this.
|
|
||||||
|
|
||||||
That brings us up to the notion of the image of an executable: it consists
|
|
||||||
of the set of the sections that together constitute the application.
|
|
||||||
|
|
||||||
@section Image of an Executable
|
|
||||||
|
|
||||||
As a program executable has many sections (note that the user can define
|
|
||||||
their own, and that compilers define theirs without any notice), one has to
|
|
||||||
specify the placement of each section as well as the type of memory
|
|
||||||
(RAM or ROM) the sections will be placed into.
|
|
||||||
For instance, a program compiled for a Personal Computer will see all the
|
|
||||||
sections to go to RAM, while a program destined to be embedded will see
|
|
||||||
some of his sections going into the ROM.
|
|
||||||
|
|
||||||
The connection between a section and where that section is loaded into
|
|
||||||
memory is made at link time. One has to let the linker know where
|
|
||||||
the different sections are to be placed once they are in memory.
|
|
||||||
|
|
||||||
The following example shows a simple layout of program sections. With
|
|
||||||
some object formats, there are many more sections but the basic
|
|
||||||
layout is conceptually similar.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
+-----------------+
|
|
||||||
| .text | RAM or ROM
|
|
||||||
+-----------------+
|
|
||||||
| .data | RAM
|
|
||||||
+-----------------+
|
|
||||||
| .bss | RAM
|
|
||||||
+-----------------+
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section Example Linker Command Script
|
|
||||||
|
|
||||||
The GNU linker has a command language to specify the image format. This
|
|
||||||
command language can be quite complicated but most of what is required
|
|
||||||
can be learned by careful examination of a well-documented example.
|
|
||||||
The following is a heavily commented version of the linker script
|
|
||||||
used with the the @code{gen68340} BSP This file can be found at
|
|
||||||
$BSP340_ROOT/startup/linkcmds.
|
|
||||||
|
|
||||||
@example
|
|
||||||
/*
|
|
||||||
* Specify that the output is to be coff-m68k regardless of what the
|
|
||||||
* native object format is.
|
|
||||||
*/
|
|
||||||
|
|
||||||
OUTPUT_FORMAT(coff-m68k)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the amount of RAM on the target board.
|
|
||||||
*
|
|
||||||
* NOTE: The default may be overridden by passing an argument to ld.
|
|
||||||
*/
|
|
||||||
|
|
||||||
RamSize = DEFINED(RamSize) ? RamSize : 4M;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the amount of RAM to be used for the application heap. Objects
|
|
||||||
* allocated using malloc() come from this area. Having a tight heap
|
|
||||||
* size is somewhat difficult and multiple attempts to squeeze it may
|
|
||||||
* be needed reducing memory usage is important. If all objects are
|
|
||||||
* allocated from the heap at system initialization time, this eases
|
|
||||||
* the sizing of the application heap.
|
|
||||||
*
|
|
||||||
* NOTE 1: The default may be overridden by passing an argument to ld.
|
|
||||||
*
|
|
||||||
* NOTE 2: The TCP/IP stack requires additional memory in the Heap.
|
|
||||||
*
|
|
||||||
* NOTE 3: The GNAT/RTEMS run-time requires additional memory in
|
|
||||||
* the Heap.
|
|
||||||
*/
|
|
||||||
|
|
||||||
HeapSize = DEFINED(HeapSize) ? HeapSize : 0x10000;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the size of the starting stack used during BSP initialization
|
|
||||||
* until first task switch. After that point, task stacks allocated
|
|
||||||
* by RTEMS are used.
|
|
||||||
*
|
|
||||||
* NOTE: The default may be overridden by passing an argument to ld.
|
|
||||||
*/
|
|
||||||
|
|
||||||
StackSize = DEFINED(StackSize) ? StackSize : 0x1000;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Starting addresses and length of RAM and ROM.
|
|
||||||
*
|
|
||||||
* The addresses must be valid addresses on the board. The
|
|
||||||
* Chip Selects should be initialized such that the code addresses
|
|
||||||
* are valid.
|
|
||||||
*/
|
|
||||||
|
|
||||||
MEMORY @{
|
|
||||||
ram : ORIGIN = 0x10000000, LENGTH = 4M
|
|
||||||
rom : ORIGIN = 0x01000000, LENGTH = 4M
|
|
||||||
@}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is for the network driver. See the Networking documentation
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ETHERNET_ADDRESS =
|
|
||||||
DEFINED(ETHERNET_ADDRESS) ? ETHERNET_ADDRESS : 0xDEAD12;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following defines the order in which the sections should go.
|
|
||||||
* It also defines a number of variables which can be used by the
|
|
||||||
* application program.
|
|
||||||
*
|
|
||||||
* NOTE: Each variable appears with 1 or 2 leading underscores to
|
|
||||||
* ensure that the variable is accessible from C code with a
|
|
||||||
* single underscore. Some object formats automatically add
|
|
||||||
* a leading underscore to all C global symbols.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SECTIONS @{
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make the RomBase variable available to the application.
|
|
||||||
*/
|
|
||||||
|
|
||||||
_RamSize = RamSize;
|
|
||||||
__RamSize = RamSize;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Boot PROM - Set the RomBase variable to the start of the ROM.
|
|
||||||
*/
|
|
||||||
|
|
||||||
rom : @{
|
|
||||||
_RomBase = .;
|
|
||||||
__RomBase = .;
|
|
||||||
@} >rom
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dynamic RAM - set the RamBase variable to the start of the RAM.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ram : @{
|
|
||||||
_RamBase = .;
|
|
||||||
__RamBase = .;
|
|
||||||
@} >ram
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Text (code) goes into ROM
|
|
||||||
*/
|
|
||||||
|
|
||||||
.text : @{
|
|
||||||
/*
|
|
||||||
* Create a symbol for each object (.o).
|
|
||||||
*/
|
|
||||||
|
|
||||||
CREATE_OBJECT_SYMBOLS
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Put all the object files code sections here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
*(.text)
|
|
||||||
|
|
||||||
. = ALIGN (16); /* go to a 16-byte boundary */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* C++ constructors and destructors
|
|
||||||
*
|
|
||||||
* NOTE: See the CROSSGCC mailing-list FAQ for
|
|
||||||
* more details about the "[......]".
|
|
||||||
*/
|
|
||||||
|
|
||||||
__CTOR_LIST__ = .;
|
|
||||||
[......]
|
|
||||||
__DTOR_END__ = .;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Declares where the .text section ends.
|
|
||||||
*/
|
|
||||||
|
|
||||||
etext = .;
|
|
||||||
_etext = .;
|
|
||||||
@} >rom
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Exception Handler Frame section
|
|
||||||
*/
|
|
||||||
|
|
||||||
.eh_fram : @{
|
|
||||||
. = ALIGN (16);
|
|
||||||
*(.eh_fram)
|
|
||||||
@} >ram
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GCC Exception section
|
|
||||||
*/
|
|
||||||
|
|
||||||
.gcc_exc : @{
|
|
||||||
. = ALIGN (16);
|
|
||||||
*(.gcc_exc)
|
|
||||||
@} >ram
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Special variable to let application get to the dual-ported
|
|
||||||
* memory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
dpram : @{
|
|
||||||
m340 = .;
|
|
||||||
_m340 = .;
|
|
||||||
. += (8 * 1024);
|
|
||||||
@} >ram
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialized Data section goes in RAM
|
|
||||||
*/
|
|
||||||
|
|
||||||
.data : @{
|
|
||||||
copy_start = .;
|
|
||||||
*(.data)
|
|
||||||
|
|
||||||
. = ALIGN (16);
|
|
||||||
_edata = .;
|
|
||||||
copy_end = .;
|
|
||||||
@} >ram
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Uninitialized Data section goes in ROM
|
|
||||||
*/
|
|
||||||
|
|
||||||
.bss : @{
|
|
||||||
/*
|
|
||||||
* M68K specific: Reserve some room for the Vector Table
|
|
||||||
* (256 vectors of 4 bytes).
|
|
||||||
*/
|
|
||||||
|
|
||||||
M68Kvec = .;
|
|
||||||
_M68Kvec = .;
|
|
||||||
. += (256 * 4);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start of memory to zero out at initialization time.
|
|
||||||
*/
|
|
||||||
|
|
||||||
clear_start = .;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Put all the object files uninitialized data sections
|
|
||||||
* here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
*(.bss)
|
|
||||||
|
|
||||||
*(COMMON)
|
|
||||||
|
|
||||||
. = ALIGN (16);
|
|
||||||
_end = .;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start of the Application Heap
|
|
||||||
*/
|
|
||||||
|
|
||||||
_HeapStart = .;
|
|
||||||
__HeapStart = .;
|
|
||||||
. += HeapSize;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The Starting Stack goes after the Application Heap.
|
|
||||||
* M68K stack grows down so start at high address.
|
|
||||||
*/
|
|
||||||
|
|
||||||
. += StackSize;
|
|
||||||
. = ALIGN (16);
|
|
||||||
stack_init = .;
|
|
||||||
|
|
||||||
clear_end = .;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The RTEMS Executive Workspace goes here. RTEMS
|
|
||||||
* allocates tasks, stacks, semaphores, etc. from this
|
|
||||||
* memory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
_WorkspaceBase = .;
|
|
||||||
__WorkspaceBase = .;
|
|
||||||
@} >ram
|
|
||||||
@}
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section Initialized Data
|
|
||||||
|
|
||||||
Now there's a problem with the initialized data: the @code{.data} section
|
|
||||||
has to be in RAM as this data may be modified during the program execution.
|
|
||||||
But how will the values be initialized at boot time?
|
|
||||||
|
|
||||||
One approach is to place the entire program image in RAM and reload
|
|
||||||
the image in its entirety each time the program is run. This is fine
|
|
||||||
for use in a debug environment where a high-speed connection is available
|
|
||||||
between the development host computer and the target. But even in this
|
|
||||||
environment, it is cumbersome.
|
|
||||||
|
|
||||||
The solution is to place a copy of the initialized data in a separate
|
|
||||||
area of memory and copy it into the proper location each time the
|
|
||||||
program is started. It is common practice to place a copy of the initialized
|
|
||||||
@code{.data} section at the end of the code (@code{.text}) section
|
|
||||||
in ROM when building a PROM image. The GNU tool @code{objcopy}
|
|
||||||
can be used for this purpose.
|
|
||||||
|
|
||||||
The following figure illustrates the steps a linked program goes through
|
|
||||||
to become a downloadable image.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
+--------------+ +--------------------+
|
|
||||||
| .data RAM | | .data RAM |
|
|
||||||
+--------------+ +--------------------+
|
|
||||||
| .bss RAM | | .bss RAM |
|
|
||||||
+--------------+ +--------------------+ +----------------+
|
|
||||||
| .text ROM | | .text ROM | | .text |
|
|
||||||
+--------------+ +--------------------+ +----------------+
|
|
||||||
| copy of .data ROM | | copy of .data |
|
|
||||||
+--------------------+ +----------------+
|
|
||||||
|
|
||||||
Step 1 Step 2 Step 3
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
In Step 1, the program is linked together using the BSP linker script.
|
|
||||||
|
|
||||||
In Step 2, a copy is made of the @code{.data} section and placed
|
|
||||||
after the @code{.text} section so it can be placed in PROM. This step
|
|
||||||
is done after the linking time. There is an example
|
|
||||||
of doing this in the file $RTEMS_ROOT/make/custom/gen68340.cfg:
|
|
||||||
|
|
||||||
@example
|
|
||||||
# make a PROM image using objcopy
|
|
||||||
m68k-rtems-objcopy \
|
|
||||||
--adjust-section-vma .data= \
|
|
||||||
|
|
||||||
`m68k-rtems-objdump --section-headers \
|
|
||||||
$(basename $@@).exe \
|
|
||||||
| awk '[...]` \
|
|
||||||
$(basename $@@).exe
|
|
||||||
@end example
|
|
||||||
|
|
||||||
NOTE: The address of the "copy of @code{.data} section" is
|
|
||||||
created by extracting the last address in the @code{.text}
|
|
||||||
section with an @code{awk} script. The details of how
|
|
||||||
this is done are not relevant.
|
|
||||||
|
|
||||||
Step 3 shows the final executable image as it logically appears in
|
|
||||||
the target's non-volatile program memory. The board initialization
|
|
||||||
code will copy the ""copy of @code{.data} section" (which are stored in
|
|
||||||
ROM) to their reserved location in RAM.
|
|
||||||
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2008.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Makefiles
|
|
||||||
|
|
||||||
This chapter discusses the Makefiles associated with a BSP. It does not
|
|
||||||
describe the process of configuring, building, and installing RTEMS.
|
|
||||||
This chapter will not provide detailed information about this process.
|
|
||||||
Nonetheless, it is important to remember that the general process consists
|
|
||||||
of four phases as shown here:
|
|
||||||
|
|
||||||
@ifset use-ascii
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
@itemize @bullet
|
|
||||||
@item bootstrap
|
|
||||||
@item configure
|
|
||||||
@item build
|
|
||||||
@item install
|
|
||||||
@end itemize
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
@ifset use-tex
|
|
||||||
@image{Developer-User-Timeline,6in,,Developer User Timeline,.png}
|
|
||||||
@c @image{FILENAME[, WIDTH[, HEIGHT[, ALTTEXT[, EXTENSION]]]]}
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
@ifset use-html
|
|
||||||
@html
|
|
||||||
<center>
|
|
||||||
<IMG SRC="Developer-User-Timeline.png" WIDTH=800 ALT="Developer User Timeline">
|
|
||||||
</center>
|
|
||||||
@end html
|
|
||||||
@end ifset
|
|
||||||
|
|
||||||
|
|
||||||
During the bootstrap phase, you are using the @code{configure.ac} and
|
|
||||||
@code{Makefile.am} files as input to GNU autoconf and automake to
|
|
||||||
generate a variety of files. This is done by running the @code{bootstrap}
|
|
||||||
script found at the top of the RTEMS source tree.
|
|
||||||
|
|
||||||
During the configure phase, a number of files are generated. These
|
|
||||||
generated files are tailored for the specific host/target combination
|
|
||||||
by the configure script. This set of files includes the Makefiles used
|
|
||||||
to actually compile and install RTEMS.
|
|
||||||
|
|
||||||
During the build phase, the source files are compiled into object files
|
|
||||||
and libraries are built.
|
|
||||||
|
|
||||||
During the install phase, the libraries, header files, and other support
|
|
||||||
files are copied to the BSP specific installation point. After installation
|
|
||||||
is successfully completed, the files generated by the configure and build
|
|
||||||
phases may be removed.
|
|
||||||
|
|
||||||
@section Makefiles Used During The BSP Building Process
|
|
||||||
|
|
||||||
RTEMS uses the @b{GNU automake} and @b{GNU autoconf} automatic
|
|
||||||
configuration package. Consequently, there are a number of
|
|
||||||
automatically generated files in each directory in the RTEMS
|
|
||||||
source tree. The @code{bootstrap} script found in the top level
|
|
||||||
directory of the RTEMS source tree is executed to produce the
|
|
||||||
automatically generated files. That script must be run from
|
|
||||||
a directory with a @code{configure.ac} file in it. The @code{bootstrap}
|
|
||||||
command is usually invoked in one of the following manners:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item @code{bootstrap} to regenerate all files that are generated by
|
|
||||||
autoconf and automake.
|
|
||||||
@item @code{bootstrap -c} to remove all files generated by autoconf and
|
|
||||||
automake.
|
|
||||||
@item @code{bootstrap -p} to regenerate @code{preinstall.am} files.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
There is a file named @code{Makefile.am} in each directory of
|
|
||||||
a BSP. This file is used by @b{automake} to produce the file named
|
|
||||||
@code{Makefile.in} which is also found in each directory of a BSP.
|
|
||||||
When modifying a @code{Makefile.am}, you can probably find examples of
|
|
||||||
anything you need to do in one of the BSPs.
|
|
||||||
|
|
||||||
|
|
||||||
The configure process specializes the @code{Makefile.in} files at the time that RTEMS
|
|
||||||
is configured for a specific development host and target. Makefiles
|
|
||||||
are automatically generated from the @code{Makefile.in} files. It is
|
|
||||||
necessary for the BSP developer to provide the @code{Makefile.am}
|
|
||||||
files and generate the @code{Makefile.in} files. Most of the
|
|
||||||
time, it is possible to copy the @code{Makefile.am} from another
|
|
||||||
similar directory and edit it.
|
|
||||||
|
|
||||||
The @code{Makefile} files generated are processed when configuring
|
|
||||||
and building RTEMS for a given BSP.
|
|
||||||
|
|
||||||
The BSP developer is responsible for generating @code{Makefile.am}
|
|
||||||
files which properly build all the files associated with their BSP.
|
|
||||||
Most BSPs will only have a single @code{Makefile.am} which details
|
|
||||||
the set of source files to build to compose the BSP support library
|
|
||||||
along with the set of include files that are to be installed.
|
|
||||||
|
|
||||||
This single @code{Makefile.am} at the top of the BSP tree specifies
|
|
||||||
the set of header files to install. This fragment from the SPARC/ERC32
|
|
||||||
BSP results in four header files being installed.
|
|
||||||
|
|
||||||
@example
|
|
||||||
include_HEADERS = include/bsp.h
|
|
||||||
include_HEADERS += include/tm27.h
|
|
||||||
include_HEADERS += include/erc32.h
|
|
||||||
include_HEADERS += include/coverhd.h
|
|
||||||
@end example
|
|
||||||
|
|
||||||
When adding new include files, you will be adding to the set of
|
|
||||||
@code{include_HEADERS}. When you finish editing the @code{Makefile.am}
|
|
||||||
file, do not forget to run @code{bootstrap -p} to regenerate the
|
|
||||||
@code{preinstall.am}.
|
|
||||||
|
|
||||||
The @code{Makefile.am} also specifies which source files to build.
|
|
||||||
By convention, logical components within the BSP each assign their
|
|
||||||
source files to a unique variable. These variables which define
|
|
||||||
the source files are collected into a single variable which instructs
|
|
||||||
the GNU autotools that we are building @code{libbsp.a}. This fragment
|
|
||||||
from the SPARC/ERC32 BSP shows how the startup related, miscellaneous
|
|
||||||
support code, and the console device driver source is managed
|
|
||||||
in the @code{Makefile.am}.
|
|
||||||
|
|
||||||
@example
|
|
||||||
startup_SOURCES = ../../sparc/shared/bspclean.c ../../shared/bsplibc.c \
|
|
||||||
../../shared/bsppredriverhook.c \
|
|
||||||
../../shared/bsppost.c ../../sparc/shared/bspstart.c \
|
|
||||||
../../shared/bootcard.c ../../shared/sbrk.c startup/setvec.c \
|
|
||||||
startup/spurious.c startup/erc32mec.c startup/boardinit.S
|
|
||||||
clock_SOURCES = clock/ckinit.c
|
|
||||||
...
|
|
||||||
noinst_LIBRARIES = libbsp.a
|
|
||||||
libbsp_a_SOURCES = $(startup_SOURCES) $(console_SOURCES) ...
|
|
||||||
@end example
|
|
||||||
|
|
||||||
When adding new files to an existing directory, do not forget to add
|
|
||||||
the new files to the list of files to be built in the corresponding
|
|
||||||
@code{XXX_SOURCES} variable in the @code{Makefile.am} and run
|
|
||||||
@code{bootstrap}.
|
|
||||||
|
|
||||||
Some BSPs use code that is built in @code{libcpu}. If you BSP does
|
|
||||||
this, then you will need to make sure the objects are pulled into your
|
|
||||||
BSP library. The following from the SPARC/ERC32 BSP pulls in the cache,
|
|
||||||
register window management and system call support code from the directory
|
|
||||||
corresponding to its @code{RTEMS_CPU} model.
|
|
||||||
|
|
||||||
@example
|
|
||||||
libbsp_a_LIBADD = ../../../libcpu/@@RTEMS_CPU@@/cache.rel \
|
|
||||||
../../../libcpu/@@RTEMS_CPU@@/reg_win.rel \
|
|
||||||
../../../libcpu/@@RTEMS_CPU@@/syscall.rel
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@b{NOTE:} The @code{Makefile.am} files are ONLY processed by
|
|
||||||
@code{bootstrap} and the resulting @code{Makefile.in} files are only
|
|
||||||
processed during the configure process of a RTEMS build. Therefore,
|
|
||||||
when developing a BSP and adding a new file to a @code{Makefile.am},
|
|
||||||
the already generated @code{Makefile} will not automatically
|
|
||||||
include the new references unless you configured RTEMS with the
|
|
||||||
@code{--enable-maintainer-mode} option. Otherwise, the new file not
|
|
||||||
being be taken into account!
|
|
||||||
|
|
||||||
@section Creating a New BSP Make Customization File
|
|
||||||
|
|
||||||
When building a BSP or an application using that BSP, it is necessary
|
|
||||||
to tailor the compilation arguments to account for compiler flags, use
|
|
||||||
custom linker scripts, include the RTEMS libraries, etc.. The BSP
|
|
||||||
must be built using this information. Later, once the BSP is installed
|
|
||||||
with the toolset, this same information must be used when building the
|
|
||||||
application. So a BSP must include a build configuration file. The
|
|
||||||
configuration file is @code{make/custom/BSP.cfg}.
|
|
||||||
|
|
||||||
The configuration file is taken into account when building one's
|
|
||||||
application using the RTEMS template Makefiles (@code{make/templates}).
|
|
||||||
These application template Makefiles have been included with the
|
|
||||||
RTEMS source distribution since the early 1990's. However there is
|
|
||||||
a desire in the RTEMS user community to move all provided examples to
|
|
||||||
GNU autoconf. They are included in the 4.9 release series and used for
|
|
||||||
all examples provided with RTEMS. There is no definite time table for
|
|
||||||
obsoleting them. You are free to use these but be warned they have
|
|
||||||
fallen out of favor with many in the RTEMS community and may disappear
|
|
||||||
in the future.
|
|
||||||
|
|
||||||
The following is a slightly shortened version of the make customization
|
|
||||||
file for the gen68340 BSP. The original source for this file can be
|
|
||||||
found in the @code{make/custom} directory.
|
|
||||||
|
|
||||||
@example
|
|
||||||
# The RTEMS CPU Family and Model
|
|
||||||
RTEMS_CPU=m68k
|
|
||||||
RTEMS_CPU_MODEL=m68340
|
|
||||||
|
|
||||||
include $(RTEMS_ROOT)/make/custom/default.cfg
|
|
||||||
|
|
||||||
# This is the actual bsp directory used during the build process.
|
|
||||||
RTEMS_BSP_FAMILY=gen68340
|
|
||||||
|
|
||||||
# This contains the compiler options necessary to select the CPU model
|
|
||||||
# and (hopefully) optimize for it.
|
|
||||||
CPU_CFLAGS = -mcpu=cpu32
|
|
||||||
|
|
||||||
# optimize flag: typically -O2
|
|
||||||
CFLAGS_OPTIMIZE_V = -O2 -g -fomit-frame-pointer
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The make customization files have generally grown simpler and simpler
|
|
||||||
with each RTEMS release. Beginning in the 4.9 release series, the rules
|
|
||||||
for linking an RTEMS application are shared by all BSPs. Only BSPs which
|
|
||||||
need to perform a transformation from linked ELF file to a downloadable
|
|
||||||
format have any additional actions for program link time. In 4.8 and
|
|
||||||
older, every BSP specified the "make executable" or @code{make-exe}
|
|
||||||
rule and duplicated the same actions.
|
|
||||||
|
|
||||||
It is generally easier to copy a @code{make/custom} file from a
|
|
||||||
BSP similar to the one being developed.
|
|
||||||
|
|
||||||
@@ -1,231 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Non-Volatile Memory Driver
|
|
||||||
|
|
||||||
The Non-Volatile driver is responsible for providing an
|
|
||||||
interface to various types of non-volatile memory. These
|
|
||||||
types of memory include, but are not limited to, Flash, EEPROM,
|
|
||||||
and battery backed RAM. The capabilities provided
|
|
||||||
by this class of device driver are:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item Initialize the Non-Volatile Memory Driver
|
|
||||||
@item Optional Disable Read and Write Handlers
|
|
||||||
@item Open a Particular Memory Partition
|
|
||||||
@item Close a Particular Memory Partition
|
|
||||||
@item Read from a Particular Memory Partition
|
|
||||||
@item Write to a Particular Memory Partition
|
|
||||||
@item Erase the Non-Volatile Memory Area
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
There is currently only one non-volatile device driver included in the
|
|
||||||
RTEMS source tree. The information provided in this chapter
|
|
||||||
is based on drivers developed for applications using RTEMS.
|
|
||||||
It is hoped that this driver model information can form the
|
|
||||||
basis for a standard non-volatile memory driver model that
|
|
||||||
can be supported in future RTEMS distribution.
|
|
||||||
|
|
||||||
@section Major and Minor Numbers
|
|
||||||
|
|
||||||
The @b{major} number of a device driver is its index in the
|
|
||||||
RTEMS Device Address Table.
|
|
||||||
|
|
||||||
A @b{minor} number is associated with each device instance
|
|
||||||
managed by a particular device driver. An RTEMS minor number
|
|
||||||
is an @code{unsigned32} entity. Convention calls
|
|
||||||
dividing the bits in the minor number down into categories
|
|
||||||
that specify an area of non-volatile memory and a partition
|
|
||||||
with that area. This results in categories
|
|
||||||
like the following:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item @b{area} - indicates a block of non-volatile memory
|
|
||||||
@item @b{partition} - indicates a particular address range with an area
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
From the above, it should be clear that a single device driver
|
|
||||||
can support multiple types of non-volatile memory in a single system.
|
|
||||||
The minor number is used to distinguish the types of memory and
|
|
||||||
blocks of memory used for different purposes.
|
|
||||||
|
|
||||||
@section Non-Volatile Memory Driver Configuration
|
|
||||||
|
|
||||||
There is not a standard non-volatile driver configuration table but some
|
|
||||||
fields are common across different drivers. The non-volatile memory driver
|
|
||||||
configuration table is typically an array of structures with each
|
|
||||||
structure containing the information for a particular area of
|
|
||||||
non-volatile memory.
|
|
||||||
The following is a list of the type of information normally required
|
|
||||||
to configure each area of non-volatile memory.
|
|
||||||
|
|
||||||
@table @b
|
|
||||||
@item memory_type
|
|
||||||
is the type of memory device in this area. Choices are battery backed RAM,
|
|
||||||
EEPROM, Flash, or an optional user-supplied type. If the user-supplied type
|
|
||||||
is configured, then the user is responsible for providing a set of
|
|
||||||
routines to program the memory.
|
|
||||||
|
|
||||||
@item memory
|
|
||||||
is the base address of this memory area.
|
|
||||||
|
|
||||||
@item attributes
|
|
||||||
is a pointer to a memory type specific attribute block. Some of
|
|
||||||
the fields commonly contained in this memory type specific attribute
|
|
||||||
structure area:
|
|
||||||
|
|
||||||
@table @b
|
|
||||||
@item use_protection_algorithm
|
|
||||||
is set to TRUE to indicate that the protection (i.e. locking) algorithm
|
|
||||||
should be used for this area of non-volatile memory. A particular
|
|
||||||
type of non-volatile memory may not have a protection algorithm.
|
|
||||||
|
|
||||||
@item access
|
|
||||||
is an enumerated type to indicate the organization of the memory
|
|
||||||
devices in this memory area. The following is a list of the
|
|
||||||
access types supported by the current driver implementation:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item simple unsigned8
|
|
||||||
@item simple unsigned16
|
|
||||||
@item simple unsigned32
|
|
||||||
@item simple unsigned64
|
|
||||||
@item single unsigned8 at offset 0 in an unsigned16
|
|
||||||
@item single unsigned8 at offset 1 in an unsigned16
|
|
||||||
@item single unsigned8 at offset 0 in an unsigned32
|
|
||||||
@item single unsigned8 at offset 1 in an unsigned32
|
|
||||||
@item single unsigned8 at offset 2 in an unsigned32
|
|
||||||
@item single unsigned8 at offset 3 in an unsigned32
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@item depth
|
|
||||||
is the depth of the progamming FIFO on this particular chip. Some
|
|
||||||
chips, particularly EEPROMs, have the same programming algorithm but
|
|
||||||
vary in the depth of the amount of data that can be programmed in a single
|
|
||||||
block.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@item number_of_partitions
|
|
||||||
is the number of logical partitions within this area.
|
|
||||||
|
|
||||||
@item Partitions
|
|
||||||
is the address of the table that contains an entry to describe each
|
|
||||||
partition in this area. Fields within each element of this
|
|
||||||
table are defined as follows:
|
|
||||||
|
|
||||||
@table @b
|
|
||||||
|
|
||||||
@item offset
|
|
||||||
is the offset of this partition from the base address of this area.
|
|
||||||
|
|
||||||
@item length
|
|
||||||
is the length of this partition.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
@end table
|
|
||||||
|
|
||||||
By dividing an area of memory into multiple partitions, it is possible
|
|
||||||
to easily divide the non-volatile memory for different purposes.
|
|
||||||
|
|
||||||
@section Initialize the Non-Volatile Memory Driver
|
|
||||||
|
|
||||||
At system initialization, the non-volatile memory driver's
|
|
||||||
initialization entry point will be invoked. As part of
|
|
||||||
initialization, the driver will perform
|
|
||||||
whatever initializatin is required on each non-volatile memory area.
|
|
||||||
|
|
||||||
The discrete I/O driver may register device names for memory
|
|
||||||
partitions of particular interest to the system. Normally this
|
|
||||||
will be restricted to the device "/dev/nv_memory" to indicate
|
|
||||||
the entire device driver.
|
|
||||||
|
|
||||||
@section Disable Read and Write Handlers
|
|
||||||
|
|
||||||
Depending on the target's non-volatile memory configuration, it may be
|
|
||||||
possible to write to a status register and make the memory area completely
|
|
||||||
inaccessible. This is target dependent and beyond the standard capabilities
|
|
||||||
of any memory type. The user has the optional capability to provide
|
|
||||||
handlers to disable and enable access to a partiticular memory area.
|
|
||||||
|
|
||||||
@section Open a Particular Memory Partition
|
|
||||||
|
|
||||||
This is the driver open call. Usually this call does nothing other than
|
|
||||||
validate the minor number.
|
|
||||||
|
|
||||||
With some drivers, it may be necessary to allocate memory when a particular
|
|
||||||
device is opened. If that is the case, then this is often the place
|
|
||||||
to do this operation.
|
|
||||||
|
|
||||||
@section Close a Particular Memory Partition
|
|
||||||
|
|
||||||
This is the driver close call. Usually this call does nothing.
|
|
||||||
|
|
||||||
With some drivers, it may be necessary to allocate memory when a particular
|
|
||||||
device is opened. If that is the case, then this is the place
|
|
||||||
where that memory should be deallocated.
|
|
||||||
|
|
||||||
@section Read from a Particular Memory Partition
|
|
||||||
|
|
||||||
This corresponds to the driver read call. After validating the minor
|
|
||||||
number and arguments, this call enables reads from the specified
|
|
||||||
memory area by invoking the user supplied "enable reads handler"
|
|
||||||
and then reads the indicated memory area. When
|
|
||||||
invoked the @code{argument_block} is actually a pointer to the following
|
|
||||||
structure type:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
typedef struct @{
|
|
||||||
uint32_t offset;
|
|
||||||
void *buffer;
|
|
||||||
uint32_t length;
|
|
||||||
uint32_t status;
|
|
||||||
@} Non_volatile_memory_Driver_arguments;
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The driver reads @code{length} bytes starting at @code{offset} into
|
|
||||||
the partition and places them at @code{buffer}. The result is returned
|
|
||||||
in @code{status}.
|
|
||||||
|
|
||||||
After the read operation is complete, the user supplied "disable reads handler"
|
|
||||||
is invoked to protect the memory area again.
|
|
||||||
|
|
||||||
@section Write to a Particular Memory Partition
|
|
||||||
|
|
||||||
This corresponds to the driver write call. After validating the minor
|
|
||||||
number and arguments, this call enables writes to the specified
|
|
||||||
memory area by invoking the "enable writes handler", then unprotecting
|
|
||||||
the memory area, and finally actually writing to the indicated memory
|
|
||||||
area. When invoked the @code{argument_block} is actually a pointer to
|
|
||||||
the following structure type:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
typedef struct @{
|
|
||||||
uint32_t offset;
|
|
||||||
void *buffer;
|
|
||||||
uint32_t length;
|
|
||||||
uint32_t status;
|
|
||||||
@} Non_volatile_memory_Driver_arguments;
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The driver writes @code{length} bytes from @code{buffer} and
|
|
||||||
writes them to the non-volatile memory starting at @code{offset} into
|
|
||||||
the partition. The result is returned in @code{status}.
|
|
||||||
|
|
||||||
After the write operation is complete, the "disable writes handler"
|
|
||||||
is invoked to protect the memory area again.
|
|
||||||
|
|
||||||
@section Erase the Non-Volatile Memory Area
|
|
||||||
|
|
||||||
This is one of the IOCTL functions supported by the I/O control
|
|
||||||
device driver entry point. When this IOCTL function is invoked,
|
|
||||||
the specified area of non-volatile memory is erased.
|
|
||||||
|
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Real-Time Clock Driver
|
|
||||||
|
|
||||||
@section Introduction
|
|
||||||
|
|
||||||
The Real-Time Clock (@b{RTC}) driver is responsible for providing an
|
|
||||||
interface to an @b{RTC} device. [NOTE: In this chapter, the abbreviation
|
|
||||||
@b{TOD} is used for @b{Time of Day}.] The capabilities provided by this
|
|
||||||
driver are:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item Set the RTC TOD to RTEMS TOD
|
|
||||||
@item Set the RTEMS TOD to the RTC TOD
|
|
||||||
@item Get the RTC TOD
|
|
||||||
@item Set the RTC TOD to the Specified TOD
|
|
||||||
@item Get the Difference Between the RTEMS and RTC TOD
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
The reference implementation for a real-time clock driver can
|
|
||||||
be found in @code{c/src/lib/libbsp/shared/tod.c}. This driver
|
|
||||||
is based on the libchip concept and can be easily configured
|
|
||||||
to work with any of the RTC chips supported by the RTC
|
|
||||||
chip drivers in the directory @code{c/src/lib/lib/libchip/rtc}.
|
|
||||||
There is a README file in this directory for each supported
|
|
||||||
RTC chip. Each of these README explains how to configure the
|
|
||||||
shared libchip implementation of the RTC driver for that particular
|
|
||||||
RTC chip.
|
|
||||||
|
|
||||||
The DY-4 DMV177 BSP used the shared libchip implementation of the RTC
|
|
||||||
driver. There were no DMV177 specific configuration routines. A BSP
|
|
||||||
could use configuration routines to dynamically determine what type
|
|
||||||
of real-time clock is on a particular board. This would be useful for
|
|
||||||
a BSP supporting multiple board models. The relevant ports of
|
|
||||||
the DMV177's @code{RTC_Table} configuration table is below:
|
|
||||||
|
|
||||||
@example
|
|
||||||
|
|
||||||
#include <bsp.h>
|
|
||||||
#include <libchip/rtc.h>
|
|
||||||
#include <libchip/icm7170.h>
|
|
||||||
|
|
||||||
bool dmv177_icm7170_probe(int minor);
|
|
||||||
|
|
||||||
rtc_tbl RTC_Table[] = @{
|
|
||||||
@{ "/dev/rtc0", /* sDeviceName */
|
|
||||||
RTC_ICM7170, /* deviceType */
|
|
||||||
&icm7170_fns, /* pDeviceFns */
|
|
||||||
dmv177_icm7170_probe, /* deviceProbe */
|
|
||||||
(void *) ICM7170_AT_1_MHZ, /* pDeviceParams */
|
|
||||||
DMV170_RTC_ADDRESS, /* ulCtrlPort1 */
|
|
||||||
0, /* ulDataPort */
|
|
||||||
icm7170_get_register_8, /* getRegister */
|
|
||||||
icm7170_set_register_8, /* setRegister */
|
|
||||||
@}
|
|
||||||
@};
|
|
||||||
|
|
||||||
unsigned long RTC_Count = (sizeof(RTC_Table)/sizeof(rtc_tbl));
|
|
||||||
rtems_device_minor_number RTC_Minor;
|
|
||||||
|
|
||||||
bool dmv177_icm7170_probe(int minor)
|
|
||||||
@{
|
|
||||||
volatile unsigned16 *card_resource_reg;
|
|
||||||
|
|
||||||
card_resource_reg = (volatile unsigned16 *) DMV170_CARD_RESORCE_REG;
|
|
||||||
|
|
||||||
if ( (*card_resource_reg & DMV170_RTC_INST_MASK) == DMV170_RTC_INSTALLED )
|
|
||||||
return TRUE;
|
|
||||||
return FALSE;
|
|
||||||
@}
|
|
||||||
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section Initialization
|
|
||||||
|
|
||||||
The @code{rtc_initialize} routine is responsible for initializing the
|
|
||||||
RTC chip so it can be used. The shared libchip implementation of this
|
|
||||||
driver supports multiple RTCs and bases its initialization order on
|
|
||||||
the order the chips are defined in the @code{RTC_Table}. Each chip
|
|
||||||
defined in the table may or may not be present on this particular board.
|
|
||||||
It is the responsibility of the @code{deviceProbe} to indicate the
|
|
||||||
presence of a particular RTC chip. The first RTC found to be present
|
|
||||||
is considered the preferred RTC.
|
|
||||||
|
|
||||||
In the shared libchip based implementation
|
|
||||||
of the driver, the following actions are performed:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_device_driver rtc_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor_arg,
|
|
||||||
void *arg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
for each RTC configured in RTC_Table
|
|
||||||
if the deviceProbe for this RTC indicates it is present
|
|
||||||
set RTC_Minor to this device
|
|
||||||
set RTC_Present to TRUE
|
|
||||||
break out of this loop
|
|
||||||
|
|
||||||
if RTC_Present is not TRUE
|
|
||||||
return RTEMS_INVALID_NUMBER to indicate that no RTC is present
|
|
||||||
|
|
||||||
register this minor number as the "/dev/rtc"
|
|
||||||
|
|
||||||
perform the deviceInitialize routine for the preferred RTC chip
|
|
||||||
|
|
||||||
for RTCs past this one in the RTC_Table
|
|
||||||
if the deviceProbe for this RTC indicates it is present
|
|
||||||
perform the deviceInitialize routine for this RTC chip
|
|
||||||
register the configured name for this RTC
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The @code{deviceProbe} routine returns TRUE if the device
|
|
||||||
configured by this entry in the @code{RTC_Table} is present.
|
|
||||||
This configuration scheme allows one to support multiple versions
|
|
||||||
of the same board with a single BSP. For example, if the first
|
|
||||||
generation of a board had Vendor A's RTC chip and the second
|
|
||||||
generation had Vendor B's RTC chip, RTC_Table could contain
|
|
||||||
information for both. The @code{deviceProbe} configured
|
|
||||||
for Vendor A's RTC chip would need to return TRUE if the
|
|
||||||
board was a first generation one. The @code{deviceProbe}
|
|
||||||
routines are very board dependent and must be provided by
|
|
||||||
the BSP.
|
|
||||||
|
|
||||||
@section setRealTimeToRTEMS
|
|
||||||
|
|
||||||
The @code{setRealTimeToRTEMS} routine sets the current RTEMS TOD to that
|
|
||||||
of the preferred RTC.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void setRealTimeToRTEMS(void)
|
|
||||||
@{
|
|
||||||
if no RTCs are present
|
|
||||||
return
|
|
||||||
|
|
||||||
invoke the deviceGetTime routine for the preferred RTC
|
|
||||||
set the RTEMS TOD using rtems_clock_set
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section setRealTimeFromRTEMS
|
|
||||||
|
|
||||||
The @code{setRealTimeFromRTEMS} routine sets the preferred RTC TOD to the
|
|
||||||
current RTEMS TOD.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void setRealTimeFromRTEMS(void)
|
|
||||||
@{
|
|
||||||
if no RTCs are present
|
|
||||||
return
|
|
||||||
|
|
||||||
obtain the RTEMS TOD using rtems_clock_get
|
|
||||||
invoke the deviceSetTime routine for the preferred RTC
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section getRealTime
|
|
||||||
|
|
||||||
The @code{getRealTime} returns the preferred RTC TOD to the
|
|
||||||
caller.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void getRealTime( rtems_time_of_day *tod )
|
|
||||||
@{
|
|
||||||
if no RTCs are present
|
|
||||||
return
|
|
||||||
|
|
||||||
invoke the deviceGetTime routine for the preferred RTC
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section setRealTime
|
|
||||||
|
|
||||||
The @code{setRealTime} routine sets the preferred RTC TOD to the
|
|
||||||
TOD specified by the caller.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void setRealTime( rtems_time_of_day *tod )
|
|
||||||
@{
|
|
||||||
if no RTCs are present
|
|
||||||
return
|
|
||||||
|
|
||||||
invoke the deviceSetTime routine for the preferred RTC
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section checkRealTime
|
|
||||||
|
|
||||||
The @code{checkRealTime} routine returns the number of seconds
|
|
||||||
difference between the RTC TOD and the current RTEMS TOD.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
int checkRealTime( void )
|
|
||||||
@{
|
|
||||||
if no RTCs are present
|
|
||||||
return -1
|
|
||||||
|
|
||||||
|
|
||||||
obtain the RTEMS TOD using rtems_clock_get
|
|
||||||
get the TOD from the preferred RTC using the deviceGetTime routine
|
|
||||||
|
|
||||||
convert the RTEMS TOD to seconds
|
|
||||||
convert the RTC TOD to seconds
|
|
||||||
|
|
||||||
return the RTEMS TOD in seconds - RTC TOD in seconds
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2002.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Shared Memory Support Driver
|
|
||||||
|
|
||||||
The Shared Memory Support Driver is responsible for providing glue
|
|
||||||
routines and configuration information required by the Shared
|
|
||||||
Memory Multiprocessor Communications Interface (MPCI). The
|
|
||||||
Shared Memory Support Driver tailors the portable Shared
|
|
||||||
Memory Driver to a particular target platform.
|
|
||||||
|
|
||||||
This driver is only required in shared memory multiprocessing
|
|
||||||
systems that use the RTEMS mulitprocessing support. For more
|
|
||||||
information on RTEMS multiprocessing capabilities and the
|
|
||||||
MPCI, refer to the @b{Multiprocessing Manager} chapter
|
|
||||||
of the @b{RTEMS Application C User's Guide}.
|
|
||||||
|
|
||||||
@section Shared Memory Configuration Table
|
|
||||||
|
|
||||||
The Shared Memory Configuration Table is defined in the following
|
|
||||||
structure:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
typedef volatile uint32_t vol_u32;
|
|
||||||
|
|
||||||
typedef struct @{
|
|
||||||
vol_u32 *address; /* write here for interrupt */
|
|
||||||
vol_u32 value; /* this value causes interrupt */
|
|
||||||
vol_u32 length; /* for this length (0,1,2,4) */
|
|
||||||
@} Shm_Interrupt_information;
|
|
||||||
|
|
||||||
struct shm_config_info @{
|
|
||||||
vol_u32 *base; /* base address of SHM */
|
|
||||||
vol_u32 length; /* length (in bytes) of SHM */
|
|
||||||
vol_u32 format; /* SHM is big or little endian */
|
|
||||||
vol_u32 (*convert)(); /* neutral conversion routine */
|
|
||||||
vol_u32 poll_intr; /* POLLED or INTR driven mode */
|
|
||||||
void (*cause_intr)( uint32_t );
|
|
||||||
Shm_Interrupt_information Intr; /* cause intr information */
|
|
||||||
@};
|
|
||||||
|
|
||||||
typedef struct shm_config_info shm_config_table;
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
where the fields are defined as follows:
|
|
||||||
|
|
||||||
@table @b
|
|
||||||
@item base
|
|
||||||
is the base address of the shared memory buffer used to pass
|
|
||||||
messages between the nodes in the system.
|
|
||||||
|
|
||||||
@item length
|
|
||||||
is the length (in bytes) of the shared memory buffer used to pass
|
|
||||||
messages between the nodes in the system.
|
|
||||||
|
|
||||||
@item format
|
|
||||||
is either SHM_BIG or SHM_LITTLE to indicate that the neutral format
|
|
||||||
of the shared memory area is big or little endian. The format
|
|
||||||
of the memory should be chosen to match most of the inter-node traffic.
|
|
||||||
|
|
||||||
@item convert
|
|
||||||
is the address of a routine which converts from native format to
|
|
||||||
neutral format. Ideally, the neutral format is the same as the
|
|
||||||
native format so this routine is quite simple.
|
|
||||||
|
|
||||||
@item poll_intr
|
|
||||||
is either INTR_MODE or POLLED_MODE to indicate how the node will be
|
|
||||||
informed of incoming messages.
|
|
||||||
|
|
||||||
@item cause_intr
|
|
||||||
|
|
||||||
@item Intr
|
|
||||||
is the information required to cause an interrupt on a node. This
|
|
||||||
structure contains the following fields:
|
|
||||||
@table @b
|
|
||||||
@item address
|
|
||||||
is the address to write at to cause an interrupt on that node.
|
|
||||||
For a polled node, this should be NULL.
|
|
||||||
|
|
||||||
@item value
|
|
||||||
is the value to write to cause an interrupt.
|
|
||||||
|
|
||||||
@item length
|
|
||||||
is the length of the entity to write on the node to cause an interrupt.
|
|
||||||
This can be 0 to indicate polled operation, 1 to write a byte, 2 to
|
|
||||||
write a sixteen-bit entity, and 4 to write a thirty-two bit entity.
|
|
||||||
@end table
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@section Primitives
|
|
||||||
|
|
||||||
@subsection Convert Address
|
|
||||||
|
|
||||||
The @code{Shm_Convert_address} is responsible for converting an address
|
|
||||||
of an entity in the shared memory area into the address that should be
|
|
||||||
used from this node. Most targets will simply return the address
|
|
||||||
passed to this routine. However, some target boards will have a special
|
|
||||||
window onto the shared memory. For example, some VMEbus boards have
|
|
||||||
special address windows to access addresses that are normally reserved
|
|
||||||
in the CPU's address space.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void *Shm_Convert_address( void *address )
|
|
||||||
@{
|
|
||||||
return the local address version of this bus address
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Get Configuration
|
|
||||||
|
|
||||||
The @code{Shm_Get_configuration} routine is responsible for filling in the
|
|
||||||
Shared Memory Configuration Table passed to it.
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void Shm_Get_configuration(
|
|
||||||
uint32_t localnode,
|
|
||||||
shm_config_table **shmcfg
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
fill in the Shared Memory Configuration Table
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection Locking Primitives
|
|
||||||
|
|
||||||
This is a collection of routines that are invoked by the portable
|
|
||||||
part of the Shared Memory Driver to manage locks in the shared
|
|
||||||
memory buffer area. Accesses to the shared memory must be
|
|
||||||
atomic. Two nodes in a multiprocessor system must not be manipulating
|
|
||||||
the shared data structures simultaneously. The locking primitives
|
|
||||||
are used to insure this.
|
|
||||||
|
|
||||||
To avoid deadlock, local processor interrupts should be disabled the entire
|
|
||||||
time the locked queue is locked.
|
|
||||||
|
|
||||||
The locking primitives operate on the lock
|
|
||||||
@code{field} of the @code{Shm_Locked_queue_Control}
|
|
||||||
data structure. This structure is defined as follows:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
typedef struct @{
|
|
||||||
vol_u32 lock; /* lock field for this queue */
|
|
||||||
vol_u32 front; /* first envelope on queue */
|
|
||||||
vol_u32 rear; /* last envelope on queue */
|
|
||||||
vol_u32 owner; /* receiving (i.e. owning) node */
|
|
||||||
@} Shm_Locked_queue_Control;
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
where each field is defined as follows:
|
|
||||||
|
|
||||||
@table @b
|
|
||||||
@item lock
|
|
||||||
is the lock field. Every node in the system must agree on how this
|
|
||||||
field will be used. Many processor families provide an atomic
|
|
||||||
"test and set" instruction that is used to manage this field.
|
|
||||||
|
|
||||||
@item front
|
|
||||||
is the index of the first message on this locked queue.
|
|
||||||
|
|
||||||
@item rear
|
|
||||||
is the index of the last message on this locked queue.
|
|
||||||
|
|
||||||
@item owner
|
|
||||||
is the node number of the node that currently has this structure locked.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@subsubsection Initializing a Shared Lock
|
|
||||||
|
|
||||||
The @code{Shm_Initialize_lock} routine is responsible for
|
|
||||||
initializing the lock field. This routines usually is implemented
|
|
||||||
as follows:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void Shm_Initialize_lock(
|
|
||||||
Shm_Locked_queue_Control *lq_cb
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
lq_cb->lock = LQ_UNLOCKED;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsubsection Acquiring a Shared Lock
|
|
||||||
|
|
||||||
The @code{Shm_Lock} routine is responsible for
|
|
||||||
acquiring the lock field. Interrupts should be
|
|
||||||
disabled while that lock is acquired. If the lock
|
|
||||||
is currently unavailble, then the locking routine
|
|
||||||
should delay a few microseconds to allow the other
|
|
||||||
node to release the lock. Doing this reduces bus contention
|
|
||||||
for the lock. This routines usually is implemented as follows:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void Shm_Lock(
|
|
||||||
Shm_Locked_queue_Control *lq_cb
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
disable processor interrupts
|
|
||||||
set Shm_isrstat to previous interrupt disable level
|
|
||||||
|
|
||||||
while ( TRUE ) @{
|
|
||||||
atomically attempt to acquire the lock
|
|
||||||
if the lock was acquired
|
|
||||||
return
|
|
||||||
delay some small period of time
|
|
||||||
@}
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsubsection Releasing a Shared Lock
|
|
||||||
|
|
||||||
The @code{Shm_Unlock} routine is responsible for
|
|
||||||
releasing the lock field and reenabling processor
|
|
||||||
interrupts. This routines usually is implemented as follows:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void Shm_Unlock(
|
|
||||||
Shm_Locked_queue_Control *lq_cb
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
set the lock to the unlocked value
|
|
||||||
reenable processor interrupts to their level prior
|
|
||||||
to the lock being acquired. This value was saved
|
|
||||||
in the global variable Shm_isrstat
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section Installing the MPCI ISR
|
|
||||||
|
|
||||||
The @code{Shm_setvec} is invoked by the portable portion
|
|
||||||
of the shared memory to install the interrupt service routine
|
|
||||||
that is invoked when an incoming message is announced. Some
|
|
||||||
target boards support an interprocessor interrupt or mailbox
|
|
||||||
scheme and this is where the ISR for that interrupt would be
|
|
||||||
installed.
|
|
||||||
|
|
||||||
On an interrupt driven node, this routine would be implemented
|
|
||||||
as follows:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
void Shm_setvec( void )
|
|
||||||
@{
|
|
||||||
install the interprocessor communications ISR
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
On a polled node, this routine would be empty.
|
|
||||||
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
@set UPDATED 24 February 2013
|
|
||||||
@set UPDATED-MONTH February 2013
|
|
||||||
@set EDITION 4.10.99.0
|
|
||||||
@set VERSION 4.10.99.0
|
|
||||||
@@ -1,366 +0,0 @@
|
|||||||
@c
|
|
||||||
@c COPYRIGHT (c) 1988-2011.
|
|
||||||
@c On-Line Applications Research Corporation (OAR).
|
|
||||||
@c All rights reserved.
|
|
||||||
|
|
||||||
@chapter Miscellaneous Support Files
|
|
||||||
|
|
||||||
@section GCC Compiler Specifications File
|
|
||||||
|
|
||||||
The file @code{bsp_specs} defines the start files and libraries
|
|
||||||
that are always used with this BSP. The format of this file
|
|
||||||
is admittedly cryptic and this document will make no attempt
|
|
||||||
to explain it completely. Below is the @code{bsp_specs}
|
|
||||||
file from the PowerPC psim BSP:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
%rename endfile old_endfile
|
|
||||||
%rename startfile old_startfile
|
|
||||||
%rename link old_link
|
|
||||||
|
|
||||||
*startfile:
|
|
||||||
%@{!qrtems: %(old_startfile)@} \
|
|
||||||
%@{!nostdlib: %@{qrtems: ecrti%O%s rtems_crti%O%s crtbegin.o%s start.o%s@}@}
|
|
||||||
|
|
||||||
*link:
|
|
||||||
%@{!qrtems: %(old_link)@} %@{qrtems: -Qy -dp -Bstatic -e _start -u __vectors@}
|
|
||||||
|
|
||||||
*endfile:
|
|
||||||
%@{!qrtems: %(old_endfile)@} %@{qrtems: crtend.o%s ecrtn.o%s@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The first section of this file renames the built-in definition of
|
|
||||||
some specification variables so they can be augmented without
|
|
||||||
embedded their original definition. The subsequent sections
|
|
||||||
specify what behavior is expected when the @code{-qrtems} option is specified.
|
|
||||||
|
|
||||||
The @code{*startfile} section specifies that the BSP specific file
|
|
||||||
@code{start.o} will be used instead of @code{crt0.o}. In addition,
|
|
||||||
various EABI support files (@code{ecrti.o} etc.) will be linked in with
|
|
||||||
the executable.
|
|
||||||
|
|
||||||
The @code{*link} section adds some arguments to the linker when it is
|
|
||||||
invoked by GCC to link an application for this BSP.
|
|
||||||
|
|
||||||
The format of this file is specific to the GNU Compiler Suite. The
|
|
||||||
argument used to override and extend the compiler built-in specifications
|
|
||||||
is available in all recent GCC versions. The @code{-specs} option is
|
|
||||||
present in all @code{egcs} distributions and @code{gcc} distributions
|
|
||||||
starting with version 2.8.0.
|
|
||||||
|
|
||||||
@section README Files
|
|
||||||
|
|
||||||
Most BSPs provide one or more @code{README} files. Generally, there
|
|
||||||
is a @code{README} file at the top of the BSP source. This file
|
|
||||||
describes the board and its hardware configuration, provides vendor
|
|
||||||
information, local configuration information, information on downloading
|
|
||||||
code to the board, debugging, etc.. The intent of this
|
|
||||||
file is to help someone begin to use the BSP faster.
|
|
||||||
|
|
||||||
A @code{README} file in a BSP subdirectory typically explains something
|
|
||||||
about the contents of that subdirectory in greater detail. For example,
|
|
||||||
it may list the documentation available for a particular peripheral
|
|
||||||
controller and how to obtain that documentation. It may also explain some
|
|
||||||
particularly cryptic part of the software in that directory or provide
|
|
||||||
rationale on the implementation.
|
|
||||||
|
|
||||||
@section times
|
|
||||||
|
|
||||||
This file contains the results of the RTEMS Timing Test Suite. It is
|
|
||||||
in a standard format so that results from one BSP can be easily compared
|
|
||||||
with those of another target board.
|
|
||||||
|
|
||||||
If a BSP supports multiple variants, then there may be multiple @code{times}
|
|
||||||
files. Usually these are named @code{times.VARIANTn}.
|
|
||||||
|
|
||||||
@section Tools Subdirectory
|
|
||||||
|
|
||||||
Some BSPs provide additional tools that aid in using the target board.
|
|
||||||
These tools run on the development host and are built as part of building
|
|
||||||
the BSP. Most common is a script to automate running the RTEMS Test Suites
|
|
||||||
on the BSP. Examples of this include:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@item @code{powerpc/psim} includes scripts to ease use of the simulator
|
|
||||||
|
|
||||||
@item @code{m68k/mvme162} includes a utility to download across the
|
|
||||||
VMEbus into target memory if the host is a VMEbus board in the same
|
|
||||||
chasis.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@section bsp.h Include File
|
|
||||||
|
|
||||||
The file @code{include/bsp.h} contains prototypes and definitions
|
|
||||||
specific to this board. Every BSP is required to provide a @code{bsp.h}.
|
|
||||||
The best approach to writing a @code{bsp.h} is copying an existing one
|
|
||||||
as a starting point.
|
|
||||||
|
|
||||||
Many @code{bsp.h} files provide prototypes of variables defined
|
|
||||||
in the linker script (@code{linkcmds}).
|
|
||||||
|
|
||||||
@section tm27.h Include File
|
|
||||||
|
|
||||||
The @code{tm27} test from the RTEMS Timing Test Suite is designed to measure the length of time required to vector to and return from an interrupt handler. This test requires some help from the BSP to know how to cause and manipulate the interrupt source used for this measurement. The following is a list of these:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item @code{MUST_WAIT_FOR_INTERRUPT} - modifies behavior of @code{tm27}.
|
|
||||||
|
|
||||||
@item @code{Install_tm27_vector} - installs the interrupt service
|
|
||||||
routine for the Interrupt Benchmark Test (@code{tm27}).
|
|
||||||
|
|
||||||
@item @code{Cause_tm27_intr} - generates the interrupt source
|
|
||||||
used in the Interrupt Benchmark Test (@code{tm27}).
|
|
||||||
|
|
||||||
@item @code{Clear_tm27_intr} - clears the interrupt source
|
|
||||||
used in the Interrupt Benchmark Test (@code{tm27}).
|
|
||||||
|
|
||||||
@item @code{Lower_tm27_intr} - lowers the interrupt mask so the
|
|
||||||
interrupt source used in the Interrupt Benchmark Test (@code{tm27})
|
|
||||||
can generate a nested interrupt.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
All members of the Timing Test Suite are designed to run @b{WITHOUT}
|
|
||||||
the Clock Device Driver installed. This increases the predictability
|
|
||||||
of the tests' execution as well as avoids occassionally including the
|
|
||||||
overhead of a clock tick interrupt in the time reported. Because of
|
|
||||||
this it is sometimes possible to use the clock tick interrupt source
|
|
||||||
as the source of this test interrupt. On other architectures, it is
|
|
||||||
possible to directly force an interrupt to occur.
|
|
||||||
|
|
||||||
@section Calling Overhead File
|
|
||||||
|
|
||||||
The file @code{include/coverhd.h} contains the overhead associated
|
|
||||||
with invoking each directive. This overhead consists of the execution
|
|
||||||
time required to package the parameters as well as to execute the "jump to
|
|
||||||
subroutine" and "return from subroutine" sequence. The intent of this
|
|
||||||
file is to help separate the calling overhead from the actual execution
|
|
||||||
time of a directive. This file is only used by the tests in the
|
|
||||||
RTEMS Timing Test Suite.
|
|
||||||
|
|
||||||
The numbers in this file are obtained by running the "Timer Overhead"
|
|
||||||
@code{tmoverhd} test. The numbers in this file may be 0 and no
|
|
||||||
overhead is subtracted from the directive execution times reported by
|
|
||||||
the Timing Suite.
|
|
||||||
|
|
||||||
There is a shared implementation of @code{coverhd.h} which sets all of
|
|
||||||
the overhead constants to 0. On faster processors, this is usually the
|
|
||||||
best alternative for the BSP as the calling overhead is extremely small.
|
|
||||||
This file is located at:
|
|
||||||
|
|
||||||
@example
|
|
||||||
c/src/lib/libbsp/shared/include/coverhd.h
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@section sbrk() Implementation
|
|
||||||
|
|
||||||
Although nearly all BSPs give all possible memory to the C Program Heap
|
|
||||||
at initialization, it is possible for a BSP to configure the initial
|
|
||||||
size of the heap small and let it grow on demand. If the BSP wants
|
|
||||||
to dynamically extend the heap used by the C Library memory allocation
|
|
||||||
routines (i.e. @code{malloc} family), then the@code{sbrk} routine must
|
|
||||||
be functional. The following is the prototype for this routine:
|
|
||||||
|
|
||||||
@example
|
|
||||||
void * sbrk(size_t increment)
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The @code{increment} amount is based upon the @code{sbrk_amount}
|
|
||||||
parameter passed to the @code{bsp_libc_init} during system initialization.
|
|
||||||
Historically initialization of the C Library was done as part of the
|
|
||||||
BSP's Pretasking Hook but now the BSP Boot Card Framework can perform
|
|
||||||
this operation.
|
|
||||||
|
|
||||||
@findex CONFIGURE_MALLOC_BSP_SUPPORTS_SBRK
|
|
||||||
If your BSP does not want to support dynamic heap extension, then you do not have to do anything special. However, if you want to support @code{sbrk}, you must provide an implementation of this method and define @code{CONFIGURE_MALLOC_BSP_SUPPORTS_SBRK} in @code{bsp.h}. This informs @code{rtems/confdefs.h} to configure the Malloc Family Extensions which support @code{sbrk}.
|
|
||||||
|
|
||||||
@section bsp_fatal_extension() - Cleanup the Hardware
|
|
||||||
|
|
||||||
The @code{bsp_fatal_extension()} is an optional BSP specific initial extension
|
|
||||||
invoked once a fatal system state is reached. Most of the BSPs use the same
|
|
||||||
shared version of @code{bsp_fatal_extension()} that does nothing or performs a
|
|
||||||
system reset. This implementation is located in the following file:
|
|
||||||
|
|
||||||
@example
|
|
||||||
c/src/lib/libbsp/shared/bspclean.c
|
|
||||||
@end example
|
|
||||||
|
|
||||||
The @code{bsp_fatal_extension()} routine can be used to return to a ROM
|
|
||||||
monitor, insure that interrupt sources are disabled, etc.. This routine is the
|
|
||||||
last place to ensure a clean shutdown of the hardware. The fatal source,
|
|
||||||
internal error indicator, and the fatal code arguments are available to
|
|
||||||
evaluate the fatal condition. All of the non-fatal shutdown sequences
|
|
||||||
ultimately pass their exit status to @code{rtems_shutdown_executive} and this
|
|
||||||
is what is passed to this routine in case the fatal source is
|
|
||||||
RTEMS_FATAL_SOURCE_EXIT.
|
|
||||||
|
|
||||||
On some BSPs, it prints a message indicating that the application
|
|
||||||
completed execution and waits for the user to press a key before
|
|
||||||
resetting the board. The PowerPC/gen83xx and PowerPC/gen5200 BSPs do
|
|
||||||
this when they are built to support the FreeScale evaluation boards.
|
|
||||||
This is convenient when using the boards in a development environment
|
|
||||||
and may be disabled for production use.
|
|
||||||
|
|
||||||
@section Configuration Macros
|
|
||||||
|
|
||||||
Each BSP can define macros in bsp.h which alter some of the the default configuration parameters in @code{rtems/confdefs.h}. This section describes those macros:
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@findex CONFIGURE_MALLOC_BSP_SUPPORTS_SBRK
|
|
||||||
@item @code{CONFIGURE_MALLOC_BSP_SUPPORTS_SBRK} must be defined if the
|
|
||||||
BSP has proper support for @code{sbrk}. This is discussed in more detail
|
|
||||||
in the previous section.
|
|
||||||
|
|
||||||
@findex BSP_IDLE_TASK_BODY
|
|
||||||
@item @code{BSP_IDLE_TASK_BODY} may be defined to the entry point of a
|
|
||||||
BSP specific IDLE thread implementation. This may be overridden if the
|
|
||||||
application provides its own IDLE task implementation.
|
|
||||||
|
|
||||||
@findex BSP_IDLE_TASK_STACK_SIZE
|
|
||||||
@item @code{BSP_IDLE_TASK_STACK_SIZE} may be defined to the desired
|
|
||||||
default stack size for the IDLE task as recommended when using this BSP.
|
|
||||||
|
|
||||||
@findex BSP_INTERRUPT_STACK_SIZE
|
|
||||||
@item @code{BSP_INTERRUPT_STACK_SIZE} may be defined to the desired default interrupt stack size as recommended when using this BSP. This is sometimes required when the BSP developer has knowledge of stack intensive interrupt handlers.
|
|
||||||
|
|
||||||
@findex BSP_ZERO_WORKSPACE_AUTOMATICALLY
|
|
||||||
@item @code{BSP_ZERO_WORKSPACE_AUTOMATICALLY} is defined when the BSP
|
|
||||||
requires that RTEMS zero out the RTEMS C Program Heap at initialization.
|
|
||||||
If the memory is already zeroed out by a test sequence or boot ROM,
|
|
||||||
then the boot time can be reduced by not zeroing memory twice.
|
|
||||||
|
|
||||||
@findex BSP_DEFAULT_UNIFIED_WORK_AREAS
|
|
||||||
@item @code{BSP_DEFAULT_UNIFIED_WORK_AREAS} is defined when the BSP
|
|
||||||
recommends that the unified work areas configuration should always
|
|
||||||
be used. This is desirable when the BSP is known to always have very
|
|
||||||
little RAM and thus saving memory by any means is desirable.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@section set_vector() - Install an Interrupt Vector
|
|
||||||
|
|
||||||
On targets with Simple Vectored Interrupts, the BSP must provide
|
|
||||||
an implementation of the @code{set_vector} routine. This routine is
|
|
||||||
responsible for installing an interrupt vector. It invokes the support
|
|
||||||
routines necessary to install an interrupt handler as either a "raw"
|
|
||||||
or an RTEMS interrupt handler. Raw handlers bypass the RTEMS interrupt
|
|
||||||
structure and are responsible for saving and restoring all their own
|
|
||||||
registers. Raw handlers are useful for handling traps, debug vectors,
|
|
||||||
etc..
|
|
||||||
|
|
||||||
The @code{set_vector} routine is a central place to perform interrupt
|
|
||||||
controller manipulation and encapsulate that information. It is usually
|
|
||||||
implemented as follows:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_isr_entry set_vector( /* returns old vector */
|
|
||||||
rtems_isr_entry handler, /* isr routine */
|
|
||||||
rtems_vector_number vector, /* vector number */
|
|
||||||
int type /* RTEMS or RAW intr */
|
|
||||||
)
|
|
||||||
@{
|
|
||||||
if the type is RAW
|
|
||||||
install the raw vector
|
|
||||||
else
|
|
||||||
use rtems_interrupt_catch to install the vector
|
|
||||||
|
|
||||||
perform any interrupt controller necessary to unmask
|
|
||||||
the interrupt source
|
|
||||||
|
|
||||||
return the previous handler
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@b{NOTE:} The i386, PowerPC and ARM ports use a Programmable
|
|
||||||
Interrupt Controller model which does not require the BSP to implement
|
|
||||||
@code{set_vector}. BSPs for these architectures must provide a different
|
|
||||||
set of support routines.
|
|
||||||
|
|
||||||
@section Interrupt Delay Profiling
|
|
||||||
|
|
||||||
The RTEMS profiling needs support by the BSP for the interrupt delay times. In
|
|
||||||
case profiling is enabled via the RTEMS build configuration option
|
|
||||||
@code{--enable-profiling} (in this case the pre-processor symbol
|
|
||||||
@code{RTEMS_PROFILING} is defined) a BSP may provide data for the interrupt
|
|
||||||
delay times. The BSP can feed interrupt delay times with the
|
|
||||||
@code{_Profiling_Update_max_interrupt_delay()} function
|
|
||||||
(@code{#include <rtems/score/profiling.h>}). For an example please have a look
|
|
||||||
at @code{c/src/lib/libbsp/sparc/leon3/clock/ckinit.c}.
|
|
||||||
|
|
||||||
@section Programmable Interrupt Controller API
|
|
||||||
|
|
||||||
A BSP can use the PIC API to install Interrupt Service Routines through
|
|
||||||
a set of generic methods. In order to do so, the header files
|
|
||||||
libbsp/shared/include/irq-generic.h and libbsp/shared/include/irq-info.h
|
|
||||||
must be included by the bsp specific irq.h file present in the include/
|
|
||||||
directory. The irq.h acts as a BSP interrupt support configuration file which
|
|
||||||
is used to define some important MACROS. It contains the declarations for
|
|
||||||
any required global functions like bsp_interrupt_dispatch(). Thus later on,
|
|
||||||
every call to the PIC interface requires including <bsp/irq.h>
|
|
||||||
|
|
||||||
The generic interrupt handler table is intitalized by invoking the
|
|
||||||
@code{bsp_interrupt_initialize()} method from bsp_start() in the bspstart.c
|
|
||||||
file which sets up this table to store the ISR addresses, whose size is based
|
|
||||||
on the definition of macros, BSP_INTERRUPT_VECTOR_MIN & BSP_INTERRUPT_VECTOR_MAX
|
|
||||||
in include/bsp.h
|
|
||||||
|
|
||||||
For the generic handler table to properly function, some bsp specific code is
|
|
||||||
required, that should be present in irq/irq.c . The bsp-specific functions required
|
|
||||||
to be writen by the BSP developer are :
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
|
|
||||||
@findex bsp_interrupt_facility_initialize()
|
|
||||||
@item @code{bsp_interrupt_facility_initialize()} contains bsp specific interrupt
|
|
||||||
initialization code(Clear Pending interrupts by modifying registers, etc.).
|
|
||||||
This method is called from bsp_interrupt_initialize() internally while setting up
|
|
||||||
the table.
|
|
||||||
|
|
||||||
@findex bsp_interrupt_handler_default()
|
|
||||||
@item @code{bsp_interrupt_handler_default()} acts as a fallback handler when
|
|
||||||
no ISR address has been provided corresponding to a vector in the table.
|
|
||||||
|
|
||||||
@findex bsp_interrupt_dispatch()
|
|
||||||
@item @code{bsp_interrupt_dispatch()} service the ISR by handling
|
|
||||||
any bsp specific code & calling the generic method bsp_interrupt_handler_dispatch()
|
|
||||||
which in turn services the interrupt by running the ISR after looking it up in
|
|
||||||
the table. It acts as an entry to the interrupt switchboard, since the bsp
|
|
||||||
branches to this function at the time of occurrence of an interrupt.
|
|
||||||
|
|
||||||
@findex bsp_interrupt_vector_enable()
|
|
||||||
@item @code{bsp_interrupt_vector_enable()} enables interrupts and is called in
|
|
||||||
irq-generic.c while setting up the table.
|
|
||||||
|
|
||||||
@findex bsp_interrupt_vector_disable()
|
|
||||||
@item @code{bsp_interrupt_vector_disable()} disables interrupts and is called in
|
|
||||||
irq-generic.c while setting up the table & during other important parts.
|
|
||||||
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
An interrupt handler is installed or removed with the help of the following functions :
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
rtems_status_code rtems_interrupt_handler_install( /* returns status code */
|
|
||||||
rtems_vector_number vector, /* interrupt vector */
|
|
||||||
const char *info, /* custom identification text */
|
|
||||||
rtems_option options, /* Type of Interrupt */
|
|
||||||
rtems_interrupt_handler handler, /* interrupt handler */
|
|
||||||
void *arg /* parameter to be passed to handler at the time of invocation */
|
|
||||||
)
|
|
||||||
|
|
||||||
rtems_status_code rtems_interrupt_handler_remove( /* returns status code */
|
|
||||||
rtems_vector_number vector, /* interrupt vector */
|
|
||||||
rtems_interrupt_handler handler, /* interrupt handler */
|
|
||||||
void *arg /* parameter to be passed to handler */
|
|
||||||
)
|
|
||||||
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user