[PATCH 3/6] posix: Add mmap/unmap support for mapping files.

Gedare Bloom gedare at rtems.org
Fri Mar 31 20:47:01 UTC 2017


From: Chris Johns <chrisj at rtems.org>

This version of mmap comes from early work done
on the RTL code base circa 2012.

Update #2859.
---
 cpukit/posix/Makefile.am                    |   1 +
 cpukit/posix/include/rtems/posix/mmanimpl.h |  44 +++++
 cpukit/posix/preinstall.am                  |   4 +
 cpukit/posix/src/mmap.c                     | 238 +++++++++++++++++++++++++---
 cpukit/posix/src/munmap.c                   |  68 ++++++--
 5 files changed, 319 insertions(+), 36 deletions(-)
 create mode 100644 cpukit/posix/include/rtems/posix/mmanimpl.h

diff --git a/cpukit/posix/Makefile.am b/cpukit/posix/Makefile.am
index 48617cc..3bb5bd2 100644
--- a/cpukit/posix/Makefile.am
+++ b/cpukit/posix/Makefile.am
@@ -32,6 +32,7 @@ include_HEADERS += include/mqueue.h
 include_rtems_posix_HEADERS += include/rtems/posix/aio_misc.h
 include_rtems_posix_HEADERS += include/rtems/posix/cond.h
 include_rtems_posix_HEADERS += include/rtems/posix/condimpl.h
+include_rtems_posix_HEADERS += include/rtems/posix/mmanimpl.h
 include_rtems_posix_HEADERS += include/rtems/posix/mqueue.h
 include_rtems_posix_HEADERS += include/rtems/posix/mqueueimpl.h
 include_rtems_posix_HEADERS += include/rtems/posix/mutex.h
