-This patch provides thread-stack isolation and thread-stack sharing mechanism for a POSIX thread.
-The patches are based on sebastian's build-2 branch of sebastian's repo https://git.rtems.org/sebh -Configurations options are provided by using the new-build system. Refer to https://ftp.rtems.org/pub/rtems/people/sebh/user.pdf, chapter 7,for basic setup and https://ftp.rtems.org/pub/rtems/people/sebh/eng.pdf(chapter 9) for the internals of the build system. --- .../realview-pbx-a9/mmu/bsp-set-mmu-attr.c | 75 ++++++++++ bsps/shared/start/stackalloc.c | 12 +- .../libbsp/arm/realview-pbx-a9/Makefile.am | 3 + cpukit/Makefile.am | 1 + cpukit/headers.am | 2 + cpukit/include/rtems/score/memoryprotection.h | 91 ++++++++++++ cpukit/include/rtems/score/stack.h | 49 +++++++ cpukit/include/rtems/score/stackprotection.h | 80 +++++++++++ cpukit/include/rtems/score/thread.h | 1 + cpukit/posix/src/mmap.c | 41 +++++- cpukit/posix/src/shmwkspace.c | 46 +++++- cpukit/score/cpu/arm/cpu_asm.S | 94 ++++++++++++ cpukit/score/src/stackprotection.c | 103 +++++++++++++ cpukit/score/src/threadhandler.c | 6 + cpukit/score/src/threadinitialize.c | 9 ++ .../arm/realview-pbx-a9/bsprealviewpbxa9.yml | 1 + spec/build/cpukit/cpuopts.yml | 2 + spec/build/cpukit/librtemscpu.yml | 3 + .../build/cpukit/optthreadstackprotection.yml | 16 +++ spec/build/testsuites/samples/grp.yml | 4 + .../samples/threadstackprotection.yml | 19 +++ .../testsuites/samples/threadstacksharing.yml | 19 +++ testsuites/samples/Makefile.am | 16 +++ testsuites/samples/configure.ac | 2 + .../samples/thread_stack_protection/init.c | 112 +++++++++++++++ .../thread_stack_protection.doc | 2 + .../thread_stack_protection.scn | 20 +++ .../samples/thread_stack_sharing/init.c | 136 ++++++++++++++++++ 28 files changed, 959 insertions(+), 6 deletions(-) create mode 100644 bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c create mode 100644 cpukit/include/rtems/score/memoryprotection.h create mode 100644 cpukit/include/rtems/score/stackprotection.h create mode 100644 cpukit/score/src/stackprotection.c create mode 100644 spec/build/cpukit/optthreadstackprotection.yml create mode 100644 spec/build/testsuites/samples/threadstackprotection.yml create mode 100644 spec/build/testsuites/samples/threadstacksharing.yml create mode 100644 testsuites/samples/thread_stack_protection/init.c create mode 100644 testsuites/samples/thread_stack_protection/thread_stack_protection.doc create mode 100644 testsuites/samples/thread_stack_protection/thread_stack_protection.scn create mode 100644 testsuites/samples/thread_stack_sharing/init.c 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 new file mode 100644 index 0000000000..c3b469dd2a --- /dev/null +++ b/bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c @@ -0,0 +1,75 @@ +#include <bsp/arm-cp15-start.h> +#include <rtems/score/memoryprotection.h> +#include <libcpu/arm-cp15.h> +#include <rtems.h> + +static uint32_t translate_flags(uint32_t attr_flags) +{ + uint32_t flags; + uint32_t memory_attribute; + + switch (attr_flags) + { + case RTEMS_READ_WRITE: + flags = ARMV7_MMU_READ_WRITE; + break; + + case RTEMS_READ_ONLY: + flags = ARMV7_MMU_READ_ONLY; + break; + + case RTEMS_NO_ACCESS: + default: + flags = 0; + break; + } + + /* + * Check for memory-cache operation + */ + if( attr_flags & RTEMS_MEMORY_CACHED ) { + flags |= ARM_MMU_SECT_TEX_0 | ARM_MMU_SECT_C | ARM_MMU_SECT_B; + } + + return flags; +} + +void _Memory_protection_Set_entries(uintptr_t begin, size_t size, uint32_t flags) +{ + uintptr_t end; + rtems_interrupt_level irq_level; + uint32_t access_flags; + + if(begin != NULL ) { + end = begin + size; + access_flags = translate_flags(flags); + + /* + * The ARM reference manual instructs to disable all the interrupts before + * setting up page table entries. + */ + rtems_interrupt_disable(irq_level); + arm_cp15_set_translation_table_entries(begin, end, access_flags); + rtems_interrupt_enable(irq_level); + } +} + +void _Memory_protection_Unset_entries(uintptr_t begin, size_t size) +{ + uint32_t access_flags; + uintptr_t end; + rtems_interrupt_level irq_level; + + if( begin != NULL ) { + end = begin + size; + access_flags = translate_flags( RTEMS_NO_ACCESS ); + + /* + * The ARM reference manual instructs to disable all the interrupts before + * setting up page table entries. + */ + rtems_interrupt_disable(irq_level); + arm_cp15_set_translation_table_entries(begin, end, access_flags); + rtems_interrupt_enable(irq_level); + } +} \ No newline at end of file diff --git a/bsps/shared/start/stackalloc.c b/bsps/shared/start/stackalloc.c index f7cf7be0f1..6ebef4d6e5 100644 --- a/bsps/shared/start/stackalloc.c +++ b/bsps/shared/start/stackalloc.c @@ -44,6 +44,15 @@ void *bsp_stack_allocate(size_t size) { void *stack = NULL; +#if defined (RTEMS_THREAD_STACK_PROTECTION) +/* + * This is a temporary hack, we need to use _Heap_Allocate_aligned() but the heap + * intialization for bsp_stack_heap fails as bsp_section_stack_size is 0. See + * bsp_stack_allocate_init(). + */ + posix_memalign(&stack, 4096 , size); + _Memory_protection_Set_entries( stack, size, ( RTEMS_READ_ONLY | RTEMS_MEMORY_CACHED ) ); +#else if (bsp_stack_heap.area_begin != 0) { stack = _Heap_Allocate(&bsp_stack_heap, size); } @@ -51,6 +60,7 @@ void *bsp_stack_allocate(size_t size) if (stack == NULL) { stack = _Workspace_Allocate(size); } +#endif return stack; } @@ -62,4 +72,4 @@ void bsp_stack_free(void *stack) if (!ok) { _Workspace_Free(stack); } -} +} \ No newline at end of file diff --git a/c/src/lib/libbsp/arm/realview-pbx-a9/Makefile.am b/c/src/lib/libbsp/arm/realview-pbx-a9/Makefile.am index d5549275be..24847c7b91 100644 --- a/c/src/lib/libbsp/arm/realview-pbx-a9/Makefile.am +++ b/c/src/lib/libbsp/arm/realview-pbx-a9/Makefile.am @@ -74,6 +74,9 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-a9mpcore. librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-cp15.c librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-v7ar-disable-data.S +#MMU +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c + # Start hooks librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/realview-pbx-a9/start/bspstarthooks.c diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am index 75e119ea3c..2d50d0fdce 100644 --- a/cpukit/Makefile.am +++ b/cpukit/Makefile.am @@ -929,6 +929,7 @@ librtemscpu_a_SOURCES += score/src/schedulercbsgetserverid.c librtemscpu_a_SOURCES += score/src/schedulercbssetparameters.c librtemscpu_a_SOURCES += score/src/schedulercbsreleasejob.c librtemscpu_a_SOURCES += score/src/schedulercbsunblock.c +librtemscpu_a_SOURCES += score/src/stackprotection.c librtemscpu_a_SOURCES += score/src/stackallocator.c librtemscpu_a_SOURCES += score/src/pheapallocate.c librtemscpu_a_SOURCES += score/src/pheapextend.c diff --git a/cpukit/headers.am b/cpukit/headers.am index 0bba9674cd..211e17ddf8 100644 --- a/cpukit/headers.am +++ b/cpukit/headers.am @@ -352,6 +352,7 @@ include_rtems_score_HEADERS += include/rtems/score/isr.h include_rtems_score_HEADERS += include/rtems/score/isrlevel.h include_rtems_score_HEADERS += include/rtems/score/isrlock.h include_rtems_score_HEADERS += include/rtems/score/memory.h +include_rtems_score_HEADERS += include/rtems/score/memoryprotection.h include_rtems_score_HEADERS += include/rtems/score/mpci.h include_rtems_score_HEADERS += include/rtems/score/mpciimpl.h include_rtems_score_HEADERS += include/rtems/score/mppkt.h @@ -405,6 +406,7 @@ include_rtems_score_HEADERS += include/rtems/score/smplockstats.h include_rtems_score_HEADERS += include/rtems/score/smplockticket.h include_rtems_score_HEADERS += include/rtems/score/stack.h include_rtems_score_HEADERS += include/rtems/score/stackimpl.h +include_rtems_score_HEADERS += include/rtems/score/stackprotection.h include_rtems_score_HEADERS += include/rtems/score/states.h include_rtems_score_HEADERS += include/rtems/score/statesimpl.h include_rtems_score_HEADERS += include/rtems/score/status.h diff --git a/cpukit/include/rtems/score/memoryprotection.h b/cpukit/include/rtems/score/memoryprotection.h new file mode 100644 index 0000000000..245e50313c --- /dev/null +++ b/cpukit/include/rtems/score/memoryprotection.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreMemoryprotection + * + * @brief This file provodes APIs for high-level memory protection + * + */ + +/* + * Copyright (C) 2020 Utkarsh Rai + * + * 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_MEMORYPROTECTION_H +#define _RTEMS_SCORE_MEMORYPROTECTION_H + +#if defined ( ASM ) + #include <rtems/asm.h> +#else + #include <rtems/score/basedefs.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined ( ASM ) + +#define RTEMS_NO_ACCESS 0x00 +#define RTEMS_READ_ONLY 0x01 +#define RTEMS_WRITE_ONLY 0x02 +#define RTEMS_READ_WRITE ( RTEMS_READ_ONLY | RTEMS_WRITE_ONLY ) +#define RTEMS_MEMORY_CACHED 0x04 + +/** + * @brief Define the memory access permission for the specified memory region + * + * @param begin_addr Beginning of the memory region + * @param size Size of the memory region + * @param flag Memory access flag + * + */ +void _Memory_protection_Set_entries( + uintptr_t begin_addr, + size_t size, + uint32_t flag +); + +/** + * @brief Unset the memory access permission for the specified memory region + * This operation implicitly sets the specified memory region with 'NO_ACCESS' + * flag. + * + * @param begin_addr Begining of the memory region + * @param size Size of the memory region + */ +void _Memory_protection_Unset_entries( + uintptr_t begin_addr, + size_t size +); + +#endif /* !defined ( ASM ) */ + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/cpukit/include/rtems/score/stack.h b/cpukit/include/rtems/score/stack.h index df1df74867..d561bf61c1 100644 --- a/cpukit/include/rtems/score/stack.h +++ b/cpukit/include/rtems/score/stack.h @@ -47,6 +47,47 @@ extern "C" { */ #define STACK_MINIMUM_SIZE CPU_STACK_MINIMUM_SIZE +/** + * The number of stacks that can be shared with a thread. + */ +#define SHARED_STACK_NUMBER 8 + +#if defined ( RTEMS_THREAD_STACK_PROTECTION ) +/** + * The following defines the attributes of a protected stack + */ +typedef struct +{ + /** The pointer to the page table base */ + uintptr_t page_table_base; + /**Memory flag for the alllocated/shared stack */ + uint32_t access_flags; +} Stack_Protection_attr; + + +/** + * The following defines the control block of a shared stack. Each stack can have + * different sharing attributes. + */ +typedef struct +{ + /** This is the attribute of a shared stack*/ + Stack_Protection_attr Base; + /** This is the stack address of the sharing thread*/ + void* shared_stack_area; + /** Stack size of the sharing thread*/ + size_t shared_stack_size; + /** This is the stack address of the target stack. Maybe this area is not + * needed but this helps in selecting the target thread during stack sharing. + */ + void* target_stack_area; + /** Error checking for valid target stack address. This is also used to + * distinguish between a normal mmap operation and a stack sharing operation. + */ + bool stack_shared; +} Stack_Shared_attr; +#endif + /** * The following defines the control block used to manage each stack. */ @@ -55,6 +96,14 @@ typedef struct { size_t size; /** This is the low memory address of stack. */ void *area; +#if defined (RTEMS_THREAD_STACK_PROTECTION) + /** The attribute of a protected stack */ + Stack_Protection_attr Base; + + Stack_Shared_attr *shared_stacks[SHARED_STACK_NUMBER]; + + uint32_t shared_stacks_count; +#endif } Stack_Control; /** diff --git a/cpukit/include/rtems/score/stackprotection.h b/cpukit/include/rtems/score/stackprotection.h new file mode 100644 index 0000000000..58ab5f8673 --- /dev/null +++ b/cpukit/include/rtems/score/stackprotection.h @@ -0,0 +1,80 @@ +/** + * @file + * + * @ingroup RTEMSScoreStackprotection + * + * @brief Stackprotection API + * + * This include file provides the API for the management of protected thread- + * stacks + */ + +/* + * COPYRIGHT (c) 2020 Utkarsh Rai. + * + * 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_STACKPROTECTION_H +#define _RTEMS_SCORE_STACKPROTECTION_H + +#include <rtems/score/basedefs.h> +#include <rtems/score/stack.h> +#include <rtems/score/memoryprotection.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Share the stack address of a given thread with the target thread. + * + * @param target_stack Stack address of the target thread + * @param sharing_stack Stack address of the sharin thread + */ + +int _Stackprotection_Share_stack( + void *target_stack, + void *sharing_stack, + size_t size, + uint32_t memory_flag +); + +/** + * @brief Swap the restored shared stacks in the page table during context + * restoration + * + * We set the entries of the restored stack and mark all the remainig stacks as + * 'NO-ACCESS'. + * + * @param Control block of the restored stack + */ +void _Stackprotection_Context_restore( + Stack_Control *heir_stack +); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/cpukit/include/rtems/score/thread.h b/cpukit/include/rtems/score/thread.h index ee0aee5b79..0ad22feac4 100644 --- a/cpukit/include/rtems/score/thread.h +++ b/cpukit/include/rtems/score/thread.h @@ -34,6 +34,7 @@ #include <rtems/score/priority.h> #include <rtems/score/schedulernode.h> #include <rtems/score/stack.h> +#include <rtems/score/stackprotection.h> #include <rtems/score/states.h> #include <rtems/score/threadq.h> #include <rtems/score/timestamp.h> diff --git a/cpukit/posix/src/mmap.c b/cpukit/posix/src/mmap.c index 176c6e4fe8..6587819c0f 100644 --- a/cpukit/posix/src/mmap.c +++ b/cpukit/posix/src/mmap.c @@ -28,7 +28,27 @@ #include <rtems/posix/mmanimpl.h> #include <rtems/posix/shmimpl.h> +#include <rtems/score/stackprotection.h> +#include <rtems/score/memoryprotection.h> +static uint32_t mmap_flag_translate(int prot) +{ + int prot_read; + int prot_write; + int memory_flag; + + prot_read = (prot_read & PROT_READ) == PROT_READ; + prot_write = (prot_write & PROT_WRITE) == PROT_WRITE; + + if(prot_read){ + memory_flag |= ( RTEMS_READ_ONLY| RTEMS_MEMORY_CACHED ); + } + if(prot_write) { + memory_flag |= ( RTEMS_READ_WRITE | RTEMS_MEMORY_CACHED ); + } + + return memory_flag; +} /** * mmap chain of mappings. @@ -50,6 +70,9 @@ void *mmap( bool map_private; bool is_shared_shm; int err; + uint32_t memory_flags; + uintptr_t shared_stack_address; + int status; map_fixed = (flags & MAP_FIXED) == MAP_FIXED; map_anonymous = (flags & MAP_ANON) == MAP_ANON; @@ -67,7 +90,10 @@ void *mmap( /* * We can provide read, write and execute because the memory in RTEMS does - * not normally have protections but we cannot hide access to memory. + * not normally have protections but we cannot hide access to memory. For + * thread-stack protection we can provide no-access option, but stacks are + * implicitly isolated and it makes no sense to specify no-access option for + * already isolated stacks. */ if ( prot == PROT_NONE ) { errno = ENOTSUP; @@ -292,11 +318,18 @@ void *mmap( free( mapping ); return MAP_FAILED; } + /** + * We share thread-stacks only when we have a shared memory object and map + * shared flag set + */ + memory_flags = mmap_flag_translate( prot ); + status = _Stackprotection_Share_stack( mapping->addr, addr, len,memory_flags ); + } + if(status == RTEMS_INVALID_ADDRESS ) { + rtems_chain_append_unprotected( &mmap_mappings, &mapping->node ); } - - rtems_chain_append_unprotected( &mmap_mappings, &mapping->node ); mmap_mappings_lock_release( ); return mapping->addr; -} +} \ No newline at end of file diff --git a/cpukit/posix/src/shmwkspace.c b/cpukit/posix/src/shmwkspace.c index 4fa4ec4771..e4e3c594d9 100644 --- a/cpukit/posix/src/shmwkspace.c +++ b/cpukit/posix/src/shmwkspace.c @@ -16,6 +16,7 @@ #include <errno.h> #include <string.h> +#include <rtems/posix/pthread.h> #include <rtems/score/wkspace.h> #include <rtems/posix/shmimpl.h> @@ -24,6 +25,49 @@ int _POSIX_Shm_Object_create_from_workspace( size_t size ) { +#if defined(RTEMS_THREAD_STACK_PROTECTION) + POSIX_Shm_Control *shm; + Objects_Id id; + Objects_Name_or_id_lookup_errors err; + Thread_Control *Control; + ISR_lock_Context lock_context; + char *name; + + shm = RTEMS_CONTAINER_OF(shm_obj, POSIX_Shm_Control, shm_object); + name = shm->Object.name.name_p; + /** We assign fixed pattern of naming for thread-stacks, and treat them + * accordingly. + */ + if( strncmp( name, "/taskfs/", 8) == 0 ) { + /** + * Obtain the object id of the thread and then get the thread control block + * corresponding to that id. + */ + err = _Objects_Name_to_id_u32( + &_POSIX_Threads_Information.Objects, + _Objects_Build_name( name[8], name[9], name[10], name[11]), + RTEMS_LOCAL, + &id + ); + Control = _Thread_Get( id, &lock_context ); + if( Control != NULL ) { + shm_obj->handle = Control->Start.Initial_stack.area; + if( size != Control->Start.Initial_stack.size) { + return ENOMEM; + } + } else { + return ENOMEM; + } + } else { + shm_obj->handle = _Workspace_Allocate( size ); + if ( shm_obj->handle == NULL ) { + return ENOMEM; + } + + shm_obj->size = size; + return 0; +} +#else shm_obj->handle = _Workspace_Allocate( size ); if ( shm_obj->handle == NULL ) { return ENOMEM; @@ -32,6 +76,7 @@ int _POSIX_Shm_Object_create_from_workspace( memset( shm_obj->handle, 0, size ); shm_obj->size = size; return 0; +#endif } int _POSIX_Shm_Object_delete_from_workspace( POSIX_Shm_Object *shm_obj ) @@ -97,4 +142,3 @@ void * _POSIX_Shm_Object_mmap_from_workspace( return (char*)shm_obj->handle + off; } - diff --git a/cpukit/score/cpu/arm/cpu_asm.S b/cpukit/score/cpu/arm/cpu_asm.S index 66f8ba6032..8e9a4a9f88 100644 --- a/cpukit/score/cpu/arm/cpu_asm.S +++ b/cpukit/score/cpu/arm/cpu_asm.S @@ -66,6 +66,73 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch) str r3, [r0, #ARM_CONTEXT_CONTROL_ISR_DISPATCH_DISABLE] +#if defined ( RTEMS_THREAD_STACK_PROTECTION ) + +/* + * We make a function call to set the memory attributes of the heir + * stack and unset that of the executing stack (including shared stacks ). + * This will be a simple asm code when done by switching the translation + * table base. + */ + +/* Save the registers modified during function call */ + mov r8, r0 + mov r9, r1 + mov r10, r2 +/* Load the parameters for function call */ + mov r0, r1 + sub r0, r0, #76 + ldr r1, [r0] + ldr r0, [r0, #4] + mov r2, #3 + bl _Memory_protection_Set_entries + +/* Restore the saved registers */ + mov r0, r8 + mov r1, r9 + mov r2, r10 + +/* We load the stack-pointer of the heir thread pre-maturely, this is + * done as oherwise the *_unset_entries call will execute from the stack of the + * executing thread causing fatal exceptions. + */ + ldr sp, [r1, #32] +/* Load the parameters of the function call */ + mov r1, r0 + sub r0, r0, #76 + ldr r1, [r0] + ldr r0, [r0, #4] + bl _Memory_protection_Unset_entries +/* + * Restore the saved registers + */ + mov r0, r8 + mov r1, r9 + mov r2, r10 + +/* Set the memory entries of the shared stack */ + sub r0, r0, #76 + add r6, r0, #16 + +.L_shared_stack_restore: + + ldr r1, [r6, #8] + ldr r0, [r6, #12] + bl _Memory_protection_Unset_entries + add r6, #4 + add r11, #1 +/* We compare with a hard-coded value, this is the number of shared stacks + * (SHARED_STACK_NUMBER) + */ + cmp r11, #8 + bne .L_shared_stack_restore + +/* Restore the saved registers */ + mov r0, r8 + mov r1, r9 + mov r2, r10 +#endif + #ifdef RTEMS_SMP /* * The executing thread no longer executes on this processor. Switch @@ -95,6 +162,7 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch) /* Start restoring context */ .L_restore: + #if !defined(RTEMS_SMP) && defined(ARM_MULTILIB_HAS_LOAD_STORE_EXCLUSIVE) clrex #endif @@ -133,7 +201,33 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch) */ DEFINE_FUNCTION_ARM(_CPU_Context_restore) mov r1, r0 + GET_SELF_CPU_CONTROL r2 + +#if defined ( RTEMS_THREAD_STACK_PROTECTION ) + + /* Save the registers modified during function call */ + mov r8, r0 + mov r9, r1 + mov r10, r2 + + /* Load the parameters for function call */ + mov r1, r0 + sub r0, r0, #76 + ldr r1, [r0] + ldr r0, [r0, #4] + mov r2, #3 + bl _Memory_protection_Set_entries + + /* Restore the saved registers */ + mov r0, r8 + mov r1, r9 + mov r2, r10 + + /* Set memory entries of the shared thread stacks */ + + +#endif b .L_restore #ifdef RTEMS_SMP diff --git a/cpukit/score/src/stackprotection.c b/cpukit/score/src/stackprotection.c new file mode 100644 index 0000000000..8427046aa0 --- /dev/null +++ b/cpukit/score/src/stackprotection.c @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreStackprotection + * + */ + +/* + * Copyright (C) 2020 Utkarsh Rai + * + * 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/stackprotection.h> +#include <rtems/score/threadimpl.h> + +void _Stackprotection_Context_restore( +Stack_Control *heir_stack +) +{ + void* stack_address; + size_t stack_size; + uint32_t memory_flags; + uint32_t index; + + for(index = 0;index < heir_stack->shared_stacks_count; index++) { + stack_address = heir_stack->shared_stacks[index]->shared_stack_area; + stack_size = heir_stack->shared_stacks[index]->shared_stack_size; + _Memory_protection_Set_entries( stack_address, stack_size, memory_flags ); + } + +} + +static bool get_target_thread( Thread_Control *Control, void *arg) +{ + Stack_Shared_attr *shared_stack; + uint32_t count; + shared_stack = arg; + /** + * Check for the target thread by comparing the stack address. Add the shared stack + * attribute structure to the array tracking all the shared stacks. + */ + if( Control->Start.Initial_stack.area == shared_stack->target_stack_area) { + count = Control->Start.Initial_stack.shared_stacks_count + 1; + if(count >= SHARED_STACK_NUMBER) { + return false; + } + Control->Start.Initial_stack.shared_stacks_count = count; + Control->Start.Initial_stack.shared_stacks[count] = shared_stack; + shared_stack->stack_shared = true; + + return true; + } +} + +int _Stackprotection_Share_stack( + void* target_stack, + void* sharing_stack, + size_t size, + uint32_t memory_flag +) +{ + Thread_Control *target_thread; + Stack_Shared_attr shared_stack; + + shared_stack.Base.access_flags= memory_flag; + shared_stack.shared_stack_area = sharing_stack; + shared_stack.target_stack_area = target_stack; + shared_stack.shared_stack_size = size; + + _Thread_Iterate( get_target_thread, &shared_stack ); + if( shared_stack.stack_shared == true ) { + return 0; + } else { + return -1; + } +} \ No newline at end of file diff --git a/cpukit/score/src/threadhandler.c b/cpukit/score/src/threadhandler.c index 6742b0b391..c18e33f688 100644 --- a/cpukit/score/src/threadhandler.c +++ b/cpukit/score/src/threadhandler.c @@ -22,6 +22,7 @@ #include <rtems/score/assert.h> #include <rtems/score/interr.h> #include <rtems/score/isrlevel.h> +#include <rtems/score/stackprotection.h> #include <rtems/score/userextimpl.h> /* @@ -94,6 +95,11 @@ void _Thread_Handler( void ) level = executing->Start.isr_level; _ISR_Set_level( level ); + /* + * Switch-out the the shared thread-stacks + */ + _Stackprotection_Context_restore( &executing->Start.Initial_stack ); + /* * Initialize the floating point context because we do not come * through _Thread_Dispatch on our first invocation. So the normal diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 691f56388e..96db4193bc 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -114,6 +114,15 @@ bool _Thread_Initialize( stack_size ); +#if defined ( RTEMS_THREAD_STACK_PROTECTION ) + /** + * Initialize the protected stack attributes. Initially we initialize the + * thread with no access attributes, on context switch/restore action the + * thread stacks are assigned READ/WRITE attribute. + */ + the_thread->Start.Initial_stack.Base.access_flags = RTEMS_NO_ACCESS | RTEMS_MEMORY_CACHED; +#endif + /* * Get thread queue heads */ diff --git a/spec/build/bsps/arm/realview-pbx-a9/bsprealviewpbxa9.yml b/spec/build/bsps/arm/realview-pbx-a9/bsprealviewpbxa9.yml index 2721152b93..f7d2187c66 100644 --- a/spec/build/bsps/arm/realview-pbx-a9/bsprealviewpbxa9.yml +++ b/spec/build/bsps/arm/realview-pbx-a9/bsprealviewpbxa9.yml @@ -57,6 +57,7 @@ links: source: - bsps/arm/realview-pbx-a9/console/console-config.c - bsps/arm/realview-pbx-a9/console/console-polled.c +- bsps/arm/realview-pbx-a9/mmu/bsp-set-mmu-attr.c - bsps/arm/realview-pbx-a9/start/bspreset.c - bsps/arm/realview-pbx-a9/start/bspstart.c - bsps/arm/realview-pbx-a9/start/bspstarthooks.c diff --git a/spec/build/cpukit/cpuopts.yml b/spec/build/cpukit/cpuopts.yml index 1902e543ca..f7641a5e50 100644 --- a/spec/build/cpukit/cpuopts.yml +++ b/spec/build/cpukit/cpuopts.yml @@ -63,6 +63,8 @@ links: uid: optszoff - role: build-dependency uid: optsztime +- role: build-dependency + uid: optthreadstackprotection - role: build-dependency uid: optversion target: cpukit/include/rtems/score/cpuopts.h diff --git a/spec/build/cpukit/librtemscpu.yml b/spec/build/cpukit/librtemscpu.yml index 63a0b7dca5..9855401665 100644 --- a/spec/build/cpukit/librtemscpu.yml +++ b/spec/build/cpukit/librtemscpu.yml @@ -353,6 +353,7 @@ install: - cpukit/include/rtems/score/isrlevel.h - cpukit/include/rtems/score/isrlock.h - cpukit/include/rtems/score/memory.h + - cpukit/include/rtems/score/memoryprotection.h - cpukit/include/rtems/score/mpci.h - cpukit/include/rtems/score/mpciimpl.h - cpukit/include/rtems/score/mppkt.h @@ -405,6 +406,7 @@ install: - cpukit/include/rtems/score/smplockstats.h - cpukit/include/rtems/score/smplockticket.h - cpukit/include/rtems/score/stack.h + - cpukit/include/rtems/score/stackprotection.h - cpukit/include/rtems/score/stackimpl.h - cpukit/include/rtems/score/states.h - cpukit/include/rtems/score/statesimpl.h @@ -1509,6 +1511,7 @@ source: - cpukit/score/src/semaphore.c - cpukit/score/src/smpbarrierwait.c - cpukit/score/src/stackallocator.c +- cpukit/score/src/stackprotection.c - cpukit/score/src/threadallocateunlimited.c - cpukit/score/src/thread.c - cpukit/score/src/threadchangepriority.c diff --git a/spec/build/cpukit/optthreadstackprotection.yml b/spec/build/cpukit/optthreadstackprotection.yml new file mode 100644 index 0000000000..4722d9f0cb --- /dev/null +++ b/spec/build/cpukit/optthreadstackprotection.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-boolean: null +- env-enable: null +- define-condition: null +build-type: option +copyrights: +- Copyright (C) 2020 Utkarsh Rai (utkarsh.ra...@gmail.com) +default: false +default-by-variant: [] +description: | + Enable the thread stack protection support +enabled-by: true +links: [] +name: RTEMS_THREAD_STACK_PROTECTION +type: build diff --git a/spec/build/testsuites/samples/grp.yml b/spec/build/testsuites/samples/grp.yml index c7591dc551..f0367b0f9b 100644 --- a/spec/build/testsuites/samples/grp.yml +++ b/spec/build/testsuites/samples/grp.yml @@ -40,6 +40,10 @@ links: uid: pppd - role: build-dependency uid: ticker +- role: build-dependency + uid: threadstackprotection +- role: build-dependency + uid: threadstacksharing - role: build-dependency uid: unlimited type: build diff --git a/spec/build/testsuites/samples/threadstackprotection.yml b/spec/build/testsuites/samples/threadstackprotection.yml new file mode 100644 index 0000000000..a33c53d392 --- /dev/null +++ b/spec/build/testsuites/samples/threadstackprotection.yml @@ -0,0 +1,19 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2020 Utkarsh Rai (utkarsh.ra...@gmail.com) +cppflags: [] +cxxflags: [] +enabled-by: true +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/samples/thread_stack_protection/init.c +stlib: [] +target: testsuites/samples/thread_stack_protection.exe +type: build +use-after: [] +use-before: [] diff --git a/spec/build/testsuites/samples/threadstacksharing.yml b/spec/build/testsuites/samples/threadstacksharing.yml new file mode 100644 index 0000000000..bbe99af189 --- /dev/null +++ b/spec/build/testsuites/samples/threadstacksharing.yml @@ -0,0 +1,19 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: test-program +cflags: [] +copyrights: +- Copyright (C) 2020 Utkarsh Rai (utkarsh.ra...@gmail.com) +cppflags: [] +cxxflags: [] +enabled-by: true +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/samples/thread_stack_sharing/init.c +stlib: [] +target: testsuites/samples/thread_stack_sharing.exe +type: build +use-after: [] +use-before: [] diff --git a/testsuites/samples/Makefile.am b/testsuites/samples/Makefile.am index 1944d90ccc..4d76bcb167 100644 --- a/testsuites/samples/Makefile.am +++ b/testsuites/samples/Makefile.am @@ -146,6 +146,22 @@ ticker_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_ticker) \ $(support_includes) endif +if TEST_thread_stack_protection +samples += thread_stack_protection +sample_screens += thread_stack_protection/thread_stack_protection.scn +sample_docs += thread_stack_protection/thread_stack_protection.doc +thread_stack_protection_SOURCES = thread_stack_protection/init.c +thread_stack_protection_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_thread_stack_protection) \ + $(support_includes) +endif + +if TEST_thread_stack_sharing +samples += thread_stack_sharing +thread_stack_sharing_SOURCES = thread_stack_sharing/init.c +thread_stack_sharing_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_thread_stack_sharing) \ + $(support_includes) +endif + if TEST_unlimited samples += unlimited sample_screens += unlimited/unlimited.scn diff --git a/testsuites/samples/configure.ac b/testsuites/samples/configure.ac index 9721ea4f26..6460f8f2c9 100644 --- a/testsuites/samples/configure.ac +++ b/testsuites/samples/configure.ac @@ -50,6 +50,8 @@ RTEMS_TEST_CHECK([nsecs]) RTEMS_TEST_CHECK([paranoia]) RTEMS_TEST_CHECK([pppd]) RTEMS_TEST_CHECK([ticker]) +RTEMS_TEST_CHECK([thread_stack_protection]) +RTEMS_TEST_CHECK([thread_stack_sharing]) RTEMS_TEST_CHECK([unlimited]) AC_CONFIG_FILES([Makefile]) diff --git a/testsuites/samples/thread_stack_protection/init.c b/testsuites/samples/thread_stack_protection/init.c new file mode 100644 index 0000000000..a9359b459d --- /dev/null +++ b/testsuites/samples/thread_stack_protection/init.c @@ -0,0 +1,112 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <tmacros.h> +#include <pthread.h> +#include <rtems/score/memoryprotection.h> +#include <rtems/score/thread.h> +const char rtems_test_name[] = " THREAD STACK PROTECTION "; + +static void fatal_extension( + rtems_fatal_source source, + bool is_internal, + rtems_fatal_code error +) +{ + if (source == RTEMS_FATAL_SOURCE_EXCEPTION) + { + printk("Internal Exception Occured \n"); + } + + exit(0); +} + +void* Test_routine( void* arg ) +{ + +} + +void *POSIX_Init( void *argument ) +{ + void *stack_addr1; + void *stack_addr2; + size_t stack_size1; + size_t stack_size2; + pthread_t id1; + pthread_t id2; + pthread_attr_t attr1; + pthread_attr_t attr2; + Thread_Control Control; + TEST_BEGIN(); + + /* + * We set the stack size as 8Kb. + */ + stack_size1 = 8192; + stack_size2 = 8192; + printf("%d %d \n",sizeof(Control.Post_switch_actions), sizeof(Control.Start.tls_area)); + /* + * We allocate page-aligned memory of the stack from the application. + */ + posix_memalign(&stack_addr1, sysconf( _SC_PAGESIZE ), stack_size1 ); + posix_memalign(&stack_addr2, sysconf( _SC_PAGESIZE ), stack_size2 ); + + pthread_attr_init( &attr1 ); + pthread_attr_init( &attr2 ); + + /* + * We set the stack size and address of the thread from the application itself + */ + pthread_attr_setstack( &attr1, stack_addr1, stack_size1 ); + pthread_attr_setstack( &attr2, stack_addr2, stack_size2 ); + + pthread_create( &id1, &attr1, Test_routine, NULL ); + pthread_create( &id2, &attr2, Test_routine, NULL ); + /* + * We set the memory attributes of the stack from the application. + */ + _Memory_protection_Set_entries( stack_addr1, stack_size1, RTEMS_NO_ACCESS | RTEMS_MEMORY_CACHED ); + _Memory_protection_Set_entries( stack_addr2, stack_size2, RTEMS_NO_ACCESS | RTEMS_MEMORY_CACHED ); + + pthread_join( id1, NULL ); + /* + * Write to the stack address of thread1 after it has been switched out. + */ + printf("Writing to the stack of thread1 \n"); + memset(stack_addr1, 0, stack_size1); + + pthread_join( id2, NULL ); + /* + * Write to the stack address of thread2 after it has been switched out. + */ + + + + TEST_END(); + rtems_test_exit( 0 ); +} + +/* configuration information */ + +#define CONFIGURE_INIT + +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_MAXIMUM_POSIX_THREADS 2 + +#define CONFIGURE_POSIX_INIT_THREAD_TABLE + +#define CONFIGURE_INITIAL_EXTENSIONS { .fatal = fatal_extension } + +#define CONFIGURE_TASK_STACK_ALLOCATOR_INIT bsp_stack_allocate_init +#define CONFIGURE_TASK_STACK_ALLOCATOR bsp_stack_allocate +#define CONFIGURE_TASK_STACK_DEALLOCATOR bsp_stack_free + +#include <bsp/stackalloc.h> +#define CONFIGURE_INIT +#include <rtems/confdefs.h> \ No newline at end of file diff --git a/testsuites/samples/thread_stack_protection/thread_stack_protection.doc b/testsuites/samples/thread_stack_protection/thread_stack_protection.doc new file mode 100644 index 0000000000..c5c9cdfa81 --- /dev/null +++ b/testsuites/samples/thread_stack_protection/thread_stack_protection.doc @@ -0,0 +1,2 @@ +This test sample demonstrates the thread stack protection functionality. We try +to write to the stack of a switched-out thread. \ No newline at end of file diff --git a/testsuites/samples/thread_stack_protection/thread_stack_protection.scn b/testsuites/samples/thread_stack_protection/thread_stack_protection.scn new file mode 100644 index 0000000000..1d36d0dfaf --- /dev/null +++ b/testsuites/samples/thread_stack_protection/thread_stack_protection.scn @@ -0,0 +1,20 @@ + +*** BEGIN OF TEST THREAD STACK PROTECTION *** +*** TEST VERSION: 5.0.0.a3b39c9e567f3f1ef5ab01de78b113e61b11853b-modified +*** TEST STATE: EXPECTED_PASS +*** TEST BUILD: RTEMS_NETWORKING RTEMS_POSIX_API +*** TEST TOOLS: 7.5.0 20191114 (RTEMS 5, RSB 5 (3bd11fd4898b), Newlib 7947581) +Creating thread1 +Creating thread2 +Joining thread1 +Writing to the stack of thread1 +Internal Exception Occured +Internal Exception Occured +Internal Exception Occured +Internal Exception Occured +Internal Exception Occured +Internal Exception Occured +Internal Exception Occured +Internal Exception Occured +Internal Exception Occured +Internal Exception Occured \ No newline at end of file diff --git a/testsuites/samples/thread_stack_sharing/init.c b/testsuites/samples/thread_stack_sharing/init.c new file mode 100644 index 0000000000..5bb7d01418 --- /dev/null +++ b/testsuites/samples/thread_stack_sharing/init.c @@ -0,0 +1,136 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <tmacros.h> +#include <pthread.h> +#include <sys/mman.h> +#include <sys/fcntl.h> +#include <rtems/score/memoryprotection.h> + +const char rtems_test_name[] = " THREAD STACK SHARING "; + +void* Test_routine( void* arg ) +{ + +} + +void *POSIX_Init( void *argument ) +{ + void *stack_addr1; + void *stack_addr2; + void* addr; + size_t stack_size1; + size_t stack_size2; + pthread_t id1; + pthread_t id2; + pthread_attr_t attr1; + pthread_attr_t attr2; + int fd; + char name[4] = "0x01"; + char thread_name[13] = "/taskfs/0x01"; + + TEST_BEGIN(); + + /* + * We set the stack size as 8Kb. + */ + stack_size1 = 8192; + stack_size2 = 8192; + + /* + * We allocate page-aligned memory of the stack from the application. + */ + posix_memalign(&stack_addr1, sysconf( _SC_PAGESIZE ), stack_size1 ); + posix_memalign(&stack_addr2, sysconf( _SC_PAGESIZE ), stack_size2 ); + + pthread_attr_init( &attr1 ); + pthread_attr_init( &attr2 ); + + /* + * We set the stack size and address of the thread from the application itself + */ + pthread_attr_setstack( &attr1, stack_addr1, stack_size1 ); + pthread_attr_setstack( &attr2, stack_addr2, stack_size2 ); + + pthread_create( &id1, &attr1, Test_routine, NULL ); + + /* + * We set the memory attributes of the stack from the application. + */ + _Memory_protection_Set_entries( stack_addr1, stack_size1, RTEMS_READ_ONLY | RTEMS_MEMORY_CACHED ); + + pthread_create( &id2, &attr2, Test_routine, NULL ); + _Memory_protection_Set_entries( stack_addr2, stack_size2, RTEMS_READ_ONLY | RTEMS_MEMORY_CACHED ); + + /* + * Add leading "/taskfs/" to denote thread-stack name. + */ + strlcat( thread_name, name, 4); + + /* + * Set the name of the thread object same as that of the shared memory object name + */ + rtems_object_set_name( id1, name); + + /* + * Create a shared memory object of the stack we want to share with + * appropraite permissions. We share the stack with read and write permission + */ + fd = shm_open( thread_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR ); + + /* + * Truncate the size of the file to the size of the stack. + */ + ftruncate( fd, stack_size1 ); + + /* + * For sharing the stack we specify the address of the + * thread-stack we want to share with, the size of the shared stack, + * protection and access flags, file descriptor of the shared memory objcet + */ + addr = mmap( stack_addr2, stack_size1, PROT_READ | PROT_WRITE, O_RDWR, fd, 0 ); + rtems_test_assert( addr != NULL ); + + pthread_join( id1, NULL ); + /* + * Write to the stack address of thread1 after it has been switched out. + */ + memset( stack_addr1, 0, stack_size1 ); + + pthread_join( id2, NULL ); + /* + * Write to the stack address of thread2 after it has been switched out. + */ + memset( stack_addr2, 0, stack_size2 ); + + + TEST_END(); + rtems_test_exit( 0 ); +} + +/* configuration information */ + +#define CONFIGURE_INIT + +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_MAXIMUM_POSIX_THREADS 4 + +#define CONFIGURE_MAXIMUM_POSIX_SHMS 2 + +#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 10 + +#define CONFIGURE_POSIX_INIT_THREAD_TABLE + +#define CONFIGURE_TASK_STACK_ALLOCATOR_INIT bsp_stack_allocate_init +#define CONFIGURE_TASK_STACK_ALLOCATOR bsp_stack_allocate +#define CONFIGURE_TASK_STACK_DEALLOCATOR bsp_stack_free + +#include <bsp/stackalloc.h> +#define CONFIGURE_INIT +#include <rtems/confdefs.h> \ No newline at end of file -- 2.17.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel