Compare commits

...

47 Commits

Author SHA1 Message Date
Chris Johns
7093cb5e5d libtest/dl01: Add dlerror tests.
Update #2747
2018-02-08 14:21:13 +11:00
Patrick Gauvin
5812a26eeb Update dlerror usage
Handles possible NULL return value

Updates #2747
2018-02-08 14:21:13 +11:00
Patrick Gauvin
dc746b50ca libdl: Fix dlerror return type
POSIX specifies char *, not const char *

Updates #2747
2018-02-08 14:21:13 +11:00
Patrick Gauvin
a346408e4e libdl: dlerror return NULL when no error
Updates #2747
2018-02-08 14:21:13 +11:00
Patrick Gauvin
a2a9751823 libdl: Clear error between dlerror invocations
Updates #2747
2018-02-08 14:21:13 +11:00
Chris Johns
1a304307a2 testsuites/libtest: Set EXENT to .exe so executable are correctly named.
The configure order effects how it works.

Close #3297
2018-02-08 14:20:26 +11:00
Christian Mauderer
d438427cbe dosfs: Allow creating a file with similar name.
If there is already a file with a long file name it isn't possible to
create a second file which has a name that ends on the first files name
(for example ets.beam and sets.beam). This patch fixes that.

Close #3258.
2017-12-07 08:04:11 +01:00
Christian Mauderer
004a63efef dosfs: Fix files with same name as volume name.
Take care that a file in the root directory with the same name as the
volume name can be found.

Close #3257.
2017-12-05 08:02:42 +01:00
Sebastian Huber
c139a70597 posix: Fix aio_cancel()
Close #3164.
2017-10-04 09:26:40 +02:00
Sebastian Huber
1a21831b3c i2c: Fix EEPROM driver program timeout handling
The RTEMS_MILLISECONDS_TO_TICKS() macro doesn't round up. Do not use it
to calculate the program timeout in ticks. Check program done condition
after the timeout check to account for pre-emptions.

Close #3162.
2017-10-02 13:44:36 +02:00
Sebastian Huber
8ca15e26ba i2c: Send MSB of address first for EEPROMs
Close #3161.
2017-10-02 13:44:32 +02:00
Sebastian Huber
a3199d91f3 dosfs: Fix fat_file_update()
Do not update the non-existant meta-data of the root directory.

Close #2944.
2017-09-06 14:40:38 +02:00
Sebastian Huber
a76c31e13d dosfs: Fix find name next entry preparation
Close #2964.
2017-09-06 14:09:11 +02:00
Sebastian Huber
e1c3dc0909 dosfs: Fix msdos_dir_read()
Set a proper name buffer length for each converter invocation.

Close #2987.
2017-09-06 13:24:34 +02:00
Chris Johns
2ed53cb982 testsuite/dl: Add C++ by default for DL tests which use C++.
- Add AM C++ support to the testsuite configure.ac script.
- Fix the dependences in the  DL tests.

Closes #3024.
2017-08-23 09:48:56 +10:00
Chris Johns
89fd08eae6 libmisc/shell: Make some internal shell functions public.
- Add 'rtems_shell_init_environment()' so a user can create the
  shell environment without needing to run a shell.
- Move 'rtems_shell_lookup_topic', 'rtems_shell_can_see_cmd',
  and 'rtems_shell_execute_cmd' from the internal interface to
  the public interface.

Closes #3104.
2017-08-23 09:48:56 +10:00
Sebastian Huber
492c95eee6 confdefs: Fix POSIX keys configuration
Remove the OBJECTS_UNLIMITED_OBJECTS flag for the memory size
configuration.

Close #3105.
2017-08-22 08:03:10 +02:00
Sebastian Huber
7d097c5c69 arm: Validate IT[7:0] bit field of PSR
Close #3093.
2017-08-10 09:24:26 +02:00
Sebastian Huber
5cc276e7c1 arm: Fix CPU context validation for Cortex-R4
Do not touch the FPSCR[QC] bit since this is DNM/RAZ on Cortex-R4.

Close #3092.
2017-08-10 08:21:04 +02:00
Sebastian Huber
7e91901303 arm: Fix ARMv7-M interrupt processing
Right after a "msr basepri_max, %[basepri]" instruction an interrupt
service may still take place (observed at least on Cortex-M7).  However,
pendable service calls that are activated during this interrupt service
may be delayed until interrupts are enable again.  The
_ARMV7M_Pendable_service_call() did not check that a thread dispatch is
allowed.  Move this test from _ARMV7M_Interrupt_service_leave() to
_ARMV7M_Pendable_service_call().

Close #3060.
2017-07-07 13:27:24 +02:00
Sebastian Huber
09cbe713ff bsps/arm: Fix bit field offset in GIC support
Close #3002.
2017-05-11 09:57:53 +02:00
Chris Johns
d2e31f70c1 libdl: Back port C++ exception throw and catch from 4.12.
Closes #2956.
2017-04-04 13:26:01 +10:00
Sebastian Huber
d51538bdbe dosfs: Fix file name search
Do not use our long file name entry count to optimize the file name
search. The Unicode comparison must be taken into account.

Close #2939.
2017-03-21 16:15:25 +01:00
Sebastian Huber
89164c67bc dosfs: Fix race condition msdos_dir_read()
Obtain file system instance lock before member access.