diff --git a/cpukit/posix/include/rtems/posix/mmanimpl.h b/cpukit/posix/include/rtems/posix/mmanimpl.h
new file mode 100644
index 0000000..9743685
--- /dev/null
+++ b/cpukit/posix/include/rtems/posix/mmanimpl.h
@@ -0,0 +1,44 @@
+/**
+ * @file
+ *
+ * @brief Internal Support for POSIX 1003.1b 6.3.1 - map pages of memory
+ *
+ */
+
+/*
+ * Copyright (c) 2012 Chris Johns
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef _RTEMS_POSIX_MMANIMPL_H
+#define _RTEMS_POSIX_MMANIMPL_H
+
+#include <rtems/chain.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Every mmap'ed region has a mapping.
+ */
+typedef struct mmap_mappings_s {
+  rtems_chain_node node;  /**< The mapping chain's node */
+  void*            addr;  /**< The address of the mapped memory */
+  size_t           len;   /**< The length of memory mapped */
+  int              flags; /**< The mapping flags */
+} mmap_mapping;
+
+extern rtems_chain_control mmap_mappings;
+
+bool mmap_mappings_lock_obtain( void );
+bool mmap_mappings_lock_release( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/posix/preinstall.am b/cpukit/posix/preinstall.am
index 1269280..cfb087c 100644
--- a/cpukit/posix/preinstall.am
+++ b/cpukit/posix/preinstall.am
@@ -72,6 +72,10 @@ $(PROJECT_INCLUDE)/rtems/posix/condimpl.h: include/rtems/posix/condimpl.h $(PROJ
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/posix/condimpl.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/posix/condimpl.h
 
+$(PROJECT_INCLUDE)/rtems/posix/mmanimpl.h: include/rtems/posix/mmanimpl.h $(PROJECT_INCLUDE)/rtems/posix/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/posix/mmanimpl.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/posix/mmanimpl.h
+
 $(PROJECT_INCLUDE)/rtems/posix/mqueue.h: include/rtems/posix/mqueue.h $(PROJECT_INCLUDE)/rtems/posix/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/posix/mqueue.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/posix/mqueue.h
diff --git a/cpukit/posix/src/mmap.c b/cpukit/posix/src/mmap.c
index 2144d91..c05a65e 100644
--- a/cpukit/posix/src/mmap.c
+++ b/cpukit/posix/src/mmap.c
@@ -1,36 +1,230 @@
-/**
- * @file
- */
-
 /*
- *  COPYRIGHT (c) 2014.
- *  On-Line Applications Research Corporation (OAR).
+ * Copyright (c) 2012 Chris Johns (chrisj at rtems.org)
  *
- *  The license and distribution terms for this file may be
- *  found in the file LICENSE in this distribution or at
- *  http://www.rtems.org/license/LICENSE.
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
  */
 
 #if HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#include <rtems.h>
+#include <errno.h>
+#include <stdlib.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "rtems/libio_.h"
+
+#include <rtems/posix/mmanimpl.h> 
+
+#define RTEMS_MUTEX_ATTRIBS \
+  (RTEMS_PRIORITY | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
+   RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
+
+/**
+ * Mmap chain of mappings.
+ */
+rtems_chain_control mmap_mappings;
+
+/**
+ * The id of the MMAP lock.
+ */
+static rtems_id mmap_mappings_lock;
+
+/**
+ * Create the lock.
+ */
+static
+bool mmap_mappings_lock_create(
+  void
+)
+{
+  /*
+   * Lock the mapping table. We only create a lock if a call is made. First we
+   * test if a mapping lock is present. If one is present we lock it. If not
+   * the libio lock is locked and we then test the mapping lock again. If not
+   * present we create the mapping lock then release libio lock.
+   */
+  if ( mmap_mappings_lock == 0 ) {
+    rtems_status_code sc = RTEMS_SUCCESSFUL;
+    rtems_chain_initialize_empty( &mmap_mappings );
+    rtems_semaphore_obtain( rtems_libio_semaphore,
+                            RTEMS_WAIT, RTEMS_NO_TIMEOUT );
+    if ( mmap_mappings_lock == 0 )
+      sc = rtems_semaphore_create( rtems_build_name( 'M', 'M', 'A', 'P' ),
+                                   1,
+                                   RTEMS_MUTEX_ATTRIBS,
+                                   RTEMS_NO_PRIORITY,
+                                   &mmap_mappings_lock );
+    rtems_semaphore_release( rtems_libio_semaphore );
+    if ( sc != RTEMS_SUCCESSFUL ) {
+      errno = EINVAL;
+      return false;
+    }
+  }
+  return true;
+}
+
+bool mmap_mappings_lock_obtain(
+  void
+)
+{
+  if ( mmap_mappings_lock_create( ) ) {
+    rtems_status_code sc;
+    sc = rtems_semaphore_obtain( mmap_mappings_lock,
+                                 RTEMS_WAIT, RTEMS_NO_TIMEOUT );
+    if ( sc != RTEMS_SUCCESSFUL ) {
+      errno = EINVAL;
+      return false;
+    }
+  }
+  return true;
+}
+
+bool mmap_mappings_lock_release(
+  void
+)
+{
+  rtems_status_code sc;
+  sc = rtems_semaphore_release( mmap_mappings_lock );
+  if (( sc != RTEMS_SUCCESSFUL ) && ( errno == 0 )) {
+    errno = EINVAL;
+    return false;
+  }
+  return true;
+}
 
 void *mmap(
-  void   *addr,
-  size_t  length,
-  int     prot,
-  int     flags,
-  int     fildes,
-  off_t   off
+  void *addr, size_t len, int prot, int flags, int fildes, off_t off
 )
 {
-  (void) addr;
-  (void) length;
-  (void) prot;
-  (void) flags;
-  (void) fildes;
-  (void) off;
-  return MAP_FAILED;
+  struct stat   sb;
+  mmap_mapping* mapping;
+  ssize_t       r;
+  
+  /*
+   * Clear errno.
+   */
+  errno = 0;
+  
+  /*
+   * Get a stat of the file to get the dev + inode number and to make sure the
+   * fd is ok. The normal libio calls cannot be used because we need to return
+   * MAP_FAILED on error and they return -1 directly without coming back to
+   * here.
+   */
+  if ( fstat( fildes, &sb ) < 0 ) {
+    errno = EBADF;
+    return MAP_FAILED;
+  }
+
+  if ( len == 0 ) {
+    errno = EINVAL;
+    return MAP_FAILED;
+  }
+
+  /*
+   * Check the type of file we have and make sure it is supported.
+   */
+  if ( S_ISDIR( sb.st_mode ) || S_ISLNK( sb.st_mode )) {
+    errno = ENODEV;
+    return MAP_FAILED;
+  }
+  
+  /*
+   * We can provide read, write and execute because the memory in RTEMS does
+   * not normally have protections but we cannot hide access to memory.
+   */
+  if ( prot == PROT_NONE ) {
+    errno = EINVAL;
+    return MAP_FAILED;
+  }
+  
+  /*
+   * Check to see if the mapping is valid for the file.
+   */
+  if ( S_ISREG( sb.st_mode )
+       && (( off >= sb.st_size ) || (( off + len ) >= sb.st_size ))) {
+    errno = EOVERFLOW;
+    return MAP_FAILED;
+  }
+
+  /*
+   * Obtain the mmap lock. Sets errno on failure.
+   */
+  if ( !mmap_mappings_lock_obtain( ) )
+    return MAP_FAILED;
+
+  if (( flags & MAP_FIXED ) == MAP_FIXED ) {
+    rtems_chain_node* node = rtems_chain_first (&mmap_mappings);
+    while ( !rtems_chain_is_tail( &mmap_mappings, node )) {
+      /*
+       * If the map is fixed see if this address is already mapped. At this
+       * point in time if there is an overlap in the mappings we return an
+       * error.
+       */
+      mapping = (mmap_mapping*) node;
+      if ( ( addr >= mapping->addr ) &&
+           ( addr < ( mapping->addr + mapping->len )) ) {
+        mmap_mappings_lock_release( );
+        errno = ENXIO;
+        return MAP_FAILED;
+      }
+      node = rtems_chain_next( node );
+    }
+  }
+
+  mapping = malloc( sizeof( mmap_mapping ));
+  if ( !mapping ) {
+    mmap_mappings_lock_release( );
+    errno = ENOMEM;
+    return NULL;
+  }
+
+  memset( mapping, 0, sizeof( mmap_mapping ));
+
+  mapping->len = len;
+  mapping->flags = flags;
+  
+  if (( flags & MAP_FIXED ) != MAP_FIXED ) {
+    mapping->addr = malloc( len );
+    if ( !mapping->addr ) {
+      mmap_mappings_lock_release( );
+      free( mapping );
+      errno = ENOMEM;
+      return MAP_FAILED;
+    }
+
+    /*
+     * Do not seek on character devices, pipes or sockets.
+     */
+    if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ) {
+      if ( lseek( fildes, off, SEEK_SET ) < 0 ) {
+        mmap_mappings_lock_release( );
+        free( mapping->addr );
+        free( mapping );
+        return MAP_FAILED;
+      }
+    }
+  }
+
+  r = read( fildes, mapping->addr, len );
+
+  if ( r != len ) {
+    mmap_mappings_lock_release( );
+    free( mapping->addr );
+    free( mapping );
+    errno = ENXIO;
+    return MAP_FAILED;
+  }
+
+  rtems_chain_append( &mmap_mappings, &mapping->node );
+
+  mmap_mappings_lock_release( );
+  
+  return mapping->addr;
 }
diff --git a/cpukit/posix/src/munmap.c b/cpukit/posix/src/munmap.c
index 2496c27..d3687df 100644
--- a/cpukit/posix/src/munmap.c
+++ b/cpukit/posix/src/munmap.c
@@ -1,28 +1,68 @@
-/**
- * @file
- */
-
 /*
- *  COPYRIGHT (c) 2014.
- *  On-Line Applications Research Corporation (OAR).
+ * Copyright (c) 2012 Chris Johns (chrisj at rtems.org)
  *
- *  The license and distribution terms for this file may be
- *  found in the file LICENSE in this distribution or at
- *  http://www.rtems.org/license/LICENSE.
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
  */
 
 #if HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#include <rtems.h>
+#include <errno.h>
+#include <stdlib.h>
 #include <sys/mman.h>
 
+#include <rtems/posix/mmanimpl.h> 
+
 int munmap(
-  void   *addr,
-  size_t  length
+  void *addr, size_t len
 )
 {
-  (void) addr;
-  (void) length;
-  return -1;
+  mmap_mapping*     mapping;
+  rtems_chain_node* node;
+  
+  /*
+   * Clear errno.
+   */
+  errno = 0;
+
+  /*
+   * Length cannot be 0.
+   */
+  if ( len == 0 ) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  /*
+   * Obtain the mmap lock. Sets errno on failure.
+   */
+  if ( !mmap_mappings_lock_obtain( ))
+    return -1;
+
+  node = rtems_chain_first (&mmap_mappings);
+  while ( !rtems_chain_is_tail( &mmap_mappings, node )) {
+    /*
+     * If the map is fixed see if this address is already mapped. At this
+     * point in time if there is an overlap in the mappings we return an
+     * error.
+     */
+    mapping = (mmap_mapping*) node;
+    if ( ( addr >= mapping->addr ) &&
+         ( addr < ( mapping->addr + mapping->len )) ) {
+      rtems_chain_extract( node );
+      if (( mapping->flags & MAP_FIXED ) != MAP_FIXED ) {
+        free( mapping->addr );
+        free( mapping );
+      }
+      break;
+    }
+    node = rtems_chain_next( node );
+  }
+
+  mmap_mappings_lock_release( );
+  return 0;
 }
-- 
2.7.4



More information about the devel mailing list