diff options
Diffstat (limited to 'cpukit')
159 files changed, 5992 insertions, 1656 deletions
diff --git a/cpukit/dtc/VERSION b/cpukit/dtc/VERSION index 77198ab947..3eccee5e6d 100644 --- a/cpukit/dtc/VERSION +++ b/cpukit/dtc/VERSION @@ -2,17 +2,24 @@ Import from: git://git.kernel.org/pub/scm/utils/dtc/dtc.git -Commit: +commit ed310803ea893ed0a8bba9c4ff0d9eb0063a8bef +Author: Luca Weiss <luca@z3ntu.xyz> +Date: Tue Apr 19 21:45:38 2022 +0200 -17739b7ef510917471409d71fb45d8eaf6a1e1fb + pylibfdt: add FdtRo.get_path() -Date: + Add a new Python method wrapping fdt_get_path() from the C API. -Thu Dec 9 07:14:20 2021 +0100 + Also add a test for the new method. + + Signed-off-by: Luca Weiss <luca@z3ntu.xyz> + Message-Id: <20220419194537.63170-1-luca@z3ntu.xyz> + Reviewed-by: Simon Glass <sjg@chromium.org> + Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Commands to generate update patches: -git format-patch 17739b7ef510917471409d71fb45d8eaf6a1e1fb -- libfdt/fdt_addresses.c libfdt/fdt.c libfdt/fdt_empty_tree.c libfdt/fdt.h libfdt/fdt_ro.c libfdt/fdt_rw.c libfdt/fdt_strerror.c libfdt/fdt_sw.c libfdt/fdt_wip.c libfdt/libfdt_env.h libfdt/libfdt.h libfdt/libfdt_internal.h libfdt/TODO +git format-patch ed310803ea893ed0a8bba9c4ff0d9eb0063a8bef -- libfdt/fdt_addresses.c libfdt/fdt.c libfdt/fdt_empty_tree.c libfdt/fdt.h libfdt/fdt_ro.c libfdt/fdt_rw.c libfdt/fdt_strerror.c libfdt/fdt_sw.c libfdt/fdt_wip.c libfdt/libfdt_env.h libfdt/libfdt.h libfdt/libfdt_internal.h libfdt/TODO sed -i 's%/libfdt/fdt.h%/cpukit/include/fdt.h%g' 00* sed -i 's%/libfdt/libfdt.h%/cpukit/include/libfdt.h%g' 00* sed -i 's%/libfdt/libfdt_env.h%/cpukit/include/libfdt_env.h%g' 00* diff --git a/cpukit/dtc/libfdt/fdt_ro.c b/cpukit/dtc/libfdt/fdt_ro.c index 17584da257..9f6c551a22 100644 --- a/cpukit/dtc/libfdt/fdt_ro.c +++ b/cpukit/dtc/libfdt/fdt_ro.c @@ -481,12 +481,12 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, if (!can_assume(VALID_INPUT)) { name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff), &namelen); + *namep = name; if (!name) { if (lenp) *lenp = namelen; return NULL; } - *namep = name; } else { *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff)); } diff --git a/cpukit/include/machine/_kernel_in.h b/cpukit/include/machine/_kernel_in.h index 29a6112e96..b33283353a 100644 --- a/cpukit/include/machine/_kernel_in.h +++ b/cpukit/include/machine/_kernel_in.h @@ -50,8 +50,14 @@ int in_broadcast(struct in_addr, struct ifnet *); int in_ifaddr_broadcast(struct in_addr, struct in_ifaddr *); int in_canforward(struct in_addr); int in_localaddr(struct in_addr); +#if __FreeBSD_version >= 1400039 +bool in_localip(struct in_addr); +#else int in_localip(struct in_addr); +#endif +bool in_localip_fib(struct in_addr, uint16_t); int in_ifhasaddr(struct ifnet *, struct in_addr); +struct in_ifaddr *in_findlocal(uint32_t, bool); int inet_aton(const char *, struct in_addr *); /* in libkern */ char *inet_ntoa_r(struct in_addr ina, char *buf); /* in libkern */ char *inet_ntop(int, const void *, char *, socklen_t); /* in libkern */ diff --git a/cpukit/include/machine/_kernel_in6.h b/cpukit/include/machine/_kernel_in6.h index c2b603fb36..7ec695bd6d 100644 --- a/cpukit/include/machine/_kernel_in6.h +++ b/cpukit/include/machine/_kernel_in6.h @@ -167,6 +167,7 @@ int in6_cksum_partial(struct mbuf *, u_int8_t, u_int32_t, u_int32_t, u_int32_t); int in6_localaddr(struct in6_addr *); int in6_localip(struct in6_addr *); +bool in6_localip_fib(struct in6_addr *, uint16_t); int in6_ifhasaddr(struct ifnet *, struct in6_addr *); int in6_addrscope(const struct in6_addr *); char *ip6_sprintf(char *, const struct in6_addr *); diff --git a/cpukit/include/machine/_kernel_uio.h b/cpukit/include/machine/_kernel_uio.h index 7e45a28c16..59929cb03c 100644 --- a/cpukit/include/machine/_kernel_uio.h +++ b/cpukit/include/machine/_kernel_uio.h @@ -71,12 +71,8 @@ struct vm_page; struct bus_dma_segment; struct uio *cloneuio(struct uio *uiop); -int copyinfrom(const void * __restrict src, void * __restrict dst, - size_t len, int seg); int copyiniov(const struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error); -int copyinstrfrom(const void * __restrict src, void * __restrict dst, - size_t len, size_t * __restrict copied, int seg); int copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop); int copyout_map(struct thread *td, vm_offset_t *addr, size_t sz); int copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz); diff --git a/cpukit/include/rtems/confdefs.h b/cpukit/include/rtems/confdefs.h index e6dd3d70ee..3927d26ec5 100644 --- a/cpukit/include/rtems/confdefs.h +++ b/cpukit/include/rtems/confdefs.h @@ -64,6 +64,7 @@ #include <rtems/confdefs/clock.h> #include <rtems/confdefs/console.h> #include <rtems/confdefs/extensions.h> +#include <rtems/confdefs/face.h> #include <rtems/confdefs/inittask.h> #include <rtems/confdefs/initthread.h> #include <rtems/confdefs/iodrivers.h> diff --git a/cpukit/include/rtems/confdefs/face.h b/cpukit/include/rtems/confdefs/face.h new file mode 100644 index 0000000000..25f321108c --- /dev/null +++ b/cpukit/include/rtems/confdefs/face.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSImplApplConfig + * + * @brief This header file evaluates configuration options related to + * the FACE Technical Standard. + * + * The FACE Technical Standard (https://opengroup.org/face) is an + * open standard designed for safety critical embedded systems. It + * includes POSIX profiles and requirements that promote safety + * and portability. As a general rules, the profiles place a minimum + * on the services which an operating system must provide. Those + * same profile definitions represent the maximum services which + * an application may use. + */ + +/* + * 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. + */ + +#ifndef _RTEMS_CONFDEFS_FACE_H +#define _RTEMS_CONFDEFS_FACE_H + +#ifndef __CONFIGURATION_TEMPLATE_h +#error "Do not include this file directly, use <rtems/confdefs.h> instead" +#endif + +#ifdef CONFIGURE_INIT + +#include <rtems/posix/timer.h> + +#ifdef CONFIGURE_POSIX_TIMERS_FACE_BEHAVIOR + int _POSIX_Timer_Is_allowed( + clockid_t clock_id + ) + { + /* + * Per the FACE Technical Standard, POSIX timers should not be + * allowed on CLOCK_REALTIME for safety reasons. If the application + * wants the FACE behavior, then this method is instantiated. + */ + if ( clock_id == CLOCK_REALTIME ) { + return EPERM; + } + + if ( clock_id != CLOCK_MONOTONIC ) { + return EINVAL; + } + + return 0; + } + +#endif /* CONFIGURE_POSIX_TIMERS_FACE_BEHAVIOR */ + +#endif /* CONFIGURE_INIT */ + +#endif /* _RTEMS_CONFDEFS_FACE_H */ diff --git a/cpukit/include/rtems/confdefs/newlib.h b/cpukit/include/rtems/confdefs/newlib.h index 96bf850163..fef71a8855 100644 --- a/cpukit/include/rtems/confdefs/newlib.h +++ b/cpukit/include/rtems/confdefs/newlib.h @@ -57,7 +57,8 @@ extern "C" { #endif -#ifdef _CONFIGURE_ENABLE_NEWLIB_REENTRANCY +#if defined(_CONFIGURE_ENABLE_NEWLIB_REENTRANCY) && \ + !defined(_REENT_THREAD_LOCAL) struct _reent *__getreent( void ) { return _Thread_Get_executing()->libc_reent; diff --git a/cpukit/include/rtems/confdefs/threads.h b/cpukit/include/rtems/confdefs/threads.h index 503a4b20ec..8e4537f90b 100644 --- a/cpukit/include/rtems/confdefs/threads.h +++ b/cpukit/include/rtems/confdefs/threads.h @@ -159,7 +159,8 @@ struct Thread_Configured_control { #if CONFIGURE_MAXIMUM_THREAD_NAME_SIZE > 1 char name[ CONFIGURE_MAXIMUM_THREAD_NAME_SIZE ]; #endif - #ifdef _CONFIGURE_ENABLE_NEWLIB_REENTRANCY + #if defined(_CONFIGURE_ENABLE_NEWLIB_REENTRANCY) && \ + !defined(_REENT_THREAD_LOCAL) struct _reent Newlib; #endif }; @@ -175,7 +176,8 @@ const Thread_Control_add_on _Thread_Control_add_ons[] = { ), offsetof( Thread_Configured_control, API_RTEMS ) } - #ifdef _CONFIGURE_ENABLE_NEWLIB_REENTRANCY + #if defined(_CONFIGURE_ENABLE_NEWLIB_REENTRANCY) && \ + !defined(_REENT_THREAD_LOCAL) , { offsetof( Thread_Configured_control, diff --git a/cpukit/include/rtems/imfs.h b/cpukit/include/rtems/imfs.h index 57c498cfe8..7db9b4e462 100644 --- a/cpukit/include/rtems/imfs.h +++ b/cpukit/include/rtems/imfs.h @@ -3,7 +3,7 @@ /** * @file * - * @brief Header File for the In-Memory File System + * @brief This header file defines the API of the In-Memory File System. */ /* @@ -39,7 +39,6 @@ #include <rtems/libio_.h> #include <rtems/pipe.h> -#include <rtems/score/timecounter.h> /** * @brief In-Memory File System Support. @@ -372,41 +371,6 @@ static inline IMFS_memfile_t *IMFS_iop_to_memfile( const rtems_libio_t *iop ) return (IMFS_memfile_t *) iop->pathinfo.node_access; } -static inline time_t _IMFS_get_time( void ) -{ - struct bintime now; - - /* Use most efficient way to get the time in seconds (CLOCK_REALTIME) */ - _Timecounter_Getbintime( &now ); - - return now.sec; -} - -static inline void IMFS_update_atime( IMFS_jnode_t *jnode ) -{ - jnode->stat_atime = _IMFS_get_time(); -} - -static inline void IMFS_update_mtime( IMFS_jnode_t *jnode ) -{ - jnode->stat_mtime = _IMFS_get_time(); -} - -static inline void IMFS_update_ctime( IMFS_jnode_t *jnode ) -{ - jnode->stat_ctime = _IMFS_get_time(); -} - -static inline void IMFS_mtime_ctime_update( IMFS_jnode_t *jnode ) -{ - time_t now; - - now = _IMFS_get_time(); - - jnode->stat_mtime = now; - jnode->stat_ctime = now; -} - typedef struct { const IMFS_mknod_control *directory; const IMFS_mknod_control *device; diff --git a/cpukit/include/rtems/imfsimpl.h b/cpukit/include/rtems/imfsimpl.h new file mode 100644 index 0000000000..db1ae32af7 --- /dev/null +++ b/cpukit/include/rtems/imfsimpl.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @brief This header file contains interfaces used by the implementation of + * the In-Memory File System. + */ + +/* + * Copyright (C) 2013, 2018 embedded brains GmbH + * + * 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. + */ + +#ifndef _RTEMS_IMFSIMPL_H +#define _RTEMS_IMFSIMPL_H + +#include <rtems/imfs.h> +#include <rtems/score/timecounter.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup IMFS + * + * @{ + */ + +static inline time_t _IMFS_get_time( void ) +{ + struct bintime now; + + /* Use most efficient way to get the time in seconds (CLOCK_REALTIME) */ + _Timecounter_Getbintime( &now ); + + return now.sec; +} + +static inline void IMFS_update_atime( IMFS_jnode_t *jnode ) +{ + jnode->stat_atime = _IMFS_get_time(); +} + +static inline void IMFS_update_mtime( IMFS_jnode_t *jnode ) +{ + jnode->stat_mtime = _IMFS_get_time(); +} + +static inline void IMFS_update_ctime( IMFS_jnode_t *jnode ) +{ + jnode->stat_ctime = _IMFS_get_time(); +} + +static inline void IMFS_mtime_ctime_update( IMFS_jnode_t *jnode ) +{ + time_t now; + + now = _IMFS_get_time(); + + jnode->stat_mtime = now; + jnode->stat_ctime = now; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _RTEMS_IMFSIMPL_H */ diff --git a/cpukit/include/rtems/libcsupport.h b/cpukit/include/rtems/libcsupport.h index 212eb16e59..67a09dc2a2 100644 --- a/cpukit/include/rtems/libcsupport.h +++ b/cpukit/include/rtems/libcsupport.h @@ -96,27 +96,33 @@ extern int malloc_info(Heap_Information_block *the_info); /* * Prototypes required to install newlib reentrancy user extension */ + +#ifdef _REENT_THREAD_LOCAL +#define _NEWLIB_CREATE_HOOK NULL +#else bool newlib_create_hook( rtems_tcb *current_task, rtems_tcb *creating_task ); +#define _NEWLIB_CREATE_HOOK newlib_create_hook +#endif void newlib_terminate_hook( rtems_tcb *current_task ); #define RTEMS_NEWLIB_EXTENSION \ -{ \ - newlib_create_hook, /* rtems_task_create */ \ - 0, /* rtems_task_start */ \ - 0, /* rtems_task_restart */ \ - 0, /* rtems_task_delete */ \ - 0, /* task_switch */ \ - 0, /* task_begin */ \ - 0, /* task_exitted */ \ - 0, /* fatal */ \ - newlib_terminate_hook /* thread terminate */ \ -} + { \ + _NEWLIB_CREATE_HOOK, /* thread_create */ \ + NULL, /* thread_start */ \ + NULL, /* thread_restart */ \ + NULL, /* thread_delete */ \ + NULL, /* thread_switch */ \ + NULL, /* thread_begin */ \ + NULL, /* thread_exitted */ \ + NULL, /* fatal */ \ + newlib_terminate_hook /* thread_terminate */ \ + } typedef struct { uint32_t active_barriers; diff --git a/cpukit/include/rtems/malloc.h b/cpukit/include/rtems/malloc.h index 7d7f8fa677..c26b262881 100644 --- a/cpukit/include/rtems/malloc.h +++ b/cpukit/include/rtems/malloc.h @@ -3,7 +3,12 @@ /** * @file * - * This file defines the interface to RTEMS extensions to the Malloc Family. + * @ingroup MallocSupport + * + * @ingroup RTEMSAPIMalloc + * + * @brief This header file defines interfaces to support and use dynamic memory + * allocation. */ /* @@ -46,11 +51,13 @@ extern "C" { #endif /** - * @defgroup MallocSupport Malloc Support + * @defgroup MallocSupport Malloc Support + * + * @ingroup libcsupport * - * @ingroup libcsupport + * @brief This group contains interfaces to support dynamic memory allocation. * - * @brief RTEMS extensions to the Malloc Family + * @{ */ /** @@ -63,8 +70,6 @@ extern Heap_Control *RTEMS_Malloc_Heap; void _Malloc_Initialize( void ); -void rtems_heap_set_sbrk_amount( ptrdiff_t sbrk_amount ); - typedef void *(*rtems_heap_extend_handler)( Heap_Control *heap, size_t alloc_size @@ -78,19 +83,6 @@ void *rtems_heap_extend_via_sbrk( size_t alloc_size ); -/** - * @brief Greedy allocate that empties the sbrk memory - * - * Afterwards all the sbrk avialable memory will have been allocated - * to the provided heap. - * - * @see rtems_heap_extend_via_sbrk(). - */ -void rtems_heap_sbrk_greedy_allocate( - Heap_Control *heap, - size_t alloc_size -); - void *rtems_heap_null_extend( Heap_Control *heap, size_t alloc_size @@ -104,6 +96,34 @@ extern const rtems_heap_extend_handler rtems_malloc_extend_handler; typedef void (*rtems_malloc_dirtier_t)(void *, size_t); extern rtems_malloc_dirtier_t rtems_malloc_dirty_helper; +/** @} */ + +/** + * @defgroup RTEMSAPIMalloc Dynamic Memory Allocation + * + * @ingroup RTEMSAPI + * + * @brief This group contains non-standard interfaces to use dynamic memory + * allocation. + * + * @{ + */ + +void rtems_heap_set_sbrk_amount( ptrdiff_t sbrk_amount ); + +/** + * @brief Greedy allocate that empties the sbrk memory + * + * Afterwards all the sbrk avialable memory will have been allocated + * to the provided heap. + * + * @see rtems_heap_extend_via_sbrk(). + */ +void rtems_heap_sbrk_greedy_allocate( + Heap_Control *heap, + size_t alloc_size +); + /** * @brief Dirty Memory Function * @@ -251,6 +271,8 @@ void *rtems_heap_greedy_allocate_all_except_largest( */ void rtems_heap_greedy_free( void *opaque ); +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpukit/include/rtems/posix/priorityimpl.h b/cpukit/include/rtems/posix/priorityimpl.h index e391448372..ce26787294 100644 --- a/cpukit/include/rtems/posix/priorityimpl.h +++ b/cpukit/include/rtems/posix/priorityimpl.h @@ -84,7 +84,7 @@ RTEMS_INLINE_ROUTINE int _POSIX_Priority_Get_maximum( * Thus, SuperCore has priorities run in the opposite sense of the POSIX API. * * Let N be the maximum priority of this scheduler instance. The SuperCore - * priority zero is system reserved (PRIORITY_PSEUDO_ISR). There are only + * priority zero is system reserved (PRIORITY_MINIMUM). There are only * N - 1 POSIX API priority levels since a thread at SuperCore priority N would * never run because of the idle threads. This is necessary because GNAT maps * the lowest Ada task priority to the lowest thread priority. The lowest diff --git a/cpukit/include/rtems/posix/timer.h b/cpukit/include/rtems/posix/timer.h index 05a6f36eab..86b45ba05d 100644 --- a/cpukit/include/rtems/posix/timer.h +++ b/cpukit/include/rtems/posix/timer.h @@ -94,6 +94,24 @@ extern Objects_Information _POSIX_Timer_Information; NULL \ ) +/** + * @brief Follow POSIX or FACE Technical Standard on timer_create + * + * POSIX allows for the creation of timers based on CLOCK_REALTIME. + * This is viewed as a safety issue by the FACE Technical Standard + * and required to return an error. These are conflicting behaviors. + * This method is instanced by configuration when FACE conformant + * behavior is desired by the application. + * + * @param[in] clock_id is the clock ID to validate + * + * @return 0 if @a clock_id is allowed for use. Otherwise an errno value. + */ +int _POSIX_Timer_Is_allowed( + clockid_t clock_id +); + + /** @} */ #ifdef __cplusplus diff --git a/cpukit/include/rtems/rtems/tasks.h b/cpukit/include/rtems/rtems/tasks.h index 81757db8c7..ba05d92531 100644 --- a/cpukit/include/rtems/rtems/tasks.h +++ b/cpukit/include/rtems/rtems/tasks.h @@ -413,8 +413,8 @@ rtems_task_priority _RTEMS_Maximum_priority( void ); /** * @ingroup RTEMSAPIClassicTasks * - * @brief This constant variable provides the lowest (least important) task - * priority of the first configured scheduler. + * @brief This runtime constant represents the lowest (least important) task + * priority of the scheduler with index zero. */ #define RTEMS_MAXIMUM_PRIORITY _RTEMS_Maximum_priority() @@ -1031,13 +1031,25 @@ rtems_status_code rtems_task_restart( * @retval ::RTEMS_CALLED_FROM_ISR The directive was called from within * interrupt context. * + * @retval ::RTEMS_INCORRECT_STATE The task termination procedure was started, + * however, waiting for the terminating task would have resulted in a + * deadlock. + * * @retval ::RTEMS_ILLEGAL_ON_REMOTE_OBJECT The task resided on a remote node. * * @par Notes * @parblock - * RTEMS stops the execution of the task and reclaims the stack memory, any - * allocated delay or timeout timers, the TCB, and, if the task is - * #RTEMS_FLOATING_POINT, its floating point context area. RTEMS explicitly + * The task deletion is done in several steps. Firstly, the task is marked as + * terminating. While the task life of the terminating task is protected, it + * executes normally until it disables the task life protection or it deletes + * itself. A terminating task will eventually stop its normal execution and + * start its termination procedure. The procedure executes in the context of + * the terminating task. The task termination procedure involves the + * destruction of POSIX key values and running the task termination user + * extensions. Once complete the execution of the task is stopped and + * task-specific resources are reclaimed by the system, such as the stack + * memory, any allocated delay or timeout timers, the TCB, and, if the task is + * #RTEMS_FLOATING_POINT, its floating point context area. RTEMS explicitly * does not reclaim the following resources: region segments, partition * buffers, semaphores, timers, or rate monotonic periods. * @@ -1049,10 +1061,12 @@ rtems_status_code rtems_task_restart( * resources and delete itself by restarting it with a special argument or by * sending it a message, an event, or a signal. * - * Deletion of the current task (#RTEMS_SELF) will force RTEMS to select + * Deletion of the calling task (#RTEMS_SELF) will force RTEMS to select * another task to execute. * - * The TCB for the deleted task is reclaimed by RTEMS. + * When a task deletes another task, the calling task waits until the task + * termination procedure of the task being deleted has completed. The + * terminating task inherits the eligible priorities of the calling task. * * When a global task is deleted, the task identifier must be transmitted to * every node in the system for deletion from the local copy of the global diff --git a/cpukit/include/rtems/score/gcov.h b/cpukit/include/rtems/score/gcov.h new file mode 100644 index 0000000000..b150c9f763 --- /dev/null +++ b/cpukit/include/rtems/score/gcov.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreGcov + * + * @brief This header file provides the interfaces of the + * @ref RTEMSScoreGcov. + */ + +/* + * Copyright (c) 2013-2014 embedded brains GmbH. 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. + */ + +#ifndef _RTEMS_SCORE_GCOV_H +#define _RTEMS_SCORE_GCOV_H + +#include <gcov.h> + +#include <rtems/linkersets.h> +#include <rtems/score/io.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup RTEMSScoreGcov Gcov Support + * + * @ingroup RTEMSScore + * + * @brief This group contains the gocv support. + * + * @{ + */ + +RTEMS_LINKER_ROSET_DECLARE( gcov_info, const struct gcov_info * ); + +/** + * @brief Dumps the gcov information as a binary gcfn and gcda data + * stream using the put character handler. + * + * @param put_char is the put character handler used to output the data stream. + * + * @param arg is the argument passed to the put character handler. + */ +void _Gcov_Dump_info( IO_Put_char put_char, void *arg ); + +/** + * @brief Dumps the gcov information as a base64 encoded gcfn and gcda data + * stream using the put character handler. + * + * @param put_char is the put character handler used to output the data stream. + * + * @param arg is the argument passed to the put character handler. + */ +void _Gcov_Dump_info_base64( IO_Put_char put_char, void *arg ); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_SCORE_GCOV_H */ diff --git a/cpukit/include/rtems/score/memory.h b/cpukit/include/rtems/score/memory.h index 5761402711..fa17ea164c 100644 --- a/cpukit/include/rtems/score/memory.h +++ b/cpukit/include/rtems/score/memory.h @@ -10,7 +10,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2019 embedded brains GmbH + * Copyright (C) 2019, 2022 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -352,6 +352,18 @@ void _Memory_Zero_free_areas( void ); */ void _Memory_Dirty_free_areas( void ); +/** + * @brief This symbol marks the begin of the non-initialized section used by + * RTEMS. + */ +extern char _Memory_Noinit_begin[]; + +/** + * @brief This symbol marks the end of the non-initialized section used by + * RTEMS. + */ +extern char _Memory_Noinit_end[]; + /** @} */ #ifdef __cplusplus diff --git a/cpukit/include/rtems/score/objectdata.h b/cpukit/include/rtems/score/objectdata.h index d624f182f9..4bdd30f2c6 100644 --- a/cpukit/include/rtems/score/objectdata.h +++ b/cpukit/include/rtems/score/objectdata.h @@ -449,7 +449,9 @@ Objects_Information name##_Information = { \ #define OBJECTS_INFORMATION_DEFINE( name, api, cls, type, max, nl, ex ) \ static Objects_Control * \ name##_Local_table[ _Objects_Maximum_per_allocation( max ) ]; \ -static type name##_Objects[ _Objects_Maximum_per_allocation( max ) ]; \ +static RTEMS_SECTION( ".noinit.rtems.content.objects." #name ) \ +type \ +name##_Objects[ _Objects_Maximum_per_allocation( max ) ]; \ Objects_Information name##_Information = { \ _Objects_Build_id( api, cls, 1, _Objects_Maximum_per_allocation( max ) ), \ name##_Local_table, \ diff --git a/cpukit/include/rtems/score/objectimpl.h b/cpukit/include/rtems/score/objectimpl.h index 72a5f6b126..7938996df8 100644 --- a/cpukit/include/rtems/score/objectimpl.h +++ b/cpukit/include/rtems/score/objectimpl.h @@ -912,6 +912,25 @@ RTEMS_INLINE_ROUTINE void _Objects_Free( } /** + * @brief Returns true, if the object associated with the zero-based index is + * contained in an allocated block of objects, otherwise false. + * + * @param index is the zero-based object index. + * @param objects_per_block is the object count per block. + * + * @retval true The object associated with the zero-based index is in an + * allocated block of objects. + * @retval false Otherwise. + */ +RTEMS_INLINE_ROUTINE bool _Objects_Is_in_allocated_block( + Objects_Maximum index, + Objects_Maximum objects_per_block +) +{ + return index >= objects_per_block; +} + +/** * @brief Activate the object. * * This function must be only used in case this objects information supports @@ -926,15 +945,17 @@ RTEMS_INLINE_ROUTINE void _Objects_Activate_unlimited( ) { Objects_Maximum objects_per_block; - Objects_Maximum block; + Objects_Maximum index; _Assert( _Objects_Is_auto_extend( information ) ); objects_per_block = information->objects_per_block; - block = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM; + index = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM; + + if ( _Objects_Is_in_allocated_block( index, objects_per_block ) ) { + Objects_Maximum block; - if ( block > objects_per_block ) { - block /= objects_per_block; + block = index / objects_per_block; information->inactive_per_block[ block ]--; information->inactive--; diff --git a/cpukit/include/rtems/score/priority.h b/cpukit/include/rtems/score/priority.h index 568e3c4e3e..6f6cc12bac 100644 --- a/cpukit/include/rtems/score/priority.h +++ b/cpukit/include/rtems/score/priority.h @@ -96,13 +96,6 @@ typedef uint64_t Priority_Control; #define PRIORITY_MINIMUM 0 /** - * @brief The priority value of pseudo-ISR threads. - * - * Examples are the MPCI and timer server threads. - */ -#define PRIORITY_PSEUDO_ISR PRIORITY_MINIMUM - -/** * @brief The default lowest (least important) thread priority value. * * This value is CPU port dependent. diff --git a/cpukit/include/rtems/score/priorityimpl.h b/cpukit/include/rtems/score/priorityimpl.h index 1463bf6c2a..55cddf53be 100644 --- a/cpukit/include/rtems/score/priorityimpl.h +++ b/cpukit/include/rtems/score/priorityimpl.h @@ -125,26 +125,6 @@ RTEMS_INLINE_ROUTINE bool _Priority_Actions_is_empty( } /** - * @brief Checks if the priority actions is valid. - * - * @param aggregation The aggregation of the priority action. - * - * @retval true The @a aggregation is valid. - * @retval false The @a aggregation is not valid. - */ -RTEMS_INLINE_ROUTINE bool _Priority_Actions_is_valid( - const Priority_Aggregation *aggregation -) -{ -#if defined(RTEMS_SMP) - return aggregation != NULL; -#else - (void) aggregation; - return false; -#endif -} - -/** * @brief Moves the priority actions' actions. * * @param[in, out] actions The priority actions to move the actions away from. @@ -389,25 +369,22 @@ RTEMS_INLINE_ROUTINE void _Priority_Set_action( aggregation->Action.type = type; } +#if defined(RTEMS_SMP) /** * @brief Gets the next action of the priority aggregation. * - * @param aggregation The priority aggregation to get the next action of. + * @param aggregation is the priority aggregation to get the next action of. * - * @retval next_action The next action of @a aggregation if RTEMS_SMP is defined. - * @retval NULL RTEMS_SMP is not defined. + * @return Returns the next action of the priority aggregation or NULL if there + * is no next action. */ RTEMS_INLINE_ROUTINE Priority_Aggregation *_Priority_Get_next_action( const Priority_Aggregation *aggregation ) { -#if defined(RTEMS_SMP) return aggregation->Action.next; -#else - (void) aggregation; - return NULL; -#endif } +#endif /** * @brief Compares two priorities. diff --git a/cpukit/include/rtems/score/processormask.h b/cpukit/include/rtems/score/processormask.h index 000bb63c8b..40fb52a70f 100644 --- a/cpukit/include/rtems/score/processormask.h +++ b/cpukit/include/rtems/score/processormask.h @@ -47,6 +47,62 @@ extern "C" { #endif /* __cplusplus */ +/* + * Recent Newlib versions provide the bitset defines in the system reserved + * namespace. + */ +#ifndef __BIT_AND2 +#define __BIT_AND2 BIT_AND2 +#endif +#ifndef __BIT_CLR +#define __BIT_CLR BIT_CLR +#endif +#ifndef __BIT_CMP +#define __BIT_CMP BIT_CMP +#endif +#ifndef __BIT_COPY +#define __BIT_COPY BIT_COPY +#endif +#ifndef __BIT_COUNT +#define __BIT_COUNT BIT_COUNT +#endif +#ifndef __BITSET_DEFINE +#define __BITSET_DEFINE BITSET_DEFINE +#endif +#ifndef __BIT_EMPTY +#define __BIT_EMPTY BIT_EMPTY +#endif +#ifndef __BIT_FILL +#define __BIT_FILL BIT_FILL +#endif +#ifndef __BIT_FLS +#define __BIT_FLS BIT_FLS +#endif +#ifndef __BIT_ISSET +#define __BIT_ISSET BIT_ISSET +#endif +#ifndef __BIT_OR2 +#define __BIT_OR2 BIT_OR2 +#endif +#ifndef __BIT_OVERLAP +#define __BIT_OVERLAP BIT_OVERLAP +#endif +#ifndef __BIT_SET +#define __BIT_SET BIT_SET +#endif +#ifndef __BIT_SETOF +#define __BIT_SETOF BIT_SETOF +#endif +#ifndef __BIT_SUBSET +#define __BIT_SUBSET BIT_SUBSET +#endif +#ifndef __BIT_XOR2 +#define __BIT_XOR2 BIT_XOR2 +#endif +#ifndef __BIT_ZERO +#define __BIT_ZERO BIT_ZERO +#endif + /** * @defgroup RTEMSScoreProcessorMask Processor Mask * @@ -65,7 +121,7 @@ extern "C" { * @brief A bit map which is large enough to provide one bit for each processor * in the system. */ -typedef BITSET_DEFINE( Processor_mask, CPU_MAXIMUM_PROCESSORS ) Processor_mask; +typedef __BITSET_DEFINE( Processor_mask, CPU_MAXIMUM_PROCESSORS ) Processor_mask; /** * @brief Sets the bits of the mask to zero, also considers CPU_MAXIMUM_PROCESSORS. @@ -74,7 +130,7 @@ typedef BITSET_DEFINE( Processor_mask, CPU_MAXIMUM_PROCESSORS ) Processor_mask; */ RTEMS_INLINE_ROUTINE void _Processor_mask_Zero( Processor_mask *mask ) { - BIT_ZERO( CPU_MAXIMUM_PROCESSORS, mask ); + __BIT_ZERO( CPU_MAXIMUM_PROCESSORS, mask ); } /** @@ -87,7 +143,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_Zero( Processor_mask *mask ) */ RTEMS_INLINE_ROUTINE bool _Processor_mask_Is_zero( const Processor_mask *mask ) { - return BIT_EMPTY( CPU_MAXIMUM_PROCESSORS, mask ); + return __BIT_EMPTY( CPU_MAXIMUM_PROCESSORS, mask ); } /** @@ -97,7 +153,7 @@ RTEMS_INLINE_ROUTINE bool _Processor_mask_Is_zero( const Processor_mask *mask ) */ RTEMS_INLINE_ROUTINE void _Processor_mask_Fill( Processor_mask *mask ) { - BIT_FILL( CPU_MAXIMUM_PROCESSORS, mask ); + __BIT_FILL( CPU_MAXIMUM_PROCESSORS, mask ); } /** @@ -110,7 +166,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_Assign( Processor_mask *dst, const Processor_mask *src ) { - BIT_COPY( CPU_MAXIMUM_PROCESSORS, src, dst ); + __BIT_COPY( CPU_MAXIMUM_PROCESSORS, src, dst ); } /** @@ -124,7 +180,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_Set( uint32_t index ) { - BIT_SET( CPU_MAXIMUM_PROCESSORS, index, mask ); + __BIT_SET( CPU_MAXIMUM_PROCESSORS, index, mask ); } /** @@ -138,7 +194,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_Clear( uint32_t index ) { - BIT_CLR( CPU_MAXIMUM_PROCESSORS, index, mask ); + __BIT_CLR( CPU_MAXIMUM_PROCESSORS, index, mask ); } /** @@ -155,7 +211,7 @@ RTEMS_INLINE_ROUTINE bool _Processor_mask_Is_set( uint32_t index ) { - return BIT_ISSET( CPU_MAXIMUM_PROCESSORS, index, mask ); + return __BIT_ISSET( CPU_MAXIMUM_PROCESSORS, index, mask ); } /** @@ -172,7 +228,7 @@ RTEMS_INLINE_ROUTINE bool _Processor_mask_Is_equal( const Processor_mask *b ) { - return !BIT_CMP( CPU_MAXIMUM_PROCESSORS, a, b ); + return !__BIT_CMP( CPU_MAXIMUM_PROCESSORS, a, b ); } /** @@ -190,7 +246,7 @@ RTEMS_INLINE_ROUTINE bool _Processor_mask_Has_overlap( const Processor_mask *b ) { - return BIT_OVERLAP( CPU_MAXIMUM_PROCESSORS, a, b ); + return __BIT_OVERLAP( CPU_MAXIMUM_PROCESSORS, a, b ); } /** @@ -208,7 +264,7 @@ RTEMS_INLINE_ROUTINE bool _Processor_mask_Is_subset( const Processor_mask *small ) { - return BIT_SUBSET( CPU_MAXIMUM_PROCESSORS, big, small ); + return __BIT_SUBSET( CPU_MAXIMUM_PROCESSORS, big, small ); } /** @@ -224,23 +280,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_And( const Processor_mask *c ) { - BIT_AND2( CPU_MAXIMUM_PROCESSORS, a, b, c ); -} - -/** - * @brief Performs a bitwise a = b & ~c. - * - * @param[out] a The processor mask that is set by this operation. - * @param b The first parameter of the operation. - * @param c The second parameter of the operation. - */ -RTEMS_INLINE_ROUTINE void _Processor_mask_Nand( - Processor_mask *a, - const Processor_mask *b, - const Processor_mask *c -) -{ - BIT_NAND2( CPU_MAXIMUM_PROCESSORS, a, b, c ); + __BIT_AND2( CPU_MAXIMUM_PROCESSORS, a, b, c ); } /** @@ -256,7 +296,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_Or( const Processor_mask *c ) { - BIT_OR2( CPU_MAXIMUM_PROCESSORS, a, b, c ); + __BIT_OR2( CPU_MAXIMUM_PROCESSORS, a, b, c ); } /** @@ -272,7 +312,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_Xor( const Processor_mask *c ) { - BIT_XOR2( CPU_MAXIMUM_PROCESSORS, a, b, c ); + __BIT_XOR2( CPU_MAXIMUM_PROCESSORS, a, b, c ); } /** @@ -284,7 +324,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_Xor( */ RTEMS_INLINE_ROUTINE uint32_t _Processor_mask_Count( const Processor_mask *a ) { - return (uint32_t) BIT_COUNT( CPU_MAXIMUM_PROCESSORS, a ); + return (uint32_t) __BIT_COUNT( CPU_MAXIMUM_PROCESSORS, a ); } /** @@ -296,7 +336,7 @@ RTEMS_INLINE_ROUTINE uint32_t _Processor_mask_Count( const Processor_mask *a ) */ RTEMS_INLINE_ROUTINE uint32_t _Processor_mask_Find_last_set( const Processor_mask *a ) { - return (uint32_t) BIT_FLS( CPU_MAXIMUM_PROCESSORS, a ); + return (uint32_t) __BIT_FLS( CPU_MAXIMUM_PROCESSORS, a ); } /** @@ -347,7 +387,7 @@ RTEMS_INLINE_ROUTINE void _Processor_mask_From_index( uint32_t index ) { - BIT_SETOF( CPU_MAXIMUM_PROCESSORS, (int) index, mask ); + __BIT_SETOF( CPU_MAXIMUM_PROCESSORS, (int) index, mask ); } typedef enum { diff --git a/cpukit/include/rtems/score/scheduleredfimpl.h b/cpukit/include/rtems/score/scheduleredfimpl.h index e0a07a8915..06a35ae95f 100644 --- a/cpukit/include/rtems/score/scheduleredfimpl.h +++ b/cpukit/include/rtems/score/scheduleredfimpl.h @@ -39,7 +39,7 @@ #define _RTEMS_SCORE_SCHEDULEREDFIMPL_H #include <rtems/score/scheduleredf.h> -#include <rtems/score/schedulerimpl.h> +#include <rtems/score/scheduleruniimpl.h> #ifdef __cplusplus extern "C" { @@ -216,30 +216,23 @@ RTEMS_INLINE_ROUTINE void _Scheduler_EDF_Extract_body( } /** - * @brief Schedules the next ready thread as the heir. + * @brief Gets the highest priority ready thread of the scheduler. * - * @param scheduler The scheduler instance to schedule the minimum of the context of. - * @param the_thread This parameter is not used. - * @param force_dispatch Indicates whether the current heir is blocked even if it is - * not set as preemptible. + * @param scheduler is the scheduler. */ -RTEMS_INLINE_ROUTINE void _Scheduler_EDF_Schedule_body( - const Scheduler_Control *scheduler, - Thread_Control *the_thread, - bool force_dispatch +RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_EDF_Get_highest_ready( + const Scheduler_Control *scheduler ) { Scheduler_EDF_Context *context; RBTree_Node *first; Scheduler_EDF_Node *node; - (void) the_thread; - context = _Scheduler_EDF_Get_context( scheduler ); first = _RBTree_Minimum( &context->Ready ); node = RTEMS_CONTAINER_OF( first, Scheduler_EDF_Node, Node ); - _Scheduler_Update_heir( node->Base.owner, force_dispatch ); + return node->Base.owner; } /** @} */ diff --git a/cpukit/include/rtems/score/schedulerimpl.h b/cpukit/include/rtems/score/schedulerimpl.h index 806cb4e145..33070651db 100644 --- a/cpukit/include/rtems/score/schedulerimpl.h +++ b/cpukit/include/rtems/score/schedulerimpl.h @@ -669,40 +669,6 @@ Status_Control _Scheduler_Set_affinity( ); /** - * @brief Blocks the thread. - * - * @param scheduler The scheduler instance. - * @param the_thread The thread to block. - * @param node The corresponding scheduler node. - * @param extract Method to extract the thread. - * @param schedule Method for scheduling threads. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block( - const Scheduler_Control *scheduler, - Thread_Control *the_thread, - Scheduler_Node *node, - void ( *extract )( - const Scheduler_Control *, - Thread_Control *, - Scheduler_Node * - ), - void ( *schedule )( - const Scheduler_Control *, - Thread_Control *, - bool - ) -) -{ - ( *extract )( scheduler, the_thread, node ); - - /* TODO: flash critical section? */ - - if ( _Thread_Is_heir( the_thread ) ) { - ( *schedule )( scheduler, the_thread, true ); - } -} - -/** * @brief Gets the number of processors of the scheduler. * * @param scheduler The scheduler instance to get the number of processors of. @@ -952,37 +918,6 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Discard_idle_thread( #endif /** - * @brief Updates the heir. - * - * @param[in, out] new_heir The new heir. - * @param force_dispatch Indicates whether the dispatch happens also if the - * currently running thread is set as not preemptible. - */ -RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir( - Thread_Control *new_heir, - bool force_dispatch -) -{ - Thread_Control *heir = _Thread_Heir; - - if ( heir != new_heir && ( heir->is_preemptible || force_dispatch ) ) { -#if defined(RTEMS_SMP) - /* - * We need this state only for _Thread_Get_CPU_time_used_locked(). Cannot - * use _Scheduler_Thread_change_state() since THREAD_SCHEDULER_BLOCKED to - * THREAD_SCHEDULER_BLOCKED state changes are illegal for the real SMP - * schedulers. - */ - heir->Scheduler.state = THREAD_SCHEDULER_BLOCKED; - new_heir->Scheduler.state = THREAD_SCHEDULER_SCHEDULED; -#endif - _Thread_Update_CPU_time_used( heir, _Thread_Get_CPU( heir ) ); - _Thread_Heir = new_heir; - _Thread_Dispatch_necessary = true; - } -} - -/** * @brief Sets a new scheduler. * * @param new_scheduler The new scheduler to set. diff --git a/cpukit/include/rtems/score/schedulerpriorityimpl.h b/cpukit/include/rtems/score/schedulerpriorityimpl.h index d8d226d6f1..06d2027a45 100644 --- a/cpukit/include/rtems/score/schedulerpriorityimpl.h +++ b/cpukit/include/rtems/score/schedulerpriorityimpl.h @@ -41,7 +41,7 @@ #include <rtems/score/schedulerpriority.h> #include <rtems/score/chainimpl.h> #include <rtems/score/prioritybitmapimpl.h> -#include <rtems/score/schedulerimpl.h> +#include <rtems/score/scheduleruniimpl.h> #include <rtems/score/thread.h> #ifdef __cplusplus @@ -231,33 +231,21 @@ RTEMS_INLINE_ROUTINE Chain_Node *_Scheduler_priority_Ready_queue_first( } /** - * @brief Scheduling decision logic. + * @brief Gets the highest priority ready thread of the scheduler. * - * This kernel routine implements scheduling decision logic - * for priority-based scheduling. - * - * @param[in, out] scheduler The scheduler instance. - * @param the_thread This parameter is unused. - * @param force_dispatch Indicates whether the dispatch happens also if - * the currently executing thread is set as not preemptible. + * @param scheduler is the scheduler. */ -RTEMS_INLINE_ROUTINE void _Scheduler_priority_Schedule_body( - const Scheduler_Control *scheduler, - Thread_Control *the_thread, - bool force_dispatch +RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_priority_Get_highest_ready( + const Scheduler_Control *scheduler ) { Scheduler_priority_Context *context = _Scheduler_priority_Get_context( scheduler ); - Thread_Control *heir = (Thread_Control *) - _Scheduler_priority_Ready_queue_first( - &context->Bit_map, - &context->Ready[ 0 ] - ); - ( void ) the_thread; - - _Scheduler_Update_heir( heir, force_dispatch ); + return (Thread_Control *) _Scheduler_priority_Ready_queue_first( + &context->Bit_map, + &context->Ready[ 0 ] + ); } /** diff --git a/cpukit/include/rtems/score/schedulersimpleimpl.h b/cpukit/include/rtems/score/schedulersimpleimpl.h index 2aaf0fe17e..2293433870 100644 --- a/cpukit/include/rtems/score/schedulersimpleimpl.h +++ b/cpukit/include/rtems/score/schedulersimpleimpl.h @@ -39,7 +39,7 @@ #include <rtems/score/schedulersimple.h> #include <rtems/score/chainimpl.h> -#include <rtems/score/schedulerimpl.h> +#include <rtems/score/scheduleruniimpl.h> #ifdef __cplusplus extern "C" { @@ -133,28 +133,18 @@ RTEMS_INLINE_ROUTINE void _Scheduler_simple_Extract( } /** - * @brief Scheduling decision logic. + * @brief Gets the highest priority ready thread of the scheduler. * - * This kernel routine implements scheduling decision logic for the simple scheduler. - * - * @param[in, out] scheduler The scheduler instance. - * @param the_thread This parameter is unused. - * @param force_dispatch Indicates whether the dispatch happens also if - * the currently executing thread is set as not preemptible. + * @param scheduler is the scheduler. */ -RTEMS_INLINE_ROUTINE void _Scheduler_simple_Schedule_body( - const Scheduler_Control *scheduler, - Thread_Control *the_thread, - bool force_dispatch +RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_simple_Get_highest_ready( + const Scheduler_Control *scheduler ) { Scheduler_simple_Context *context = _Scheduler_simple_Get_context( scheduler ); - Thread_Control *heir = (Thread_Control *) _Chain_First( &context->Ready ); - - ( void ) the_thread; - _Scheduler_Update_heir( heir, force_dispatch ); + return (Thread_Control *) _Chain_First( &context->Ready ); } /** @} */ diff --git a/cpukit/include/rtems/score/scheduleruniimpl.h b/cpukit/include/rtems/score/scheduleruniimpl.h new file mode 100644 index 0000000000..faa719ce45 --- /dev/null +++ b/cpukit/include/rtems/score/scheduleruniimpl.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreScheduler + * + * @brief This header file provides interfaces of the supporting the + * implementation of uniprocessor schedulers. + */ + +/* + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * Copyright (C) 2014, 2022 embedded brains GmbH + * + * 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. + */ + +#ifndef _RTEMS_SCORE_SCHEDULERUNIIMPL_H +#define _RTEMS_SCORE_SCHEDULERUNIIMPL_H + +#include <rtems/score/schedulerimpl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup RTEMSScoreScheduler + * + * @{ + */ + +/** + * @brief Updates the heir thread of the processor. + * + * @param[in, out] heir is the current heir thread. + * @param[in, out] new_heir is the new heir thread. + */ +RTEMS_INLINE_ROUTINE void _Scheduler_uniprocessor_Update_heir( + Thread_Control *heir, + Thread_Control *new_heir +) +{ + _Assert( heir != new_heir ); +#if defined(RTEMS_SMP) + /* + * We need this state only for _Thread_Get_CPU_time_used_locked(). Cannot + * use _Scheduler_Thread_change_state() since THREAD_SCHEDULER_BLOCKED to + * THREAD_SCHEDULER_BLOCKED state changes are illegal for the real SMP + * schedulers. + */ + heir->Scheduler.state = THREAD_SCHEDULER_BLOCKED; + new_heir->Scheduler.state = THREAD_SCHEDULER_SCHEDULED; +#endif + _Thread_Update_CPU_time_used( heir, _Thread_Get_CPU( heir ) ); + _Thread_Heir = new_heir; + _Thread_Dispatch_necessary = true; +} + +/** + * @brief Updates the heir thread of the processor if the current heir is + * not equal to the new heir thread. + * + * The update takes place even if the current heir thread is not preemptible. + * + * @param[in, out] new_heir is the new heir thread. + */ +RTEMS_INLINE_ROUTINE void _Scheduler_uniprocessor_Update_heir_if_necessary( + Thread_Control *new_heir +) +{ + Thread_Control *heir = _Thread_Heir; + + if ( heir != new_heir ) { + _Scheduler_uniprocessor_Update_heir( heir, new_heir ); + } +} + +/** + * @brief Updates the heir thread of the processor if the current heir thread + * is preemptible. + * + * @param[in, out] heir is the current heir thread. + * @param[in, out] new_heir is the new heir thread. + */ +RTEMS_INLINE_ROUTINE void _Scheduler_uniprocessor_Update_heir_if_preemptible( + Thread_Control *heir, + Thread_Control *new_heir +) +{ + if ( heir != new_heir && heir->is_preemptible ) { + _Scheduler_uniprocessor_Update_heir( heir, new_heir ); + } +} + +/** + * @brief Blocks the thread. + * + * @param scheduler is the scheduler. + * @param the_thread is the thread to block. + * @param node is the scheduler node of the thread. + * @param extract is the handler to extract the thread. + * @param get_highest_ready is the handler to get the highest ready thread. + */ +RTEMS_INLINE_ROUTINE void _Scheduler_uniprocessor_Block( + const Scheduler_Control *scheduler, + Thread_Control *the_thread, + Scheduler_Node *node, + void ( *extract )( + const Scheduler_Control *, + Thread_Control *, + Scheduler_Node * + ), + Thread_Control *( *get_highest_ready )( const Scheduler_Control * ) +) +{ + ( *extract )( scheduler, the_thread, node ); + + /* TODO: flash critical section? */ + + if ( _Thread_Is_heir( the_thread ) ) { + Thread_Control *highest_ready; + + highest_ready = ( *get_highest_ready )( scheduler ); + _Scheduler_uniprocessor_Update_heir( _Thread_Heir, highest_ready ); + } +} + +/** + * @brief Schedule the unblocked thread if it is the highest ready thread. + * + * @param scheduler is the scheduler. + * @param the_thread is the thread. + * @param priority is the priority of the thread. + */ +RTEMS_INLINE_ROUTINE void _Scheduler_uniprocessor_Unblock( + const Scheduler_Control *scheduler, + Thread_Control *the_thread, + Priority_Control priority +) +{ + Thread_Control *heir; + + heir = _Thread_Heir; + + /* + * If the thread is more important than the heir, then we have a new heir. + * This may or may not result in a context switch. If the current heir + * thread is preemptible, then we need to do a context switch. + */ + if ( priority < _Thread_Get_priority( heir ) ) { + _Scheduler_uniprocessor_Update_heir_if_preemptible( heir, the_thread ); + } +} + +/** + * @brief Schedules the highest ready thread if the current heir thread of the + * processor is preemptible. + * + * @param scheduler is the scheduler. + * @param get_highest_ready is the handler to get the highest ready thread. + */ +RTEMS_INLINE_ROUTINE void _Scheduler_uniprocessor_Schedule( + const Scheduler_Control *scheduler, + Thread_Control *( *get_highest_ready )( const Scheduler_Control * ) +) +{ + Thread_Control *highest_ready; + + highest_ready = ( *get_highest_ready )( scheduler ); + _Scheduler_uniprocessor_Update_heir_if_preemptible( + _Thread_Heir, + highest_ready + ); +} + +/** + * @brief Yields to the highest ready thread. + * + * @param scheduler is the scheduler. + * @param get_highest_ready is the handler to get the highest ready thread. + */ +RTEMS_INLINE_ROUTINE void _Scheduler_uniprocessor_Yield( + const Scheduler_Control *scheduler, + Thread_Control *( *get_highest_ready )( const Scheduler_Control * ) +) +{ + Thread_Control *highest_ready; + + highest_ready = ( *get_highest_ready )( scheduler ); + _Scheduler_uniprocessor_Update_heir_if_necessary( highest_ready ); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _RTEMS_SCORE_SCHEDULERUNIIMPL_H */ diff --git a/cpukit/include/rtems/score/thread.h b/cpukit/include/rtems/score/thread.h index dd32b51a5f..40fefbc79a 100644 --- a/cpukit/include/rtems/score/thread.h +++ b/cpukit/include/rtems/score/thread.h @@ -921,8 +921,12 @@ struct _Thread_Control { */ Context_Control_fp *fp_context; #endif + +#ifndef _REENT_THREAD_LOCAL /** This field points to the newlib reentrancy structure for this thread. */ struct _reent *libc_reent; +#endif + /** This array contains the API extension area pointers. */ void *API_Extensions[ THREAD_API_LAST + 1 ]; @@ -1147,9 +1151,11 @@ Objects_Control *_Thread_Allocate_unlimited( Objects_Information *information ); #define THREAD_INFORMATION_DEFINE( name, api, cls, max ) \ static Objects_Control * \ name##_Local_table[ _Objects_Maximum_per_allocation( max ) ]; \ -static Thread_Configured_control \ +static RTEMS_SECTION( ".noinit.rtems.content.objects." #name ) \ +Thread_Configured_control \ name##_Objects[ _Objects_Maximum_per_allocation( max ) ]; \ -static Thread_queue_Configured_heads \ +static RTEMS_SECTION( ".noinit.rtems.content.objects." #name ) \ +Thread_queue_Configured_heads \ name##_Heads[ _Objects_Maximum_per_allocation( max ) ]; \ Thread_Information name##_Information = { \ { \ diff --git a/cpukit/include/rtems/score/threadimpl.h b/cpukit/include/rtems/score/threadimpl.h index 10800aa023..638815237f 100644 --- a/cpukit/include/rtems/score/threadimpl.h +++ b/cpukit/include/rtems/score/threadimpl.h @@ -380,15 +380,23 @@ RTEMS_NO_RETURN void _Thread_Exit( ); /** - * @brief Joins the currently executing thread with the given thread to wait - * for. + * @brief Joins the currently executing thread with the thread. * - * @param[in, out] the_thread The thread to wait for. - * @param waiting_for_join The states control for the join. - * @param[in, out] executing The currently executing thread. - * @param queue_context The thread queue context. + * @param[in, out] the_thread is the thread to join. + * + * @param waiting_for_join is the thread state for the currently executing + * thread. + * + * @param[in, out] executing is the currently executing thread. + * + * @param queue_context[in, out] is the thread queue context. The caller shall + * have acquired the thread state lock using the thread queue context. + * + * @retval STATUS_SUCCESSFUL The operation was successful. + * + * @retval STATUS_DEADLOCK A deadlock occurred. */ -void _Thread_Join( +Status_Control _Thread_Join( Thread_Control *the_thread, States_Control waiting_for_join, Thread_Control *executing, @@ -396,23 +404,38 @@ void _Thread_Join( ); /** + * @brief Indicates the resulting state of _Thread_Cancel(). + */ +typedef enum { + /** + * @brief Indicates that the thread cancel operation is done. + */ + THREAD_CANCEL_DONE, + + /** + * @brief Indicates that the thread cancel operation is in progress. + * + * The cancelled thread is terminating. It may be joined. + */ + THREAD_CANCEL_IN_PROGRESS +} Thread_Cancel_state; + +/** * @brief Cancels the thread. * - * @param[in, out] the_thread The thread to cancel. - * @param executing The currently executing thread. - * @param exit_value The exit value for the thread. + * @param[in, out] the_thread is the thread to cancel. + + * @param[in, out] executing is the currently executing thread. + + * @param[in, out] life_states_to_clear is the set of thread life states to + * clear for the thread to cancel. */ -void _Thread_Cancel( - Thread_Control *the_thread, - Thread_Control *executing, - void *exit_value +Thread_Cancel_state _Thread_Cancel( + Thread_Control *the_thread, + Thread_Control *executing, + Thread_Life_state life_states_to_clear ); -typedef struct { - Thread_queue_Context Base; - Thread_Control *cancel; -} Thread_Close_context; - /** * @brief Closes the thread. * @@ -420,14 +443,21 @@ typedef struct { * case the executing thread is not terminated, then this function waits until * the terminating thread reached the zombie state. * - * @param the_thread The thread to close. - * @param executing The currently executing thread. - * @param[in, out] context The thread close context. + * @param the_thread is the thread to close. + * + * @param[in, out] executing is the currently executing thread. + * + * @param[in, out] queue_context is the thread queue context. The caller shall + * have disabled interrupts using the thread queue context. + * + * @retval STATUS_SUCCESSFUL The operation was successful. + * + * @retval STATUS_DEADLOCK A deadlock occurred. */ -void _Thread_Close( +Status_Control _Thread_Close( Thread_Control *the_thread, Thread_Control *executing, - Thread_Close_context *context + Thread_queue_Context *queue_context ); /** @@ -778,6 +808,7 @@ RTEMS_INLINE_ROUTINE void _Thread_Priority_change( ); } +#if defined(RTEMS_SMP) /** * @brief Replaces the victim priority node with the replacement priority node * in the corresponding thread priority aggregation. @@ -795,6 +826,7 @@ void _Thread_Priority_replace( Priority_Node *victim_node, Priority_Node *replacement_node ); +#endif /** * @brief Updates the priority of all threads in the set diff --git a/cpukit/include/rtems/score/timecounter.h b/cpukit/include/rtems/score/timecounter.h index 1ecfc02085..6559801559 100644 --- a/cpukit/include/rtems/score/timecounter.h +++ b/cpukit/include/rtems/score/timecounter.h @@ -292,6 +292,31 @@ void _Timecounter_Set_NTP_update_second( */ void _Timecounter_NTP_update_second(int64_t *adjustment, time_t *newsec); +/** + * @brief Gets the frequency in Hz of the current timecounter at some time + * point during the call. + * + * @return Returns the frequency in Hz. + */ +uint64_t _Timecounter_Get_frequency(void); + +/** + * @brief Updates the timecounter frequency adjustment used by + * _Timecounter_Set_NTP_update_second(). + * + * This function is part of the time synchronization using a PPS + * (Pulse Per Second) signal. + * + * When an event (a rising or falling edge of the PPS signal) occurs, the + * functions pps_capture() and pps_event() are executed. Only if the kernel + * consumer is configured to be PPS_KC_HARDPPS, the timecounter is disciplined. + * + * @param[in] tsp is the time at PPS event + * + * @param[i] nsec is the time in nanoseconds from the last PPS event + */ +void _Timecounter_Discipline(struct timespec *tsp, long nsec); + /** @} */ #ifdef __cplusplus diff --git a/cpukit/include/rtems/shellconfig.h b/cpukit/include/rtems/shellconfig.h index b09d5ae1d3..a013840ee7 100644 --- a/cpukit/include/rtems/shellconfig.h +++ b/cpukit/include/rtems/shellconfig.h @@ -110,6 +110,7 @@ extern rtems_shell_cmd_t rtems_shell_STACKUSE_Command; extern rtems_shell_cmd_t rtems_shell_PERIODUSE_Command; extern rtems_shell_cmd_t rtems_shell_PROFREPORT_Command; extern rtems_shell_cmd_t rtems_shell_WKSPACE_INFO_Command; +extern rtems_shell_cmd_t rtems_shell_RTEMS_Command; extern rtems_shell_cmd_t rtems_shell_MALLOC_INFO_Command; extern rtems_shell_cmd_t rtems_shell_RTRACE_Command; #if RTEMS_NETWORKING @@ -489,6 +490,11 @@ extern rtems_shell_alias_t * const rtems_shell_Initial_aliases[]; defined(CONFIGURE_SHELL_COMMAND_WKSPACE_INFO) &rtems_shell_WKSPACE_INFO_Command, #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_RTEMS)) || \ + defined(CONFIGURE_SHELL_COMMAND_RTEMS) + &rtems_shell_RTEMS_Command, + #endif /* * Malloc family commands diff --git a/cpukit/include/rtems/test-info.h b/cpukit/include/rtems/test-info.h index 1bc963249c..3b839533c2 100644 --- a/cpukit/include/rtems/test-info.h +++ b/cpukit/include/rtems/test-info.h @@ -70,7 +70,7 @@ void rtems_test_fatal_extension( * @brief Initial extension for tests. */ #define RTEMS_TEST_INITIAL_EXTENSION \ - { NULL, NULL, NULL, NULL, NULL, NULL, NULL, rtems_test_fatal_extension } + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, rtems_test_fatal_extension, NULL } /** * @brief Test states. @@ -108,14 +108,14 @@ typedef enum /** * @brief Prints a begin of test message using printf(). * - * @returns As specified by printf(). + * @return As specified by printf(). */ int rtems_test_begin(const char* name, const RTEMS_TEST_STATE state); /** * @brief Prints an end of test message using printf(). * - * @returns As specified by printf(). + * @return As specified by printf(). */ int rtems_test_end(const char* name); @@ -128,7 +128,7 @@ RTEMS_NO_RETURN void rtems_test_exit(int status); /** * @brief Prints via the RTEMS printer. * - * @returns As specified by printf(). + * @return As specified by printf(). */ int rtems_test_printf(const char* format, ...) RTEMS_PRINTFLIKE(1, 2); @@ -331,6 +331,12 @@ RTEMS_NO_RETURN void rtems_test_run( const RTEMS_TEST_STATE state ); +/** + * @brief Dumps the gcov information as a base64 encoded gcfn and gcda data + * stream using rtems_put_char(). + */ +void rtems_test_gcov_dump_info( void ); + /** @} */ #ifdef __cplusplus diff --git a/cpukit/include/rtems/test.h b/cpukit/include/rtems/test.h index 305fe3f5f3..c283be7860 100644 --- a/cpukit/include/rtems/test.h +++ b/cpukit/include/rtems/test.h @@ -2464,6 +2464,8 @@ T_thread_switch_log *T_thread_switch_record_10(T_thread_switch_log_10 *); void T_report_hash_sha256(T_event, const char *); +void T_report_hash_sha256_update(char c); + void T_check_heap(T_event, const char *); #ifdef __rtems__ diff --git a/cpukit/include/rtems/tftp.h b/cpukit/include/rtems/tftp.h index 8fa516042b..d2328e3cdc 100644 --- a/cpukit/include/rtems/tftp.h +++ b/cpukit/include/rtems/tftp.h @@ -1,13 +1,20 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * - * @brief * Trivial File Transfer Protocol (TFTP) + * @ingroup RTEMSImplTFTPFS + * + * @brief This header file provides interfaces and functions used to + * implement the TFTP file system. * - * Transfer file to/from remote host + * This file declares the public functions of the Trivial File + * Transfer Protocol (TFTP) file system. */ /* - * Copyright (c) 1998 Eric Norum <eric@norum.ca> + * Copyright (C) 1998 W. Eric Norum <eric@norum.ca> + * Copyright (C) 2022 embedded brains GmbH (http://www.embedded-brains.de) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,16 +38,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/* - * Usage: - * - * To open `/bootfiles/image' on `hostname' for reading: - * fd = open ("/TFTP/hostname/bootfiles/image", O_RDONLY); - * - * The 'TFTP' is the mount path and the `hostname' must be four dot-separated - * decimal values. - */ - #ifndef _RTEMS_TFTP_H #define _RTEMS_TFTP_H @@ -48,9 +45,14 @@ extern "C" { #endif +#include <stdint.h> #include <rtems/fs.h> -/* +/** + * @brief Do not call directly, use mount(). + * + * @ingroup RTEMSImplTFTPFS + * * Filesystem Mount table entry. */ int rtems_tftpfs_initialize( @@ -58,6 +60,383 @@ int rtems_tftpfs_initialize( const void *data ); +/** + * @defgroup RTEMSAPITFTPFS Trivial File Transfer Protocol (TFTP) API + * + * @ingroup RTEMSAPIIO + * + * @brief The TFTP client library provides an API to read files from and + * to write files to remote servers using the Trivial File Transfer + * Protocol (TFTP). + * + * See the _RTEMS Filesystem Design Guide_ Chapter _Trivial FTP Client + * Filesystem_. + * + * Usage as TFTP File System + * ========================= + * + * To open `/bootfiles/image` on `hostname` for reading: + * + * fd = open ("/TFTP/hostname:bootfiles/image", O_RDONLY); + * + * The `TFTP` is the mount path and the `hostname` must be + * + * + an IPv4 address (like `127.0.0.1`) or + * + the (full-qualified) name of an IPv4 host (acceptable to + * `gethostbyname()`) + * + * IPv6 is currently not supported. `bootfiles/image` is a path on the + * TFTP server `hostname` where the file (here `image`) can be found. + * + * Usage of TFTP Client + * ==================== + * + * The pseudo-code below shows the principal usage for reading a file. + * + * @code + * int res; + * ssize_t bytes; + * void *tftp_handle; + * tftp_net_config config; + * const size_t buffer_size = 4000; + * char data_buffer[buffer_size]; + * + * tftp_initialize_net_config( &config ); + * config.options.window_size = 1; // Set desired config values + * + * res = tftp_open( + * "127.0.0.1", + * "filename.txt", + * true, // is_for_reading + * &config, + * &tftp_handle + * ); + * + * if ( res != 0 || tftp_handle == NULL ) { + * // Error + * } + * + * // Use tftp_read() (probably in a loop) ... + * bytes = tftp_read( + * tftp_handle, + * data_buffer, + * buffer_size + * ); + * // ... or use tftp_write() instead when the file is open for writing. + * + * res = tftp_close( tftp_handle ); + * + * if ( res != 0 ) { + * // Error ... check! Especially when writing! + * } + * @endcode + * + * @{ + */ + +/* + * The functions below use of the TFTP client library standalone + * - i.e. without going through the file system. + */ + +/** + * @brief This block size meets RFC 1350 and avoids the sending of + * the `blksize` option to the TFTP server. + */ +#define TFTP_RFC1350_BLOCK_SIZE 512 + +/** + * @brief This window size avoids the sending of the `windowsize` + * option to the TFTP server. + * + * This effectively mimics the operation defined in RFC 1350 which + * does not know any window size. + */ +#define TFTP_RFC1350_WINDOW_SIZE 1 + +/** + * @brief This block size is suggested in RFC 2348 and is used as + * default if no different block size is provided. + */ +#define TFTP_DEFAULT_BLOCK_SIZE 1456 + +/** + * @brief This window size is suggested in RFC 2348 and is used as + * default if no different window size is provided. + */ +#define TFTP_DEFAULT_WINDOW_SIZE 8 + +/** + * @brief This structure represents TFTP options negotiated between + * client and server. + * + * RFC 2347 is the basis for the TFTP option. + */ +typedef struct tftp_options { + /** + * @brief This member represents the desired size of a data block. + * + * The TFTP blocksize option is introduced in RFC 2348. It defines the + * number of octets in the data packets transferred. Valid values + * range between 8 and 65464 octets, inclusive. Values larger + * than 1468 may cause packet fragmentation over standard Ethernet. + * A value of 512 will prevent this option from being sent to + * the server. + * + * The default value is 1456. + */ + uint16_t block_size; + + /** + * @brief This member represents the desired size of a window. + * + * The TFTP windowsize option is introduced in RFC 7440. It defines the + * number of data packets send before the receiver must send an + * acknowledgment packet. Valid values range between 1 and 65535 + * packets, inclusive. Simple TFTP servers usually do not support this + * option. This option may negatively contribute to network + * congestion. This can be avoided by using a window size of 1. + * A value of 1 will prevent this option from being sent to + * the server. + * + * The default value is 8. + */ + uint16_t window_size; +} tftp_options; + +/** + * @brief This structure represents configuration value used by the TFTP + * client. + * + * As defaults the values suggested in RFC 7440 are used. + */ +typedef struct tftp_net_config { + /** + * @brief This member defines how many attempts are made to send a + * network packet to the server. + * + * Repetitions occur when the server does not response to a packet + * send by the client within a timeout period. When the here defined + * number of repetitions is reached and the server does still not + * respond, the connection is considered broken and the file transfer + * is ended with an error. + * + * The default value is 6. + */ + uint16_t retransmissions; + + /** + * @brief This member defines the port on which the server is listening + * for incoming connections. + * + * The default port number is 69. + */ + uint16_t server_port; + + /** + * @brief This member defines the maximum time in milliseconds the + * client waits for an answer packet from the server. + * + * If the time out is exceeded, the client will re-transmit the last + * packet it send to the server. In case @c window_size is larger one, + * several packets may subject to re-transmission. + * + * Note that this timeout applies only after the first re-transmission + * of a packet. The timeout till the first re-transmission is + * @c first_timeout. + * + * The default value is 1000ms. + */ + uint32_t timeout; + + /** + * @brief This member defines the maximum time in milliseconds the + * client waits for the first answer packet from the server. + * + * The @c first_timeout is used instead of the regular @c timeout + * for the first wait-period directly after the client sends a packet + * for the first time to the server. That is, this is the timeout + * of the first re-transmission. For any following re-transmissions + * of the current packet the regular @c timeout is used. + * + * The default value is 400ms. + */ + uint32_t first_timeout; + + /** + * @brief This member represents the options to be sent to the server. + * + * These option values are sent to the server. Yet, the server may + * + * + ignore one or all options + * + ask the client to use a different value for an option + * + reject the whole request with an error + * + * If the server rejects a request with options, the current client + * implementation will automatically send a second request without + * options. Hence, the user should be aware that the actual file + * transfer may not use the option values specified here. + */ + tftp_options options; +} tftp_net_config; + +/** + * @brief Set all members of a @c tftp_net_config structure to their + * default values. + * + * @param config references a @c tftp_net_config structure. + * The values are set to the defaults defined in + * @ref tftp_net_config "`type tftp_net_config`". + */ +void tftp_initialize_net_config( + tftp_net_config *config +); + +/** + * @brief Opens and starts a TFTP client session to read or write a + * single file. + * + * This directive resolves the hostname or IP address, establishes a connection + * to the TFTP server and initiates the data transfer. It will not return + * before an error is encountered or the TFTP server has responded to the + * read or write request with a network packet. + * + * TFTP uses timeouts (of unspecified length). It does not know keep-alive + * messages. If the client does not respond to the server in due time, + * the server sets the connection faulty and drops it. To avoid this + * the user of this code must read or write enough data fast enough. + * + * "Enough data" means at least so much data which fills a single data + * packet or all packets of a window if windows are used. The data + * can be read or written in anything from one single large chunk to + * byte-by-byte pieces. The point is, one cannot pause the reading + * or writing for longer periods of time. + * + * @param hostname is the IPv4 address as string or the name of the TFTP + * server to connect to. + * @param path is the pathname at the TFTP server side of the file to + * read or write. According to RFC 1350 the path must be in + * NETASCII. This is ASCII as defined in "USA Standard Code for + * Information Interchange" with the modifications specified in "Telnet + * Protocol Specification". + * @param is_for_reading indicated whether the file is to be read or written. + * A value of @c true indicates that the file is intended to be read from + * the server. A value of @c false indicates that the file is to be + * written to the server. + * @param config either references a structure defining the configuration + * values for this file transfer or is @c NULL. If it is @c NULL, default + * configuration values are used. See @ref tftp_net_config + * "type tftp_net_config" for a description and the defaults values. + * This function copies the data so that the memory pointed to by + * @c config can be used for other purposes after the call returns. + * @param[out] tftp_handle references a place where a handle of the connection + * can be stored. On success a pointer to a handle is stored. On failure + * (return value other than 0) a @c NULL pointer is stored. This handle + * must be provided to all further calls to @c tftp_read(), + * @c tftp_write(), and @c tftp_close(). + * + * When this directive stores a non-NULL pointer in this place, a call + * to @c tftp_close() is mandatory to release allocated resources. + * This parameter cannot be @c NULL. + * + * @retval 0 When the client session was opened successfully. + * @return Returns a POSIX @c errno value in case an error occurred. + */ +int tftp_open( + const char *hostname, + const char *path, + bool is_for_reading, + const tftp_net_config *config, + void **tftp_handle +); + +/** + * @brief Read data from a TFTP server. + * + * This directive attempts to read data from a TFTP connection open for + * reading. + * + * Upon success, the buffer is always filled with @c count bytes of received + * data with the exception when the end of the file has been reached. + * + * TFTP cannot recover from errors. Once an error is reported, the + * connection must be and can only be closed. + * + * @param tftp_handle is the reference returned by a call to tftp_open(). + * The file must be opened for reading. + * @param[out] buffer references a memory area into which the received + * data is written. + * @param count defines the size of the @c buffer in bytes. + * + * @retval 0 The end of the file has been reached. There is no more data. + * @return If greater or equal to 0, returns the number of bytes written + * into the buffer. If the return value is negative, an error occurred. + * In this case the negated value is a POSIX @c errno value. + */ +ssize_t tftp_read( + void *tftp_handle, + void *buffer, + size_t count +); + +/** + * @brief Write data to a TFTP server. + * + * This directive attempts to write data to a TFTP connection open for + * writing. + * + * On a successful call, all data in the @c buffer will be used. Yet, this + * does not imply that all data is actually sent. This depends on + * whether a whole data packet or window can be filled. + * + * TFTP cannot recover from errors. Once an error is reported, the connection + * must be and can only be closed. + * + * @param tftp_handle is the reference returned by a call to tftp_open(). + * The file must be opened for writing. + * @param buffer references a memory area which contains the data to be + * sent. + * @param count defines the size of the data in @c buffer in bytes. + * + * @return If greater or equal to 0, returns the number of bytes used + * from the buffer. The value is always @c count on a successful call. + * If the return value is negative, an error occurred. In this case + * the negated value is a POSIX @c errno value. + */ +ssize_t tftp_write( + void *tftp_handle, + const void *buffer, + size_t count +); + +/** + * @brief Close a TFTP client connection. + * + * This directive sends all data which are still stored in a write buffer + * to the server (if any), tells the server that the connection ends (if + * required by RFC 1350) and releases any resources allocated at the + * client side. + * + * @note Especially, when writing a file to the server, the return + * code of `tftp_close()` should be checked. Invoking + * `tftp_close()` triggers the sending of the last -- not + * completely filled -- data block. This may fail the same way as any + * `tftp_write()` may fail. Therefore, an error returned by + * `tftp_close()` likely indicates that the file was not + * completely transferred. + * + * @param tftp_handle is the reference returned by a call to tftp_open(). + * If this parameter is @c NULL, the directive call is a no-op. + * + * @retval 0 When the client session was closed successfully. + * @return Returns a POSIX @c errno value in case an error occurred. + */ +int tftp_close( + void *tftp_handle +); + +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpukit/include/sys/exec_elf.h b/cpukit/include/sys/exec_elf.h index 4242415f54..dc56237f16 100644 --- a/cpukit/include/sys/exec_elf.h +++ b/cpukit/include/sys/exec_elf.h @@ -1,4 +1,4 @@ -/* $NetBSD: exec_elf.h,v 1.102 2010/03/01 11:27:29 skrll Exp $ */ +/* $NetBSD: exec_elf.h,v 1.168 2020/10/19 19:33:02 christos Exp $ */ /*- * Copyright (c) 1994 The NetBSD Foundation, Inc. @@ -44,6 +44,7 @@ #include <sys/types.h> #else #include <inttypes.h> +#include <stddef.h> #endif /* _KERNEL || _STANDALONE */ #if defined(ELFSIZE) @@ -60,49 +61,41 @@ #include <machine/elf_machdep.h> #endif -typedef uint8_t Elf_Byte; - -typedef uint32_t Elf32_Addr; -#define ELF32_FSZ_ADDR 4 -typedef uint32_t Elf32_Off; -typedef int32_t Elf32_SOff; -#define ELF32_FSZ_OFF 4 -typedef int32_t Elf32_Sword; -#define ELF32_FSZ_SWORD 4 -typedef uint32_t Elf32_Word; -#define ELF32_FSZ_WORD 4 -typedef uint16_t Elf32_Half; -#define ELF32_FSZ_HALF 2 -typedef uint64_t Elf32_Lword; -#define ELF32_FSZ_LWORD 8 - -typedef uint64_t Elf64_Addr; -#define ELF64_FSZ_ADDR 8 -typedef uint64_t Elf64_Off; -typedef int64_t Elf64_SOff; -#define ELF64_FSZ_OFF 8 -typedef int32_t Elf64_Shalf; -#define ELF64_FSZ_SHALF 4 - -#ifndef ELF64_FSZ_SWORD -typedef int32_t Elf64_Sword; -#define ELF64_FSZ_SWORD 4 -#endif /* ELF64_FSZ_SWORD */ -#ifndef ELF64_FSZ_WORD -typedef uint32_t Elf64_Word; -#define ELF64_FSZ_WORD 4 -#endif /* ELF64_FSZ_WORD */ - -typedef int64_t Elf64_Sxword; -#define ELF64_FSZ_SXWORD 8 -typedef uint64_t Elf64_Xword; -#define ELF64_FSZ_XWORD 8 -typedef uint64_t Elf64_Lword; -#define ELF64_FSZ_LWORD 8 -typedef uint32_t Elf64_Half; -#define ELF64_FSZ_HALF 4 -typedef uint16_t Elf64_Quarter; -#define ELF64_FSZ_QUARTER 2 +typedef uint8_t Elf_Byte; + +typedef uint32_t Elf32_Addr; +#define ELF32_FSZ_ADDR 4 +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_SOff; +#define ELF32_FSZ_OFF 4 +typedef int32_t Elf32_Sword; +#define ELF32_FSZ_SWORD 4 +typedef uint32_t Elf32_Word; +#define ELF32_FSZ_WORD 4 +typedef uint16_t Elf32_Half; +#define ELF32_FSZ_HALF 2 +typedef uint64_t Elf32_Lword; +#define ELF32_FSZ_LWORD 8 + +typedef uint64_t Elf64_Addr; +#define ELF64_FSZ_ADDR 8 +typedef uint64_t Elf64_Off; +typedef int64_t Elf64_SOff; +#define ELF64_FSZ_OFF 8 + +typedef int32_t Elf64_Sword; +#define ELF64_FSZ_SWORD 4 +typedef uint32_t Elf64_Word; +#define ELF64_FSZ_WORD 4 + +typedef int64_t Elf64_Sxword; +#define ELF64_FSZ_SXWORD 8 +typedef uint64_t Elf64_Xword; +#define ELF64_FSZ_XWORD 8 +typedef uint64_t Elf64_Lword; +#define ELF64_FSZ_LWORD 8 +typedef uint16_t Elf64_Half; +#define ELF64_FSZ_HALF 2 /* * ELF Header @@ -118,29 +111,29 @@ typedef struct { Elf32_Off e_phoff; /* Program hdr offset */ Elf32_Off e_shoff; /* Section hdr offset */ Elf32_Word e_flags; /* Processor flags */ - Elf32_Half e_ehsize; /* sizeof ehdr */ - Elf32_Half e_phentsize; /* Program header entry size */ - Elf32_Half e_phnum; /* Number of program headers */ - Elf32_Half e_shentsize; /* Section header entry size */ - Elf32_Half e_shnum; /* Number of section headers */ - Elf32_Half e_shstrndx; /* String table index */ + Elf32_Half e_ehsize; /* sizeof ehdr */ + Elf32_Half e_phentsize; /* Program header entry size */ + Elf32_Half e_phnum; /* Number of program headers */ + Elf32_Half e_shentsize; /* Section header entry size */ + Elf32_Half e_shnum; /* Number of section headers */ + Elf32_Half e_shstrndx; /* String table index */ } Elf32_Ehdr; typedef struct { unsigned char e_ident[ELF_NIDENT]; /* Id bytes */ - Elf64_Quarter e_type; /* file type */ - Elf64_Quarter e_machine; /* machine type */ - Elf64_Half e_version; /* version number */ + Elf64_Half e_type; /* file type */ + Elf64_Half e_machine; /* machine type */ + Elf64_Word e_version; /* version number */ Elf64_Addr e_entry; /* entry point */ Elf64_Off e_phoff; /* Program hdr offset */ Elf64_Off e_shoff; /* Section hdr offset */ - Elf64_Half e_flags; /* Processor flags */ - Elf64_Quarter e_ehsize; /* sizeof ehdr */ - Elf64_Quarter e_phentsize; /* Program header entry size */ - Elf64_Quarter e_phnum; /* Number of program headers */ - Elf64_Quarter e_shentsize; /* Section header entry size */ - Elf64_Quarter e_shnum; /* Number of section headers */ - Elf64_Quarter e_shstrndx; /* String table index */ + Elf64_Word e_flags; /* Processor flags */ + Elf64_Half e_ehsize; /* sizeof ehdr */ + Elf64_Half e_phentsize; /* Program header entry size */ + Elf64_Half e_phnum; /* Number of program headers */ + Elf64_Half e_shentsize; /* Section header entry size */ + Elf64_Half e_shnum; /* Number of section headers */ + Elf64_Half e_shstrndx; /* String table index */ } Elf64_Ehdr; /* e_ident offsets */ @@ -184,11 +177,11 @@ typedef struct { #define ELFOSABI_SYSV 0 /* UNIX System V ABI */ #define ELFOSABI_HPUX 1 /* HP-UX operating system */ #define ELFOSABI_NETBSD 2 /* NetBSD */ -#define ELFOSABI_LINUX 3 /* GNU/Linux */ -#define ELFOSABI_HURD 4 /* GNU/Hurd */ -#define ELFOSABI_86OPEN 5 /* 86Open */ +#define ELFOSABI_GNU 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd - historical */ +#define ELFOSABI_86OPEN 5 /* 86Open - historical */ #define ELFOSABI_SOLARIS 6 /* Solaris */ -#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_AIX 7 /* AIX */ #define ELFOSABI_IRIX 8 /* IRIX */ #define ELFOSABI_FREEBSD 9 /* FreeBSD */ #define ELFOSABI_TRU64 10 /* TRU64 UNIX */ @@ -197,12 +190,18 @@ typedef struct { #define ELFOSABI_OPENVMS 13 /* OpenVMS */ #define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ #define ELFOSABI_AROS 15 /* Amiga Research OS */ +#define ELFOSABI_FENIXOS 16 /* The FenixOS highly scalable multi-core OS */ +#define ELFOSABI_CLOUDABI 17 /* Nuxi CloudABI */ +#define ELFOSABI_OPENVOS 18 /* Stratus Technologies OpenVOS */ /* Unofficial OSABIs follow */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ #define ELFOSABI_NONE ELFOSABI_SYSV -#define ELFOSABI_AIX ELFOSABI_MONTEREY + +/* Historical aliases. */ +#define ELFOSABI_LINUX ELFOSABI_GNU +#define ELFOSABI_MONTEREY ELFOSABI_AIX /* e_type */ #define ET_NONE 0 /* No file type */ @@ -224,7 +223,8 @@ typedef struct { #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola 68000 */ #define EM_88K 5 /* Motorola 88000 */ -#define EM_486 6 /* Intel 80486 */ +#define EM_486 6 /* Intel 80486 [old] */ +#define EM_IAMCU 6 /* Intel MCU. */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS I Architecture */ #define EM_S370 9 /* Amdahl UTS on System/370 */ @@ -238,14 +238,15 @@ typedef struct { #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* 64-bit PowerPC */ - /* 22-35 - Reserved */ -#define EM_S390 22 /* System/390 XXX reserved */ +#define EM_S390 22 /* IBM System/390 Processor */ +#define EM_SPU 23 /* IBM SPU/SPC */ + /* 24-35 - Reserved */ #define EM_V800 36 /* NEC V800 */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* Advanced RISC Machines ARM */ -#define EM_ALPHA 41 /* DIGITAL Alpha */ +#define EM_OLD_ALPHA 41 /* DIGITAL Alpha (obsolete) */ #define EM_SH 42 /* Hitachi Super-H */ #define EM_SPARCV9 43 /* SPARC Version 9 */ #define EM_TRICORE 44 /* Siemens Tricore */ @@ -296,7 +297,8 @@ typedef struct { #define EM_MN10300 89 /* Matsushita MN10300 */ #define EM_MN10200 90 /* Matsushita MN10200 */ #define EM_PJ 91 /* picoJava */ -#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_OR1K 92 /* OpenRISC 32-bit embedded processor */ +#define EM_OPENRISC EM_OR1K #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ #define EM_VIDEOCORE 95 /* Alphamosaic VideoCore processor */ @@ -318,19 +320,96 @@ typedef struct { #define EM_EXCESS 111 /* eXcess: 16/32/64-bit configurable embedded CPU */ #define EM_DXP 112 /* Icera Semiconductor Inc. Deep Execution Processor */ #define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */ -#define EM_CRX 114 /* National Semiconductor CRX */ +#define EM_CRX 114 /* National Semiconductor CompactRISC CRX microprocessor */ #define EM_XGATE 115 /* Motorola XGATE embedded processor */ #define EM_C166 116 /* Infineon C16x/XC16x processor */ #define EM_M16C 117 /* Renesas M16C series microprocessors */ #define EM_DSPIC30F 118 /* Microchip Technology dsPIC30F Digital Signal Controller */ #define EM_CE 119 /* Freescale Communication Engine RISC core */ #define EM_M32C 120 /* Renesas M32C series microprocessors */ - -#define EM_LATTICEMICO32 138 /* RICS processor for Lattice FPGA architecture */ - -#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze 32-bit RISC soft processor core */ - -#define EM_MOXIE 0xFEED + /* 121-130 - Reserved */ +#define EM_TSK3000 131 /* Altium TSK3000 core */ +#define EM_RS08 132 /* Freescale RS08 embedded processor */ +#define EM_SHARC 133 /* Analog Devices SHARC family of 32-bit DSP processors */ +#define EM_ECOG2 134 /* Cyan Technology eCOG2 microprocessor */ +#define EM_SCORE7 135 /* Sunplus S+core7 RISC processor */ +#define EM_DSP24 136 /* New Japan Radio (NJR) 24-bit DSP Processor */ +#define EM_VIDEOCORE3 137 /* Broadcom VideoCore III processor */ +#define EM_LATTICEMICO32 138 /* RISC processor for Lattice FPGA architecture */ +#define EM_SE_C17 139 /* Seiko Epson C17 family */ +#define EM_TI_C6000 140 /* The Texas Instruments TMS320C6000 DSP family */ +#define EM_TI_C2000 141 /* The Texas Instruments TMS320C2000 DSP family */ +#define EM_TI_C5500 142 /* The Texas Instruments TMS320C55x DSP family */ +#define EM_TI_ARP32 143 /* Texas Instruments Application Specific RISC Processor, 32bit fetch */ +#define EM_TI_PRU 144 /* Texas Instruments Programmable Realtime Unit */ + /* 145-159 - Reserved */ +#define EM_MMDSP_PLUS 160 /* STMicroelectronics 64bit VLIW Data Signal Processor */ +#define EM_CYPRESS_M8C 161 /* Cypress M8C microprocessor */ +#define EM_R32C 162 /* Renesas R32C series microprocessors */ +#define EM_TRIMEDIA 163 /* NXP Semiconductors TriMedia architecture family */ +#define EM_QDSP6 164 /* QUALCOMM DSP6 Processor */ +#define EM_8051 165 /* Intel 8051 and variants */ +#define EM_STXP7X 166 /* STMicroelectronics STxP7x family of configurable and extensible RISC processors */ +#define EM_NDS32 167 /* Andes Technology compact code size embedded RISC processor family */ +#define EM_ECOG1 168 /* Cyan Technology eCOG1X family */ +#define EM_ECOG1X 168 /* Cyan Technology eCOG1X family */ +#define EM_MAXQ30 169 /* Dallas Semiconductor MAXQ30 Core Micro-controllers */ +#define EM_XIMO16 170 /* New Japan Radio (NJR) 16-bit DSP Processor */ +#define EM_MANIK 171 /* M2000 Reconfigurable RISC Microprocessor */ +#define EM_CRAYNV2 172 /* Cray Inc. NV2 vector architecture */ +#define EM_RX 173 /* Renesas RX family */ +#define EM_METAG 174 /* Imagination Technologies META processor architecture */ +#define EM_MCST_ELBRUS 175 /* MCST Elbrus general purpose hardware architecture */ +#define EM_ECOG16 176 /* Cyan Technology eCOG16 family */ +#define EM_CR16 177 /* National Semiconductor CompactRISC CR16 16-bit microprocessor */ +#define EM_ETPU 178 /* Freescale Extended Time Processing Unit */ +#define EM_SLE9X 179 /* Infineon Technologies SLE9X core */ +#define EM_L10M 180 /* Intel L10M */ +#define EM_K10M 181 /* Intel K10M */ + /* 182 - Reserved */ +#define EM_AARCH64 183 /* AArch64 64-bit ARM microprocessor */ + /* 184 - Reserved */ +//#define EM_AVR32 185 /* Atmel Corporation 32-bit microprocessor family*/ +#define EM_TILE64 187 /* Tilera TILE64 multicore architecture family */ +#define EM_TILEPRO 188 /* Tilera TILEPro multicore architecture family */ +#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze 32-bit RISC soft processor core */ +#define EM_CUDA 190 /* NVIDIA CUDA architecture */ +#define EM_TILEGX 191 /* Tilera TILE-GX multicore architecture family */ +#define EM_CLOUDSHIELD 192 /* CloudShield architecture family */ +#define EM_COREA_1ST 193 /* KIPO-KAIST Core-A 1st generation processor family */ +#define EM_COREA_2ND 194 /* KIPO-KAIST Core-A 2nd generation processor family */ +#define EM_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */ +#define EM_OPEN8 196 /* Open8 8-bit RISC soft processor core */ +#define EM_RL78 197 /* Renesas RL78 family */ +#define EM_VIDEOCORE5 198 /* Broadcom VideoCore V processor */ +#define EM_78KOR 199 /* Renesas 78KOR family */ +#define EM_56800EX 200 /* Freescale 56800EX Digital Signal Controller (DSC) */ +#define EM_BA1 201 /* Beyond BA1 CPU architecture */ +#define EM_BA2 202 /* Beyond BA2 CPU architecture */ +#define EM_XCORE 203 /* XMOS xCORE processor family */ +#define EM_MCHP_PIC 204 /* Microchip 8-bit PIC(r) family */ +#define EM_INTEL205 205 /* Reserved by Intel */ +#define EM_INTEL206 206 /* Reserved by Intel */ +#define EM_INTEL207 207 /* Reserved by Intel */ +#define EM_INTEL208 208 /* Reserved by Intel */ +#define EM_INTEL209 209 /* Reserved by Intel */ +#define EM_KM32 210 /* KM211 KM32 32-bit processor */ +#define EM_KMX32 211 /* KM211 KMX32 32-bit processor */ +#define EM_KMX16 212 /* KM211 KMX16 16-bit processor */ +#define EM_KMX8 213 /* KM211 KMX8 8-bit processor */ +#define EM_KVARC 214 /* KM211 KVARC processor */ +#define EM_CDP 215 /* Paneve CDP architecture family */ +#define EM_COGE 216 /* Cognitive Smart Memory Processor */ +#define EM_COOL 217 /* Bluechip Systems CoolEngine */ +#define EM_NORC 218 /* Nanoradio Optimized RISC */ +#define EM_CSR_KALIMBA 219 /* CSR Kalimba architecture family */ +#define EM_Z80 220 /* Zilog Z80 */ +#define EM_VISIUM 221 /* Controls and Data Services VISIUMcore processor */ +#define EM_FT32 222 /* FTDI Chip FT32 high performance 32-bit RISC architecture */ +#define EM_MOXIE 223 /* Moxie processor family */ +#define EM_AMDGPU 224 /* AMD GPU architecture */ + /* 225-242 - Reserved */ +#define EM_RISCV 243 /* RISC-V */ /* Unofficial machine types follow */ #define EM_AVR32 6317 /* used by NetBSD/avr32 */ @@ -352,8 +431,8 @@ typedef struct { } Elf32_Phdr; typedef struct { - Elf64_Half p_type; /* entry type */ - Elf64_Half p_flags; /* flags */ + Elf64_Word p_type; /* entry type */ + Elf64_Word p_flags; /* flags */ Elf64_Off p_offset; /* offset */ Elf64_Addr p_vaddr; /* virtual address */ Elf64_Addr p_paddr; /* physical address */ @@ -370,14 +449,22 @@ typedef struct { #define PT_NOTE 4 /* Auxiliary information */ #define PT_SHLIB 5 /* Reserved, unspecified semantics */ #define PT_PHDR 6 /* Entry for header table itself */ -#define PT_NUM 7 +#define PT_TLS 7 /* TLS initialisation image */ +#define PT_NUM 8 + +#define PT_LOOS 0x60000000 /* OS-specific range */ -#define PT_LOOS 0x60000000 /* OS-specific range */ -#define PT_HIOS 0x6fffffff -#define PT_LOPROC 0x70000000 /* Processor-specific range */ -#define PT_HIPROC 0x7fffffff +/* GNU-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* EH frame segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicate executable stack */ +#define PT_GNU_RELRO 0x6474e552 /* Make read-only after relocation */ + +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 /* Processor-specific range */ +#define PT_HIPROC 0x7fffffff #define PT_MIPS_REGINFO 0x70000000 +#define PT_MIPS_ABIFLAGS 0x70000003 /* p_flags */ #define PF_R 0x4 /* Segment is readable */ @@ -407,66 +494,91 @@ typedef struct { } Elf32_Shdr; typedef struct { - Elf64_Half sh_name; /* section name (.shstrtab index) */ - Elf64_Half sh_type; /* section type */ + Elf64_Word sh_name; /* section name (.shstrtab index) */ + Elf64_Word sh_type; /* section type */ Elf64_Xword sh_flags; /* section flags */ Elf64_Addr sh_addr; /* virtual address */ Elf64_Off sh_offset; /* file offset */ Elf64_Xword sh_size; /* section size */ - Elf64_Half sh_link; /* link to another */ - Elf64_Half sh_info; /* misc info */ + Elf64_Word sh_link; /* link to another */ + Elf64_Word sh_info; /* misc info */ Elf64_Xword sh_addralign; /* memory alignment */ Elf64_Xword sh_entsize; /* table entry size */ } Elf64_Shdr; /* sh_type */ -#define SHT_NULL 0 /* Section header table entry unused */ -#define SHT_PROGBITS 1 /* Program information */ -#define SHT_SYMTAB 2 /* Symbol table */ -#define SHT_STRTAB 3 /* String table */ -#define SHT_RELA 4 /* Relocation information w/ addend */ -#define SHT_HASH 5 /* Symbol hash table */ -#define SHT_DYNAMIC 6 /* Dynamic linking information */ -#define SHT_NOTE 7 /* Auxiliary information */ -#define SHT_NOBITS 8 /* No space allocated in file image */ -#define SHT_REL 9 /* Relocation information w/o addend */ -#define SHT_SHLIB 10 /* Reserved, unspecified semantics */ -#define SHT_DYNSYM 11 /* Symbol table for dynamic linker */ -#define SHT_INIT_ARRAY 14 /* Initialization function pointers */ -#define SHT_FINI_ARRAY 15 /* Termination function pointers */ -#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs */ -#define SHT_GROUP 17 /* Section group */ -#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX) */ -#define SHT_NUM 19 - -#define SHT_LOOS 0x60000000 /* Operating system specific range */ -#define SHT_SUNW_move 0x6ffffffa -#define SHT_SUNW_syminfo 0x6ffffffc -#define SHT_SUNW_verdef 0x6ffffffd /* Versions defined by file */ -#define SHT_GNU_verdef SHT_SUNW_verdef -#define SHT_SUNW_verneed 0x6ffffffe /* Versions needed by file */ -#define SHT_GNU_verneed SHT_SUNW_verneed -#define SHT_SUNW_versym 0x6fffffff /* Symbol versions */ -#define SHT_GNU_versym SHT_SUNW_versym -#define SHT_HIOS 0x6fffffff -#define SHT_LOPROC 0x70000000 /* Processor-specific range */ -#define SHT_AMD64_UNWIND 0x70000001 /* unwind information */ -#define SHT_HIPROC 0x7fffffff -#define SHT_LOUSER 0x80000000 /* Application-specific range */ -#define SHT_HIUSER 0xffffffff +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program information */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation information w/ addend */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Auxiliary information */ +#define SHT_NOBITS 8 /* No space allocated in file image */ +#define SHT_REL 9 /* Relocation information w/o addend */ +#define SHT_SHLIB 10 /* Reserved, unspecified semantics */ +#define SHT_DYNSYM 11 /* Symbol table for dynamic linker */ +#define SHT_INIT_ARRAY 14 /* Initialization function pointers */ +#define SHT_FINI_ARRAY 15 /* Termination function pointers */ +#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX) */ +#define SHT_NUM 19 + +#define SHT_LOOS 0x60000000 /* Operating system specific range */ +#define SHT_GNU_INCREMENTAL_INPUTS 0x6fff4700 /* GNU incremental build data */ +#define SHT_LOSUNW 0x6ffffff4 +#define SHT_SUNW_dof 0x6ffffff4 +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* GNU object attributes */ +#define SHT_SUNW_cap 0x6ffffff5 +#define SHT_SUNW_SIGNATURE 0x6ffffff6 +#define SHT_GNU_HASH 0x6ffffff6 /* GNU style symbol hash table */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* GNU list of prelink dependencies */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_SUNW_verdef 0x6ffffffd /* Versions defined by file */ +#define SHT_GNU_verdef SHT_SUNW_verdef +#define SHT_SUNW_verneed 0x6ffffffe /* Versions needed by file */ +#define SHT_GNU_verneed SHT_SUNW_verneed +#define SHT_SUNW_versym 0x6fffffff /* Symbol versions */ +#define SHT_GNU_versym SHT_SUNW_versym +#define SHT_HISUNW 0x6fffffff +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 /* Processor-specific range */ +#define SHT_AMD64_UNWIND 0x70000001 /* unwind information */ +#define SHT_ARM_EXIDX 0x70000001 /* exception index table */ +#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking + * pre-emption map */ +#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility + * attributes */ +#define SHT_ARM_DEBUGOVERLAY 0x70000004 /* See DBGOVL for details */ +#define SHT_ARM_OVERLAYSECTION 0x70000005 +#define SHT_MIPS_REGINFO 0x70000006 +#define SHT_MIPS_OPTIONS 0x7000000d +#define SHT_MIPS_DWARF 0x7000001e /* MIPS gcc uses MIPS_DWARF */ +#define SHT_MIPS_XHASH 0x7000002b /* MIPS version of GNU_HASH */ +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 /* Application-specific range */ +#define SHT_HIUSER 0xffffffff /* sh_flags */ -#define SHF_WRITE 0x1 /* Section contains writable data */ -#define SHF_ALLOC 0x2 /* Section occupies memory */ -#define SHF_EXECINSTR 0x4 /* Section contains executable insns */ -#define SHF_MERGE 0x10 /* Section contains data that can be merged */ -#define SHF_STRINGS 0x20 /* Section contains null-terminated strings */ -#define SHF_INFO_LINK 0x40 /* Section header's sh_info holds table index */ -#define SHF_LINK_ORDER 0x80 /* Section has special ordering requirements */ - -#define SHF_MASKOS 0x0f000000 /* Operating system specific values */ -#define SHF_MASKPROC 0xf0000000 /* Processor-specific values */ - +#define SHF_WRITE 0x00000001 /* Contains writable data */ +#define SHF_ALLOC 0x00000002 /* Occupies memory */ +#define SHF_EXECINSTR 0x00000004 /* Contains executable insns */ +#define SHF_MERGE 0x00000010 /* Might be merged */ +#define SHF_STRINGS 0x00000020 /* Contains nul terminated strings */ +#define SHF_INFO_LINK 0x00000040 /* "sh_info" contains SHT index */ +#define SHF_LINK_ORDER 0x00000080 /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING 0x00000100 /* OS specific handling required */ +#define SHF_GROUP 0x00000200 /* Is member of a group */ +#define SHF_TLS 0x00000400 /* Holds thread-local data */ +#define SHF_MASKOS 0x0ff00000 /* Operating system specific values */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific values */ +#define SHF_ORDERED 0x40000000 /* Ordering requirement (Solaris) */ +#define SHF_EXCLUDE 0x80000000 /* Excluded unless unles ref/alloc + (Solaris).*/ /* * Symbol Table */ @@ -480,10 +592,10 @@ typedef struct { } Elf32_Sym; typedef struct { - Elf64_Half st_name; /* Symbol name (.strtab index) */ + Elf64_Word st_name; /* Symbol name (.strtab index) */ Elf_Byte st_info; /* type / binding attrs */ Elf_Byte st_other; /* unused */ - Elf64_Quarter st_shndx; /* section index of symbol */ + Elf64_Half st_shndx; /* section index of symbol */ Elf64_Addr st_value; /* value of symbol */ Elf64_Xword st_size; /* size of symbol */ } Elf64_Sym; @@ -515,6 +627,7 @@ typedef struct { #define STT_NUM 7 #define STT_LOOS 10 /* Operating system specific range */ +#define STT_GNU_IFUNC 10 /* GNU extension: indirect function */ #define STT_HIOS 12 #define STT_LOPROC 13 /* Processor-specific range */ #define STT_HIPROC 15 @@ -610,8 +723,8 @@ typedef struct { Elf64_Lword m_value; /* symbol value */ Elf64_Xword m_info; /* size + index */ Elf64_Xword m_poffset; /* symbol offset */ - Elf64_Half m_repeat; /* repeat count */ - Elf64_Half m_stride; /* stride info */ + Elf64_Word m_repeat; /* repeat count */ + Elf64_Word m_stride; /* stride info */ } Elf64_Move; #define ELF64_M_SYM(info) ((info) >> 8) @@ -686,9 +799,15 @@ typedef struct { #define DT_FINI_ARRAY 26 /* Size, in bytes, of DT_INIT_ARRAY array */ #define DT_INIT_ARRAYSZ 27 /* Address of termination function array */ #define DT_FINI_ARRAYSZ 28 /* Size, in bytes, of DT_FINI_ARRAY array*/ -#define DT_NUM 29 +#define DT_RUNPATH 29 /* overrides DT_RPATH */ +#define DT_FLAGS 30 /* Encodes ORIGIN, SYMBOLIC, TEXTREL, BIND_NOW, STATIC_TLS */ +#define DT_ENCODING 31 /* ??? */ +#define DT_PREINIT_ARRAY 32 /* Address of pre-init function array */ +#define DT_PREINIT_ARRAYSZ 33 /* Size, in bytes, of DT_PREINIT_ARRAY array */ +#define DT_NUM 34 #define DT_LOOS 0x60000000 /* Operating system specific range */ +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table */ #define DT_VERSYM 0x6ffffff0 /* Symbol versions */ #define DT_FLAGS_1 0x6ffffffb /* ELF dynamic flags */ #define DT_VERDEF 0x6ffffffc /* Versions defined by file */ @@ -697,10 +816,44 @@ typedef struct { #define DT_VERNEEDNUM 0x6fffffff /* Number of versions needed by file */ #define DT_HIOS 0x6fffffff #define DT_LOPROC 0x70000000 /* Processor-specific range */ +#define DT_MIPS_XHASH 0x70000036 /* MIPS version of GNU_HASH */ #define DT_HIPROC 0x7fffffff -/* Flag values for DT_FLAGS_1 (incomplete) */ -#define DF_1_INITFIRST 0x00000020 /* Object's init/fini take priority */ +/* Flag values for DT_FLAGS */ +#define DF_ORIGIN 0x00000001 /* uses $ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* */ +#define DF_TEXTREL 0x00000004 /* */ +#define DF_BIND_NOW 0x00000008 /* */ +#define DF_STATIC_TLS 0x00000010 /* */ + +/* Flag values for DT_FLAGS_1 */ +#define DF_1_NOW 0x00000001 /* Same as DF_BIND_NOW */ +#define DF_1_GLOBAL 0x00000002 /* Unused */ +#define DF_1_GROUP 0x00000004 /* Is member of group */ +#define DF_1_NODELETE 0x00000008 /* Cannot be deleted from process */ +#define DF_1_LOADFLTR 0x00000010 /* Immediate loading of filters */ +#define DF_1_INITFIRST 0x00000020 /* init/fini takes priority */ +#define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */ +#define DF_1_ORIGIN 0x00000080 /* Require $ORIGIN processing */ +#define DF_1_DIRECT 0x00000100 /* Enable direct bindings */ +#define DF_1_INTERPOSE 0x00000400 /* Is an interposer */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default library search path */ +#define DF_1_NODUMP 0x00001000 /* Cannot be dumped with dldump(3C) */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative */ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee ends filter's search */ +#define DF_1_DISPRELDNE 0x00008000 /* Did displacement relocation */ +#define DF_1_DISPRELPND 0x00010000 /* Pending displacement relocation */ +#define DF_1_NODIRECT 0x00020000 /* Has non-direct bindings */ +#define DF_1_IGNMULDEF 0x00040000 /* Used internally */ +#define DF_1_NOKSYMS 0x00080000 /* Used internally */ +#define DF_1_NOHDR 0x00100000 /* Used internally */ +#define DF_1_EDITED 0x00200000 /* Has been modified since build */ +#define DF_1_NORELOC 0x00400000 /* Used internally */ +#define DF_1_SYMINTPOSE 0x00800000 /* Has individual symbol interposers */ +#define DF_1_GLOBAUDIT 0x01000000 /* Require global auditing */ +#define DF_1_SINGLETON 0x02000000 /* Has singleton symbols */ +#define DF_1_STUB 0x04000000 /* Stub */ +#define DF_1_PIE 0x08000000 /* Position Independent Executable */ /* * Auxiliary Vectors @@ -711,8 +864,8 @@ typedef struct { } Aux32Info; typedef struct { - Elf64_Half a_type; /* 32-bit id */ - Elf64_Xword a_v; /* 64-bit id */ + Elf64_Word a_type; /* 32-bit id */ + Elf64_Xword a_v; /* 64-bit id */ } Aux64Info; /* a_type */ @@ -729,6 +882,7 @@ typedef struct { #define AT_DCACHEBSIZE 10 /* Data cache block size */ #define AT_ICACHEBSIZE 11 /* Instruction cache block size */ #define AT_UCACHEBSIZE 12 /* Unified cache block size */ +#define AT_STACKBASE 13 /* Base address of the main thread */ /* Vendor specific */ #define AT_MIPS_NOTELF 10 /* XXX a_val != 0 -> MIPS XCOFF executable */ @@ -756,6 +910,16 @@ typedef struct { #define AT_SUN_EXECNAME 2014 /* + * The header for GNU-style hash sections. + */ +typedef struct { + uint32_t gh_nbuckets; /* Number of hash buckets. */ + uint32_t gh_symndx; /* First visible symbol in .dynsym. */ + uint32_t gh_maskwords; /* #maskwords used in bloom filter. */ + uint32_t gh_shift2; /* Bloom filter shift count. */ +} Elf_GNU_Hash_Header; + +/* * Note Headers */ typedef struct { @@ -765,42 +929,155 @@ typedef struct { } Elf32_Nhdr; typedef struct { - Elf64_Half n_namesz; - Elf64_Half n_descsz; - Elf64_Half n_type; + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; } Elf64_Nhdr; -#define ELF_NOTE_TYPE_ABI_TAG 1 +#define ELF_NOTE_GNU_NAMESZ 4 +#define ELF_NOTE_GNU_NAME "GNU\0" +/* + * GNU-specific note type: ABI tag + * name: GNU\0 + * namesz: 4 + * desc: + * word[0]: OS tag + * word[1]: major version + * word[2]: minor version + * word[3]: teeny version + * descsz: 16 + */ /* GNU-specific note name and description sizes */ -#define ELF_NOTE_ABI_NAMESZ 4 -#define ELF_NOTE_ABI_DESCSZ 16 -/* GNU-specific note name */ -#define ELF_NOTE_ABI_NAME "GNU\0" - +#define ELF_NOTE_TYPE_ABI_TAG 1 +#define ELF_NOTE_ABI_NAME ELF_NOTE_GNU_NAME +#define ELF_NOTE_ABI_NAMESZ ELF_NOTE_GNU_NAMESZ +#define ELF_NOTE_ABI_DESCSZ 16 /* GNU-specific OS/version value stuff */ -#define ELF_NOTE_ABI_OS_LINUX 0 -#define ELF_NOTE_ABI_OS_HURD 1 -#define ELF_NOTE_ABI_OS_SOLARIS 2 +#define ELF_NOTE_ABI_OS_LINUX 0 +#define ELF_NOTE_ABI_OS_HURD 1 +#define ELF_NOTE_ABI_OS_SOLARIS 2 +#define ELF_NOTE_ABI_OS_KFREEBSD 3 +#define ELF_NOTE_ABI_OS_KNETBSD 4 + +/* Old gcc style, under the ABI tag */ +#define ELF_NOTE_OGCC_NAMESZ 8 +#define ELF_NOTE_OGCC_NAME "01.01\0\0\0\0" +#define ELF_NOTE_OGCC_DESCSZ 0 + +/* + * GNU-specific note type: Hardware capabilities + * name: GNU\0 + * namesz: 4 + * desc: + * word[0]: Number of entries + * word[1]: Bitmask of enabled entries + * Followed by a byte id, and a NUL terminated string per entry + * descsz: variable + */ +#define ELF_NOTE_TYPE_GNU_HWCAP 2 -/* NetBSD-specific note type: Emulation name. desc is emul name string. */ -#define ELF_NOTE_TYPE_NETBSD_TAG 1 +/* + * GNU-specific note type: Build ID generated by ld + * name: GNU\0 + * desc: + * word[0..4] SHA1 [default] + * or + * word[0..3] md5 or uuid + * descsz: 16 or 20 + */ +#define ELF_NOTE_TYPE_GNU_BUILD_ID 3 + +/* SuSE-specific note type: ABI + * name: SuSE\0 + * namesz: 5 + * desc: + * half[0] = MMmm + * + * M = product major version + * m = product minor version + * descsz: 2 + */ +#define ELF_NOTE_TYPE_SUSE_TAG 1 +/* SuSE-specific note name and description sizes */ +#define ELF_NOTE_SUSE_NAMESZ 5 +#define ELF_NOTE_SUSE_DESCSZ 2 +/* SuSE-specific note name */ +#define ELF_NOTE_SUSE_NAME "SuSE\0" + +/* SuSE-specific note type: version + * name: SuSE\0\0\0\0 + * namesz: 8 + * desc: + * word[0] = VVTTMMmm + * + * V = version of following data + * T = product type: [box, sles, nld, whatever] + * M = product major version + * m = product minor version + * descsz: 8 + */ +#define ELF_NOTE_TYPE_SUSE_VERSION_TAG 0x45537553 /* SuSE in LE */ +/* SuSE-specific note name and description sizes */ +#define ELF_NOTE_SUSE_VERSION_NAMESZ 8 +#define ELF_NOTE_SUSE_VERSION_DESCSZ 8 +/* SuSE-specific note name */ +#define ELF_NOTE_SUSE_VERSION_NAME "SuSE\0\0\0\0" + +/* Go-specific note type: buildid + * name: Go\0\0 + * namesz: 4 + * desc: + * words[10] + * descsz: 40 + */ +#define ELF_NOTE_TYPE_GO_BUILDID_TAG 4 +#define ELF_NOTE_GO_BUILDID_NAMESZ 4 +#define ELF_NOTE_GO_BUILDID_DESCSZ 40 +#define ELF_NOTE_GO_BUILDID_NAME "Go\0\0" + +/* NetBSD-specific note type: NetBSD ABI version. + * name: NetBSD\0\0 + * namesz: 8 + * desc: + * word[0]: MMmmrrpp00 + * + * M = major version + * m = minor version + * r = release ["",A-Z,Z[A-Z] but numeric] + * p = patchlevel + * descsz: 4 + */ +#define ELF_NOTE_TYPE_NETBSD_TAG 1 /* NetBSD-specific note name and description sizes */ #define ELF_NOTE_NETBSD_NAMESZ 7 #define ELF_NOTE_NETBSD_DESCSZ 4 /* NetBSD-specific note name */ -#define ELF_NOTE_NETBSD_NAME "NetBSD\0\0" - -/* NetBSD-specific note type: Checksum. There should be 1 NOTE per PT_LOAD - section. desc is a tuple of <phnum>(16),<chk-type>(16),<chk-value>. */ -#define ELF_NOTE_TYPE_CHECKSUM_TAG 2 -#define ELF_NOTE_CHECKSUM_CRC32 1 -#define ELF_NOTE_CHECKSUM_MD5 2 -#define ELF_NOTE_CHECKSUM_SHA1 3 -#define ELF_NOTE_CHECKSUM_SHA256 4 - -/* NetBSD-specific note type: PaX. There should be 1 NOTE per executable. - section. desc is a 32 bit bitmask */ +#define ELF_NOTE_NETBSD_NAME "NetBSD\0\0" + +/* NetBSD-specific note type: Emulation (obsolete; last used early 2000) + * name: NetBSD\0\0 + * namesz: 8 + * desc: + * "netbsd\0" + * + * descsz: 8 + */ +#define ELF_NOTE_TYPE_NETBSD_EMUL_TAG 2 +#define ELF_NOTE_NETBSD_EMUL_NAMESZ 7 +#define ELF_NOTE_NETBSD_EMUL_DESCSZ 7 +/* NetBSD-specific note name */ +#define ELF_NOTE_NETBSD_EMUL_NAME "NetBSD\0\0" + +/* + * NetBSD-specific note type: PaX. + * There should be 1 NOTE per executable. + * name: PaX\0 + * namesz: 4 + * desc: + * word[0]: capability bitmask + * descsz: 4 + */ #define ELF_NOTE_TYPE_PAX_TAG 3 #define ELF_NOTE_PAX_MPROTECT 0x01 /* Force enable Mprotect */ #define ELF_NOTE_PAX_NOMPROTECT 0x02 /* Force disable Mprotect */ @@ -825,6 +1102,8 @@ typedef struct { * * ELF_NOTE_NETBSD_CORE_PROCINFO * Note is a "netbsd_elfcore_procinfo" structure. + * ELF_NOTE_NETBSD_CORE_AUXV + * Note is an array of AuxInfo structures. * * We also use ptrace(2) request numbers (the ones that exist in * machine-dependent space) to identify register info notes. The @@ -838,6 +1117,7 @@ typedef struct { #define ELF_NOTE_NETBSD_CORE_NAME "NetBSD-CORE" #define ELF_NOTE_NETBSD_CORE_PROCINFO 1 +#define ELF_NOTE_NETBSD_CORE_AUXV 2 #define NETBSD_ELFCORE_PROCINFO_VERSION 1 @@ -849,8 +1129,8 @@ struct netbsd_elfcore_procinfo { uint32_t cpi_sigcode; /* signal code */ uint32_t cpi_sigpend[4]; /* pending signals */ uint32_t cpi_sigmask[4]; /* blocked signals */ - uint32_t cpi_sigignore[4];/* blocked signals */ - uint32_t cpi_sigcatch[4];/* blocked signals */ + uint32_t cpi_sigignore[4];/* ignored signals */ + uint32_t cpi_sigcatch[4];/* caught signals */ int32_t cpi_pid; /* process ID */ int32_t cpi_ppid; /* parent process ID */ int32_t cpi_pgrp; /* process group ID */ @@ -867,46 +1147,108 @@ struct netbsd_elfcore_procinfo { int32_t cpi_siglwp; /* LWP target of killing signal */ }; +/* + * NetBSD-specific note type: MACHINE_ARCH. + * There should be 1 NOTE per executable. + * name: NetBSD\0 + * namesz: 7 + * desc: string + * descsz: variable + */ +#define ELF_NOTE_TYPE_MARCH_TAG 5 +/* NetBSD-specific note name and description sizes */ +#define ELF_NOTE_MARCH_NAMESZ ELF_NOTE_NETBSD_NAMESZ +/* NetBSD-specific note name */ +#define ELF_NOTE_MARCH_NAME ELF_NOTE_NETBSD_NAME + +/* + * NetBSD-specific note type: MCMODEL + * There should be 1 NOTE per executable. + * name: NetBSD\0 + * namesz: 7 + * code model: string + */ + +#define ELF_NOTE_TYPE_MCMODEL_TAG 6 +/* NetBSD-specific note name and description sizes */ +#define ELF_NOTE_MCMODEL_NAMESZ ELF_NOTE_NETBSD_NAMESZ +/* NetBSD-specific note name */ +#define ELF_NOTE_MCMODEL_NAME ELF_NOTE_NETBSD_NAME + + +#if !defined(ELFSIZE) +# if defined(_RUMPKERNEL) || !defined(_KERNEL) +# define ELFSIZE ARCH_ELFSIZE +# else +# define ELFSIZE KERN_ELFSIZE +# endif +#endif + +#if defined(ELFSIZE) +#define CONCAT(x,y) __CONCAT(x,y) +#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) +#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) +#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) +#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) +#define ElfW(x) CONCAT(Elf,CONCAT(ELFSIZE,CONCAT(_,x))) +#endif + #if defined(ELFSIZE) && (ELFSIZE == 32) -#define Elf_Ehdr Elf32_Ehdr -#define Elf_Phdr Elf32_Phdr -#define Elf_Shdr Elf32_Shdr -#define Elf_Sym Elf32_Sym -#define Elf_Rel Elf32_Rel -#define Elf_Rela Elf32_Rela -#define Elf_Dyn Elf32_Dyn -#define Elf_Word Elf32_Word -#define Elf_Sword Elf32_Sword -#define Elf_Addr Elf32_Addr -#define Elf_Off Elf32_Off -#define Elf_SOff Elf32_SOff -#define Elf_Nhdr Elf32_Nhdr - -#define ELF_R_SYM ELF32_R_SYM -#define ELF_R_TYPE ELF32_R_TYPE -#define ELFCLASS ELFCLASS32 - -#define AuxInfo Aux32Info +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Rel Elf32_Rel +#define Elf_Rela Elf32_Rela +#define Elf_Dyn Elf32_Dyn +#define Elf_Word Elf32_Word +#define Elf_Sword Elf32_Sword +#define Elf_Half Elf32_Half +#define Elf_Addr Elf32_Addr +#define Elf_Off Elf32_Off +#define Elf_SOff Elf32_SOff +#define Elf_Nhdr Elf32_Nhdr +#define Elf_Verdef Elf32_Verdef +#define Elf_Verdaux Elf32_Verdaux +#define Elf_Verneed Elf32_Verneed +#define Elf_Vernaux Elf32_Vernaux +#define Elf_Versym Elf32_Versym + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELFCLASS ELFCLASS32 + +#define AuxInfo Aux32Info #elif defined(ELFSIZE) && (ELFSIZE == 64) -#define Elf_Ehdr Elf64_Ehdr -#define Elf_Phdr Elf64_Phdr -#define Elf_Shdr Elf64_Shdr -#define Elf_Sym Elf64_Sym -#define Elf_Rel Elf64_Rel -#define Elf_Rela Elf64_Rela -#define Elf_Dyn Elf64_Dyn -#define Elf_Word Elf64_Word -#define Elf_Sword Elf64_Sword -#define Elf_Addr Elf64_Addr -#define Elf_Off Elf64_Off -#define Elf_SOff Elf64_SOff -#define Elf_Nhdr Elf64_Nhdr - -#define ELF_R_SYM ELF64_R_SYM -#define ELF_R_TYPE ELF64_R_TYPE -#define ELFCLASS ELFCLASS64 - -#define AuxInfo Aux64Info +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rel +#define Elf_Rela Elf64_Rela +#define Elf_Dyn Elf64_Dyn +#define Elf_Word Elf64_Word +#define Elf_Sword Elf64_Sword +#define Elf_Half Elf64_Half +#define Elf_Addr Elf64_Addr +#define Elf_Off Elf64_Off +#define Elf_SOff Elf64_SOff +#define Elf_Nhdr Elf64_Nhdr +#define Elf_Verdef Elf64_Verdef +#define Elf_Verdaux Elf64_Verdaux +#define Elf_Verneed Elf64_Verneed +#define Elf_Vernaux Elf64_Vernaux +#define Elf_Versym Elf64_Versym + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELFCLASS ELFCLASS64 + +#define AuxInfo Aux64Info +#endif + +#ifndef Elf_Symindx +#define Elf_Symindx uint32_t #endif #define ELF32_ST_BIND(info) ELF_ST_BIND(info) @@ -925,8 +1267,8 @@ typedef struct { } Elf32_Syminfo; typedef struct { - Elf64_Half si_boundto; /* direct bindings - symbol bound to */ - Elf64_Half si_flags; /* per symbol flags */ + Elf64_Word si_boundto; /* direct bindings - symbol bound to */ + Elf64_Word si_flags; /* per symbol flags */ } Elf64_Syminfo; #define SYMINFO_FLG_DIRECT 0x0001 /* symbol ref has direct association @@ -956,7 +1298,12 @@ typedef struct { * These constants are used for Elf32_Verdef struct's version number. */ #define VER_DEF_NONE 0 -#define VER_DEF_CURRENT 1 +#define VER_DEF_CURRENT 1 + +/* + * These constants are used for Elf32_Verdef struct's vd_ndx. + */ +#define VER_DEF_IDX(x) VER_NDX(x) /* * These constants are used for Elf32_Verdef struct's vd_flags. @@ -967,8 +1314,9 @@ typedef struct { /* * These are used in an Elf32_Versym field. */ -#define VER_NDX_LOCAL 0 -#define VER_NDX_GLOBAL 1 +#define VER_NDX_LOCAL 0 +#define VER_NDX_GLOBAL 1 +#define VER_NDX_GIVEN 2 /* * These constants are used for Elf32_Verneed struct's version number. @@ -977,10 +1325,20 @@ typedef struct { #define VER_NEED_CURRENT 1 /* - * GNU Extension hidding symb + * These constants are used for Elf32_Vernaux struct's vna_other. */ -#define VERSYM_HIDDEN 0x8000 -#define VERSYM_VERSION 0x7fff +#define VER_NEED_HIDDEN VER_NDX_HIDDEN +#define VER_NEED_IDX(x) VER_NDX(x) + +/* index */ +#define VER_NDX_HIDDEN 0x8000 +#define VER_NDX(x) ((x) & ~VER_NDX_HIDDEN) + +/* + * GNU Extension hidding symbol + */ +#define VERSYM_HIDDEN 0x8000 +#define VERSYM_VERSION 0x7fff #define ELF_VER_CHR '@' @@ -1030,7 +1388,14 @@ typedef Elf32_Versym Elf64_Versym; #ifdef _KERNEL -#define ELF_AUX_ENTRIES 14 /* Max size of aux array passed to loader */ +/* + * Arbitrary limits to avoid DoS for excessive memory allocation. + */ +#define ELF_MAXPHNUM 128 +#define ELF_MAXSHNUM 32768 +#define ELF_MAXNOTESIZE 1024 + +#define ELF_AUX_ENTRIES 15 /* Max size of aux array passed to loader */ #define ELF32_NO_ADDR (~(Elf32_Addr)0) /* Indicates addr. not yet filled in */ #define ELF32_LINK_ADDR ((Elf32_Addr)-2) /* advises to use link address */ #define ELF64_NO_ADDR (~(Elf64_Addr)0) /* Indicates addr. not yet filled in */ @@ -1060,11 +1425,11 @@ typedef Elf32_Versym Elf64_Versym; #if defined(ELFSIZE) struct elf_args { - Elf_Addr arg_entry; /* program entry point */ - Elf_Addr arg_interp; /* Interpreter load address */ - Elf_Addr arg_phaddr; /* program header address */ - Elf_Addr arg_phentsize; /* Size of program header */ - Elf_Addr arg_phnum; /* Number of program headers */ + Elf_Addr arg_entry; /* program entry point */ + Elf_Addr arg_interp; /* Interpreter load address */ + Elf_Addr arg_phaddr; /* program header address */ + Elf_Addr arg_phentsize; /* Size of program header */ + Elf_Addr arg_phnum; /* Number of program headers */ }; #endif @@ -1072,30 +1437,41 @@ struct elf_args { #include "opt_execfmt.h" #endif +struct ps_strings; +struct coredump_iostate; +struct note_state; +struct exec_package; + #ifdef EXEC_ELF32 int exec_elf32_makecmds(struct lwp *, struct exec_package *); +int elf32_populate_auxv(struct lwp *, struct exec_package *, char **); int elf32_copyargs(struct lwp *, struct exec_package *, struct ps_strings *, char **, void *); -int coredump_elf32(struct lwp *, void *); -int coredump_writenote_elf32(struct proc *, void *, Elf32_Nhdr *, - const char *, void *); - -int elf32_check_header(Elf32_Ehdr *, int); +int elf32_check_header(Elf32_Ehdr *); #endif +int real_coredump_elf32(struct lwp *, struct coredump_iostate *); +int coredump_elf32(struct lwp *, struct coredump_iostate *); +void coredump_savenote_elf32(struct note_state *, unsigned int, + const char *, void *, size_t); + + #ifdef EXEC_ELF64 int exec_elf64_makecmds(struct lwp *, struct exec_package *); +int elf64_populate_auxv(struct lwp *, struct exec_package *, char **); int elf64_copyargs(struct lwp *, struct exec_package *, struct ps_strings *, char **, void *); -int coredump_elf64(struct lwp *, void *); -int coredump_writenote_elf64(struct proc *, void *, Elf64_Nhdr *, - const char *, void *); - -int elf64_check_header(Elf64_Ehdr *, int); +int elf64_check_header(Elf64_Ehdr *); #endif +int real_coredump_elf64(struct lwp *, struct coredump_iostate *); +int coredump_elf64(struct lwp *, struct coredump_iostate *); +void coredump_savenote_elf64(struct note_state *, unsigned int, + const char *, void *, size_t); + + #endif /* _KERNEL */ #endif /* !_SYS_EXEC_ELF_H_ */ diff --git a/cpukit/include/sys/timepps.h b/cpukit/include/sys/timepps.h index 01212f0b43..030c734477 100644 --- a/cpukit/include/sys/timepps.h +++ b/cpukit/include/sys/timepps.h @@ -24,12 +24,24 @@ #include <sys/_ffcounter.h> #include <sys/ioccom.h> #include <sys/time.h> +#ifdef __rtems__ +#include <rtems/score/atomic.h> +#define PPS_SYNC +#define hardpps _Timecounter_Discipline +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __rtems__ */ #define PPS_API_VERS_1 1 typedef int pps_handle_t; +#ifndef __rtems__ typedef unsigned pps_seq_t; +#else /* __rtems__ */ +typedef Atomic_Uint pps_seq_t; +#endif /* __rtems__ */ typedef struct ntp_fp { unsigned int integral; @@ -157,6 +169,30 @@ struct pps_state { int ppscap; struct timecounter *ppstc; unsigned ppscount[3]; +#ifdef __rtems__ + /** + * @brief Wait for an event. + * + * Called internally when time_pps_fetch() is used. + * It is initialized by pps_init() to a handler which just returns ETIMEDOUT. + * + * @param pps is the pointer to the object. + * + * @param timeout + * + * @retval 0 A wakeup event was received. + * + * @retval ETIMEDOUT A timeout occurred while waiting for the event. + */ + int (*wait)(struct pps_state *pps, struct timespec timeout); + + /** + * @brief Wakeup the tasks waiting for an event. + * + * @param pps is the pointer to the object. + */ + void (*wakeup)(struct pps_state *pps); +#endif /* __rtems__ */ /* * The following fields are valid if the driver calls pps_init_abi(). */ @@ -263,4 +299,9 @@ time_pps_kcbind(pps_handle_t handle, const int kernel_consumer, #endif /* KERNEL */ +#ifdef __rtems__ +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __rtems__ */ #endif /* !_SYS_TIMEPPS_H_ */ diff --git a/cpukit/include/sys/timetc.h b/cpukit/include/sys/timetc.h index 5cdfdfe9b3..1ef58b378d 100644 --- a/cpukit/include/sys/timetc.h +++ b/cpukit/include/sys/timetc.h @@ -16,6 +16,10 @@ #ifndef _KERNEL #error "no user-serviceable parts inside" #endif +#else /* __rtems__ */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ #endif /* __rtems__ */ /*- @@ -36,6 +40,7 @@ struct vdso_timehands32; typedef u_int timecounter_get_t(struct timecounter *); #else /* __rtems__ */ typedef uint32_t timecounter_get_t(struct timecounter *); +#define tc_getfrequency _Timecounter_Get_frequency #endif /* __rtems__ */ typedef void timecounter_pps_t(struct timecounter *); typedef uint32_t timecounter_fill_vdso_timehands_t(struct vdso_timehands *, @@ -104,4 +109,9 @@ void cpu_tick_calibration(void); SYSCTL_DECL(_kern_timecounter); #endif +#ifdef __rtems__ +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __rtems__ */ #endif /* !_SYS_TIMETC_H_ */ diff --git a/cpukit/libcsupport/src/__gettod.c b/cpukit/libcsupport/src/__gettod.c index 610f2c4d4a..b43081c9eb 100644 --- a/cpukit/libcsupport/src/__gettod.c +++ b/cpukit/libcsupport/src/__gettod.c @@ -41,7 +41,7 @@ /* * Needed to get the prototype for the newlib helper method */ -#define _COMPILING_NEWLIB +#define _LIBC #include <sys/time.h> #include <reent.h> diff --git a/cpukit/libcsupport/src/__times.c b/cpukit/libcsupport/src/__times.c index 629a7bc633..14625b5aae 100644 --- a/cpukit/libcsupport/src/__times.c +++ b/cpukit/libcsupport/src/__times.c @@ -38,9 +38,9 @@ #endif /* - * Needed to get the prototype for this newlib helper method + * Needed to get the prototype for this libc helper method */ -#define _COMPILING_NEWLIB +#define _LIBC #include <rtems.h> diff --git a/cpukit/libcsupport/src/gcovfork.c b/cpukit/libcsupport/src/gcovfork.c new file mode 100644 index 0000000000..763412d735 --- /dev/null +++ b/cpukit/libcsupport/src/gcovfork.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup libcsupport + * + * @brief This source file contains functions required by GCC if code and + * branch coverage instrumentation (gcov) is enabled. + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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 <sys/types.h> + +#include <errno.h> + +#include <rtems/seterr.h> + +int __gcov_execl( const char *, char *, ... ); + +int __gcov_execl( const char *path, char *arg, ... ) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +int __gcov_execlp( const char *, char *, ... ); + +int __gcov_execlp( const char *path, char *arg, ... ) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +int __gcov_execle( const char *, char *, ... ); + +int __gcov_execle( const char *path, char *arg, ... ) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +int __gcov_execv( const char *, char *const[] ); + +int __gcov_execv( const char *path, char *const argv[] ) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +int __gcov_execvp( const char *, char *const[] ); + +int __gcov_execvp( const char *path, char *const argv[] ) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +int __gcov_execve( const char *, char *const[], char *const[] ); + +int __gcov_execve( const char *path, char *const argv[], char *const envp[] ) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +pid_t __gcov_fork( void ); + +pid_t __gcov_fork( void ) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} diff --git a/cpukit/libcsupport/src/getreentglobal.c b/cpukit/libcsupport/src/getreentglobal.c index 72b513ee81..c64f09ac2c 100644 --- a/cpukit/libcsupport/src/getreentglobal.c +++ b/cpukit/libcsupport/src/getreentglobal.c @@ -15,8 +15,10 @@ #if defined(RTEMS_NEWLIB) #include <sys/reent.h> +#ifndef _REENT_THREAD_LOCAL struct _reent *__getreent(void) { return _GLOBAL_REENT; } #endif +#endif diff --git a/cpukit/libcsupport/src/newlibc_reent.c b/cpukit/libcsupport/src/newlibc_reent.c index 2dccfd0375..ee82f00858 100644 --- a/cpukit/libcsupport/src/newlibc_reent.c +++ b/cpukit/libcsupport/src/newlibc_reent.c @@ -29,6 +29,7 @@ #include <rtems/libcsupport.h> #include <rtems/score/threadimpl.h> +#ifndef _REENT_THREAD_LOCAL bool newlib_create_hook( rtems_tcb *current_task RTEMS_UNUSED, rtems_tcb *creating_task @@ -38,12 +39,17 @@ bool newlib_create_hook( return true; } +#endif void newlib_terminate_hook( rtems_tcb *current_task ) { +#ifdef _REENT_THREAD_LOCAL + _reclaim_reent(NULL); +#else _reclaim_reent(current_task->libc_reent); +#endif } #endif diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c index 37d9f4575e..8a21c5df73 100644 --- a/cpukit/libdl/rtl-elf.c +++ b/cpukit/libdl/rtl-elf.c @@ -1171,7 +1171,7 @@ rtems_rtl_elf_symbols_load (rtems_rtl_obj* obj, rtems_chain_set_off_chain (&osym->node); memcpy (string, name, strlen (name) + 1); osym->name = string; - osym->value = (uint8_t*) value; + osym->value = (void*) (intptr_t) value; osym->data = symbol.st_shndx; if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) diff --git a/cpukit/libdl/rtl-elf.h b/cpukit/libdl/rtl-elf.h index c7c17c525a..0476c1ecd7 100644 --- a/cpukit/libdl/rtl-elf.h +++ b/cpukit/libdl/rtl-elf.h @@ -51,7 +51,7 @@ extern "C" { /* * Do not add '()'. Leave plain. */ -#if defined(__powerpc64__) || defined(__arch64__) || (__riscv_xlen == 64) +#if defined(__powerpc64__) || defined(__aarch64__) || (__riscv_xlen == 64) #define ELFSIZE 64 #else #define ELFSIZE 32 diff --git a/cpukit/libdl/rtl-mdreloc-aarch64.c b/cpukit/libdl/rtl-mdreloc-aarch64.c new file mode 100644 index 0000000000..c60ecb31c9 --- /dev/null +++ b/cpukit/libdl/rtl-mdreloc-aarch64.c @@ -0,0 +1,520 @@ +/* + * Taken from NetBSD and stripped of the relocations not needed on RTEMS. + */ + +/* $NetBSD: mdreloc.c,v 1.14 2020/06/16 21:01:30 joerg Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/*- + * Copyright (c) 2014-2015 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Andrew Turner + * under sponsorship from the FreeBSD Foundation. + * + * 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 AUTHOR 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 AUTHOR 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 <sys/cdefs.h> +#ifndef lint +__RCSID("$NetBSD: mdreloc.c,v 1.14 2020/06/16 21:01:30 joerg Exp $"); +#endif /* not lint */ + +#include <sys/types.h> +#include <string.h> +#include <errno.h> +#include <inttypes.h> +#include <sys/stat.h> +#include <sys/endian.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-elf.h" +#include "rtl-error.h" +#include <rtems/rtl/rtl-trace.h> +#include "rtl-unwind-arm.h" + +struct tls_data { + size_t td_tlsindex; + Elf_Addr td_tlsoffs; +}; + +rtems_rtl_elf_rel_status +rtems_rtl_elf_reloc_rela ( + rtems_rtl_obj* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue, + const bool parsing +); + +#define __BITS(hi,lo) ((~((~(Elf_Addr)0)<<((hi)+1)))&((~(Elf_Addr)0)<<(lo))) +#define WIDTHMASK(w) (0xffffffffffffffffUL >> (64 - (w))) + +static inline bool +checkoverflow(Elf_Addr addr, int bitwidth, Elf_Addr targetaddr, + const char *bitscale, void *where, Elf64_Addr off) +{ + const Elf_Addr mask = ~__BITS(bitwidth - 1, 0); + + if (((addr & mask) != 0) && ((addr & mask) != mask)) { + printf("kobj_reloc: Relocation 0x%jx too far from %p" + " (base+0x%jx) for %dbit%s\n", + (uintptr_t)targetaddr, where, off, bitwidth, bitscale); + return true; + } + + return false; +} + +static inline bool +checkalign(Elf_Addr addr, int alignbyte, void *where, Elf64_Addr off) +{ + if ((addr & (alignbyte - 1)) != 0) { + printf("kobj_reloc: Relocation 0x%jx unaligned at %p" + " (base+0x%jx). must be aligned %d\n", + (uintptr_t)addr, where, off, alignbyte); + return true; + } + return false; +} + +/* + * Set to 1 to allow untested relocations. If you tested one and it + * works or you fixed the relocation please remove the guard. + */ +#define ALLOW_UNTESTED_RELOCS 1 + +static void* +set_veneer(void* tramopline, Elf_Addr target) +{ + /* + * http://shell-storm.org/online/Online-Assembler-and-Disassembler/ + * + * ldr x9, #8 + * br x9 + * + */ + uint64_t* tramp = (uint64_t*) tramopline; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + *tramp++ = 0xd61f012058000049; +#else + *tramp++ = 0xd61f012058000049; /* not tested */ +#endif + *tramp++ = (uint64_t) target; + return tramp; +} + +static size_t +get_veneer_size(int type) +{ + (void) type; + return 16; +} + +size_t +rtems_rtl_elf_relocate_tramp_max_size (void) +{ + return 16; +} + +uint32_t +rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj, + const Elf_Shdr* shdr) +{ + return 0; +} + +uint32_t +rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj, + int section, + const char* name, + const Elf_Shdr* shdr, + const uint32_t flags) +{ + (void) obj; + (void) section; + (void) name; + (void) shdr; + return flags; +} + +bool +rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj, + rtems_rtl_obj_sect* sect) +{ + (void) obj; + (void) sect; + return false; +} + +bool +rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj, + rtems_rtl_obj_sect* sect) +{ + (void) obj; + (void) sect; + return false; +} + +bool +rtems_rtl_elf_rel_resolve_sym (Elf_Word type) +{ + return true; +} + +rtems_rtl_elf_rel_status +rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue, + const bool parsing) +{ + Elf64_Addr *where; + Elf32_Addr *where32; + Elf_Addr off = rela->r_offset; + Elf_Addr target; + Elf_Addr raddr; + uint32_t *insn, immhi, immlo, shift; + + where = (Elf_Addr *)(sect->base + rela->r_offset); + where32 = (void *)where; + + insn = (uint32_t *)where; + + /* + * S - the address of the symbol + * A - the addend of the reolcation + * P - the address of the place being relocated (derived from r_offset) + * Page(expr) - the page address of the expression expr, defined as (expr & ~0xFFF). + */ + switch (ELF_R_TYPE(rela->r_info)) { + case R_TYPE(NONE): + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { + printf ("rtl: NONE %p in %s\n", where, rtems_rtl_obj_oname (obj)); + } + break; + + case R_TYPE(ABS64): /* word S + A */ + case R_TYPE(GLOB_DAT): /* word S + A */ + if (!parsing) { + target = (Elf_Addr)symvalue + rela->r_addend; + + if (*where != target) + *where = target; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc 64/GLOB_DAT in %s --> %p in %s\n", + sect->name, (void *)*where, + rtems_rtl_obj_oname (obj)); + } + break; + + /* + * If S is a normal symbol, resolves to the difference between the static + * link address of S and the execution address of S. If S is the null symbol + * (ELF symbol index 0), resolves to the difference between the static link + * address of P and the execution address of P. + */ + case R_TYPE(RELATIVE): /* Delta(S) + A */ + if (!parsing) { + *where = (Elf_Addr)(sect->base + rela->r_addend); + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: reloc RELATIVE in %s --> %p in %s\n", + sect->name, (void *)*where, + rtems_rtl_obj_oname (obj)); + } + break; + + case R_TYPE(COPY): + /* + * These are deferred until all other relocations have + * been done. All we do here is make sure that the + * COPY relocation is not in a shared library. They + * are allowed only in executable files. + */ + printf("rtl: reloc COPY (please report)\n"); + break; + + case R_AARCH64_ADD_ABS_LO12_NC: /* S + A */ + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH_LDST16_ABS_LO12_NC: + case R_AARCH_LDST32_ABS_LO12_NC: + case R_AARCH_LDST64_ABS_LO12_NC: + switch (ELF_R_TYPE(rela->r_info)) { + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST8_ABS_LO12_NC: + shift = 0; + break; + case R_AARCH_LDST16_ABS_LO12_NC: + shift = 1; + break; + case R_AARCH_LDST32_ABS_LO12_NC: + shift = 2; + break; + case R_AARCH_LDST64_ABS_LO12_NC: + shift = 3; + break; + default: + printf("illegal rtype: %ld\n", ELF_R_TYPE(rela->r_info)); + break; + } + + /* + * S + A + * e.g.) add x0,x0,#:lo12:<sym>+<addend> + * ldrb w0,[x0,#:lo12:<sym>+<addend>] + * ldrh w0,[x0,#:lo12:<sym>+<addend>] + * ldr w0,[x0,#:lo12:<sym>+<addend>] + * ldr x0,[x0,#:lo12:<sym>+<addend>] + */ + if (!parsing) { + target = (Elf_Addr)symvalue + rela->r_addend; + if (checkalign(target, 1 << shift, where, off)) { + printf ("rtl: reloc checkalign failed in %s --> %p in %s\n", + sect->name, (void *)*where, + rtems_rtl_obj_oname (obj)); + printf("ELF_R_TYPE is : %ld\n", ELF_R_TYPE(rela->r_info)); + break; + } + target &= WIDTHMASK(12); + target >>= shift; + *insn = htole32( + (le32toh(*insn) & ~__BITS(21,10)) | (target << 10)); + } + break; + + case R_AARCH64_ADR_PREL_PG_HI21: + /* + * Page(S + A) - Page(P) + * e.g.) adrp x0,<sym>+<addend> + */ + if (!parsing) { + target = (Elf_Addr)symvalue + rela->r_addend; + target = target >> 12; + raddr = target << 12; + target -= (uintptr_t)where >> 12; + + if (checkoverflow(target, 21, raddr, " x 4k", where, off)) { + return rtems_rtl_elf_rel_failure; + } + + immlo = target & WIDTHMASK(2); + immhi = (target >> 2) & WIDTHMASK(19); + *insn = htole32((le32toh(*insn) & + ~(__BITS(30,29) | __BITS(23,5))) | + (immlo << 29) | (immhi << 5)); + } + break; + + case R_AARCH_JUMP26: + case R_AARCH_CALL26: + /* + * S + A - P + * e.g.) b <sym>+<addend> + * bl <sym>+<addend> + */ + if (parsing && sect->base == 0) { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: JUMP26/PC26/CALL tramp cache\n"); + return rtems_rtl_elf_rel_tramp_cache; + } + + raddr = (Elf_Addr)symvalue + rela->r_addend; + target = raddr - (uintptr_t)where; + if (checkalign(target, 4, where, off)) { + return rtems_rtl_elf_rel_failure; + } + + target = (intptr_t)target >> 2; + + if (((Elf_Sword)target > 0x1FFFFFF) || ((Elf_Sword)target < -0x2000000)) { + Elf_Word tramp_addr; + size_t tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info)); + + if (parsing) { + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: JUMP26/PC26/CALL tramp add\n"); + return rtems_rtl_elf_rel_tramp_add; + } + + if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) { + rtems_rtl_set_error (EINVAL, + "%s: CALL/JUMP26: overflow: no tramp memory", + sect->name); + return rtems_rtl_elf_rel_failure; + } + + tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1); + obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue); + + target = tramp_addr + rela->r_addend - (uintptr_t)where; + target = (uintptr_t)target >> 2; + } + + if (checkoverflow(target, 26, raddr, " word", where, off)) { + return rtems_rtl_elf_rel_failure; + } + + if (!parsing) { + target &= WIDTHMASK(26); + *insn = htole32((le32toh(*insn) & ~__BITS(25,0)) | target); + } + + break; + + case R_AARCH64_PREL32: + /* + * S + A - P + * e.g.) 1: .word <sym>+<addend>-1b + */ + if (!parsing) { + raddr = (Elf_Addr)symvalue + rela->r_addend; + target = raddr - (uintptr_t)where; + if (checkoverflow(target, 32, raddr, "", where, off)) { + return rtems_rtl_elf_rel_failure; + } + *where32 = target; + } + break; + + case R_TYPE(TLSDESC): + printf ("rtl: reloc TLSDESC in %s --> %p in %s\n", + sect->name, (void *)*where, + rtems_rtl_obj_oname (obj)); + break; + + case R_TLS_TYPE(TLS_DTPREL): + printf ("rtl: reloc TLS_DTPREL in %s --> %p in %s\n", + sect->name, (void *)*where, + rtems_rtl_obj_oname (obj)); + break; + case R_TLS_TYPE(TLS_DTPMOD): + printf ("rtl: reloc TLS_DTPMOD in %s --> %p in %s\n", + sect->name, (void *)*where, + rtems_rtl_obj_oname (obj)); + break; + + case R_TLS_TYPE(TLS_TPREL): + printf ("rtl: reloc TLS_TPREL in %s --> %p in %s\n", + sect->name, (void *)*where, + rtems_rtl_obj_oname (obj)); + break; + + default: + printf ("rtl: Unsupported relocation type in %s --> %p in %s\n", + sect->name, (void *)where, + rtems_rtl_obj_oname (obj)); + return rtems_rtl_elf_rel_failure; + } + + return rtems_rtl_elf_rel_no_error; +} + +rtems_rtl_elf_rel_status +rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + return rtems_rtl_elf_reloc_rela (obj, + rela, + sect, + symname, + syminfo, + symvalue, + true); +} + +rtems_rtl_elf_rel_status +rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + return rtems_rtl_elf_reloc_rela (obj, + rela, + sect, + symname, + syminfo, + symvalue, + false); +} + +rtems_rtl_elf_rel_status +rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + return rtems_rtl_elf_rel_failure; +} + +rtems_rtl_elf_rel_status +rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue) +{ + rtems_rtl_set_error (EINVAL, "rela type record not supported"); + return rtems_rtl_elf_rel_failure; +} diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c index 4950dcdab1..fbfd42dc58 100644 --- a/cpukit/libdl/rtl-mdreloc-arm.c +++ b/cpukit/libdl/rtl-mdreloc-arm.c @@ -12,14 +12,12 @@ #include <string.h> #include <sys/types.h> #include <sys/stat.h> -#include <unwind.h> -#include <unwind-arm-common.h> #include <rtems/rtl/rtl.h> #include "rtl-elf.h" #include "rtl-error.h" #include <rtems/rtl/rtl-trace.h> -#include "rtl-unwind.h" +#include "rtl-unwind-arm.h" /* * Set to 1 to allow untested relocations. If you tested one and it @@ -597,78 +595,3 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, symvalue, false); } - -bool -rtems_rtl_elf_unwind_parse (const rtems_rtl_obj* obj, - const char* name, - uint32_t flags) -{ - /* - * We location the EH sections in section flags. - */ - return false; -} - -bool -rtems_rtl_elf_unwind_register (rtems_rtl_obj* obj) -{ - return true; -} - -bool -rtems_rtl_elf_unwind_deregister (rtems_rtl_obj* obj) -{ - obj->loader = NULL; - return true; -} - -/* An exception index table entry. */ -typedef struct __EIT_entry -{ - _uw fnoffset; - _uw content; -} __EIT_entry; - -/* The exception index table location in the base module */ -extern __EIT_entry __exidx_start; -extern __EIT_entry __exidx_end; - -/* - * A weak reference is in libgcc, provide a real version and provide a way to - * manage loaded modules. - * - * Passed in the return address and a reference to the number of records - * found. We set the start of the exidx data and the number of records. - */ -_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address, - int* nrec) __attribute__ ((__noinline__, - __used__, - __noclone__)); - -_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address, - int* nrec) -{ - rtems_rtl_data* rtl; - rtems_chain_node* node; - __EIT_entry* exidx_start = &__exidx_start; - __EIT_entry* exidx_end = &__exidx_end; - - rtl = rtems_rtl_lock (); - - node = rtems_chain_first (&rtl->objects); - while (!rtems_chain_is_tail (&rtl->objects, node)) { - rtems_rtl_obj* obj = (rtems_rtl_obj*) node; - if (rtems_rtl_obj_text_inside (obj, (void*) return_address)) { - exidx_start = (__EIT_entry*) obj->eh_base; - exidx_end = (__EIT_entry*) (obj->eh_base + obj->eh_size); - break; - } - node = rtems_chain_next (node); - } - - rtems_rtl_unlock (); - - *nrec = exidx_end - exidx_start; - - return (_Unwind_Ptr) exidx_start; -} diff --git a/cpukit/libdl/rtl-obj-comp.c b/cpukit/libdl/rtl-obj-comp.c index ea408527b7..001d416e80 100644 --- a/cpukit/libdl/rtl-obj-comp.c +++ b/cpukit/libdl/rtl-obj-comp.c @@ -115,7 +115,7 @@ rtems_rtl_obj_comp_read (rtems_rtl_obj_comp* comp, } if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP)) - printf ("rtl: comp: %2d: fd=%d length=%zu level=%u offset=%" PRIdoff_t " area=[%" + printf ("rtl: comp: %2d: fd=%d length=%zu level=%zu offset=%" PRIdoff_t " area=[%" PRIdoff_t ",%" PRIdoff_t "] read=%" PRIu32 " size=%zu\n", comp->fd, comp->cache->fd, length, comp->level, comp->offset, comp->offset, comp->offset + length, @@ -143,7 +143,7 @@ rtems_rtl_obj_comp_read (rtems_rtl_obj_comp* comp, if ((comp->level - buffer_level) != 0) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP)) - printf ("rtl: comp: copy-down: level=%u length=%zu\n", + printf ("rtl: comp: copy-down: level=%zu length=%zu\n", comp->level, comp->level - buffer_level); memmove (comp->buffer, @@ -221,7 +221,7 @@ rtems_rtl_obj_comp_read (rtems_rtl_obj_comp* comp, if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP)) printf ("rtl: comp: expand: offset=%" PRIdoff_t \ - " level=%u read=%" PRIu32 "\n", + " level=%zu read=%" PRIu32 "\n", comp->offset, comp->level, comp->read); } } diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c index 732f66131e..69de6bad83 100644 --- a/cpukit/libdl/rtl-shell.c +++ b/cpukit/libdl/rtl-shell.c @@ -406,7 +406,7 @@ typedef struct const rtems_rtl_obj_print* print; /**< The print data. */ bool first; /**< Is this the first line printed. */ bool show_name; /**< Show the object name. */ - size_t indent; /**< The indent. */ + int indent; /**< The indent. */ } rtems_rtl_dep_data; static bool @@ -849,7 +849,7 @@ rtems_rtl_shell_archive (const rtems_printer* printer, int argc, char* argv[]) while (!rtems_chain_is_tail (&rtl->archives.archives, node)) { - #define SYM_DUPLICATE (1 << ((8 * sizeof (size_t)) - 1)) + #define SYM_DUPLICATE (((size_t) 1) << ((8 * sizeof (size_t)) - 1)) rtems_rtl_archive* archive = (rtems_rtl_archive*) node; diff --git a/cpukit/libdl/rtl-sym.c b/cpukit/libdl/rtl-sym.c index c29c8c49d6..5c9c3981df 100644 --- a/cpukit/libdl/rtl-sym.c +++ b/cpukit/libdl/rtl-sym.c @@ -124,7 +124,7 @@ rtems_rtl_symbol_global_add (rtems_rtl_obj* obj, return false; } ++count; - s += l + sizeof (unsigned long) + 1; + s += l + sizeof (void *) + 1; } /* diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c index a774c7f1c9..43a05e9887 100644 --- a/cpukit/libdl/rtl-unresolved.c +++ b/cpukit/libdl/rtl-unresolved.c @@ -810,8 +810,8 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec, case rtems_rtl_trampoline_reloc: if (dd->show_relocs) printf (" %3zu: 2:reloc%c: obj:%s name:%2d: sect:%d\n", - rec->type == rtems_rtl_unresolved_reloc ? 'R' : 'T', dd->rec, + rec->type == rtems_rtl_unresolved_reloc ? 'R' : 'T', rec->rec.reloc.obj == NULL ? "resolved" : rec->rec.reloc.obj->oname, rec->rec.reloc.name, rec->rec.reloc.sect); diff --git a/cpukit/libdl/rtl-unwind-arm.c b/cpukit/libdl/rtl-unwind-arm.c new file mode 100644 index 0000000000..35361fe8d5 --- /dev/null +++ b/cpukit/libdl/rtl-unwind-arm.c @@ -0,0 +1,65 @@ +#include "rtl-unwind-arm.h" + +bool +rtems_rtl_elf_unwind_parse (const rtems_rtl_obj* obj, + const char* name, + uint32_t flags) +{ + /* + * We location the EH sections in section flags. + */ + return false; +} + +bool +rtems_rtl_elf_unwind_register (rtems_rtl_obj* obj) +{ + return true; +} + +bool +rtems_rtl_elf_unwind_deregister (rtems_rtl_obj* obj) +{ + obj->loader = NULL; + return true; +} + +/* + * A weak reference is in libgcc, provide a real version and provide a way to + * manage loaded modules. + * + * Passed in the return address and a reference to the number of records + * found. We set the start of the exidx data and the number of records. + */ +_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address, + int* nrec) __attribute__ ((__noinline__, + __used__, + __noclone__)); + +_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address, + int* nrec) +{ + rtems_rtl_data* rtl; + rtems_chain_node* node; + __EIT_entry* exidx_start = &__exidx_start; + __EIT_entry* exidx_end = &__exidx_end; + + rtl = rtems_rtl_lock (); + + node = rtems_chain_first (&rtl->objects); + while (!rtems_chain_is_tail (&rtl->objects, node)) { + rtems_rtl_obj* obj = (rtems_rtl_obj*) node; + if (rtems_rtl_obj_text_inside (obj, (void*) return_address)) { + exidx_start = (__EIT_entry*) obj->eh_base; + exidx_end = (__EIT_entry*) (obj->eh_base + obj->eh_size); + break; + } + node = rtems_chain_next (node); + } + + rtems_rtl_unlock (); + + *nrec = exidx_end - exidx_start; + + return (_Unwind_Ptr) exidx_start; +} diff --git a/cpukit/libdl/rtl-unwind-arm.h b/cpukit/libdl/rtl-unwind-arm.h new file mode 100644 index 0000000000..08a2660560 --- /dev/null +++ b/cpukit/libdl/rtl-unwind-arm.h @@ -0,0 +1,46 @@ +#include <unwind.h> + +#include <rtems/rtl/rtl.h> +#include "rtl-unwind.h" + +typedef unsigned _Unwind_Word __attribute__((__mode__(__word__))); +typedef _Unwind_Word _uw; + +bool +rtems_rtl_elf_unwind_parse (const rtems_rtl_obj* obj, + const char* name, + uint32_t flags); + +bool +rtems_rtl_elf_unwind_register (rtems_rtl_obj* obj); + +bool +rtems_rtl_elf_unwind_deregister (rtems_rtl_obj* obj); + +/* An exception index table entry. */ +typedef struct __EIT_entry +{ + _uw fnoffset; + _uw content; +} __EIT_entry; + +/* The exception index table location in the base module */ +extern __EIT_entry __exidx_start; +extern __EIT_entry __exidx_end; + +/* + * A weak reference is in libgcc, provide a real version and provide a way to + * manage loaded modules. + * + * Passed in the return address and a reference to the number of records + * found. We set the start of the exidx data and the number of records. + */ +_Unwind_Ptr +__gnu_Unwind_Find_exidx (_Unwind_Ptr return_address, + int* nrec) __attribute__ ((__noinline__, + __used__, + __noclone__)); + +_Unwind_Ptr +__gnu_Unwind_Find_exidx (_Unwind_Ptr return_address, + int* nrec); diff --git a/cpukit/libfs/src/ftpfs/tftpDriver.c b/cpukit/libfs/src/ftpfs/tftpDriver.c index bebe748ca5..59136ef59f 100644 --- a/cpukit/libfs/src/ftpfs/tftpDriver.c +++ b/cpukit/libfs/src/ftpfs/tftpDriver.c @@ -3,16 +3,26 @@ /** * @file * - * Trivial File Transfer Protocol file system (TFTP client) for RFC 1350. + * @ingroup RTEMSImplTFTPFS * - * Transfer file to/from remote host + * @brief This source file contains the implementation of + * a Trivial File Transfer Protocol (TFTP) client library. + * + * The code in this file provides the ability to read files from and + * to write files to remote servers using the Trivial File Transfer + * Protocol (TFTP). It is used by the @ref tftpfs.c "TFTP file system" and + * tested through its test suite. The + * following RFCs are implemented: + * + * + RFC 1350 "The TFTP Protocol (Revision 2)" + * + RFC 2347 "TFTP Option Extension" + * + RFC 2348 "TFTP Blocksize Option" + * + RFC 7440 "TFTP Windowsize Option" */ /* - * Copyright (c) 1998 Eric Norum <eric@norum.ca> - * - * Modifications to support reference counting in the file system are - * Copyright (c) 2012 embedded brains GmbH. + * Copyright (C) 1998 W. Eric Norum <eric@norum.ca> + * Copyright (C) 2012, 2022 embedded brains GmbH (http://www.embedded-brains.de) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,29 +52,21 @@ #include <stdio.h> #include <stdlib.h> +#include <inttypes.h> #include <errno.h> #include <malloc.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <rtems.h> -#include <rtems/libio_.h> -#include <rtems/seterr.h> #include <rtems/tftp.h> -#include <rtems/thread.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> -#ifdef RTEMS_NETWORKING -#include <rtems/rtems_bsdnet.h> -#endif - -#ifdef RTEMS_TFTP_DRIVER_DEBUG -int rtems_tftp_driver_debug = 1; -#endif +#include "tftp_driver.h" /* * Range of UDP ports to try @@ -75,9 +77,21 @@ int rtems_tftp_driver_debug = 1; * Default limits */ #define PACKET_FIRST_TIMEOUT_MILLISECONDS 400L -#define PACKET_TIMEOUT_MILLISECONDS 6000L -#define OPEN_RETRY_LIMIT 10 -#define IO_RETRY_LIMIT 10 +#define TFTP_WINDOW_SIZE_MIN 1 +#define TFTP_BLOCK_SIZE_MIN 8 +#define TFTP_BLOCK_SIZE_MAX 65464 + +#define TFTP_BLOCK_SIZE_OPTION "blksize" +#define TFTP_WINDOW_SIZE_OPTION "windowsize" +#define TFTP_DECIMAL_BASE 10 + +#define TFTP_DEFAULT_SERVER_PORT 69 + +/* + * These values are suggested by RFC 7440. + */ +#define TFTP_RFC7440_DATA_RETRANSMISSIONS 6 +#define TFTP_RFC7440_TIMEOUT_MILLISECONDS 1000 /* * TFTP opcodes @@ -87,11 +101,46 @@ int rtems_tftp_driver_debug = 1; #define TFTP_OPCODE_DATA 3 #define TFTP_OPCODE_ACK 4 #define TFTP_OPCODE_ERROR 5 +#define TFTP_OPCODE_OACK 6 + +/* + * TFTP error codes + */ +#define TFTP_ERROR_CODE_NOT_DEFINED 0 +#define TFTP_ERROR_CODE_NOT_FOUND 1 +#define TFTP_ERROR_CODE_NO_ACCESS 2 +#define TFTP_ERROR_CODE_DISK_FULL 3 +#define TFTP_ERROR_CODE_ILLEGAL 4 +#define TFTP_ERROR_CODE_UNKNOWN_ID 5 +#define TFTP_ERROR_CODE_FILE_EXISTS 6 +#define TFTP_ERROR_CODE_NO_USER 7 +#define TFTP_ERROR_CODE_OPTION_NEGO 8 + +/* + * Special return values for process_*_packet() functions + * (other return values are POSIX errors) + */ +#define GOT_EXPECTED_PACKET 0 +#define GOT_DUPLICATE_OF_CURRENT_PACKET -1 +#define GOT_OLD_PACKET -2 +#define GOT_FIRST_OUT_OF_ORDER_PACKET -3 + +/* + * Special argument value for getPacket() + */ +#define GET_PACKET_DONT_WAIT -1 /* - * Largest data transfer + * Special return value for prepare_*_packet_for_sending() functions + * (other return values are the length of the packet to be send) */ -#define TFTP_BUFSIZE 512 +#define DO_NOT_SEND_PACKET 0 + +#define PKT_SIZE_FROM_BLK_SIZE(_blksize) ((_blksize) + 2 * sizeof (uint16_t)) +#define BLK_SIZE_FROM_PKT_SIZE(_pktsize) ((_pktsize) - 2 * sizeof (uint16_t)) +#define MUST_SEND_OPTIONS(_options) (\ + (_options).block_size != TFTP_RFC1350_BLOCK_SIZE || \ + (_options).window_size != TFTP_RFC1350_WINDOW_SIZE ) /* * Packets transferred between machines @@ -102,7 +151,7 @@ union tftpPacket { */ struct tftpRWRQ { uint16_t opcode; - char filename_mode[TFTP_BUFSIZE]; + char filename_mode[]; } tftpRWRQ; /* @@ -111,7 +160,7 @@ union tftpPacket { struct tftpDATA { uint16_t opcode; uint16_t blocknum; - uint8_t data[TFTP_BUFSIZE]; + uint8_t data[]; } tftpDATA; /* @@ -123,12 +172,20 @@ union tftpPacket { } tftpACK; /* + * OACK packet + */ + struct tftpOACK { + uint16_t opcode; + char options[]; + } tftpOACK; + + /* * ERROR packet */ struct tftpERROR { uint16_t opcode; uint16_t errorCode; - char errorMessage[TFTP_BUFSIZE]; + char errorMessage[]; } tftpERROR; }; @@ -137,16 +194,57 @@ union tftpPacket { */ struct tftpStream { /* - * Buffer for storing most recently-received packet + * Buffer for storing packets for sending and receiving. Can point + * to the same address when only one buffer is needed for reading. */ - union tftpPacket pkbuf; + union tftpPacket *receive_buf; + union tftpPacket *send_buf; /* - * Last block number transferred + * Current block number - i.e. the block currently send or received */ uint16_t blocknum; /* + * Size of the data area in a DATA single packet. + */ + size_t block_size; + + /* + * The maximum size of a packet. It depends linearly on the block_size. + * The receive_buf and (the packets in) the send_buf are of this size. + */ + size_t packet_size; + + /* + * The number of packets which can be stored in the send buffer. + * During option negotiation and for reading a file from the server + * only a buffer for a single packet is needed. In those cases, this + * value is always one. When a file is written to the server, + * the value equals the window size: + * send_buf_size_in_pkts == server_options.window_size + * + * Packet N is stored in + * send_buf + packet_size * (N % send_buf_size_in_pkts) + */ + uint16_t send_buf_size_in_pkts; + + /* + * When writing files with windowsize > 1, the number of the completely + * filled packet with the highest block number in the send buffer. + * When the user calls write(), the data will be written into + * the block after this one. + */ + uint16_t blocknum_last_filled; + + /* + * When writing files with windowsize > 1, the number of the packet + * which is the last one in the whole file (i.e. the user + * called close()). This block is never full (but maybe empty). + */ + uint16_t blocknum_eof_block; + + /* * Data transfer socket */ int socket; @@ -155,6 +253,9 @@ struct tftpStream { /* * Indices into buffer + * In case of sending a file with windowsize > 1, these values apply + * only to the packet with the highest number in the send buffer + * (blocknum_last_filled + 1). */ int nleft; int nused; @@ -163,143 +264,161 @@ struct tftpStream { * Flags */ int firstReply; - int eof; - int writing; + bool at_eof; + bool is_for_reading; + + /* + * Function pointers and members for use by communicate_with_server(). + */ + ssize_t (*prepare_packet_for_sending) ( + struct tftpStream *tp, + bool force_retransmission, + union tftpPacket **send_buf, + bool *wait_for_packet_reception, + const void *create_packet_data + ); + int (*process_data_packet) (struct tftpStream *tp, ssize_t len); + int (*process_ack_packet) (struct tftpStream *tp, ssize_t len); + int (*process_oack_packet) (struct tftpStream *tp, ssize_t len); + int (*process_error_packet) (struct tftpStream *tp, ssize_t len); + int retransmission_error_code; + bool ignore_out_of_order_packets; + int32_t blocknum_of_first_packet_of_window; + int error; + + /* + * Configuration and TFTP options + * + * * config.options are options desired by the user (i.e. the values + * send to the server). + * * server_options are the options agreed by the server + * (the option values actually used for the transfer of data). + */ + tftp_net_config config; + tftp_options server_options; }; /* - * Flags for filesystem info. + * Forward declaration cannot be avoided. */ -#define TFTPFS_VERBOSE (1 << 0) +static ssize_t prepare_data_packet_for_sending ( + struct tftpStream *tp, + bool force_retransmission, + union tftpPacket **send_buf, + bool *wait_for_packet_reception, + const void *path_name +); +static ssize_t prepare_ack_packet_for_sending ( + struct tftpStream *tp, + bool force_retransmission, + union tftpPacket **send_buf, + bool *wait_for_packet_reception, + const void *path_name +); /* - * TFTP File system info. + * Calculate the address of packet N in the send buffer */ -typedef struct tftpfs_info_s { - uint32_t flags; - rtems_mutex tftp_mutex; - int nStreams; - struct tftpStream ** volatile tftpStreams; -} tftpfs_info_t; - -#define tftpfs_info_mount_table(_mt) ((tftpfs_info_t*) ((_mt)->fs_info)) -#define tftpfs_info_pathloc(_pl) ((tftpfs_info_t*) ((_pl)->mt_entry->fs_info)) -#define tftpfs_info_iop(_iop) (tftpfs_info_pathloc (&((_iop)->pathinfo))) +static union tftpPacket *get_send_buffer_packet ( + struct tftpStream *tp, + uint16_t packet_num +) +{ + return (union tftpPacket *) ( ( (char *) tp->send_buf) + tp->packet_size * + (packet_num % tp->send_buf_size_in_pkts) ); +} /* - * Number of streams open at the same time + * Create read or write request */ - -static const rtems_filesystem_operations_table rtems_tftp_ops; -static const rtems_filesystem_file_handlers_r rtems_tftp_handlers; - -static bool rtems_tftp_is_directory( +static size_t create_request ( + union tftpPacket *send_buf, + size_t data_size, + bool is_for_reading, const char *path, - size_t pathlen + const tftp_options *options ) { - return path [pathlen - 1] == '/'; -} + size_t res_size; + char *cur = send_buf->tftpRWRQ.filename_mode; -int rtems_tftpfs_initialize( - rtems_filesystem_mount_table_entry_t *mt_entry, - const void *data -) -{ - const char *device = mt_entry->dev; - size_t devicelen = strlen (device); - tftpfs_info_t *fs = NULL; - char *root_path; - - if (devicelen == 0) { - root_path = malloc (1); - if (root_path == NULL) - goto error; - root_path [0] = '\0'; + send_buf->tftpRWRQ.opcode = htons ( + is_for_reading ? TFTP_OPCODE_RRQ : TFTP_OPCODE_WRQ + ); + + res_size = snprintf (cur, data_size, "%s%c%s", path, 0, "octet"); + if (res_size >= data_size) { + return -1; } - else { - root_path = malloc (devicelen + 2); - if (root_path == NULL) - goto error; - - root_path = memcpy (root_path, device, devicelen); - root_path [devicelen] = '/'; - root_path [devicelen + 1] = '\0'; + res_size++; + data_size -= res_size; + cur += res_size; + + if (options->block_size != TFTP_RFC1350_BLOCK_SIZE) { + res_size = snprintf ( + cur, + data_size, + "%s%c%"PRIu16, + TFTP_BLOCK_SIZE_OPTION, + 0, + options->block_size + ); + if (res_size >= data_size) { + return -1; + } + res_size++; + data_size -= res_size; + cur += res_size; } - fs = malloc (sizeof (*fs)); - if (fs == NULL) - goto error; - fs->flags = 0; - fs->nStreams = 0; - fs->tftpStreams = 0; - - mt_entry->fs_info = fs; - mt_entry->mt_fs_root->location.node_access = root_path; - mt_entry->mt_fs_root->location.handlers = &rtems_tftp_handlers; - mt_entry->ops = &rtems_tftp_ops; - - /* - * Now allocate a semaphore for mutual exclusion. - * - * NOTE: This could be in an fsinfo for this filesystem type. - */ - - rtems_mutex_init (&fs->tftp_mutex, "TFTPFS"); - - if (data) { - char* config = (char*) data; - char* token; - char* saveptr; - token = strtok_r (config, " ", &saveptr); - while (token) { - if (strcmp (token, "verbose") == 0) - fs->flags |= TFTPFS_VERBOSE; - token = strtok_r (NULL, " ", &saveptr); + if (options->window_size != TFTP_RFC1350_WINDOW_SIZE) { + res_size = snprintf ( + cur, + data_size, + "%s%c%"PRIu16, + TFTP_WINDOW_SIZE_OPTION, + 0, + options->window_size + ); + if (res_size >= data_size) { + return -1; } + res_size++; + data_size -= res_size; + cur += res_size; } - - return 0; -error: - - free (fs); - free (root_path); - - rtems_set_errno_and_return_minus_one (ENOMEM); + return cur - (char *)send_buf; } -/* - * Release a stream and clear the pointer to it - */ -static void -releaseStream (tftpfs_info_t *fs, int s) +static bool parse_decimal_number ( + char **pos, + size_t *remain, + long min, + long max, + uint16_t *variable +) { - if (fs->tftpStreams[s] && (fs->tftpStreams[s]->socket >= 0)) - close (fs->tftpStreams[s]->socket); - rtems_mutex_lock (&fs->tftp_mutex); - free (fs->tftpStreams[s]); - fs->tftpStreams[s] = NULL; - rtems_mutex_unlock (&fs->tftp_mutex); -} + long value; + const char *start = *pos; + if (*remain < 2) { + return false; + } + value = strtoul(start, pos, TFTP_DECIMAL_BASE); + if (value < min || value > max || **pos != 0) { + return false; + } + *variable = (uint16_t) value; + (*pos)++; + *remain -= *pos - start; -static void -rtems_tftpfs_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry) -{ - tftpfs_info_t *fs = tftpfs_info_mount_table (mt_entry); - int s; - for (s = 0; s < fs->nStreams; s++) - releaseStream (fs, s); - rtems_mutex_destroy (&fs->tftp_mutex); - free (fs); - free (mt_entry->mt_fs_root->location.node_access); + return true; } /* * Map error message */ -static int -tftpErrno (struct tftpStream *tp) +static int tftpErrno (uint16_t error_code) { unsigned int tftpError; static const int errorMap[] = { @@ -311,9 +430,10 @@ tftpErrno (struct tftpStream *tp) ENXIO, EEXIST, ESRCH, + ENOTSUP, /* Error: Option negotiation failed (RFC 2347) */ }; - tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode); + tftpError = ntohs (error_code); if (tftpError < (sizeof errorMap / sizeof errorMap[0])) return errorMap[tftpError]; else @@ -321,25 +441,87 @@ tftpErrno (struct tftpStream *tp) } /* - * Send a message to make the other end shut up + * Parse options from an OACK packet + */ +static bool parse_options ( + union tftpPacket *receive_buf, + size_t packet_size, + tftp_options *options_in, + tftp_options *options_out +) +{ + char *pos = receive_buf->tftpOACK.options; + size_t remain = packet_size - sizeof (receive_buf->tftpOACK.opcode); + + /* + * Make sure there is a 0 byte in the end before comparing strings + */ + if (remain > 0 && pos[remain - 1] != 0) { + return false; + } + + while (remain > 0) { + if (strcasecmp(pos, TFTP_BLOCK_SIZE_OPTION) == 0 && + options_in->block_size != TFTP_RFC1350_BLOCK_SIZE) { + remain -= sizeof (TFTP_BLOCK_SIZE_OPTION); + pos += sizeof (TFTP_BLOCK_SIZE_OPTION); + if (!parse_decimal_number ( + &pos, + &remain, + TFTP_BLOCK_SIZE_MIN, + options_in->block_size, + &options_out->block_size)) { + return false; + }; + + } else if (strcasecmp(pos, TFTP_WINDOW_SIZE_OPTION) == 0 && + options_in->window_size != TFTP_RFC1350_WINDOW_SIZE) { + remain -= sizeof (TFTP_WINDOW_SIZE_OPTION); + pos += sizeof (TFTP_WINDOW_SIZE_OPTION); + if (!parse_decimal_number ( + &pos, + &remain, + TFTP_WINDOW_SIZE_MIN, + options_in->window_size, + &options_out->window_size)) { + return false; + }; + + } else { + return false; /* Unknown option */ + } + } + + return true; +} + +/* + * Send an error message */ -static void -sendStifle (struct tftpStream *tp, struct sockaddr_in *to) +static void send_error ( + struct tftpStream *tp, + struct sockaddr_in *to, + uint8_t error_code, + const char *error_message +) { int len; struct { uint16_t opcode; uint16_t errorCode; - char errorMessage[12]; + char errorMessage[80]; } msg; /* * Create the error packet (Unknown transfer ID). */ msg.opcode = htons (TFTP_OPCODE_ERROR); - msg.errorCode = htons (5); - len = sizeof msg.opcode + sizeof msg.errorCode + 1; - len += sprintf (msg.errorMessage, "GO AWAY"); + msg.errorCode = htons (error_code); + len = snprintf (msg.errorMessage, sizeof (msg.errorMessage), error_message); + if (len >= sizeof (msg.errorMessage)) { + len = sizeof (msg.errorMessage) - 1; + } + len += sizeof (msg.opcode) + sizeof (msg.errorCode) + 1; /* * Send it @@ -348,32 +530,47 @@ sendStifle (struct tftpStream *tp, struct sockaddr_in *to) } /* - * Wait for a data packet + * Send a message to make the other end shut up + */ +static void sendStifle (struct tftpStream *tp, struct sockaddr_in *to) +{ + send_error (tp, to, TFTP_ERROR_CODE_UNKNOWN_ID, "GO AWAY"); +} + +/* + * Wait for a packet */ -static int +static ssize_t getPacket (struct tftpStream *tp, int retryCount) { - int len; + ssize_t len; struct timeval tv; - - if (retryCount == 0) { - tv.tv_sec = PACKET_FIRST_TIMEOUT_MILLISECONDS / 1000L; - tv.tv_usec = (PACKET_FIRST_TIMEOUT_MILLISECONDS % 1000L) * 1000L; - } - else { - tv.tv_sec = PACKET_TIMEOUT_MILLISECONDS / 1000L; - tv.tv_usec = (PACKET_TIMEOUT_MILLISECONDS % 1000L) * 1000L; + int flags = 0; + + if (retryCount == GET_PACKET_DONT_WAIT) { + flags = MSG_DONTWAIT; + } else if (retryCount == 0) { + tv.tv_sec = tp->config.first_timeout / 1000L; + tv.tv_usec = (tp->config.first_timeout % 1000L) * 1000L; + setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); + } else { + tv.tv_sec = tp->config.timeout / 1000L; + tv.tv_usec = (tp->config.timeout % 1000L) * 1000L; + setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); } - setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); for (;;) { union { struct sockaddr s; struct sockaddr_in i; } from; socklen_t fromlen = sizeof from; - len = recvfrom (tp->socket, &tp->pkbuf, - sizeof tp->pkbuf, 0, - &from.s, &fromlen); + len = recvfrom (tp->socket, + tp->receive_buf, + tp->packet_size, + flags, + &from.s, + &fromlen + ); if (len < 0) break; if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) { @@ -391,397 +588,706 @@ getPacket (struct tftpStream *tp, int retryCount) */ sendStifle (tp, &from.i); } - tv.tv_sec = 0; - tv.tv_usec = 0; - setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); -#ifdef RTEMS_TFTP_DRIVER_DEBUG - if (rtems_tftp_driver_debug) { - if (len >= (int) sizeof tp->pkbuf.tftpACK) { - int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); - switch (opcode) { - default: - printf ("TFTP: OPCODE %d\n", opcode); - break; - - case TFTP_OPCODE_DATA: - printf ("TFTP: RECV %d\n", ntohs (tp->pkbuf.tftpDATA.blocknum)); - break; - - case TFTP_OPCODE_ACK: - printf ("TFTP: GOT ACK %d\n", ntohs (tp->pkbuf.tftpACK.blocknum)); - break; - } - } - else { - printf ("TFTP: %d-byte packet\n", len); - } + if (retryCount != GET_PACKET_DONT_WAIT) { + tv.tv_sec = 0; + tv.tv_usec = 0; + setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); } -#endif return len; } +static int process_unexpected_packet (struct tftpStream *tp, ssize_t len) +{ + (void) len; + send_error ( + tp, + &tp->farAddress, + TFTP_ERROR_CODE_ILLEGAL, + "Got packet with unexpected opcode from server" + ); + return EPROTO; +} + +static int process_malformed_packet (struct tftpStream *tp, ssize_t len) +{ + (void) len; + send_error ( + tp, + &tp->farAddress, + TFTP_ERROR_CODE_ILLEGAL, + "Got malformed packet from server" + ); + return EPROTO; +} + +static int process_error_packet (struct tftpStream *tp, ssize_t len) +{ + (void) len; + return tftpErrno (tp->receive_buf->tftpERROR.errorCode); +} + /* - * Send an acknowledgement + * When an RRQ or a WRQ with options is sent and the server responds with + * an error, this function will trigger a re-sent of an RRQ or WRQ + * without options (falling back to old RFC1350). + * + * If someone wants to change the implementation to force using options + * (i.e. prevent fallback to RFC1350), at least these points must be + * considered: + * + * * Use `process_error_packet()` instead of + * `process_error_packet_option_negotiation()` + * * React to DATA and ACK packets, which are an immediate response to + * an RRQ or a WRQ with options, with an error packet. + * * Check the option values in the OACK whether they are in the + * desired range. */ -static int -sendAck (struct tftpStream *tp) +static int process_error_packet_option_negotiation ( + struct tftpStream *tp, ssize_t len +) { -#ifdef RTEMS_TFTP_DRIVER_DEBUG - if (rtems_tftp_driver_debug) - printf ("TFTP: ACK %d\n", tp->blocknum); -#endif - + (void) len; /* - * Create the acknowledgement + * Setting tp->config.options causes an RRQ or a WRQ to be created without + * options. + * Setting tp->server_option is defensive programming as these fields + * should already have these values. */ - tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK); - tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum); + tp->config.options.block_size = TFTP_RFC1350_BLOCK_SIZE; + tp->config.options.window_size = TFTP_RFC1350_WINDOW_SIZE; + tp->server_options.block_size = TFTP_RFC1350_BLOCK_SIZE; + tp->server_options.window_size = TFTP_RFC1350_WINDOW_SIZE; + tp->process_error_packet = process_error_packet; /* - * Send it + * GOT_FIRST_OUT_OF_ORDER_PACKET will trigger a re-send of the RRQ or WRQ. */ - if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0, - (struct sockaddr *)&tp->farAddress, - sizeof tp->farAddress) < 0) - return errno; - return 0; + return GOT_FIRST_OUT_OF_ORDER_PACKET; } -/* - * Convert a path to canonical form - */ -static void -fixPath (char *path) +static int process_data_packet (struct tftpStream *tp, ssize_t len) { - char *inp, *outp, *base; + ssize_t plen; + int32_t pkt_blocknum; + union tftpPacket *send_buf; - outp = inp = path; - base = NULL; - for (;;) { - if (inp[0] == '.') { - if (inp[1] == '\0') - break; - if (inp[1] == '/') { - inp += 2; - continue; - } - if (inp[1] == '.') { - if (inp[2] == '\0') { - if ((base != NULL) && (outp > base)) { - outp--; - while ((outp > base) && (outp[-1] != '/')) - outp--; - } - break; - } - if (inp[2] == '/') { - inp += 3; - if (base == NULL) - continue; - if (outp > base) { - outp--; - while ((outp > base) && (outp[-1] != '/')) - outp--; - } - continue; - } - } - } - if (base == NULL) - base = inp; - while (inp[0] != '/') { - if ((*outp++ = *inp++) == '\0') - return; - } - *outp++ = '/'; - while (inp[0] == '/') - inp++; + if (len < sizeof (tp->receive_buf->tftpACK)) { + return process_malformed_packet (tp, len); + } + pkt_blocknum = (int32_t) ntohs (tp->receive_buf->tftpACK.blocknum); + if (pkt_blocknum == 0) { + return process_malformed_packet (tp, len); + } + + /* + * In case of reading a file from the server: + * If the latest ACK packet(s) did not reach the server, the server + * starts the window from the last ACK it received. This if-clause + * ensures, the client sends an ACK after having seen `windowsize` + * packets. + */ + if (pkt_blocknum < tp->blocknum_of_first_packet_of_window && + pkt_blocknum >= (int32_t) tp->blocknum + 1 - + (int32_t) tp->server_options.window_size) { + tp->blocknum_of_first_packet_of_window = pkt_blocknum; + } + if (!tp->ignore_out_of_order_packets && + pkt_blocknum > (int32_t) tp->blocknum + 1) { + tp->ignore_out_of_order_packets = true; + return GOT_FIRST_OUT_OF_ORDER_PACKET; + } else if (pkt_blocknum == (int32_t) tp->blocknum) { + /* + * In case of reading a file from the server: + * If the last ACK packet send by the client did not reach the + * server, the server re-sends all packets of the window. In this + * case, the client must re-send the ACK packet after having + * received the last packet of the window (even through it has + * already received that packet before). + * GOT_OLD_PACKET would wrongly suppress this. + */ + return GOT_DUPLICATE_OF_CURRENT_PACKET; + } else if (pkt_blocknum != (int32_t) tp->blocknum + 1) { + return GOT_OLD_PACKET; } - *outp = '\0'; - return; + tp->ignore_out_of_order_packets = false; + + tp->blocknum++; + tp->nused = 0; /* Only for 2nd, 3rd, 4th DATA packet received */ + tp->nleft = BLK_SIZE_FROM_PKT_SIZE (len); + tp->at_eof = (tp->nleft < tp->server_options.block_size); + /* + * After the last DATA packet, the client must send a final ACK + */ + if (tp->at_eof) { + plen = prepare_ack_packet_for_sending (tp, true, &send_buf, NULL, NULL); + + /* + * Send it. Errors during send will not matter for this last ACK. + */ + sendto ( + tp->socket, + send_buf, + plen, + 0, + (struct sockaddr *) &tp->farAddress, + sizeof (tp->farAddress) + ); + } + tp->prepare_packet_for_sending = prepare_ack_packet_for_sending; + return GOT_EXPECTED_PACKET; } -static void rtems_tftp_eval_path(rtems_filesystem_eval_path_context_t *self) +static int process_ack_packet (struct tftpStream *tp, ssize_t len) { - int eval_flags = rtems_filesystem_eval_path_get_flags (self); - - if ((eval_flags & RTEMS_FS_MAKE) == 0) { - int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE; - - if ((eval_flags & rw) != rw) { - rtems_filesystem_location_info_t *currentloc = - rtems_filesystem_eval_path_get_currentloc (self); - char *current = currentloc->node_access; - size_t currentlen = strlen (current); - const char *path = rtems_filesystem_eval_path_get_path (self); - size_t pathlen = rtems_filesystem_eval_path_get_pathlen (self); - size_t len = currentlen + pathlen; - - rtems_filesystem_eval_path_clear_path (self); - - current = realloc (current, len + 1); - if (current != NULL) { - memcpy (current + currentlen, path, pathlen); - current [len] = '\0'; - if (!rtems_tftp_is_directory (current, len)) { - fixPath (current); - } - currentloc->node_access = current; - } else { - rtems_filesystem_eval_path_error (self, ENOMEM); - } - } else { - rtems_filesystem_eval_path_error (self, EINVAL); - } - } else { - rtems_filesystem_eval_path_error (self, EIO); + uint16_t blocknum_ack; + if (len < sizeof (tp->receive_buf->tftpACK)) { + return process_malformed_packet (tp, len); + } + blocknum_ack = ntohs (tp->receive_buf->tftpACK.blocknum); + if ((int32_t) blocknum_ack == tp->blocknum_of_first_packet_of_window - 1 && + blocknum_ack != 0 + ) { + tp->blocknum = tp->blocknum_of_first_packet_of_window; + return GOT_DUPLICATE_OF_CURRENT_PACKET; } + if ((int32_t) blocknum_ack < tp->blocknum_of_first_packet_of_window || + blocknum_ack > tp->blocknum_last_filled) { + return GOT_OLD_PACKET; + } + tp->blocknum = blocknum_ack + 1; + tp->blocknum_of_first_packet_of_window = (int32_t) tp->blocknum; + tp->prepare_packet_for_sending = prepare_data_packet_for_sending; + return GOT_EXPECTED_PACKET; } -/* - * The routine which does most of the work for the IMFS open handler - */ -static int rtems_tftp_open_worker( - rtems_libio_t *iop, - char *full_path_name, - int oflag +static ssize_t prepare_data_packet_for_sending ( + struct tftpStream *tp, + bool force_retransmission, + union tftpPacket **send_buf, + bool *wait_for_packet_reception, + const void *not_used ) { - tftpfs_info_t *fs; - struct tftpStream *tp; - int retryCount; - struct in_addr farAddress; - int s; - int len; - char *cp1; - char *cp2; - char *remoteFilename; - rtems_interval now; - char *hostname; + (void) not_used; + ssize_t len; + *send_buf = get_send_buffer_packet (tp, tp->blocknum); + + len = PKT_SIZE_FROM_BLK_SIZE ( + (tp->blocknum == tp->blocknum_eof_block) ? tp->nused : tp->block_size + ); + (*send_buf)->tftpDATA.opcode = htons (TFTP_OPCODE_DATA); + (*send_buf)->tftpDATA.blocknum = htons (tp->blocknum); /* - * Get the file system info. - */ - fs = tftpfs_info_iop (iop); - - /* - * Extract the host name component + * If the client sends the last packet of a window, + * it must wait for an ACK and - in case no ACK is received - begin + * a retransmission with the first packet of the window. + * Note that the last DATA block for the whole transfer is also + * a "last packet of a window". */ - if (*full_path_name == '/') - full_path_name++; - - hostname = full_path_name; - cp1 = strchr (full_path_name, ':'); - if (!cp1) { -#ifdef RTEMS_NETWORKING - hostname = "BOOTP_HOST"; -#endif + if ((int32_t) tp->blocknum + 1 >= + tp->blocknum_of_first_packet_of_window + tp->send_buf_size_in_pkts || + tp->blocknum == tp->blocknum_eof_block) { + tp->blocknum = (uint16_t) tp->blocknum_of_first_packet_of_window; } else { - *cp1 = '\0'; - ++cp1; + tp->blocknum++; + *wait_for_packet_reception = false; } + tp->process_data_packet = process_unexpected_packet; + tp->process_ack_packet = process_ack_packet; + tp->process_oack_packet = process_unexpected_packet; + tp->process_error_packet = process_error_packet; + /* - * Convert hostname to Internet address + * Our last packet won't necessarily be acknowledged! */ -#ifdef RTEMS_NETWORKING - if (strcmp (hostname, "BOOTP_HOST") == 0) - farAddress = rtems_bsdnet_bootp_server_address; - else -#endif - if (inet_aton (hostname, &farAddress) == 0) { - struct hostent *he = gethostbyname(hostname); - if (he == NULL) - return ENOENT; - memcpy (&farAddress, he->h_addr, sizeof (farAddress)); + if (tp->blocknum == tp->blocknum_eof_block) { + tp->retransmission_error_code = 0; } - - /* - * Extract file pathname component - */ -#ifdef RTEMS_NETWORKING - if (strcmp (cp1, "BOOTP_FILE") == 0) { - cp1 = rtems_bsdnet_bootp_boot_file_name; + + return len; +} + +static ssize_t prepare_ack_packet_for_sending ( + struct tftpStream *tp, + bool force_retransmission, + union tftpPacket **send_buf, + bool *wait_for_packet_reception, + const void *path_name +) +{ + (void) wait_for_packet_reception; + if (!force_retransmission && + tp->blocknum_of_first_packet_of_window - 1 + + (int32_t) tp->server_options.window_size > (int32_t) tp->blocknum) { + return DO_NOT_SEND_PACKET; } -#endif - if (*cp1 == '\0') - return ENOENT; - remoteFilename = cp1; - if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10)) - return ENOENT; + tp->blocknum_of_first_packet_of_window = (int32_t) tp->blocknum + 1; /* - * Find a free stream + * Create the acknowledgement */ - rtems_mutex_lock (&fs->tftp_mutex); - for (s = 0 ; s < fs->nStreams ; s++) { - if (fs->tftpStreams[s] == NULL) - break; + *send_buf = tp->send_buf; + (*send_buf)->tftpACK.opcode = htons (TFTP_OPCODE_ACK); + (*send_buf)->tftpACK.blocknum = htons (tp->blocknum); + + tp->process_data_packet = process_data_packet; + tp->process_ack_packet = process_unexpected_packet; + tp->process_oack_packet = process_unexpected_packet; + tp->process_error_packet = process_error_packet; + + return sizeof (tp->send_buf->tftpACK); +} + +static int process_oack_packet (struct tftpStream *tp, ssize_t len) +{ + if (!parse_options(tp->receive_buf, + len, + &tp->config.options, + &tp->server_options)) { + send_error ( + tp, + &tp->farAddress, + TFTP_ERROR_CODE_OPTION_NEGO, + "Bad options, option values or malformed OACK packet" + ); + return EPROTO; } - if (s == fs->nStreams) { + if (tp->is_for_reading) { /* - * Reallocate stream pointers - * Guard against the case where realloc() returns NULL. + * Since no DATA packet has been received yet, tell + * tftp_read() there is no data left. */ - struct tftpStream **np; + tp->nleft = 0; + tp->prepare_packet_for_sending = prepare_ack_packet_for_sending; + } else { + tp->blocknum_of_first_packet_of_window = 1; + tp->blocknum = (uint16_t) tp->blocknum_of_first_packet_of_window; + tp->prepare_packet_for_sending = prepare_data_packet_for_sending; + } + return GOT_EXPECTED_PACKET; +} + +static ssize_t prepare_request_packet_for_sending ( + struct tftpStream *tp, + bool force_retransmission, + union tftpPacket **send_buf, + bool *wait_for_packet_reception, + const void *path_name +) +{ + (void) wait_for_packet_reception; + ssize_t len; + *send_buf = tp->send_buf; + len = create_request ( + *send_buf, + tp->block_size, + tp->is_for_reading, + path_name, + &tp->config.options + ); + + if (len < 0) { + tp->error = ENAMETOOLONG; + } else { + tp->process_data_packet = tp->is_for_reading ? + process_data_packet : process_unexpected_packet; + tp->process_ack_packet = tp->is_for_reading ? + process_unexpected_packet : process_ack_packet; + tp->process_oack_packet = MUST_SEND_OPTIONS(tp->config.options) ? + process_oack_packet : process_unexpected_packet; + tp->process_error_packet = MUST_SEND_OPTIONS(tp->config.options) ? + process_error_packet_option_negotiation : process_error_packet; + } - np = realloc (fs->tftpStreams, ++fs->nStreams * sizeof *fs->tftpStreams); - if (np == NULL) { - rtems_mutex_unlock (&fs->tftp_mutex); - return ENOMEM; + /* + * getPacket() will change these values when the first packet is + * received. Yet, this first packet may be an unexpected one + * (e.g. an ERROR or having a wrong block number). + * If a second, third, forth, ... RRQ/WRQ is to be sent, it should + * be directed to the server port again and not to the port the + * first unexpected packet came from. + */ + tp->farAddress.sin_port = htons (tp->config.server_port); + tp->firstReply = 1; + + return len; +} + +/* + * Conduct one communication step with the server. For windowsize == 1, + * one step is: + * a) Send a packet to the server + * b) Receive a reply packet from the server + * c) Handle errors (if any) + * d) If no packet has been received from the server and the maximum + * retransmission count has not yet been reached, start over with a) + * The flow of packets (i.e. which packet to send and which packet(s) to + * expect from the server) is controlled by function pointers found in + * struct tftpStream. + * + * Besides of handling errors and retransmissions, the essential data exchange + * follows these patterns: + * + * Connection establishment and option negotiation: + * * Send RRQ/WRQ (read or write request packet) + * * Receive OACK (read and write) or ACK (write only) or DATA (read only) + * + * Read step with windowsize == 1: + * * Send ACK packet + * * Receive DATA packet + * Sending the very last ACK packet for a "read" session is treated as a + * special case. + * + * Write step with windowsize == 1: + * * Send DATA packet + * * Receive ACK packet + * + * A windowsize lager than one makes thinks more complicated. + * In this case, a step normally only receives (read) or only sends (write) + * a packet. The sending or receiving of the ACK packets is skipped normally + * and happens only at the last step of the window (in which case this last + * step is similar to the windowsize == 1 case): + * + * Normal read step with windowsize > 1: + * * Receive DATA packet + * Last read step of a window with windowsize > 1: + * * Send ACK packet + * * Receive DATA packet + * + * Normal write step with windowsize > 1: + * * Send DATA packet + * * Check for an ACK packet but do not wait for it + * Last write step of a window with windowsize > 1: + * * Send DATA packet + * * Receive ACK packet + * + * The "normal write step for windowsize > 1" checks whether an ACK packet + * has been received after each sending of a DATA packet. Package lost and + * exchanges in the network can give rise to situations in which the server + * sends more than a single ACK packet during a window. If these packets + * are not reacted on immediately, the network would be flooded with + * surplus packets. (An example where two ACK packets appear in a window + * appears in test case "read_file_windowsize_trouble" where the client/server + * roles are exchanged.) + */ +static int communicate_with_server ( + struct tftpStream *tp, + const void *create_packet_data +) +{ + ssize_t len; + uint16_t opcode; + union tftpPacket *send_buf; + bool received_duplicated_or_old_package = false; + bool force_retransmission = false; + bool wait_for_packet_reception; + int retryCount = 0; + while (tp->error == 0) { + + if (!received_duplicated_or_old_package) { + wait_for_packet_reception = true; + len = tp->prepare_packet_for_sending ( + tp, + force_retransmission, + &send_buf, + &wait_for_packet_reception, + create_packet_data + ); + if (len < 0) { + if (tp->error == 0) { + tp->error = EIO; + } + break; + } + + if (len != DO_NOT_SEND_PACKET) { + /* + * Send the packet + */ + if (sendto (tp->socket, send_buf, len, 0, + (struct sockaddr *)&tp->farAddress, + sizeof tp->farAddress) < 0) { + tp->error = EIO; + break; + } + } + } + received_duplicated_or_old_package = false; + force_retransmission = false; + + /* + * Get reply + */ + len = getPacket ( + tp, + wait_for_packet_reception ? retryCount : GET_PACKET_DONT_WAIT + ); + if (len >= (int) sizeof (tp->receive_buf->tftpDATA.opcode)) { + opcode = ntohs (tp->receive_buf->tftpDATA.opcode); + switch (opcode) { + case TFTP_OPCODE_DATA: + tp->error = tp->process_data_packet (tp, len); + break; + case TFTP_OPCODE_ACK: + tp->error = tp->process_ack_packet (tp, len); + break; + case TFTP_OPCODE_OACK: + tp->error = tp->process_oack_packet (tp, len); + break; + case TFTP_OPCODE_ERROR: + tp->error = tp->process_error_packet (tp, len); + break; + default: + tp->error = process_unexpected_packet (tp, len); + break; + } + if (tp->error == GOT_EXPECTED_PACKET) { + break; + } else if (tp->error == GOT_DUPLICATE_OF_CURRENT_PACKET) { + tp->error = 0; + } else if (tp->error == GOT_OLD_PACKET) { + received_duplicated_or_old_package = true; + tp->error = 0; + } else if (tp->error <= GOT_FIRST_OUT_OF_ORDER_PACKET) { + force_retransmission = true; + tp->error = 0; + } /* else ... tp->error > 0 means "exit this function with error" */ + } else if (len >= 0) { + tp->error = process_malformed_packet (tp, len); + } else if (len < 0 && !wait_for_packet_reception) { + tp->error = 0; + break; + } else { + /* + * Timeout or other problems to receive packets + * Attempt a retransmission + */ + if (++retryCount >= (int) tp->config.retransmissions) { + tp->error = tp->retransmission_error_code; + break; + } + force_retransmission = true; } - fs->tftpStreams = np; } - tp = fs->tftpStreams[s] = malloc (sizeof (struct tftpStream)); - rtems_mutex_unlock (&fs->tftp_mutex); - if (tp == NULL) - return ENOMEM; - iop->data0 = s; - iop->data1 = tp; + + return tp->error; +} + +/* + * Allocate and initialize an struct tftpStream object. + * + * This function does not check whether the config values are in valid ranges. + */ +static struct tftpStream *create_stream( + const tftp_net_config *config, + const struct in_addr *farAddress, + bool is_for_reading +) +{ + struct tftpStream *tp = NULL; + tp = malloc (sizeof (struct tftpStream)); + if (tp == NULL) { + return NULL; + } + + /* + * Initialize fields accessed by _Tftp_Destroy(). + */ + tp->receive_buf = NULL; + tp->send_buf = NULL; + tp->socket = 0; + + /* + * Allocate send and receive buffer for exchange of RRQ/WRQ and ACK/OACK. + */ + tp->block_size = TFTP_RFC1350_BLOCK_SIZE; + tp->packet_size = PKT_SIZE_FROM_BLK_SIZE (tp->block_size); + tp->receive_buf = malloc (tp->packet_size); + if (tp->receive_buf == NULL) { + _Tftp_Destroy (tp); + return NULL; + } + tp->send_buf = tp->receive_buf; + tp->send_buf_size_in_pkts = 1; /* * Create the socket */ if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { - releaseStream (fs, s); - return ENOMEM; + _Tftp_Destroy (tp); + return NULL; } /* - * Bind the socket to a local address + * Setup configuration and options */ - retryCount = 0; - now = rtems_clock_get_ticks_since_boot(); - for (;;) { - int try = (now + retryCount) % 10; - - tp->myAddress.sin_family = AF_INET; - tp->myAddress.sin_port = htons (UDP_PORT_BASE + fs->nStreams * try + s); - tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY); - if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0) - break; - if (++retryCount == 10) { - releaseStream (fs, s); - return EBUSY; - } + if ( config == NULL ) { + tftp_initialize_net_config (&tp->config); + } else { + tp->config = *config; } /* + * If the server does not confirm our option values later on, + * use numbers from the original RFC 1350 for the actual transfer. + */ + tp->server_options.block_size = TFTP_RFC1350_BLOCK_SIZE; + tp->server_options.window_size = TFTP_RFC1350_WINDOW_SIZE; + + /* * Set the UDP destination to the TFTP server * port on the remote machine. */ - tp->farAddress.sin_family = AF_INET; - tp->farAddress.sin_addr = farAddress; - tp->farAddress.sin_port = htons (69); + tp->farAddress.sin_family = AF_INET; + tp->farAddress.sin_addr = *farAddress; + tp->farAddress.sin_port = htons (tp->config.server_port); + + tp->nleft = 0; + tp->nused = 0; + tp->blocknum = 0; + tp->blocknum_last_filled = 0; + tp->blocknum_eof_block = UINT16_MAX; + tp->firstReply = 1; + tp->at_eof = false; + tp->is_for_reading = is_for_reading; + + tp->prepare_packet_for_sending = prepare_request_packet_for_sending; + tp->process_data_packet = process_unexpected_packet; + tp->process_ack_packet = process_unexpected_packet; + tp->process_oack_packet = process_unexpected_packet; + tp->process_error_packet = process_error_packet; + tp->retransmission_error_code = EIO; + tp->ignore_out_of_order_packets = false; + tp->blocknum_of_first_packet_of_window = INT32_MIN; + tp->error = 0; + + return tp; +} +/* + * Change the size of the receive and send buffer to match the options + * values acknowledged by the server. + */ +static struct tftpStream *reallocate_stream_buffer(struct tftpStream *tp) +{ + tp->block_size = tp->server_options.block_size; + tp->packet_size = PKT_SIZE_FROM_BLK_SIZE (tp->block_size); /* - * Start the transfer + * Defensive programming */ - tp->firstReply = 1; - retryCount = 0; - for (;;) { - /* - * Create the request - */ - if ((oflag & O_ACCMODE) == O_RDONLY) { - tp->writing = 0; - tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ); - } - else { - tp->writing = 1; - tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_WRQ); - } - cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode; - cp2 = (char *) remoteFilename; - while ((*cp1++ = *cp2++) != '\0') - continue; - cp2 = "octet"; - while ((*cp1++ = *cp2++) != '\0') - continue; - len = cp1 - (char *)&tp->pkbuf.tftpRWRQ; + if (tp->receive_buf == tp->send_buf) { + tp->send_buf = NULL; + } else { + free (tp->send_buf); + } - /* - * Send the request - */ - if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0, - (struct sockaddr *)&tp->farAddress, - sizeof tp->farAddress) < 0) { - releaseStream (fs, s); - return EIO; - } + tp->receive_buf = realloc (tp->receive_buf, tp->packet_size); + if (tp->is_for_reading) { + tp->send_buf = tp->receive_buf; + } else { + tp->send_buf_size_in_pkts = tp->server_options.window_size; + tp->send_buf = malloc ( + tp->send_buf_size_in_pkts * tp->packet_size + ); + } - /* - * Get reply - */ - len = getPacket (tp, retryCount); - if (len >= (int) sizeof tp->pkbuf.tftpACK) { - int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); - if (!tp->writing - && (opcode == TFTP_OPCODE_DATA) - && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) { - tp->nused = 0; - tp->blocknum = 1; - tp->nleft = len - 2 * sizeof (uint16_t ); - tp->eof = (tp->nleft < TFTP_BUFSIZE); - if (sendAck (tp) != 0) { - releaseStream (fs, s); - return EIO; - } - break; - } - if (tp->writing - && (opcode == TFTP_OPCODE_ACK) - && (ntohs (tp->pkbuf.tftpACK.blocknum) == 0)) { - tp->nused = 0; - tp->blocknum = 1; - break; - } - if (opcode == TFTP_OPCODE_ERROR) { - int e = tftpErrno (tp); - releaseStream (fs, s); - return e; - } - } + if (tp->receive_buf == NULL || tp->send_buf == NULL) { + sendStifle (tp, &tp->farAddress); + _Tftp_Destroy (tp); + return NULL; + } + return tp; +} - /* - * Keep trying - */ - if (++retryCount >= OPEN_RETRY_LIMIT) { - releaseStream (fs, s); - return EIO; +/* + * Convert hostname to an Internet address + */ +static struct in_addr *get_ip_address( + const char *hostname, + struct in_addr *farAddress +) +{ + struct hostent *he = gethostbyname(hostname); + if (he == NULL) { + return NULL; } + memcpy (farAddress, he->h_addr, sizeof (*farAddress)); + return farAddress; +} + +void tftp_initialize_net_config (tftp_net_config *config) +{ + static const tftp_net_config default_config = { + .retransmissions = TFTP_RFC7440_DATA_RETRANSMISSIONS, + .server_port = TFTP_DEFAULT_SERVER_PORT, + .timeout = TFTP_RFC7440_TIMEOUT_MILLISECONDS, + .first_timeout = PACKET_FIRST_TIMEOUT_MILLISECONDS, + .options = { + .block_size = TFTP_DEFAULT_BLOCK_SIZE, + .window_size = TFTP_DEFAULT_WINDOW_SIZE } - return 0; + }; + + if (config != NULL) { + memcpy (config, &default_config, sizeof (default_config)); + } } -static int rtems_tftp_open( - rtems_libio_t *iop, - const char *new_name, - int oflag, - mode_t mode +int tftp_open( + const char *hostname, + const char *path, + bool is_for_reading, + const tftp_net_config *config, + void **tftp_handle ) { - tftpfs_info_t *fs; - char *full_path_name; - int err; - - full_path_name = iop->pathinfo.node_access; + struct tftpStream *tp; + struct in_addr farAddress; + int err; - if (rtems_tftp_is_directory (full_path_name, strlen (full_path_name))) { - rtems_set_errno_and_return_minus_one (ENOTSUP); + /* + * Check parameters + */ + if (tftp_handle == NULL) { + return EINVAL; + } + *tftp_handle = NULL; + if (hostname == NULL || path == NULL) { + return EINVAL; + } + if (config != NULL && ( + config->options.window_size < TFTP_WINDOW_SIZE_MIN || + config->options.block_size < TFTP_BLOCK_SIZE_MIN || + config->options.block_size > TFTP_BLOCK_SIZE_MAX ) ) { + return EINVAL; } /* - * Get the file system info. + * Create tftpStream structure */ - fs = tftpfs_info_iop (iop); + if (get_ip_address( hostname, &farAddress ) == NULL) { + return ENOENT; + } + tp = create_stream( config, &farAddress, is_for_reading ); + if (tp == NULL) { + return ENOMEM; + } - if (fs->flags & TFTPFS_VERBOSE) - printf ("TFTPFS: %s\n", full_path_name); + /* + * Send RRQ or WRQ and wait for reply + */ + tp->prepare_packet_for_sending = prepare_request_packet_for_sending; + err = communicate_with_server (tp, path); + if ( err != 0 ) { + _Tftp_Destroy (tp); + return err; + } - err = rtems_tftp_open_worker (iop, full_path_name, oflag); - if (err != 0) { - rtems_set_errno_and_return_minus_one (err); + *tftp_handle = reallocate_stream_buffer ( tp ); + if( *tftp_handle == NULL ) { + return ENOMEM; } return 0; @@ -790,20 +1296,20 @@ static int rtems_tftp_open( /* * Read from a TFTP stream */ -static ssize_t rtems_tftp_read( - rtems_libio_t *iop, +ssize_t tftp_read( + void *tftp_handle, void *buffer, size_t count ) { char *bp; - struct tftpStream *tp = iop->data1; - int retryCount; + struct tftpStream *tp = tftp_handle; int nwant; + int err; + + if (tp == NULL || !tp->is_for_reading || buffer == NULL) + return -EIO; - if (!tp) - rtems_set_errno_and_return_minus_one( EIO ); - /* * Read till user request is satisfied or EOF is reached */ @@ -816,7 +1322,7 @@ static ssize_t rtems_tftp_read( ncopy = nwant; else ncopy = tp->nleft; - memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy); + memcpy (bp, &tp->receive_buf->tftpDATA.data[tp->nused], ncopy); tp->nused += ncopy; tp->nleft -= ncopy; bp += ncopy; @@ -824,39 +1330,29 @@ static ssize_t rtems_tftp_read( if (nwant == 0) break; } - if (tp->eof) + if (tp->at_eof) { break; + } /* * Wait for the next packet */ - retryCount = 0; - for (;;) { - int len = getPacket (tp, retryCount); - if (len >= (int)sizeof tp->pkbuf.tftpACK) { - int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); - uint16_t nextBlock = tp->blocknum + 1; - if ((opcode == TFTP_OPCODE_DATA) - && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) { - tp->nused = 0; - tp->nleft = len - 2 * sizeof (uint16_t); - tp->eof = (tp->nleft < TFTP_BUFSIZE); - tp->blocknum++; - if (sendAck (tp) != 0) - rtems_set_errno_and_return_minus_one (EIO); - break; - } - if (opcode == TFTP_OPCODE_ERROR) - rtems_set_errno_and_return_minus_one (tftpErrno (tp)); - } - - /* - * Keep trying? - */ - if (++retryCount == IO_RETRY_LIMIT) - rtems_set_errno_and_return_minus_one (EIO); - if (sendAck (tp) != 0) - rtems_set_errno_and_return_minus_one (EIO); + tp->retransmission_error_code = -EIO; + err = communicate_with_server(tp, NULL); + if (err == tp->retransmission_error_code) { + return -EIO; + } + /* + * If communicate_with_server() returns an error, either + * * an error message from the server was received or + * * an error message was already sent to the server + * Setting tp->at_eof true, prevents all further calls to + * communicate_with_server() and suppresses the sending of + * an error message to the server by tftp_close(). + */ + if (err != 0) { + tp->at_eof = true; + return -err; } } return count - nwant; @@ -864,101 +1360,110 @@ static ssize_t rtems_tftp_read( /* * Flush a write buffer and wait for acknowledgement + * + * This function returns only if there is at least one packet buffer free + * in the tp->send_buf. This ensures that tftp_write() can store + * further data for sending in this free packet buffer. + * + * When the end of file has been reached (i.e. tftp_close() called this + * function), this function returns only after all packets + * in the write buffer have been send and acknowledged (or if an error + * occurred). */ static int rtems_tftp_flush (struct tftpStream *tp) { - int wlen, rlen; - int retryCount = 0; + int err; - wlen = tp->nused + 2 * sizeof (uint16_t ); - for (;;) { - tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA); - tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum); -#ifdef RTEMS_TFTP_DRIVER_DEBUG - if (rtems_tftp_driver_debug) - printf ("TFTP: SEND %d (%d)\n", tp->blocknum, tp->nused); -#endif - if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0, - (struct sockaddr *)&tp->farAddress, - sizeof tp->farAddress) < 0) - return EIO; - rlen = getPacket (tp, retryCount); + if (tp->at_eof) { + return 0; + } + + do { + err = communicate_with_server(tp, NULL); /* - * Our last packet won't necessarily be acknowledged! + * If communicate_with_server() returns an error, either + * * an error message from the server was received or + * * an error message was already sent to the server + * Setting tp->at_eof true, prevents all further calls to + * communicate_with_server() and suppresses the sending of + * an error message to the server by tftp_close(). */ - if ((rlen < 0) && (tp->nused < sizeof tp->pkbuf.tftpDATA.data)) - return 0; - if (rlen >= (int)sizeof tp->pkbuf.tftpACK) { - int opcode = ntohs (tp->pkbuf.tftpACK.opcode); - if ((opcode == TFTP_OPCODE_ACK) - && (ntohs (tp->pkbuf.tftpACK.blocknum) == tp->blocknum)) { - tp->nused = 0; - tp->blocknum++; - return 0; - } - if (opcode == TFTP_OPCODE_ERROR) - return tftpErrno (tp); + if (err != 0) { + tp->at_eof = true; + return err; } + } while( + (int32_t) tp->blocknum_last_filled + 1 >= + tp->blocknum_of_first_packet_of_window + tp->send_buf_size_in_pkts || + /* + * tp->blocknum_eof_block == tp->blocknum_last_filled + * holds only true when the user invoked tftp_close(). + */ + (tp->blocknum_eof_block == tp->blocknum_last_filled && + tp->blocknum_of_first_packet_of_window <= + (int32_t) tp->blocknum_eof_block) + ); - /* - * Keep trying? - */ - if (++retryCount == IO_RETRY_LIMIT) - return EIO; - } + return 0; } /* * Close a TFTP stream */ -static int rtems_tftp_close( - rtems_libio_t *iop +int tftp_close( + void *tftp_handle ) { - tftpfs_info_t *fs; - struct tftpStream *tp = iop->data1; + struct tftpStream *tp = tftp_handle; int e = 0; - - /* - * Get the file system info. - */ - fs = tftpfs_info_iop (iop); - - if (!tp) - rtems_set_errno_and_return_minus_one (EIO); - - if (tp->writing) + + if (tp == NULL) { + return 0; + } + + if (!tp->is_for_reading) { + tp->blocknum_last_filled++; + tp->blocknum_eof_block = tp->blocknum_last_filled; e = rtems_tftp_flush (tp); - if (!tp->eof && !tp->firstReply) { + tp->at_eof = true; + } + if (!tp->at_eof && !tp->firstReply) { /* * Tell the other end to stop */ rtems_interval ticksPerSecond; - sendStifle (tp, &tp->farAddress); + send_error ( + tp, + &tp->farAddress, + TFTP_ERROR_CODE_NO_USER, + "User (client) stopped reading or " + "server stopped sending packets (timeout)" + ); ticksPerSecond = rtems_clock_get_ticks_per_second(); rtems_task_wake_after (1 + ticksPerSecond / 10); } - releaseStream (fs, iop->data0); - if (e) - rtems_set_errno_and_return_minus_one (e); - return 0; + _Tftp_Destroy (tp); + return e; } -static ssize_t rtems_tftp_write( - rtems_libio_t *iop, +ssize_t tftp_write( + void *tftp_handle, const void *buffer, size_t count ) { const char *bp; - struct tftpStream *tp = iop->data1; + struct tftpStream *tp = tftp_handle; int nleft, nfree, ncopy; + int err; + union tftpPacket *send_buf; /* * Bail out if an error has occurred */ - if (!tp->writing) - rtems_set_errno_and_return_minus_one (EIO); + if (tp == NULL || tp->is_for_reading || tp->at_eof || buffer == NULL) { + return -EIO; + } /* * Write till user request is satisfied @@ -970,119 +1475,45 @@ static ssize_t rtems_tftp_write( bp = buffer; nleft = count; while (nleft) { - nfree = sizeof tp->pkbuf.tftpDATA.data - tp->nused; + nfree = tp->block_size - tp->nused; if (nleft < nfree) ncopy = nleft; else ncopy = nfree; - memcpy (&tp->pkbuf.tftpDATA.data[tp->nused], bp, ncopy); + send_buf = get_send_buffer_packet (tp, tp->blocknum_last_filled + 1); + memcpy (&send_buf->tftpDATA.data[tp->nused], bp, ncopy); tp->nused += ncopy; nleft -= ncopy; bp += ncopy; - if (tp->nused == sizeof tp->pkbuf.tftpDATA.data) { - int e = rtems_tftp_flush (tp); - if (e) { - tp->writing = 0; - rtems_set_errno_and_return_minus_one (e); + if (tp->nused == tp->block_size) { + tp->blocknum_last_filled++; + err = rtems_tftp_flush (tp); + if (err) { + return -err; } + tp->nused = 0; } } return count; } -/* - * Dummy version to let fopen(xxxx,"w") work properly. - */ -static int rtems_tftp_ftruncate( - rtems_libio_t *iop RTEMS_UNUSED, - off_t count RTEMS_UNUSED +void _Tftp_Destroy( + void *tftp_handle ) { - return 0; -} - -static int rtems_tftp_fstat( - const rtems_filesystem_location_info_t *loc, - struct stat *buf -) -{ - const char *path = loc->node_access; - size_t pathlen = strlen (path); - - buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO - | (rtems_tftp_is_directory (path, pathlen) ? S_IFDIR : S_IFREG); - - return 0; -} - -static int rtems_tftp_clone( - rtems_filesystem_location_info_t *loc -) -{ - int rv = 0; - - loc->node_access = strdup (loc->node_access); - - if (loc->node_access == NULL) { - errno = ENOMEM; - rv = -1; + struct tftpStream *tp = tftp_handle; + if (tp == NULL) { + return; } - return rv; -} - -static void rtems_tftp_free_node_info( - const rtems_filesystem_location_info_t *loc -) -{ - free (loc->node_access); -} + if (tp->socket >= 0) { + close (tp->socket); + } -static bool rtems_tftp_are_nodes_equal( - const rtems_filesystem_location_info_t *a, - const rtems_filesystem_location_info_t *b -) -{ - return strcmp (a->node_access, b->node_access) == 0; + if (tp->receive_buf == tp->send_buf) { + tp->send_buf = NULL; + } + free (tp->receive_buf); + free (tp->send_buf); + free (tp); } - -static const rtems_filesystem_operations_table rtems_tftp_ops = { - .lock_h = rtems_filesystem_default_lock, - .unlock_h = rtems_filesystem_default_unlock, - .eval_path_h = rtems_tftp_eval_path, - .link_h = rtems_filesystem_default_link, - .are_nodes_equal_h = rtems_tftp_are_nodes_equal, - .mknod_h = rtems_filesystem_default_mknod, - .rmnod_h = rtems_filesystem_default_rmnod, - .fchmod_h = rtems_filesystem_default_fchmod, - .chown_h = rtems_filesystem_default_chown, - .clonenod_h = rtems_tftp_clone, - .freenod_h = rtems_tftp_free_node_info, - .mount_h = rtems_filesystem_default_mount, - .unmount_h = rtems_filesystem_default_unmount, - .fsunmount_me_h = rtems_tftpfs_shutdown, - .utimens_h = rtems_filesystem_default_utimens, - .symlink_h = rtems_filesystem_default_symlink, - .readlink_h = rtems_filesystem_default_readlink, - .rename_h = rtems_filesystem_default_rename, - .statvfs_h = rtems_filesystem_default_statvfs -}; - -static const rtems_filesystem_file_handlers_r rtems_tftp_handlers = { - .open_h = rtems_tftp_open, - .close_h = rtems_tftp_close, - .read_h = rtems_tftp_read, - .write_h = rtems_tftp_write, - .ioctl_h = rtems_filesystem_default_ioctl, - .lseek_h = rtems_filesystem_default_lseek, - .fstat_h = rtems_tftp_fstat, - .ftruncate_h = rtems_tftp_ftruncate, - .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, - .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, - .fcntl_h = rtems_filesystem_default_fcntl, - .kqfilter_h = rtems_filesystem_default_kqfilter, - .mmap_h = rtems_filesystem_default_mmap, - .poll_h = rtems_filesystem_default_poll, - .readv_h = rtems_filesystem_default_readv, - .writev_h = rtems_filesystem_default_writev -}; diff --git a/cpukit/libfs/src/ftpfs/tftp_driver.h b/cpukit/libfs/src/ftpfs/tftp_driver.h new file mode 100644 index 0000000000..949bea1820 --- /dev/null +++ b/cpukit/libfs/src/ftpfs/tftp_driver.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSImplTFTPFS + * + * @brief This header file provides private interfaces of the + * TFTP client library. + * + * This file declares the private functions of the Trivial File + * Transfer Protocol (TFTP) client library. + */ + +/* + * Copyright (C) 2022 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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. + */ + +#ifndef _TFTP_DRIVER_H +#define _TFTP_DRIVER_H + +/* Remove for C++ code */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup RTEMSImplTFTPFS Trivial File Transfer Protocol (TFTP) file system + * + * @ingroup FileSystemTypesAndMount + * + * @brief The TFTP file system provides the ability to read files from and + * to write files to remote servers using the Trivial File Transfer + * Protocol (TFTP). + * + * The file `spec/build/cpukit/libtftpfs.yml` specifies how the RTEMS + * WAF build system has to compile, link and install `libtftpfs`. + * + * There also exists a @ref RTEMSTestSuiteTestsTFTPFS + * "TFTP file system test suite". + * + * @{ + */ + +/** + * @brief Free the resources associated with a TFTP client connection. + * + * This directive releases any resources allocated at the client side. + * The connection is not closed which implies that the server will not + * be informed and data is likely lost. According to RFC 1350 the + * server will recognize the defect connection by timeouts. + * This directive is internally used when the TFTP file system is unmounted. + * + * @param tftp_handle is the reference returned by a call to tftp_open(). + * If this parameter is @c NULL, the directive call is a no-op. + */ +void _Tftp_Destroy( + void *tftp_handle +); + +/* Only non-private to ease unit testing */ +ssize_t _Tftpfs_Parse_options( + const char *option_str, + tftp_net_config *tftp_config, + uint32_t *flags +); + +/** @} */ + +/* Remove for C++ code */ +#ifdef __cplusplus +} +#endif + +#endif /* _TFTP_DRIVER_H */ diff --git a/cpukit/libfs/src/ftpfs/tftpfs.c b/cpukit/libfs/src/ftpfs/tftpfs.c new file mode 100644 index 0000000000..b699694117 --- /dev/null +++ b/cpukit/libfs/src/ftpfs/tftpfs.c @@ -0,0 +1,615 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSImplTFTPFS + * + * @brief This source file contains the implementation of + * the Trivial File Transfer Protocol (TFTP) file system. + * + * The code in this file handles the file system operations (such as + * `mount()`, `open()`, `read()`, `write()`, `close()` etc.). + * The networking part, i.e. the actual Trivial File Transfer Protocol + * implementation, is realized in another file - the + * @ref tftpDriver.c "TFTP client library". + */ + +/* + * Copyright (C) 1998 W. Eric Norum <eric@norum.ca> + * Copyright (C) 2012, 2022 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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 <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <malloc.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <rtems.h> +#include <rtems/libio_.h> +#include <rtems/seterr.h> +#include <rtems/tftp.h> +#include <rtems/thread.h> + +#include "tftp_driver.h" + +/* + * Flags for filesystem info. + */ +#define TFTPFS_VERBOSE (1 << 0) + +/* + * TFTP File system info. + */ +typedef struct tftpfs_info_s { + uint32_t flags; + rtems_mutex tftp_mutex; + size_t nStreams; + void ** volatile tftpStreams; + tftp_net_config tftp_config; +} tftpfs_info_t; + +#define tftpfs_info_mount_table(_mt) ((tftpfs_info_t*) ((_mt)->fs_info)) +#define tftpfs_info_pathloc(_pl) ((tftpfs_info_t*) ((_pl)->mt_entry->fs_info)) +#define tftpfs_info_iop(_iop) (tftpfs_info_pathloc (&((_iop)->pathinfo))) + +/* Forward declarations */ +static const rtems_filesystem_operations_table rtems_tftp_ops; +static const rtems_filesystem_file_handlers_r rtems_tftp_handlers; + +static bool rtems_tftp_is_directory( + const char *path, + size_t pathlen +) +{ + return path [pathlen - 1] == '/'; +} + +/* + * Return value: + * 0 if options have been pracessed without error + * N+1 if parsing failed at position N + */ +ssize_t _Tftpfs_Parse_options( + const char *option_str, + tftp_net_config *tftp_config, + uint32_t *flags +) +{ + const char *cur_pos = option_str; + size_t verbose_len = strlen ("verbose"); + size_t rfc1350_len = strlen ("rfc1350"); + int len; + + while(cur_pos != NULL && *cur_pos != '\0') { + if (strncmp (cur_pos, "verbose", verbose_len) == 0) { + *flags |= TFTPFS_VERBOSE; + len = (int) verbose_len; + } else if (strncmp (cur_pos, "rfc1350", rfc1350_len) == 0) { + tftp_config->options.block_size = TFTP_RFC1350_BLOCK_SIZE; + tftp_config->options.window_size = TFTP_RFC1350_WINDOW_SIZE; + len = (int) rfc1350_len; + } else if (sscanf( + cur_pos, + "blocksize=%"SCNu16"%n", + &tftp_config->options.block_size, + &len + ) == 1) { + } else if (sscanf( + cur_pos, + "windowsize=%"SCNu16"%n", + &tftp_config->options.window_size, + &len + ) == 1) { + } else if (*cur_pos == ',') { /* skip surplus "," */ + len = 0; + } else { + return cur_pos - option_str + 1; + } + + cur_pos += len; + if (*cur_pos != ',' && *cur_pos != '\0') { + return cur_pos - option_str + 1; + } + if (*cur_pos == ',') { + cur_pos++; + } + } + + return 0; +} + +int rtems_tftpfs_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +) +{ + const char *device = mt_entry->dev; + size_t devicelen = strlen (device); + tftpfs_info_t *fs = NULL; + char *root_path; + size_t err_pos; + int errno_store = ENOMEM; + + if (devicelen == 0) { + root_path = malloc (1); + if (root_path == NULL) + goto error; + root_path [0] = '\0'; + } + else { + root_path = malloc (devicelen + 2); + if (root_path == NULL) + goto error; + + root_path = memcpy (root_path, device, devicelen); + root_path [devicelen] = '/'; + root_path [devicelen + 1] = '\0'; + } + + fs = malloc (sizeof (*fs)); + if (fs == NULL) + goto error; + fs->flags = 0; + fs->nStreams = 0; + fs->tftpStreams = 0; + + tftp_initialize_net_config (&fs->tftp_config); + err_pos = _Tftpfs_Parse_options (data, &fs->tftp_config, &fs->flags); + if (err_pos != 0) { + printf( + "TFTP FS: ERROR in mount options '%s'.\n" + "TFTP FS: Cannot parse from this point: '%s'\n", + ((char *) data), + ((char *) data) + (err_pos - 1) + ); + errno_store = EINVAL; + goto error; + } + + mt_entry->fs_info = fs; + mt_entry->mt_fs_root->location.node_access = root_path; + mt_entry->mt_fs_root->location.handlers = &rtems_tftp_handlers; + mt_entry->ops = &rtems_tftp_ops; + + /* + * Now allocate a semaphore for mutual exclusion. + * + * NOTE: This could be in an fsinfo for this filesystem type. + */ + + rtems_mutex_init (&fs->tftp_mutex, "TFTPFS"); + + return 0; + +error: + + free (fs); + free (root_path); + + rtems_set_errno_and_return_minus_one (errno_store); +} + +/* + * Clear the pointer to a stream + */ +static void +releaseStream (tftpfs_info_t *fs, size_t s) +{ + rtems_mutex_lock (&fs->tftp_mutex); + fs->tftpStreams[s] = NULL; + rtems_mutex_unlock (&fs->tftp_mutex); +} + +static void +rtems_tftpfs_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry) +{ + tftpfs_info_t *fs = tftpfs_info_mount_table (mt_entry); + size_t s; + void *tp; + for (s = 0; s < fs->nStreams; s++) { + tp = fs->tftpStreams[s]; + releaseStream (fs, s); + _Tftp_Destroy(tp); + } + rtems_mutex_destroy (&fs->tftp_mutex); + free (fs); + free (mt_entry->mt_fs_root->location.node_access); +} + +/* + * Convert a path to canonical form + */ +static void +fixPath (char *path) +{ + char *inp, *outp, *base; + + outp = inp = path; + base = NULL; + for (;;) { + if (inp[0] == '.') { + if (inp[1] == '\0') + break; + if (inp[1] == '/') { + inp += 2; + continue; + } + if (inp[1] == '.') { + if (inp[2] == '\0') { + if ((base != NULL) && (outp > base)) { + outp--; + while ((outp > base) && (outp[-1] != '/')) + outp--; + } + break; + } + if (inp[2] == '/') { + inp += 3; + if (base == NULL) + continue; + if (outp > base) { + outp--; + while ((outp > base) && (outp[-1] != '/')) + outp--; + } + continue; + } + } + } + if (base == NULL) + base = inp; + while (inp[0] != '/') { + if ((*outp++ = *inp++) == '\0') + return; + } + *outp++ = '/'; + while (inp[0] == '/') + inp++; + } + *outp = '\0'; + return; +} + +static void rtems_tftp_eval_path(rtems_filesystem_eval_path_context_t *self) +{ + int eval_flags = rtems_filesystem_eval_path_get_flags (self); + + if ((eval_flags & RTEMS_FS_MAKE) == 0) { + int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE; + + if ((eval_flags & rw) != rw) { + rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_get_currentloc (self); + char *current = currentloc->node_access; + size_t currentlen = strlen (current); + const char *path = rtems_filesystem_eval_path_get_path (self); + size_t pathlen = rtems_filesystem_eval_path_get_pathlen (self); + size_t len = currentlen + pathlen; + + rtems_filesystem_eval_path_clear_path (self); + + current = realloc (current, len + 1); + if (current != NULL) { + memcpy (current + currentlen, path, pathlen); + current [len] = '\0'; + if (!rtems_tftp_is_directory (current, len)) { + fixPath (current); + } + currentloc->node_access = current; + } else { + rtems_filesystem_eval_path_error (self, ENOMEM); + } + } else { + rtems_filesystem_eval_path_error (self, EINVAL); + } + } else { + rtems_filesystem_eval_path_error (self, EIO); + } +} + +/* + * The routine which does most of the work for the IMFS open handler + */ +static int rtems_tftp_open_worker( + rtems_libio_t *iop, + char *full_path_name, + int oflag +) +{ + tftpfs_info_t *fs; + void *tp; + size_t s; + char *cp1; + char *remoteFilename; + char *hostname; + int err; + + /* + * Get the file system info. + */ + fs = tftpfs_info_iop (iop); + + /* + * Extract the host name component + */ + if (*full_path_name == '/') + full_path_name++; + + hostname = full_path_name; + cp1 = strchr (full_path_name, ':'); + if (!cp1) { + return EINVAL; /* No ':' in path: no hostname or no filename */ + } else { + *cp1 = '\0'; + ++cp1; + } + + /* + * Extract file pathname component + */ + if (*cp1 == '\0') + return ENOENT; + remoteFilename = cp1; + + /* + * Establish the connection + */ + err = tftp_open ( + hostname, + remoteFilename, + (oflag & O_ACCMODE) == O_RDONLY, + &fs->tftp_config, + &tp + ); + if (err != 0) { + return err; + } + + /* + * Find a free stream + */ + rtems_mutex_lock (&fs->tftp_mutex); + for (s = 0 ; s < fs->nStreams ; s++) { + if (fs->tftpStreams[s] == NULL) + break; + } + if (s == fs->nStreams) { + /* + * Reallocate stream pointers + * Guard against the case where realloc() returns NULL. + */ + void **np; + + np = realloc (fs->tftpStreams, ++fs->nStreams * sizeof *fs->tftpStreams); + if (np == NULL) { + rtems_mutex_unlock (&fs->tftp_mutex); + tftp_close( tp ); + return ENOMEM; + } + fs->tftpStreams = np; + } + fs->tftpStreams[s] = tp; + rtems_mutex_unlock (&fs->tftp_mutex); + iop->data0 = s; + iop->data1 = tp; + + return 0; +} + +static int rtems_tftp_open( + rtems_libio_t *iop, + const char *new_name, + int oflag, + mode_t mode +) +{ + tftpfs_info_t *fs; + char *full_path_name; + int err; + + full_path_name = iop->pathinfo.node_access; + + if (rtems_tftp_is_directory (full_path_name, strlen (full_path_name))) { + rtems_set_errno_and_return_minus_one (ENOTSUP); + } + + /* + * Get the file system info. + */ + fs = tftpfs_info_iop (iop); + + if (fs->flags & TFTPFS_VERBOSE) + printf ("TFTPFS: %s\n", full_path_name); + + err = rtems_tftp_open_worker (iop, full_path_name, oflag); + if (err != 0) { + rtems_set_errno_and_return_minus_one (err); + } + + return 0; +} + +/* + * Read from a TFTP stream + */ +static ssize_t rtems_tftp_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + void *tp = iop->data1; + ssize_t result = tftp_read (tp, buffer, count); + + if (result < 0) { + rtems_set_errno_and_return_minus_one (-result); + } + return result; +} + +/* + * Close a TFTP stream + */ +static int rtems_tftp_close( + rtems_libio_t *iop +) +{ + tftpfs_info_t *fs; + void *tp = iop->data1; + int e = 0; + + /* + * Get the file system info. + */ + fs = tftpfs_info_iop (iop); + + if (!tp) + rtems_set_errno_and_return_minus_one (EIO); + + releaseStream (fs, iop->data0); + e = tftp_close (tp); + if (e) + rtems_set_errno_and_return_minus_one (e); + return 0; +} + +static ssize_t rtems_tftp_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + void *tp = iop->data1; + ssize_t result = tftp_write (tp, buffer, count); + + if (result < 0) { + rtems_set_errno_and_return_minus_one (-result); + } + return result; +} + +/* + * Dummy version to let fopen(xxxx,"w") work properly. + */ +static int rtems_tftp_ftruncate( + rtems_libio_t *iop RTEMS_UNUSED, + off_t count RTEMS_UNUSED +) +{ + return 0; +} + +static int rtems_tftp_fstat( + const rtems_filesystem_location_info_t *loc, + struct stat *buf +) +{ + const char *path = loc->node_access; + size_t pathlen = strlen (path); + + buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO + | (rtems_tftp_is_directory (path, pathlen) ? S_IFDIR : S_IFREG); + + return 0; +} + +static int rtems_tftp_clone( + rtems_filesystem_location_info_t *loc +) +{ + int rv = 0; + + loc->node_access = strdup (loc->node_access); + + if (loc->node_access == NULL) { + errno = ENOMEM; + rv = -1; + } + + return rv; +} + +static void rtems_tftp_free_node_info( + const rtems_filesystem_location_info_t *loc +) +{ + free (loc->node_access); +} + +static bool rtems_tftp_are_nodes_equal( + const rtems_filesystem_location_info_t *a, + const rtems_filesystem_location_info_t *b +) +{ + return strcmp (a->node_access, b->node_access) == 0; +} + +static const rtems_filesystem_operations_table rtems_tftp_ops = { + .lock_h = rtems_filesystem_default_lock, + .unlock_h = rtems_filesystem_default_unlock, + .eval_path_h = rtems_tftp_eval_path, + .link_h = rtems_filesystem_default_link, + .are_nodes_equal_h = rtems_tftp_are_nodes_equal, + .mknod_h = rtems_filesystem_default_mknod, + .rmnod_h = rtems_filesystem_default_rmnod, + .fchmod_h = rtems_filesystem_default_fchmod, + .chown_h = rtems_filesystem_default_chown, + .clonenod_h = rtems_tftp_clone, + .freenod_h = rtems_tftp_free_node_info, + .mount_h = rtems_filesystem_default_mount, + .unmount_h = rtems_filesystem_default_unmount, + .fsunmount_me_h = rtems_tftpfs_shutdown, + .utimens_h = rtems_filesystem_default_utimens, + .symlink_h = rtems_filesystem_default_symlink, + .readlink_h = rtems_filesystem_default_readlink, + .rename_h = rtems_filesystem_default_rename, + .statvfs_h = rtems_filesystem_default_statvfs +}; + +static const rtems_filesystem_file_handlers_r rtems_tftp_handlers = { + .open_h = rtems_tftp_open, + .close_h = rtems_tftp_close, + .read_h = rtems_tftp_read, + .write_h = rtems_tftp_write, + .ioctl_h = rtems_filesystem_default_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_tftp_fstat, + .ftruncate_h = rtems_tftp_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl, + .kqfilter_h = rtems_filesystem_default_kqfilter, + .mmap_h = rtems_filesystem_default_mmap, + .poll_h = rtems_filesystem_default_poll, + .readv_h = rtems_filesystem_default_readv, + .writev_h = rtems_filesystem_default_writev +}; diff --git a/cpukit/libfs/src/imfs/imfs_add_node.c b/cpukit/libfs/src/imfs/imfs_add_node.c index 814736284d..d12ed03077 100644 --- a/cpukit/libfs/src/imfs/imfs_add_node.c +++ b/cpukit/libfs/src/imfs/imfs_add_node.c @@ -37,7 +37,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> int IMFS_add_node( const char *path, IMFS_jnode_t *node, void *arg ) { diff --git a/cpukit/libfs/src/imfs/imfs_chown.c b/cpukit/libfs/src/imfs/imfs_chown.c index 5a0049ba2d..20210470a1 100644 --- a/cpukit/libfs/src/imfs/imfs_chown.c +++ b/cpukit/libfs/src/imfs/imfs_chown.c @@ -38,7 +38,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> #include <unistd.h> diff --git a/cpukit/libfs/src/imfs/imfs_fchmod.c b/cpukit/libfs/src/imfs/imfs_fchmod.c index 7f885a1987..6f6c57ff23 100644 --- a/cpukit/libfs/src/imfs/imfs_fchmod.c +++ b/cpukit/libfs/src/imfs/imfs_fchmod.c @@ -38,7 +38,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> int IMFS_fchmod( const rtems_filesystem_location_info_t *loc, diff --git a/cpukit/libfs/src/imfs/imfs_fifo.c b/cpukit/libfs/src/imfs/imfs_fifo.c index a3154e18bd..be86187663 100644 --- a/cpukit/libfs/src/imfs/imfs_fifo.c +++ b/cpukit/libfs/src/imfs/imfs_fifo.c @@ -37,7 +37,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> #include <sys/filio.h> diff --git a/cpukit/libfs/src/imfs/imfs_linfile.c b/cpukit/libfs/src/imfs/imfs_linfile.c index 4f961d19e8..c9b1ec9e90 100644 --- a/cpukit/libfs/src/imfs/imfs_linfile.c +++ b/cpukit/libfs/src/imfs/imfs_linfile.c @@ -38,7 +38,7 @@ #include <string.h> -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> static ssize_t IMFS_linfile_read( rtems_libio_t *iop, diff --git a/cpukit/libfs/src/imfs/imfs_link.c b/cpukit/libfs/src/imfs/imfs_link.c index 301a280211..3ea05b0807 100644 --- a/cpukit/libfs/src/imfs/imfs_link.c +++ b/cpukit/libfs/src/imfs/imfs_link.c @@ -38,7 +38,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> static const IMFS_node_control IMFS_node_control_hard_link; diff --git a/cpukit/libfs/src/imfs/imfs_make_generic_node.c b/cpukit/libfs/src/imfs/imfs_make_generic_node.c index abecf5ec53..23beee431d 100644 --- a/cpukit/libfs/src/imfs/imfs_make_generic_node.c +++ b/cpukit/libfs/src/imfs/imfs_make_generic_node.c @@ -37,7 +37,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> #include <string.h> diff --git a/cpukit/libfs/src/imfs/imfs_memfile.c b/cpukit/libfs/src/imfs/imfs_memfile.c index 769a570ecf..66c67c6ba0 100644 --- a/cpukit/libfs/src/imfs/imfs_memfile.c +++ b/cpukit/libfs/src/imfs/imfs_memfile.c @@ -38,7 +38,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> #include <stdlib.h> #include <string.h> diff --git a/cpukit/libfs/src/imfs/imfs_mknod.c b/cpukit/libfs/src/imfs/imfs_mknod.c index 17aa1d3802..cd027fe7f6 100644 --- a/cpukit/libfs/src/imfs/imfs_mknod.c +++ b/cpukit/libfs/src/imfs/imfs_mknod.c @@ -41,7 +41,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> static const IMFS_mknod_control *get_control( const IMFS_mknod_controls *controls, diff --git a/cpukit/libfs/src/imfs/imfs_node.c b/cpukit/libfs/src/imfs/imfs_node.c index 91bd89d66c..10e9e72d01 100644 --- a/cpukit/libfs/src/imfs/imfs_node.c +++ b/cpukit/libfs/src/imfs/imfs_node.c @@ -41,7 +41,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> IMFS_jnode_t *IMFS_initialize_node( IMFS_jnode_t *node, diff --git a/cpukit/libfs/src/imfs/imfs_rename.c b/cpukit/libfs/src/imfs/imfs_rename.c index d925591b32..94876d9217 100644 --- a/cpukit/libfs/src/imfs/imfs_rename.c +++ b/cpukit/libfs/src/imfs/imfs_rename.c @@ -38,7 +38,7 @@ #include "config.h" #endif -#include <rtems/imfs.h> +#include <rtems/imfsimpl.h> #include <string.h> #include <stdlib.h> diff --git a/cpukit/libfs/src/jffs2/VERSION b/cpukit/libfs/src/jffs2/VERSION index 7d9c9f41b2..b13bed5750 100644 --- a/cpukit/libfs/src/jffs2/VERSION +++ b/cpukit/libfs/src/jffs2/VERSION @@ -1,9 +1,9 @@ -This directory contains a port of the JFFS2 file system from Linux v4.17. +This directory contains a port of the JFFS2 file system from Linux v5.9. To update to a newer Linux version use this command in a Git clone of Linux to generate the relevant patches: - git format-patch v4.17..v9.99 -- + git format-patch v5.9..v9.99 -- include/uapi/linux/jffs2.h \ fs/jffs2/LICENCE \ fs/jffs2/acl.h \ diff --git a/cpukit/libfs/src/jffs2/include/linux/jffs2.h b/cpukit/libfs/src/jffs2/include/linux/jffs2.h index a18b719f49..784ba0b969 100644 --- a/cpukit/libfs/src/jffs2/include/linux/jffs2.h +++ b/cpukit/libfs/src/jffs2/include/linux/jffs2.h @@ -77,11 +77,6 @@ #define JFFS2_ACL_VERSION 0x0001 -// Maybe later... -//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) -//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) - - #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at mount time, don't wait for it to happen later */ diff --git a/cpukit/libfs/src/jffs2/src/acl.h b/cpukit/libfs/src/jffs2/src/acl.h index 2e2b5745c3..12d0271bdd 100644 --- a/cpukit/libfs/src/jffs2/src/acl.h +++ b/cpukit/libfs/src/jffs2/src/acl.h @@ -22,6 +22,7 @@ struct jffs2_acl_entry_short { struct jffs2_acl_header { jint32_t a_version; + struct jffs2_acl_entry a_entries[]; }; #ifdef CONFIG_JFFS2_FS_POSIX_ACL diff --git a/cpukit/libfs/src/jffs2/src/erase.c b/cpukit/libfs/src/jffs2/src/erase.c index 9ffffafaea..e8ab569462 100644 --- a/cpukit/libfs/src/jffs2/src/erase.c +++ b/cpukit/libfs/src/jffs2/src/erase.c @@ -403,7 +403,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb { size_t retlen; int ret; - uint32_t uninitialized_var(bad_offset); + uint32_t bad_offset; switch (jffs2_block_check_erase(c, jeb, &bad_offset)) { case -EAGAIN: goto refile; diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c index 8bc3d85cc3..b863c74547 100644 --- a/cpukit/libfs/src/jffs2/src/fs-rtems.c +++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c @@ -1316,30 +1316,6 @@ int rtems_jffs2_initialize( // //========================================================================== -unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, - struct jffs2_inode_info *f, - unsigned long offset, - unsigned long *priv) -{ - int ret; - struct super_block *sb = OFNI_BS_2SFFJ(c); - unsigned char *gc_buffer = &sb->s_gc_buffer[0]; - - ret = jffs2_read_inode_range(c, f, gc_buffer, - offset & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE); - if (ret) - return ERR_PTR(ret); - - return gc_buffer; -} - -void jffs2_gc_release_page(struct jffs2_sb_info *c, - unsigned char *ptr, - unsigned long *priv) -{ - /* Do nothing */ -} - static struct _inode *new_inode(struct super_block *sb) { diff --git a/cpukit/libfs/src/jffs2/src/gc.c b/cpukit/libfs/src/jffs2/src/gc.c index f557075ab8..04ec073d2b 100644 --- a/cpukit/libfs/src/jffs2/src/gc.c +++ b/cpukit/libfs/src/jffs2/src/gc.c @@ -1173,12 +1173,17 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, uint32_t start, uint32_t end) { +#ifndef __rtems__ + struct inode *inode = OFNI_EDONI_2SFFJ(f); +#endif /* __rtems__ */ struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; uint32_t alloclen, offset, orig_end, orig_start; int ret = 0; unsigned char *comprbuf = NULL, *writebuf; - unsigned long pg; +#ifndef __rtems__ + struct page *page; +#endif /* __rtems__ */ unsigned char *pg_ptr; memset(&ri, 0, sizeof(ri)); @@ -1333,15 +1338,26 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era * end up here trying to GC the *same* page that jffs2_write_begin() is * trying to write out, read_cache_page() will not deadlock. */ mutex_unlock(&f->sem); - pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); - mutex_lock(&f->sem); - - if (IS_ERR(pg_ptr)) { +#ifndef __rtems__ + page = read_cache_page(inode->i_mapping, start >> PAGE_SHIFT, + jffs2_do_readpage_unlock, inode); + if (IS_ERR(page)) { pr_warn("read_cache_page() returned error: %ld\n", - PTR_ERR(pg_ptr)); - return PTR_ERR(pg_ptr); + PTR_ERR(page)); + mutex_lock(&f->sem); + return PTR_ERR(page); } + pg_ptr = kmap(page); +#else /* __rtems__ */ + pg_ptr = &OFNI_BS_2SFFJ(c)->s_gc_buffer[0]; + ret = jffs2_read_inode_range(c, f, pg_ptr, + start & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE); + if (ret) + return ret; +#endif /* __rtems__ */ + mutex_lock(&f->sem); + offset = start; while(offset < orig_end) { uint32_t datalen; @@ -1404,6 +1420,9 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era } } - jffs2_gc_release_page(c, pg_ptr, &pg); +#ifndef __rtems__ + kunmap(page); + put_page(page); +#endif /* __rtems__ */ return ret; } diff --git a/cpukit/libfs/src/jffs2/src/nodelist.h b/cpukit/libfs/src/jffs2/src/nodelist.h index 143f60dbcb..4eee0ac8ff 100644 --- a/cpukit/libfs/src/jffs2/src/nodelist.h +++ b/cpukit/libfs/src/jffs2/src/nodelist.h @@ -259,7 +259,7 @@ struct jffs2_full_dirent uint32_t ino; /* == zero for unlink */ unsigned int nhash; unsigned char type; - unsigned char name[0]; + unsigned char name[]; }; /* diff --git a/cpukit/libfs/src/jffs2/src/os-rtems.h b/cpukit/libfs/src/jffs2/src/os-rtems.h index db1be61e67..d9e4330371 100644 --- a/cpukit/libfs/src/jffs2/src/os-rtems.h +++ b/cpukit/libfs/src/jffs2/src/os-rtems.h @@ -56,7 +56,7 @@ static inline unsigned int full_name_hash(const void *salt, const unsigned char #define jffs2_can_mark_obsolete(c) (1) #define JFFS2_INODE_INFO(i) (&(i)->jffs2_i) -#define OFNI_EDONI_2SFFJ(f) ((struct _inode *) ( ((char *)f) - ((char *)(&((struct _inode *)NULL)->jffs2_i)) ) ) +#define OFNI_EDONI_2SFFJ(f) RTEMS_CONTAINER_OF(f, struct _inode, jffs2_i) #define ITIME(sec) (sec) #define I_SEC(tv) (tv) @@ -136,9 +136,6 @@ struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino); void jffs2_iput(struct _inode * i); void jffs2_gc_release_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, int inum, int nlink); -unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - unsigned long offset, unsigned long *priv); -void jffs2_gc_release_page(struct jffs2_sb_info *c, unsigned char *pg, unsigned long *priv); /* Avoid polluting RTEMS namespace with names not starting in jffs2_ */ #define os_to_jffs2_mode(x) jffs2_from_os_mode(x) diff --git a/cpukit/libfs/src/jffs2/src/readinode.c b/cpukit/libfs/src/jffs2/src/readinode.c index e6c9452c03..831fb8f3f9 100644 --- a/cpukit/libfs/src/jffs2/src/readinode.c +++ b/cpukit/libfs/src/jffs2/src/readinode.c @@ -1294,7 +1294,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, dbg_readinode("symlink's target '%s' cached\n", f->target); } - /* fall through... */ + fallthrough; case S_IFBLK: case S_IFCHR: @@ -1434,11 +1434,12 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) } jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); - +#ifdef __rtems__ if (f->target) { kfree(f->target); f->target = NULL; } +#endif /* __rtems__ */ fds = f->dents; while(fds) { diff --git a/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h b/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h index 1017a71c1f..56395e1528 100644 --- a/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h +++ b/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h @@ -33,3 +33,4 @@ #define __ECOS 1 #define KBUILD_MODNAME "JFFS2" +#define fallthrough __attribute__((__fallthrough__)) diff --git a/cpukit/libfs/src/jffs2/src/scan.c b/cpukit/libfs/src/jffs2/src/scan.c index 177a0cdd3f..765bf55478 100644 --- a/cpukit/libfs/src/jffs2/src/scan.c +++ b/cpukit/libfs/src/jffs2/src/scan.c @@ -264,7 +264,8 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } #endif if (c->nr_erasing_blocks) { - if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { + if (!c->used_size && !c->unchecked_size && + ((c->nr_free_blocks+empty_blocks+bad_blocks) != c->nr_blocks || bad_blocks == c->nr_blocks)) { pr_notice("Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); pr_notice("empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n", empty_blocks, bad_blocks, c->nr_blocks); @@ -530,8 +531,11 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo err = jffs2_fill_scan_buf(c, sumptr, jeb->offset + c->sector_size - sumlen, sumlen - buf_len); - if (err) + if (err) { + if (sumlen > buf_size) + kfree(sumptr); return err; + } } } diff --git a/cpukit/libfs/src/jffs2/src/summary.h b/cpukit/libfs/src/jffs2/src/summary.h index 60207a2ae9..e4131cb1f1 100644 --- a/cpukit/libfs/src/jffs2/src/summary.h +++ b/cpukit/libfs/src/jffs2/src/summary.h @@ -61,7 +61,7 @@ struct jffs2_sum_dirent_flash jint32_t ino; /* == zero for unlink */ uint8_t nsize; /* dirent name size */ uint8_t type; /* dirent type */ - uint8_t name[0]; /* dirent name */ + uint8_t name[]; /* dirent name */ } __attribute__((packed)); struct jffs2_sum_xattr_flash @@ -117,7 +117,7 @@ struct jffs2_sum_dirent_mem jint32_t ino; /* == zero for unlink */ uint8_t nsize; /* dirent name size */ uint8_t type; /* dirent type */ - uint8_t name[0]; /* dirent name */ + uint8_t name[]; /* dirent name */ } __attribute__((packed)); struct jffs2_sum_xattr_mem diff --git a/cpukit/libmd/md5.c b/cpukit/libmd/md5.c index 4c909f37a0..5e3a100c7b 100644 --- a/cpukit/libmd/md5.c +++ b/cpukit/libmd/md5.c @@ -165,7 +165,7 @@ void MD5Update ( ends with the desired message digest in mdContext->digest[0...15]. */ void MD5Final ( - unsigned char hash[], + unsigned char hash[16], MD5_CTX *mdContext ) { UINT4 in[16]; diff --git a/cpukit/libmisc/shell/hexdump-conv.c b/cpukit/libmisc/shell/hexdump-conv.c index aa16f9b169..24b28353f3 100644 --- a/cpukit/libmisc/shell/hexdump-conv.c +++ b/cpukit/libmisc/shell/hexdump-conv.c @@ -117,7 +117,11 @@ retry: if (clen == 0) clen = 1; else if (clen == (size_t)-1 || (clen == (size_t)-2 && +#ifndef __rtems__ buf == peekbuf)) { +#else /* __rtems__ */ + &buf[0] == &peekbuf[0])) { +#endif /* __rtems__ */ memset(&pr->mbstate, 0, sizeof(pr->mbstate)); wc = *p; clen = 1; diff --git a/cpukit/libmisc/shell/main_edit.c b/cpukit/libmisc/shell/main_edit.c index ed1371f7fa..4cc742719a 100644 --- a/cpukit/libmisc/shell/main_edit.c +++ b/cpukit/libmisc/shell/main_edit.c @@ -55,7 +55,9 @@ #if defined(__linux__) || defined(__rtems__) #include <sys/ioctl.h> #include <termios.h> +#ifndef O_BINARY #define O_BINARY 0 +#endif static int linux_console; #endif diff --git a/cpukit/libmisc/shell/main_rtems.c b/cpukit/libmisc/shell/main_rtems.c new file mode 100644 index 0000000000..956c6bcb72 --- /dev/null +++ b/cpukit/libmisc/shell/main_rtems.c @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup + * + * @brief This source file contains the kernel command. + */ + +/* + * Copyright (c) 2022 Chris Johns. 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/version.h> + +static void kernel_summary(void) { + printf( + "RTEMS: %d.%d.%d", + rtems_version_major(), rtems_version_minor(), rtems_version_revision()); + if (rtems_version_control_key_is_valid(rtems_version_control_key())) { + printf(" (%s)", rtems_version_control_key()); + } +#if RTEMS_SMP + printf(" SMP:%d cores", rtems_scheduler_get_processor_maximum()); +#endif + printf("\n"); +} + +static void cpu_summary(void) { + printf("CPU: " CPU_NAME " (" CPU_MODEL_NAME ")\n"); +} + +static void bsp_summary(void) { + printf("BSP: %s\n", rtems_board_support_package()); +} + +static void tools_summary(void) { + printf( "Tools: " __VERSION__ "\n"); +} + +static void opts_summary(void) { + printf("Options:" +#if RTEMS_DEBUG + " DEBUG" +#endif +#if RTEMS_MULTIPROCESSING + " MULTIPROCESSING" +#endif +#if RTEMS_NETWORKING + " NETWORKING" +#endif +#if RTEMS_PARAVIRT + " PARAVIRT" +#endif +#if RTEMS_POSIX_API + " POSIX" +#endif +#if RTEMS_PROFILING + " PROFILING" +#endif +#if RTEMS_SMP + " SMP" +#endif + "\n"); +} + +static void help(void) { + printf( "Usage:: rtems <command>\n"); + printf( " where <command> is:\n"); + printf( " help : this help\n"); + printf( " ver : kernel version\n"); + printf( " cpu : kernel version\n"); + printf( " bsp : BSP name\n"); + printf( " tools : tools version\n"); + printf( " opts : options\n"); + printf( " all : all commands\n"); +} + +static int rtems_shell_main_rtems( + int argc, char *argv[]) { + + if (argc == 1) { + kernel_summary(); + } else if (argc == 2) { + if (strcmp(argv[1], "help") == 0) { + help(); + } else if (strcmp(argv[1], "ver") == 0) { + kernel_summary(); + } else if (strcmp(argv[1], "cpu") == 0) { + cpu_summary(); + } else if (strcmp(argv[1], "bsp") == 0) { + bsp_summary(); + } else if (strcmp(argv[1], "tools") == 0) { + tools_summary(); + } else if (strcmp(argv[1], "opts") == 0) { + opts_summary(); + } else if (strcmp(argv[1], "all") == 0) { + kernel_summary(); + cpu_summary(); + bsp_summary(); + tools_summary(); + opts_summary(); + } else { + printf("error: invalid command\n"); + return 1; + } + } else { + printf("error: invalid command\n"); + return 1; + } + return 0; +} + +#define HELP_LINE \ + "rtems <command> (eg. help)" + +rtems_shell_cmd_t rtems_shell_RTEMS_Command = { + "rtems", /* name */ + HELP_LINE, /* usage */ + "rtems", /* topic */ + rtems_shell_main_rtems, /* command */ + NULL, /* alias */ + NULL, /* next */ + 0500, /* mode */ + 0, /* uid */ + 0 /* gid */ +}; diff --git a/cpukit/libtest/t-test-hash-sha256.c b/cpukit/libtest/t-test-hash-sha256.c index 32e946b4cf..a023d3969c 100644 --- a/cpukit/libtest/t-test-hash-sha256.c +++ b/cpukit/libtest/t-test-hash-sha256.c @@ -44,6 +44,15 @@ typedef struct { static T_report_hash_sha256_context T_report_hash_sha256_instance; +void +T_report_hash_sha256_update(char c) +{ + T_report_hash_sha256_context *ctx; + + ctx = &T_report_hash_sha256_instance; + SHA256_Update(&ctx->sha256, &c, sizeof(c)); +} + static void T_report_hash_sha256_putchar(int c, void *arg) { diff --git a/cpukit/libtest/testgcovbspreset.c b/cpukit/libtest/testgcovbspreset.c new file mode 100644 index 0000000000..6e10615f8c --- /dev/null +++ b/cpukit/libtest/testgcovbspreset.c @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTest + * + * @brief This source file contains the implementation of a wrapper for + * bsp_reset() which dumps the gcov information using + * rtems_test_gcov_dump_info() before the real bsp_reset() is called. + */ + +/* + * Copyright (C) 2021, 2022 embedded brains GmbH + * + * 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/test-info.h> + +#include <rtems/score/cpu.h> + +void __real_bsp_reset( void ); + +void __wrap_bsp_reset( void ); + +void __wrap_bsp_reset( void ) +{ + rtems_test_gcov_dump_info(); + __real_bsp_reset(); +} diff --git a/cpukit/libtest/testgcovcpufatalhalt.c b/cpukit/libtest/testgcovcpufatalhalt.c new file mode 100644 index 0000000000..dd8f10149c --- /dev/null +++ b/cpukit/libtest/testgcovcpufatalhalt.c @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTest + * + * @brief This source file contains the implementation of a wrapper for + * _CPU_Fatal_halt() which dumps the gcov information using + * rtems_test_gcov_dump_info() before the real _CPU_Fatal_halt() is called. + */ + +/* + * Copyright (C) 2021, 2022 embedded brains GmbH + * + * 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/test-info.h> + +#include <rtems/score/cpu.h> + +void __real__CPU_Fatal_halt( uint32_t source, CPU_Uint32ptr error ); + +void __wrap__CPU_Fatal_halt( uint32_t source, CPU_Uint32ptr error ); + +void __wrap__CPU_Fatal_halt( uint32_t source, CPU_Uint32ptr error ) +{ + rtems_test_gcov_dump_info(); + __real__CPU_Fatal_halt( source, error ); +} diff --git a/cpukit/libtest/testgcovdumpinfo.c b/cpukit/libtest/testgcovdumpinfo.c new file mode 100644 index 0000000000..7139d7d623 --- /dev/null +++ b/cpukit/libtest/testgcovdumpinfo.c @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTest + * + * @brief This source file contains the implementation of + * rtems_test_gcov_dump_info(). + */ + +/* + * Copyright (C) 2021, 2022 embedded brains GmbH + * + * 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/test-info.h> + +#include <rtems/score/gcov.h> +#include <rtems/score/isrlock.h> +#include <rtems/bspIo.h> + +ISR_LOCK_DEFINE( static, gcov_dump_lock, "gcov dump" ); + +static bool gcov_dump_done; + +void rtems_test_gcov_dump_info( void ) +{ + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire( &gcov_dump_lock, &lock_context ); + + if ( !gcov_dump_done ) { + gcov_dump_done = true; + + _IO_Printf( rtems_put_char, NULL, "\n*** BEGIN OF GCOV INFO BASE64 ***\n" ); + _Gcov_Dump_info_base64( rtems_put_char, NULL ); + _IO_Printf( rtems_put_char, NULL, "\n*** END OF GCOV INFO BASE64 ***\n" ); + } + + _ISR_lock_Release_and_ISR_enable( &gcov_dump_lock, &lock_context ); +} diff --git a/cpukit/posix/src/_execve.c b/cpukit/posix/src/_execve.c index 2858d13082..63afadec43 100644 --- a/cpukit/posix/src/_execve.c +++ b/cpukit/posix/src/_execve.c @@ -43,9 +43,9 @@ #endif /* - * Needed to get the prototype for this newlib helper method + * Needed to get the prototype for this libc helper method */ -#define _COMPILING_NEWLIB +#define _LIBC #include <errno.h> #include <rtems/seterr.h> diff --git a/cpukit/posix/src/cancel.c b/cpukit/posix/src/cancel.c index 300055d68a..1ccfe75b0b 100644 --- a/cpukit/posix/src/cancel.c +++ b/cpukit/posix/src/cancel.c @@ -75,7 +75,7 @@ int pthread_cancel( pthread_t thread ) } else { _Thread_Dispatch_disable_with_CPU( cpu_self, &lock_context ); _ISR_lock_ISR_enable( &lock_context ); - _Thread_Cancel( the_thread, executing, PTHREAD_CANCELED ); + (void) _Thread_Cancel( the_thread, executing, 0 ); _Thread_Dispatch_enable( cpu_self ); } return 0; diff --git a/cpukit/posix/src/clocknanosleep.c b/cpukit/posix/src/clocknanosleep.c index 3fa890fecd..43f15346de 100644 --- a/cpukit/posix/src/clocknanosleep.c +++ b/cpukit/posix/src/clocknanosleep.c @@ -82,6 +82,15 @@ int clock_nanosleep( rmtp = NULL; } else { absolute = false; + + /* + * A relative CLOCK_REALTIME time out shall not be affected by + * CLOCK_REALTIME changes through clock_settime(). Since our + * CLOCK_REALTIME is basically just CLOCK_MONOTONIC plus an offset, we can + * simply use the CLOCK_MONOTONIC watchdog for relative CLOCK_REALTIME time + * outs. + */ + clock_id = CLOCK_MONOTONIC; } if ( clock_id == CLOCK_REALTIME ) { @@ -118,11 +127,8 @@ int clock_nanosleep( struct timespec actual_end; struct timespec planned_end; - if ( clock_id == CLOCK_REALTIME ) { - _Timecounter_Nanotime( &actual_end ); - } else { - _Timecounter_Nanouptime( &actual_end ); - } + _Assert( clock_id == CLOCK_MONOTONIC ); + _Timecounter_Nanouptime( &actual_end ); _Watchdog_Ticks_to_timespec( executing->Timer.Watchdog.expire, diff --git a/cpukit/posix/src/psxtimercreate.c b/cpukit/posix/src/psxtimercreate.c index 0eefac3f42..907da01836 100644 --- a/cpukit/posix/src/psxtimercreate.c +++ b/cpukit/posix/src/psxtimercreate.c @@ -51,6 +51,31 @@ #include <rtems/seterr.h> #include <rtems/sysinit.h> +RTEMS_WEAK int _POSIX_Timer_Is_allowed( + clockid_t clock_id +) +{ + int rc = 0; + + /* + * Allow timer_create(CLOCK_REALTIME. ...) per POSIX by default + * on CLOCK_REALTIME or CLOCK_MONOTONIC. + * + * But per the FACE Technical Standard, POSIX timers should not be + * allowed on CLOCK_REALTIME for safety reasons. If the application + * configures that it wants the FACE behavior, then this method + * is overridden by <rtems/confdefs/timer.h>. + */ + + if ( clock_id != CLOCK_REALTIME ) { + if ( clock_id != CLOCK_MONOTONIC ) { + rc = EINVAL; + } + } + + return rc; +} + int timer_create( clockid_t clock_id, struct sigevent *__restrict evp, @@ -58,9 +83,11 @@ int timer_create( ) { POSIX_Timer_Control *ptimer; + int rc; - if ( clock_id != CLOCK_REALTIME && clock_id != CLOCK_MONOTONIC ) - rtems_set_errno_and_return_minus_one( EINVAL ); + rc = _POSIX_Timer_Is_allowed( clock_id ); + if ( rc != 0 ) + rtems_set_errno_and_return_minus_one( rc ); if ( !timerid ) rtems_set_errno_and_return_minus_one( EINVAL ); diff --git a/cpukit/posix/src/pthreadjoin.c b/cpukit/posix/src/pthreadjoin.c index 84ff15ceec..e4f978f6b4 100644 --- a/cpukit/posix/src/pthreadjoin.c +++ b/cpukit/posix/src/pthreadjoin.c @@ -54,26 +54,16 @@ static int _POSIX_Threads_Join( pthread_t thread, void **value_ptr ) { Thread_Control *the_thread; Thread_queue_Context queue_context; - Per_CPU_Control *cpu_self; Thread_Control *executing; - void *value; + Status_Control status; _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context ); the_thread = _Thread_Get( thread, &queue_context.Lock_context.Lock_context ); if ( the_thread == NULL ) { return ESRCH; } - cpu_self = _Per_CPU_Get(); - executing = _Per_CPU_Get_executing( cpu_self ); - - if ( executing == the_thread ) { - _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); - return EDEADLK; - } - _Thread_State_acquire_critical( the_thread, &queue_context.Lock_context.Lock_context @@ -84,33 +74,20 @@ static int _POSIX_Threads_Join( pthread_t thread, void **value_ptr ) return EINVAL; } - if ( _States_Is_waiting_for_join_at_exit( the_thread->current_state ) ) { - value = the_thread->Life.exit_value; - _Thread_Clear_state_locked( the_thread, STATES_WAITING_FOR_JOIN_AT_EXIT ); - _Thread_Dispatch_disable_with_CPU( - cpu_self, - &queue_context.Lock_context.Lock_context - ); - _Thread_State_release( the_thread, &queue_context.Lock_context.Lock_context ); - _Thread_Dispatch_direct( cpu_self ); - } else { - _Thread_Join( - the_thread, - STATES_INTERRUPTIBLE_BY_SIGNAL | STATES_WAITING_FOR_JOIN, - executing, - &queue_context - ); - - if ( _POSIX_Get_error_after_wait( executing ) != 0 ) { - _Assert( _POSIX_Get_error_after_wait( executing ) == EINTR ); - return EINTR; - } - - value = executing->Wait.return_argument; + executing = _Thread_Executing; + status = _Thread_Join( + the_thread, + STATES_INTERRUPTIBLE_BY_SIGNAL | STATES_WAITING_FOR_JOIN, + executing, + &queue_context + ); + + if ( status != STATUS_SUCCESSFUL ) { + return _POSIX_Get_error( status ); } if ( value_ptr != NULL ) { - *value_ptr = value; + *value_ptr = executing->Wait.return_argument; } return 0; diff --git a/cpukit/rtems/src/schedulerident.c b/cpukit/rtems/src/schedulerident.c index e73d3d743a..60e7765ccd 100644 --- a/cpukit/rtems/src/schedulerident.c +++ b/cpukit/rtems/src/schedulerident.c @@ -10,7 +10,7 @@ */ /* - * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * Copyright (C) 2014, 2022 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,25 +46,20 @@ rtems_status_code rtems_scheduler_ident( rtems_id *id ) { - rtems_status_code sc; + size_t i; - if ( id != NULL ) { - size_t n = _Scheduler_Count; - size_t i; - - sc = RTEMS_INVALID_NAME; + if ( id == NULL ) { + return RTEMS_INVALID_ADDRESS; + } - for ( i = 0 ; i < n && sc == RTEMS_INVALID_NAME ; ++i ) { - const Scheduler_Control *scheduler = &_Scheduler_Table[ i ]; + for ( i = 0; i < _Scheduler_Count; ++i ) { + const Scheduler_Control *scheduler = &_Scheduler_Table[ i ]; - if ( scheduler->name == name ) { - *id = _Scheduler_Build_id( i ); - sc = RTEMS_SUCCESSFUL; - } + if ( scheduler->name == name ) { + *id = _Scheduler_Build_id( i ); + return RTEMS_SUCCESSFUL; } - } else { - sc = RTEMS_INVALID_ADDRESS; } - return sc; + return RTEMS_INVALID_NAME; } diff --git a/cpukit/rtems/src/taskdelete.c b/cpukit/rtems/src/taskdelete.c index 2e3de0922e..410842f393 100644 --- a/cpukit/rtems/src/taskdelete.c +++ b/cpukit/rtems/src/taskdelete.c @@ -40,6 +40,7 @@ #endif #include <rtems/rtems/tasksimpl.h> +#include <rtems/rtems/statusimpl.h> #include <rtems/score/threadimpl.h> rtems_status_code rtems_task_delete( @@ -47,12 +48,13 @@ rtems_status_code rtems_task_delete( ) { Thread_Control *the_thread; - Thread_Close_context context; + Thread_queue_Context queue_context; Per_CPU_Control *cpu_self; Thread_Control *executing; + Status_Control status; - _Thread_queue_Context_initialize( &context.Base ); - the_thread = _Thread_Get( id, &context.Base.Lock_context.Lock_context ); + _Thread_queue_Context_initialize( &queue_context ); + the_thread = _Thread_Get( id, &queue_context.Lock_context.Lock_context ); if ( the_thread == NULL ) { #if defined(RTEMS_MULTIPROCESSING) @@ -67,23 +69,22 @@ rtems_status_code rtems_task_delete( cpu_self = _Per_CPU_Get(); if ( _Per_CPU_Is_ISR_in_progress( cpu_self ) ) { - _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); + _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); return RTEMS_CALLED_FROM_ISR; } executing = _Per_CPU_Get_executing( cpu_self ); if ( the_thread == executing ) { - _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); + _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); /* * The Classic tasks are neither detached nor joinable. In case of * self deletion, they are detached, otherwise joinable by default. */ _Thread_Exit( NULL, THREAD_LIFE_TERMINATING | THREAD_LIFE_DETACHED ); - } else { - _Thread_Close( the_thread, executing, &context ); } - return RTEMS_SUCCESSFUL; + status = _Thread_Close( the_thread, executing, &queue_context ); + return _Status_Get( status ); } diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c index 5d863bd79c..e5242c82a5 100644 --- a/cpukit/rtems/src/timerserver.c +++ b/cpukit/rtems/src/timerserver.c @@ -173,7 +173,7 @@ static rtems_status_code _Timer_server_Initiate( } if ( priority == RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) { - priority = PRIORITY_PSEUDO_ISR; + priority = PRIORITY_MINIMUM; } /* diff --git a/cpukit/score/cpu/aarch64/cpu.c b/cpukit/score/cpu/aarch64/cpu.c index 88e7ad8a8c..923f53da08 100644 --- a/cpukit/score/cpu/aarch64/cpu.c +++ b/cpukit/score/cpu/aarch64/cpu.c @@ -174,28 +174,6 @@ uint32_t _CPU_ISR_Get_level( void ) return ( level & AARCH64_PSTATE_I ) != 0; } -void _CPU_ISR_install_vector( - uint32_t vector, - CPU_ISR_handler new_handler, - CPU_ISR_handler *old_handler -) -{ - /* Redirection table starts at the end of the vector table */ - CPU_ISR_handler *table = (CPU_ISR_handler *) (MAX_EXCEPTIONS * 4); - - CPU_ISR_handler current_handler = table [vector]; - - /* The current handler is now the old one */ - if (old_handler != NULL) { - *old_handler = current_handler; - } - - /* Write only if necessary to avoid writes to a maybe read-only memory */ - if (current_handler != new_handler) { - table [vector] = new_handler; - } -} - void _CPU_Initialize( void ) { /* Do nothing */ diff --git a/cpukit/score/cpu/aarch64/include/libcpu/mmu-vmsav8-64.h b/cpukit/score/cpu/aarch64/include/libcpu/mmu-vmsav8-64.h index 6b6296bb7a..0d65004f88 100644 --- a/cpukit/score/cpu/aarch64/include/libcpu/mmu-vmsav8-64.h +++ b/cpukit/score/cpu/aarch64/include/libcpu/mmu-vmsav8-64.h @@ -60,7 +60,6 @@ extern "C" { #define MMU_PAGE_BITS 12 #define MMU_PAGE_SIZE ( 1 << MMU_PAGE_BITS ) #define MMU_BITS_PER_LEVEL 9 -#define MMU_TOP_LEVEL_PAGE_BITS ( 2 * MMU_BITS_PER_LEVEL + MMU_PAGE_BITS ) #define AARCH64_MMU_FLAGS_BASE \ ( MMU_DESC_VALID | MMU_DESC_SH_INNER | MMU_DESC_AF ) diff --git a/cpukit/score/cpu/aarch64/include/machine/elf_machdep.h b/cpukit/score/cpu/aarch64/include/machine/elf_machdep.h new file mode 100644 index 0000000000..c1d219d715 --- /dev/null +++ b/cpukit/score/cpu/aarch64/include/machine/elf_machdep.h @@ -0,0 +1,256 @@ +/* $NetBSD: elf_machdep.h,v 1.4 2018/10/12 01:28:58 ryo Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifndef _AARCH64_ELF_MACHDEP_H_ +#define _AARCH64_ELF_MACHDEP_H_ + +#ifdef __aarch64__ + +#if defined(__AARCH64EB__) +#define ELF64_MACHDEP_ENDIANNESS ELFDATA2MSB +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB +#else +#define ELF64_MACHDEP_ENDIANNESS ELFDATA2LSB +#define ELF32_MACHDEP_ENDIANNESS ELFDATA2LSB +#endif + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x00000001 +#define EF_ARM_HASENTRY 0x00000002 +#define EF_ARM_INTERWORK 0x00000004 /* GNU binutils 000413 */ +#define EF_ARM_SYMSARESORTED 0x00000004 /* ARM ELF A08 */ +#define EF_ARM_APCS_26 0x00000008 /* GNU binutils 000413 */ +#define EF_ARM_DYNSYMSUSESEGIDX 0x00000008 /* ARM ELF B01 */ +#define EF_ARM_APCS_FLOAT 0x00000010 /* GNU binutils 000413 */ +#define EF_ARM_MAPSYMSFIRST 0x00000010 /* ARM ELF B01 */ +#define EF_ARM_PIC 0x00000020 +#define EF_ARM_ALIGN8 0x00000040 /* 8-bit structure alignment. */ +#define EF_ARM_NEW_ABI 0x00000080 +#define EF_ARM_OLD_ABI 0x00000100 +#define EF_ARM_SOFT_FLOAT 0x00000200 +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_EABIMASK 0xff000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +#define ELF32_MACHDEP_ID_CASES \ + case EM_ARM: \ + break; + +#define ELF64_MACHDEP_ID_CASES \ + case EM_AARCH64: \ + break; + +#define ELF64_MACHDEP_ID EM_AARCH64 +#define ELF32_MACHDEP_ID EM_ARM + +#define KERN_ELFSIZE 64 +#define ARCH_ELFSIZE 64 /* MD native binary size */ + +/* Processor specific relocation types */ + +#define R_AARCH64_NONE 0 +#define R_AARCH64_NONE2 256 + +#define R_AARCH64_ABS64 257 /* S + A */ +#define R_AARCH64_ABS32 258 /* S + A */ +#define R_AARCH64_ABS16 259 /* S + A */ +#define R_AARCH64_PREL64 260 /* S + A - P */ +#define R_AARCH64_PREL32 261 /* S + A - P */ +#define R_AARCH64_PREL16 262 /* S + A - P */ +#define R_AARCH64_MOVW_UABS_G0 263 /* S + A [bits 0..15] */ +#define R_AARCH64_MOVW_UABS_G0_NC 264 /* S + A [bits 0..15] */ +#define R_AARCH64_MOVW_UABS_G1 265 /* S + A [bits 16..31] */ +#define R_AARCH64_MOVW_UABS_G1_NC 266 /* S + A [bits 16..31] */ +#define R_AARCH64_MOVW_UABS_G2 267 /* S + A [bits 32..47] */ +#define R_AARCH64_MOVW_UABS_G2_NC 268 /* S + A [bits 32..47] */ +#define R_AARCH64_MOVW_UABS_G3 269 /* S + A [bits 48..63] */ +#define R_AARCH64_MOVW_SABS_G0 270 /* S + A [bits 0..15] */ +#define R_AARCH64_MOVW_SABS_G1 271 /* S + A [bits 16..31] */ +#define R_AARCH64_MOVW_SABS_G2 272 /* S + A [bits 32..47] */ +#define R_AARCH64_LD_PREL_LO19 273 /* S + A - P */ +#define R_AARCH64_ADR_PREL_LO21 274 /* S + A - P */ +#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page(S + A) - Page(P) */ +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Page(S + A) - Page(P) */ +#define R_AARCH64_ADD_ABS_LO12_NC 277 /* S + A */ +#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* S + A */ +#define R_AARCH_TSTBR14 279 /* S + A - P */ +#define R_AARCH_CONDBR19 281 /* S + A - P */ +#define R_AARCH_JUMP26 282 /* S + A - P */ +#define R_AARCH_CALL26 283 /* S + A - P */ +#define R_AARCH_LDST16_ABS_LO12_NC 284 /* S + A */ +#define R_AARCH_LDST32_ABS_LO12_NC 285 /* S + A */ +#define R_AARCH_LDST64_ABS_LO12_NC 286 /* S + A */ +#define R_AARCH64_MOVW_PREL_G0 287 /* S + A - P */ +#define R_AARCH64_MOVW_PREL_G0_NC 288 /* S + A - P */ +#define R_AARCH64_MOVW_PREL_G1 289 /* S + A - P */ +#define R_AARCH64_MOVW_PREL_G1_NC 290 /* S + A - P */ +#define R_AARCH64_MOVW_PREL_G2 291 /* S + A - P */ +#define R_AARCH64_MOVW_PREL_G2_NC 292 /* S + A - P */ +#define R_AARCH64_MOVW_PREL_G3 293 /* S + A - P */ + +#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* S + A */ +#define R_AARCH64_MOVW_GOTOFF_G0 300 /* G(GDAT(S + A)) - GOT */ +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* G(GDAT(S + A)) - GOT */ +#define R_AARCH64_MOVW_GOTOFF_G1 302 /* G(GDAT(S + A)) - GOT */ +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* G(GDAT(S + A)) - GOT */ +#define R_AARCH64_MOVW_GOTOFF_G2 304 /* G(GDAT(S + A)) - GOT */ +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* G(GDAT(S + A)) - GOT */ +#define R_AARCH64_MOVW_GOTOFF_G3 306 /* G(GDAT(S + A)) - GOT */ +#define R_AARCH64_GOTREL64 307 /* S + A - GOT */ +#define R_AARCH64_GOTREL32 308 /* S + A - GOT */ +#define R_AARCH64_GOT_LD_PREL19 309 /* G(GDAT(S + A)) - P */ +#define R_AARCH64_LD64_GOTOFF_LO15 310 /* G(GDAT(S + A)) - GOT */ +#define R_AARCH64_ADR_GOT_PAGE 311 /* Page(G(GDAT(S + A))) - Page(GOT) */ +#define R_AARCH64_LD64_GOT_LO12_NC 312 /* G(GDAT(S + A)) */ +#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* G(GDAT(S + A)) - Page(GOT) */ + +#define R_AARCH64_TLSGD_ADR_PREL21 512 /* G(GTLSIDX(S,A)) - P */ +#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* Page(G(GTLSIDX(S,A))) - Page(P) */ +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* G(GTLSIDX(S,A)) */ +#define R_AARCH64_TLSGD_MOVW_G1 515 /* G(GTLSIDX(S,A)) - GOT */ +#define R_AARCH64_TLSGD_MOVW_G0_NV 516 /* G(GTLSIDX(S,A)) - GOT */ +#define R_AARCH64_TLSLD_ADR_PREL21 517 /* G(GLDM(S,A)) - P */ +#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Page(G(GLDM(S))) - Page(P) */ +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* G(GLDM(S)) */ +#define R_AARCH64_TLSLD_MOVW_G1 520 /* G(GLDM(S)) - GOT */ +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* G(GLDM(S)) - GOT */ +#define R_AARCH64_TLSLD_LD_PREL21 522 /* G(GLDM(S)) - P */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 528 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* DTPREL(S+A) */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* G(GTPREL(S+A)) - GOT */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* G(GTPREL(S+A)) - GOT */ +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page(G(GTPREL(S+A))) - Page(P) */ +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* G(GTPREL(S+A)) */ +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* G(GTPREL(S+A)) - P */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TPREL(S+A) */ +#define R_AARCH64_MOVW_TPREL_G1 545 /* TPREL(S+A) */ +#define R_AARCH64_MOVW_TPREL_G1_NC 546 /* TPREL(S+A) */ +#define R_AARCH64_MOVW_TPREL_G0 547 /* TPREL(S+A) */ +#define R_AARCH64_MOVW_TPREL_G0_NC 548 /* TPREL(S+A) */ +#define R_AARCH64_ADD_TPREL_HI12 549 /* TPREL(S+A) */ +#define R_AARCH64_ADD_TPREL_LO12 550 /* TPREL(S+A) */ +#define R_AARCH64_ADD_TPREL_LO12_NC 551 /* TPREL(S+A) */ +#define R_AARCH64_LDST8_TPREL_LO12 552 /* TPREL(S+A) */ +#define R_AARCH64_LDST8_TPREL_LO12_NC 553 /* TPREL(S+A) */ +#define R_AARCH64_LDST16_TPREL_LO12 554 /* TPREL(S+A) */ +#define R_AARCH64_LDST16_TPREL_LO12_NC 555 /* TPREL(S+A) */ +#define R_AARCH64_LDST32_TPREL_LO12 556 /* TPREL(S+A) */ +#define R_AARCH64_LDST32_TPREL_LO12_NC 557 /* TPREL(S+A) */ +#define R_AARCH64_LDST64_TPREL_LO12 558 /* TPREL(S+A) */ +#define R_AARCH64_LDST64_TPREL_LO12_NC 559 /* TPREL(S+A) */ +#define R_AARCH64_TLSDESC_LD_PREL19 560 /* G(GTLSDESC(S+A)) - P */ +#define R_AARCH64_TLSDESC_LD_PREL21 561 /* G(GTLSDESC(S+A)) - P */ +#define R_AARCH64_TLSDESC_LD_PAGE21 562 /* Page(G(GTLSDESC(S+A))) - Page(P) */ +#define R_AARCH64_TLSDESC_LD64_LO12 563 /* G(GTLSDESC(S+A)) */ +#define R_AARCH64_TLSDESC_ADD_LO12 564 /* G(GTLSDESC(S+A)) */ +#define R_AARCH64_TLSDESC_OFF_G1 565 /* G(GTLSDESC(S+A)) - GOT */ +#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* G(GTLSDESC(S+A)) - GOT */ +#define R_AARCH64_TLSDESC_LDR 567 /* */ +#define R_AARCH64_TLSDESC_ADD 568 /* */ +#define R_AARCH64_TLSDESC_CALL 569 /* */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* TPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 572 /* DTPREL(S+A) */ + +/* Dynamic Relocations */ +#define R_AARCH64_P32_COPY 180 +#define R_AARCH64_P32_GLOB_DAT 181 /* S + A */ +#define R_AARCH64_P32_JUMP_SLOT 182 /* S + A */ +#define R_AARCH64_P32_RELATIVE 183 /* Delta(S) + A */ +#define R_AARCH64_P32_TLS_DTPREL 184 /* DTPREL(S+A) */ +#define R_AARCH64_P32_TLS_DTPMOD 185 /* LBM(S) */ +#define R_AARCH64_P32_TLS_TPREL 186 /* TPREL(S+A) */ +#define R_AARCH64_P32_TLSDESC 187 /* TLSDESC(S+A) */ +#define R_AARCH64_P32_IRELATIVE 188 /* Indirect(Delta(S) + A) */ + +#define R_AARCH64_COPY 1024 +#define R_AARCH64_GLOB_DAT 1025 /* S + A */ +#define R_AARCH64_JUMP_SLOT 1026 /* S + A */ +#define R_AARCH64_RELATIVE 1027 /* Delta(S) + A */ +#define R_AARCH64_TLS_DTPREL64 1028 /* DTPREL(S+A) */ +#define R_AARCH64_TLS_DTPMOD64 1029 /* LBM(S) */ +#define R_AARCH64_TLS_TPREL64 1030 /* TPREL(S+A) */ +#define R_AARCH64_TLSDESC 1031 /* TLSDESC(S+A) */ +#define R_AARCH64_IRELATIVE 1032 /* Indirect(Delta(S) + A) */ + +#define R_TYPE(name) R_AARCH64_ ## name +#define R_TLS_TYPE(name) R_AARCH64_ ## name ## 64 + +/* Processor specific program header types */ +#define PT_AARCH64_ARCHEXT (PT_LOPROC + 0) +#define PT_AARCH64_UNWIND (PT_LOPROC + 1) + +/* Processor specific section header flags */ +#define SHF_ENTRYSECT 0x10000000 +#define SHF_COMDEF 0x80000000 + +#define SHT_AARCH64_ATTRIBUTES (SHT_LOPROC + 3) + +#ifdef _KERNEL +#ifdef ELFSIZE +#define ELF_MD_PROBE_FUNC ELFNAME2(aarch64_netbsd,probe) +#endif + +struct exec_package; + +int aarch64_netbsd_elf64_probe(struct lwp *, struct exec_package *, void *, + char *, vaddr_t *); +int aarch64_netbsd_elf32_probe(struct lwp *, struct exec_package *, void *, + char *, vaddr_t *); +#endif + +#elif defined(__arm__) + +#include <arm/elf_machdep.h> + +#endif + +#endif /* _AARCH64_ELF_MACHDEP_H_ */ diff --git a/cpukit/score/cpu/aarch64/include/rtems/score/cpu.h b/cpukit/score/cpu/aarch64/include/rtems/score/cpu.h index fdc0e3d929..47a8e97985 100644 --- a/cpukit/score/cpu/aarch64/include/rtems/score/cpu.h +++ b/cpukit/score/cpu/aarch64/include/rtems/score/cpu.h @@ -306,12 +306,6 @@ void _CPU_Initialize( void ); typedef void ( *CPU_ISR_handler )( void ); -void _CPU_ISR_install_vector( - uint32_t vector, - CPU_ISR_handler new_handler, - CPU_ISR_handler *old_handler -); - /** * @brief CPU switch context. */ diff --git a/cpukit/score/cpu/aarch64/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/aarch64/include/rtems/score/cpuimpl.h index ffdef2f30a..14836965ef 100644 --- a/cpukit/score/cpu/aarch64/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/aarch64/include/rtems/score/cpuimpl.h @@ -162,6 +162,15 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + __asm__ volatile ( + "msr TPIDR_EL0, %0" : : "r" ( context->thread_id ) : "memory" + ); +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/arm/aarch32-psma-init.c b/cpukit/score/cpu/arm/aarch32-psma-init.c index ee9338f050..543e1b7d9b 100644 --- a/cpukit/score/cpu/arm/aarch32-psma-init.c +++ b/cpukit/score/cpu/arm/aarch32-psma-init.c @@ -45,7 +45,7 @@ #include <rtems/score/aarch32-system-registers.h> #include <rtems/score/cpu.h> -#define AARCH32_PSMA_REGION_MAX \ +#define AARCH32_PMSA_REGION_MAX \ ( ( AARCH32_MPUIR_REGION_MASK >> AARCH32_MPUIR_REGION_SHIFT ) + 1 ) static void _AArch32_PMSA_Configure( @@ -133,16 +133,16 @@ size_t _AArch32_PMSA_Map_sections_to_regions( if ( attr == region_attr ) { uint32_t region_end; - if ( end == region_base ) { - /* Extend the region region */ + if ( end - region_base <= AARCH32_PMSA_MIN_REGION_ALIGN ) { + /* Extend the region */ regions[ ri ].base = base; break; } region_end = region_limit + AARCH32_PMSA_MIN_REGION_ALIGN; - if ( base == region_end ) { - /* Extend the region region */ + if ( region_end - base <= AARCH32_PMSA_MIN_REGION_ALIGN ) { + /* Extend the region */ regions[ ri ].limit = limit; break; } @@ -153,7 +153,7 @@ size_t _AArch32_PMSA_Map_sections_to_regions( } } - if ( end <= region_base ) { + if ( base <= region_base ) { size_t i; if ( region_used >= region_max ) { @@ -196,7 +196,7 @@ void _AArch32_PMSA_Initialize( size_t section_count ) { - AArch32_PMSA_Region regions[ AARCH32_PSMA_REGION_MAX ]; + AArch32_PMSA_Region regions[ AARCH32_PMSA_REGION_MAX ]; size_t region_max; size_t region_used; diff --git a/cpukit/score/cpu/arm/cpu.c b/cpukit/score/cpu/arm/cpu.c index 5c5b253470..b2cc6039b0 100644 --- a/cpukit/score/cpu/arm/cpu.c +++ b/cpukit/score/cpu/arm/cpu.c @@ -167,8 +167,10 @@ void _CPU_ISR_install_vector( CPU_ISR_handler *old_handler ) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" /* Redirection table starts at the end of the vector table */ - CPU_ISR_handler *table = (CPU_ISR_handler *) (MAX_EXCEPTIONS * 4); + CPU_ISR_handler volatile *table = (CPU_ISR_handler *) (MAX_EXCEPTIONS * 4); CPU_ISR_handler current_handler = table [vector]; @@ -181,6 +183,7 @@ void _CPU_ISR_install_vector( if (current_handler != new_handler) { table [vector] = new_handler; } +#pragma GCC diagnostic pop } void _CPU_Initialize( void ) diff --git a/cpukit/score/cpu/arm/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/arm/include/rtems/score/cpuimpl.h index 0ce347c86f..4f20113b71 100644 --- a/cpukit/score/cpu/arm/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/arm/include/rtems/score/cpuimpl.h @@ -160,6 +160,19 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ +#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER + __asm__ volatile ( + "mcr p15, 0, %0, c13, c0, 3" : : "r" ( context->thread_id ) : "memory" + ); +#else + (void) context; +#endif +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/bfin/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/bfin/include/rtems/score/cpuimpl.h index 1485abd365..91e57da4a0 100644 --- a/cpukit/score/cpu/bfin/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/bfin/include/rtems/score/cpuimpl.h @@ -59,6 +59,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h index 31ec0ac8bb..71f2679dde 100644 --- a/cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h @@ -80,6 +80,32 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + uint32_t tmp; + uint32_t cpu_index; + +#ifdef RTEMS_SMP + cpu_index = _CPU_SMP_Get_current_processor(); +#else + cpu_index = 0; +#endif + + __asm__ volatile ( + "movl " RTEMS_XSTRING( I386_CONTEXT_CONTROL_GS_0_OFFSET ) "(%2), %0\n" + "movl %0, _Global_descriptor_table+24(,%1,8)\n" + "movl " RTEMS_XSTRING( I386_CONTEXT_CONTROL_GS_1_OFFSET ) "(%2), %0\n" + "movl %0, _Global_descriptor_table+28(,%1,8)\n" + "leal 24(,%1,8), %0\n" + "movl %0, %%gs\n" + : "=&r" ( tmp ) + : "r" ( cpu_index ), "r" ( context ) + : "memory" + ); +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/lm32/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/lm32/include/rtems/score/cpuimpl.h index eb0c058723..24e8e5cb41 100644 --- a/cpukit/score/cpu/lm32/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/lm32/include/rtems/score/cpuimpl.h @@ -58,6 +58,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/m68k/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/m68k/include/rtems/score/cpuimpl.h index e3b61efd9f..5c7c35943a 100644 --- a/cpukit/score/cpu/m68k/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/m68k/include/rtems/score/cpuimpl.h @@ -78,6 +78,17 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + /* + * There is nothing to do since the thread-local storage area is obtained by + * calling __m68k_read_tp(). + */ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/microblaze/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/microblaze/include/rtems/score/cpuimpl.h index 0573759d52..e4f0303ad8 100644 --- a/cpukit/score/cpu/microblaze/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/microblaze/include/rtems/score/cpuimpl.h @@ -86,6 +86,17 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + /* + * There is nothing to do since the thread-local storage area is obtained by + * calling __tls_get_addr(). + */ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/mips/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/mips/include/rtems/score/cpuimpl.h index 0568134351..23d3f35960 100644 --- a/cpukit/score/cpu/mips/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/mips/include/rtems/score/cpuimpl.h @@ -78,6 +78,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/moxie/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/moxie/include/rtems/score/cpuimpl.h index 038a1326cc..a54824f16b 100644 --- a/cpukit/score/cpu/moxie/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/moxie/include/rtems/score/cpuimpl.h @@ -78,6 +78,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/nios2/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/nios2/include/rtems/score/cpuimpl.h index 215df68f67..518fac4308 100644 --- a/cpukit/score/cpu/nios2/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/nios2/include/rtems/score/cpuimpl.h @@ -70,6 +70,18 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + register uint32_t r23 __asm__( "r23" ); + + r23 = context->r23; + + /* Make sure that the register assignment is not optimized away */ + __asm__ volatile ( "" : : "r" ( r23 ) ); +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/no_cpu/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/no_cpu/include/rtems/score/cpuimpl.h index 6f4abfcfc3..1eec4e6b7a 100644 --- a/cpukit/score/cpu/no_cpu/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/no_cpu/include/rtems/score/cpuimpl.h @@ -166,6 +166,23 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +/** + * @brief Uses the thread-local storage area of the context. + * + * Some architectures may use dedicated registers to reference the thread-local + * storage area of the associated thread. This function should set these + * registers to the values defined by the specified processor context. + * + * @param context is the processor context defining the thread-local storage + * area to use. + */ +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/or1k/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/or1k/include/rtems/score/cpuimpl.h index 37cd1db436..35d186990d 100644 --- a/cpukit/score/cpu/or1k/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/or1k/include/rtems/score/cpuimpl.h @@ -70,6 +70,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "l.nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/or1k/include/rtems/score/or1k-utility.h b/cpukit/score/cpu/or1k/include/rtems/score/or1k-utility.h index c7618c9355..58db24fbbd 100644 --- a/cpukit/score/cpu/or1k/include/rtems/score/or1k-utility.h +++ b/cpukit/score/cpu/or1k/include/rtems/score/or1k-utility.h @@ -345,7 +345,7 @@ static inline uint32_t _OR1K_mfspr(uint32_t reg) { uint32_t spr_value; - asm volatile ( + __asm__ volatile ( "l.mfspr %0, %1, 0;\n\t" : "=r" (spr_value) : "r" (reg)); @@ -354,7 +354,7 @@ static inline uint32_t _OR1K_mfspr(uint32_t reg) static inline void _OR1K_mtspr(uint32_t reg, uint32_t value) { - asm volatile ( + __asm__ volatile ( "l.mtspr %1, %0, 0;\n\t" :: "r" (value), "r" (reg) ); @@ -386,12 +386,12 @@ static inline void _OR1K_mtspr(uint32_t reg, uint32_t value) static inline void _OR1K_Sync_mem( void ) { - asm volatile("l.msync"); + __asm__ volatile("l.msync"); } static inline void _OR1K_Sync_pipeline( void ) { - asm volatile("l.psync"); + __asm__ volatile("l.psync"); } /** @@ -402,7 +402,7 @@ static inline void _OR1K_Sync_pipeline( void ) * */ #define _OR1KSIM_CPU_Halt() \ - asm volatile ("l.nop 0xc") + __asm__ volatile ("l.nop 0xc") #ifdef __cplusplus } diff --git a/cpukit/score/cpu/powerpc/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/powerpc/include/rtems/score/cpuimpl.h index cfed43ced4..4a88fe18b1 100644 --- a/cpukit/score/cpu/powerpc/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/powerpc/include/rtems/score/cpuimpl.h @@ -283,6 +283,22 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ +#ifdef __powerpc64__ + register uintptr_t tp __asm__( "13" ); +#else + register uintptr_t tp __asm__( "2" ); +#endif + + tp = ppc_get_context( context )->tp; + + /* Make sure that the register assignment is not optimized away */ + __asm__ volatile ( "" : : "r" ( tp ) ); +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/riscv/include/libcpu/byteorder.h b/cpukit/score/cpu/riscv/include/libcpu/byteorder.h index 939e51fe84..1b4f6f3b1e 100644 --- a/cpukit/score/cpu/riscv/include/libcpu/byteorder.h +++ b/cpukit/score/cpu/riscv/include/libcpu/byteorder.h @@ -7,6 +7,8 @@ #ifndef _LIBCPU_BYTEORDER_H #define _LIBCPU_BYTEORDER_H +#include <stdint.h> + static inline void st_le32(volatile uint32_t *addr, uint32_t value) { *(addr)=value ; diff --git a/cpukit/score/cpu/riscv/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/riscv/include/rtems/score/cpuimpl.h index 5162cbbd51..ca09832d0e 100644 --- a/cpukit/score/cpu/riscv/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/riscv/include/rtems/score/cpuimpl.h @@ -430,6 +430,18 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + register uintptr_t tp __asm__( "tp" ); + + tp = context->tp; + + /* Make sure that the register assignment is not optimized away */ + __asm__ volatile ( "" : : "r" ( tp ) ); +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/sh/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/sh/include/rtems/score/cpuimpl.h index 745a185d1a..cb20bab616 100644 --- a/cpukit/score/cpu/sh/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/sh/include/rtems/score/cpuimpl.h @@ -59,6 +59,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h index 7197eb960e..2a200be7e3 100644 --- a/cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h @@ -234,6 +234,18 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + register uint32_t g7 __asm__( "g7" ); + + g7 = context->g7; + + /* Make sure that the register assignment is not optimized away */ + __asm__ volatile ( "" : : "r" ( g7 ) ); +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/sparc64/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/sparc64/include/rtems/score/cpuimpl.h index c026687d01..23aed1a8d6 100644 --- a/cpukit/score/cpu/sparc64/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/sparc64/include/rtems/score/cpuimpl.h @@ -78,6 +78,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/v850/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/v850/include/rtems/score/cpuimpl.h index 23c1437ba0..8f73b45ad6 100644 --- a/cpukit/score/cpu/v850/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/v850/include/rtems/score/cpuimpl.h @@ -78,6 +78,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/cpu/x86_64/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/x86_64/include/rtems/score/cpuimpl.h index d3a4b848e6..680c61ae20 100644 --- a/cpukit/score/cpu/x86_64/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/x86_64/include/rtems/score/cpuimpl.h @@ -62,6 +62,13 @@ RTEMS_INLINE_ROUTINE void _CPU_Instruction_no_operation( void ) __asm__ volatile ( "nop" ); } +RTEMS_INLINE_ROUTINE void _CPU_Use_thread_local_storage( + const Context_Control *context +) +{ + (void) context; +} + #ifdef __cplusplus } #endif diff --git a/cpukit/score/src/gcovdumpinfo.c b/cpukit/score/src/gcovdumpinfo.c new file mode 100644 index 0000000000..8598fce578 --- /dev/null +++ b/cpukit/score/src/gcovdumpinfo.c @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreIO + * + * @brief This source file contains the implementation of _Gcov_Ddump_info(). + */ + +/* + * Copyright (C) 2021, 2022 embedded brains GmbH + * + * 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/score/gcov.h> + +typedef struct { + IO_Put_char put_char; + void *arg; +} Gcov_Context; + +static void _Gcov_Dump( const void *data, unsigned length, void *arg ) +{ + Gcov_Context *ctx; + IO_Put_char put_char; + void *ctx_arg; + const char *in; + const void *end; + + ctx = arg; + in = data; + end = in + length; + put_char = ctx->put_char; + ctx_arg = ctx->arg; + + while ( in != end ) { + ( *put_char )( *in, ctx_arg ); + ++in; + } +} + +static void _Gcov_Filename( const char *filename, void *arg ) +{ + __gcov_filename_to_gcfn( filename, _Gcov_Dump, arg ); +} + +static void *_Gcov_Allocate( unsigned length, void *arg ) +{ + (void) length; + (void) arg; + return NULL; +} + +void _Gcov_Dump_info( IO_Put_char put_char, void *arg ) +{ + Gcov_Context ctx; + const struct gcov_info * const *item; + + ctx.put_char = put_char; + ctx.arg = arg; + + RTEMS_LINKER_SET_FOREACH( gcov_info, item ) { + __gcov_info_to_gcda( + *item, + _Gcov_Filename, + _Gcov_Dump, + _Gcov_Allocate, + &ctx + ); + } +} diff --git a/cpukit/score/src/gcovdumpinfobase64.c b/cpukit/score/src/gcovdumpinfobase64.c new file mode 100644 index 0000000000..be07f03291 --- /dev/null +++ b/cpukit/score/src/gcovdumpinfobase64.c @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreIO + * + * @brief This source file contains the implementation of + * _Gcov_Dump_info_base64(). + */ + +/* + * Copyright (C) 2021, 2022 embedded brains GmbH + * + * 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/score/gcov.h> + +#include <limits.h> +#include <string.h> + +typedef struct { + IO_Put_char put_char; + void *arg; + int out; + size_t index; + char buf[ 57 ]; +} Gcov_Base64_context; + +static void _Gcov_Base64_put_char( int c, void *arg ) +{ + Gcov_Base64_context *ctx; + + ctx = arg; + + ( *ctx->put_char )( c, ctx->arg ); + ++ctx->out; + + if ( ctx->out >= 76 ) { + ctx->out = 0; + ( *ctx->put_char )( '\n', ctx->arg ); + } +} + +static void _Gcov_Base64_encode( int c, void *arg ) +{ + Gcov_Base64_context *ctx; + size_t index; + + ctx = arg; + index = ctx->index; + ctx->buf[ index ] = (char) c; + + if ( index == RTEMS_ARRAY_SIZE( ctx->buf ) - 1 ) { + index = 0; + _IO_Base64( + _Gcov_Base64_put_char, + ctx, + ctx->buf, + sizeof( ctx->buf ), + NULL, + INT_MAX + ); + } else { + ++index; + } + + ctx->index = index; +} + +void _Gcov_Dump_info_base64( IO_Put_char put_char, void *arg ) +{ + Gcov_Base64_context ctx; + + memset( &ctx, 0, sizeof( ctx ) ); + ctx.put_char = put_char; + ctx.arg = arg; + _Gcov_Dump_info( _Gcov_Base64_encode, &ctx ); + _IO_Base64( _Gcov_Base64_put_char, &ctx, ctx.buf, ctx.index, NULL, INT_MAX ); +} diff --git a/cpukit/score/src/gcovinfoset.c b/cpukit/score/src/gcovinfoset.c new file mode 100644 index 0000000000..6fd695043b --- /dev/null +++ b/cpukit/score/src/gcovinfoset.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreIO + * + * @brief This source file contains the definition of the gcov information + * linker set. + */ + +/* + * Copyright (C) 2021, 2022 embedded brains GmbH + * + * 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/score/gcov.h> + +RTEMS_LINKER_ROSET( gcov_info, const struct gcov_info * ); diff --git a/cpukit/score/src/kern_ntptime.c b/cpukit/score/src/kern_ntptime.c index cb39133408..1233166a61 100644 --- a/cpukit/score/src/kern_ntptime.c +++ b/cpukit/score/src/kern_ntptime.c @@ -58,6 +58,9 @@ __FBSDID("$FreeBSD$"); #include <sys/time.h> #include <sys/timex.h> #include <sys/timetc.h> +#ifdef __rtems__ +#define _KERNEL +#endif /* __rtems__ */ #include <sys/timepps.h> #ifndef __rtems__ #include <sys/syscallsubr.h> @@ -71,11 +74,31 @@ __FBSDID("$FreeBSD$"); #define ntp_update_second _Timecounter_NTP_update_second #define time_uptime _Timecounter_Time_uptime struct thread; + +static inline long +lmax(long a, long b) +{ + + if (a > b) + return (a); + return (b); +} + +static inline quad_t +qmin(quad_t a, quad_t b) +{ + + if (a < b) + return (a); + return (b); +} #endif /* __rtems__ */ +#ifndef __rtems__ #ifdef PPS_SYNC FEATURE(pps_sync, "Support usage of external PPS signal by kernel PLL"); #endif +#endif /* __rtems__ */ /* * Single-precision macros for 64-bit machines @@ -374,7 +397,6 @@ SYSCTL_NODE(_kern, OID_AUTO, ntp_pll, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, SYSCTL_PROC(_kern_ntp_pll, OID_AUTO, gettime, CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval", ""); -#endif /* __rtems__ */ #ifdef PPS_SYNC SYSCTL_INT(_kern_ntp_pll, OID_AUTO, pps_shiftmax, CTLFLAG_RW, @@ -391,6 +413,7 @@ SYSCTL_S64(_kern_ntp_pll, OID_AUTO, time_freq, CTLFLAG_RD | CTLFLAG_MPSAFE, &time_freq, 0, "Frequency offset (ns/sec)"); #endif +#endif /* __rtems__ */ /* * ntp_adjtime() - NTP daemon application interface @@ -531,16 +554,6 @@ kern_ntp_adjtime(struct thread *td, struct timex *ntv, int *retvalp) ntv->jitcnt = pps_jitcnt; ntv->stbcnt = pps_stbcnt; #endif /* PPS_SYNC */ -#ifdef __rtems__ - ntv->ppsfreq = 0; - ntv->jitter = 0; - ntv->shift = 0; - ntv->stabil = 0; - ntv->jitcnt = 0; - ntv->calcnt = 0; - ntv->errcnt = 0; - ntv->stbcnt = 0; -#endif /* __rtems__ */ retval = ntp_is_time_error(time_status) ? TIME_ERROR : time_state; NTP_UNLOCK(); diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c index e57da2c0ca..643026a1c8 100644 --- a/cpukit/score/src/kern_tc.c +++ b/cpukit/score/src/kern_tc.c @@ -56,12 +56,17 @@ #define timecounter _Timecounter #define time_second _Timecounter_Time_second #define time_uptime _Timecounter_Time_uptime + #include <rtems/score/timecounterimpl.h> +#include <rtems/score/assert.h> #include <rtems/score/atomic.h> #include <rtems/score/smp.h> #include <rtems/score/todimpl.h> #include <rtems/score/watchdogimpl.h> #include <rtems/rtems/clock.h> + +#define ENOIOCTL EINVAL +#define KASSERT(exp, arg) _Assert(exp) #endif /* __rtems__ */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -90,6 +95,7 @@ __FBSDID("$FreeBSD$"); #include <sys/vdso.h> #endif /* __rtems__ */ #ifdef __rtems__ +#include <errno.h> #include <limits.h> #include <string.h> #include <rtems.h> @@ -115,6 +121,13 @@ atomic_thread_fence_rel(void) } static inline u_int +atomic_load_int(Atomic_Uint *i) +{ + + return (_Atomic_Load_uint(i, ATOMIC_ORDER_RELAXED)); +} + +static inline u_int atomic_load_acq_int(Atomic_Uint *i) { @@ -1506,7 +1519,6 @@ unlock: #endif /* __rtems__ */ } -#ifndef __rtems__ /* Report the frequency of the current timecounter. */ uint64_t tc_getfrequency(void) @@ -1515,6 +1527,7 @@ tc_getfrequency(void) return (timehands->th_counter->tc_frequency); } +#ifndef __rtems__ static bool sleeping_on_old_rtc(struct thread *td) { @@ -1891,7 +1904,6 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, "Timecounter hardware detected"); #endif /* __rtems__ */ -#ifndef __rtems__ /* * RFC 2783 PPS-API implementation. */ @@ -1910,9 +1922,15 @@ abi_aware(struct pps_state *pps, int vers) static int pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps) { +#ifndef __rtems__ int err, timo; +#else /* __rtems__ */ + int err; +#endif /* __rtems__ */ pps_seq_t aseq, cseq; +#ifndef __rtems__ struct timeval tv; +#endif /* __rtems__ */ if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) return (EINVAL); @@ -1925,6 +1943,7 @@ pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps) * sleep a long time. */ if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) { +#ifndef __rtems__ if (fapi->timeout.tv_sec == -1) timo = 0x7fffffff; else { @@ -1932,10 +1951,12 @@ pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps) tv.tv_usec = fapi->timeout.tv_nsec / 1000; timo = tvtohz(&tv); } +#endif /* __rtems__ */ aseq = atomic_load_int(&pps->ppsinfo.assert_sequence); cseq = atomic_load_int(&pps->ppsinfo.clear_sequence); while (aseq == atomic_load_int(&pps->ppsinfo.assert_sequence) && cseq == atomic_load_int(&pps->ppsinfo.clear_sequence)) { +#ifndef __rtems__ if (abi_aware(pps, 1) && pps->driver_mtx != NULL) { if (pps->flags & PPSFLAG_MTX_SPIN) { err = msleep_spin(pps, pps->driver_mtx, @@ -1956,6 +1977,12 @@ pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps) } else if (err != 0) { return (err); } +#else /* __rtems__ */ + _Assert(pps->wait != NULL); + err = (*pps->wait)(pps, fapi->timeout); + if (err != 0) + return (err); +#endif /* __rtems__ */ } } @@ -2051,9 +2078,43 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) } } +#ifdef __rtems__ +/* + * The real implementation of hardpps() is defined in kern_ntptime.c. Use it + * only if the NTP support is needed by the application. + */ +RTEMS_WEAK void +hardpps(struct timespec *tsp, long nsec) +{ + + (void)tsp; + (void)nsec; +} + +static int +default_wait(struct pps_state *pps, struct timespec timeout) +{ + + (void)pps; + (void)timeout; + + return (ETIMEDOUT); +} + +static void +default_wakeup(struct pps_state *pps) +{ + + (void)pps; +} +#endif /* __rtems__ */ void pps_init(struct pps_state *pps) { +#ifdef __rtems__ + pps->wait = default_wait; + pps->wakeup = default_wakeup; +#endif /* __rtems__ */ pps->ppscap |= PPS_TSFMT_TSPEC | PPS_CANWAIT; if (pps->ppscap & PPS_CAPTUREASSERT) pps->ppscap |= PPS_OFFSETASSERT; @@ -2089,9 +2150,11 @@ pps_capture(struct pps_state *pps) pps->capffth = fftimehands; #endif pps->capcount = th->th_counter->tc_get_timecount(th->th_counter); +#if defined(RTEMS_SMP) atomic_thread_fence_acq(); if (pps->capgen != th->th_generation) pps->capgen = 0; +#endif } void @@ -2116,7 +2179,11 @@ pps_event(struct pps_state *pps, int event) if ((event & pps->ppsparam.mode) == 0) return; /* If the timecounter was wound up underneath us, bail out. */ +#if defined(RTEMS_SMP) if (pps->capgen == 0 || pps->capgen != +#else + if (pps->capgen != +#endif atomic_load_acq_int(&pps->capth->th_generation)) return; @@ -2220,11 +2287,13 @@ pps_event(struct pps_state *pps, int event) #endif /* Wakeup anyone sleeping in pps_fetch(). */ +#ifndef __rtems__ wakeup(pps); -} #else /* __rtems__ */ -/* FIXME: https://devel.rtems.org/ticket/2349 */ + _Assert(pps->wakeup != NULL); + (*pps->wakeup)(pps); #endif /* __rtems__ */ +} /* * Timecounters need to be updated every so often to prevent the hardware @@ -2260,9 +2329,13 @@ _Timecounter_Tick(void) { Per_CPU_Control *cpu_self = _Per_CPU_Get(); +#if defined(RTEMS_SMP) if (_Per_CPU_Is_boot_processor(cpu_self)) { +#endif tc_windup(NULL); +#if defined(RTEMS_SMP) } +#endif _Watchdog_Tick(cpu_self); } diff --git a/cpukit/score/src/memorydirtyfreeareas.c b/cpukit/score/src/memorydirtyfreeareas.c index fc6c2630bf..8a817c2208 100644 --- a/cpukit/score/src/memorydirtyfreeareas.c +++ b/cpukit/score/src/memorydirtyfreeareas.c @@ -10,7 +10,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2020 embedded brains GmbH + * Copyright (C) 2020, 2022 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +40,14 @@ #include <rtems/score/memory.h> +#include <string.h> + void _Memory_Dirty_free_areas( void ) { _Memory_Fill( _Memory_Get(), 0xcf ); + memset( + _Memory_Noinit_begin, + 0xcf, + (uintptr_t) _Memory_Noinit_end - (uintptr_t) _Memory_Noinit_begin + ); } diff --git a/cpukit/score/src/memorynoinit.c b/cpukit/score/src/memorynoinit.c new file mode 100644 index 0000000000..19772356cd --- /dev/null +++ b/cpukit/score/src/memorynoinit.c @@ -0,0 +1,45 @@ +/** + * @file + * + * @ingroup RTEMSScoreMemory + * + * @brief This source file contains the definition of ::_Memory_Noinit_begin + * and ::_Memory_Noinit_end. + */ + +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2022 embedded brains GmbH + * + * 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/score/memory.h> + +RTEMS_SECTION( ".noinit.rtems.begin" ) char _Memory_Noinit_begin[ 0 ]; + +RTEMS_SECTION( ".noinit.rtems.end" ) char _Memory_Noinit_end[ 0 ]; diff --git a/cpukit/score/src/memoryzerofreeareas.c b/cpukit/score/src/memoryzerofreeareas.c index 4ea0812426..b1cef47ef9 100644 --- a/cpukit/score/src/memoryzerofreeareas.c +++ b/cpukit/score/src/memoryzerofreeareas.c @@ -10,7 +10,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2020 embedded brains GmbH + * Copyright (C) 2020, 2022 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +40,14 @@ #include <rtems/score/memory.h> +#include <string.h> + void _Memory_Zero_free_areas( void ) { _Memory_Fill( _Memory_Get(), 0 ); + memset( + _Memory_Noinit_begin, + 0, + (uintptr_t) _Memory_Noinit_end - (uintptr_t) _Memory_Noinit_begin + ); } diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c index 3b525a2066..458031c794 100644 --- a/cpukit/score/src/mpci.c +++ b/cpukit/score/src/mpci.c @@ -162,7 +162,7 @@ static void _MPCI_Create_server( void ) memset( &config, 0, sizeof( config ) ); config.scheduler = &_Scheduler_Table[ 0 ]; config.name = _Objects_Build_name( 'M', 'P', 'C', 'I' ); - config.priority = PRIORITY_PSEUDO_ISR; + config.priority = PRIORITY_MINIMUM; config.is_fp = CPU_ALL_TASKS_ARE_FP; config.stack_size = _Stack_Minimum() + _MPCI_Configuration.extra_mpci_receive_server_stack diff --git a/cpukit/score/src/objectactivecount.c b/cpukit/score/src/objectactivecount.c index 028058e473..5f0304fead 100644 --- a/cpukit/score/src/objectactivecount.c +++ b/cpukit/score/src/objectactivecount.c @@ -46,14 +46,22 @@ Objects_Maximum _Objects_Active_count( const Objects_Information *information ) { - Objects_Maximum inactive; - Objects_Maximum maximum; + Objects_Maximum active; + Objects_Maximum index; + Objects_Maximum maximum; + Objects_Control **local_table; _Assert( _Objects_Allocator_is_owner() ); - inactive = (Objects_Maximum) - _Chain_Node_count_unprotected( &information->Inactive ); + active = 0; maximum = _Objects_Get_maximum_index( information ); + local_table = information->local_table; - return maximum - inactive; + for ( index = 0; index < maximum; ++index ) { + if ( local_table[ index ] != NULL ) { + ++active; + } + } + + return active; } diff --git a/cpukit/score/src/objectfree.c b/cpukit/score/src/objectfree.c index 45b2ba2c86..06d7d82672 100644 --- a/cpukit/score/src/objectfree.c +++ b/cpukit/score/src/objectfree.c @@ -51,14 +51,16 @@ void _Objects_Free_unlimited( if ( _Objects_Is_auto_extend( information ) ) { Objects_Maximum objects_per_block; - Objects_Maximum block; - Objects_Maximum inactive; + Objects_Maximum index; objects_per_block = information->objects_per_block; - block = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM; + index = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM; - if ( block > objects_per_block ) { - block /= objects_per_block; + if ( _Objects_Is_in_allocated_block( index, objects_per_block ) ) { + Objects_Maximum block; + Objects_Maximum inactive; + + block = index / objects_per_block; ++information->inactive_per_block[ block ]; diff --git a/cpukit/score/src/rbtreemax.c b/cpukit/score/src/rbtreemax.c index 1b0e463aa2..f42e42043e 100644 --- a/cpukit/score/src/rbtreemax.c +++ b/cpukit/score/src/rbtreemax.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -8,7 +10,7 @@ */ /* - * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * Copyright (C) 2021 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/score/src/rbtreemin.c b/cpukit/score/src/rbtreemin.c index b3cd4331c1..86e5b6e5c9 100644 --- a/cpukit/score/src/rbtreemin.c +++ b/cpukit/score/src/rbtreemin.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -8,7 +10,7 @@ */ /* - * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * Copyright (C) 2021 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/score/src/rbtreenext.c b/cpukit/score/src/rbtreenext.c index 5d43af0068..a18b1cec2e 100644 --- a/cpukit/score/src/rbtreenext.c +++ b/cpukit/score/src/rbtreenext.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -9,7 +11,7 @@ */ /* - * Copyright (C) 2012 embedded brains GmbH (http://www.embedded-brains.de) + * Copyright (C) 2012 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/score/src/rbtreeprev.c b/cpukit/score/src/rbtreeprev.c index 9869cade99..c23910c085 100644 --- a/cpukit/score/src/rbtreeprev.c +++ b/cpukit/score/src/rbtreeprev.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -8,7 +10,7 @@ */ /* - * Copyright (C) 2012 embedded brains GmbH (http://www.embedded-brains.de) + * Copyright (C) 2012 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/cpukit/score/src/scheduleredfblock.c b/cpukit/score/src/scheduleredfblock.c index 56f7c9c021..cb7ab91450 100644 --- a/cpukit/score/src/scheduleredfblock.c +++ b/cpukit/score/src/scheduleredfblock.c @@ -47,11 +47,11 @@ void _Scheduler_EDF_Block( Scheduler_Node *node ) { - _Scheduler_Generic_block( + _Scheduler_uniprocessor_Block( scheduler, the_thread, node, _Scheduler_EDF_Extract_body, - _Scheduler_EDF_Schedule_body + _Scheduler_EDF_Get_highest_ready ); } diff --git a/cpukit/score/src/scheduleredfchangepriority.c b/cpukit/score/src/scheduleredfchangepriority.c index 26ce1c348f..de17ca0fad 100644 --- a/cpukit/score/src/scheduleredfchangepriority.c +++ b/cpukit/score/src/scheduleredfchangepriority.c @@ -71,5 +71,8 @@ void _Scheduler_EDF_Update_priority( _Scheduler_EDF_Extract( context, the_node ); _Scheduler_EDF_Enqueue( context, the_node, insert_priority ); - _Scheduler_EDF_Schedule_body( scheduler, the_thread, false ); + _Scheduler_uniprocessor_Schedule( + scheduler, + _Scheduler_EDF_Get_highest_ready + ); } diff --git a/cpukit/score/src/scheduleredfschedule.c b/cpukit/score/src/scheduleredfschedule.c index d0acea7a30..40c5ab2c06 100644 --- a/cpukit/score/src/scheduleredfschedule.c +++ b/cpukit/score/src/scheduleredfschedule.c @@ -46,5 +46,8 @@ void _Scheduler_EDF_Schedule( Thread_Control *the_thread ) { - _Scheduler_EDF_Schedule_body( scheduler, the_thread, false ); + _Scheduler_uniprocessor_Schedule( + scheduler, + _Scheduler_EDF_Get_highest_ready + ); } diff --git a/cpukit/score/src/scheduleredfunblock.c b/cpukit/score/src/scheduleredfunblock.c index d6604686e3..4638eedf71 100644 --- a/cpukit/score/src/scheduleredfunblock.c +++ b/cpukit/score/src/scheduleredfunblock.c @@ -62,23 +62,5 @@ void _Scheduler_EDF_Unblock( the_node->priority = priority; _Scheduler_EDF_Enqueue( context, the_node, insert_priority ); - - /* - * If the thread that was unblocked is more important than the heir, - * then we have a new heir. This may or may not result in a - * context switch. - * - * Normal case: - * If the current thread is preemptible, then we need to do - * a context switch. - * Pseudo-ISR case: - * Even if the thread isn't preemptible, if the new heir is - * a pseudo-ISR system task, we need to do a context switch. - */ - if ( priority < _Thread_Get_priority( _Thread_Heir ) ) { - _Scheduler_Update_heir( - the_thread, - priority == ( SCHEDULER_EDF_PRIO_MSB | PRIORITY_PSEUDO_ISR ) - ); - } + _Scheduler_uniprocessor_Unblock( scheduler, the_thread, priority ); } diff --git a/cpukit/score/src/scheduleredfyield.c b/cpukit/score/src/scheduleredfyield.c index d83e1d9268..d38bea705a 100644 --- a/cpukit/score/src/scheduleredfyield.c +++ b/cpukit/score/src/scheduleredfyield.c @@ -55,5 +55,5 @@ void _Scheduler_EDF_Yield( _Scheduler_EDF_Extract( context, the_node ); _Scheduler_EDF_Enqueue( context, the_node, the_node->priority ); - _Scheduler_EDF_Schedule_body( scheduler, the_thread, true ); + _Scheduler_uniprocessor_Yield( scheduler, _Scheduler_EDF_Get_highest_ready ); } diff --git a/cpukit/score/src/schedulerpriorityblock.c b/cpukit/score/src/schedulerpriorityblock.c index 53636940dc..ffc7a3ad86 100644 --- a/cpukit/score/src/schedulerpriorityblock.c +++ b/cpukit/score/src/schedulerpriorityblock.c @@ -49,11 +49,11 @@ void _Scheduler_priority_Block( Scheduler_Node *node ) { - _Scheduler_Generic_block( + _Scheduler_uniprocessor_Block( scheduler, the_thread, node, _Scheduler_priority_Extract_body, - _Scheduler_priority_Schedule_body + _Scheduler_priority_Get_highest_ready ); } diff --git a/cpukit/score/src/schedulerprioritychangepriority.c b/cpukit/score/src/schedulerprioritychangepriority.c index 8a059763de..3588a2ce42 100644 --- a/cpukit/score/src/schedulerprioritychangepriority.c +++ b/cpukit/score/src/schedulerprioritychangepriority.c @@ -96,5 +96,8 @@ void _Scheduler_priority_Update_priority( ); } - _Scheduler_priority_Schedule_body( scheduler, the_thread, false ); + _Scheduler_uniprocessor_Schedule( + scheduler, + _Scheduler_priority_Get_highest_ready + ); } diff --git a/cpukit/score/src/schedulerpriorityschedule.c b/cpukit/score/src/schedulerpriorityschedule.c index bde749f9bc..bb7cf87399 100644 --- a/cpukit/score/src/schedulerpriorityschedule.c +++ b/cpukit/score/src/schedulerpriorityschedule.c @@ -46,5 +46,8 @@ void _Scheduler_priority_Schedule( Thread_Control *the_thread ) { - _Scheduler_priority_Schedule_body( scheduler, the_thread, false ); + _Scheduler_uniprocessor_Schedule( + scheduler, + _Scheduler_priority_Get_highest_ready + ); } diff --git a/cpukit/score/src/schedulerpriorityunblock.c b/cpukit/score/src/schedulerpriorityunblock.c index 190c126908..f9b6cabff7 100644 --- a/cpukit/score/src/schedulerpriorityunblock.c +++ b/cpukit/score/src/schedulerpriorityunblock.c @@ -76,19 +76,5 @@ void _Scheduler_priority_Unblock ( /* TODO: flash critical section? */ - /* - * If the thread that was unblocked is more important than the heir, - * then we have a new heir. This may or may not result in a - * context switch. - * - * Normal case: - * If the current thread is preemptible, then we need to do - * a context switch. - * Pseudo-ISR case: - * Even if the thread isn't preemptible, if the new heir is - * a pseudo-ISR system task, we need to do a context switch. - */ - if ( priority < _Thread_Get_priority( _Thread_Heir ) ) { - _Scheduler_Update_heir( the_thread, priority == PRIORITY_PSEUDO_ISR ); - } + _Scheduler_uniprocessor_Unblock( scheduler, the_thread, priority ); } diff --git a/cpukit/score/src/schedulerpriorityyield.c b/cpukit/score/src/schedulerpriorityyield.c index 77fcecc418..adb443df94 100644 --- a/cpukit/score/src/schedulerpriorityyield.c +++ b/cpukit/score/src/schedulerpriorityyield.c @@ -59,5 +59,8 @@ void _Scheduler_priority_Yield( _Chain_Append_unprotected( ready_chain, &the_thread->Object.Node ); } - _Scheduler_priority_Schedule_body( scheduler, the_thread, true ); + _Scheduler_uniprocessor_Yield( + scheduler, + _Scheduler_priority_Get_highest_ready + ); } diff --git a/cpukit/score/src/schedulersimpleblock.c b/cpukit/score/src/schedulersimpleblock.c index a8229d409f..dfd18df3a2 100644 --- a/cpukit/score/src/schedulersimpleblock.c +++ b/cpukit/score/src/schedulersimpleblock.c @@ -47,11 +47,11 @@ void _Scheduler_simple_Block( Scheduler_Node *node ) { - _Scheduler_Generic_block( + _Scheduler_uniprocessor_Block( scheduler, the_thread, node, _Scheduler_simple_Extract, - _Scheduler_simple_Schedule_body + _Scheduler_simple_Get_highest_ready ); } diff --git a/cpukit/score/src/schedulersimplechangepriority.c b/cpukit/score/src/schedulersimplechangepriority.c index b4711dfd01..5c53c96fb3 100644 --- a/cpukit/score/src/schedulersimplechangepriority.c +++ b/cpukit/score/src/schedulersimplechangepriority.c @@ -60,5 +60,8 @@ void _Scheduler_simple_Update_priority( _Scheduler_simple_Extract( scheduler, the_thread, node ); _Scheduler_simple_Insert( &context->Ready, the_thread, new_priority ); - _Scheduler_simple_Schedule_body( scheduler, the_thread, false ); + _Scheduler_uniprocessor_Schedule( + scheduler, + _Scheduler_simple_Get_highest_ready + ); } diff --git a/cpukit/score/src/schedulersimpleschedule.c b/cpukit/score/src/schedulersimpleschedule.c index 4108fdaee8..83a3fed7fe 100644 --- a/cpukit/score/src/schedulersimpleschedule.c +++ b/cpukit/score/src/schedulersimpleschedule.c @@ -46,5 +46,8 @@ void _Scheduler_simple_Schedule( Thread_Control *the_thread ) { - _Scheduler_simple_Schedule_body( scheduler, the_thread, false ); + _Scheduler_uniprocessor_Schedule( + scheduler, + _Scheduler_simple_Get_highest_ready + ); } diff --git a/cpukit/score/src/schedulersimpleunblock.c b/cpukit/score/src/schedulersimpleunblock.c index 7791503d7a..436f20ac38 100644 --- a/cpukit/score/src/schedulersimpleunblock.c +++ b/cpukit/score/src/schedulersimpleunblock.c @@ -58,23 +58,5 @@ void _Scheduler_simple_Unblock( priority = _Thread_Get_priority( the_thread ); insert_priority = SCHEDULER_PRIORITY_APPEND( priority ); _Scheduler_simple_Insert( &context->Ready, the_thread, insert_priority ); - - /* - * If the thread that was unblocked is more important than the heir, - * then we have a new heir. This may or may not result in a - * context switch. - * - * Normal case: - * If the current thread is preemptible, then we need to do - * a context switch. - * Pseudo-ISR case: - * Even if the thread isn't preemptible, if the new heir is - * a pseudo-ISR system task, we need to do a context switch. - */ - if ( priority < _Thread_Get_priority( _Thread_Heir ) ) { - _Scheduler_Update_heir( - the_thread, - priority == PRIORITY_PSEUDO_ISR - ); - } + _Scheduler_uniprocessor_Unblock( scheduler, the_thread, priority ); } diff --git a/cpukit/score/src/schedulersimpleyield.c b/cpukit/score/src/schedulersimpleyield.c index c25cceb8a7..ed8dd5b4cc 100644 --- a/cpukit/score/src/schedulersimpleyield.c +++ b/cpukit/score/src/schedulersimpleyield.c @@ -58,5 +58,8 @@ void _Scheduler_simple_Yield( insert_priority = (unsigned int) _Thread_Get_priority( the_thread ); insert_priority = SCHEDULER_PRIORITY_APPEND( insert_priority ); _Scheduler_simple_Insert( &context->Ready, the_thread, insert_priority ); - _Scheduler_simple_Schedule_body( scheduler, the_thread, false ); + _Scheduler_uniprocessor_Yield( + scheduler, + _Scheduler_simple_Get_highest_ready + ); } diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c index 321bb15cab..0ddfd1cf9b 100644 --- a/cpukit/score/src/threadchangepriority.c +++ b/cpukit/score/src/threadchangepriority.c @@ -135,11 +135,15 @@ static void _Thread_Priority_do_perform_actions( priority_aggregation = _Priority_Actions_move( &queue_context->Priority.Actions ); do { +#if defined(RTEMS_SMP) Priority_Aggregation *next_aggregation; +#endif Priority_Node *priority_action_node; Priority_Action_type priority_action_type; +#if defined(RTEMS_SMP) next_aggregation = _Priority_Get_next_action( priority_aggregation ); +#endif priority_action_node = priority_aggregation->Action.node; priority_action_type = priority_aggregation->Action.type; @@ -198,8 +202,12 @@ static void _Thread_Priority_do_perform_actions( break; } +#if defined(RTEMS_SMP) priority_aggregation = next_aggregation; - } while ( _Priority_Actions_is_valid( priority_aggregation ) ); + } while ( priority_aggregation != NULL ); +#else + } while ( false ); +#endif if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) { _Thread_queue_Context_add_priority_update( queue_context, the_thread ); @@ -352,6 +360,7 @@ void _Thread_Priority_changed( ); } +#if defined(RTEMS_SMP) void _Thread_Priority_replace( Thread_Control *the_thread, Priority_Node *victim_node, @@ -367,6 +376,7 @@ void _Thread_Priority_replace( replacement_node ); } +#endif void _Thread_Priority_update( Thread_queue_Context *queue_context ) { diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c index 9f3c01d118..b5e0cfdc9b 100644 --- a/cpukit/score/src/threadcreateidle.c +++ b/cpukit/score/src/threadcreateidle.c @@ -40,6 +40,7 @@ #endif #include <rtems/score/threadidledata.h> +#include <rtems/score/cpuimpl.h> #include <rtems/score/threadimpl.h> #include <rtems/score/assert.h> #include <rtems/score/schedulerimpl.h> @@ -111,10 +112,10 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu ) void _Thread_Create_idle( void ) { +#if defined(RTEMS_SMP) uint32_t cpu_max; uint32_t cpu_index; - _System_state_Set( SYSTEM_STATE_BEFORE_MULTITASKING ); cpu_max = _SMP_Get_processor_maximum(); for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) { @@ -124,4 +125,12 @@ void _Thread_Create_idle( void ) _Thread_Create_idle_for_CPU( cpu ); } } +#else + _Thread_Create_idle_for_CPU( _Per_CPU_Get() ); +#endif + + _CPU_Use_thread_local_storage( + &_Per_CPU_Get_executing( _Per_CPU_Get() )->Registers + ); + _System_state_Set( SYSTEM_STATE_BEFORE_MULTITASKING ); } diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 457fdaa54a..9b37206c6d 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -298,6 +298,7 @@ static bool _Thread_Try_initialize( the_thread->Start.is_preemptible = config->is_preemptible; the_thread->Start.cpu_budget_operations = config->cpu_budget_operations; the_thread->Start.stack_free = config->stack_free; + the_thread->Join_queue.Queue.owner = the_thread; _Thread_Timer_initialize( &the_thread->Timer, cpu ); _Thread_Initialize_scheduler_and_wait_nodes( the_thread, config ); diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c index 33fc5a44cb..fbea9f6de6 100644 --- a/cpukit/score/src/threadqops.c +++ b/cpukit/score/src/threadqops.c @@ -404,8 +404,12 @@ static void _Thread_queue_Priority_priority_actions( break; } +#if defined(RTEMS_SMP) priority_aggregation = _Priority_Get_next_action( priority_aggregation ); - } while ( _Priority_Actions_is_valid( priority_aggregation ) ); + } while ( priority_aggregation != NULL ); +#else + } while ( false ); +#endif } static void _Thread_queue_Priority_do_initialize( @@ -734,14 +738,18 @@ static void _Thread_queue_Priority_inherit_priority_actions( priority_aggregation = _Priority_Actions_move( priority_actions ); do { +#if defined(RTEMS_SMP) Priority_Aggregation *next_aggregation; +#endif Scheduler_Node *scheduler_node; size_t scheduler_index; Thread_queue_Priority_queue *priority_queue; Scheduler_Node *scheduler_node_of_owner; Priority_Action_type priority_action_type; +#if defined(RTEMS_SMP) next_aggregation = _Priority_Get_next_action( priority_aggregation ); +#endif scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ); scheduler_index = _Thread_queue_Scheduler_index( scheduler_node ); @@ -797,8 +805,12 @@ static void _Thread_queue_Priority_inherit_priority_actions( break; } +#if defined(RTEMS_SMP) priority_aggregation = next_aggregation; - } while ( _Priority_Actions_is_valid( priority_aggregation ) ); + } while ( priority_aggregation != NULL ); +#else + } while ( false ); +#endif } static void _Thread_queue_Priority_inherit_do_initialize( diff --git a/cpukit/score/src/threadqtimeout.c b/cpukit/score/src/threadqtimeout.c index 271ea27f27..10e194f6d8 100644 --- a/cpukit/score/src/threadqtimeout.c +++ b/cpukit/score/src/threadqtimeout.c @@ -132,7 +132,7 @@ void _Thread_queue_Add_timeout_monotonic_timespec( { struct timespec now; - _Timecounter_Getnanouptime( &now ); + _Timecounter_Nanouptime( &now ); _Thread_queue_Add_timeout_timespec( queue, the_thread, @@ -152,7 +152,7 @@ void _Thread_queue_Add_timeout_realtime_timespec( { struct timespec now; - _Timecounter_Getnanotime( &now ); + _Timecounter_Nanotime( &now ); _Thread_queue_Add_timeout_timespec( queue, the_thread, diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index 25f57e2a40..635143427c 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -14,7 +14,7 @@ * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * - * Copyright (c) 2014, 2021 embedded brains GmbH. + * Copyright (C) 2014, 2022 embedded brains GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,7 +55,9 @@ #include <rtems/score/userextimpl.h> #include <rtems/score/watchdogimpl.h> -#define THREAD_JOIN_TQ_OPERATIONS &_Thread_queue_Operations_priority +#include <pthread.h> + +#define THREAD_JOIN_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit static void _Thread_Life_action_handler( Thread_Control *executing, @@ -70,31 +72,6 @@ Thread_Zombie_registry _Thread_Zombies = { .Chain = CHAIN_INITIALIZER_EMPTY( _Thread_Zombies.Chain ) }; -static void _Thread_Raise_real_priority( - Thread_Control *the_thread, - Priority_Control priority -) -{ - Thread_queue_Context queue_context; - - _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_clear_priority_updates( &queue_context ); - _Thread_Wait_acquire( the_thread, &queue_context ); - - if ( priority < the_thread->Real_priority.priority ) { - _Thread_Priority_change( - the_thread, - &the_thread->Real_priority, - priority, - PRIORITY_GROUP_LAST, - &queue_context - ); - } - - _Thread_Wait_release( the_thread, &queue_context ); - _Thread_Priority_update( &queue_context ); -} - typedef struct { Thread_queue_Context Base; void *exit_value; @@ -388,18 +365,37 @@ static void _Thread_Remove_life_change_request( Thread_Control *the_thread ) _Thread_State_release( the_thread, &lock_context ); } -void _Thread_Join( +static void _Thread_Clear_waiting_for_join_at_exit( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Per_CPU_Control *cpu_self, + Thread_queue_Context *queue_context +) +{ + (void) the_thread; + (void) cpu_self; + (void) queue_context; + _Thread_Clear_state( queue->owner, STATES_WAITING_FOR_JOIN_AT_EXIT ); +} + +Status_Control _Thread_Join( Thread_Control *the_thread, States_Control waiting_for_join, Thread_Control *executing, Thread_queue_Context *queue_context ) { - _Assert( the_thread != executing ); _Assert( _Thread_State_is_owner( the_thread ) ); executing->Wait.return_argument = NULL; - + _Thread_queue_Context_set_enqueue_callout( + queue_context, + _Thread_Clear_waiting_for_join_at_exit + ); + _Thread_queue_Context_set_deadlock_callout( + queue_context, + _Thread_queue_Deadlock_status + ); _Thread_queue_Context_set_thread_state( queue_context, waiting_for_join ); _Thread_queue_Enqueue( &the_thread->Join_queue.Queue, @@ -407,6 +403,7 @@ void _Thread_Join( executing, queue_context ); + return _Thread_Wait_get_status( executing ); } static void _Thread_Set_exit_value( @@ -435,77 +432,70 @@ static void _Thread_Try_life_change_request( } } -void _Thread_Cancel( - Thread_Control *the_thread, - Thread_Control *executing, - void *exit_value +Thread_Cancel_state _Thread_Cancel( + Thread_Control *the_thread, + Thread_Control *executing, + Thread_Life_state life_states_to_clear ) { - ISR_lock_Context lock_context; - Thread_Life_state previous; - Per_CPU_Control *cpu_self; + ISR_lock_Context lock_context; + Thread_Life_state previous; _Assert( the_thread != executing ); _Thread_State_acquire( the_thread, &lock_context ); - _Thread_Set_exit_value( the_thread, exit_value ); + _Thread_Set_exit_value( the_thread, PTHREAD_CANCELED ); previous = _Thread_Change_life_locked( the_thread, - 0, + life_states_to_clear, THREAD_LIFE_TERMINATING, 0 ); - cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); - if ( _States_Is_dormant( the_thread->current_state ) ) { _Thread_State_release( the_thread, &lock_context ); _Thread_Make_zombie( the_thread ); - } else { - Priority_Control priority; - - _Thread_Try_life_change_request( the_thread, previous, &lock_context ); - priority = _Thread_Get_priority( executing ); - _Thread_Raise_real_priority( the_thread, priority ); + return THREAD_CANCEL_DONE; } - _Thread_Dispatch_enable( cpu_self ); + _Thread_Try_life_change_request( the_thread, previous, &lock_context ); + return THREAD_CANCEL_IN_PROGRESS; } -static void _Thread_Close_enqueue_callout( - Thread_queue_Queue *queue, +Status_Control _Thread_Close( Thread_Control *the_thread, - Per_CPU_Control *cpu_self, + Thread_Control *executing, Thread_queue_Context *queue_context ) { - Thread_Close_context *context; - - context = (Thread_Close_context *) queue_context; - _Thread_Cancel( context->cancel, the_thread, NULL ); -} + Per_CPU_Control *cpu_self; + Thread_Cancel_state cancel_state; -void _Thread_Close( - Thread_Control *the_thread, - Thread_Control *executing, - Thread_Close_context *context -) -{ - context->cancel = the_thread; - _Thread_queue_Context_set_enqueue_callout( - &context->Base, - _Thread_Close_enqueue_callout + cpu_self = _Thread_Dispatch_disable_critical( + &queue_context->Lock_context.Lock_context ); + _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context ); + + cancel_state = _Thread_Cancel( the_thread, executing, THREAD_LIFE_DETACHED ); + + if ( cancel_state == THREAD_CANCEL_DONE ) { + _Thread_Dispatch_enable( cpu_self ); + return STATUS_SUCCESSFUL; + } + + _ISR_lock_ISR_disable( &queue_context->Lock_context.Lock_context ); + _Thread_Dispatch_unnest( cpu_self ); _Thread_State_acquire_critical( the_thread, - &context->Base.Lock_context.Lock_context + &queue_context->Lock_context.Lock_context ); - _Thread_Join( + + return _Thread_Join( the_thread, STATES_WAITING_FOR_JOIN, executing, - &context->Base + queue_context ); } diff --git a/cpukit/score/src/watchdogtick.c b/cpukit/score/src/watchdogtick.c index 6edb3f071a..71311b598e 100644 --- a/cpukit/score/src/watchdogtick.c +++ b/cpukit/score/src/watchdogtick.c @@ -83,9 +83,13 @@ void _Watchdog_Tick( Per_CPU_Control *cpu ) Thread_Control *executing; const Thread_CPU_budget_operations *cpu_budget_operations; +#ifdef RTEMS_SMP if ( _Per_CPU_Is_boot_processor( cpu ) ) { +#endif ++_Watchdog_Ticks_since_boot; +#ifdef RTEMS_SMP } +#endif _ISR_lock_ISR_disable_and_acquire( &cpu->Watchdog.Lock, &lock_context ); |