Close #2937.
2017-03-21 16:15:21 +01:00
Sebastian Huber
4c4869f483 dosfs: Rename fat_entries to lfn_entries
The name "fat_entries" for long file name directory entries is quite
misleading.
2017-03-21 16:15:17 +01:00
Sebastian Huber
7011f26061 dosfs: Fix long file name padding
Close #2934.
2017-03-21 16:15:11 +01:00
Sebastian Huber
49eb6061ec dosfs: msdos_filename_utf8_to_short_name_for_save
Simplify.
2017-03-21 16:15:09 +01:00
Sebastian Huber
5ed41a6d82 dosfs: Fix msdos_add_file()
Make sure that long file names work accross cluster boundaries.

Close #2929.
2017-03-21 16:15:04 +01:00
Sebastian Huber
58e8131184 dosfs: Simplify msdos_add_file()
Update #2929.
2017-03-21 16:15:00 +01:00
Sebastian Huber
565b1a57b7 dosfs: Add and use msdos_lfn_checksum()
Update #2929.
2017-03-21 16:14:59 +01:00
Sebastian Huber
ad3a744ac4 dosfs: Simplify fat_file_open()
Update #2929.
2017-03-21 16:14:57 +01:00
Sebastian Huber
201f3797b3 dosfs: Simplify msdos_creat_node()
Update #2929.
2017-03-21 16:14:53 +01:00
Sebastian Huber
c38f1fcf8f dosfs: Fix fat_file_write()
Remove forced overwrite which leads to file data corruption.  The logic
to determine a forced overwrite was fundamentally broken.  For simplity,
disable this feature.

Close #2622.
2017-03-21 16:14:44 +01:00
Sebastian Huber
21d7154b07 dosfs: Fix msdos_utf8_normalize_and_fold()
It is all right in case the result uses the full destination buffer.
Without this fix the handling of a maximum 8.3 short file name is
broken.

Close #2928.
2017-03-21 16:14:37 +01:00
Sebastian Huber
f08c71339c libio: Fix deadlock in location management
Perform a context-dependent deferred location release to avoid a
deadlock on the file system instance locks, for example during a
chdir().

Close #2936.
2017-03-21 16:13:11 +01:00
Chris Johns
2ea436a167 Config (.cfg) files are only valid if deeper than 5.
Closes #2827.
2017-03-21 14:38:59 +11:00
Sebastian Huber
a27128c5dc termios: Fix infinite loop in receive path
In canonical mode, the raw input buffer or the canonical buffer may
overflow without an end of line.  Avoid an infinite loop in this case.

Update #2915.
2017-02-28 09:55:58 +01:00
Sebastian Huber
0e8d205559 termios: Protect raw input buffer with device lock
Use the device lock to protect the raw input buffer management, e.g.
tail, head and buffer content updates.

Update #2914.
2017-02-28 09:55:55 +01:00
Sebastian Huber
35a3d81581 termios: Simplify rtems_termios_read_tty()
Remove dead code.

Update #2914.
2017-02-28 09:53:21 +01:00
Sebastian Huber
17f81ee3cb dosfs: Fix FAT32 formatter
The second FAT entry contains a bit to indicate if the FAT32 filesystem
is not dirty and a bit to indicate if there was no IO error.  Set both
bits for a fresh filesystem.  This prevents a warning if mounted on
Windows.

Update #2913.
2017-02-28 09:50:58 +01:00
Sebastian Huber
6ec60de37d dosfs: Directories should have a file size of 0
Update #2755.
2017-02-28 09:50:53 +01:00
Nick Withers
7e0a02a70f Remove old CVS keywords
Close #2388.
2017-02-15 14:53:07 +01:00
Sudarshan Rajagopalan
5b5ef4e479 Fix exception handler for supporting FPU
Close #2401.
2017-02-15 14:18:53 +01:00
Sebastian Huber
04684cbc43 dosfs: Fix msdos_find_file_in_directory()
For a filename match the entry must match without anything remaining.

Update #2908.
2017-02-14 08:09:57 +01:00
Sebastian Huber
69ae534cbb Change version to 4.11.1.99
Update #2886.
2017-01-26 08:31:50 +01:00
Christian Spindeldreier
af9143fba5 GRETH: Interrupt Handler Uses Wrong Events
closes #2796.
2017-01-12 09:38:38 -06:00
Joel Sherrill
d46a65d052 Remove texinfo format documentation. Replaced by Sphinx formatted documentation.
updates #2812.
2017-01-11 12:08:15 -06:00
455 changed files with 5701 additions and 146874 deletions

View File

@@ -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 : ; \

View File

@@ -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)

View File

@@ -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])

View File

@@ -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`

View File

@@ -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])

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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])
])

View File

@@ -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

View File

@@ -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])

View File

@@ -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;

View File

@@ -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(

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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);
}
}

View File

@@ -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(

View File

@@ -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) {

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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'. */

View File

@@ -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

View File

@@ -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

View File

@@ -19,6 +19,7 @@
#include "config.h"
#endif
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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.
*

View File

@@ -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 ();
}
}

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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, &sect->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, &sect->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;
}

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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.
*

View File

@@ -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

View 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;
}

View 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
View 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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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--;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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
);
}

View File

@@ -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");

View File

@@ -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");

View File

@@ -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(

View File

@@ -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) {

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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. :)

View File

@@ -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.

View File

@@ -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
])
])

View File

@@ -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-??

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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