forked from Imagelibrary/rtems
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7093cb5e5d | ||
|
|
5812a26eeb | ||
|
|
dc746b50ca | ||
|
|
a346408e4e | ||
|
|
a2a9751823 | ||
|
|
1a304307a2 | ||
|
|
d438427cbe | ||
|
|
004a63efef | ||
|
|
c139a70597 | ||
|
|
1a21831b3c | ||
|
|
8ca15e26ba | ||
|
|
a3199d91f3 | ||
|
|
a76c31e13d | ||
|
|
e1c3dc0909 | ||
|
|
2ed53cb982 | ||
|
|
89fd08eae6 | ||
|
|
492c95eee6 | ||
|
|
7d097c5c69 | ||
|
|
5cc276e7c1 | ||
|
|
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
|
||||
|
||||
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)`; \
|
||||
for i in $$files; do \
|
||||
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)/excludes \
|
||||
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 \
|
||||
-f rtems-$(rtems_version)$(TAG_SUFFIX).tar.bz2 rtems-$(rtems_version)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
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])
|
||||
|
||||
@@ -223,7 +223,6 @@ clean)
|
||||
needles="$needles install-sh"
|
||||
needles="$needles missing"
|
||||
needles="$needles mdate-sh"
|
||||
needles="$needles texinfo.tex"
|
||||
fi
|
||||
for j in $needles; do
|
||||
files=`find . -name "$j" -print`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
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])
|
||||
|
||||
@@ -43,7 +43,7 @@ extern "C" {
|
||||
#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_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)
|
||||
{
|
||||
|
||||
@@ -246,7 +246,7 @@ static void greth_interrupt (void *arg)
|
||||
|
||||
/* Send the event(s) */
|
||||
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)
|
||||
|
||||
@@ -30,10 +30,6 @@ RTEMS_ENABLE_MULTILIB
|
||||
RTEMS_ENABLE_PARAVIRT
|
||||
RTEMS_ENABLE_DRVMGR
|
||||
|
||||
AC_ARG_ENABLE([docs],
|
||||
[AS_HELP_STRING([--enable-docs],[enable building documentation
|
||||
(default:disabled)])])
|
||||
|
||||
## NOTES:
|
||||
## * tools/build are host-native tools to be installed on the host.
|
||||
## * 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])
|
||||
])
|
||||
|
||||
AS_IF([test x"${enable_docs}" = x"yes"],
|
||||
[RTEMS_BUILD_CONFIG_SUBDIRS([doc])])
|
||||
|
||||
AS_IF([test x"$enable_multilib" = x"yes"],[
|
||||
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-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-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
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
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])
|
||||
|
||||
@@ -39,7 +39,7 @@ typedef struct {
|
||||
uint32_t size;
|
||||
uint16_t i2c_address_mask;
|
||||
uint16_t i2c_address_shift;
|
||||
rtems_interval program_timeout;
|
||||
rtems_interval program_timeout_in_ticks;
|
||||
} eeprom;
|
||||
|
||||
static uint16_t eeprom_i2c_addr(eeprom *dev, uint32_t off)
|
||||
@@ -48,6 +48,23 @@ static uint16_t eeprom_i2c_addr(eeprom *dev, uint32_t off)
|
||||
| ((off >> dev->i2c_address_shift) & dev->i2c_address_mask);
|
||||
}
|
||||
|
||||
static void eeprom_set_addr(
|
||||
const eeprom *dev,
|
||||
uint32_t off,
|
||||
uint8_t addr[EEPROM_MAX_ADDRESS_BYTES]
|
||||
)
|
||||
{
|
||||
int shift = 24 - (4 - dev->address_bytes) * 8;
|
||||
|
||||
addr[0] = (uint8_t) (off >> shift);
|
||||
shift -= 8;
|
||||
addr[1] = (uint8_t) (off >> shift);
|
||||
shift -= 8;
|
||||
addr[2] = (uint8_t) (off >> shift);
|
||||
shift -= 8;
|
||||
addr[3] = (uint8_t) (off >> shift);
|
||||
}
|
||||
|
||||
static ssize_t eeprom_read(
|
||||
i2c_dev *base,
|
||||
void *buf,
|
||||
@@ -80,12 +97,7 @@ static ssize_t eeprom_read(
|
||||
*/
|
||||
uint16_t cur = (uint16_t) (todo < 255 ? todo : 255);
|
||||
|
||||
uint8_t addr[EEPROM_MAX_ADDRESS_BYTES] = {
|
||||
(uint8_t) off,
|
||||
(uint8_t) (off >> 8),
|
||||
(uint8_t) (off >> 16),
|
||||
(uint8_t) (off >> 24)
|
||||
};
|
||||
uint8_t addr[EEPROM_MAX_ADDRESS_BYTES];
|
||||
i2c_msg msgs[2] = {
|
||||
{
|
||||
.addr = i2c_addr,
|
||||
@@ -101,6 +113,7 @@ static ssize_t eeprom_read(
|
||||
};
|
||||
int err;
|
||||
|
||||
eeprom_set_addr(dev, off, addr);
|
||||
err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
|
||||
if (err != 0) {
|
||||
return err;
|
||||
@@ -141,12 +154,7 @@ static ssize_t eeprom_write(
|
||||
uint16_t i2c_addr = eeprom_i2c_addr(dev, off);
|
||||
uint16_t rem = dev->page_size - (off & (dev->page_size - 1));
|
||||
uint16_t cur = (uint16_t) (todo < rem ? todo : rem);
|
||||
uint8_t addr[EEPROM_MAX_ADDRESS_BYTES] = {
|
||||
(uint8_t) off,
|
||||
(uint8_t) (off >> 8),
|
||||
(uint8_t) (off >> 16),
|
||||
(uint8_t) (off >> 24)
|
||||
};
|
||||
uint8_t addr[EEPROM_MAX_ADDRESS_BYTES];
|
||||
i2c_msg msgs[2] = {
|
||||
{
|
||||
.addr = i2c_addr,
|
||||
@@ -164,17 +172,24 @@ static ssize_t eeprom_write(
|
||||
int err;
|
||||
ssize_t m;
|
||||
rtems_interval timeout;
|
||||
bool before;
|
||||
|
||||
eeprom_set_addr(dev, off, addr);
|
||||
err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs));
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
timeout = rtems_clock_tick_later(dev->program_timeout);
|
||||
timeout = rtems_clock_tick_later(dev->program_timeout_in_ticks);
|
||||
|
||||
do {
|
||||
before = rtems_clock_tick_before(timeout);
|
||||
|
||||
m = eeprom_read(&dev->base, &in[0], cur, off);
|
||||
} while (m != cur && rtems_clock_tick_before(timeout));
|
||||
if (m == cur) {
|
||||
break;
|
||||
}
|
||||
} while (before);
|
||||
|
||||
if (m != cur) {
|
||||
return -ETIMEDOUT;
|
||||
@@ -217,6 +232,7 @@ int i2c_dev_register_eeprom(
|
||||
)
|
||||
{
|
||||
uint32_t extra_address;
|
||||
uint32_t ms_per_tick;
|
||||
eeprom *dev;
|
||||
|
||||
if (address_bytes > EEPROM_MAX_ADDRESS_BYTES) {
|
||||
@@ -252,7 +268,9 @@ int i2c_dev_register_eeprom(
|
||||
dev->address_bytes = address_bytes;
|
||||
dev->page_size = page_size_in_bytes;
|
||||
dev->size = size_in_bytes;
|
||||
dev->program_timeout = RTEMS_MILLISECONDS_TO_TICKS(program_timeout_in_ms);
|
||||
ms_per_tick = rtems_configuration_get_milliseconds_per_tick();
|
||||
dev->program_timeout_in_ticks = (program_timeout_in_ms + ms_per_tick - 1)
|
||||
/ ms_per_tick + 1;
|
||||
|
||||
if (extra_address != 0) {
|
||||
dev->i2c_address_mask = extra_address - 1;
|
||||
|
||||
@@ -507,11 +507,14 @@ rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain(
|
||||
* 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] deferred If true, then do a deferred release, otherwise release
|
||||
* it immediately.
|
||||
*
|
||||
* @see rtems_filesystem_global_location_obtain().
|
||||
*/
|
||||
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(
|
||||
|
||||
@@ -39,7 +39,7 @@ int rtems_filesystem_chdir( rtems_filesystem_location_info_t *loc )
|
||||
);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ int chroot( const char *path )
|
||||
}
|
||||
|
||||
if ( rv != 0 ) {
|
||||
rtems_filesystem_global_location_release( new_root_loc );
|
||||
rtems_filesystem_global_location_release( new_root_loc, true );
|
||||
}
|
||||
} else {
|
||||
rv = -1;
|
||||
@@ -89,7 +89,7 @@ int chroot( const char *path )
|
||||
rtems_filesystem_eval_path_cleanup( &ctx );
|
||||
|
||||
if ( rv != 0 ) {
|
||||
rtems_filesystem_global_location_release( new_current_loc );
|
||||
rtems_filesystem_global_location_release( new_current_loc, false );
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
||||
@@ -126,7 +126,7 @@ static int register_subordinate_file_system(
|
||||
);
|
||||
rtems_filesystem_mt_unlock();
|
||||
} else {
|
||||
rtems_filesystem_global_location_release( mt_point_node );
|
||||
rtems_filesystem_global_location_release( mt_point_node, true );
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
|
||||
if (!uses_global_env) {
|
||||
rtems_filesystem_global_location_release(env->current_directory);
|
||||
rtems_filesystem_global_location_release(env->root_directory);
|
||||
rtems_filesystem_global_location_release(env->current_directory, false);
|
||||
rtems_filesystem_global_location_release(env->root_directory, false);
|
||||
free(env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,8 +301,8 @@ void rtems_filesystem_eval_path_cleanup(
|
||||
{
|
||||
free_location(&ctx->currentloc);
|
||||
rtems_filesystem_instance_unlock(&ctx->startloc->location);
|
||||
rtems_filesystem_global_location_release(ctx->startloc);
|
||||
rtems_filesystem_global_location_release(ctx->rootloc);
|
||||
rtems_filesystem_global_location_release(ctx->startloc, false);
|
||||
rtems_filesystem_global_location_release(ctx->rootloc, false);
|
||||
}
|
||||
|
||||
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;
|
||||
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(
|
||||
@@ -183,10 +183,11 @@ rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain(
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
@@ -232,7 +233,7 @@ void rtems_filesystem_do_unmount(
|
||||
rtems_filesystem_mt_lock();
|
||||
rtems_chain_extract_unprotected(&mt_entry->mt_node);
|
||||
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);
|
||||
|
||||
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
|
||||
*/
|
||||
static rtems_status_code
|
||||
static void
|
||||
fillBufferPoll (struct rtems_termios_tty *tty)
|
||||
{
|
||||
int n;
|
||||
@@ -1449,23 +1449,27 @@ fillBufferPoll (struct rtems_termios_tty *tty)
|
||||
}
|
||||
}
|
||||
}
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill the input buffer from the raw input queue
|
||||
*/
|
||||
static rtems_status_code
|
||||
static void
|
||||
fillBufferQueue (struct rtems_termios_tty *tty)
|
||||
{
|
||||
rtems_termios_device_context *ctx = tty->device_context;
|
||||
rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
|
||||
rtems_status_code sc;
|
||||
int wait = 1;
|
||||
bool wait = true;
|
||||
|
||||
while ( wait ) {
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
/*
|
||||
* Process characters read from raw queue
|
||||
*/
|
||||
|
||||
rtems_termios_device_lock_acquire (ctx, &lock_context);
|
||||
|
||||
while ((tty->rawInBuf.Head != tty->rawInBuf.Tail) &&
|
||||
(tty->ccount < (CBUFSIZE-1))) {
|
||||
unsigned char c;
|
||||
@@ -1474,6 +1478,7 @@ fillBufferQueue (struct rtems_termios_tty *tty)
|
||||
newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
|
||||
c = tty->rawInBuf.theBuf[newHead];
|
||||
tty->rawInBuf.Head = newHead;
|
||||
|
||||
if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
|
||||
% tty->rawInBuf.Size)
|
||||
< tty->lowwater) {
|
||||
@@ -1495,29 +1500,40 @@ fillBufferQueue (struct rtems_termios_tty *tty)
|
||||
}
|
||||
}
|
||||
|
||||
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||
|
||||
/* continue processing new character */
|
||||
if (tty->termios.c_lflag & ICANON) {
|
||||
if (siproc (c, tty))
|
||||
wait = 0;
|
||||
wait = false;
|
||||
} else {
|
||||
siproc (c, tty);
|
||||
if (tty->ccount >= tty->termios.c_cc[VMIN])
|
||||
wait = 0;
|
||||
wait = false;
|
||||
}
|
||||
timeout = tty->rawInBufSemaphoreTimeout;
|
||||
|
||||
rtems_termios_device_lock_acquire (ctx, &lock_context);
|
||||
}
|
||||
|
||||
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||
|
||||
/*
|
||||
* Wait for characters
|
||||
*/
|
||||
if ( wait ) {
|
||||
sc = rtems_semaphore_obtain(
|
||||
tty->rawInBuf.Semaphore, tty->rawInBufSemaphoreOptions, timeout);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
if (wait) {
|
||||
if (tty->ccount < CBUFSIZE - 1) {
|
||||
rtems_status_code sc;
|
||||
|
||||
sc = rtems_semaphore_obtain(
|
||||
tty->rawInBuf.Semaphore, tty->rawInBufSemaphoreOptions, timeout);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
rtems_status_code
|
||||
@@ -1544,12 +1560,9 @@ rtems_termios_read (void *arg)
|
||||
tty->cindex = tty->ccount = 0;
|
||||
tty->read_start_column = tty->column;
|
||||
if (tty->handler.poll_read != NULL && tty->handler.mode == TERMIOS_POLLED)
|
||||
sc = fillBufferPoll (tty);
|
||||
fillBufferPoll (tty);
|
||||
else
|
||||
sc = fillBufferQueue (tty);
|
||||
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
tty->cindex = tty->ccount = 0;
|
||||
fillBufferQueue (tty);
|
||||
}
|
||||
while (count && (tty->cindex < tty->ccount)) {
|
||||
*buffer++ = tty->cbuf[tty->cindex++];
|
||||
@@ -1584,7 +1597,6 @@ int
|
||||
rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
|
||||
{
|
||||
struct rtems_termios_tty *tty = ttyp;
|
||||
unsigned int newTail;
|
||||
char c;
|
||||
int dropped = 0;
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
|
||||
/* if chars_in_buffer > highwater */
|
||||
unsigned int head;
|
||||
unsigned int oldTail;
|
||||
unsigned int newTail;
|
||||
|
||||
rtems_termios_device_lock_acquire (ctx, &lock_context);
|
||||
if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
|
||||
% tty->rawInBuf.Size) > tty->highwater) &&
|
||||
!(tty->flow_ctrl & FL_IREQXOF)) {
|
||||
|
||||
head = tty->rawInBuf.Head;
|
||||
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 */
|
||||
tty->flow_ctrl |= FL_IREQXOF;
|
||||
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 */
|
||||
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||
|
||||
if (newTail == tty->rawInBuf.Head) {
|
||||
dropped++;
|
||||
} else {
|
||||
if (newTail != head) {
|
||||
tty->rawInBuf.theBuf[newTail] = c;
|
||||
tty->rawInBuf.Tail = newTail;
|
||||
|
||||
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||
|
||||
/*
|
||||
* 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_rcvwakeup = 1;
|
||||
}
|
||||
} else {
|
||||
++dropped;
|
||||
rtems_termios_device_lock_release (ctx, &lock_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ libdl_a_SOURCES = \
|
||||
rtl-string.c \
|
||||
rtl-sym.c \
|
||||
rtl-trace.c \
|
||||
rtl-unwind-dw2.c \
|
||||
rtl-unresolved.c
|
||||
|
||||
libdl_a_SOURCES += rtl-mdreloc-@RTEMS_CPU@.c
|
||||
|
||||
@@ -38,7 +38,8 @@ convert_ascii_to_voidp (const char* arg)
|
||||
int
|
||||
shell_dlopen (int argc, char* argv[])
|
||||
{
|
||||
int arg;
|
||||
int arg;
|
||||
char *err;
|
||||
for (arg = 1; arg < argc; arg++)
|
||||
{
|
||||
void* handle = dlopen (argv[arg], RTLD_NOW | RTLD_GLOBAL);
|
||||
@@ -53,7 +54,10 @@ shell_dlopen (int argc, char* argv[])
|
||||
printf ("handle: %p %s\n", handle, message);
|
||||
}
|
||||
else
|
||||
printf ("error: %s\n", dlerror ());
|
||||
{
|
||||
err = dlerror ();
|
||||
printf ("error: %s\n", err ? err : "");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
#include <rtems/rtl/rtl.h>
|
||||
#include "rtl-error.h"
|
||||
|
||||
static rtems_rtl_obj_t*
|
||||
dl_get_obj_from_handle (void* handle)
|
||||
@@ -125,12 +126,15 @@ dlsym (void* handle, const char *symbol)
|
||||
return symval;
|
||||
}
|
||||
|
||||
const char*
|
||||
char*
|
||||
dlerror (void)
|
||||
{
|
||||
static char msg[64];
|
||||
rtems_rtl_get_error (msg, sizeof (msg));
|
||||
return msg;
|
||||
rtems_rtl_clear_error ();
|
||||
if (msg[0] == '\0')
|
||||
return NULL;
|
||||
return msg;
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -56,7 +56,7 @@ int dladdr(void * __restrict, Dl_info * __restrict);
|
||||
int dlctl(void *, int, void *);
|
||||
#endif
|
||||
int dlinfo(void *, int, void *);
|
||||
const char *dlerror(void);
|
||||
char *dlerror(void);
|
||||
__END_DECLS
|
||||
|
||||
/* Values for dlopen `mode'. */
|
||||
|
||||
@@ -80,7 +80,8 @@
|
||||
#define R_ARM_ALU_SBREL_19_12 36
|
||||
#define R_ARM_ALU_SBREL_27_20 37
|
||||
#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_MOVT_ABS 44
|
||||
|
||||
@@ -459,6 +459,10 @@ typedef struct {
|
||||
#define SHF_WRITE 0x1 /* Section contains writable data */
|
||||
#define SHF_ALLOC 0x2 /* Section occupies memory */
|
||||
#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_MASKPROC 0xf0000000 /* Processor-specific values */
|
||||
@@ -949,13 +953,13 @@ typedef struct {
|
||||
#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_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_WEAK 0x2
|
||||
@@ -967,7 +971,7 @@ typedef struct {
|
||||
#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_CURRENT 1
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -152,6 +152,7 @@ rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag,
|
||||
bool
|
||||
rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
||||
void** const_base, size_t const_size,
|
||||
void** eh_base, size_t eh_size,
|
||||
void** data_base, size_t data_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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -184,7 +198,8 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
||||
data_size, false);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -195,7 +210,8 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
||||
bss_size, false);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -206,12 +222,14 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
|
||||
void
|
||||
rtems_rtl_alloc_module_del (void** text_base,
|
||||
void** const_base,
|
||||
void** eh_base,
|
||||
void** data_base,
|
||||
void** 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, *eh_base);
|
||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *const_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 const_base Pointer to the const base pointer.
|
||||
* @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_size The size of the read/write secton.
|
||||
* @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,
|
||||
void** const_base, size_t const_size,
|
||||
void** eh_base, size_t eh_size,
|
||||
void** data_base, size_t data_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 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 bss_base Pointer to the bss base pointer.
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@ _rtld_debug_state (void)
|
||||
int
|
||||
_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;
|
||||
uint32_t obj_num = obj->obj_num;
|
||||
int i;
|
||||
uint32_t obj_num = obj->obj_num;
|
||||
int i;
|
||||
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||
printf ("rtl: linkmap_add\n");
|
||||
@@ -78,8 +78,10 @@ _rtld_linkmap_add (rtems_rtl_obj_t* obj)
|
||||
void
|
||||
_rtld_linkmap_delete (rtems_rtl_obj_t* obj)
|
||||
{
|
||||
struct link_map* l = (struct link_map*)obj->detail;
|
||||
/* link_maps are allocated together if not 1 */
|
||||
struct link_map* l = obj->linkmap;
|
||||
/*
|
||||
* link_maps are allocated together if not 1
|
||||
*/
|
||||
struct link_map* e = l + obj->obj_num - 1;
|
||||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((l->l_prev->l_next = e->l_next) != NULL)
|
||||
e->l_next->l_prev = l->l_prev;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "rtl-elf.h"
|
||||
#include "rtl-error.h"
|
||||
#include "rtl-trace.h"
|
||||
#include "rtl-unwind.h"
|
||||
#include "rtl-unresolved.h"
|
||||
|
||||
/**
|
||||
@@ -169,6 +170,9 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
|
||||
&relbuf[0], reloc_size))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Read the symbol details.
|
||||
*/
|
||||
if (is_rela)
|
||||
off = (obj->ooffset + symsect->offset +
|
||||
(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 (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,
|
||||
(int) ELF_R_TYPE (rela->r_info), rela->r_offset, (int) rela->r_addend);
|
||||
if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
|
||||
@@ -256,7 +260,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
|
||||
else
|
||||
{
|
||||
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,
|
||||
(int) ELF_R_TYPE (rel->r_info), rel->r_offset);
|
||||
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_addend = reloc->rel[REL_R_ADDEND];
|
||||
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),
|
||||
rela.r_offset, (int) rela.r_addend);
|
||||
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_info = reloc->rel[REL_R_INFO];
|
||||
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),
|
||||
rel.r_offset);
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
case SHT_NULL:
|
||||
@@ -707,9 +716,16 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
||||
break;
|
||||
|
||||
default:
|
||||
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);
|
||||
/*
|
||||
* See if there are architecture specific 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;
|
||||
}
|
||||
|
||||
@@ -718,6 +734,13 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
|
||||
char* name;
|
||||
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;
|
||||
if (!rtems_rtl_obj_cache_read (strings, fd,
|
||||
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)
|
||||
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,
|
||||
shdr.sh_size, shdr.sh_offset,
|
||||
shdr.sh_addralign, shdr.sh_link,
|
||||
@@ -771,16 +800,19 @@ rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd)
|
||||
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_node* node = NULL;
|
||||
size_t mask = 0;
|
||||
struct link_map* l = NULL;
|
||||
int sec_num = 0;
|
||||
section_detail* sd;
|
||||
int i = 0;
|
||||
|
||||
/* caculate the size of sections' name. */
|
||||
/*
|
||||
* Caculate the size of sections' name.
|
||||
*/
|
||||
|
||||
for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
|
||||
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))
|
||||
{
|
||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||
|
||||
if ((sect->size != 0) && ((sect->flags & mask) != 0))
|
||||
{
|
||||
++sec_num;
|
||||
@@ -801,32 +832,31 @@ bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj)
|
||||
}
|
||||
|
||||
obj->obj_num = 1;
|
||||
obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||
sizeof(struct link_map) +
|
||||
sec_num * sizeof (section_detail), true);
|
||||
if (!obj->detail)
|
||||
obj->linkmap = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||
sizeof(struct link_map) +
|
||||
sec_num * sizeof (section_detail), true);
|
||||
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;
|
||||
}
|
||||
|
||||
l = (struct link_map*) obj->detail;
|
||||
l->name = obj->oname;
|
||||
l->sec_num = sec_num;
|
||||
l->sec_detail = (section_detail*) (l + 1);
|
||||
l->rpathlen = 0;
|
||||
l->rpath = NULL;
|
||||
l->l_next = NULL;
|
||||
l->l_prev = NULL;
|
||||
l->sec_addr[rap_text] = obj->text_base;
|
||||
l->sec_addr[rap_const] = obj->const_base;
|
||||
l->sec_addr[rap_data] = obj->data_base;
|
||||
l->sec_addr[rap_bss] = obj->bss_base;
|
||||
obj->linkmap->name = obj->oname;
|
||||
obj->linkmap->sec_num = sec_num;
|
||||
obj->linkmap->sec_detail = (section_detail*) (obj->linkmap + 1);
|
||||
obj->linkmap->rpathlen = 0;
|
||||
obj->linkmap->rpath = NULL;
|
||||
obj->linkmap->l_next = NULL;
|
||||
obj->linkmap->l_prev = NULL;
|
||||
obj->linkmap->sec_addr[rap_text] = obj->text_base;
|
||||
obj->linkmap->sec_addr[rap_const] = obj->const_base;
|
||||
obj->linkmap->sec_addr[rap_data] = obj->data_base;
|
||||
obj->linkmap->sec_addr[rap_bss] = obj->bss_base;
|
||||
|
||||
|
||||
section_detail* sd = l->sec_detail;
|
||||
sd = obj->linkmap->sec_detail;
|
||||
sections = &obj->sections;
|
||||
node = rtems_chain_first (sections);
|
||||
|
||||
for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
|
||||
mask <= RTEMS_RTL_OBJ_SECT_BSS;
|
||||
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);
|
||||
|
||||
if (!rtems_rtl_elf_load_details (obj))
|
||||
if (!rtems_rtl_elf_load_linkmap (obj))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,18 @@ extern "C" {
|
||||
*/
|
||||
#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
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -39,9 +40,27 @@ int
|
||||
rtems_rtl_get_error (char* message, size_t max_message)
|
||||
{
|
||||
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
||||
int last_errno = rtl->last_errno;
|
||||
strncpy (message, rtl->last_error, sizeof (rtl->last_error));
|
||||
rtems_rtl_unlock ();
|
||||
return last_errno;
|
||||
if (rtl != NULL)
|
||||
{
|
||||
int last_errno = rtl->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;
|
||||
}
|
||||
|
||||
void
|
||||
rtems_rtl_clear_error (void)
|
||||
{
|
||||
rtems_rtl_data_t* rtl = rtems_rtl_lock ();
|
||||
if (rtl != NULL)
|
||||
{
|
||||
rtl->last_errno = 0;
|
||||
rtl->last_error[0] = '\0';
|
||||
rtems_rtl_unlock ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,11 @@ extern "C" {
|
||||
*/
|
||||
void rtems_rtl_set_error (int error, const char* format, ...) RTEMS_RTL_PRINTF_ATTR;
|
||||
|
||||
/**
|
||||
* Clears the error.
|
||||
*/
|
||||
void rtems_rtl_clear_error (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -10,11 +10,14 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unwind.h>
|
||||
#include <unwind-arm-common.h>
|
||||
|
||||
#include <rtems/rtl/rtl.h>
|
||||
#include "rtl-elf.h"
|
||||
#include "rtl-error.h"
|
||||
#include "rtl-trace.h"
|
||||
#include "rtl-unwind.h"
|
||||
|
||||
/*
|
||||
* It is possible for the compiler to emit relocations for unaligned data.
|
||||
@@ -23,6 +26,8 @@
|
||||
#define RELOC_ALIGNED_P(x) \
|
||||
(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
|
||||
|
||||
#define SHT_ARM_EXIDX 0x70000001 /* Section holds ARM unwind info. */
|
||||
|
||||
static inline Elf_Addr
|
||||
load_ptr(void *where)
|
||||
{
|
||||
@@ -52,6 +57,24 @@ isThumb(Elf_Word symvalue)
|
||||
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
|
||||
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);
|
||||
|
||||
switch (ELF_R_TYPE(rel->r_info)) {
|
||||
case R_TYPE(NONE):
|
||||
break;
|
||||
case R_TYPE(NONE):
|
||||
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(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(ABS32): /* 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))) {
|
||||
tmp = *where + symvalue;
|
||||
if (isThumb(symvalue))
|
||||
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;
|
||||
else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
|
||||
tmp = sign_extend31(tmp - (Elf_Addr)where);
|
||||
*where = tmp;
|
||||
} else {
|
||||
tmp = load_ptr(where) + symvalue;
|
||||
if (isThumb(symvalue))
|
||||
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;
|
||||
else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
|
||||
tmp = sign_extend31(tmp - (Elf_Addr)where);
|
||||
store_ptr(where, tmp);
|
||||
}
|
||||
|
||||
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));
|
||||
break;
|
||||
|
||||
@@ -306,7 +340,7 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
|
||||
(void *)*where, where, rtems_rtl_obj_oname (obj));
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
|
||||
"contents = %p\n",
|
||||
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 "
|
||||
"in non-PLT relocations",
|
||||
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-error.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
|
||||
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");
|
||||
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-error.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
|
||||
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");
|
||||
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-error.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
|
||||
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;
|
||||
}
|
||||
|
||||
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-error.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
|
||||
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");
|
||||
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-error.h"
|
||||
#include "rtl-trace.h"
|
||||
#include "rtl-unwind.h"
|
||||
#include "rtl-unwind-dw2.h"
|
||||
|
||||
static inline int overflow_8_check(int value)
|
||||
{
|
||||
@@ -30,6 +32,13 @@ static inline int overflow_16_check(int value)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||
const Elf_Shdr* shdr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
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");
|
||||
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-error.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
|
||||
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;
|
||||
}
|
||||
|
||||
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-error.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
|
||||
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");
|
||||
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-error.h"
|
||||
#include "rtl-trace.h"
|
||||
#include "rtl-unwind.h"
|
||||
#include "rtl-unwind-dw2.h"
|
||||
|
||||
#define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
|
||||
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
|
||||
#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
|
||||
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));
|
||||
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:
|
||||
printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
|
||||
"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");
|
||||
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-error.h"
|
||||
#include "rtl-trace.h"
|
||||
#include "rtl-unwind.h"
|
||||
#include "rtl-unwind-dw2.h"
|
||||
|
||||
/*
|
||||
* 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])
|
||||
|
||||
uint32_t
|
||||
rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
|
||||
const Elf_Shdr* shdr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
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_Word type, value, mask;
|
||||
Elf_Addr tmp = 0;
|
||||
|
||||
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;
|
||||
|
||||
if (RELOC_UNALIGNED(type)) {
|
||||
/* Handle unaligned relocations. */
|
||||
Elf_Addr tmp = 0;
|
||||
char *ptr = (char *)where;
|
||||
/*
|
||||
* Handle unaligned relocations.
|
||||
*/
|
||||
char *ptr = (char*) where;
|
||||
int i, size = RELOC_TARGET_SIZE (type) / 8;
|
||||
|
||||
/* 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 &= ~mask;
|
||||
tmp |= value;
|
||||
|
||||
/* Write it back out. */
|
||||
for (i=0; i<size; i++)
|
||||
ptr[i] = ((tmp >> (8*i)) & 0xff);
|
||||
|
||||
for (i = size - 1; i >= 0; i--, tmp >>= 8)
|
||||
ptr[i] = tmp & 0xff;
|
||||
} else {
|
||||
*where &= ~mask;
|
||||
*where |= value;
|
||||
tmp = *where;
|
||||
}
|
||||
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
|
||||
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;
|
||||
}
|
||||
@@ -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");
|
||||
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-error.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
|
||||
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");
|
||||
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.
|
||||
*/
|
||||
static rtems_rtl_loader_table_t loaders[RTEMS_RTL_ELF_LOADER_COUNT +
|
||||
RTEMS_RTL_RAP_LOADER_COUNT] =
|
||||
#define RTEMS_RTL_LOADERS (RTEMS_RTL_ELF_LOADER_COUNT + RTEMS_RTL_RAP_LOADER_COUNT)
|
||||
static const rtems_rtl_loader_table_t loaders[RTEMS_RTL_LOADERS] =
|
||||
{
|
||||
#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
|
||||
#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
|
||||
};
|
||||
|
||||
@@ -72,6 +79,10 @@ rtems_rtl_obj_alloc (void)
|
||||
* Initialise the chains.
|
||||
*/
|
||||
rtems_chain_initialize_empty (&obj->sections);
|
||||
/*
|
||||
* No valid format.
|
||||
*/
|
||||
obj->format = -1;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@@ -97,14 +108,14 @@ rtems_rtl_obj_free (rtems_rtl_obj_t* obj)
|
||||
}
|
||||
if (!rtems_chain_is_node_off_chain (&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);
|
||||
rtems_rtl_symbol_obj_erase (obj);
|
||||
rtems_rtl_obj_free_names (obj);
|
||||
if (obj->sec_num)
|
||||
free (obj->sec_num);
|
||||
if (obj->detail)
|
||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*)obj->detail);
|
||||
if (obj->linkmap)
|
||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->linkmap);
|
||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
|
||||
return true;
|
||||
}
|
||||
@@ -238,7 +249,7 @@ rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
|
||||
static size_t
|
||||
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);
|
||||
return offset;
|
||||
}
|
||||
@@ -264,12 +275,12 @@ rtems_rtl_obj_sect_summer (rtems_chain_node* node, void* data)
|
||||
}
|
||||
|
||||
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;
|
||||
summer.mask = mask;
|
||||
summer.size = 0;
|
||||
rtems_rtl_chain_iterate (&obj->sections,
|
||||
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
|
||||
rtems_rtl_obj_sect_summer,
|
||||
&summer);
|
||||
return summer.size;
|
||||
@@ -302,12 +313,12 @@ rtems_rtl_obj_sect_aligner (rtems_chain_node* node, void* data)
|
||||
}
|
||||
|
||||
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;
|
||||
aligner.mask = mask;
|
||||
aligner.alignment = 0;
|
||||
rtems_rtl_chain_iterate (&obj->sections,
|
||||
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
|
||||
rtems_rtl_obj_sect_aligner,
|
||||
&aligner);
|
||||
return aligner.alignment;
|
||||
@@ -401,26 +412,30 @@ rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj,
|
||||
int info,
|
||||
uint32_t flags)
|
||||
{
|
||||
rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||
sizeof (rtems_rtl_obj_sect_t), true);
|
||||
if (!sect)
|
||||
if (size > 0)
|
||||
{
|
||||
rtems_rtl_set_error (ENOMEM, "adding allocated section");
|
||||
return false;
|
||||
}
|
||||
sect->section = section;
|
||||
sect->name = rtems_rtl_strdup (name);
|
||||
sect->size = size;
|
||||
sect->offset = offset;
|
||||
sect->alignment = alignment;
|
||||
sect->link = link;
|
||||
sect->info = info;
|
||||
sect->flags = flags;
|
||||
sect->base = NULL;
|
||||
rtems_chain_append (&obj->sections, §->node);
|
||||
rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||
sizeof (rtems_rtl_obj_sect_t),
|
||||
true);
|
||||
if (!sect)
|
||||
{
|
||||
rtems_rtl_set_error (ENOMEM, "adding allocated section");
|
||||
return false;
|
||||
}
|
||||
sect->section = section;
|
||||
sect->name = rtems_rtl_strdup (name);
|
||||
sect->size = size;
|
||||
sect->offset = offset;
|
||||
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))
|
||||
printf ("rtl: sect: %-2d: %s\n", section, name);
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
|
||||
printf ("rtl: sect: %-2d: %s (%zu)\n", section, name, size);
|
||||
}
|
||||
|
||||
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_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;
|
||||
match.sect = NULL;
|
||||
match.name = name;
|
||||
rtems_rtl_chain_iterate (&obj->sections,
|
||||
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
|
||||
rtems_rtl_obj_sect_match_name,
|
||||
&match);
|
||||
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_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;
|
||||
match.sect = NULL;
|
||||
match.index = index;
|
||||
rtems_rtl_chain_iterate (&obj->sections,
|
||||
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
|
||||
rtems_rtl_obj_sect_match_index,
|
||||
&match);
|
||||
return match.sect;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -572,21 +601,25 @@ typedef struct
|
||||
static bool
|
||||
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;
|
||||
uintptr_t old_end;
|
||||
uintptr_t new_start;
|
||||
uintptr_t old_end;
|
||||
uintptr_t new_start;
|
||||
|
||||
if ( !(sect->flags & sync_ctx->mask) || !sect->size)
|
||||
if ((sect->flags & sync_ctx->mask) == 0 || sect->size == 0)
|
||||
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;
|
||||
} else {
|
||||
old_end = (uintptr_t)sync_ctx->end_va & ~(sync_ctx->cache_line_size - 1);
|
||||
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) ) {
|
||||
}
|
||||
else
|
||||
{
|
||||
old_end = (uintptr_t) sync_ctx->end_va & ~(sync_ctx->cache_line_size - 1);
|
||||
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,
|
||||
sync_ctx->end_va - sync_ctx->start_va + 1);
|
||||
sync_ctx->start_va = sect->base;
|
||||
@@ -599,7 +632,7 @@ rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 |
|
||||
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.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);
|
||||
}
|
||||
|
||||
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
|
||||
rtems_rtl_obj_sections_loader (uint32_t mask,
|
||||
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);
|
||||
size_t base_offset = 0;
|
||||
bool first = true;
|
||||
int order = 0;
|
||||
|
||||
while (!rtems_chain_is_tail (sections, node))
|
||||
{
|
||||
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
|
||||
|
||||
if ((sect->size != 0) && ((sect->flags & mask) != 0))
|
||||
{
|
||||
if (!first)
|
||||
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 (sect->load_order == order)
|
||||
{
|
||||
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;
|
||||
rtems_rtl_set_error (errno, "section has no load/clear op");
|
||||
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;
|
||||
first = false;
|
||||
base_offset += sect->size;
|
||||
|
||||
++order;
|
||||
|
||||
node = rtems_chain_first (sections);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
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 const_size;
|
||||
size_t eh_size;
|
||||
size_t data_size;
|
||||
size_t bss_size;
|
||||
|
||||
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);
|
||||
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
|
||||
* standard heap or provide a specific allocator with memory protection.
|
||||
*/
|
||||
if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size,
|
||||
&obj->const_base, const_size,
|
||||
&obj->eh_base, eh_size,
|
||||
&obj->data_base, data_size,
|
||||
&obj->bss_base, bss_size))
|
||||
{
|
||||
@@ -720,7 +856,7 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj,
|
||||
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))
|
||||
{
|
||||
@@ -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));
|
||||
printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n",
|
||||
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",
|
||||
obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj));
|
||||
printf ("rtl: load sect: bss - b:%p s:%zi a:%" PRIu32 "\n",
|
||||
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
|
||||
* 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) ||
|
||||
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST,
|
||||
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,
|
||||
obj, fd, obj->data_base, handler, data) ||
|
||||
!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS,
|
||||
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->exec_size = 0;
|
||||
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.
|
||||
*/
|
||||
#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,
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (loaders[l].check (obj, fd))
|
||||
{
|
||||
obj->format = l;
|
||||
return loaders[l].load (obj, fd);
|
||||
}
|
||||
}
|
||||
|
||||
rtems_rtl_set_error (ENOENT, "no format loader found");
|
||||
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
|
||||
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))
|
||||
{
|
||||
rtems_rtl_obj_caches_flush ();
|
||||
close (fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the format specific loader. Currently this is a call to the ELF
|
||||
* loader. This call could be changed to allow probes then calls if more than
|
||||
* one format is supported.
|
||||
* Call the format specific loader.
|
||||
*/
|
||||
if (!rtems_rtl_obj_file_load (obj, fd))
|
||||
{
|
||||
rtems_rtl_obj_caches_flush ();
|
||||
close (fd);
|
||||
return false;
|
||||
}
|
||||
@@ -1081,8 +1236,6 @@ rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
rtems_rtl_obj_caches_flush ();
|
||||
|
||||
close (fd);
|
||||
|
||||
return true;
|
||||
@@ -1092,6 +1245,6 @@ bool
|
||||
rtems_rtl_obj_unload (rtems_rtl_obj_t* obj)
|
||||
{
|
||||
_rtld_linkmap_delete(obj);
|
||||
rtems_rtl_symbol_obj_erase (obj);
|
||||
return rtems_rtl_obj_free (obj);
|
||||
rtems_rtl_obj_file_unload (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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* format.
|
||||
* The type of the format loader unload handler. This handler unloads the
|
||||
* 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);
|
||||
|
||||
@@ -72,9 +78,10 @@ typedef rtems_rtl_loader_format_t* (*rtems_rtl_loader_sig) (void);
|
||||
*/
|
||||
typedef struct rtems_rtl_loader_table_s
|
||||
{
|
||||
rtems_rtl_loader_check check; /**< The check handler. */
|
||||
rtems_rtl_loader_load load; /**< The loader. */
|
||||
rtems_rtl_loader_sig signature; /**< The loader's signature. */
|
||||
rtems_rtl_loader_check check; /**< The check handler. */
|
||||
rtems_rtl_loader_load load; /**< The loader. */
|
||||
rtems_rtl_loader_unload unload; /**< The unloader. */
|
||||
rtems_rtl_loader_sig signature; /**< The loader's signature. */
|
||||
} 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_DATA (1 << 2) /**< Section holds program data. */
|
||||
#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_RELA (1 << 5) /**< Section holds relocation addend
|
||||
#define RTEMS_RTL_OBJ_SECT_EH (1 << 4) /**< Section holds exception data. */
|
||||
#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. */
|
||||
#define RTEMS_RTL_OBJ_SECT_SYM (1 << 6) /**< Section holds symbols. */
|
||||
#define RTEMS_RTL_OBJ_SECT_STR (1 << 7) /**< Section holds strings. */
|
||||
#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 8) /**< Section allocates runtime memory. */
|
||||
#define RTEMS_RTL_OBJ_SECT_LOAD (1 << 9) /**< Section is loaded from object file. */
|
||||
#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 10) /**< Section is writable, ie data. */
|
||||
#define RTEMS_RTL_OBJ_SECT_EXEC (1 << 11) /**< Section is executable. */
|
||||
#define RTEMS_RTL_OBJ_SECT_ZERO (1 << 12) /**< Section is preset to zero. */
|
||||
#define RTEMS_RTL_OBJ_SECT_CTOR (1 << 13) /**< Section contains constructors. */
|
||||
#define RTEMS_RTL_OBJ_SECT_DTOR (1 << 14) /**< Section contains destructors. */
|
||||
#define RTEMS_RTL_OBJ_SECT_SYM (1 << 7) /**< Section holds symbols. */
|
||||
#define RTEMS_RTL_OBJ_SECT_STR (1 << 8) /**< Section holds strings. */
|
||||
#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 9) /**< Section allocates runtime memory. */
|
||||
#define RTEMS_RTL_OBJ_SECT_LOAD (1 << 10) /**< Section is loaded from object file. */
|
||||
#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 11) /**< Section is writable, ie data. */
|
||||
#define RTEMS_RTL_OBJ_SECT_EXEC (1 << 12) /**< Section is executable. */
|
||||
#define RTEMS_RTL_OBJ_SECT_ZERO (1 << 13) /**< Section is preset to zero. */
|
||||
#define RTEMS_RTL_OBJ_SECT_LINK (1 << 14) /**< Section is link-ordered. */
|
||||
#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
|
||||
@@ -109,13 +128,14 @@ struct rtems_rtl_obj_sect_s
|
||||
const char* name; /**< The section's name. */
|
||||
size_t size; /**< The size of the section in memory. */
|
||||
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. */
|
||||
int link; /**< Section link field. */
|
||||
int info; /**< Secfion info field. */
|
||||
uint32_t flags; /**< The section's flags. */
|
||||
void* base; /**< The base address of the section in
|
||||
* 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. */
|
||||
uint32_t flags; /**< The status of 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* oname; /**< The object file name. Can be
|
||||
* relative. */
|
||||
@@ -153,26 +174,27 @@ struct rtems_rtl_obj_s
|
||||
size_t global_size; /**< Global symbol memory usage. */
|
||||
uint32_t unresolved; /**< The number of unresolved relocations. */
|
||||
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
|
||||
* 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
|
||||
* in memory. */
|
||||
* in memory. */
|
||||
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 exec_size; /**< The amount of executable memory
|
||||
* allocated */
|
||||
* allocated */
|
||||
void* entry; /**< The entry point of the module. */
|
||||
uint32_t checksum; /**< The checksum of the text sections. A
|
||||
* 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.*/
|
||||
* zero means do not checksum. */
|
||||
uint32_t* sec_num; /**< The sec nums of each obj. */
|
||||
uint32_t obj_num; /**< The count of elf files in an rtl obj. */
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -299,18 +335,6 @@ bool rtems_rtl_parse_name (const char* name,
|
||||
const char** oname,
|
||||
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.
|
||||
*
|
||||
@@ -371,8 +395,8 @@ void rtems_rtl_obj_erase_sections (rtems_rtl_obj_t* obj);
|
||||
* @retval NULL The section was not found.
|
||||
* @return rtems_rtl_obj_sect_t* The named section.
|
||||
*/
|
||||
rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj,
|
||||
const char* name);
|
||||
rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (const rtems_rtl_obj_t* obj,
|
||||
const char* name);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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,
|
||||
int index);
|
||||
rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj_t* obj,
|
||||
int index);
|
||||
|
||||
/**
|
||||
* The text size of the object file. Only use once all the sections has been
|
||||
* added. It includes alignments between sections that are part of the object's
|
||||
* text area. The consts sections are included in this section.
|
||||
* The text section size. Only use once all the sections has been added. It
|
||||
* includes alignments between sections that are part of the object's text
|
||||
* area. The consts sections are included in this section.
|
||||
*
|
||||
* @param obj The object file's descriptor.
|
||||
* @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
|
||||
* 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.
|
||||
* @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
|
||||
* added. It includes alignments between sections that are part of the object's
|
||||
* const area. The consts sections are included in this section.
|
||||
* The const section size. Only use once all the sections has been added. It
|
||||
* includes alignments between sections that are part of the object's const
|
||||
* area. The consts sections are included in this section.
|
||||
*
|
||||
* @param obj The object file's descriptor.
|
||||
* @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
|
||||
* 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.
|
||||
* @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
|
||||
* added. It includes alignments between sections that are part of the object's
|
||||
* data area.
|
||||
* The eh section size. Only use once all the sections has been added. It
|
||||
* includes alignments between sections that are part of the object's bss 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.
|
||||
* @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
|
||||
* 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.
|
||||
* @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
|
||||
* added. It includes alignments between sections that are part of the object's
|
||||
* bss area.
|
||||
* The bss section size. Only use once all the sections has been added. It
|
||||
* includes alignments between sections that are part of the object's bss 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_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
|
||||
* 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.
|
||||
* @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
|
||||
|
||||
@@ -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])|
|
||||
* obj_name(0..obj_num)|section_name(0..sec_num[0..obj_num])
|
||||
*
|
||||
*/
|
||||
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;
|
||||
section_detail* tmp2;
|
||||
uint32_t obj_detail_size;
|
||||
uint32_t pos = 0;
|
||||
int i,j;
|
||||
section_detail* tmp2;
|
||||
uint32_t obj_detail_size;
|
||||
uint32_t pos = 0;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
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 = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||
obj_detail_size + rap->strtable_size, true);
|
||||
detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
|
||||
obj_detail_size + rap->strtable_size, true);
|
||||
|
||||
if (!obj->detail)
|
||||
if (!detail)
|
||||
{
|
||||
rap->strtable_size = 0;
|
||||
rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
|
||||
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))
|
||||
{
|
||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj->detail);
|
||||
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, detail);
|
||||
return false;
|
||||
}
|
||||
|
||||
obj->linkmap = (struct link_map*) detail;
|
||||
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||
{
|
||||
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)
|
||||
{
|
||||
tmp1 = (struct link_map*) (obj->detail) + i;
|
||||
tmp1 = obj->linkmap + i;
|
||||
tmp1->name = rap->strtable + pos;
|
||||
tmp1->sec_num = obj->sec_num[i];
|
||||
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)
|
||||
{
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||
{
|
||||
printf ("File %d: %s\n", i, ((struct link_map*) obj->detail + i)->name);
|
||||
printf ("Section: %d sections\n",(unsigned int) obj->sec_num[i]);
|
||||
printf ("File %d: %s\n", i, (obj->linkmap + i)->name);
|
||||
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)
|
||||
{
|
||||
@@ -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, &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;
|
||||
}
|
||||
|
||||
@@ -907,7 +915,7 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
|
||||
if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -975,6 +983,13 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
rtems_rtl_rap_file_unload (rtems_rtl_obj_t* obj)
|
||||
{
|
||||
(void) obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
rtems_rtl_loader_format_t*
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* Flag the targets where off_t is 32 bits. This is not a compiler type
|
||||
* so we can't rely on prerdefines.
|
||||
*/
|
||||
#if defined(__m32r__) || defined(__moxie__)
|
||||
#if defined(__moxie__)
|
||||
#define PRIdoff_t PRIo32
|
||||
#else
|
||||
#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 rtems_rtl_data_t* rtl;
|
||||
static bool rtl_data_init;
|
||||
|
||||
/**
|
||||
* 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_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.
|
||||
*/
|
||||
rtl = malloc (sizeof (rtems_rtl_data_t));
|
||||
if (!rtl)
|
||||
{
|
||||
rtems_libio_unlock ();
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
@@ -120,6 +135,7 @@ rtems_rtl_data_init (void)
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
{
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -128,6 +144,7 @@ rtems_rtl_data_init (void)
|
||||
{
|
||||
rtems_semaphore_delete (lock);
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -143,6 +160,7 @@ rtems_rtl_data_init (void)
|
||||
{
|
||||
rtems_semaphore_delete (lock);
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -152,6 +170,7 @@ rtems_rtl_data_init (void)
|
||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||
rtems_semaphore_delete (lock);
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -162,6 +181,7 @@ rtems_rtl_data_init (void)
|
||||
rtems_rtl_unresolved_table_close (&rtl->unresolved);
|
||||
rtems_semaphore_delete (lock);
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -173,6 +193,7 @@ rtems_rtl_data_init (void)
|
||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||
rtems_semaphore_delete (lock);
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -185,6 +206,7 @@ rtems_rtl_data_init (void)
|
||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||
rtems_semaphore_delete (lock);
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -198,6 +220,7 @@ rtems_rtl_data_init (void)
|
||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||
rtems_semaphore_delete (lock);
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -212,6 +235,7 @@ rtems_rtl_data_init (void)
|
||||
rtems_rtl_symbol_table_close (&rtl->globals);
|
||||
rtems_semaphore_delete (lock);
|
||||
free (rtl);
|
||||
rtems_libio_unlock ();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -288,7 +312,7 @@ rtems_rtl_obj_caches (rtems_rtl_obj_cache_t** symbols,
|
||||
}
|
||||
|
||||
void
|
||||
rtems_rtl_obj_caches_flush ()
|
||||
rtems_rtl_obj_caches_flush (void)
|
||||
{
|
||||
if (rtl)
|
||||
{
|
||||
@@ -438,6 +462,7 @@ rtems_rtl_load_object (const char* name, int mode)
|
||||
if (!rtems_rtl_obj_find_file (obj, name))
|
||||
{
|
||||
rtems_rtl_obj_free (obj);
|
||||
rtems_rtl_obj_caches_flush ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -446,9 +471,12 @@ rtems_rtl_load_object (const char* name, int mode)
|
||||
if (!rtems_rtl_obj_load (obj))
|
||||
{
|
||||
rtems_rtl_obj_free (obj);
|
||||
rtems_rtl_obj_caches_flush ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rtems_rtl_obj_caches_flush ();
|
||||
|
||||
rtems_rtl_unresolved_resolve ();
|
||||
}
|
||||
|
||||
@@ -514,6 +542,9 @@ rtems_rtl_unload_object (rtems_rtl_obj_t* obj)
|
||||
obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
|
||||
|
||||
ok = rtems_rtl_obj_unload (obj);
|
||||
|
||||
rtems_rtl_obj_free (obj);
|
||||
rtems_rtl_obj_caches_flush ();
|
||||
}
|
||||
|
||||
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.
|
||||
* @retval NULL The RTL data is not initialised.
|
||||
|
||||
@@ -200,13 +200,12 @@ _fat_block_read(
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
fat_block_write(
|
||||
fat_block_write(
|
||||
fat_fs_info_t *fs_info,
|
||||
const uint32_t start_blk,
|
||||
const uint32_t offset,
|
||||
const uint32_t count,
|
||||
const void *buf,
|
||||
const bool overwrite_block)
|
||||
const void *buf)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
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 ( overwrite_block
|
||||
|| (bytes_to_write == fs_info->vol.bytes_per_block))
|
||||
if (bytes_to_write == fs_info->vol.bytes_per_block)
|
||||
{
|
||||
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'
|
||||
* count - count of bytes to write
|
||||
* buff - buffer provided by user
|
||||
* overwrite_cluster - true if cluster can get overwritten, false if cluster content must be kept
|
||||
*
|
||||
* RETURNS:
|
||||
* bytes written on success, or -1 if error occured
|
||||
@@ -411,8 +408,7 @@ fat_cluster_write(
|
||||
const uint32_t start_cln,
|
||||
const uint32_t offset,
|
||||
const uint32_t count,
|
||||
const void *buff,
|
||||
const bool overwrite_cluster)
|
||||
const void *buff)
|
||||
{
|
||||
ssize_t rc = RC_OK;
|
||||
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bpc - offset));
|
||||
@@ -436,8 +432,7 @@ fat_cluster_write(
|
||||
cur_blk,
|
||||
ofs_blk,
|
||||
c,
|
||||
&buffer[bytes_written],
|
||||
overwrite_cluster);
|
||||
&buffer[bytes_written]);
|
||||
if (c != ret)
|
||||
rc = -1;
|
||||
else
|
||||
|
||||
@@ -511,8 +511,7 @@ fat_cluster_write(fat_fs_info_t *fs_info,
|
||||
uint32_t start_cln,
|
||||
uint32_t offset,
|
||||
uint32_t count,
|
||||
const void *buff,
|
||||
bool overwrite_cluster);
|
||||
const void *buff);
|
||||
|
||||
ssize_t
|
||||
fat_sector_write(fat_fs_info_t *fs_info,
|
||||
|
||||
@@ -110,12 +110,10 @@ fat_file_open(
|
||||
/* access "removed-but-still-open" hash table */
|
||||
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 )
|
||||
rtems_set_errno_and_return_minus_one( ENOMEM );
|
||||
|
||||
memset(lfat_fd, 0, sizeof(fat_file_fd_t));
|
||||
|
||||
lfat_fd->links_num = 1;
|
||||
lfat_fd->flags &= ~FAT_FILE_REMOVED;
|
||||
lfat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
|
||||
@@ -170,11 +168,9 @@ fat_file_update(fat_fs_info_t *fs_info, fat_file_fd_t *fat_fd)
|
||||
{
|
||||
int ret_rc = RC_OK;
|
||||
|
||||
/*
|
||||
* if fat-file descriptor is not marked as "removed", synchronize
|
||||
* size, first cluster number, write time and date fields of the file
|
||||
*/
|
||||
if (!FAT_FILE_IS_REMOVED(fat_fd) && FAT_FILE_HAS_META_DATA_CHANGED(fat_fd))
|
||||
if (!FAT_FILE_IS_REMOVED(fat_fd) &&
|
||||
FAT_FILE_HAS_META_DATA_CHANGED(fat_fd) &&
|
||||
!FAT_FD_OF_ROOT_DIR(fat_fd))
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -403,20 +399,18 @@ static bool
|
||||
* start - offset(in bytes) to write from
|
||||
* count - count
|
||||
* buf - buffer provided by user
|
||||
* file_cln_initial - initial current cluster number of the file
|
||||
*
|
||||
* RETURNS:
|
||||
* number of bytes actually written to the file on success, or -1 if
|
||||
* error occured (errno set appropriately)
|
||||
*/
|
||||
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_file_fd_t *fat_fd,
|
||||
const uint32_t start,
|
||||
const uint32_t count,
|
||||
const uint8_t *buf,
|
||||
const uint32_t file_cln_initial)
|
||||
const uint8_t *buf)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
uint32_t cmpltd = 0;
|
||||
@@ -426,35 +420,27 @@ static ssize_t
|
||||
uint32_t ofs_cln = start - (start_cln << fs_info->vol.bpc_log2);
|
||||
uint32_t ofs_cln_save = ofs_cln;
|
||||
uint32_t bytes_to_write = count;
|
||||
uint32_t file_cln_cnt;
|
||||
ssize_t ret;
|
||||
uint32_t c;
|
||||
bool overwrite_cluster = false;
|
||||
|
||||
rc = fat_file_lseek(fs_info, fat_fd, start_cln, &cur_cln);
|
||||
if (RC_OK == rc)
|
||||
{
|
||||
file_cln_cnt = cur_cln - fat_fd->cln;
|
||||
while ( (RC_OK == rc)
|
||||
&& (bytes_to_write > 0))
|
||||
{
|
||||
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,
|
||||
cur_cln,
|
||||
ofs_cln,
|
||||
c,
|
||||
&buf[cmpltd],
|
||||
overwrite_cluster);
|
||||
&buf[cmpltd]);
|
||||
if (0 > ret)
|
||||
rc = -1;
|
||||
|
||||
if (RC_OK == rc)
|
||||
{
|
||||
++file_cln_cnt;
|
||||
bytes_to_write -= ret;
|
||||
cmpltd += ret;
|
||||
save_cln = cur_cln;
|
||||
@@ -509,7 +495,6 @@ fat_file_write(
|
||||
uint32_t byte;
|
||||
uint32_t c = 0;
|
||||
bool zero_fill = start > fat_fd->fat_file_size;
|
||||
uint32_t file_cln_initial = fat_fd->map.file_cln;
|
||||
uint32_t cln;
|
||||
|
||||
|
||||
@@ -543,8 +528,7 @@ fat_file_write(
|
||||
cln,
|
||||
byte,
|
||||
count,
|
||||
buf,
|
||||
false);
|
||||
buf);
|
||||
if (0 > ret)
|
||||
rc = -1;
|
||||
else
|
||||
@@ -556,8 +540,7 @@ fat_file_write(
|
||||
fat_fd,
|
||||
start,
|
||||
count,
|
||||
buf,
|
||||
file_cln_initial);
|
||||
buf);
|
||||
if (0 > ret)
|
||||
rc = -1;
|
||||
else
|
||||
|
||||
@@ -482,6 +482,8 @@ int msdos_get_dotdot_dir_info_cluster_num_and_offset(
|
||||
|
||||
int msdos_sync(rtems_libio_t *iop);
|
||||
|
||||
uint8_t msdos_lfn_checksum(const void *entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -288,7 +288,13 @@ msdos_get_valid_utf16_filename_character (const uint16_t utf16_character)
|
||||
static char
|
||||
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
|
||||
@@ -556,7 +562,6 @@ msdos_filename_utf8_to_short_name_for_save (
|
||||
size_t name_size = utf8_name_size;
|
||||
char *dest_ptr = (char*)short_name;
|
||||
unsigned int i;
|
||||
char c;
|
||||
size_t name_size_tmp;
|
||||
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] = '_';
|
||||
else if ( 0xE5 == *name_ptr )
|
||||
dest_ptr[0] = 0x05;
|
||||
else if (0 != (c = msdos_get_valid_codepage_filename_character( *name_ptr ) ) )
|
||||
dest_ptr[0] = c;
|
||||
else
|
||||
dest_ptr[0] = '_';
|
||||
dest_ptr[0] = msdos_get_valid_codepage_filename_character(*name_ptr);
|
||||
++name_ptr;
|
||||
++returned_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
|
||||
*/
|
||||
for (i = 1; i <= 7 && name_size && *name_ptr != '.'; ++i) {
|
||||
c = msdos_get_valid_codepage_filename_character ( *name_ptr );
|
||||
if (c != 0)
|
||||
dest_ptr[i] = c;
|
||||
else
|
||||
dest_ptr[i] = '_';
|
||||
dest_ptr[i] = msdos_get_valid_codepage_filename_character(*name_ptr);
|
||||
++name_ptr;
|
||||
++returned_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.
|
||||
*/
|
||||
for (; i <= 10 && name_size ; i++) {
|
||||
c = msdos_get_valid_codepage_filename_character ( *name_ptr);
|
||||
if (c != 0)
|
||||
dest_ptr[i] = c;
|
||||
else
|
||||
dest_ptr[i] = '_';
|
||||
dest_ptr[i] = msdos_get_valid_codepage_filename_character(*name_ptr);
|
||||
++name_ptr;
|
||||
++returned_size;
|
||||
name_size--;
|
||||
|
||||
@@ -222,10 +222,10 @@ static int msdos_utf8_normalize_and_fold(
|
||||
);
|
||||
|
||||
if ( result >= 0 ) {
|
||||
if ( result < unicode_buf_size ) {
|
||||
if ( result <= unicode_buf_size ) {
|
||||
unicodes_to_reencode = result;
|
||||
} else {
|
||||
unicodes_to_reencode = unicode_buf_size - 1;
|
||||
unicodes_to_reencode = unicode_buf_size;
|
||||
eno = ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
@@ -179,6 +179,8 @@ msdos_creat_node(const rtems_filesystem_location_info_t *parent_loc,
|
||||
*/
|
||||
if (type == FAT_DIRECTORY)
|
||||
{
|
||||
uint32_t unused;
|
||||
|
||||
/* open new directory as fat-file */
|
||||
rc = fat_file_open(&fs_info->fat, &dir_pos, &fat_fd);
|
||||
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
|
||||
* descritor
|
||||
*/
|
||||
fat_fd->fat_file_size = 0;
|
||||
fat_fd->fat_file_type = FAT_DIRECTORY;
|
||||
fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
|
||||
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
|
||||
* 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));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
*MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
|
||||
CT_LE_W((uint16_t )((fat_fd->cln) & 0x0000FFFF));
|
||||
*MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
|
||||
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,
|
||||
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
|
||||
(uint8_t *)DOT_NODE_P(dot_dotdot));
|
||||
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
|
||||
(uint8_t *)dot_dotdot);
|
||||
if (ret < 0)
|
||||
{
|
||||
rc = -1;
|
||||
|
||||
@@ -72,7 +72,7 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
||||
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
||||
fat_file_fd_t *tmp_fat_fd = NULL;
|
||||
struct dirent tmp_dirent;
|
||||
size_t tmp_lfn_len = 0;
|
||||
size_t lfn_len = 0;
|
||||
uint16_t *lfn_buf = converter->buffer.data;
|
||||
char *sfn_buf = converter->buffer.data;
|
||||
const size_t buf_size = converter->buffer.size;
|
||||
@@ -85,9 +85,13 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
||||
uint32_t lfn_start = FAT_FILE_SHORT_NAME;
|
||||
uint8_t lfn_checksum = 0;
|
||||
int lfn_entries = 0;
|
||||
size_t string_size = sizeof(tmp_dirent.d_name);
|
||||
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
|
||||
* multiples of the -dirent- size. These could result in unexpected
|
||||
@@ -107,11 +111,6 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
||||
fat_fd->fat_file_size :
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@@ -185,7 +184,7 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
||||
*/
|
||||
lfn_entries = (*MSDOS_DIR_ENTRY_TYPE(entry) &
|
||||
MSDOS_LAST_LONG_ENTRY_MASK);
|
||||
tmp_lfn_len = 0;
|
||||
lfn_len = 0;
|
||||
lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
|
||||
memset (tmp_dirent.d_name, 0, sizeof(tmp_dirent.d_name));
|
||||
}
|
||||
@@ -220,7 +219,7 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
||||
|
||||
lfn_entries--;
|
||||
offset_lfn = lfn_entries * MSDOS_LFN_LEN_PER_ENTRY;
|
||||
tmp_lfn_len += msdos_get_utf16_string_from_long_entry (
|
||||
lfn_len += msdos_get_utf16_string_from_long_entry (
|
||||
entry,
|
||||
&lfn_buf[offset_lfn],
|
||||
buf_size - offset_lfn,
|
||||
@@ -281,33 +280,30 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
||||
*/
|
||||
if (lfn_start != FAT_FILE_SHORT_NAME)
|
||||
{
|
||||
uint8_t cs = 0;
|
||||
uint8_t* p = (uint8_t*) entry;
|
||||
int i;
|
||||
if (lfn_entries == 0 &&
|
||||
lfn_checksum == msdos_lfn_checksum(entry)) {
|
||||
size_t len = sizeof(tmp_dirent.d_name) - 1;
|
||||
|
||||
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;
|
||||
|
||||
eno = (*convert_handler->utf16_to_utf8) (
|
||||
converter,
|
||||
lfn_buf,
|
||||
tmp_lfn_len,
|
||||
(uint8_t*)(&tmp_dirent.d_name[0]),
|
||||
&string_size);
|
||||
if (eno == 0) {
|
||||
tmp_dirent.d_namlen = string_size;
|
||||
tmp_dirent.d_name[tmp_dirent.d_namlen] = '\0';
|
||||
}
|
||||
else {
|
||||
eno = (*convert_handler->utf16_to_utf8) (
|
||||
converter,
|
||||
lfn_buf,
|
||||
lfn_len,
|
||||
(uint8_t *) &tmp_dirent.d_name[0],
|
||||
&len);
|
||||
if (eno == 0) {
|
||||
tmp_dirent.d_namlen = len;
|
||||
tmp_dirent.d_name[len] = '\0';
|
||||
} else {
|
||||
lfn_start = FAT_FILE_SHORT_NAME;
|
||||
}
|
||||
} else {
|
||||
lfn_start = FAT_FILE_SHORT_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (lfn_start == FAT_FILE_SHORT_NAME)
|
||||
{
|
||||
if (lfn_start == FAT_FILE_SHORT_NAME) {
|
||||
size_t len = sizeof(tmp_dirent.d_name) - 1;
|
||||
|
||||
/*
|
||||
* convert dir entry from fixed 8+3 format (without dot)
|
||||
* to 0..8 + 1dot + 0..3 format
|
||||
@@ -318,13 +314,12 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
|
||||
converter,
|
||||
sfn_buf,
|
||||
tmp_dirent.d_namlen,
|
||||
(uint8_t*)(&tmp_dirent.d_name[0]),
|
||||
&string_size);
|
||||
(uint8_t *) &tmp_dirent.d_name[0],
|
||||
&len);
|
||||
if ( 0 == eno ) {
|
||||
tmp_dirent.d_namlen = string_size;
|
||||
tmp_dirent.d_name[tmp_dirent.d_namlen] = '\0';
|
||||
}
|
||||
else {
|
||||
tmp_dirent.d_namlen = len;
|
||||
tmp_dirent.d_name[len] = '\0';
|
||||
} else {
|
||||
cmpltd = -1;
|
||||
errno = eno;
|
||||
}
|
||||
|
||||
@@ -1204,8 +1204,8 @@ int msdos_format
|
||||
case FAT_FAT32:
|
||||
/* FAT entry 0: 0xffffff00|media_type */
|
||||
FAT_SET_VAL32(tmp_sec,0,0xffffff00|fmt_params.media_code);
|
||||
/* FAT entry 1: EOC */
|
||||
FAT_SET_VAL32(tmp_sec,4,FAT_FAT32_EOC);
|
||||
/* FAT entry 1: Not dirty, no IO error, EOC */
|
||||
FAT_SET_VAL32(tmp_sec,4,0xc0000000|FAT_FAT32_EOC);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -55,6 +55,23 @@
|
||||
const char *const MSDOS_DOT_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 --
|
||||
* Routine to check the character in a file or directory name.
|
||||
* The characters support in the short file name are letters,
|
||||
@@ -99,7 +116,7 @@ msdos_is_valid_name_char(const char ch)
|
||||
*
|
||||
*/
|
||||
static void
|
||||
msdos_short_name_hex(char* sfn, int num)
|
||||
msdos_short_name_hex(char* sfn, uint32_t num)
|
||||
{
|
||||
static const char* hex = "0123456789ABCDEF";
|
||||
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);
|
||||
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,
|
||||
(char *)(&le_new_length));
|
||||
if ( ret < 0 )
|
||||
@@ -997,7 +1019,7 @@ msdos_on_entry_found (
|
||||
char *name_dir_entry,
|
||||
char *entry,
|
||||
fat_dir_pos_t *dir_pos,
|
||||
uint32_t *dir_offset,
|
||||
uint32_t dir_offset,
|
||||
const uint32_t dir_entry,
|
||||
const fat_pos_t *lfn_start
|
||||
)
|
||||
@@ -1013,7 +1035,7 @@ msdos_on_entry_found (
|
||||
rc = fat_file_ioctl(&fs_info->fat,
|
||||
fat_fd,
|
||||
F_CLU_NUM,
|
||||
*dir_offset * bts2rd,
|
||||
dir_offset * bts2rd,
|
||||
&dir_pos->sname.cln);
|
||||
if (rc == RC_OK) {
|
||||
dir_pos->sname.ofs = dir_entry;
|
||||
@@ -1219,10 +1241,10 @@ msdos_compare_entry_against_filename (
|
||||
const uint8_t *entry,
|
||||
const size_t entry_size,
|
||||
const uint8_t *filename,
|
||||
const size_t filename_size_remaining,
|
||||
const size_t name_len_remaining,
|
||||
bool *is_matching)
|
||||
{
|
||||
ssize_t size_remaining = filename_size_remaining;
|
||||
ssize_t size_remaining = name_len_remaining;
|
||||
int eno = 0;
|
||||
uint8_t entry_normalized[MSDOS_LFN_ENTRY_SIZE_UTF8];
|
||||
size_t bytes_in_entry_normalized = sizeof ( entry_normalized );
|
||||
@@ -1248,7 +1270,7 @@ msdos_compare_entry_against_filename (
|
||||
*is_matching = true;
|
||||
} else {
|
||||
*is_matching = false;
|
||||
size_remaining = filename_size_remaining;
|
||||
size_remaining = name_len_remaining;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1265,6 +1287,18 @@ msdos_compare_entry_against_filename (
|
||||
return size_remaining;
|
||||
}
|
||||
|
||||
static void
|
||||
msdos_prepare_for_next_entry(
|
||||
fat_pos_t *lfn_start,
|
||||
bool *entry_matched,
|
||||
ssize_t *name_len_remaining,
|
||||
size_t name_len_for_compare)
|
||||
{
|
||||
lfn_start->cln = FAT_FILE_SHORT_NAME;
|
||||
*entry_matched = false;
|
||||
*name_len_remaining = name_len_for_compare;
|
||||
}
|
||||
|
||||
static int
|
||||
msdos_find_file_in_directory (
|
||||
const uint8_t *filename_converted,
|
||||
@@ -1275,28 +1309,27 @@ msdos_find_file_in_directory (
|
||||
fat_file_fd_t *fat_fd,
|
||||
const uint32_t bts2rd,
|
||||
const bool create_node,
|
||||
const unsigned int fat_entries,
|
||||
const unsigned int lfn_entries,
|
||||
char *name_dir_entry,
|
||||
fat_dir_pos_t *dir_pos,
|
||||
uint32_t *dir_offset,
|
||||
uint32_t *empty_space_offset,
|
||||
uint32_t *empty_space_entry,
|
||||
uint32_t *empty_space_count)
|
||||
uint32_t *empty_file_offset,
|
||||
uint32_t *empty_entry_count)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
ssize_t bytes_read;
|
||||
uint32_t dir_entry;
|
||||
fat_pos_t lfn_start;
|
||||
uint8_t lfn_checksum = 0;
|
||||
bool entry_matched = false;
|
||||
bool entry_matched;
|
||||
bool empty_space_found = false;
|
||||
uint32_t entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
|
||||
int lfn_entry = 0;
|
||||
uint8_t entry_utf8_normalized[MSDOS_LFN_ENTRY_SIZE_UTF8];
|
||||
size_t bytes_in_entry;
|
||||
bool filename_matched = false;
|
||||
ssize_t filename_size_remaining = name_len_for_compare;
|
||||
ssize_t name_len_remaining;
|
||||
rtems_dosfs_convert_control *converter = fs_info->converter;
|
||||
uint32_t dir_offset = 0;
|
||||
|
||||
/*
|
||||
* Scan the directory seeing if the file is present. While
|
||||
@@ -1304,15 +1337,17 @@ msdos_find_file_in_directory (
|
||||
* create the entry if the name is not found.
|
||||
*/
|
||||
|
||||
lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
|
||||
msdos_prepare_for_next_entry(&lfn_start, &entry_matched,
|
||||
&name_len_remaining,
|
||||
name_len_for_compare);
|
||||
|
||||
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
|
||||
&& rc == RC_OK)
|
||||
{
|
||||
bool remainder_empty = false;
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ("MSFS:[2] dir_offset:%li\n", *dir_offset);
|
||||
printf ("MSFS:[2] dir_offset:%li\n", dir_offset);
|
||||
#endif
|
||||
|
||||
if (bytes_read < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
|
||||
@@ -1337,20 +1372,19 @@ msdos_find_file_in_directory (
|
||||
MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY);
|
||||
#if MSDOS_FIND_PRINT
|
||||
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));
|
||||
#endif
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
* is a count of empty entries.
|
||||
*/
|
||||
if (*empty_space_count == 0)
|
||||
if (*empty_entry_count == 0)
|
||||
{
|
||||
*empty_space_entry = dir_entry;
|
||||
*empty_space_offset = *dir_offset;
|
||||
*empty_file_offset = dir_offset * bts2rd + dir_entry;
|
||||
}
|
||||
|
||||
if (remainder_empty)
|
||||
@@ -1374,11 +1408,11 @@ msdos_find_file_in_directory (
|
||||
if ( !empty_space_found
|
||||
&& rc == RC_OK )
|
||||
{
|
||||
*empty_space_count +=
|
||||
*empty_entry_count +=
|
||||
entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
|
||||
empty_space_found = true;
|
||||
#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
|
||||
}
|
||||
break;
|
||||
@@ -1390,15 +1424,18 @@ msdos_find_file_in_directory (
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ("MSFS:[4.1] esc:%li esf:%i\n",
|
||||
*empty_space_count, empty_space_found);
|
||||
*empty_entry_count, empty_space_found);
|
||||
#endif
|
||||
msdos_prepare_for_next_entry(&lfn_start, &entry_matched,
|
||||
&name_len_remaining,
|
||||
name_len_for_compare);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1410,8 +1447,8 @@ msdos_find_file_in_directory (
|
||||
*/
|
||||
if (create_node && !empty_space_found)
|
||||
{
|
||||
*empty_space_entry = 0;
|
||||
*empty_space_count = 0;
|
||||
*empty_file_offset = 0;
|
||||
*empty_entry_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1421,6 +1458,9 @@ msdos_find_file_in_directory (
|
||||
if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
|
||||
MSDOS_ATTR_LFN)
|
||||
{
|
||||
bool is_first_lfn_entry =
|
||||
(lfn_start.cln == FAT_FILE_SHORT_NAME);
|
||||
|
||||
/* int o;*/
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
|
||||
@@ -1432,7 +1472,7 @@ msdos_find_file_in_directory (
|
||||
* If we are not already processing a LFN see if this is
|
||||
* the first entry of a LFN ?
|
||||
*/
|
||||
if (lfn_start.cln == FAT_FILE_SHORT_NAME)
|
||||
if (is_first_lfn_entry)
|
||||
{
|
||||
entry_matched = false;
|
||||
|
||||
@@ -1444,23 +1484,10 @@ msdos_find_file_in_directory (
|
||||
MSDOS_LAST_LONG_ENTRY) == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* 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.cln = dir_offset;
|
||||
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);
|
||||
|
||||
#if MSDOS_FIND_PRINT
|
||||
@@ -1482,7 +1509,10 @@ msdos_find_file_in_directory (
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ("MSFS:[4.4] no match\n");
|
||||
#endif
|
||||
lfn_start.cln = FAT_FILE_SHORT_NAME;
|
||||
msdos_prepare_for_next_entry(&lfn_start,
|
||||
&entry_matched,
|
||||
&name_len_remaining,
|
||||
name_len_for_compare);
|
||||
continue;
|
||||
}
|
||||
#if MSDOS_FIND_PRINT
|
||||
@@ -1493,26 +1523,29 @@ msdos_find_file_in_directory (
|
||||
bytes_in_entry = msdos_long_entry_to_utf8_name (
|
||||
converter,
|
||||
entry,
|
||||
(lfn_entry + 1) == fat_entries,
|
||||
is_first_lfn_entry,
|
||||
&entry_utf8_normalized[0],
|
||||
sizeof (entry_utf8_normalized));
|
||||
if (bytes_in_entry > 0) {
|
||||
filename_size_remaining = msdos_compare_entry_against_filename (
|
||||
name_len_remaining = msdos_compare_entry_against_filename (
|
||||
converter,
|
||||
&entry_utf8_normalized[0],
|
||||
bytes_in_entry,
|
||||
&filename_converted[0],
|
||||
filename_size_remaining,
|
||||
name_len_remaining,
|
||||
&entry_matched);
|
||||
|
||||
if (filename_size_remaining < 0
|
||||
|| (! entry_matched)) {
|
||||
filename_size_remaining = name_len_for_compare;
|
||||
lfn_start.cln = FAT_FILE_SHORT_NAME;
|
||||
if (name_len_remaining < 0 || !entry_matched) {
|
||||
msdos_prepare_for_next_entry(&lfn_start,
|
||||
&entry_matched,
|
||||
&name_len_remaining,
|
||||
name_len_for_compare);
|
||||
}
|
||||
} else {
|
||||
lfn_start.cln = FAT_FILE_SHORT_NAME;
|
||||
entry_matched = false;
|
||||
msdos_prepare_for_next_entry(&lfn_start,
|
||||
&entry_matched,
|
||||
&name_len_remaining,
|
||||
name_len_for_compare);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1530,16 +1563,14 @@ msdos_find_file_in_directory (
|
||||
*/
|
||||
if (entry_matched)
|
||||
{
|
||||
uint8_t cs = 0;
|
||||
uint8_t* p = (uint8_t*) MSDOS_DIR_NAME(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;
|
||||
else {
|
||||
if (lfn_entry ||
|
||||
name_len_remaining > 0 ||
|
||||
lfn_checksum != msdos_lfn_checksum(entry)) {
|
||||
msdos_prepare_for_next_entry(&lfn_start,
|
||||
&entry_matched,
|
||||
&name_len_remaining,
|
||||
name_len_for_compare);
|
||||
} else if (name_len_remaining == 0) {
|
||||
filename_matched = true;
|
||||
rc = msdos_on_entry_found (
|
||||
fs_info,
|
||||
@@ -1556,9 +1587,10 @@ msdos_find_file_in_directory (
|
||||
|
||||
#if MSDOS_FIND_PRINT
|
||||
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
|
||||
} else {
|
||||
} else if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_VOLUME_ID)
|
||||
== 0) {
|
||||
bytes_in_entry = MSDOS_SHORT_NAME_LEN + 1;
|
||||
bytes_in_entry = msdos_short_entry_to_utf8_name (
|
||||
converter,
|
||||
@@ -1566,14 +1598,14 @@ msdos_find_file_in_directory (
|
||||
&entry_utf8_normalized[0],
|
||||
bytes_in_entry);
|
||||
if (bytes_in_entry > 0) {
|
||||
filename_size_remaining = msdos_compare_entry_against_filename (
|
||||
name_len_remaining = msdos_compare_entry_against_filename (
|
||||
converter,
|
||||
&entry_utf8_normalized[0],
|
||||
bytes_in_entry,
|
||||
&filename_converted[0],
|
||||
name_len_for_compare,
|
||||
&entry_matched);
|
||||
if (entry_matched && filename_size_remaining == 0) {
|
||||
if (entry_matched && name_len_remaining == 0) {
|
||||
filename_matched = true;
|
||||
rc = msdos_on_entry_found (
|
||||
fs_info,
|
||||
@@ -1587,15 +1619,17 @@ msdos_find_file_in_directory (
|
||||
&lfn_start
|
||||
);
|
||||
}
|
||||
if (rc == RC_OK && (! filename_matched)) {
|
||||
lfn_start.cln = FAT_FILE_SHORT_NAME;
|
||||
entry_matched = false;
|
||||
filename_size_remaining = name_len_for_compare;
|
||||
if (rc == RC_OK && !filename_matched) {
|
||||
msdos_prepare_for_next_entry(&lfn_start,
|
||||
&entry_matched,
|
||||
&name_len_remaining,
|
||||
name_len_for_compare);
|
||||
}
|
||||
} else {
|
||||
lfn_start.cln = FAT_FILE_SHORT_NAME;
|
||||
entry_matched = false;
|
||||
filename_size_remaining = name_len_for_compare;
|
||||
msdos_prepare_for_next_entry(&lfn_start,
|
||||
&entry_matched,
|
||||
&name_len_remaining,
|
||||
name_len_for_compare);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1605,7 +1639,7 @@ msdos_find_file_in_directory (
|
||||
if (filename_matched || remainder_empty)
|
||||
break;
|
||||
|
||||
(*dir_offset)++;
|
||||
dir_offset++;
|
||||
}
|
||||
if ( ! filename_matched ) {
|
||||
/*
|
||||
@@ -1615,14 +1649,28 @@ msdos_find_file_in_directory (
|
||||
rc = MSDOS_NAME_NOT_FOUND_ERR;
|
||||
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" eso:%"PRIu32" ese:%"PRIu32"\n",
|
||||
*dir_offset, *empty_space_count, *empty_space_offset, *empty_space_entry );
|
||||
printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" efo:%"PRIu32"\n",
|
||||
dir_offset, *empty_entry_count, *empty_file_offset );
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
msdos_add_file (
|
||||
const char *name_converted,
|
||||
@@ -1630,263 +1678,161 @@ msdos_add_file (
|
||||
msdos_fs_info_t *fs_info,
|
||||
fat_file_fd_t *fat_fd,
|
||||
const uint32_t bts2rd,
|
||||
const unsigned int fat_entries,
|
||||
const unsigned int lfn_entries,
|
||||
const char *name_dir_entry,
|
||||
fat_dir_pos_t *dir_pos,
|
||||
const uint32_t dir_offset,
|
||||
const uint32_t empty_space_offset_param,
|
||||
const uint32_t empty_space_entry_param,
|
||||
const uint32_t empty_space_count
|
||||
|
||||
uint32_t empty_file_offset,
|
||||
const uint32_t empty_entry_count
|
||||
)
|
||||
{
|
||||
int ret = 0;
|
||||
ssize_t bytes_written = 0;
|
||||
uint8_t lfn_checksum = 0;
|
||||
uint32_t empty_space_offset = empty_space_offset_param;
|
||||
uint32_t empty_space_entry = empty_space_entry_param;
|
||||
bool read_cluster = false;
|
||||
int lfn_entry = 0;
|
||||
fat_pos_t lfn_start;
|
||||
uint32_t dir_entry;
|
||||
int ret;
|
||||
ssize_t bytes_written;
|
||||
uint8_t lfn_checksum;
|
||||
int lfn_entry;
|
||||
uint8_t *entry;
|
||||
uint32_t short_file_offset;
|
||||
uint32_t length;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* If there is not enough space available then extend the file.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
int slot = (((empty_space_offset * bts2rd) + empty_space_entry) /
|
||||
MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + fat_entries + 1;
|
||||
uint32_t slot;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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)
|
||||
{
|
||||
uint8_t* p = (uint8_t*) MSDOS_DIR_NAME(name_dir_entry);
|
||||
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;
|
||||
/* Get position of short file name entry */
|
||||
ret = msdos_get_pos(fs_info, fat_fd, bts2rd, short_file_offset,
|
||||
&dir_pos->sname);
|
||||
|
||||
/*
|
||||
* Handle the entry writes.
|
||||
*/
|
||||
lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
|
||||
lfn_entry = 0;
|
||||
entry = fs_info->cl_buf;
|
||||
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ("MSFS:[9] read_cluster:%d eso:%ld ese:%ld\n",
|
||||
read_cluster, empty_space_offset, empty_space_entry);
|
||||
printf ("MSFS:[9] read_cluster:%d efo:%ld ese:%ld\n",
|
||||
read_cluster, empty_file_offset, empty_space_entry);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The one more is the short entry.
|
||||
*/
|
||||
while (lfn_entry < (fat_entries + 1))
|
||||
{
|
||||
int length = 0;
|
||||
/* Long file name entries */
|
||||
for (lfn_entry = 0; lfn_entry < lfn_entries; ++lfn_entry) {
|
||||
uint8_t *p;
|
||||
const uint8_t *n;
|
||||
int i;
|
||||
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 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 (*n != 0 || *(n + 1) != 0)
|
||||
{
|
||||
if (ret != FAT_EOF)
|
||||
rtems_set_errno_and_return_minus_one(EIO);
|
||||
|
||||
#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;
|
||||
}
|
||||
*p = *n;
|
||||
*(p + 1) = *(n + 1);
|
||||
n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ( "'%c''%c'", *p, *(p+1) );
|
||||
#endif
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 4:
|
||||
p += 5;
|
||||
break;
|
||||
case 10:
|
||||
p += 4;
|
||||
break;
|
||||
default:
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p [0] = fill;
|
||||
p [1] = fill;
|
||||
fill = 0xff;
|
||||
}
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ( "\n" );
|
||||
printf ( "'%c''%c'", *p, *(p+1) );
|
||||
#endif
|
||||
*MSDOS_DIR_ENTRY_TYPE(entry) = (fat_entries - lfn_entry) + 1;
|
||||
if (lfn_entry == 1)
|
||||
*MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
|
||||
*MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
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,
|
||||
(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;
|
||||
entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
|
||||
}
|
||||
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
|
||||
@@ -1905,11 +1851,9 @@ msdos_find_name_in_fat_file (
|
||||
ssize_t name_len_for_save;
|
||||
ssize_t name_len_for_compare;
|
||||
uint32_t bts2rd = 0;
|
||||
uint32_t empty_space_offset = 0;
|
||||
uint32_t empty_space_entry = 0;
|
||||
uint32_t empty_space_count = 0;
|
||||
uint32_t dir_offset = 0;
|
||||
unsigned int fat_entries;
|
||||
uint32_t empty_file_offset = 0;
|
||||
uint32_t empty_entry_count = 0;
|
||||
unsigned int lfn_entries;
|
||||
rtems_dosfs_convert_control *converter = fs_info->converter;
|
||||
void *buffer = converter->buffer.data;
|
||||
size_t buffer_size = converter->buffer.size;
|
||||
@@ -1935,7 +1879,7 @@ msdos_find_name_in_fat_file (
|
||||
buffer,
|
||||
MSDOS_SHORT_NAME_LEN);
|
||||
if (name_len_for_compare > 0) {
|
||||
fat_entries = 0;
|
||||
lfn_entries = 0;
|
||||
}
|
||||
else
|
||||
retval = -1;
|
||||
@@ -1948,7 +1892,7 @@ msdos_find_name_in_fat_file (
|
||||
buffer,
|
||||
buffer_size);
|
||||
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;
|
||||
name_len_for_compare = msdos_filename_utf8_to_long_name_for_compare (
|
||||
converter,
|
||||
@@ -1979,13 +1923,11 @@ msdos_find_name_in_fat_file (
|
||||
fat_fd,
|
||||
bts2rd,
|
||||
create_node,
|
||||
fat_entries,
|
||||
lfn_entries,
|
||||
name_dir_entry,
|
||||
dir_pos,
|
||||
&dir_offset,
|
||||
&empty_space_offset,
|
||||
&empty_space_entry,
|
||||
&empty_space_count);
|
||||
&empty_file_offset,
|
||||
&empty_entry_count);
|
||||
}
|
||||
/* Create a non-existing file/directory if requested */
|
||||
if ( retval == RC_OK
|
||||
@@ -1999,7 +1941,7 @@ msdos_find_name_in_fat_file (
|
||||
buffer,
|
||||
MSDOS_SHORT_NAME_LEN);
|
||||
if (name_len_for_save > 0 ) {
|
||||
fat_entries = 0;
|
||||
lfn_entries = 0;
|
||||
}
|
||||
else
|
||||
retval = -1;
|
||||
@@ -2012,7 +1954,7 @@ msdos_find_name_in_fat_file (
|
||||
buffer,
|
||||
buffer_size);
|
||||
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;
|
||||
}
|
||||
else
|
||||
@@ -2031,13 +1973,11 @@ msdos_find_name_in_fat_file (
|
||||
fs_info,
|
||||
fat_fd,
|
||||
bts2rd,
|
||||
fat_entries,
|
||||
lfn_entries,
|
||||
name_dir_entry,
|
||||
dir_pos,
|
||||
dir_offset,
|
||||
empty_space_offset,
|
||||
empty_space_entry,
|
||||
empty_space_count
|
||||
empty_file_offset,
|
||||
empty_entry_count
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1019,7 +1019,7 @@ rtems_status_code status;
|
||||
initialised = 1;
|
||||
|
||||
fprintf(stderr,
|
||||
"RTEMS-NFS $Release$, " \
|
||||
"RTEMS-NFS, " \
|
||||
"Till Straumann, Stanford/SLAC/SSRL 2002, " \
|
||||
"See LICENSE file for licensing info.\n");
|
||||
|
||||
|
||||
@@ -958,7 +958,7 @@ int noblock = 1;
|
||||
struct sockwakeup wkup;
|
||||
|
||||
if (ourSock < 0) {
|
||||
fprintf(stderr,"RTEMS-RPCIOD $Release$, " \
|
||||
fprintf(stderr,"RTEMS-RPCIOD, " \
|
||||
"Till Straumann, Stanford/SLAC/SSRL 2002, " \
|
||||
"See LICENSE file for licensing info.\n");
|
||||
|
||||
|
||||
@@ -11,24 +11,9 @@
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
struct rtems_shell_topic_tt;
|
||||
typedef struct rtems_shell_topic_tt rtems_shell_topic_t;
|
||||
|
||||
struct rtems_shell_topic_tt {
|
||||
const char *topic;
|
||||
rtems_shell_topic_t *next;
|
||||
};
|
||||
|
||||
|
||||
extern rtems_shell_cmd_t * rtems_shell_first_cmd;
|
||||
extern rtems_shell_topic_t * rtems_shell_first_topic;
|
||||
|
||||
rtems_shell_topic_t * rtems_shell_lookup_topic(const char *topic);
|
||||
|
||||
bool rtems_shell_can_see_cmd(const rtems_shell_cmd_t *shell_cmd);
|
||||
|
||||
int rtems_shell_execute_cmd(const char *cmd, int argc, char *argv[]);
|
||||
|
||||
extern void rtems_shell_register_monitor_commands(void);
|
||||
|
||||
extern void rtems_shell_print_heap_info(
|
||||
|
||||
@@ -147,6 +147,12 @@ static void rtems_shell_init_once(void)
|
||||
"running on %m\n");
|
||||
|
||||
rtems_shell_init_commands();
|
||||
rtems_shell_register_monitor_commands();
|
||||
}
|
||||
|
||||
void rtems_shell_init_environment(void)
|
||||
{
|
||||
assert(pthread_once(&rtems_shell_once, rtems_shell_init_once) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -721,10 +727,7 @@ bool rtems_shell_main_loop(
|
||||
FILE *stdinToClose = NULL;
|
||||
FILE *stdoutToClose = NULL;
|
||||
|
||||
eno = pthread_once(&rtems_shell_once, rtems_shell_init_once);
|
||||
assert(eno == 0);
|
||||
|
||||
rtems_shell_register_monitor_commands();
|
||||
rtems_shell_init_environment();
|
||||
|
||||
shell_env = rtems_shell_init_env(shell_env_arg);
|
||||
if (shell_env == NULL) {
|
||||
|
||||
@@ -94,6 +94,14 @@ typedef struct {
|
||||
const char *alias;
|
||||
} rtems_shell_alias_t;
|
||||
|
||||
struct rtems_shell_topic_tt;
|
||||
typedef struct rtems_shell_topic_tt rtems_shell_topic_t;
|
||||
|
||||
struct rtems_shell_topic_tt {
|
||||
const char *topic;
|
||||
rtems_shell_topic_t *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* The return value has RTEMS_SHELL_KEYS_EXTENDED set if the key
|
||||
* is extended, ie a special key.
|
||||
@@ -125,6 +133,26 @@ extern int rtems_shell_make_args(
|
||||
int max_args
|
||||
);
|
||||
|
||||
extern rtems_shell_topic_t * rtems_shell_lookup_topic(
|
||||
const char *topic
|
||||
);
|
||||
|
||||
extern bool rtems_shell_can_see_cmd(
|
||||
const rtems_shell_cmd_t *shell_cmd
|
||||
);
|
||||
|
||||
extern int rtems_shell_execute_cmd(
|
||||
const char *cmd, int argc, char *argv[]
|
||||
);
|
||||
|
||||
/*
|
||||
* Call to set up the shell environment if you need to execute commands before
|
||||
* running a shell.
|
||||
*/
|
||||
extern void rtems_shell_init_environment(
|
||||
void
|
||||
);
|
||||
|
||||
extern int rtems_shell_cat_file(
|
||||
FILE *out,
|
||||
const char *name
|
||||
|
||||
@@ -58,7 +58,7 @@ int aio_cancel(int fildes, struct aiocb *aiocbp)
|
||||
rtems_chain_extract (&r_chain->next_fd);
|
||||
rtems_aio_remove_fd (r_chain);
|
||||
pthread_mutex_destroy (&r_chain->mutex);
|
||||
pthread_cond_destroy (&r_chain->mutex);
|
||||
pthread_cond_destroy (&r_chain->cond);
|
||||
free (r_chain);
|
||||
|
||||
pthread_mutex_unlock (&aio_request_queue.mutex);
|
||||
|
||||
@@ -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
|
||||
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)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rap.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rap.h
|
||||
|
||||
@@ -2480,7 +2480,8 @@ const rtems_libio_helper rtems_fs_init_helper =
|
||||
#define CONFIGURE_MEMORY_FOR_POSIX_KEYS(_keys, _key_value_pairs) \
|
||||
(_Configure_Object_RAM(_keys, sizeof(POSIX_Keys_Control) ) \
|
||||
+ _Configure_From_workspace( \
|
||||
_key_value_pairs * sizeof(POSIX_Keys_Key_value_pair)))
|
||||
_Configure_Max_Objects(_key_value_pairs) \
|
||||
* sizeof(POSIX_Keys_Key_value_pair)))
|
||||
|
||||
/*
|
||||
* The rest of the POSIX threads API features are only available when
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2013, 2017 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -44,9 +44,14 @@
|
||||
#define FRAME_SIZE (FRAME_OFFSET_LR + 4)
|
||||
#endif
|
||||
|
||||
.syntax unified
|
||||
.section .text
|
||||
|
||||
#ifdef __thumb2__
|
||||
FUNCTION_THUMB_ENTRY(_CPU_Context_validate)
|
||||
#else
|
||||
FUNCTION_ENTRY(_CPU_Context_validate)
|
||||
#endif
|
||||
|
||||
/* Save */
|
||||
|
||||
@@ -99,12 +104,7 @@ FUNCTION_THUMB_ENTRY(_CPU_Context_validate)
|
||||
#ifdef ARM_MULTILIB_VFP
|
||||
/* R3 contains the FPSCR */
|
||||
vmrs r3, FPSCR
|
||||
movs r4, #0x001f
|
||||
#ifdef ARM_MULTILIB_ARCH_V7M
|
||||
movt r4, #0xf000
|
||||
#else
|
||||
movt r4, #0xf800
|
||||
#endif
|
||||
ldr r4, =0xf000001f
|
||||
bic r3, r3, r4
|
||||
and r4, r4, r0
|
||||
orr r3, r3, r4
|
||||
@@ -175,11 +175,34 @@ check:
|
||||
bne restore
|
||||
.endm
|
||||
|
||||
cmp r2, sp
|
||||
/* A compare involving the stack pointer is deprecated */
|
||||
mov r1, sp
|
||||
cmp r2, r1
|
||||
bne restore
|
||||
|
||||
mov r1, r0
|
||||
|
||||
#ifdef __thumb2__
|
||||
cmp r1, r1
|
||||
itttt eq
|
||||
addeq r1, #1
|
||||
addeq r1, #2
|
||||
addeq r1, #4
|
||||
addeq r1, #8
|
||||
subs r1, #15
|
||||
cmp r1, r0
|
||||
bne restore
|
||||
cmp r1, r1
|
||||
iteee eq
|
||||
addeq r1, #1
|
||||
addne r1, #2
|
||||
addne r1, #4
|
||||
addne r1, #8
|
||||
subs r1, #1
|
||||
cmp r1, r0
|
||||
bne restore
|
||||
#endif
|
||||
|
||||
#ifndef ARM_MULTILIB_VFP
|
||||
check_register r3
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2013, 2017 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -29,8 +29,7 @@ FUNCTION_THUMB_ENTRY(_CPU_Context_volatile_clobber)
|
||||
|
||||
#ifdef ARM_MULTILIB_VFP
|
||||
vmrs r1, FPSCR
|
||||
movs r2, #0x001f
|
||||
movt r2, #0xf800
|
||||
ldr r2, =0xf000001f
|
||||
bic r1, r1, r2
|
||||
and r2, r2, r0
|
||||
orr r1, r1, r2
|
||||
|
||||
@@ -28,10 +28,10 @@ void __attribute__((naked)) _ARMV7M_Exception_default( void )
|
||||
"mov r2, lr\n"
|
||||
"mrs r1, msp\n"
|
||||
"mrs r0, psp\n"
|
||||
"cmn r2, #3\n"
|
||||
"itt ne\n"
|
||||
"movne r0, r1\n"
|
||||
"addne r0, %[cpufsz]\n"
|
||||
"tst lr, #4\n"
|
||||
"itt eq\n"
|
||||
"moveq r0, r1\n"
|
||||
"addeq r0, %[cpufsz]\n"
|
||||
"add r2, r0, %[v7mlroff]\n"
|
||||
"add r1, sp, %[cpulroff]\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
|
||||
* Obere Lagerstr. 30
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
@@ -48,29 +48,42 @@ static void _ARMV7M_Trigger_lazy_floating_point_context_save( void )
|
||||
|
||||
void _ARMV7M_Pendable_service_call( void )
|
||||
{
|
||||
ARMV7M_Exception_frame *ef;
|
||||
|
||||
_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 );
|
||||
Per_CPU_Control *cpu_self = _Per_CPU_Get();
|
||||
|
||||
/*
|
||||
* According to "ARMv7-M Architecture Reference Manual" section B1.5.6
|
||||
* "Exception entry behavior" the return address is half-word aligned.
|
||||
* We must check here if a thread dispatch is allowed. Right after a
|
||||
* "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 *)
|
||||
((uintptr_t) _ARMV7M_Thread_dispatch & ~((uintptr_t) 1));
|
||||
if (
|
||||
( 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 )
|
||||
{
|
||||
Per_CPU_Control *cpu_self = _Per_CPU_Get();
|
||||
ARMV7M_Exception_frame *ef;
|
||||
|
||||
_ARMV7M_Trigger_lazy_floating_point_context_save();
|
||||
@@ -79,10 +92,9 @@ void _ARMV7M_Supervisor_call( void )
|
||||
++ef;
|
||||
_ARMV7M_Set_PSP( (uint32_t) ef );
|
||||
|
||||
_ISR_Nest_level = 0;
|
||||
RTEMS_COMPILER_MEMORY_BARRIER();
|
||||
cpu_self->isr_nest_level = 0;
|
||||
|
||||
if ( _Thread_Dispatch_necessary ) {
|
||||
if ( cpu_self->dispatch_necessary ) {
|
||||
_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
|
||||
* Obere Lagerstr. 30
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
@@ -30,19 +30,25 @@
|
||||
|
||||
void _ARMV7M_Interrupt_service_enter( void )
|
||||
{
|
||||
++_Thread_Dispatch_disable_level;
|
||||
++_ISR_Nest_level;
|
||||
Per_CPU_Control *cpu_self = _Per_CPU_Get();
|
||||
|
||||
++cpu_self->thread_dispatch_disable_level;
|
||||
++cpu_self->isr_nest_level;
|
||||
}
|
||||
|
||||
void _ARMV7M_Interrupt_service_leave( void )
|
||||
{
|
||||
--_ISR_Nest_level;
|
||||
--_Thread_Dispatch_disable_level;
|
||||
if (
|
||||
_ISR_Nest_level == 0
|
||||
&& _Thread_Dispatch_disable_level == 0
|
||||
&& _Thread_Dispatch_necessary
|
||||
) {
|
||||
Per_CPU_Control *cpu_self = _Per_CPU_Get();
|
||||
|
||||
--cpu_self->thread_dispatch_disable_level;
|
||||
--cpu_self->isr_nest_level;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user