summaryrefslogtreecommitdiffstats
path: root/cpukit
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit')
-rw-r--r--cpukit/dtc/VERSION17
-rw-r--r--cpukit/dtc/libfdt/fdt_ro.c2
-rw-r--r--cpukit/include/machine/_kernel_in.h6
-rw-r--r--cpukit/include/machine/_kernel_in6.h1
-rw-r--r--cpukit/include/machine/_kernel_uio.h4
-rw-r--r--cpukit/include/rtems/confdefs.h1
-rw-r--r--cpukit/include/rtems/confdefs/face.h81
-rw-r--r--cpukit/include/rtems/confdefs/newlib.h3
-rw-r--r--cpukit/include/rtems/confdefs/threads.h6
-rw-r--r--cpukit/include/rtems/imfs.h38
-rw-r--r--cpukit/include/rtems/imfsimpl.h92
-rw-r--r--cpukit/include/rtems/libcsupport.h28
-rw-r--r--cpukit/include/rtems/malloc.h60
-rw-r--r--cpukit/include/rtems/posix/priorityimpl.h2
-rw-r--r--cpukit/include/rtems/posix/timer.h18
-rw-r--r--cpukit/include/rtems/rtems/tasks.h28
-rw-r--r--cpukit/include/rtems/score/gcov.h87
-rw-r--r--cpukit/include/rtems/score/memory.h14
-rw-r--r--cpukit/include/rtems/score/objectdata.h4
-rw-r--r--cpukit/include/rtems/score/objectimpl.h29
-rw-r--r--cpukit/include/rtems/score/priority.h7
-rw-r--r--cpukit/include/rtems/score/priorityimpl.h33
-rw-r--r--cpukit/include/rtems/score/processormask.h106
-rw-r--r--cpukit/include/rtems/score/scheduleredfimpl.h19
-rw-r--r--cpukit/include/rtems/score/schedulerimpl.h65
-rw-r--r--cpukit/include/rtems/score/schedulerpriorityimpl.h30
-rw-r--r--cpukit/include/rtems/score/schedulersimpleimpl.h22
-rw-r--r--cpukit/include/rtems/score/scheduleruniimpl.h221
-rw-r--r--cpukit/include/rtems/score/thread.h10
-rw-r--r--cpukit/include/rtems/score/threadimpl.h80
-rw-r--r--cpukit/include/rtems/score/timecounter.h25
-rw-r--r--cpukit/include/rtems/shellconfig.h6
-rw-r--r--cpukit/include/rtems/test-info.h14
-rw-r--r--cpukit/include/rtems/test.h2
-rw-r--r--cpukit/include/rtems/tftp.h407
-rw-r--r--cpukit/include/sys/exec_elf.h840
-rw-r--r--cpukit/include/sys/timepps.h41
-rw-r--r--cpukit/include/sys/timetc.h10
-rw-r--r--cpukit/libcsupport/src/__gettod.c2
-rw-r--r--cpukit/libcsupport/src/__times.c4
-rw-r--r--cpukit/libcsupport/src/gcovfork.c94
-rw-r--r--cpukit/libcsupport/src/getreentglobal.c2
-rw-r--r--cpukit/libcsupport/src/newlibc_reent.c6
-rw-r--r--cpukit/libdl/rtl-elf.c2
-rw-r--r--cpukit/libdl/rtl-elf.h2
-rw-r--r--cpukit/libdl/rtl-mdreloc-aarch64.c520
-rw-r--r--cpukit/libdl/rtl-mdreloc-arm.c79
-rw-r--r--cpukit/libdl/rtl-obj-comp.c6
-rw-r--r--cpukit/libdl/rtl-shell.c4
-rw-r--r--cpukit/libdl/rtl-sym.c2
-rw-r--r--cpukit/libdl/rtl-unresolved.c2
-rw-r--r--cpukit/libdl/rtl-unwind-arm.c65
-rw-r--r--cpukit/libdl/rtl-unwind-arm.h46
-rw-r--r--cpukit/libfs/src/ftpfs/tftpDriver.c1757
-rw-r--r--cpukit/libfs/src/ftpfs/tftp_driver.h96
-rw-r--r--cpukit/libfs/src/ftpfs/tftpfs.c615
-rw-r--r--cpukit/libfs/src/imfs/imfs_add_node.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_chown.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_fchmod.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_fifo.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_linfile.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_link.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_make_generic_node.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_memfile.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_mknod.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_node.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_rename.c2
-rw-r--r--cpukit/libfs/src/jffs2/VERSION4
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/jffs2.h5
-rw-r--r--cpukit/libfs/src/jffs2/src/acl.h1
-rw-r--r--cpukit/libfs/src/jffs2/src/erase.c2
-rw-r--r--cpukit/libfs/src/jffs2/src/fs-rtems.c24
-rw-r--r--cpukit/libfs/src/jffs2/src/gc.c35
-rw-r--r--cpukit/libfs/src/jffs2/src/nodelist.h2
-rw-r--r--cpukit/libfs/src/jffs2/src/os-rtems.h5
-rw-r--r--cpukit/libfs/src/jffs2/src/readinode.c5
-rw-r--r--cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h1
-rw-r--r--cpukit/libfs/src/jffs2/src/scan.c8
-rw-r--r--cpukit/libfs/src/jffs2/src/summary.h4
-rw-r--r--cpukit/libmd/md5.c2
-rw-r--r--cpukit/libmisc/shell/hexdump-conv.c4
-rw-r--r--cpukit/libmisc/shell/main_edit.c2
-rw-r--r--cpukit/libmisc/shell/main_rtems.c156
-rw-r--r--cpukit/libtest/t-test-hash-sha256.c9
-rw-r--r--cpukit/libtest/testgcovbspreset.c54
-rw-r--r--cpukit/libtest/testgcovcpufatalhalt.c54
-rw-r--r--cpukit/libtest/testgcovdumpinfo.c66
-rw-r--r--cpukit/posix/src/_execve.c4
-rw-r--r--cpukit/posix/src/cancel.c2
-rw-r--r--cpukit/posix/src/clocknanosleep.c16
-rw-r--r--cpukit/posix/src/psxtimercreate.c31
-rw-r--r--cpukit/posix/src/pthreadjoin.c47
-rw-r--r--cpukit/rtems/src/schedulerident.c27
-rw-r--r--cpukit/rtems/src/taskdelete.c17
-rw-r--r--cpukit/rtems/src/timerserver.c2
-rw-r--r--cpukit/score/cpu/aarch64/cpu.c22
-rw-r--r--cpukit/score/cpu/aarch64/include/libcpu/mmu-vmsav8-64.h1
-rw-r--r--cpukit/score/cpu/aarch64/include/machine/elf_machdep.h256
-rw-r--r--cpukit/score/cpu/aarch64/include/rtems/score/cpu.h6
-rw-r--r--cpukit/score/cpu/aarch64/include/rtems/score/cpuimpl.h9
-rw-r--r--cpukit/score/cpu/arm/aarch32-psma-init.c14
-rw-r--r--cpukit/score/cpu/arm/cpu.c5
-rw-r--r--cpukit/score/cpu/arm/include/rtems/score/cpuimpl.h13
-rw-r--r--cpukit/score/cpu/bfin/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h26
-rw-r--r--cpukit/score/cpu/lm32/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/cpu/m68k/include/rtems/score/cpuimpl.h11
-rw-r--r--cpukit/score/cpu/microblaze/include/rtems/score/cpuimpl.h11
-rw-r--r--cpukit/score/cpu/mips/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/cpu/moxie/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/cpu/nios2/include/rtems/score/cpuimpl.h12
-rw-r--r--cpukit/score/cpu/no_cpu/include/rtems/score/cpuimpl.h17
-rw-r--r--cpukit/score/cpu/or1k/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/cpu/or1k/include/rtems/score/or1k-utility.h10
-rw-r--r--cpukit/score/cpu/powerpc/include/rtems/score/cpuimpl.h16
-rw-r--r--cpukit/score/cpu/riscv/include/libcpu/byteorder.h2
-rw-r--r--cpukit/score/cpu/riscv/include/rtems/score/cpuimpl.h12
-rw-r--r--cpukit/score/cpu/sh/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h12
-rw-r--r--cpukit/score/cpu/sparc64/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/cpu/v850/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/cpu/x86_64/include/rtems/score/cpuimpl.h7
-rw-r--r--cpukit/score/src/gcovdumpinfo.c96
-rw-r--r--cpukit/score/src/gcovdumpinfobase64.c104
-rw-r--r--cpukit/score/src/gcovinfoset.c43
-rw-r--r--cpukit/score/src/kern_ntptime.c35
-rw-r--r--cpukit/score/src/kern_tc.c81
-rw-r--r--cpukit/score/src/memorydirtyfreeareas.c9
-rw-r--r--cpukit/score/src/memorynoinit.c45
-rw-r--r--cpukit/score/src/memoryzerofreeareas.c9
-rw-r--r--cpukit/score/src/mpci.c2
-rw-r--r--cpukit/score/src/objectactivecount.c18
-rw-r--r--cpukit/score/src/objectfree.c12
-rw-r--r--cpukit/score/src/rbtreemax.c4
-rw-r--r--cpukit/score/src/rbtreemin.c4
-rw-r--r--cpukit/score/src/rbtreenext.c4
-rw-r--r--cpukit/score/src/rbtreeprev.c4
-rw-r--r--cpukit/score/src/scheduleredfblock.c4
-rw-r--r--cpukit/score/src/scheduleredfchangepriority.c5
-rw-r--r--cpukit/score/src/scheduleredfschedule.c5
-rw-r--r--cpukit/score/src/scheduleredfunblock.c20
-rw-r--r--cpukit/score/src/scheduleredfyield.c2
-rw-r--r--cpukit/score/src/schedulerpriorityblock.c4
-rw-r--r--cpukit/score/src/schedulerprioritychangepriority.c5
-rw-r--r--cpukit/score/src/schedulerpriorityschedule.c5
-rw-r--r--cpukit/score/src/schedulerpriorityunblock.c16
-rw-r--r--cpukit/score/src/schedulerpriorityyield.c5
-rw-r--r--cpukit/score/src/schedulersimpleblock.c4
-rw-r--r--cpukit/score/src/schedulersimplechangepriority.c5
-rw-r--r--cpukit/score/src/schedulersimpleschedule.c5
-rw-r--r--cpukit/score/src/schedulersimpleunblock.c20
-rw-r--r--cpukit/score/src/schedulersimpleyield.c5
-rw-r--r--cpukit/score/src/threadchangepriority.c12
-rw-r--r--cpukit/score/src/threadcreateidle.c11
-rw-r--r--cpukit/score/src/threadinitialize.c1
-rw-r--r--cpukit/score/src/threadqops.c16
-rw-r--r--cpukit/score/src/threadqtimeout.c4
-rw-r--r--cpukit/score/src/threadrestart.c128
-rw-r--r--cpukit/score/src/watchdogtick.c4
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 );