For the design details of the stack sharing mechanism please refer to the following post - https://gsoc2020memoryprotection.blogspot.com/2020/08/high-level-design-and-implementation-of.html --- cpukit/posix/src/mmap.c | 39 ++++- cpukit/posix/src/shmopen.c | 62 +------- .../samples/thread_stack_sharing/init.c | 136 ++++++++++++++++++ 3 files changed, 173 insertions(+), 64 deletions(-) create mode 100644 testsuites/samples/thread_stack_sharing/init.c
diff --git a/cpukit/posix/src/mmap.c b/cpukit/posix/src/mmap.c index 176c6e4fe8..1d4b65cea6 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,9 +318,16 @@ 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( ); diff --git a/cpukit/posix/src/shmopen.c b/cpukit/posix/src/shmopen.c index 1e7fda66f8..b439592fd7 100644 --- a/cpukit/posix/src/shmopen.c +++ b/cpukit/posix/src/shmopen.c @@ -19,13 +19,11 @@ #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> -#include <string.h> #include <rtems/libio_.h> #include <rtems/seterr.h> #include <rtems/posix/shmimpl.h> -#include <rtems/posix/pthread.h> #include <rtems/score/wkspace.h> #include <rtems/sysinit.h> @@ -93,61 +91,6 @@ static int shm_ftruncate( rtems_libio_t *iop, off_t length ) return 0; } -static int shm_stack_ftruncate ( rtems_libio_t *iop, off_t length ) -{ - int err; - Objects_Id id; - Objects_Name_or_id_lookup_errors obj_err; - Thread_Control *Control; - ISR_lock_Context lock_context; - size_t size; - char *name; - POSIX_Shm_Control *shm = iop_to_shm ( iop ); - - 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. - */ - obj_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->shm_object.handle = Control->Start.Initial_stack.area; - if( length != Control->Start.Initial_stack.size) { - return ENOMEM; - } - } else { - return ENOMEM; - } - }else{ - - _Objects_Allocator_lock(); - - err = (*shm->shm_object.ops->object_resize)( &shm->shm_object, length ); - - if ( err != 0 ) { - _Objects_Allocator_unlock(); - rtems_set_errno_and_return_minus_one( err ); - } - - _POSIX_Shm_Update_mtime_ctime( shm ); - - _Objects_Allocator_unlock(); - return 0; - } - -} - static int shm_close( rtems_libio_t *iop ) { POSIX_Shm_Control *shm = iop_to_shm( iop ); @@ -363,11 +306,7 @@ static const rtems_filesystem_file_handlers_r shm_handlers = { .ioctl_h = rtems_filesystem_default_ioctl, .lseek_h = rtems_filesystem_default_lseek, .fstat_h = shm_fstat, - #if defined ( RTEMS_THREAD_STACK_PROTECTION ) - .ftruncate_h = shm_stack_ftruncate, - #else .ftruncate_h = shm_ftruncate, - #endif .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, .fcntl_h = rtems_filesystem_default_fcntl, @@ -388,3 +327,4 @@ RTEMS_SYSINIT_ITEM( RTEMS_SYSINIT_POSIX_SHM, RTEMS_SYSINIT_ORDER_MIDDLE ); + 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