<div dir="ltr"><div>Sorry for the late reply, I somehow missed the mail notification!</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Aug 13, 2020 at 9:35 PM Gedare Bloom <<a href="mailto:gedare@rtems.org">gedare@rtems.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Thu, Aug 13, 2020 at 9:06 AM Utkarsh Rai <<a href="mailto:utkarsh.rai60@gmail.com" target="_blank">utkarsh.rai60@gmail.com</a>> wrote:<br>
><br>
> -This patch provides thread-stack isolation and thread-stack sharing<br>
>  mechanism for a POSIX thread.<br>
><br>
Monster patch! think to yourself whether or not it makes sense to<br>
split these up. The main constraint is that every patch in the series<br>
should compile/run as they are applied.<br></blockquote><div> </div><div>Maybe I can break this up into 3 separate patches, stack-isolation, stack-sharing, and the configuration option?</div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> -The patches are based on sebastian's build-2 branch of sebastian's repo <a href="https://git.rtems.org/sebh" rel="noreferrer" target="_blank">https://git.rtems.org/sebh</a><br>
><br>
> -Configurations options are provided by using the new-build system. Refer to <a href="https://ftp.rtems.org/pub/rtems/people/sebh/user.pdf" rel="noreferrer" target="_blank">https://ftp.rtems.org/pub/rtems/people/sebh/user.pdf</a>,<br>
>  chapter 7,for basic setup and <a href="https://ftp.rtems.org/pub/rtems/people/sebh/eng.pdf(chapter" rel="noreferrer" target="_blank">https://ftp.rtems.org/pub/rtems/people/sebh/eng.pdf(chapter</a> 9) for the internals of the build system.<br>
> ---<br>
>  .../realview-pbx-a9/mmu/bsp-set-mmu-attr.c    |  75 ++++++++++<br>
>  bsps/shared/start/stackalloc.c                |  12 +-<br>
>  .../libbsp/arm/realview-pbx-a9/Makefile.am    |   3 +<br>
>  cpukit/Makefile.am                            |   1 +<br>
>  cpukit/<a href="http://headers.am" rel="noreferrer" target="_blank">headers.am</a>                             |   2 +<br>
>  cpukit/include/rtems/score/memoryprotection.h |  91 ++++++++++++<br>
>  cpukit/include/rtems/score/stack.h            |  49 +++++++<br>
>  cpukit/include/rtems/score/stackprotection.h  |  80 +++++++++++<br>
>  cpukit/include/rtems/score/thread.h           |   1 +<br>
>  cpukit/posix/src/mmap.c                       |  41 +++++-<br>
>  cpukit/posix/src/shmwkspace.c                 |  46 +++++-<br>
>  cpukit/score/cpu/arm/cpu_asm.S                |  94 ++++++++++++<br>
>  cpukit/score/src/stackprotection.c            | 103 +++++++++++++<br>
>  cpukit/score/src/threadhandler.c              |   6 +<br>
>  cpukit/score/src/threadinitialize.c           |   9 ++<br>
>  .../arm/realview-pbx-a9/bsprealviewpbxa9.yml  |   1 +<br>
>  spec/build/cpukit/cpuopts.yml                 |   2 +<br>
>  spec/build/cpukit/librtemscpu.yml             |   3 +<br>
>  .../build/cpukit/optthreadstackprotection.yml |  16 +++<br>
>  spec/build/testsuites/samples/grp.yml         |   4 +<br>
>  .../samples/threadstackprotection.yml         |  19 +++<br>
>  .../testsuites/samples/threadstacksharing.yml |  19 +++<br>
>  testsuites/samples/Makefile.am                |  16 +++<br>
>  testsuites/samples/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a>               |   2 +<br>
>  .../samples/thread_stack_protection/init.c    | 112 +++++++++++++++<br>
>  .../thread_stack_protection.doc               |   2 +<br>
>  .../thread_stack_protection.scn               |  20 +++<br>
>  .../samples/thread_stack_sharing/init.c       | 136 ++++++++++++++++++<br>
>  28 files changed, 959 insertions(+), 6 deletions(-)<br>
>  create mode 100644 bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c<br>
>  create mode 100644 cpukit/include/rtems/score/memoryprotection.h<br>
>  create mode 100644 cpukit/include/rtems/score/stackprotection.h<br>
>  create mode 100644 cpukit/score/src/stackprotection.c<br>
>  create mode 100644 spec/build/cpukit/optthreadstackprotection.yml<br>
>  create mode 100644 spec/build/testsuites/samples/threadstackprotection.yml<br>
>  create mode 100644 spec/build/testsuites/samples/threadstacksharing.yml<br>
>  create mode 100644 testsuites/samples/thread_stack_protection/init.c<br>
>  create mode 100644 testsuites/samples/thread_stack_protection/thread_stack_protection.doc<br>
>  create mode 100644 testsuites/samples/thread_stack_protection/thread_stack_protection.scn<br>
>  create mode 100644 testsuites/samples/thread_stack_sharing/init.c<br>
><br>
> diff --git a/bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c b/bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c<br>
> new file mode 100644<br>
> index 0000000000..c3b469dd2a<br>
> --- /dev/null<br>
> +++ b/bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c<br>
> @@ -0,0 +1,75 @@<br>
file header block?<br>
<br>
> +#include <bsp/arm-cp15-start.h><br>
> +#include <rtems/score/memoryprotection.h><br>
> +#include <libcpu/arm-cp15.h><br>
> +#include <rtems.h><br>
> +<br>
> +static uint32_t translate_flags(uint32_t attr_flags)<br>
> +{<br>
> +  uint32_t flags;<br>
> +  uint32_t memory_attribute;<br>
> +<br>
> +  switch (attr_flags)<br>
> +  {<br>
> +    case RTEMS_READ_WRITE:<br>
> +     flags = ARMV7_MMU_READ_WRITE;<br>
> +     break;<br>
> +<br>
> +    case RTEMS_READ_ONLY:<br>
> +     flags = ARMV7_MMU_READ_ONLY;<br>
> +     break;<br>
> +<br>
> +    case RTEMS_NO_ACCESS:<br>
> +    default:<br>
> +     flags = 0;<br>
> +     break;<br>
> +  }<br>
<br>
Does this switch statement work when the attr_flags have other fields<br>
defined such as RTEMS_MEMORY_CACHED?<br>
<br></blockquote><div><br></div><div>Yes, I missed that.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
When bit flags are not mutually exclusive it makes more sense to write as...<br>
<br>
if ( (attr_flags & RTEMS_READ_WRITE) == RTEMS_READ_WRITE) ) {<br>
   ...<br>
}<br>
if ( ... ) {<br>
  ...<br>
}<br>
Maybe it makes more sense to write your helper function this way?<br>
<br>
> +<br>
> + /*<br>
> +  * Check for memory-cache operation<br>
> +  */<br>
> +  if( attr_flags & RTEMS_MEMORY_CACHED ) {<br>
> +    flags |= ARM_MMU_SECT_TEX_0 | ARM_MMU_SECT_C | ARM_MMU_SECT_B;<br>
> +  }<br>
> +<br>
> +  return flags;<br>
> +}<br>
> +<br>
> +void _Memory_protection_Set_entries(uintptr_t begin, size_t size, uint32_t flags)<br>
> +{<br>
> +  uintptr_t end;<br>
> +  rtems_interrupt_level irq_level;<br>
> +  uint32_t access_flags;<br>
> +<br>
> +  if(begin != NULL ) {<br>
whitespace: "if ( begin ..."<br>
<br>
If begin is invalid, the set_entries fails. Maybe you want to return<br>
an error code?<br>
<br>
You might want to refactor a helper to validate the memory range. That<br>
will make this easier to maintain and tighten the checks.<br></blockquote><div><br></div><div>We can only change the memory attributes of the workspace and heap region, so we need to check the memory range for only these regions right?</div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> +    end = begin + size;<br>
> +    access_flags = translate_flags(flags);<br>
> +<br>
> +    /*<br>
> +     * The ARM reference manual instructs to disable all the interrupts before<br>
> +     * setting up page table entries.<br>
> +     */<br>
> +    rtems_interrupt_disable(irq_level);<br>
> +    arm_cp15_set_translation_table_entries(begin, end, access_flags);<br>
> +    rtems_interrupt_enable(irq_level);<br>
> +  }<br>
> +}<br>
> +<br>
> +void _Memory_protection_Unset_entries(uintptr_t begin, size_t size)<br>
> +{<br>
> +  uint32_t access_flags;<br>
> +  uintptr_t end;<br>
> +  rtems_interrupt_level irq_level;<br>
> +<br>
> +  if( begin != NULL ) {<br>
> +    end = begin + size;<br>
> +    access_flags = translate_flags( RTEMS_NO_ACCESS );<br>
> +<br>
> +    /*<br>
> +     *  The ARM reference manual instructs to disable all the interrupts before<br>
> +     * setting up page table entries.<br>
> +     */<br>
> +    rtems_interrupt_disable(irq_level);<br>
> +    arm_cp15_set_translation_table_entries(begin, end, access_flags);<br>
> +    rtems_interrupt_enable(irq_level);<br>
> +  }<br>
> +}<br>
> \ No newline at end of file<br>
> diff --git a/bsps/shared/start/stackalloc.c b/bsps/shared/start/stackalloc.c<br>
> index f7cf7be0f1..6ebef4d6e5 100644<br>
> --- a/bsps/shared/start/stackalloc.c<br>
> +++ b/bsps/shared/start/stackalloc.c<br>
> @@ -44,6 +44,15 @@ void *bsp_stack_allocate(size_t size)<br>
>  {<br>
>    void *stack = NULL;<br>
><br>
> +#if defined (RTEMS_THREAD_STACK_PROTECTION)<br>
> +/*<br>
> + * This is a temporary hack, we need to use _Heap_Allocate_aligned() but the heap<br>
> + * intialization for bsp_stack_heap fails as bsp_section_stack_size is 0. See<br>
typo: initialization<br>
<br>
> + * bsp_stack_allocate_init().<br>
<br>
This is an interesting problem. You may want to explore how to solve<br>
this better.<br>
<br>
> + */<br>
> +  posix_memalign(&stack, 4096 , size);<br>
> +  _Memory_protection_Set_entries( stack, size, ( RTEMS_READ_ONLY | RTEMS_MEMORY_CACHED ) );<br>
> +#else<br>
>    if (bsp_stack_heap.area_begin != 0) {<br>
>      stack = _Heap_Allocate(&bsp_stack_heap, size);<br>
>    }<br>
> @@ -51,6 +60,7 @@ void *bsp_stack_allocate(size_t size)<br>
>    if (stack == NULL) {<br>
>      stack = _Workspace_Allocate(size);<br>
>    }<br>
> +#endif<br>
><br>
>    return stack;<br>
>  }<br>
> @@ -62,4 +72,4 @@ void bsp_stack_free(void *stack)<br>
>    if (!ok) {<br>
>      _Workspace_Free(stack);<br>
>    }<br>
> -}<br>
> +}<br>
> \ No newline at end of file<br>
spurious change. check the settings on your text editor. It seems to<br>
be truncating the end of your files.<br>
<br>
> diff --git a/c/src/lib/libbsp/arm/realview-pbx-a9/Makefile.am b/c/src/lib/libbsp/arm/realview-pbx-a9/Makefile.am<br>
> index d5549275be..24847c7b91 100644<br>
> --- a/c/src/lib/libbsp/arm/realview-pbx-a9/Makefile.am<br>
> +++ b/c/src/lib/libbsp/arm/realview-pbx-a9/Makefile.am<br>
> @@ -74,6 +74,9 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-a9mpcore.<br>
>  librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-cp15.c<br>
>  librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-v7ar-disable-data.S<br>
><br>
> +#MMU<br>
> +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c<br>
> +<br>
>  # Start hooks<br>
>  librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/realview-pbx-a9/start/bspstarthooks.c<br>
><br>
> diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am<br>
> index 75e119ea3c..2d50d0fdce 100644<br>
> --- a/cpukit/Makefile.am<br>
> +++ b/cpukit/Makefile.am<br>
> @@ -929,6 +929,7 @@ librtemscpu_a_SOURCES += score/src/schedulercbsgetserverid.c<br>
>  librtemscpu_a_SOURCES += score/src/schedulercbssetparameters.c<br>
>  librtemscpu_a_SOURCES += score/src/schedulercbsreleasejob.c<br>
>  librtemscpu_a_SOURCES += score/src/schedulercbsunblock.c<br>
> +librtemscpu_a_SOURCES += score/src/stackprotection.c<br>
>  librtemscpu_a_SOURCES += score/src/stackallocator.c<br>
>  librtemscpu_a_SOURCES += score/src/pheapallocate.c<br>
>  librtemscpu_a_SOURCES += score/src/pheapextend.c<br>
> diff --git a/cpukit/<a href="http://headers.am" rel="noreferrer" target="_blank">headers.am</a> b/cpukit/<a href="http://headers.am" rel="noreferrer" target="_blank">headers.am</a><br>
> index 0bba9674cd..211e17ddf8 100644<br>
> --- a/cpukit/<a href="http://headers.am" rel="noreferrer" target="_blank">headers.am</a><br>
> +++ b/cpukit/<a href="http://headers.am" rel="noreferrer" target="_blank">headers.am</a><br>
> @@ -352,6 +352,7 @@ include_rtems_score_HEADERS += include/rtems/score/isr.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/isrlevel.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/isrlock.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/memory.h<br>
> +include_rtems_score_HEADERS += include/rtems/score/memoryprotection.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/mpci.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/mpciimpl.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/mppkt.h<br>
> @@ -405,6 +406,7 @@ include_rtems_score_HEADERS += include/rtems/score/smplockstats.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/smplockticket.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/stack.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/stackimpl.h<br>
> +include_rtems_score_HEADERS += include/rtems/score/stackprotection.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/states.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/statesimpl.h<br>
>  include_rtems_score_HEADERS += include/rtems/score/status.h<br>
> diff --git a/cpukit/include/rtems/score/memoryprotection.h b/cpukit/include/rtems/score/memoryprotection.h<br>
> new file mode 100644<br>
> index 0000000000..245e50313c<br>
> --- /dev/null<br>
> +++ b/cpukit/include/rtems/score/memoryprotection.h<br>
> @@ -0,0 +1,91 @@<br>
> +/* SPDX-License-Identifier: BSD-2-Clause */<br>
> +<br>
> +/**<br>
> + * @file<br>
> + *<br>
> + * @ingroup RTEMSScoreMemoryprotection<br>
> + *<br>
> + * @brief This file provodes APIs for high-level memory protection<br>
typo<br>
<br>
> + *<br>
remove extra blank line<br>
<br>
> + */<br>
> +<br>
> +/*<br>
> + * Copyright (C) 2020 Utkarsh Rai<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
> + * POSSIBILITY OF SUCH DAMAGE.<br>
> + */<br>
> +<br>
> +#ifndef _RTEMS_SCORE_MEMORYPROTECTION_H<br>
> +#define _RTEMS_SCORE_MEMORYPROTECTION_H<br>
> +<br>
> +#if defined ( ASM )<br>
> +  #include <rtems/asm.h><br>
> +#else<br>
> +  #include <rtems/score/basedefs.h><br>
> +#endif<br>
> +<br>
> +#ifdef __cplusplus<br>
> +extern "C" {<br>
> +#endif<br>
> +<br>
> +#if !defined ( ASM )<br>
> +<br>
> +#define RTEMS_NO_ACCESS 0x00<br>
> +#define RTEMS_READ_ONLY 0x01<br>
> +#define RTEMS_WRITE_ONLY 0x02<br>
> +#define RTEMS_READ_WRITE ( RTEMS_READ_ONLY | RTEMS_WRITE_ONLY )<br>
> +#define RTEMS_MEMORY_CACHED 0x04<br>
> +<br>
> +/**<br>
> + * @brief Define the memory access permission for the specified memory region<br>
> + *<br>
> + * @param begin_addr Beginning of the memory region<br>
> + * @param size Size of the memory region<br>
> + * @param flag Memory access flag<br>
> + *<br>
delete extra blank<br>
<br>
> + */<br>
> +void _Memory_protection_Set_entries(<br>
> +  uintptr_t begin_addr,<br>
> +  size_t size,<br>
> +  uint32_t flag<br>
> +);<br>
> +<br>
> +/**<br>
> + * @brief Unset the memory access permission for the specified memory region<br>
> + * This operation implicitly sets the specified memory region with 'NO_ACCESS'<br>
> + * flag.<br>
> + *<br>
> + * @param begin_addr Begining of the memory region<br>
typo: Beginning<br>
<br>
> + * @param size Size of the memory region<br>
> + */<br>
> +void _Memory_protection_Unset_entries(<br>
> +  uintptr_t begin_addr,<br>
> +  size_t size<br>
> +);<br>
> +<br>
> +#endif  /* !defined ( ASM ) */<br>
> +<br>
does this get included from ASM? if so, it is not actually doing anything...<br>
<br>
> +#ifdef __cplusplus<br>
> +}<br>
> +#endif<br>
> +<br>
> +#endif<br>
> \ No newline at end of file<br>
> diff --git a/cpukit/include/rtems/score/stack.h b/cpukit/include/rtems/score/stack.h<br>
> index df1df74867..d561bf61c1 100644<br>
> --- a/cpukit/include/rtems/score/stack.h<br>
> +++ b/cpukit/include/rtems/score/stack.h<br>
> @@ -47,6 +47,47 @@ extern "C" {<br>
>   */<br>
>  #define STACK_MINIMUM_SIZE  CPU_STACK_MINIMUM_SIZE<br>
><br>
> +/**<br>
> + * The number of stacks that can be shared with a thread.<br>
> + */<br>
> +#define SHARED_STACK_NUMBER 8<br>
> +<br>
Magic number 8?<br></blockquote><div><br></div><div>Will it be ok to have the shared stack number equal to CONFIGURE_MAXIMUM_POSIX_THREADS -1?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> +#if defined ( RTEMS_THREAD_STACK_PROTECTION )<br>
> +/**<br>
> + * The following defines the attributes of a protected stack<br>
> + */<br>
> +typedef struct<br>
> +{<br>
> +  /** The pointer to the page table base */<br>
> +  uintptr_t      page_table_base;<br>
PT is an attribute of a thread, not a stack. This is a little bit misplaced.<br>
<br>
> +  /**Memory flag for the alllocated/shared stack */<br>
typo: allocated<br>
<br>
> +  uint32_t  access_flags;<br>
> +} Stack_Protection_attr;<br>
> +<br>
> +<br>
> +/**<br>
> + * The following defines the control block  of a shared stack. Each stack can have<br>
> + * different sharing attributes.<br>
> + */<br>
> +typedef struct<br>
> +{<br>
> +  /** This is the attribute of a shared stack*/<br>
> +  Stack_Protection_attr    Base;<br>
> +  /** This is the stack address of the sharing thread*/<br>
> +  void* shared_stack_area;<br>
> +  /** Stack size of the sharing thread*/<br>
> +  size_t shared_stack_size;<br>
> +  /** This is the stack address of the target stack. Maybe this area is not<br>
> +   * needed but this helps in selecting the target thread during stack sharing.<br>
> +   */<br>
> +  void* target_stack_area;<br>
> + /** Error checking for valid target stack address. This is also used to<br>
> +  * distinguish between a normal mmap operation and a stack sharing operation.<br>
> +  */<br>
> +  bool stack_shared;<br>
> +} Stack_Shared_attr;<br>
> +#endif<br>
> +<br>
I thought you were planning to integrate this better with the existing<br>
Stack_Control stuff?<br>
<br>
Do we really need a separate structure to track 'shared' stacks (as<br>
opposed to 'non-shared' ones?)<br>
<br></blockquote><div><br></div><div>This is because of the design of the stack sharing mechanism. I have elaborated more on this below.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
>  /**<br>
>   *  The following defines the control block used to manage each stack.<br>
>   */<br>
> @@ -55,6 +96,14 @@ typedef struct {<br>
>    size_t      size;<br>
>    /** This is the low memory address of stack. */<br>
>    void       *area;<br>
> +#if defined (RTEMS_THREAD_STACK_PROTECTION)<br>
> +   /** The attribute of a protected stack */<br>
> +  Stack_Protection_attr    Base;<br>
<br>
This 'Base' stuff should only be used when the structure sits at the<br>
base, to implement some kind of inheritance/polymorphism.<br>
<br>
> +<br>
> +  Stack_Shared_attr *shared_stacks[SHARED_STACK_NUMBER];<br>
I'm not sure about this design choice.<br>
<br></blockquote><div><br></div><div>Yes, I now realize that we cannot do it this way. But we do have to track the shared stacks as discussed <a href="https://lists.rtems.org/pipermail/devel/2020-August/061071.html">here</a>,  and for setting memory attributes of any shared stack we need three properties, base address, size of the stack, and the memory flag for sharing which can be different from its 'intrinsic' memory flag. The stack control structure already has the size and the base address but a single thread stack can be shared with multiple threads with different memory flags. This is an implementation challenge I have to look out for.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> +<br>
> +  uint32_t shared_stacks_count;<br>
> +#endif<br>
>  }   Stack_Control;<br>
><br>
>  /**<br>
> diff --git a/cpukit/include/rtems/score/stackprotection.h b/cpukit/include/rtems/score/stackprotection.h<br>
> new file mode 100644<br>
> index 0000000000..58ab5f8673<br>
> --- /dev/null<br>
> +++ b/cpukit/include/rtems/score/stackprotection.h<br>
> @@ -0,0 +1,80 @@<br>
> +/**<br>
> + * @file<br>
> + *<br>
> + * @ingroup RTEMSScoreStackprotection<br>
> + *<br>
> + * @brief Stackprotection API<br>
> + *<br>
> + * This include file provides the API for the management of protected thread-<br>
> + * stacks<br>
> + */<br>
> +<br>
> +/*<br>
> + *  COPYRIGHT (c) 2020 Utkarsh Rai.<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + * notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + * notice, this list of conditions and the following disclaimer in the<br>
> + * documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
> + * POSSIBILITY OF SUCH DAMAGE.<br>
> + *<br>
> + */<br>
> +<br>
> +#ifndef _RTEMS_SCORE_STACKPROTECTION_H<br>
> +#define _RTEMS_SCORE_STACKPROTECTION_H<br>
> +<br>
> +#include <rtems/score/basedefs.h><br>
> +#include <rtems/score/stack.h><br>
> +#include <rtems/score/memoryprotection.h><br>
> +<br>
> +#ifdef __cplusplus<br>
> +extern "C" {<br>
> +#endif<br>
> +<br>
> +/**<br>
> + * @brief Share the stack address of a given thread with the target thread.<br>
> + *<br>
> + * @param target_stack Stack address of the target thread<br>
> + * @param sharing_stack Stack address of the sharin thread<br>
> + */<br>
> +<br>
> +int _Stackprotection_Share_stack(<br>
_Stack_protection_<br>
<br>
> +  void *target_stack,<br>
> +  void *sharing_stack,<br>
> +  size_t size,<br>
> +  uint32_t memory_flag<br>
> +);<br>
> +<br>
> +/**<br>
> + * @brief Swap the restored shared stacks  in the page table during context<br>
> + * restoration<br>
> + *<br>
> + * We set the entries of the restored stack and mark all the remainig stacks as<br>
typo: remaining<br>
<br>
> + * 'NO-ACCESS'.<br>
> + *<br>
> + * @param Control block of the restored stack<br>
> + */<br>
> +void _Stackprotection_Context_restore(<br>
> +  Stack_Control *heir_stack<br>
> +);<br>
> +<br>
> +#ifdef __cplusplus<br>
> +}<br>
> +#endif<br>
> +<br>
> +#endif<br>
> \ No newline at end of file<br>
> diff --git a/cpukit/include/rtems/score/thread.h b/cpukit/include/rtems/score/thread.h<br>
> index ee0aee5b79..0ad22feac4 100644<br>
> --- a/cpukit/include/rtems/score/thread.h<br>
> +++ b/cpukit/include/rtems/score/thread.h<br>
> @@ -34,6 +34,7 @@<br>
>  #include <rtems/score/priority.h><br>
>  #include <rtems/score/schedulernode.h><br>
>  #include <rtems/score/stack.h><br>
> +#include <rtems/score/stackprotection.h><br>
>  #include <rtems/score/states.h><br>
>  #include <rtems/score/threadq.h><br>
>  #include <rtems/score/timestamp.h><br>
> diff --git a/cpukit/posix/src/mmap.c b/cpukit/posix/src/mmap.c<br>
> index 176c6e4fe8..6587819c0f 100644<br>
> --- a/cpukit/posix/src/mmap.c<br>
> +++ b/cpukit/posix/src/mmap.c<br>
> @@ -28,7 +28,27 @@<br>
><br>
>  #include <rtems/posix/mmanimpl.h><br>
>  #include <rtems/posix/shmimpl.h><br>
> +#include <rtems/score/stackprotection.h><br>
> +#include <rtems/score/memoryprotection.h><br>
><br>
> +static uint32_t mmap_flag_translate(int prot)<br>
> +{<br>
> +  int prot_read;<br>
> +  int prot_write;<br>
> +  int memory_flag;<br>
> +<br>
> +  prot_read = (prot_read & PROT_READ) == PROT_READ;<br>
> +  prot_write = (prot_write & PROT_WRITE) == PROT_WRITE;<br>
> +<br>
> +  if(prot_read){<br>
whitespace<br>
<br>
> +    memory_flag |= ( RTEMS_READ_ONLY| RTEMS_MEMORY_CACHED );<br>
> +  }<br>
> +  if(prot_write) {<br>
ws<br>
<br>
> +    memory_flag |= ( RTEMS_READ_WRITE | RTEMS_MEMORY_CACHED );<br>
> +  }<br>
> +<br>
> +  return memory_flag;<br>
> +}<br>
><br>
>  /**<br>
>   * mmap chain of mappings.<br>
> @@ -50,6 +70,9 @@ void *mmap(<br>
>    bool            map_private;<br>
>    bool            is_shared_shm;<br>
>    int             err;<br>
> +  uint32_t memory_flags;<br>
> +  uintptr_t shared_stack_address;<br>
> +  int status;<br>
><br>
>    map_fixed = (flags & MAP_FIXED) == MAP_FIXED;<br>
>    map_anonymous = (flags & MAP_ANON) == MAP_ANON;<br>
> @@ -67,7 +90,10 @@ void *mmap(<br>
><br>
>    /*<br>
>     * We can provide read, write and execute because the memory in RTEMS does<br>
> -   * not normally have protections but we cannot hide access to memory.<br>
> +   * not normally have protections but we cannot hide access to memory. For<br>
> +   * thread-stack protection we can provide no-access option, but stacks are<br>
> +   * implicitly isolated and it makes no sense to specify no-access option for<br>
> +   * already isolated stacks.<br>
>     */<br>
>    if ( prot == PROT_NONE ) {<br>
>      errno = ENOTSUP;<br>
> @@ -292,11 +318,18 @@ void *mmap(<br>
>        free( mapping );<br>
>        return MAP_FAILED;<br>
>      }<br>
> +  /**<br>
> +    * We share thread-stacks only when we have a shared memory object and map<br>
> +    * shared flag set<br>
> +    */<br>
> +    memory_flags = mmap_flag_translate( prot );<br>
> +    status = _Stackprotection_Share_stack( mapping->addr, addr, len,memory_flags );<br>
<br>
What if someone passes an addr that is not in stack?<br>
<br>
Fundamentally what is the difference between sharing stacks and<br>
sharing some arbitrary 'pages'? <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> +  }<br>
> +  if(status == RTEMS_INVALID_ADDRESS ) {<br>
ws<br>
<br>
what leads to this status?<br></blockquote><div><br></div><div><br></div><div>The _Stackprotection_Share_stack() takes the address of the target thread-stack and sharing thread-stack. Now we check all the thread stack addresses against the passed</div><div>thread stack address. If we match against a valid address it returns RTEMS_SUCCESSFUL otherwise we return RTEMS_INVALID_ADDRESS. Although now when I relook at</div><div>the implementation there is a glaring mistake, simply adding the pointer of the Shared_stack structure that has been initialized from a  thread stack that we may not be able</div><div>to access from a certain thread. I will have to change the implementation a bit, again :(. </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> +    rtems_chain_append_unprotected( &mmap_mappings, &mapping->node );<br>
>    }<br>
> -<br>
> -  rtems_chain_append_unprotected( &mmap_mappings, &mapping->node );<br>
><br>
>    mmap_mappings_lock_release( );<br>
><br>
>    return mapping->addr;<br>
> -}<br>
> +}<br>
> \ No newline at end of file<br>
> diff --git a/cpukit/posix/src/shmwkspace.c b/cpukit/posix/src/shmwkspace.c<br>
> index 4fa4ec4771..e4e3c594d9 100644<br>
> --- a/cpukit/posix/src/shmwkspace.c<br>
> +++ b/cpukit/posix/src/shmwkspace.c<br>
> @@ -16,6 +16,7 @@<br>
><br>
>  #include <errno.h><br>
>  #include <string.h><br>
> +#include <rtems/posix/pthread.h><br>
>  #include <rtems/score/wkspace.h><br>
>  #include <rtems/posix/shmimpl.h><br>
><br>
> @@ -24,6 +25,49 @@ int _POSIX_Shm_Object_create_from_workspace(<br>
>    size_t size<br>
>  )<br>
>  {<br>
> +#if defined(RTEMS_THREAD_STACK_PROTECTION)<br>
> +  POSIX_Shm_Control *shm;<br>
> +  Objects_Id id;<br>
> +  Objects_Name_or_id_lookup_errors err;<br>
> +  Thread_Control *Control;<br>
> +  ISR_lock_Context lock_context;<br>
> +  char *name;<br>
> +<br>
> +  shm = RTEMS_CONTAINER_OF(shm_obj, POSIX_Shm_Control, shm_object);<br>
> +  name = shm->Object.name.name_p;<br>
> +  /** We assign fixed pattern of naming for thread-stacks, and treat them<br>
> +   *  accordingly.<br>
> +   */<br>
> +  if( strncmp( name, "/taskfs/", 8) == 0 ) {<br>
> +    /**<br>
> +     * Obtain the object id of the thread and then get the thread control block<br>
> +     * corresponding to that id.<br>
> +     */<br>
> +    err = _Objects_Name_to_id_u32(<br>
> +            &_POSIX_Threads_Information.Objects,<br>
> +           _Objects_Build_name( name[8], name[9], name[10], name[11]),<br>
> +            RTEMS_LOCAL,<br>
> +            &id<br>
> +            );<br>
> +    Control = _Thread_Get( id, &lock_context );<br>
> +     if( Control != NULL ) {<br>
ws<br>
<br>
> +       shm_obj->handle = Control->Start.Initial_stack.area;<br>
> +       if( size != Control->Start.Initial_stack.size) {<br>
ws<br>
<br>
> +         return ENOMEM;<br>
> +       }<br>
<br>
I'm not sure this is the right place for this logic. It's not really<br>
creating from the workplace in case of the tasksfs name match? should<br>
this be handled before calling this function?<br>
<br>
> +     } else {<br>
> +       return ENOMEM;<br>
> +     }<br>
> +  } else {<br>
> +    shm_obj->handle = _Workspace_Allocate( size );<br>
> +    if ( shm_obj->handle == NULL ) {<br>
> +      return ENOMEM;<br>
> +  }<br>
> +<br>
> +  shm_obj->size = size;<br>
> +  return 0;<br>
> +}<br>
> +#else<br>
>    shm_obj->handle = _Workspace_Allocate( size );<br>
>    if ( shm_obj->handle == NULL ) {<br>
>      return ENOMEM;<br>
> @@ -32,6 +76,7 @@ int _POSIX_Shm_Object_create_from_workspace(<br>
>    memset( shm_obj->handle, 0, size );<br>
>    shm_obj->size = size;<br>
>    return 0;<br>
> +#endif<br>
>  }<br>
><br>
>  int _POSIX_Shm_Object_delete_from_workspace( POSIX_Shm_Object *shm_obj )<br>
> @@ -97,4 +142,3 @@ void * _POSIX_Shm_Object_mmap_from_workspace(<br>
><br>
>    return (char*)shm_obj->handle + off;<br>
>  }<br>
> -<br>
stray change<br>
<br>
> diff --git a/cpukit/score/cpu/arm/cpu_asm.S b/cpukit/score/cpu/arm/cpu_asm.S<br>
> index 66f8ba6032..8e9a4a9f88 100644<br>
> --- a/cpukit/score/cpu/arm/cpu_asm.S<br>
> +++ b/cpukit/score/cpu/arm/cpu_asm.S<br>
> @@ -66,6 +66,73 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch)<br>
><br>
>         str     r3, [r0, #ARM_CONTEXT_CONTROL_ISR_DISPATCH_DISABLE]<br>
><br>
> +#if defined ( RTEMS_THREAD_STACK_PROTECTION )<br>
> +<br>
> +/*<br>
> + * We make a function call to set the memory attributes of the heir<br>
> + * stack and unset that of the executing stack (including shared stacks ).<br>
> + * This will be a simple asm code when done by switching the translation<br>
> + * table base.<br>
> + */<br>
> +<br>
> +/* Save the registers modified during function call */<br>
> +       mov r8, r0<br>
> +       mov r9, r1<br>
> +       mov r10, r2<br>
> +/* Load the parameters for function call */<br>
> +       mov r0, r1<br>
> +       sub r0, r0, #76<br>
> +       ldr r1, [r0]<br>
> +       ldr r0, [r0, #4]<br>
> +       mov r2, #3<br>
> +       bl _Memory_protection_Set_entries<br>
> +<br>
> +/* Restore the saved registers  */<br>
> +       mov r0, r8<br>
> +       mov r1, r9<br>
> +       mov r2, r10<br>
> +<br>
> +/* We load the stack-pointer of the heir thread pre-maturely, this is<br>
> + * done as oherwise the *_unset_entries call will execute from the stack of the<br>
> + * executing thread causing fatal exceptions.<br>
> + */<br>
> +       ldr sp, [r1, #32]<br>
> +/* Load the parameters of the function call */<br>
> +       mov r1, r0<br>
> +       sub r0, r0, #76<br>
> +       ldr r1, [r0]<br>
> +       ldr r0, [r0, #4]<br>
> +       bl  _Memory_protection_Unset_entries<br>
> +/*<br>
> + * Restore the saved registers<br>
> + */<br>
> +       mov r0, r8<br>
> +       mov r1, r9<br>
> +       mov r2, r10<br>
> +<br>
> +/* Set the memory entries of the shared stack */<br>
> +    sub        r0, r0, #76<br>
> +       add r6, r0, #16<br>
> +<br>
> +.L_shared_stack_restore:<br>
> +<br>
> +       ldr r1, [r6, #8]<br>
> +       ldr r0, [r6, #12]<br>
> +       bl _Memory_protection_Unset_entries<br>
> +       add  r6, #4<br>
> +       add  r11, #1<br>
> +/* We compare with a hard-coded value, this is the number of shared stacks<br>
> + * (SHARED_STACK_NUMBER)<br>
> + */<br>
> +       cmp r11, #8<br>
> +       bne .L_shared_stack_restore<br>
> +<br>
> +/* Restore the saved registers  */<br>
> +       mov r0, r8<br>
> +       mov r1, r9<br>
> +       mov r2, r10<br>
> +#endif<br>
> +<br>
>  #ifdef RTEMS_SMP<br>
>         /*<br>
>          * The executing thread no longer executes on this processor.  Switch<br>
> @@ -95,6 +162,7 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch)<br>
><br>
>  /* Start restoring context */<br>
>  .L_restore:<br>
> +<br>
>  #if !defined(RTEMS_SMP) && defined(ARM_MULTILIB_HAS_LOAD_STORE_EXCLUSIVE)<br>
>         clrex<br>
>  #endif<br>
> @@ -133,7 +201,33 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch)<br>
>   */<br>
>  DEFINE_FUNCTION_ARM(_CPU_Context_restore)<br>
>          mov     r1, r0<br>
> +<br>
>         GET_SELF_CPU_CONTROL    r2<br>
> +<br>
> +#if defined ( RTEMS_THREAD_STACK_PROTECTION )<br>
> +<br>
> +       /* Save the registers modified during function call */<br>
> +       mov r8, r0<br>
> +       mov r9, r1<br>
> +       mov r10, r2<br>
> +<br>
> +       /* Load the parameters for function call */<br>
> +       mov r1, r0<br>
> +       sub r0, r0, #76<br>
> +       ldr r1, [r0]<br>
> +       ldr r0, [r0, #4]<br>
> +       mov r2, #3<br>
> +       bl _Memory_protection_Set_entries<br>
> +<br>
> +       /* Restore the saved registers   */<br>
> +       mov r0, r8<br>
> +       mov r1, r9<br>
> +       mov r2, r10<br>
> +<br>
> +       /* Set memory entries of the shared thread stacks */<br>
> +<br>
> +<br>
> +#endif<br>
>          b       .L_restore<br>
><br>
>  #ifdef RTEMS_SMP<br>
> diff --git a/cpukit/score/src/stackprotection.c b/cpukit/score/src/stackprotection.c<br>
> new file mode 100644<br>
> index 0000000000..8427046aa0<br>
> --- /dev/null<br>
> +++ b/cpukit/score/src/stackprotection.c<br>
> @@ -0,0 +1,103 @@<br>
> +/* SPDX-License-Identifier: BSD-2-Clause */<br>
> +<br>
> +/**<br>
> + * @file<br>
> + *<br>
> + * @ingroup RTEMSScoreStackprotection<br>
> + *<br>
> + */<br>
> +<br>
> +/*<br>
> + * Copyright (C) 2020 Utkarsh Rai<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
> + * POSSIBILITY OF SUCH DAMAGE.<br>
> + */<br>
> +<br>
> +<br>
> +#ifdef HAVE_CONFIG_H<br>
> +#include "config.h"<br>
> +#endif<br>
> +<br>
> +#include <rtems/score/stackprotection.h><br>
> +#include <rtems/score/threadimpl.h><br>
> +<br>
> +void _Stackprotection_Context_restore(<br>
> +Stack_Control *heir_stack<br>
> +)<br>
> +{<br>
> +  void* stack_address;<br>
> +  size_t stack_size;<br>
> +  uint32_t memory_flags;<br>
> +  uint32_t index;<br>
> +<br>
> +  for(index = 0;index < heir_stack->shared_stacks_count; index++) {<br>
> +    stack_address = heir_stack->shared_stacks[index]->shared_stack_area;<br>
> +    stack_size = heir_stack->shared_stacks[index]->shared_stack_size;<br>
> +    _Memory_protection_Set_entries( stack_address, stack_size, memory_flags );<br>
> +  }<br>
> +<br>
> +}<br>
> +<br>
> +static bool get_target_thread( Thread_Control *Control, void *arg)<br>
> +{<br>
> +  Stack_Shared_attr *shared_stack;<br>
> +  uint32_t count;<br>
> +  shared_stack = arg;<br>
> +  /**<br>
> +   * Check for the target thread by comparing the stack address. Add the shared stack<br>
> +   * attribute structure to the array tracking all the shared stacks.<br>
> +   */<br>
> +  if( Control->Start.Initial_stack.area == shared_stack->target_stack_area) {<br>
> +     count =  Control->Start.Initial_stack.shared_stacks_count + 1;<br>
> +     if(count >= SHARED_STACK_NUMBER) {<br>
> +       return false;<br>
> +     }<br>
> +     Control->Start.Initial_stack.shared_stacks_count = count;<br>
> +     Control->Start.Initial_stack.shared_stacks[count] = shared_stack;<br>
> +     shared_stack->stack_shared = true;<br>
> +<br>
> +     return true;<br>
> +  }<br>
> +}<br>
> +<br>
> +int _Stackprotection_Share_stack(<br>
> +  void* target_stack,<br>
> +  void* sharing_stack,<br>
> +  size_t size,<br>
> +  uint32_t memory_flag<br>
> +)<br>
> +{<br>
> + Thread_Control *target_thread;<br>
> + Stack_Shared_attr shared_stack;<br>
> +<br>
> + shared_stack.Base.access_flags= memory_flag;<br>
> + shared_stack.shared_stack_area = sharing_stack;<br>
> + shared_stack.target_stack_area = target_stack;<br>
> + shared_stack.shared_stack_size = size;<br>
> +<br>
> + _Thread_Iterate( get_target_thread, &shared_stack );<br>
> + if( shared_stack.stack_shared == true ) {<br>
> +   return 0;<br>
> + } else {<br>
> +   return -1;<br>
> + }<br>
> +}<br>
> \ No newline at end of file<br>
> diff --git a/cpukit/score/src/threadhandler.c b/cpukit/score/src/threadhandler.c<br>
> index 6742b0b391..c18e33f688 100644<br>
> --- a/cpukit/score/src/threadhandler.c<br>
> +++ b/cpukit/score/src/threadhandler.c<br>
> @@ -22,6 +22,7 @@<br>
>  #include <rtems/score/assert.h><br>
>  #include <rtems/score/interr.h><br>
>  #include <rtems/score/isrlevel.h><br>
> +#include <rtems/score/stackprotection.h><br>
>  #include <rtems/score/userextimpl.h><br>
><br>
>  /*<br>
> @@ -94,6 +95,11 @@ void _Thread_Handler( void )<br>
>    level = executing->Start.isr_level;<br>
>    _ISR_Set_level( level );<br>
><br>
> +  /*<br>
> +   * Switch-out the the shared thread-stacks<br>
delete the<br>
<br>
> +   */<br>
> +  _Stackprotection_Context_restore( &executing->Start.Initial_stack );<br>
> +<br>
>    /*<br>
>     * Initialize the floating point context because we do not come<br>
>     * through _Thread_Dispatch on our first invocation. So the normal<br>
> diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c<br>
> index 691f56388e..96db4193bc 100644<br>
> --- a/cpukit/score/src/threadinitialize.c<br>
> +++ b/cpukit/score/src/threadinitialize.c<br>
> @@ -114,6 +114,15 @@ bool _Thread_Initialize(<br>
>       stack_size<br>
>    );<br>
><br>
> +#if defined ( RTEMS_THREAD_STACK_PROTECTION )<br>
> +  /**<br>
> +   * Initialize the protected stack attributes. Initially we initialize the<br>
> +   * thread with no access attributes, on context switch/restore action the<br>
> +   * thread stacks are assigned READ/WRITE attribute.<br>
> +   */<br>
> +   the_thread->Start.Initial_stack.Base.access_flags = RTEMS_NO_ACCESS | RTEMS_MEMORY_CACHED;<br>
> +#endif<br>
> +<br>
>    /*<br>
>     *  Get thread queue heads<br>
>     */<br>
> diff --git a/spec/build/bsps/arm/realview-pbx-a9/bsprealviewpbxa9.yml b/spec/build/bsps/arm/realview-pbx-a9/bsprealviewpbxa9.yml<br>
> index 2721152b93..f7d2187c66 100644<br>
> --- a/spec/build/bsps/arm/realview-pbx-a9/bsprealviewpbxa9.yml<br>
> +++ b/spec/build/bsps/arm/realview-pbx-a9/bsprealviewpbxa9.yml<br>
> @@ -57,6 +57,7 @@ links:<br>
>  source:<br>
>  - bsps/arm/realview-pbx-a9/console/console-config.c<br>
>  - bsps/arm/realview-pbx-a9/console/console-polled.c<br>
> +- bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c<br>
>  - bsps/arm/realview-pbx-a9/start/bspreset.c<br>
>  - bsps/arm/realview-pbx-a9/start/bspstart.c<br>
>  - bsps/arm/realview-pbx-a9/start/bspstarthooks.c<br>
> diff --git a/spec/build/cpukit/cpuopts.yml b/spec/build/cpukit/cpuopts.yml<br>
> index 1902e543ca..f7641a5e50 100644<br>
> --- a/spec/build/cpukit/cpuopts.yml<br>
> +++ b/spec/build/cpukit/cpuopts.yml<br>
> @@ -63,6 +63,8 @@ links:<br>
>    uid: optszoff<br>
>  - role: build-dependency<br>
>    uid: optsztime<br>
> +- role: build-dependency<br>
> +  uid: optthreadstackprotection<br>
>  - role: build-dependency<br>
>    uid: optversion<br>
>  target: cpukit/include/rtems/score/cpuopts.h<br>
> diff --git a/spec/build/cpukit/librtemscpu.yml b/spec/build/cpukit/librtemscpu.yml<br>
> index 63a0b7dca5..9855401665 100644<br>
> --- a/spec/build/cpukit/librtemscpu.yml<br>
> +++ b/spec/build/cpukit/librtemscpu.yml<br>
> @@ -353,6 +353,7 @@ install:<br>
>    - cpukit/include/rtems/score/isrlevel.h<br>
>    - cpukit/include/rtems/score/isrlock.h<br>
>    - cpukit/include/rtems/score/memory.h<br>
> +  - cpukit/include/rtems/score/memoryprotection.h<br>
>    - cpukit/include/rtems/score/mpci.h<br>
>    - cpukit/include/rtems/score/mpciimpl.h<br>
>    - cpukit/include/rtems/score/mppkt.h<br>
> @@ -405,6 +406,7 @@ install:<br>
>    - cpukit/include/rtems/score/smplockstats.h<br>
>    - cpukit/include/rtems/score/smplockticket.h<br>
>    - cpukit/include/rtems/score/stack.h<br>
> +  - cpukit/include/rtems/score/stackprotection.h<br>
>    - cpukit/include/rtems/score/stackimpl.h<br>
>    - cpukit/include/rtems/score/states.h<br>
>    - cpukit/include/rtems/score/statesimpl.h<br>
> @@ -1509,6 +1511,7 @@ source:<br>
>  - cpukit/score/src/semaphore.c<br>
>  - cpukit/score/src/smpbarrierwait.c<br>
>  - cpukit/score/src/stackallocator.c<br>
> +- cpukit/score/src/stackprotection.c<br>
>  - cpukit/score/src/threadallocateunlimited.c<br>
>  - cpukit/score/src/thread.c<br>
>  - cpukit/score/src/threadchangepriority.c<br>
> diff --git a/spec/build/cpukit/optthreadstackprotection.yml b/spec/build/cpukit/optthreadstackprotection.yml<br>
> new file mode 100644<br>
> index 0000000000..4722d9f0cb<br>
> --- /dev/null<br>
> +++ b/spec/build/cpukit/optthreadstackprotection.yml<br>
> @@ -0,0 +1,16 @@<br>
> +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause<br>
> +actions:<br>
> +- get-boolean: null<br>
> +- env-enable: null<br>
> +- define-condition: null<br>
> +build-type: option<br>
> +copyrights:<br>
> +- Copyright (C) 2020 Utkarsh Rai (<a href="mailto:utkarsh.rai60@gmail.com" target="_blank">utkarsh.rai60@gmail.com</a>)<br>
> +default: false<br>
> +default-by-variant: []<br>
> +description: |<br>
> +  Enable the thread stack protection support<br>
> +enabled-by: true<br>
> +links: []<br>
> +name: RTEMS_THREAD_STACK_PROTECTION<br>
> +type: build<br>
> diff --git a/spec/build/testsuites/samples/grp.yml b/spec/build/testsuites/samples/grp.yml<br>
> index c7591dc551..f0367b0f9b 100644<br>
> --- a/spec/build/testsuites/samples/grp.yml<br>
> +++ b/spec/build/testsuites/samples/grp.yml<br>
> @@ -40,6 +40,10 @@ links:<br>
>    uid: pppd<br>
>  - role: build-dependency<br>
>    uid: ticker<br>
> +- role: build-dependency<br>
> +  uid: threadstackprotection<br>
> +- role: build-dependency<br>
> +  uid: threadstacksharing<br>
>  - role: build-dependency<br>
>    uid: unlimited<br>
>  type: build<br>
> diff --git a/spec/build/testsuites/samples/threadstackprotection.yml b/spec/build/testsuites/samples/threadstackprotection.yml<br>
> new file mode 100644<br>
> index 0000000000..a33c53d392<br>
> --- /dev/null<br>
> +++ b/spec/build/testsuites/samples/threadstackprotection.yml<br>
> @@ -0,0 +1,19 @@<br>
> +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause<br>
> +build-type: test-program<br>
> +cflags: []<br>
> +copyrights:<br>
> +- Copyright (C) 2020 Utkarsh Rai (<a href="mailto:utkarsh.rai60@gmail.com" target="_blank">utkarsh.rai60@gmail.com</a>)<br>
> +cppflags: []<br>
> +cxxflags: []<br>
> +enabled-by: true<br>
> +features: c cprogram<br>
> +includes: []<br>
> +ldflags: []<br>
> +links: []<br>
> +source:<br>
> +- testsuites/samples/thread_stack_protection/init.c<br>
> +stlib: []<br>
> +target: testsuites/samples/thread_stack_protection.exe<br>
> +type: build<br>
> +use-after: []<br>
> +use-before: []<br>
> diff --git a/spec/build/testsuites/samples/threadstacksharing.yml b/spec/build/testsuites/samples/threadstacksharing.yml<br>
> new file mode 100644<br>
> index 0000000000..bbe99af189<br>
> --- /dev/null<br>
> +++ b/spec/build/testsuites/samples/threadstacksharing.yml<br>
> @@ -0,0 +1,19 @@<br>
> +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause<br>
> +build-type: test-program<br>
> +cflags: []<br>
> +copyrights:<br>
> +- Copyright (C) 2020 Utkarsh Rai (<a href="mailto:utkarsh.rai60@gmail.com" target="_blank">utkarsh.rai60@gmail.com</a>)<br>
> +cppflags: []<br>
> +cxxflags: []<br>
> +enabled-by: true<br>
> +features: c cprogram<br>
> +includes: []<br>
> +ldflags: []<br>
> +links: []<br>
> +source:<br>
> +- testsuites/samples/thread_stack_sharing/init.c<br>
> +stlib: []<br>
> +target: testsuites/samples/thread_stack_sharing.exe<br>
> +type: build<br>
> +use-after: []<br>
> +use-before: []<br>
> diff --git a/testsuites/samples/Makefile.am b/testsuites/samples/Makefile.am<br>
> index 1944d90ccc..4d76bcb167 100644<br>
> --- a/testsuites/samples/Makefile.am<br>
> +++ b/testsuites/samples/Makefile.am<br>
> @@ -146,6 +146,22 @@ ticker_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_ticker) \<br>
>         $(support_includes)<br>
>  endif<br>
><br>
> +if TEST_thread_stack_protection<br>
> +samples += thread_stack_protection<br>
> +sample_screens += thread_stack_protection/thread_stack_protection.scn<br>
> +sample_docs += thread_stack_protection/thread_stack_protection.doc<br>
> +thread_stack_protection_SOURCES = thread_stack_protection/init.c<br>
> +thread_stack_protection_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_thread_stack_protection) \<br>
> +       $(support_includes)<br>
> +endif<br>
> +<br>
> +if TEST_thread_stack_sharing<br>
> +samples += thread_stack_sharing<br>
> +thread_stack_sharing_SOURCES = thread_stack_sharing/init.c<br>
> +thread_stack_sharing_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_thread_stack_sharing) \<br>
> +       $(support_includes)<br>
> +endif<br>
> +<br>
>  if TEST_unlimited<br>
>  samples += unlimited<br>
>  sample_screens += unlimited/unlimited.scn<br>
> diff --git a/testsuites/samples/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a> b/testsuites/samples/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
> index 9721ea4f26..6460f8f2c9 100644<br>
> --- a/testsuites/samples/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
> +++ b/testsuites/samples/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
> @@ -50,6 +50,8 @@ RTEMS_TEST_CHECK([nsecs])<br>
>  RTEMS_TEST_CHECK([paranoia])<br>
>  RTEMS_TEST_CHECK([pppd])<br>
>  RTEMS_TEST_CHECK([ticker])<br>
> +RTEMS_TEST_CHECK([thread_stack_protection])<br>
> +RTEMS_TEST_CHECK([thread_stack_sharing])<br>
>  RTEMS_TEST_CHECK([unlimited])<br>
><br>
>  AC_CONFIG_FILES([Makefile])<br>
> diff --git a/testsuites/samples/thread_stack_protection/init.c b/testsuites/samples/thread_stack_protection/init.c<br>
> new file mode 100644<br>
> index 0000000000..a9359b459d<br>
> --- /dev/null<br>
> +++ b/testsuites/samples/thread_stack_protection/init.c<br>
> @@ -0,0 +1,112 @@<br>
> +#ifdef HAVE_CONFIG_H<br>
> +#include "config.h"<br>
> +#endif<br>
> +<br>
> +#include <rtems.h><br>
> +#include <tmacros.h><br>
> +#include <pthread.h><br>
> +#include <rtems/score/memoryprotection.h><br>
> +#include <rtems/score/thread.h><br>
> +const char rtems_test_name[] = " THREAD STACK PROTECTION ";<br>
> +<br>
> +static void fatal_extension(<br>
> +  rtems_fatal_source source,<br>
> +  bool is_internal,<br>
> +  rtems_fatal_code error<br>
> +)<br>
> +{<br>
> +  if (source == RTEMS_FATAL_SOURCE_EXCEPTION)<br>
> +     {<br>
> +       printk("Internal Exception Occured \n");<br>
> +     }<br>
> +<br>
> +  exit(0);<br>
> +}<br>
> +<br>
> +void* Test_routine( void* arg )<br>
> +{<br>
> +<br>
> +}<br>
> +<br>
> +void *POSIX_Init( void *argument )<br>
> +{<br>
> +  void *stack_addr1;<br>
> +  void *stack_addr2;<br>
> +  size_t stack_size1;<br>
> +  size_t stack_size2;<br>
> +  pthread_t id1;<br>
> +  pthread_t id2;<br>
> +  pthread_attr_t attr1;<br>
> +  pthread_attr_t attr2;<br>
> +  Thread_Control Control;<br>
> +  TEST_BEGIN();<br>
> +<br>
> + /*<br>
> +  *  We set the stack size as 8Kb.<br>
> +  */<br>
> +  stack_size1 = 8192;<br>
> +  stack_size2 = 8192;<br>
> +  printf("%d %d \n",sizeof(Control.Post_switch_actions), sizeof(Control.Start.tls_area));<br>
> +  /*<br>
> +   * We allocate page-aligned memory of the stack  from the application.<br>
> +   */<br>
> +  posix_memalign(&stack_addr1, sysconf( _SC_PAGESIZE ), stack_size1 );<br>
> +  posix_memalign(&stack_addr2, sysconf( _SC_PAGESIZE ), stack_size2 );<br>
> +<br>
> +  pthread_attr_init( &attr1 );<br>
> +  pthread_attr_init( &attr2 );<br>
> +<br>
> + /*<br>
> +  * We set the stack size and address of the thread from the application itself<br>
> +  */<br>
> +  pthread_attr_setstack( &attr1, stack_addr1, stack_size1 );<br>
> +  pthread_attr_setstack( &attr2, stack_addr2, stack_size2 );<br>
> +<br>
> +  pthread_create( &id1, &attr1, Test_routine, NULL );<br>
> +  pthread_create( &id2, &attr2, Test_routine, NULL );<br>
> + /*<br>
> +  * We set the memory attributes of the stack from the application.<br>
> +  */<br>
> +  _Memory_protection_Set_entries( stack_addr1, stack_size1, RTEMS_NO_ACCESS | RTEMS_MEMORY_CACHED );<br>
> +  _Memory_protection_Set_entries( stack_addr2, stack_size2, RTEMS_NO_ACCESS | RTEMS_MEMORY_CACHED );<br>
> +<br>
> +  pthread_join( id1, NULL );<br>
> +  /*<br>
> +   * Write to the stack address of thread1 after it has been switched out.<br>
> +   */<br>
> +  printf("Writing to the stack of thread1 \n");<br>
> +  memset(stack_addr1, 0, stack_size1);<br>
> +<br>
> +  pthread_join( id2, NULL );<br>
> +   /*<br>
> +   * Write to the stack address of thread2 after it has been switched out.<br>
> +   */<br>
> +<br>
> +<br>
> +<br>
> +  TEST_END();<br>
> +  rtems_test_exit( 0 );<br>
> +}<br>
> +<br>
> +/* configuration information */<br>
> +<br>
> +#define CONFIGURE_INIT<br>
> +<br>
> +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER<br>
> +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER<br>
> +<br>
> +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION<br>
> +<br>
> +#define CONFIGURE_MAXIMUM_POSIX_THREADS        2<br>
> +<br>
> +#define CONFIGURE_POSIX_INIT_THREAD_TABLE<br>
> +<br>
> +#define CONFIGURE_INITIAL_EXTENSIONS { .fatal = fatal_extension }<br>
> +<br>
> +#define CONFIGURE_TASK_STACK_ALLOCATOR_INIT  bsp_stack_allocate_init<br>
> +#define CONFIGURE_TASK_STACK_ALLOCATOR       bsp_stack_allocate<br>
> +#define CONFIGURE_TASK_STACK_DEALLOCATOR     bsp_stack_free<br>
> +<br>
> +#include <bsp/stackalloc.h><br>
> +#define CONFIGURE_INIT<br>
> +#include <rtems/confdefs.h><br>
> \ No newline at end of file<br>
> diff --git a/testsuites/samples/thread_stack_protection/thread_stack_protection.doc b/testsuites/samples/thread_stack_protection/thread_stack_protection.doc<br>
> new file mode 100644<br>
> index 0000000000..c5c9cdfa81<br>
> --- /dev/null<br>
> +++ b/testsuites/samples/thread_stack_protection/thread_stack_protection.doc<br>
> @@ -0,0 +1,2 @@<br>
> +This test sample demonstrates the thread stack protection functionality. We try<br>
> +to write to the stack of a switched-out thread.<br>
> \ No newline at end of file<br>
> diff --git a/testsuites/samples/thread_stack_protection/thread_stack_protection.scn b/testsuites/samples/thread_stack_protection/thread_stack_protection.scn<br>
> new file mode 100644<br>
> index 0000000000..1d36d0dfaf<br>
> --- /dev/null<br>
> +++ b/testsuites/samples/thread_stack_protection/thread_stack_protection.scn<br>
> @@ -0,0 +1,20 @@<br>
> +<br>
> +*** BEGIN OF TEST  THREAD STACK PROTECTION  ***<br>
> +*** TEST VERSION: 5.0.0.a3b39c9e567f3f1ef5ab01de78b113e61b11853b-modified<br>
> +*** TEST STATE: EXPECTED_PASS<br>
> +*** TEST BUILD: RTEMS_NETWORKING RTEMS_POSIX_API<br>
> +*** TEST TOOLS: 7.5.0 20191114 (RTEMS 5, RSB 5 (3bd11fd4898b), Newlib 7947581)<br>
> +Creating thread1<br>
> +Creating thread2<br>
> +Joining thread1<br>
> +Writing to the stack of thread1<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> +Internal Exception Occured<br>
> \ No newline at end of file<br>
> diff --git a/testsuites/samples/thread_stack_sharing/init.c b/testsuites/samples/thread_stack_sharing/init.c<br>
> new file mode 100644<br>
> index 0000000000..5bb7d01418<br>
> --- /dev/null<br>
> +++ b/testsuites/samples/thread_stack_sharing/init.c<br>
> @@ -0,0 +1,136 @@<br>
> +#ifdef HAVE_CONFIG_H<br>
> +#include "config.h"<br>
> +#endif<br>
> +<br>
> +#include <rtems.h><br>
> +#include <tmacros.h><br>
> +#include <pthread.h><br>
> +#include <sys/mman.h><br>
> +#include <sys/fcntl.h><br>
> +#include <rtems/score/memoryprotection.h><br>
> +<br>
> +const char rtems_test_name[] = " THREAD STACK SHARING ";<br>
> +<br>
> +void* Test_routine( void* arg )<br>
> +{<br>
> +<br>
> +}<br>
> +<br>
> +void *POSIX_Init( void *argument )<br>
> +{<br>
> +  void *stack_addr1;<br>
> +  void *stack_addr2;<br>
> +  void* addr;<br>
> +  size_t stack_size1;<br>
> +  size_t stack_size2;<br>
> +  pthread_t id1;<br>
> +  pthread_t id2;<br>
> +  pthread_attr_t attr1;<br>
> +  pthread_attr_t attr2;<br>
> +  int fd;<br>
> +  char name[4] = "0x01";<br>
> +  char thread_name[13] = "/taskfs/0x01";<br>
> +<br>
> +  TEST_BEGIN();<br>
> +<br>
> + /*<br>
> +  *  We set the stack size as 8Kb.<br>
> +  */<br>
> +  stack_size1 = 8192;<br>
> +  stack_size2 = 8192;<br>
> +<br>
> +  /*<br>
> +   * We allocate page-aligned memory of the stack  from the application.<br>
> +   */<br>
> +  posix_memalign(&stack_addr1, sysconf( _SC_PAGESIZE ), stack_size1 );<br>
> +  posix_memalign(&stack_addr2, sysconf( _SC_PAGESIZE ), stack_size2 );<br>
> +<br>
> +  pthread_attr_init( &attr1 );<br>
> +  pthread_attr_init( &attr2 );<br>
> +<br>
> + /*<br>
> +  * We set the stack size and address of the thread from the application itself<br>
> +  */<br>
> +  pthread_attr_setstack( &attr1, stack_addr1, stack_size1 );<br>
> +  pthread_attr_setstack( &attr2, stack_addr2, stack_size2 );<br>
> +<br>
> +  pthread_create( &id1, &attr1, Test_routine, NULL );<br>
> +<br>
> + /*<br>
> +  * We set the memory attributes of the stack from the application.<br>
> +  */<br>
> +  _Memory_protection_Set_entries( stack_addr1, stack_size1, RTEMS_READ_ONLY | RTEMS_MEMORY_CACHED );<br>
> +<br>
> +    pthread_create( &id2, &attr2, Test_routine, NULL );<br>
> +  _Memory_protection_Set_entries( stack_addr2, stack_size2, RTEMS_READ_ONLY | RTEMS_MEMORY_CACHED );<br>
> +<br>
> +  /*<br>
> +   * Add leading "/taskfs/" to denote thread-stack name.<br>
> +   */<br>
> +  strlcat( thread_name, name, 4);<br>
> +<br>
> +  /*<br>
> +  * Set the name of the thread object same as that of the shared memory object name<br>
> +  */<br>
> +  rtems_object_set_name( id1, name);<br>
> +<br>
> +  /*<br>
> +   * Create a shared memory object of the  stack we want to share with<br>
> +   * appropraite permissions. We share the stack with read and write permission<br>
> +   */<br>
> +  fd = shm_open( thread_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR );<br>
> +<br>
> +  /*<br>
> +   * Truncate the size of the file to the size of the stack.<br>
> +   */<br>
> +  ftruncate( fd, stack_size1 );<br>
> +<br>
> +  /*<br>
> +   * For sharing the stack we specify the address of the<br>
> +   * thread-stack we want to share with, the size of the shared stack,<br>
> +   * protection and access flags, file descriptor of the shared memory objcet<br>
> +   */<br>
> +  addr = mmap( stack_addr2, stack_size1, PROT_READ | PROT_WRITE, O_RDWR, fd, 0 );<br>
> +  rtems_test_assert( addr != NULL );<br>
> +<br>
> +  pthread_join( id1, NULL );<br>
> +  /*<br>
> +   * Write to the stack address of thread1 after it has been switched out.<br>
> +   */<br>
> +  memset( stack_addr1, 0, stack_size1 );<br>
> +<br>
> +  pthread_join( id2, NULL );<br>
> +   /*<br>
> +   * Write to the stack address of thread2 after it has been switched out.<br>
> +   */<br>
> +  memset( stack_addr2, 0, stack_size2 );<br>
> +<br>
> +<br>
> +  TEST_END();<br>
> +  rtems_test_exit( 0 );<br>
> +}<br>
> +<br>
> +/* configuration information */<br>
> +<br>
> +#define CONFIGURE_INIT<br>
> +<br>
> +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER<br>
> +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER<br>
> +<br>
> +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION<br>
> +<br>
> +#define CONFIGURE_MAXIMUM_POSIX_THREADS        4<br>
> +<br>
> +#define CONFIGURE_MAXIMUM_POSIX_SHMS           2<br>
> +<br>
> +#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 10<br>
> +<br>
> +#define CONFIGURE_POSIX_INIT_THREAD_TABLE<br>
> +<br>
> +#define CONFIGURE_TASK_STACK_ALLOCATOR_INIT  bsp_stack_allocate_init<br>
> +#define CONFIGURE_TASK_STACK_ALLOCATOR       bsp_stack_allocate<br>
> +#define CONFIGURE_TASK_STACK_DEALLOCATOR     bsp_stack_free<br>
> +<br>
> +#include <bsp/stackalloc.h><br>
> +#define CONFIGURE_INIT<br>
> +#include <rtems/confdefs.h><br>
> \ No newline at end of file<br>
> --<br>
> 2.17.1<br>
><br>
</blockquote></div></div>