diff options
Diffstat (limited to '')
50 files changed, 2199 insertions, 1044 deletions
diff --git a/cpukit/libmisc/xz/COPYING b/cpukit/compression/xz/COPYING index fc4fbf798d..fc4fbf798d 100644 --- a/cpukit/libmisc/xz/COPYING +++ b/cpukit/compression/xz/COPYING diff --git a/cpukit/libmisc/xz/README b/cpukit/compression/xz/README index 1d5b9d85b2..1d5b9d85b2 100644 --- a/cpukit/libmisc/xz/README +++ b/cpukit/compression/xz/README diff --git a/cpukit/libmisc/xz/xz_config.h b/cpukit/compression/xz/xz_config.h index eb9dac1a4b..eb9dac1a4b 100644 --- a/cpukit/libmisc/xz/xz_config.h +++ b/cpukit/compression/xz/xz_config.h diff --git a/cpukit/libmisc/xz/xz_crc32.c b/cpukit/compression/xz/xz_crc32.c index 34532d14fd..34532d14fd 100644 --- a/cpukit/libmisc/xz/xz_crc32.c +++ b/cpukit/compression/xz/xz_crc32.c diff --git a/cpukit/libmisc/xz/xz_crc64.c b/cpukit/compression/xz/xz_crc64.c index ca1caee899..ca1caee899 100644 --- a/cpukit/libmisc/xz/xz_crc64.c +++ b/cpukit/compression/xz/xz_crc64.c diff --git a/cpukit/libmisc/xz/xz_dec_lzma2.c b/cpukit/compression/xz/xz_dec_lzma2.c index 6de808c5b3..6de808c5b3 100644 --- a/cpukit/libmisc/xz/xz_dec_lzma2.c +++ b/cpukit/compression/xz/xz_dec_lzma2.c diff --git a/cpukit/libmisc/xz/xz_dec_stream.c b/cpukit/compression/xz/xz_dec_stream.c index d6525506a1..d6525506a1 100644 --- a/cpukit/libmisc/xz/xz_dec_stream.c +++ b/cpukit/compression/xz/xz_dec_stream.c diff --git a/cpukit/libmisc/xz/xz_lzma2.h b/cpukit/compression/xz/xz_lzma2.h index 071d67bee9..071d67bee9 100644 --- a/cpukit/libmisc/xz/xz_lzma2.h +++ b/cpukit/compression/xz/xz_lzma2.h diff --git a/cpukit/libmisc/xz/xz_private.h b/cpukit/compression/xz/xz_private.h index 482b90f363..482b90f363 100644 --- a/cpukit/libmisc/xz/xz_private.h +++ b/cpukit/compression/xz/xz_private.h diff --git a/cpukit/libmisc/xz/xz_stream.h b/cpukit/compression/xz/xz_stream.h index 66cb5a7055..66cb5a7055 100644 --- a/cpukit/libmisc/xz/xz_stream.h +++ b/cpukit/compression/xz/xz_stream.h diff --git a/cpukit/libmisc/cpuuse/cpuinforeport.c b/cpukit/libmisc/cpuuse/cpuinforeport.c index dcbc7f1747..ac9ad10169 100644 --- a/cpukit/libmisc/cpuuse/cpuinforeport.c +++ b/cpukit/libmisc/cpuuse/cpuinforeport.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* - * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * Copyright (c) 2016 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libmisc/cpuuse/cpuusagedata.c b/cpukit/libmisc/cpuuse/cpuusagedata.c index 350ade309b..fa39a6d754 100644 --- a/cpukit/libmisc/cpuuse/cpuusagedata.c +++ b/cpukit/libmisc/cpuuse/cpuusagedata.c @@ -3,11 +3,10 @@ /** * @file * - * @ingroup libmisc_cpuuse CPU Usage + * @ingroup RTEMSImplCPUUsageReporting * - * @brief CPU Usage Data - * - * CPU Usage Reporter - Shared Data + * @brief This source file contains the definition of + * ::CPU_usage_Uptime_at_last_reset. */ /* diff --git a/cpukit/libmisc/cpuuse/cpuusagereport.c b/cpukit/libmisc/cpuuse/cpuusagereport.c index bc7c897db5..bdeee375e3 100644 --- a/cpukit/libmisc/cpuuse/cpuusagereport.c +++ b/cpukit/libmisc/cpuuse/cpuusagereport.c @@ -3,9 +3,10 @@ /** * @file * - * @ingroup libmisc_cpuuse CPU Usage + * @ingroup RTEMSImplCPUUsageReporting * - * @brief CPU Usage Report + * @brief This source file contains the definition of + * rtems_cpu_usage_report() and rtems_cpu_usage_report_with_plugin(). */ /* diff --git a/cpukit/libmisc/cpuuse/cpuusagereset.c b/cpukit/libmisc/cpuuse/cpuusagereset.c index bdfba7c944..e56ab3cded 100644 --- a/cpukit/libmisc/cpuuse/cpuusagereset.c +++ b/cpukit/libmisc/cpuuse/cpuusagereset.c @@ -3,9 +3,10 @@ /** * @file * - * @ingroup libmisc_cpuuse CPU Usage + * @ingroup RTEMSImplCPUUsageReporting * - * @brief CPU Usage Reset + * @brief This source file contains the definition of + * rtems_cpu_usage_reset(). */ /* diff --git a/cpukit/libmisc/cpuuse/cpuusagetop.c b/cpukit/libmisc/cpuuse/cpuusagetop.c index 045a38ae55..eed89ad211 100644 --- a/cpukit/libmisc/cpuuse/cpuusagetop.c +++ b/cpukit/libmisc/cpuuse/cpuusagetop.c @@ -3,9 +3,10 @@ /** * @file * - * @ingroup libmisc_cpuuse CPU Usage + * @ingroup RTEMSImplCPUUsageReporting * - * @brief CPU Usage Top + * @brief This source file contains the definition of + * rtems_cpu_usage_top() and rtems_cpu_usage_top_with_plugin(). */ /* diff --git a/cpukit/libmisc/cpuuse/cpuuseimpl.h b/cpukit/libmisc/cpuuse/cpuuseimpl.h index 1162d1e892..8c6c407b4b 100644 --- a/cpukit/libmisc/cpuuse/cpuuseimpl.h +++ b/cpukit/libmisc/cpuuse/cpuuseimpl.h @@ -1,5 +1,14 @@ /* SPDX-License-Identifier: BSD-2-Clause */ +/** + * @file + * + * @ingroup RTEMSImplCPUUsageReporting + * + * @brief This header file provides interfaces of the + * @ref RTEMSImplCPUUsageReporting implementation. + */ + /* * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). @@ -35,8 +44,25 @@ extern "C" { #endif +/** + * @defgroup RTEMSImplCPUUsageReporting CPU Usage Reporting + * + * @ingroup RTEMSImpl + * + * @brief This group contains the implementation of + * @ref RTEMSAPICPUUsageReporting. + * + * @{ + */ + +/** + * @brief This object provides the uptime timestamp at the last CPU usage + * reset. + */ extern Timestamp_Control CPU_usage_Uptime_at_last_reset; +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpukit/libmisc/devnull/devzero.c b/cpukit/libmisc/devnull/devzero.c index 7cfd05d4be..5be370b991 100644 --- a/cpukit/libmisc/devnull/devzero.c +++ b/cpukit/libmisc/devnull/devzero.c @@ -9,7 +9,7 @@ */ /* - * Copyright (c) 2011 embedded brains GmbH. All rights reserved. + * Copyright (c) 2011 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libmisc/regulator/regulator.c b/cpukit/libmisc/regulator/regulator.c new file mode 100644 index 0000000000..97a48be4f5 --- /dev/null +++ b/cpukit/libmisc/regulator/regulator.c @@ -0,0 +1,680 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @brief Regulator Library Implementation + */ + +/* + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> + +#include <rtems.h> +#include <rtems/regulator.h> +#include <string.h> + +#include <rtems/regulatorimpl.h> + +/** + * @ingroup RegulatorInternalAPI + * + * This method is the body for the task which delivers the output for + * this regulator instance at the configured rate. + * + * @param[in] arg points to the regulator instance this thread + * is associated with + * + * @note The argument passed in cannot be NULL if the + * rtems_regulator_create worked. + */ +static rtems_task _Regulator_Output_task_body( + rtems_task_argument arg +) +{ + _Regulator_Control *the_regulator = (_Regulator_Control *)arg; + rtems_status_code sc; + size_t to_dequeue; + _Regulator_Message_t regulator_message; + size_t regulator_message_size; + bool release_it; + + the_regulator->delivery_thread_is_running = true; + + /** + * This thread uses a rate monotonic period object instance. A rate + * monotonic period object must be created by the thread using it. + * It can be deleted by any thread which simplifies clean up. + * + * The rate_monotonic_create() call can fail if the application + * is incorrectly configured. This thread has no way to report the + * failure. If it continues with an invalid id, then the thread will + * not block on the period and spin continuously consuming CPU. The only + * alternatives are to invoke rtems_fatal_error_occurred() or silently + * exit the thread. + */ + sc = rtems_rate_monotonic_create( + rtems_build_name('P', 'E', 'R', 'D'), + &the_regulator->delivery_thread_period_id + ); + if (sc != RTEMS_SUCCESSFUL) { + goto exit_delivery_thread; + } + + /** + * Loop on the rate_monotonic_period() based on the specified period. + */ + while (1) { + sc = rtems_rate_monotonic_period( + the_regulator->delivery_thread_period_id, + the_regulator->Attributes.delivery_thread_period + ); + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); + + /** + * If the delivery thread has been requested to exit, then + * quit processing messages, break out of this loop, and exit + * this thread. + */ + if (the_regulator->delivery_thread_request_exit) { + break; + } + + /** + * Loop for the configured number of messages to deliver per period. + * If we reach the point, there are no more messages, block for the + * rest of this period. If there are messages, deliver them. + */ + for (to_dequeue = 0; + to_dequeue < the_regulator->Attributes.maximum_to_dequeue_per_period; + to_dequeue++) { + regulator_message_size = sizeof(_Regulator_Message_t); + sc = rtems_message_queue_receive( + the_regulator->queue_id, + ®ulator_message, + ®ulator_message_size, + RTEMS_NO_WAIT, + 0 + ); + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); + if (sc != RTEMS_SUCCESSFUL) { + break; + } + + release_it = the_regulator->Attributes.deliverer( + the_regulator->Attributes.deliverer_context, + regulator_message.buffer, + regulator_message.length + ); + + the_regulator->Statistics.delivered++; + + /** + * The message was successfully delivered. If the delivery function + * wants the buffer returned, do it now. The delivery to the Destination + * may involve handing the buffer off to something like DMA + * and need to wait for it to complete before releasing the buffer. + * + * Note that this is the underlying RTEMS service + * used by @a rtems_regulator_obtain_buffer() and @a + * rtems_regulator_release_buffer(). + */ + if (release_it == true) { + the_regulator->Statistics.released++; + sc = rtems_partition_return_buffer( + the_regulator->messages_partition_id, + regulator_message.buffer + ); + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); + } + } + } + + /** + * This thread was requested to exit. Do so. + */ +exit_delivery_thread: + the_regulator->delivery_thread_is_running = false; + the_regulator->delivery_thread_has_exited = true; + + (void) rtems_rate_monotonic_delete(the_regulator->delivery_thread_period_id); + + rtems_task_exit(); +} + +/** + * @ingroup RegulatorInternalAPI + * + * This method frees the resources associated with a regulator instance. + * The resources are freed in the opposite of the order in which they are + * allocated. This is used on error cases in @a rtems_regulator_create() and in + * @a rtems_regulator_delete(). + * + * @param[in] the_regulator is the instance to operate upon + * @param[in] ticks is the length of time to wait for the delivery thread + * to exit + * + * @return This method returns true is successful and false on timeout. + */ +static bool _Regulator_Free_helper( + _Regulator_Control *the_regulator, + rtems_interval ticks +) +{ + rtems_status_code sc; + + + /* + * If the output thread has not started running, then we can just delete it. + */ + + if (ticks == 0 || the_regulator->delivery_thread_is_running == false) { + sc = rtems_task_delete(the_regulator->delivery_thread_id); + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); + } else { + rtems_interval remaining = ticks; + + the_regulator->delivery_thread_request_exit = true; + + while (1) { + if (the_regulator->delivery_thread_has_exited) { + break; + } + + if (remaining == 0) { + return false; + } + + (void) rtems_task_wake_after(1); + remaining--; + } + } + + /* + * The output thread deletes the rate monotonic period that it created. + */ + + /* + * The regulator's message_queue_storage is implicitly freed by this call. + */ + sc = rtems_message_queue_delete(the_regulator->queue_id); + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); + + sc = rtems_partition_delete(the_regulator->messages_partition_id); + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); + + if (the_regulator->message_memory) { + free(the_regulator->message_memory); + } + + the_regulator->initialized = 0; + free(the_regulator); + return true; +} + +/** + * @ingroup RegulatorInternalAPI + */ +rtems_status_code rtems_regulator_create( + rtems_regulator_attributes *attributes, + rtems_regulator_instance **regulator +) +{ + _Regulator_Control *the_regulator; + rtems_status_code sc; + size_t alloc_size; + + /** + * Perform basic validation of parameters + */ + if (attributes == NULL) { + return RTEMS_INVALID_ADDRESS; + } + + if (regulator == NULL) { + return RTEMS_INVALID_ADDRESS; + } + + /** + * Verify attributes are OK. Some are checked by calls to object create + * methods. Specifically the following are not checked: + * + * - delivery_thread_priority by rtems_task_create() + * - delivery_thread_stack_size can be any value + */ + if (attributes->deliverer == NULL) { + return RTEMS_INVALID_ADDRESS; + } + + if (attributes->maximum_messages == 0) { + return RTEMS_INVALID_NUMBER; + } + + if (attributes->maximum_message_size == 0) { + return RTEMS_INVALID_SIZE; + } + + if (attributes->maximum_to_dequeue_per_period == 0) { + return RTEMS_INVALID_NUMBER; + } + + if (attributes->delivery_thread_period == 0) { + return RTEMS_INVALID_NUMBER; + } + + /** + * Allocate memory for regulator instance + */ + the_regulator = (_Regulator_Control *) calloc(sizeof(_Regulator_Control), 1); + if (the_regulator == NULL) { + return RTEMS_NO_MEMORY; + } + + /** + * We do NOT want the delivery_thread_id field to be initialized to 0. If the + * @a rtems_task_create() fails, then the field will not be overwritten. + * This results in an attempt to rtems_task_delete(0) during clean + * up. The thread ID of 0 is self which results in the calling thread + * accidentally deleting itself. + */ + the_regulator->delivery_thread_id = (rtems_id) -1; + + /** + * Copy the attributes to an internal area for later use + */ + the_regulator->Attributes = *attributes; + + /** + * Allocate memory for the messages. There is no need to zero out the + * message memory because the user should fill that in. + */ + alloc_size = attributes->maximum_message_size * attributes->maximum_messages; + the_regulator->message_memory = calloc(alloc_size, 1); + if (the_regulator->message_memory == NULL) { + _Regulator_Free_helper(the_regulator, 0); + return RTEMS_NO_MEMORY; + } + + /** + * Associate message memory with a partition so allocations are atomic + */ + sc = rtems_partition_create( + rtems_build_name('P', 'O', 'O', 'L'), + the_regulator->message_memory, + alloc_size, + attributes->maximum_message_size, + RTEMS_DEFAULT_ATTRIBUTES, + &the_regulator->messages_partition_id + ); + if (sc != RTEMS_SUCCESSFUL) { + _Regulator_Free_helper(the_regulator, 0); + return sc; + } + + /** + * Create the message queue between the sender and output thread + */ + RTEMS_MESSAGE_QUEUE_BUFFER(sizeof(_Regulator_Message_t)) regulator_message_t; + + size_t storage_size = sizeof(regulator_message_t) * attributes->maximum_messages; + + the_regulator->message_queue_storage = malloc(storage_size); + if (the_regulator->message_queue_storage == NULL) { + _Regulator_Free_helper(the_regulator, 0); + return RTEMS_NO_MEMORY; + } + + rtems_message_queue_config mq_config = { + .name = rtems_build_name('S', 'N', 'D', 'Q'), + .maximum_pending_messages = attributes->maximum_messages, + .maximum_message_size = sizeof(_Regulator_Message_t), + .storage_area = the_regulator->message_queue_storage, + .storage_size = storage_size, + .storage_free = free, + .attributes = RTEMS_DEFAULT_ATTRIBUTES + }; + sc = rtems_message_queue_construct( + &mq_config, + &the_regulator->queue_id + ); + if (sc != RTEMS_SUCCESSFUL) { + _Regulator_Free_helper(the_regulator, 0); + return sc; + } + + /** + * @note A rate monotonic period object must be created by the thread + * using it. Thus that specific create operation is not included + * in this method. All other resources are allocated here. + */ + + /** + * Create the output thread Using the priority and stack size attributes + * specified by the user. + */ + sc = rtems_task_create( + rtems_build_name('R', 'E', 'G', 'U'), + attributes->delivery_thread_priority, + attributes->delivery_thread_stack_size, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &the_regulator->delivery_thread_id + ); + if (sc != RTEMS_SUCCESSFUL) { + _Regulator_Free_helper(the_regulator, 0); + return sc; + } + + /** + * Start the output thread. + * + * @note There should be no way this call can fail. The task id is valid, + * the regulator output thread entry point is valid, and the argument + * is valid. + */ + the_regulator->delivery_thread_is_running = true; + the_regulator->delivery_thread_request_exit = false; + the_regulator->delivery_thread_has_exited = false; + + sc = rtems_task_start( + the_regulator->delivery_thread_id, + _Regulator_Output_task_body, + (rtems_task_argument) the_regulator + ); + _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL); + + /** + * The regulator is successfully initialized. Set the initialized field + * to reflect this and return the instance pointer. + */ + the_regulator->initialized = REGULATOR_INITIALIZED; + + *regulator = (void *)the_regulator; + + return RTEMS_SUCCESSFUL; +} + +/** + * @brief Validate the regulator instance provided by the user + * + * Validate the regulator instance provided by the user + * + * @param[in] regulator is the instance provided by the user + * @param[inout] status will contain the RTEMS status for this check + * + * @return This method returns a @a _Regulator_Control instance pointer + * which is NULL if invalid or points to the internal regulator + * control structure if valid. + */ +static inline _Regulator_Control *_Regulator_Get( + rtems_regulator_instance *regulator, + rtems_status_code *status +) +{ + _Regulator_Control *the_regulator = (_Regulator_Control *) regulator; + + if (the_regulator == NULL) { + *status = RTEMS_INVALID_ADDRESS; + return NULL; + } + + if (the_regulator->initialized != REGULATOR_INITIALIZED) { + *status = RTEMS_INCORRECT_STATE; + return NULL; + } + + status = RTEMS_SUCCESSFUL; + return the_regulator; +} + +/** + * @ingroup RegulatorInternalAPI + */ +rtems_status_code rtems_regulator_delete( + rtems_regulator_instance *regulator, + rtems_interval ticks +) +{ + _Regulator_Control *the_regulator; + rtems_status_code status; + + /** + * Convert external handle to internal instance pointer + */ + the_regulator = _Regulator_Get(regulator, &status); + if (the_regulator == NULL) { + return status; + } + + /** + * There can be no buffers outstanding + */ + _Regulator_Statistics *stats = &the_regulator->Statistics; + + if (stats->obtained != stats->released ) { + return RTEMS_RESOURCE_IN_USE; + } + + /** + * Free the resources associated with this regulator instance. + */ + bool bc; + bc = _Regulator_Free_helper(the_regulator, ticks); + if (bc == false) { + return RTEMS_TIMEOUT; + } + + return RTEMS_SUCCESSFUL; +} + +/** + * @ingroup RegulatorInternalAPI + * + * Allocate a buffer for the caller using the internal partition. + */ +rtems_status_code rtems_regulator_obtain_buffer( + rtems_regulator_instance *regulator, + void **buffer +) +{ + _Regulator_Control *the_regulator; + rtems_status_code status; + + /** + * Convert external handle to internal instance pointer + */ + the_regulator = _Regulator_Get(regulator, &status); + if (the_regulator == NULL) { + return status; + } + + /** + * Allocate a buffer for the user application from the buffer pool managed + * by an Classic API partition. + */ + status = rtems_partition_get_buffer( + the_regulator->messages_partition_id, + buffer + ); + + if (status == RTEMS_SUCCESSFUL) { + the_regulator->Statistics.obtained++; + } + + return status; +} + +/** + * @ingroup RegulatorInternalAPI + * + * Allocate a buffer for the caller using the internal partition. + */ +rtems_status_code rtems_regulator_release_buffer( + rtems_regulator_instance *regulator, + void *buffer +) +{ + _Regulator_Control *the_regulator; + rtems_status_code status; + + /** + * Convert external handle to internal instance pointer + */ + the_regulator = _Regulator_Get(regulator, &status); + if (the_regulator == NULL) { + return status; + } + + /** + * Deallocate the buffer to the buffer pool managed by a Classic + * API partition. + */ + status = rtems_partition_return_buffer( + the_regulator->messages_partition_id, + buffer + ); + + if (status == RTEMS_SUCCESSFUL) { + the_regulator->Statistics.released++; + } + + return status; +} + +/** + * @ingroup RegulatorInternalAPI + */ +rtems_status_code rtems_regulator_send( + rtems_regulator_instance *regulator, + void *message, + size_t length +) +{ + _Regulator_Control *the_regulator; + rtems_status_code status; + _Regulator_Message_t regulator_message; + + the_regulator = (_Regulator_Control *) regulator; + + /** + * Validate the arguments and ensure the regulator was successfully + * initialized. + */ + if (message == NULL) { + return RTEMS_INVALID_ADDRESS; + } + + if (length == 0) { + return RTEMS_INVALID_NUMBER; + } + + /** + * Convert external handle to internal instance pointer + */ + the_regulator = _Regulator_Get(regulator, &status); + if (the_regulator == NULL) { + return status; + } + + /** + * Place the message pointer and length into a temporary structure. This + * lets the implementation internally send the message by reference and + * have a zero-copy implementation. + */ + regulator_message.buffer = message; + regulator_message.length = length; + + /** + * Send the application message to the output thread for delivery using + * a Classic API message queue. + */ + status = rtems_message_queue_send( + the_regulator->queue_id, + ®ulator_message, + sizeof(_Regulator_Message_t) + ); + if (status != RTEMS_SUCCESSFUL) { + return status; + } + + return status; +} + +/** + * @ingroup RegulatorInternalAPI + */ +rtems_status_code rtems_regulator_get_statistics( + rtems_regulator_instance *regulator, + rtems_regulator_statistics *statistics +) +{ + _Regulator_Control *the_regulator; + rtems_status_code status; + + /** + * Validate the arguments and ensure the regulator was successfully + * initialized. + */ + if (statistics == NULL) { + return RTEMS_INVALID_ADDRESS; + } + + /** + * Convert external handle to internal instance pointer + */ + the_regulator = _Regulator_Get(regulator, &status); + if (the_regulator == NULL) { + return status; + } + + /** + * Zero out the statistics structure in case the get period statistics + * fails below. + */ + memset(statistics, 0, sizeof(rtems_regulator_statistics)); + + /** + * Fill in the caller's statistics structure from information + * maintained by the regulator instance about buffers processed. + */ + statistics->obtained = the_regulator->Statistics.obtained; + statistics->released = the_regulator->Statistics.released; + statistics->delivered = the_regulator->Statistics.delivered; + + /** + * Attempt to retrieve the delivery thread's period's statistics. + * + * NOTE; If the Delivery Thread has not run yet, the period will not + * exist yet. We should not fail for this reason but it is why + * we zeroed out the entire structure above. + */ + (void) rtems_rate_monotonic_get_statistics( + the_regulator->delivery_thread_period_id, + &statistics->period_statistics + ); + + return RTEMS_SUCCESSFUL; +} diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c index 76f5cd7dbb..0bf6c84208 100644 --- a/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c +++ b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c @@ -127,32 +127,6 @@ rtems_fdt_get_value32 (const char* path, size_t size, uint32_t* value) { - const void* prop; - int node; - int length; - - node = rtems_fdt_path_offset(&cmd_fdt_handle, path); - if (node < 0) - { - rtems_fdt_check_error (node, "path lookup", path); - return false; - } - - prop = rtems_fdt_getprop(&cmd_fdt_handle, node, property, &length); - if (length < 0) - { - rtems_fdt_check_error (length, "get property", path); - return false; - } - - if (length != sizeof (uint32_t)) - { - printf ("error: property is not sizeof(uint32_t): %s\n", path); - return false; - } - - *value = rtems_fdt_get_uint32 (prop); - return true; } @@ -185,7 +159,10 @@ rtems_fdt_shell_ls (int argc, char *argv[]) bool debug = false; int arg = 1; size_t path_len = 0; + int total_entries = 0; int num_entries = 0; + int max_name_len = 0; + int name_offset = 0; int i = 0; while (arg < argc) @@ -220,10 +197,15 @@ rtems_fdt_shell_ls (int argc, char *argv[]) ++arg; } - if (!path) + if (path == NULL) { path = ""; } + else + { + if (path[0] != '/') + name_offset = 1; + } /* Eliminate trailing slashes. */ path_len = strlen (path); @@ -231,45 +213,99 @@ rtems_fdt_shell_ls (int argc, char *argv[]) if (path_len > 0 && path[path_len - 1] == '/') path_len--; - /* Loop through the entries, looking for matches. */ - num_entries = rtems_fdt_num_entries(&cmd_fdt_handle); - printf("Total: %d\n", num_entries); - for (i = 0; i < num_entries; i++) + /* Loop through the entries to get the mac name len. */ + total_entries = rtems_fdt_num_entries(&cmd_fdt_handle); + + for (i = 0; i < total_entries; i++) { /* Add it to the result set. */ const char *name = rtems_fdt_entry_name(&cmd_fdt_handle, i); size_t name_len = strlen(name); - if ((name_len > path_len) && - ((strncmp (path, name, path_len) == 0) && (name[path_len] == '/')) && - (recursive || (index(&name[path_len+1], '/') == 0))) + if ((name_len >= path_len + name_offset) && + ((strncmp (path, name + name_offset, path_len) == 0) && + ((name[path_len + name_offset] == '/' || + name[path_len + name_offset] == '\0'))) && + (recursive || name_len == path_len + name_offset || + (strchr(&name[path_len + name_offset + 1], '/') == NULL))) { + ++num_entries; if (long_path) { - printf ("%s", name); + if (name_len > max_name_len) + { + max_name_len = name_len; + } } else if (name_len != path_len) { - printf ("%s", &name[path_len + 1]); + if (name_len - path_len > max_name_len) + { + max_name_len = name_len - path_len; + } } + } + } - if (debug) + printf("Total: %d of %d\n", num_entries, total_entries); + + for (i = 0; i < total_entries; i++) + { + /* Add it to the result set. */ + const char *name = rtems_fdt_entry_name(&cmd_fdt_handle, i); + size_t name_len = strlen(name); + + if ((name_len >= path_len + name_offset) && + ((strncmp (path, name + name_offset, path_len) == 0) && + ((name[path_len + name_offset] == '/' || + name[path_len + name_offset] == '\0'))) && + (recursive || name_len == path_len + name_offset || + (strchr(&name[path_len + name_offset + 1], '/') == NULL))) + { + const char* print_name = "."; + + if (long_path) { - /* Get properties if we're in debug mode. */ - int proplen = 0; - int offset = rtems_fdt_entry_offset(&cmd_fdt_handle, i); - const void *prop = rtems_fdt_getprop(&cmd_fdt_handle, offset, "reg", &proplen); - const void *prop2 = rtems_fdt_getprop(&cmd_fdt_handle, offset, "mask", &proplen); + print_name = name + name_offset; + } + else if (name_len != path_len + name_offset) + { + print_name = &name[path_len + name_offset + 1]; + } - if (prop) - { - printf(" addr 0x%08" PRIx32, *(uint32_t *)prop); - } + printf ("%-*s", max_name_len, print_name); - proplen = 0; - if (prop2) + if (debug) + { + /* Get properties if we're in debug mode. */ + int printed = 0; + const int noffset = rtems_fdt_entry_offset(&cmd_fdt_handle, i); + int poffset = rtems_fdt_first_prop_offset(&cmd_fdt_handle, noffset); + int address_cells = + rtems_fdt_getprop_address_cells(&cmd_fdt_handle, noffset); + int size_cells = rtems_fdt_getprop_size_cells(&cmd_fdt_handle, noffset); + printf("cells(a:%d s:%d) ", address_cells, size_cells); + while (poffset >= 0) { - printf(" mask 0x%08" PRIx32, *(uint32_t *)prop2); + int plen = 0; + const char* pname = NULL; + const uint8_t *pvalue = + rtems_fdt_getprop_by_offset(&cmd_fdt_handle, poffset, &pname, &plen); + if (pvalue != NULL) + { + int b; + if (printed > 0) + printf(","); + ++printed; + printf(" %s %i:", pname, plen); + for (b = 0; b < plen; ++b) + { + if (b > 0 && (b % 4) == 0) + printf(" "); + printf("%02" PRIx8, *pvalue++); + } + } + poffset = rtems_fdt_next_prop_offset(&cmd_fdt_handle, poffset); } } @@ -283,9 +319,11 @@ rtems_fdt_shell_ls (int argc, char *argv[]) static int rtems_fdt_shell_wr (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t value; + rtems_fdt_address_map addr_map; + uint64_t offset = 0; + uint32_t value; + int fmt; + int r; if ((argc < 3) || (argc > 4)) return rtems_fdt_wrong_number_of_args (); @@ -296,18 +334,30 @@ rtems_fdt_shell_wr (int argc, char *argv[]) } else { - offset = strtoul (argv[2], 0, 0); + offset = strtoull (argv[2], 0, 0); value = strtoul (argv[3], 0, 0); } - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } - address += offset; + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 "\n", address, value); + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 "\n", fmt, addr_map.address, value); - rtems_fdt_write (address, value); + rtems_fdt_write (addr_map.address, value); return 0; } @@ -315,8 +365,10 @@ rtems_fdt_shell_wr (int argc, char *argv[]) static int rtems_fdt_shell_rd (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + int fmt; + int r; if ((argc < 1) || (argc > 3)) return rtems_fdt_wrong_number_of_args (); @@ -324,12 +376,25 @@ rtems_fdt_shell_rd (int argc, char *argv[]) if (argc == 3) offset = strtoul (argv[2], 0, 0); - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } - address += offset; + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; - printf ("0x%08" PRIx32 " => 0x%08" PRIx32 "\n", address, rtems_fdt_read (address)); + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; + + printf ("0x%0*" PRIx64 " => 0x%08" PRIx32 "\n", + fmt, addr_map.address, rtems_fdt_read (addr_map.address)); return 0; } @@ -337,11 +402,13 @@ rtems_fdt_shell_rd (int argc, char *argv[]) static int rtems_fdt_shell_set (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t value; - int mask_arg; - uint32_t mask; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + uint32_t value; + int mask_arg; + uint32_t mask; + int fmt; + int r; if ((argc < 3) || (argc > 4)) return rtems_fdt_wrong_number_of_args (); @@ -354,24 +421,38 @@ rtems_fdt_shell_set (int argc, char *argv[]) mask_arg = 3; } - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); + return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; if (isdigit ((unsigned char) argv[mask_arg][0])) mask = strtoul (argv[mask_arg], 0, 0); else { + mask = 0; if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) return 1; } - address += offset; - value = rtems_fdt_read (address); + value = rtems_fdt_read (addr_map.address); - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 " | 0x%08" PRIx32 "\n", - address, value | mask, value, mask); + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 " | 0x%08" PRIx32 "\n", + fmt, addr_map.address, value | mask, value, mask); - rtems_fdt_write (address, value | mask); + rtems_fdt_write (addr_map.address, value | mask); return 0; } @@ -379,11 +460,13 @@ rtems_fdt_shell_set (int argc, char *argv[]) static int rtems_fdt_shell_cl (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t value; - int mask_arg; - uint32_t mask; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + uint32_t value; + int mask_arg; + uint32_t mask; + int fmt; + int r; if ((argc < 3) || (argc > 4)) return rtems_fdt_wrong_number_of_args (); @@ -396,25 +479,39 @@ rtems_fdt_shell_cl (int argc, char *argv[]) mask_arg = 3; } - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); + return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; if (isdigit ((unsigned char) argv[mask_arg][0])) mask = strtoul (argv[mask_arg], 0, 0); else { + mask = 0; if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) return 1; } - address += offset; - value = rtems_fdt_read (address); + value = rtems_fdt_read (addr_map.address); - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 \ + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 \ " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")\n", - address, value & ~mask, value, mask, ~mask); + fmt, addr_map.address, value & ~mask, value, mask, ~mask); - rtems_fdt_write (address, value & ~mask); + rtems_fdt_write (addr_map.address, value & ~mask); return 0; } @@ -422,12 +519,14 @@ rtems_fdt_shell_cl (int argc, char *argv[]) static int rtems_fdt_shell_up (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t set; - uint32_t value; - int mask_arg; - uint32_t mask; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + uint32_t set; + uint32_t value; + int mask_arg; + uint32_t mask; + int fmt; + int r; if ((argc < 4) || (argc > 5)) return rtems_fdt_wrong_number_of_args (); @@ -442,25 +541,39 @@ rtems_fdt_shell_up (int argc, char *argv[]) set = strtoul (argv[mask_arg + 1], 0, 0); - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; if (isdigit ((unsigned char) argv[mask_arg][0])) mask = strtoul (argv[mask_arg], 0, 0); else { + mask = 0; if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) return 1; } - address += offset; - value = rtems_fdt_read (address); + value = rtems_fdt_read (addr_map.address); - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = (0x%08" PRIx32 \ + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = (0x%08" PRIx32 \ " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")) | 0x%08" PRIx32 "\n", - address, (value & ~mask) | set, value, mask, ~mask, set); + fmt, addr_map.address, (value & ~mask) | set, value, mask, ~mask, set); - rtems_fdt_write (address, (value & ~mask) | set); + rtems_fdt_write (addr_map.address, (value & ~mask) | set); return 0; } @@ -468,13 +581,15 @@ rtems_fdt_shell_up (int argc, char *argv[]) static int rtems_fdt_shell_tst (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t test; - uint32_t value = 0; - int mask_arg; - uint32_t mask; - time_t start; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + uint32_t test; + uint32_t value = 0; + int mask_arg; + uint32_t mask; + time_t start; + int fmt; + int r; if ((argc < 4) || (argc > 5)) return rtems_fdt_wrong_number_of_args (); @@ -489,37 +604,50 @@ rtems_fdt_shell_tst (int argc, char *argv[]) test = strtoul (argv[mask_arg + 1], 0, 0); - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; if (isdigit ((unsigned char) argv[mask_arg][0])) mask = strtoul (argv[mask_arg], 0, 0); else { - if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) + mask = 0; + if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) return 1; } - address += offset; - start = time (NULL); - printf ("0x%08" PRIx32 " => (value & 0x%08" PRIx32 ") == 0x%08" PRIx32 \ + printf ("0x%0*" PRIx64 " => (value & 0x%08" PRIx32 ") == 0x%08" PRIx32 \ " for %ld seconds\n", - address, mask, test, rtems_fdt_test_timeout); + fmt, addr_map.address, mask, test, rtems_fdt_test_timeout); while ((time (NULL) - start) < rtems_fdt_test_timeout) { int i; for (i = 0; i < 10000; ++i) { - value = rtems_fdt_read (address); + value = rtems_fdt_read (addr_map.address); if ((value & mask) == test) return 0; } } - printf ("0x%08" PRIx32 " => 0x%08" PRIx32 ": timeout\n", address, value); + printf ("0x%0*" PRIx64 " => 0x%08" PRIx32 ": timeout\n", fmt, addr_map.address, value); return 1; } diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt.c b/cpukit/libmisc/rtems-fdt/rtems-fdt.c index 7dd2bc1047..9f8d7bfb24 100644 --- a/cpukit/libmisc/rtems-fdt/rtems-fdt.c +++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.c @@ -25,9 +25,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <errno.h> #include <fcntl.h> -#include <stdlib.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> @@ -35,6 +33,7 @@ #include <libfdt.h> #include <zlib.h> +#include <rtems/malloc.h> #include <rtems/rtems-fdt.h> #include <rtems/thread.h> @@ -175,14 +174,14 @@ rtems_fdt_init_index (rtems_fdt_handle* fdt, rtems_fdt_blob* blob) /* * Create the index. */ - entries = calloc(num_entries, sizeof(rtems_fdt_index_entry)); + entries = rtems_calloc(num_entries, sizeof(rtems_fdt_index_entry)); if (!entries) { return -RTEMS_FDT_ERR_NO_MEMORY; } - names = calloc(1, total_name_memory); - if (!entries) + names = rtems_calloc(1, total_name_memory); + if (!names) { free(entries); return -RTEMS_FDT_ERR_NO_MEMORY; @@ -505,7 +504,7 @@ rtems_fdt_load (const char* filename, rtems_fdt_handle* handle) { size_t offset; - cdata = malloc(sb.st_size); + cdata = rtems_malloc(sb.st_size); if (!cdata) { close (bf); @@ -546,7 +545,7 @@ rtems_fdt_load (const char* filename, rtems_fdt_handle* handle) name_len = strlen (filename) + 1; - blob = malloc(sizeof (rtems_fdt_blob) + name_len + bsize); + blob = rtems_malloc(sizeof (rtems_fdt_blob) + name_len + bsize); if (!blob) { free(cdata); @@ -649,7 +648,7 @@ rtems_fdt_register (const void* dtb, rtems_fdt_handle* handle) return fe; } - blob = malloc(sizeof (rtems_fdt_blob)); + blob = rtems_malloc(sizeof (rtems_fdt_blob)); if (!blob) { return -RTEMS_FDT_ERR_NO_MEMORY; @@ -700,14 +699,14 @@ rtems_fdt_unload (rtems_fdt_handle* handle) rtems_chain_extract_unprotected (&handle->blob->node); + rtems_fdt_release_index(&handle->blob->index); + free (handle->blob); handle->blob = NULL; rtems_fdt_unlock (fdt); - rtems_fdt_release_index(&handle->blob->index); - return 0; } @@ -782,6 +781,27 @@ rtems_fdt_get_name (rtems_fdt_handle* handle, int nodeoffset, int* length) return name; } +int +rtems_fdt_first_prop_offset(rtems_fdt_handle* handle, int nodeoffset) +{ + return fdt_first_property_offset(handle->blob->blob, nodeoffset); +} + +int +rtems_fdt_next_prop_offset(rtems_fdt_handle* handle, int propoffset) +{ + return fdt_next_property_offset(handle->blob->blob, propoffset); +} + +const void* +rtems_fdt_getprop_by_offset(rtems_fdt_handle* handle, + int propoffset, + const char** name, + int* length) +{ + return fdt_getprop_by_offset(handle->blob->blob, propoffset, name, length); +} + const void* rtems_fdt_getprop_namelen (rtems_fdt_handle* handle, int nodeoffset, @@ -941,7 +961,8 @@ rtems_fdt_strerror (int errval) "no memory", "file not found", "DTB read fail", - "blob has references" + "blob has references", + "bad length" }; if (errval > -RTEMS_FDT_ERR_RTEMS_MIN) return fdt_strerror (errval); @@ -977,7 +998,7 @@ rtems_fdt_prop_value(const char* const path, if (length > (int) *size) { rtems_fdt_release_handle (&fdt); - return RTEMS_FDT_ERR_BADPATH; + return -RTEMS_FDT_ERR_BADPATH; } *size = length; @@ -987,11 +1008,29 @@ rtems_fdt_prop_value(const char* const path, return 0; } +bool +rtems_fdt_get_parent_prop_value(rtems_fdt_handle* handle, + int nodeoffset, + const char* name, + uint32_t* value) +{ + const void* prop; + int plen = 0; + int node = rtems_fdt_parent_offset(handle, nodeoffset); + if (node < 0) + return false; + prop = rtems_fdt_getprop(handle, node, name, &plen); + if (plen < 0) + return false; + *value = rtems_fdt_get_uint32(prop); + return true; +} + int rtems_fdt_prop_map(const char* const path, const char* const propname, const char* const names[], - uint32_t* values, + uintptr_t* values, size_t count) { rtems_fdt_handle fdt; @@ -1006,10 +1045,9 @@ rtems_fdt_prop_map(const char* const path, for (item = 0; item < count; item++) { - const void* prop; - const uint8_t* p; - int length; - int subnode; + const void* prop; + int length; + int subnode; subnode = rtems_fdt_subnode_offset (&fdt, node, names[item]); if (subnode < 0) @@ -1025,40 +1063,85 @@ rtems_fdt_prop_map(const char* const path, return length; } - if (length != sizeof (uint32_t)) + if (length > sizeof (uintptr_t)) { rtems_fdt_release_handle (&fdt); - return RTEMS_FDT_ERR_BADPATH; + return -RTEMS_FDT_ERR_BADPATH; } - p = prop; - - values[item] = ((((uint32_t) p[0]) << 24) | - (((uint32_t) p[1]) << 16) | - (((uint32_t) p[2]) << 8) | - (uint32_t) p[3]); + values[item] = rtems_fdt_get_offset_len_uintptr(prop, 0, length); } return 0; } +uintptr_t +rtems_fdt_get_offset_len_uintptr (const void* prop, int offset, int len) +{ + const uint8_t* p = prop; + uintptr_t value = 0; + int b; + if (len <= sizeof(uintptr_t)) { + for (b = 0; b < len; ++b) { + value = (value << 8) | (uintptr_t) p[offset++]; + } + } + return value; +} + + uint32_t -rtems_fdt_get_uint32 (const void* prop) +rtems_fdt_get_offset_uint32 (const void* prop, int offset) { const uint8_t* p = prop; uint32_t value; - value = ((((uint32_t) p[0]) << 24) | - (((uint32_t) p[1]) << 16) | - (((uint32_t) p[2]) << 8) | - (uint32_t) p[3]); + offset *= sizeof(uint32_t); + value = ((((uint32_t) p[offset + 0]) << 24) | + (((uint32_t) p[offset + 1]) << 16) | + (((uint32_t) p[offset + 2]) << 8) | + (uint32_t) p[offset + 3]); return value; } +uint32_t +rtems_fdt_get_uint32 (const void* prop) +{ + return rtems_fdt_get_offset_uint32(prop, 0); +} + +uint64_t +rtems_fdt_get_offset_uint64 (const void* prop, int offset) +{ + uint64_t value = rtems_fdt_get_offset_uint32(prop, offset); + value = (value << 16) << 16; + return value | rtems_fdt_get_offset_uint32(prop, offset + 1); +} + +uint64_t +rtems_fdt_get_uint64 (const void* prop) +{ + return rtems_fdt_get_offset_uint64(prop, 0); +} + +uintptr_t +rtems_fdt_get_uintptr (const void* prop) +{ + return rtems_fdt_get_offset_uintptr(prop, 0); +} + +uintptr_t +rtems_fdt_get_offset_uintptr (const void* prop, int offset) +{ + if (sizeof(intptr_t) == sizeof(uint32_t)) + return rtems_fdt_get_offset_uint32(prop, offset); + return rtems_fdt_get_offset_uint64(prop, offset); +} + int rtems_fdt_get_value (const char* path, const char* property, size_t size, - uint32_t* value) + uintptr_t* value) { rtems_fdt_handle fdt; const void* prop; @@ -1081,8 +1164,8 @@ rtems_fdt_get_value (const char* path, return length; } - if (length == sizeof (uint32_t)) - *value = rtems_fdt_get_uint32 (prop); + if (length == sizeof (uintptr_t)) + *value = rtems_fdt_get_uintptr (prop); else *value = 0; @@ -1119,3 +1202,111 @@ rtems_fdt_entry_offset(rtems_fdt_handle* handle, int id) { return handle->blob->index.entries[id].offset; } + +int +rtems_fdt_getprop_address_cells(rtems_fdt_handle* handle, int nodeoffset) +{ + uint32_t value = 0; + if (!rtems_fdt_get_parent_prop_value(handle, nodeoffset, "#address-cells", &value)) + return -1; + return value; +} + +int +rtems_fdt_getprop_size_cells(rtems_fdt_handle* handle, int nodeoffset) +{ + uint32_t value = 0; + if (!rtems_fdt_get_parent_prop_value(handle, nodeoffset, "#size-cells", &value)) + return -1; + return value; +} + +int rtems_fdt_getprop_address_map(rtems_fdt_handle* handle, + const char* path, + const char* name, + rtems_fdt_address_map* addr_map) +{ + const void* prop; + int plen = 0; + int poff = 0; + int len; + + memset(addr_map, 0, sizeof(*addr_map)); + + addr_map->node = rtems_fdt_path_offset(handle, path); + if (addr_map->node < 0) + return -RTEMS_FDT_ERR_NOTFOUND; + + addr_map->address_cells = rtems_fdt_getprop_address_cells(handle, addr_map->node); + addr_map->size_cells = rtems_fdt_getprop_size_cells(handle, addr_map->node); + + prop = rtems_fdt_getprop(handle, addr_map->node, name, &plen); + if (plen < 0) + return -RTEMS_FDT_ERR_NOTFOUND; + + if (addr_map->address_cells == 0) + return -RTEMS_FDT_ERR_BADOFFSET; + + if (addr_map->address_cells < 0) + { + if (addr_map->size_cells > 0) + return -RTEMS_FDT_ERR_BADOFFSET; + addr_map->address_cells = 1; + } + + if (addr_map->size_cells < 0) + { + addr_map->size = sizeof(uint32_t); + addr_map->size_cells = 0; + } + + len = (addr_map->address_cells + addr_map->size_cells) * sizeof(uint32_t); + + if (len != plen) + return -RTEMS_FDT_ERR_BADLENGTH; + + switch (addr_map->address_cells) + { + case 1: + if (plen < sizeof(uint32_t)) + return -RTEMS_FDT_ERR_BADLENGTH; + addr_map->address = rtems_fdt_get_offset_uint32(prop, poff); + poff += 1; + plen -= sizeof(uint32_t); + break; + case 2: + if (plen < sizeof(uint64_t)) + return -RTEMS_FDT_ERR_BADLENGTH; + addr_map->address = rtems_fdt_get_offset_uint64(prop, poff); + poff += 2; + plen -= sizeof(uint64_t); + break; + default: + return -RTEMS_FDT_ERR_BADLENGTH; + } + + switch (addr_map->size_cells) + { + case 0: + addr_map->size = sizeof(uint32_t); + break; + case 1: + if (plen < sizeof(uint32_t)) + return -RTEMS_FDT_ERR_BADLENGTH; + addr_map->size = rtems_fdt_get_offset_uint32(prop, poff); + poff += 1; + plen -= sizeof(uint32_t); + break; + case 2: + if (plen < sizeof(uint64_t)) + return -RTEMS_FDT_ERR_BADLENGTH; + addr_map->size = rtems_fdt_get_offset_uint64(prop, poff); + poff += 2; + plen -= sizeof(uint64_t); + break; + default: + return -RTEMS_FDT_ERR_BADLENGTH; + } + + return 0; +} diff --git a/cpukit/libmisc/serdbg/README b/cpukit/libmisc/serdbg/README deleted file mode 100644 index 64623ebd89..0000000000 --- a/cpukit/libmisc/serdbg/README +++ /dev/null @@ -1,134 +0,0 @@ -This directory contains three useful packages related to the termios I/O -system: - -PACKAGE SERDBGIO -================ -"serdbgio" provides the "serial gdb" standard I/O functions "getDebugChar" -and "putDebugChar" for any device driver supporting polled termios mode. - -The initialization function "serdbg_open" opens the v.24 port intended -for the serial debug connection, and sets the desired baud rate. The -"getDebugChar" and "putDebugChar" functions then interact with the -corresponding driver using the calls intended for polled termios -operation. - -Specification for the debug device, baud rate and other parameters is -done in a global structure of type "serdbg_conf_t". A configuration -mechanism quite similar to the overall RTEMS configuration is available. - -PACKAGE SERDBG -============== -"serdbg" provides a means to optionally initialize and/or start a -serial gdb session as soon as possible, this means as soon as all -drivers have been initialized. The serial debug I/O functions can -either be integrated as special routines of the BSP drivers, or using -the package "serdbgio" - -PACKAGE TERMIOS_PRINTK -====================== -"termios_printk" provides a standard output function suitable to use -with "printk". It uses the same technique as serdbgio, hooking the -interface between a polled device driver and the termios system. - - -REQUIREMENTS -============ - -- These two packages can be used with any polled termios device -driver. -- For standard initialization, they need a modified "bsppost.c" -to perform the initialization calls. - -USAGE -===== - -For using these packages add the following to your "init" module or -your "system.h" file (Note: most macro settings fall back to a -default, if not set.): - -/* - * CONFIGURE_USE_SERDBG - * set this macro, if you want to connect gdb over a serial line - * when set, the debug stub will be connected after driver - * initialization in "bsppost.c" - */ -#define CONFIGURE_USE_SERDBG - - -/* - * CONFIGURE_SERDBG_SKIP_INIT_BKPT - * set this macro, if you do not want the gdb interface to wait for a - * debugger connection directly after initialization - * If you set this macro, the gdb stub will only hook various - * exception vectors when called from "bsppost.c". - */ -/* #define CONFIGURE_SERDBG_SKIP_INIT_BKPT */ - -/* - * CONFIGURE_SERDBG_USE_POLLED_TERMIOS - * set this macro, if you want "serdbgio" to provide the I/O - * functions for the serial gdb connection - */ -#define CONFIGURE_SERDBG_USE_POLLED_TERMIOS - -/* - * CONFIGURE_SERDBG_DEVNAME - * use this macro to specify the serial device to use - * for "serdbgio". - * Only used, when CONFIGURE_SERDBG_USE_POLLED_TERMIOS is set - */ -#define CONFIGURE_SERDBG_DEVNAME "/dev/tty03" - -/* - * CONFIGURE_SERDBG_BAUDRATE - * use this macro to specify the baud rate to use - * for "serdbgio". - * Only used, when CONFIGURE_SERDBG_USE_POLLED_TERMIOS is set - */ -#define CONFIGURE_SERDBG_BAUDRATE 57600 - -/* - * CONFIGURE_SERDBG_CALLOUT - * use this macro to specify a routine that will called during I/O polling - * Only used, when CONFIGURE_SERDBG_USE_POLLED_TERMIOS is set - * This function of type "void pollfnc(void)" can be used for e.g. - * tickling a watchdog - */ -/* #define CONFIGURE_SERDBG_CALLOUT tickle_my_watchdog_fnc */ - -#include <serdbgcnf.h> - -/* - * CONFIGURE_USE_TERMIOS_PRINTK - * set this macro, if you want printk output to be sent to a serial - * driver using the polled termios interface - * when set, the printk output function will be connected after driver - * initialization in "bsppost.c" - */ -#define CONFIGURE_USE_TERMIOS_PRINTK - -/* - * CONFIGURE_TERMIOS_PRINTK_DEVNAME - * use this macro to specify the serial device to use - * for printk output. - * Only used, when CONFIGURE_USE_TERMIOS_PRINTK is set - */ -#define CONFIGURE_TERMIOS_PRINTK_DEVNAME "/dev/console" - -/* - * CONFIGURE_TERMIOS_PRINTK_BAUDRATE - * use this macro to specify the baudrate to use - * for printk output. - * Only used, when CONFIGURE_USE_TERMIOS_PRINTK is set - */ -#define CONFIGURE_TERMIOS_PRINTK_BAUDRATE 9600 - -/* - * CONFIGURE_TERMIOS_PRINTK_CALLOUT - * use this macro to specify a routine that will called during I/O polling - * This function of type "void pollfnc(void)" can be used for e.g. - * tickling a watchdog - */ -/* #define CONFIGURE_TERMIOS_PRINTK_CALLOUT tickle_my_watchdog_fnc */ - -#include <termios_printk_cnf.h> diff --git a/cpukit/libmisc/serdbg/serdbg.c b/cpukit/libmisc/serdbg/serdbg.c deleted file mode 100644 index c49e78762a..0000000000 --- a/cpukit/libmisc/serdbg/serdbg.c +++ /dev/null @@ -1,105 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ - -/* - * RTEMS remote gdb over serial line - * - * This file contains intialization and utility functions to add - * a gdb remote debug stub to an RTEMS system. - */ - -/* - * Copyright (c) 2002 IMD Ingenieurbuero fuer Microcomputertechnik - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <rtems/serdbg.h> - - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -int serdbg_init_dbg -( -/*-------------------------------------------------------------------------*\ -| Purpose: | -| initialize remote gdb session over serial line | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ - void -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| rtems_status_code | -\*=========================================================================*/ -{ - static bool is_initialized = false; - - rtems_status_code rc = RTEMS_SUCCESSFUL; - - if (is_initialized) { - return RTEMS_SUCCESSFUL; - } - is_initialized = true; - /* - * try to open serial device - */ - if (rc == RTEMS_SUCCESSFUL) { - if ((serdbg_conf.open_io != NULL) && - (0 > serdbg_conf.open_io(serdbg_conf.devname,serdbg_conf.baudrate))) { - fprintf(stderr, - "remote_gdb_init: cannot open device %s " - "for gdb connection:%s\n",serdbg_conf.devname,strerror(errno)); - rc = RTEMS_IO_ERROR; - } - } - /* - * initialize gdb stub - */ - if (rc == RTEMS_SUCCESSFUL) { - set_debug_traps(); - } - /* - * now activate gdb stub - */ - if ((rc == RTEMS_SUCCESSFUL) && - !serdbg_conf.skip_init_bkpt) { - breakpoint(); - } - - /* - * return to original function - * this may be already unter gdb control - */ - return rc; -} diff --git a/cpukit/libmisc/serdbg/serdbgio.c b/cpukit/libmisc/serdbg/serdbgio.c deleted file mode 100644 index 07c77a0b03..0000000000 --- a/cpukit/libmisc/serdbg/serdbgio.c +++ /dev/null @@ -1,264 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ - -/* - * TERMIOS serial gdb interface support - * the functions in this file allow the standard gdb stubs like - * "m68k-stub.c" to access any serial interfaces that work with - * RTEMS termios in polled mode - */ - -/* - * Copyright (c) 2002 IMD Ingenieurbuero fuer Microcomputertechnik - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems.h> -#include <rtems/libio_.h> -#include <errno.h> -#include <unistd.h> /* close */ -#include <stdio.h> -#include <fcntl.h> -#include <termios.h> - -#include <rtems/termiostypes.h> -#include <rtems/serdbg.h> - - -/* - * internal variables - */ -int serdbg_fd = -1; -struct rtems_termios_tty *serdbg_tty; - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -int serdbg_open - -/*-------------------------------------------------------------------------*\ -| Purpose: | -| try to open given serial debug port | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ -( - const char *dev_name, /* name of device to open */ - uint32_t baudrate /* baud rate to use */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| 0 on success, -1 and errno otherwise | -\*=========================================================================*/ -{ - bool err_occurred = false; - rtems_libio_t *iop = NULL; - struct termios act_termios; - tcflag_t baudcode = B0; - -#define FD_STORE_CNT 3 - int fd_store[FD_STORE_CNT]; - int fd_store_used = 0; - - /* - * translate baudrate into baud code - */ - switch(baudrate) { - case 50: baudcode = B50; break; - case 75: baudcode = B75; break; - case 110: baudcode = B110; break; - case 134: baudcode = B134; break; - case 150: baudcode = B150; break; - case 200: baudcode = B200; break; - case 300: baudcode = B300; break; - case 600: baudcode = B600; break; - case 1200: baudcode = B1200; break; - case 1800: baudcode = B1800; break; - case 2400: baudcode = B2400; break; - case 4800: baudcode = B4800; break; - case 9600: baudcode = B9600; break; - case 19200: baudcode = B19200; break; - case 38400: baudcode = B38400; break; - case 57600: baudcode = B57600; break; - case 115200: baudcode = B115200; break; - case 230400: baudcode = B230400; break; - case 460800: baudcode = B460800; break; - default : err_occurred = true; errno = EINVAL; break; - } - - /* - * open device for serdbg operation - * skip any fds that are between 0..2, because they are - * reserved for stdin/out/err - */ - if (!err_occurred && - (dev_name != NULL) && - (dev_name[0] != '\0')) { - do { - serdbg_fd = open(dev_name,O_RDWR); - if (serdbg_fd < 0) { - err_occurred = true; - } - else { - if (serdbg_fd < 3) { - if (fd_store_used >= FD_STORE_CNT) { - err_occurred = true; - } - else { - fd_store[fd_store_used++] = serdbg_fd; - } - } - } - } while (!err_occurred && - (serdbg_fd < 3)); - } - /* - * close any fds, that have been placed in fd_store - * so fd 0..2 are reusable again - */ - while (--fd_store_used >= 0) { - close(fd_store[fd_store_used]); - } - - /* - * capture tty structure - */ - if (!err_occurred) { - iop = rtems_libio_iop(serdbg_fd); - serdbg_tty = iop->data1; - } - /* - * set device baudrate - * (and transp mode, this is not really needed) - * ... - */ - /* - * ... get fd settings - */ - if (!err_occurred && - (0 != tcgetattr(serdbg_fd,&act_termios))) { - err_occurred = true; - } - if (!err_occurred) { - act_termios.c_iflag - &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - act_termios.c_oflag - &= ~OPOST; - - act_termios.c_lflag - &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - - cfsetospeed(&act_termios,baudcode); - cfsetispeed(&act_termios,baudcode); - - if (0 != tcsetattr(serdbg_fd,TCSANOW,&act_termios)) { - err_occurred = true; - } - } - return (err_occurred - ? -1 - : 0); -} - -void putDebugChar(char c) __attribute__ ((__weak__)); -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -void putDebugChar -/*-------------------------------------------------------------------------*\ -| Purpose: | -| send one character to serial port | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ -( - char c /* character to print */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - /* - * call serdbg polling callout, if available - */ - if (serdbg_conf.callout != NULL) { - serdbg_conf.callout(); - } - /* - * check, whether debug serial port is available - */ - if ((serdbg_tty != NULL) && - (serdbg_tty->device.write != NULL)) { - /* - * send character to debug serial port - */ - serdbg_tty->device.write(serdbg_tty->minor,&c,1); - } -} - -int getDebugChar(void) __attribute__ ((__weak__)); -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -int getDebugChar -/*-------------------------------------------------------------------------*\ -| Purpose: | -| wait for one character from serial port | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ -( - void /* none */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| received character | -\*=========================================================================*/ -{ - int c = -1; - /* - * check, whether debug serial port is available - */ - if ((serdbg_tty != NULL) && - (serdbg_tty->device.pollRead != NULL)) { - do { - /* - * call serdbg polling callout, if available - */ - if (serdbg_conf.callout != NULL) { - serdbg_conf.callout(); - } - /* - * get character from debug serial port - */ - c = serdbg_tty->device.pollRead(serdbg_tty->minor); - } while (c < 0); - } - return c; -} diff --git a/cpukit/libmisc/serdbg/termios_printk.c b/cpukit/libmisc/serdbg/termios_printk.c deleted file mode 100644 index 2b5a7f8e69..0000000000 --- a/cpukit/libmisc/serdbg/termios_printk.c +++ /dev/null @@ -1,245 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ - -/* - * TERMIOS printk support - * this module performs low-level printk output using - * a polled termios driver - */ - -/* - * Copyright (c) 2002 IMD Ingenieurbuero fuer Microcomputertechnik - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems.h> -#include <rtems/libio_.h> -#include <errno.h> -#include <stdio.h> -#include <fcntl.h> -#include <termios.h> - -#include <rtems/termiostypes.h> -#include <rtems/bspIo.h> -#include <rtems/termios_printk.h> - -/* - * internal variables - */ -int termios_printk_fd = -1; -struct rtems_termios_tty *termios_printk_tty; - -static void _termios_printk_null_char( - char c RTEMS_UNUSED) -{ - return; -} - -BSP_output_char_function_type BSP_output_char = _termios_printk_null_char; -BSP_polling_getchar_function_type BSP_poll_char; - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -void termios_printk_outputchar -/*-------------------------------------------------------------------------*\ -| Purpose: | -| send one character to serial port | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ -( - char c /* character to print */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| <none> | -\*=========================================================================*/ -{ - /* - * check, whether printk serial port is available - */ - - if ((termios_printk_tty != NULL) && - (termios_printk_tty->device.write != NULL)) { - /* - * call termios_printk polling callout, if available - */ - if (termios_printk_conf.callout != NULL) { - termios_printk_conf.callout(); - } - /* - * send character to debug serial port - */ - termios_printk_tty->device.write(termios_printk_tty->minor,&c,1); - } -} - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -int termios_printk_inputchar -/*-------------------------------------------------------------------------*\ -| Purpose: | -| wait for one character from serial port | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ -( - void /* none */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| received character | -\*=========================================================================*/ -{ - int c = -1; - /* - * check, whether debug serial port is available - */ - if ((termios_printk_tty != NULL) && - (termios_printk_tty->device.pollRead != NULL)) { - do { - /* - * call termios_printk polling callout, if available - */ - if (termios_printk_conf.callout != NULL) { - termios_printk_conf.callout(); - } - /* - * get character from debug serial port - */ - c = termios_printk_tty->device.pollRead(termios_printk_tty->minor); - } while (c < 0); - } - return c; -} - - -/*=========================================================================*\ -| Function: | -\*-------------------------------------------------------------------------*/ -int termios_printk_open - -/*-------------------------------------------------------------------------*\ -| Purpose: | -| try to open given serial debug port | -+---------------------------------------------------------------------------+ -| Input Parameters: | -\*-------------------------------------------------------------------------*/ -( - const char *dev_name, /* name of device to open */ - uint32_t baudrate /* baud rate to use */ -) -/*-------------------------------------------------------------------------*\ -| Return Value: | -| 0 on success, -1 and errno otherwise | -\*=========================================================================*/ -{ - bool err_occurred = false; - rtems_libio_t *iop = NULL; - struct termios act_termios; - tcflag_t baudcode = B0; - - if (termios_printk_fd >= 0) { - /* - * already initialized - */ - return 0; - } - /* - * translate baudrate into baud code - */ - switch(baudrate) { - case 50: baudcode = B50; break; - case 75: baudcode = B75; break; - case 110: baudcode = B110; break; - case 134: baudcode = B134; break; - case 150: baudcode = B150; break; - case 200: baudcode = B200; break; - case 300: baudcode = B300; break; - case 600: baudcode = B600; break; - case 1200: baudcode = B1200; break; - case 1800: baudcode = B1800; break; - case 2400: baudcode = B2400; break; - case 4800: baudcode = B4800; break; - case 9600: baudcode = B9600; break; - case 19200: baudcode = B19200; break; - case 38400: baudcode = B38400; break; - case 57600: baudcode = B57600; break; - case 115200: baudcode = B115200; break; - case 230400: baudcode = B230400; break; - case 460800: baudcode = B460800; break; - default : err_occurred = true; errno = EINVAL; break; - } - /* - * open device for serdbg operation - */ - if (!err_occurred && - (dev_name != NULL) && - (dev_name[0] != '\0')) { - termios_printk_fd = open(dev_name,O_RDWR); - if (termios_printk_fd < 0) { - err_occurred = true; - } - } - /* - * capture tty structure - */ - if (!err_occurred) { - iop = rtems_libio_iop(termios_printk_fd); - termios_printk_tty = iop->data1; - } - /* - * set device baudrate - * (and transp mode, this is not really needed) - * ... - */ - /* - * ... get fd settings - */ - if (!err_occurred && - (0 != tcgetattr(termios_printk_fd,&act_termios))) { - err_occurred = true; - } - if (!err_occurred) { - - cfsetospeed(&act_termios,baudcode); - cfsetispeed(&act_termios,baudcode); - - if (0 != tcsetattr(termios_printk_fd,TCSANOW,&act_termios)) { - err_occurred = true; - } - } - if (!err_occurred) { - BSP_output_char = termios_printk_outputchar; - BSP_poll_char = termios_printk_inputchar; - } - return (err_occurred - ? -1 - : 0); -} diff --git a/cpukit/libmisc/shell/login_check.c b/cpukit/libmisc/shell/login_check.c index 5ba2332070..d9bce28a7d 100644 --- a/cpukit/libmisc/shell/login_check.c +++ b/cpukit/libmisc/shell/login_check.c @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2009-2014 embedded brains GmbH and others. + * Copyright (C) 2009, 2014 embedded brains GmbH & Co. KG * * Based on work from Chris Johns and Fernando Ruiz. * diff --git a/cpukit/libmisc/shell/login_prompt.c b/cpukit/libmisc/shell/login_prompt.c index 6eda753607..149966be63 100644 --- a/cpukit/libmisc/shell/login_prompt.c +++ b/cpukit/libmisc/shell/login_prompt.c @@ -48,7 +48,7 @@ * * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 * - * Copyright (c) 2009 embedded brains GmbH and others. + * Copyright (c) 2009 embedded brains GmbH & Co. KG * * Based on work from Chris Johns, Fernando Ruiz and Till Straumann. * diff --git a/cpukit/libmisc/shell/main_blkstats.c b/cpukit/libmisc/shell/main_blkstats.c index 294dd1b7d9..3acc652d87 100644 --- a/cpukit/libmisc/shell/main_blkstats.c +++ b/cpukit/libmisc/shell/main_blkstats.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * Copyright (c) 2012 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/main_chmod.c b/cpukit/libmisc/shell/main_chmod.c index 1f646d92d4..9a42cbd940 100644 --- a/cpukit/libmisc/shell/main_chmod.c +++ b/cpukit/libmisc/shell/main_chmod.c @@ -56,7 +56,7 @@ static int rtems_shell_main_chmod( * Now change the files modes */ for (n=2 ; n < argc ; n++) { - sc = chmod(argv[n++], mode); + sc = chmod(argv[n], mode); _Assert_Unused_variable_unequal(sc, -1); } diff --git a/cpukit/libmisc/shell/main_cmdchmod.c b/cpukit/libmisc/shell/main_cmdchmod.c index dee4d899a8..b6ec03bd5d 100644 --- a/cpukit/libmisc/shell/main_cmdchmod.c +++ b/cpukit/libmisc/shell/main_cmdchmod.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * Copyright (c) 2014 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/main_cmdchown.c b/cpukit/libmisc/shell/main_cmdchown.c index 6ceab0f5b1..ba44d70ebb 100644 --- a/cpukit/libmisc/shell/main_cmdchown.c +++ b/cpukit/libmisc/shell/main_cmdchown.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * Copyright (c) 2014 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/main_cmdls.c b/cpukit/libmisc/shell/main_cmdls.c index ab11c83892..529e070e8b 100644 --- a/cpukit/libmisc/shell/main_cmdls.c +++ b/cpukit/libmisc/shell/main_cmdls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * Copyright (c) 2014 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/main_cpuinfo.c b/cpukit/libmisc/shell/main_cpuinfo.c index 846f5efd4a..70179dcee8 100644 --- a/cpukit/libmisc/shell/main_cpuinfo.c +++ b/cpukit/libmisc/shell/main_cpuinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * Copyright (c) 2016 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/main_drvmgr.c b/cpukit/libmisc/shell/main_drvmgr.c index bdf8d1c9ae..6090dde6b1 100644 --- a/cpukit/libmisc/shell/main_drvmgr.c +++ b/cpukit/libmisc/shell/main_drvmgr.c @@ -1,12 +1,31 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * DRVMGR Command Implementation * * COPYRIGHT (c) 2010. * Cobham Gaisler AB. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H diff --git a/cpukit/libmisc/shell/main_edit.c b/cpukit/libmisc/shell/main_edit.c index 4cc742719a..8317452b7b 100644 --- a/cpukit/libmisc/shell/main_edit.c +++ b/cpukit/libmisc/shell/main_edit.c @@ -412,6 +412,9 @@ static void move_gap(struct editor *ed, int pos, int minsize) { if (gapsize + MINEXTEND > minsize) minsize = gapsize + MINEXTEND; newsize = (ed->end - ed->start) - gapsize + minsize; start = (unsigned char *) malloc(newsize); // TODO check for out of memory + if (start == NULL) { + return; + } gap = start + pos; rest = gap + minsize; end = start + newsize; @@ -755,8 +758,23 @@ static void get_console_size(struct env *env) { env->cols = ws.ws_col; env->lines = ws.ws_row - 1; #elif defined(__rtems__) - env->cols = 80; + char* e; env->lines = 25; + env->cols = 80; + e = getenv("LINES"); + if (e != NULL) { + int lines = strtol(e, 0, 10); + if (lines > 0) { + env->lines = lines - 1; + } + } + e = getenv("COLUMNS"); + if (e != NULL) { + int cols = strtol(e, 0, 10); + if (cols > 0) { + env->cols = cols; + } + } #else struct term *term = gettib()->proc->term; env->cols = term->cols; @@ -1695,7 +1713,6 @@ static void copy_selection(struct editor *ed) { ed->env->clipboard = (unsigned char *) realloc(ed->env->clipboard, ed->env->clipsize); if (!ed->env->clipboard) return; copy(ed, ed->env->clipboard, selstart, ed->env->clipsize); - select_toggle(ed); } static void cut_selection(struct editor *ed) { @@ -1794,14 +1811,14 @@ static void save_editor(struct editor *ed) { ed->refresh = 1; } -static void close_editor(struct editor *ed) { +static struct editor* close_editor(struct editor *ed) { struct env *env = ed->env; if (ed->dirty) { display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename); if (!ask()) { ed->refresh = 1; - return; + return ed; } } @@ -1813,6 +1830,7 @@ static void close_editor(struct editor *ed) { new_file(ed, ""); } ed->refresh = 1; + return ed; } static void pipe_command(struct editor *ed) { @@ -2113,7 +2131,7 @@ static void edit(struct editor *ed) { case ctrl('e'): select_toggle(ed); break; case ctrl('a'): select_all(ed); break; - case ctrl('c'): copy_selection(ed); break; + case ctrl('c'): copy_selection(ed);select_toggle(ed); break; case ctrl('f'): find_text(ed, 0); break; case ctrl('l'): goto_line(ed); break; case ctrl('g'): find_text(ed, 1); break; @@ -2136,15 +2154,7 @@ static void edit(struct editor *ed) { case ctrl('s'): save_editor(ed); break; case ctrl('p'): pipe_command(ed); break; #endif -#if defined(__rtems__) - /* - * Coverity spotted this as using ed after free() so changing - * the order of the statements. - */ - case ctrl('w'): ed = ed->env->current; close_editor(ed); break; -#else - case ctrl('w'): close_editor(ed); ed = ed->env->current; break; -#endif + case ctrl('w'): ed = close_editor(ed); break; } } } diff --git a/cpukit/libmisc/shell/main_flashdev.c b/cpukit/libmisc/shell/main_flashdev.c new file mode 100644 index 0000000000..ca2454b33c --- /dev/null +++ b/cpukit/libmisc/shell/main_flashdev.c @@ -0,0 +1,584 @@ +/* + * Copyright (C) 2023 Aaron Nyholm + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <errno.h> +#include <rtems/shell.h> + +#include <dev/flash/flashdev.h> + +static int flashdev_shell_read(char *dev_path, int argc, char *argv[]); +static int flashdev_shell_write(char *dev_path, int argc, char *argv[]); +static int flashdev_shell_erase(char *dev_path, int argc, char *argv[]); +static int flashdev_shell_type(char *dev_path); +static int flashdev_shell_jedecid(char *dev_path); +static int flashdev_shell_page_off(char *dev_path, int argc, char *argv[]); +static int flashdev_shell_page_idx(char *dev_path, int argc, char *argv[]); +static int flashdev_shell_pg_count(char *dev_path); +static int flashdev_shell_wb_size(char *dev_path); + +static int flashdev_shell_ioctl_value( + char *dev_path, + int ioctl_call, + void *ret +); + +static int flashdev_shell_page( + char *dev_path, + int argc, + char *argv[], + int ioctl_call +); + +static const char rtems_flashdev_shell_usage [] = + "simple flash read / write / erase\n" + "\n" + "flashdev <FLASH_DEV_PATH> [OPTION]\n" + " -r <address> <bytes> Read at address for bytes\n" + " -w <address> <file> Write file to address\n" + " -e <address> <bytes> Erase at address for bytes\n" + " -t Print the flash type\n" + " -d Print the JEDEC ID of flash device\n" + " -o <address> Print the page information of page at address\n" + " -i <index> Print the page information of page at index\n" + " -p Print the number of pages\n" + " -b Print the write block size\n" + " -h Print this help\n"; + + +static int rtems_flashdev_shell_main( int argc, char *argv[] ) { + + char *dev_path = NULL; + int i; + + for (i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + /* + * Check that a path to flashdev has been provided before running + * command. + */ + if (dev_path == NULL) { + printf("Please input FLASH_DEV_PATH before instruction\n"); + return 1; + } + /* Run command */ + switch (argv[i][1]) { + case ('r'): + /* Read */ + return flashdev_shell_read(dev_path, argc, &argv[i]); + case ('w'): + /* Write */ + return flashdev_shell_write(dev_path, argc, &argv[i]); + case ('e'): + /* Erase */ + return flashdev_shell_erase(dev_path, argc, &argv[i]); + case ('t'): + /* Flash Type */ + return flashdev_shell_type(dev_path); + case ('d'): + /* JEDEC Id */ + return flashdev_shell_jedecid(dev_path); + case ('o'): + /* Page info by offset */ + return flashdev_shell_page_off(dev_path, argc, &argv[i]); + case ('i'): + /* Page info by index */ + return flashdev_shell_page_idx(dev_path, argc, &argv[i]); + case ('p'): + /* Page count */ + return flashdev_shell_pg_count(dev_path); + case ('b'): + /* Write block size */ + return flashdev_shell_wb_size(dev_path); + case ('h'): + default: + /* Help */ + printf(rtems_flashdev_shell_usage); + break; + } + } else if (dev_path == NULL) { + dev_path = argv[i]; + } else { + printf("Invalid argument: %s\n", argv[i]); + return 1; + } + } + + if (argc == 1) { + printf(rtems_flashdev_shell_usage); + } + + return 0; +} + +int flashdev_shell_read( + char *dev_path, + int argc, + char *argv[] +) +{ + uint32_t address; + uint32_t bytes; + int fd; + int status; + void *buffer; + + /* Check arguments */ + if (argc < 5) { + printf("Missing argument\n"); + return -1; + } + + /* Get arguments */ + errno = 0; + address = (uint32_t) strtoul(argv[1], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + errno = 0; + bytes = (uint32_t) strtoul(argv[2], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + + /* Open flash device */ + fd = open(dev_path, O_RDONLY); + if (fd == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + + /* Move to address */ + status = lseek(fd, address, SEEK_SET); + if (status == -1) { + printf("Reading failed\n"); + close(fd); + return -1; + } + + /* Create a buffer to read into */ + buffer = calloc((bytes + bytes%4), 1); + if (buffer == NULL) { + printf("Failed to allocate read buffer\n"); + close(fd); + return -1; + } + + /* Read into buffer */ + status = read(fd, buffer, bytes); + if (status == -1) { + printf("Reading failed\n"); + free(buffer); + close(fd); + return -1; + } + + /* Print buffer out in 32bit blocks */ + printf("Reading %s at 0x%08x for %d bytes\n", dev_path, address, bytes); + for (int i = 0; i < (bytes/4); i++) { + printf("%08x ", ((uint32_t*)buffer)[i]); + if ((i+1)%4 == 0) { + printf("\n"); + } + } + printf("\n"); + + /* Clean up */ + free(buffer); + close(fd); + return 0; +} + +int flashdev_shell_write( + char *dev_path, + int argc, + char *argv[] +) +{ + uint32_t address; + int flash; + int file; + int status; + int read_len; + off_t length; + void *buffer; + uint32_t offset; + char *file_path; + + /* Check arguments */ + if (argc < 5) { + printf("Missing argument\n"); + return -1; + } + + /* Get arguments */ + errno = 0; + address = (uint32_t) strtoul(argv[1], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + errno = 0; + file_path = argv[2]; + + /* Open flash device and move to write offset */ + flash = open(dev_path, O_WRONLY); + if (flash == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + status = lseek(flash, address, SEEK_SET); + if (status == -1) { + printf("Reading failed\n"); + close(flash); + return -1; + } + + /* Open file and get file length */ + file = open(file_path, O_RDONLY); + if (file == -1) { + printf("Couldn't open %s\n", file_path); + close(flash); + return -1; + } + + length = lseek(file, 0, SEEK_END); + if (length == -1) { + close(flash); + close(file); + printf("Couldn't find length of file\n"); + return -1; + } + + if (lseek(file, 0, SEEK_SET) == -1) { + close(flash); + close(file); + printf("Couldn't find length of file\n"); + return -1; + } + + /* Create buffer */ + buffer = calloc(1, 0x1000); + + /* Write file to flash device in 0x1000 byte chunks */ + offset = 0; + while (offset != length) { + + read_len = length - offset; + if (read_len > 0x1000) { + read_len = 0x1000; + } + + status = read(file, buffer, read_len); + if (status == -1) { + free(buffer); + close(flash); + close(file); + printf("Can't read %s\n", file_path); + return -1; + } + + status = write(flash, buffer, read_len); + if (status == -1) { + free(buffer); + close(flash); + close(file); + printf("Can't write %s\n", dev_path); + return -1; + } + + offset = offset + read_len; + } + + /* Clean up */ + close(flash); + close(file); + free(buffer); + return 0; +} + +int flashdev_shell_erase( + char *dev_path, + int argc, + char *argv[] +) +{ + uint32_t address; + uint32_t bytes; + int fd; + int status; + rtems_flashdev_region args; + + /* Check arguments */ + if (argc < 5) { + printf("Missing argument\n"); + return -1; + } + + /* Get arguments */ + errno = 0; + address = (uint32_t) strtoul(argv[1], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + errno = 0; + bytes = (uint32_t) strtoul(argv[2], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + + /* Open flash device */ + fd = open(dev_path, O_RDWR); + if (fd == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + + printf("Erasing at %08x for %x bytes\n", address, bytes); + + /* Erase flash */ + args.offset = address; + args.size = bytes; + + status = ioctl(fd, RTEMS_FLASHDEV_IOCTL_ERASE, &args); + if (status == -1) { + printf("Erase failed\n"); + close(fd); + return -1; + } + + /* Clean up */ + close(fd); + + return 0; +} + +int flashdev_shell_type( char *dev_path ) +{ + int type; + int status; + + /* Get type */ + status = flashdev_shell_ioctl_value( + dev_path, + RTEMS_FLASHDEV_IOCTL_TYPE, + &type + ); + + if (status) { + printf("Failed to get flash type\n"); + return status; + } + + /* Print type */ + switch(type) { + case RTEMS_FLASHDEV_NOR: + printf("NOR flash\n"); + break; + case RTEMS_FLASHDEV_NAND: + printf("NAND flash\n"); + break; + default: + printf("Unknown type\n"); + } + + return 0; +} + +int flashdev_shell_jedecid( char *dev_path ) { + uint32_t ret; + int status; + + /* Get JEDEC Id */ + status = flashdev_shell_ioctl_value( + dev_path, + RTEMS_FLASHDEV_IOCTL_JEDEC_ID, + &ret + ); + + /* Print JEDEC Id */ + if (status) { + printf("Failed to get JEDEC Id\n"); + return status; + } else { + printf("JEDEC Id: 0x%x\n", ret); + } + return 0; +} + +static int flashdev_shell_page_off( + char *dev_path, + int argc, + char *argv[] +) +{ + return flashdev_shell_page( + dev_path, + argc, + argv, + RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_OFFSET + ); +} + +static int flashdev_shell_page_idx( + char *dev_path, + int argc, + char *argv[] +) +{ + return flashdev_shell_page( + dev_path, + argc, + argv, + RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_INDEX + ); +} + +static int flashdev_shell_pg_count( char *dev_path ) +{ + uint32_t ret; + int status; + + /* Get Page Count */ + status = flashdev_shell_ioctl_value( + dev_path, + RTEMS_FLASHDEV_IOCTL_PAGE_COUNT, + &ret + ); + + /* Print Page Count */ + if (status) { + printf("Failed to get page count\n"); + return status; + } else { + printf("Page count: 0x%x\n", ret); + } + return 0; +} + +static int flashdev_shell_wb_size( char *dev_path ) +{ + size_t ret; + int status; + + /* Get Write Block Size */ + status = flashdev_shell_ioctl_value( + dev_path, + RTEMS_FLASHDEV_IOCTL_WRITE_BLOCK_SIZE, + &ret + ); + + /* Print Write Block Size */ + if (status) { + printf("Failed to get write block size\n"); + return status; + } else { + printf("Write block size: 0x%zx\n", ret); + } + return 0; +} + +static int flashdev_shell_ioctl_value( + char *dev_path, + int ioctl_call, + void *ret +) +{ + int fd; + int status; + + fd = open(dev_path, O_RDONLY); + if (fd == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + + status = ioctl(fd, ioctl_call, ret); + if (status == -1) { + close(fd); + return -1; + } + + close(fd); + return 0; +} + +static int flashdev_shell_page( + char *dev_path, + int argc, + char *argv[], + int ioctl_call +) +{ + rtems_flashdev_ioctl_page_info pg_info; + int fd; + int status; + + /* Check arguments */ + if (argc < 4) { + printf("Missing argument\n"); + return -1; + } + + /* Get arguments */ + errno = 0; + pg_info.location = (off_t) strtoul(argv[1], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + + /* Open flash device */ + fd = open(dev_path, O_RDWR); + if (fd == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + + status = ioctl(fd, ioctl_call, &pg_info); + if (status == -1) { + printf("Failed to get page info\n"); + close(fd); + return -1; + } + + printf( + "Page offset: 0x%jx\nPage length: 0x%zx\n", + pg_info.page_info.offset, + pg_info.page_info.size + ); + + /* Clean up */ + close(fd); + return 0; +} + +rtems_shell_cmd_t rtems_shell_FLASHDEV_Command = { + .name = "flashdev", + .usage = rtems_flashdev_shell_usage, + .topic = "misc", + .command = rtems_flashdev_shell_main, +}; diff --git a/cpukit/libmisc/shell/main_help.c b/cpukit/libmisc/shell/main_help.c index 564bc30a9c..e6d939d08f 100644 --- a/cpukit/libmisc/shell/main_help.c +++ b/cpukit/libmisc/shell/main_help.c @@ -22,23 +22,34 @@ #include "internal.h" #include <string.h> +static int rtems_shell_help_pause(int line, int lines) { + if (lines && line >= lines - 1) { + printf("\rPress any key to continue..."); + (void) getchar(); + printf("\r%*c\r", 29, ' '); + line = 0; + } + return line; +} + /* * show the help for one command. */ static int rtems_shell_help_cmd( - const rtems_shell_cmd_t *shell_cmd + const rtems_shell_cmd_t *shell_cmd, int indent, int line, + int cols, int lines ) { const char * pc; - int col,line; + int col; if (!rtems_shell_can_see_cmd(shell_cmd)) { return 0; } - printf("%-12.12s - ",shell_cmd->name); - col = 14; - line = 1; + printf("%-*s - ", indent, shell_cmd->name); + indent += 3; + col = indent; if (shell_cmd->alias) { printf("is an <alias> for command '%s'",shell_cmd->alias->name); } else if (shell_cmd->usage) { @@ -48,8 +59,10 @@ static int rtems_shell_help_cmd( case '\r': break; case '\n': - putchar('\n'); - col = 0; + if (*(pc + 1) != '\0') { + putchar('\n'); + col = 0; + } break; default: putchar(*pc); @@ -57,19 +70,21 @@ static int rtems_shell_help_cmd( break; } pc++; - if (col>78) { /* What daring... 78?*/ + if (col > (cols - 3)) { if (*pc) { putchar('\n'); col = 0; } } - if (!col && *pc) { - printf(" "); - col = 12;line++; + if (col == 0 && *pc) { + line = rtems_shell_help_pause(line + 1, lines); + printf("%*c", indent, ' '); + col = indent; } } } puts(""); + line = rtems_shell_help_pause(line + 1, lines); return line; } @@ -83,15 +98,27 @@ static int rtems_shell_help( char * argv[] ) { - int col,line,lines,arg; - char* lines_env; + int col,line,cols,lines,arg,indent; + char *lines_env, *cols_env; rtems_shell_topic_t *topic; + rtems_shell_cmd_t *shell_cmd; + lines = 16; + cols = 80; lines_env = getenv("SHELL_LINES"); - if (lines_env) + if (lines_env) { lines = strtol(lines_env, 0, 0); - else - lines = 16; + } else { + lines_env = getenv("LINES"); + if (lines_env) { + lines = strtol(lines_env, 0, 0); + } + } + + cols_env = getenv("COLUMNS"); + if (cols_env) { + cols = strtol(cols_env, 0, 0); + } if (argc<2) { printf("help: The topics are\n"); @@ -101,7 +128,7 @@ static int rtems_shell_help( if (!col){ col = printf(" %s",topic->topic); } else { - if ((col+strlen(topic->topic)+2)>78){ + if ((col+strlen(topic->topic)+2)>(cols - 2)){ printf("\n"); col = printf(" %s",topic->topic); } else { @@ -113,18 +140,19 @@ static int rtems_shell_help( printf("\n"); return 1; } + indent = 0; + shell_cmd = rtems_shell_first_cmd; + while (shell_cmd) { + size_t len = strlen(shell_cmd->name); + if (len > indent) { + indent = len; + } + shell_cmd = shell_cmd->next; + } line = 0; for (arg = 1;arg<argc;arg++) { const char *cur = argv[arg]; - rtems_shell_cmd_t *shell_cmd; - - if (lines && (line > lines)) { - printf("Press any key to continue..."); - (void) getchar(); /* we only want to know a character was pressed */ - printf("\n"); - line = 0; - } - topic = rtems_shell_lookup_topic(cur); + topic = rtems_shell_lookup_topic(cur); if (topic == NULL) { if ((shell_cmd = rtems_shell_lookup_cmd(cur)) == NULL) { if (strcmp(cur, "all") != 0) { @@ -132,11 +160,11 @@ static int rtems_shell_help( "help: topic or cmd '%s' not found. Try <help> alone for a list\n", cur ); - line++; + line = rtems_shell_help_pause(line + 1, lines); continue; } } else { - line+= rtems_shell_help_cmd(shell_cmd); + line = rtems_shell_help_cmd(shell_cmd, indent, line, cols, lines); continue; } } @@ -144,18 +172,12 @@ static int rtems_shell_help( line++; shell_cmd = rtems_shell_first_cmd; while (shell_cmd) { - if (topic == NULL || !strcmp(topic->topic,shell_cmd->topic)) - line+= rtems_shell_help_cmd(shell_cmd); - if (lines && (line > lines)) { - printf("Press any key to continue..."); - (void) getchar(); - printf("\n"); - line = 0; + if (topic == NULL || !strcmp(topic->topic,shell_cmd->topic)) { + line = rtems_shell_help_cmd(shell_cmd, indent, line, cols, lines); } shell_cmd = shell_cmd->next; } } - puts(""); return 0; } diff --git a/cpukit/libmisc/shell/main_i2cdetect.c b/cpukit/libmisc/shell/main_i2cdetect.c index e953b4eaef..1a863434b7 100644 --- a/cpukit/libmisc/shell/main_i2cdetect.c +++ b/cpukit/libmisc/shell/main_i2cdetect.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2020 embedded brains GmbH. + * Copyright (C) 2020 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libmisc/shell/main_i2cget.c b/cpukit/libmisc/shell/main_i2cget.c index ffa551308b..5726c6ea14 100644 --- a/cpukit/libmisc/shell/main_i2cget.c +++ b/cpukit/libmisc/shell/main_i2cget.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2020 embedded brains GmbH. + * Copyright (C) 2020 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libmisc/shell/main_i2cset.c b/cpukit/libmisc/shell/main_i2cset.c index d9025b3b28..cdc42a57f9 100644 --- a/cpukit/libmisc/shell/main_i2cset.c +++ b/cpukit/libmisc/shell/main_i2cset.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2020 embedded brains GmbH. + * Copyright (C) 2020 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libmisc/shell/main_lsof.c b/cpukit/libmisc/shell/main_lsof.c index efe886e6de..2cc35f96fe 100644 --- a/cpukit/libmisc/shell/main_lsof.c +++ b/cpukit/libmisc/shell/main_lsof.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 embedded brains GmbH. All rights reserved. + * Copyright (C) 2012, 2014 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/main_mmove.c b/cpukit/libmisc/shell/main_mmove.c index 38731b10a2..0029882d62 100644 --- a/cpukit/libmisc/shell/main_mmove.c +++ b/cpukit/libmisc/shell/main_mmove.c @@ -62,7 +62,7 @@ static int rtems_shell_main_mmove( /* * Now copy the memory. */ - memcpy(dst, src, length); + memmove(dst, src, length); return 0; } diff --git a/cpukit/libmisc/shell/main_pci.c b/cpukit/libmisc/shell/main_pci.c index 08fdae78ae..4902ed07b9 100644 --- a/cpukit/libmisc/shell/main_pci.c +++ b/cpukit/libmisc/shell/main_pci.c @@ -1,11 +1,30 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* LIBPCI Command Implementation * * COPYRIGHT (c) 2010. * Cobham Gaisler AB. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H @@ -356,7 +375,7 @@ static int shell_pci_infodev( printf(" PCIID: 0x%04x\n", dev->busdevfun); bus = dev->bus; if (!bus) { - printf(" AT BUS: 0x%x via Host Bridge\n", bus->num); + printf(" AT BUS: via Host Bridge\n"); } else { printf(" AT BUS: 0x%x via Bridge at [%x:%x:%x]\n", bus->num, PCI_DEV_EXPAND(bus->dev.busdevfun)); diff --git a/cpukit/libmisc/shell/main_profreport.c b/cpukit/libmisc/shell/main_profreport.c index a3c64a5e5d..ab14cc1e49 100644 --- a/cpukit/libmisc/shell/main_profreport.c +++ b/cpukit/libmisc/shell/main_profreport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * Copyright (c) 2015 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/main_rtc.c b/cpukit/libmisc/shell/main_rtc.c index 21ca8bb9d1..940c7c9b52 100644 --- a/cpukit/libmisc/shell/main_rtc.c +++ b/cpukit/libmisc/shell/main_rtc.c @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2009 embedded brains GmbH. All rights reserved. + * Copyright (c) 2009 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/main_spi.c b/cpukit/libmisc/shell/main_spi.c index 487a22fc6c..9c47ba0054 100644 --- a/cpukit/libmisc/shell/main_spi.c +++ b/cpukit/libmisc/shell/main_spi.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2020 embedded brains GmbH. + * Copyright (C) 2020 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libmisc/shell/shell-wait-for-input.c b/cpukit/libmisc/shell/shell-wait-for-input.c index db1387baf3..60d6ea4225 100644 --- a/cpukit/libmisc/shell/shell-wait-for-input.c +++ b/cpukit/libmisc/shell/shell-wait-for-input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 embedded brains GmbH. All rights reserved. + * Copyright (c) 2011 embedded brains GmbH & Co. KG * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c index 64f90be121..9cefc80255 100644 --- a/cpukit/libmisc/shell/shell.c +++ b/cpukit/libmisc/shell/shell.c @@ -1,6 +1,6 @@ /** * @file - * + * * @brief Instantatiate a new terminal shell. */ @@ -805,6 +805,183 @@ void rtems_shell_print_env( } #endif +/* + * Wait for the string to return or timeout. + */ +static bool rtems_shell_term_wait_for(const int fd, const char* str, const int timeout) +{ + int msec = timeout; + int i = 0; + while (msec-- > 0 && str[i] != '\0') { + char ch[2]; + if (read(fd, &ch[0], 1) == 1) { + fflush(stdout); + if (ch[0] != str[i++]) { + return false; + } + msec = timeout; + } else { + usleep(1000); + } + } + if (msec == 0) { + return false; + } + return true; +} + +/* + * Buffer a string up to the end string + */ +static int rtems_shell_term_buffer_until(const int fd, + char* buf, + const int size, + const char* end, + const int timeout) +{ + int msec = timeout; + int i = 0; + int e = 0; + memset(&buf[0], 0, size); + while (msec-- > 0 && i < size && end[e] != '\0') { + char ch[2]; + if (read(fd, &ch[0], 1) == 1) { + fflush(stdout); + buf[i++] = ch[0]; + if (ch[0] == end[e]) { + e++; + } else { + e = 0; + } + msec = timeout; + } else { + usleep(1000); + } + } + if (msec == 0 || end[e] != '\0') { + return -1; + } + i -= e; + if (i < size) { + buf[i] = '\0'; + } + return i; +} + +/* + * Determine if the terminal has the row and column values + * swapped + * + * https://github.com/tmux/tmux/issues/3457 + * + * Tmux has a bug where the lines and cols are swapped. There is a lag + * in the time it takes to get the fix into code so see if tmux is + * running and which version and work around the bug. + * + * The terminal device needs to have VMIN=0, and VTIME=0 + */ +static bool rtems_shell_term_row_column_swapped(const int fd, const int timeout) { + char buf[64]; + memset(&buf[0], 0, sizeof(buf)); + /* + * CSI > Ps q + * Ps = 0 => DCS > | text ST + */ + fputs("\033[>0q", stdout); + fflush(stdout); + if (rtems_shell_term_wait_for(fd, "\033P>|", timeout)) { + int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "\033\\", timeout); + if (len > 0) { + if (memcmp(buf, "tmux ", 5) == 0) { + static const char* bad_versions[] = { + "3.2", "3.2a", "3.3", "3.3a" + }; + size_t i; + for (i = 0; i < RTEMS_ARRAY_SIZE(bad_versions); ++i) { + if (strcmp(bad_versions[i], buf + 5) == 0) { + return true; + } + } + } + } + } + return false; +} + +/* + * Direct method to get the size of an XTERM window. + * + * If you do not use an XTERM the env variables are not define. + */ +static void rtems_shell_winsize( void ) +{ + const int fd = fileno(stdin); + struct winsize ws; + const int timeout = 150; + char buf[64]; + bool ok = false; + int lines = 0; + int cols = 0; + int r; + r = ioctl(fd, TIOCGWINSZ, &ws); + if (r == 0) { + ok = true; + lines = ws.ws_row; + cols = ws.ws_col; + } else if (isatty(fd)) { + struct termios cterm; + if (tcgetattr(fd, &cterm) >= 0) { + struct termios term = cterm; + term.c_cc[VMIN] = 0; + term.c_cc[VTIME] = 0; + if (tcsetattr (fd, TCSADRAIN, &term) >= 0) { + memset(&buf[0], 0, sizeof(buf)); + /* + * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Miscellaneous + * + * CSI 1 8 t + */ + fputs("\033[18t", stdout); + fflush(stdout); + if (rtems_shell_term_wait_for(fd, "\033[8;", timeout)) { + int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), ";", timeout); + if (len > 0) { + int i; + lines = 0; + i = 0; + while (i < len) { + lines *= 10; + lines += buf[i++] - '0'; + } + len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "t", timeout); + if (len > 0) { + cols = 0; + i = 0; + while (i < len) { + cols *= 10; + cols += buf[i++] - '0'; + } + ok = true; + } + } + } + } + if (rtems_shell_term_row_column_swapped(fd, timeout)) { + int tmp = lines; + lines = cols; + cols = tmp; + } + tcsetattr (fd, TCSADRAIN, &cterm); + } + } + if (ok) { + snprintf(buf, sizeof(buf) - 1, "%d", lines); + setenv("LINES", buf, 1); + snprintf(buf, sizeof(buf) - 1, "%d", cols); + setenv("COLUMNS", buf, 1); + } +} + static rtems_task rtems_shell_task(rtems_task_argument task_argument) { rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument; @@ -984,7 +1161,9 @@ static bool shell_main_loop( memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE); if (!rtems_shell_make_args(cmd_argv, &argc, argv, RTEMS_SHELL_MAXIMUM_ARGUMENTS)) { - int exit_code = rtems_shell_execute_cmd(argv[0], argc, argv); + int exit_code; + rtems_shell_winsize(); + exit_code = rtems_shell_execute_cmd(argv[0], argc, argv); if (shell_env->exit_code != NULL) *shell_env->exit_code = exit_code; if (exit_code != 0 && shell_env->exit_on_error) diff --git a/cpukit/libmisc/stackchk/check.c b/cpukit/libmisc/stackchk/check.c index 48342ce957..53b96f462c 100644 --- a/cpukit/libmisc/stackchk/check.c +++ b/cpukit/libmisc/stackchk/check.c @@ -413,134 +413,166 @@ static inline void *Stack_check_Find_high_water_mark( return (void *) base; #endif - return (void *)0; + return NULL; } -static bool Stack_check_Dump_stack_usage( - const Stack_Control *stack, - const void *current, - const char *name, - uint32_t id, - const rtems_printer *printer +static void Stack_check_Visit_stack( + const Stack_Control *stack, + const void *current, + const char *name, + rtems_id id, + rtems_stack_checker_visitor visit, + void *arg ) { - uint32_t size; - uint32_t used; - void *low; - void *high_water_mark; + rtems_stack_checker_info info; /* This is likely to occur if the stack checker is not actually enabled */ if ( stack->area == NULL ) { - return false; + return; } - low = Stack_check_Usable_stack_start(stack); - size = Stack_check_Usable_stack_size(stack); + info.id = id; + info.name = name; + info.current = current; + info.begin = Stack_check_Usable_stack_start( stack ); + info.size = Stack_check_Usable_stack_size( stack ); - high_water_mark = Stack_check_Find_high_water_mark(low, size); + if ( Stack_check_Initialized ) { + void *high_water_mark; - if ( high_water_mark ) - used = Stack_check_Calculate_used( low, size, high_water_mark ); - else - used = 0; + high_water_mark = + Stack_check_Find_high_water_mark( info.begin, info.size ); - rtems_printf( - printer, - "0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRId32 " ", - id, - name, - (uintptr_t) stack->area, - (uintptr_t) stack->area + (uintptr_t) stack->size - 1, - (uintptr_t) current, - size - ); - - if (Stack_check_Initialized) { - rtems_printf( printer, "%6" PRId32 "\n", used ); + if ( high_water_mark != NULL ) { + info.used = + Stack_check_Calculate_used( info.begin, info.size, high_water_mark ); + } else { + info.used = 0; + } } else { - rtems_printf( printer, "N/A\n" ); + info.used = UINTPTR_MAX; } - return false; + ( *visit )( &info, arg ); } -static bool Stack_check_Dump_threads_usage( +typedef struct { + rtems_stack_checker_visitor visit; + void *arg; +} Stack_check_Visitor; + +static bool Stack_check_Visit_thread( Thread_Control *the_thread, void *arg ) { + Stack_check_Visitor *visitor; char name[ 22 ]; - const rtems_printer *printer; uintptr_t sp = _CPU_Context_Get_SP( &the_thread->Registers ); - printer = arg; + visitor = arg; _Thread_Get_name( the_thread, name, sizeof( name ) ); - Stack_check_Dump_stack_usage( + Stack_check_Visit_stack( &the_thread->Start.Initial_stack, (void *) sp, name, the_thread->Object.id, - printer + visitor->visit, + visitor->arg ); return false; } -static void Stack_check_Dump_interrupt_stack_usage( - const Stack_Control *stack, - uint32_t id, - const rtems_printer *printer +static void Stack_check_Visit_interrupt_stack( + const Stack_Control *stack, + uint32_t id, + rtems_stack_checker_visitor visit, + void *arg ) { - Stack_check_Dump_stack_usage( + Stack_check_Visit_stack( stack, NULL, "Interrupt Stack", id, - printer + visit, + arg ); } -/* - * rtems_stack_checker_report_usage - */ +static void Stack_check_Print_info( + const rtems_stack_checker_info *info, + void *arg +) +{ + const rtems_printer *printer; + + printer = arg; + + rtems_printf( + printer, + "0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRIuPTR " ", + info->id, + info->name, + (uintptr_t) info->begin, + (uintptr_t) info->begin + info->size - 1, + (uintptr_t) info->current, + info->size + ); + + if ( info->used != UINTPTR_MAX ) { + rtems_printf( printer, "%6" PRIuPTR "\n", info->used ); + } else { + rtems_printf( printer, "N/A\n" ); + } +} void rtems_stack_checker_report_usage_with_plugin( const rtems_printer* printer ) { - uint32_t cpu_max; - uint32_t cpu_index; - rtems_printf( printer, " STACK USAGE BY THREAD\n" "ID NAME LOW HIGH CURRENT AVAIL USED\n" ); - /* iterate over all threads and dump the usage */ - rtems_task_iterate( - Stack_check_Dump_threads_usage, + rtems_stack_checker_iterate( + Stack_check_Print_info, RTEMS_DECONST( rtems_printer *, printer ) ); +} + +void rtems_stack_checker_report_usage( void ) +{ + rtems_printer printer; + rtems_print_printer_printk(&printer); + rtems_stack_checker_report_usage_with_plugin( &printer ); +} + +void rtems_stack_checker_iterate( rtems_stack_checker_visitor visit, void *arg ) +{ + Stack_check_Visitor visitor; + uint32_t cpu_max; + uint32_t cpu_index; + + visitor.visit = visit; + visitor.arg = arg; + rtems_task_iterate( Stack_check_Visit_thread, &visitor ); cpu_max = rtems_scheduler_get_processor_maximum(); for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) { - Stack_check_Dump_interrupt_stack_usage( + Stack_check_Visit_interrupt_stack( &Stack_check_Interrupt_stack[ cpu_index ], cpu_index, - printer + visit, + arg ); } } -void rtems_stack_checker_report_usage( void ) -{ - rtems_printer printer; - rtems_print_printer_printk(&printer); - rtems_stack_checker_report_usage_with_plugin( &printer ); -} - static void Stack_check_Prepare_interrupt_stacks( void ) { Stack_Control stack; diff --git a/cpukit/libmisc/untar/untar_tgz.c b/cpukit/libmisc/untar/untar_tgz.c index 5298b871dc..d2612fd566 100644 --- a/cpukit/libmisc/untar/untar_tgz.c +++ b/cpukit/libmisc/untar/untar_tgz.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* - * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * Copyright (c) 2016 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/libmisc/uuid/gen_uuid.c b/cpukit/libmisc/uuid/gen_uuid.c index 71b8a569bb..5601c887c9 100644 --- a/cpukit/libmisc/uuid/gen_uuid.c +++ b/cpukit/libmisc/uuid/gen_uuid.c @@ -171,7 +171,12 @@ static int get_random_fd(void) fcntl(fd, F_SETFD, i | FD_CLOEXEC); } #endif +#ifdef __rtems__ + srand((((time_t)getpid()) << ((sizeof(pid_t)*CHAR_BIT)>>1)) ^ getuid() + ^ tv.tv_sec ^ tv.tv_usec); +#else srand((getpid() << ((sizeof(pid_t)*CHAR_BIT)>>1)) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); +#endif #ifdef DO_JRAND_MIX jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); @@ -343,11 +348,17 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low, state_fd = open("/var/lib/libuuid/clock.txt", O_RDWR|O_CREAT, 0660); (void) umask(save_umask); +#ifdef __rtems__ + if (state_fd >= 0) { +#endif state_f = fdopen(state_fd, "r+"); if (!state_f) { close(state_fd); state_fd = -1; } +#ifdef __rtems__ + } +#endif } fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; |