Complets ram mapping logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3578 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2011-05-08 14:42:42 +00:00
parent 365a11a5ec
commit 36a7f0be04
12 changed files with 404 additions and 118 deletions
+78
View File
@@ -0,0 +1,78 @@
fs/mmap README File
===================
NuttX operates in a flat open address space and is focused on MCUs that do
support Memory Management Units (MMUs). Therefore, NuttX generally does not
require mmap() functionality and the MCUs generally cannot support true
memory-mapped files.
However, memory mapping of files is the mechanism used by NXFLAT, the NuttX
tiny binary format, to get files into memory in order to execute them.
mmap() support is therefore required to support NXFLAT. There are two
conditions where mmap() can be supported:
1. mmap can be used to support eXecute In Place (XIP) on random access media
under the following very restrictive conditions:
a. The filesystem supports the FIOC_MMAP ioctl command. Any file
system that maps files contiguously on the media should support
this ioctl. (vs. file system that scatter files over the media
in non-contiguous sectors). As of this writing, ROMFS is the
only file system that meets this requirement.
b. The underlying block driver supports the BIOC_XIPBASE ioctl
command that maps the underlying media to a randomly accessible
address. At present, only the RAM/ROM disk driver does this.
Some limitations of this approach are as follows:
a. Since no real mapping occurs, all of the file contents are "mapped"
into memory.
b. All mapped files are read-only.
c. There are no access privileges.
2. If CONFIG_FS_RAMMAP is defined in the configuration, then mmap() will
support simulation of memory mapped files by copying files whole
into RAM. These copied files have some of the properties of
standard memory mapped files. There are many, many exceptions
exceptions, however. Some of these include:
a. The goal is to have a single region of memory that represents a single
file and can be shared by many threads. That is, given a filename a
thread should be able to open the file, get a file descriptor, and
call mmap() to get a memory region. Different file descriptors opened
with the same file path should get the same memory region when mapped.
The limitation in the current design is that there is insufficient
knowledge to know that these different file descriptors correspond to
the same file. So, for the time being, a new memory region is created
each time that rammap() is called. Not very useful!
b. The entire mapped portion of the file must be present in memory.
Since it is assumed the the MCU does not have an MMU, on-demanding
paging in of file blocks cannot be supported. Since the while mapped
portion of the file must be present in memory, there are limitations
in the size of files that may be memory mapped (especially on MCUs
with no significant RAM resources).
c. All mapped files are read-only. You can write to the in-memory image,
but the file contents will not change.
d. There are no access privileges.
e. Since there are no processes in NuttX, all mmap() and munmap()
operations have immediate, global effects. Under Linux, for example,
munmap() would eliminate only the mapping with a process; the mappings
to the same file in other processes would not be effected.
f. Like true mapped file, the region will persist after closing the file
descriptor. However, at present, these ram copied file regions are
*not* automatically "unmapped" (i.e., freed) when a thread is terminated.
This is primarily because it is not possible to know how many users
of the mapped region there are and, therefore, when would be the
appropriate time to free the region (other than when munmap is called).
NOTE: Note, if the design limitation of a) were solved, then it would be
easy to solve exception d) as well.
+10 -20
View File
@@ -47,6 +47,7 @@
#include <debug.h>
#include "fs_internal.h"
#include "fs_rammap.h"
/****************************************************************************
* Global Functions
@@ -135,16 +136,15 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags,
(flags & (MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_DENYWRITE)) != 0)
{
fdbg("Unsupported options, prot=%x flags=%04x\n", prot, flags);
ret = ENOSYS;
goto errout_with_ret;
errno = ENOSYS;
return MAP_FAILED;
}
if (length == 0 ||
(flags & MAP_SHARED) == 0)
if (length == 0 || (flags & MAP_SHARED) == 0)
{
fdbg("Invalid options, lengt=%d flags=%04x\n", length, flags);
ret = EINVAL;
goto errout_with_ret;
errno = EINVAL;
return MAP_FAILED;
}
#endif
@@ -161,24 +161,14 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags,
if (ret < 0)
{
#ifdef CONFIG_FS_RAMMAP
ret = rammap(fd, length, offset, &addr);
if (ret < 0)
return rammap(fd, length, offset);
#else
fdbg("ioctl(FIOC_MMAP) failed: %d\n", errno);
return MAP_FAILED;
#endif
{
fdbg("ioctl(FIOC_MMAP) failed: %d\n", errno);
goto errout;
}
}
/* Return the offset address */
return (void*)(((uint8_t*)addr) + offset);
#ifdef CONFIG_DEBUG
errout_with_ret:
errno = ret;
#endif
errout:
return MAP_FAILED;
}
+53 -18
View File
@@ -44,9 +44,13 @@
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include "fs_internal.h"
#include "fs_rammap.h"
#ifdef CONFIG_FS_RAMMAP
@@ -60,8 +64,8 @@
* Description:
*
* munmap() system call deletes mappings for the specified address range.
* The region is also automatically unmapped when the process is terminated.
* On the other hand, closing the file descriptor does not unmap the region.
* All memory starting with 'start' and continuing for a length of 'length'
* bytes are removed.
*
* NuttX operates in a flat open address space. Therefore, it generally
* does not require mmap() and, hence, munmap functionality. There are
@@ -96,8 +100,7 @@
* simplified munmap() implementation, the *must* be the start
* address of the memory region (the same address returned by
* mmap()).
* length The length region to be umapped. Ignored. The entire underlying
* media is always freed.
* length The length region to be umapped.
*
* Returned Value:
* On success, munmap() returns 0, on failure -1, and errno is set
@@ -110,13 +113,14 @@ int munmap(FAR void *start, size_t length)
FAR struct fs_rammap_s *prev;
FAR struct fs_rammap_s *curr;
FAR void *newaddr;
unsigned int offset;
int ret;
int err;
/* Find a region containing this start and length in the list of regions */
#warning "Missing semaphore initialization"
ret = sem_wait(g_rammaps.exclsem);
rammap_initialize();
ret = sem_wait(&g_rammaps.exclsem);
if (ret < 0)
{
return ERROR;
@@ -124,7 +128,7 @@ int munmap(FAR void *start, size_t length)
/* Seach the list of regions */
for (prev = NULL, curr = g_rammaps.head; prev = curr, curr = curr->flink)
for (prev = NULL, curr = g_rammaps.head; curr; prev = curr, curr = curr->flink)
{
/* Does this region include any part of the specified range? */
@@ -144,32 +148,63 @@ int munmap(FAR void *start, size_t length)
goto errout_with_semaphore;
}
/* There is not yet any support for freeing memory at the beginning of the
* region or for increasing the size of the mapped region.
/* Get the offset from the beginning of the region and the actual number
* of bytes to "unmap". All mappings must extend to the end of the region.
* There is no support for free a block of memory but leaving a block of
* memory at the end. This is a consequence of using realloc() to
* simulate the unmapping.
*/
if (start != curr->addr || length > curr->length)
offset = start - curr->addr;
if (offset + length < curr->length)
{
fdbg("Unmapping at offset/Extending not supported\n");
fdbg("Cannot umap without unmapping to the end\n");
err = ENOSYS;
goto errout_with_semaphore;
}
/* Otherwise, we can simply realloc the region. Since we are reducing
* the size of the region, this should not change the start addres.
/* Okay.. the region is beging umapped to the end. Make sure the length
* indicates that.
*/
if (length < curr->length)
length = curr->length - offset;
/* Are we unmapping the entire region (offset == 0)? */
if (length >= curr->length)
{
newaddr = realloc(curr->addr, length);
DEBUGASSERT(newaddr == curr->addr);
/* Yes.. remove the mapping from the list */
if (prev)
{
prev->flink = curr->flink;
}
else
{
g_rammaps.head = curr->flink;
}
/* Then free the region */
kfree(curr);
}
sem_post(g_rammaps.exclsem);
/* No.. We have been asked to "unmap' only a portion of the memory
* (offset > 0).
*/
else
{
newaddr = krealloc(curr->addr, sizeof(struct fs_rammap_s) + length);
DEBUGASSERT(newaddr == (FAR void*)(curr->addr));
curr->length = length;
}
sem_post(&g_rammaps.exclsem);
return OK;
errout_with_semaphore:
sem_post(g_rammaps.exclsem);
sem_post(&g_rammaps.exclsem);
errno = err;
return ERROR;
}
+52 -16
View File
@@ -40,19 +40,55 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include "fs_internal.h"
#include "fs_rammap.h"
#ifdef CONFIG_FS_RAMMAP
/****************************************************************************
* Global Data
****************************************************************************/
/* This is the list of all mapped files */
struct fs_allmaps_s g_rammaps;
/****************************************************************************
* Global Functions
****************************************************************************/
/****************************************************************************
* Name: rammap_initialize
*
* Description:
* Verified that this capability has been initialized.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void rammap_initialize(void)
{
if (!g_rammaps.initialized)
{
sem_init(&g_rammaps.exclsem, 0, 1);
g_rammaps.initialized = true;
}
}
/****************************************************************************
* Name: rammmap
*
@@ -78,9 +114,9 @@
*
****************************************************************************/
int rammap(int fd, size_t length, off_t offset, FAR void **addr)
FAR void *rammap(int fd, size_t length, off_t offset)
{
FAR struct fs_rammap_s *rammap;
FAR struct fs_rammap_s *map;
FAR uint8_t *alloc;
FAR uint8_t *rdbuffer;
ssize_t nread;
@@ -113,11 +149,11 @@ int rammap(int fd, size_t length, off_t offset, FAR void **addr)
/* Initialize the region */
rammap = (FAR struct fs_rammap_s *)alloc;
memset(rammap, 0, sizeof(struct fs_rammap_s));
rammap->addr = alloc + sizeof(struct fs_rammap_s);
rammap->length = length;
rammap->offset = offset;
map = (FAR struct fs_rammap_s *)alloc;
memset(map, 0, sizeof(struct fs_rammap_s));
map->addr = alloc + sizeof(struct fs_rammap_s);
map->length = length;
map->offset = offset;
/* Seek to the specified file offset */
@@ -135,7 +171,7 @@ int rammap(int fd, size_t length, off_t offset, FAR void **addr)
/* Read the file data into the memory region */
rdbuffer = rammap->addr;
rdbuffer = map->addr;
while (length > 0)
{
nread = read(fd, rdbuffer, length);
@@ -175,18 +211,18 @@ int rammap(int fd, size_t length, off_t offset, FAR void **addr)
/* Add the buffer to the list of regions */
#warning "Missing semaphore initialization"
ret = sem_wait(g_rammaps.exclsem);
rammap_initialize();
ret = sem_wait(&g_rammaps.exclsem);
if (ret < 0)
{
goto errout_with_errno;
}
rammap->flink = g_rammaps.head;
g_rammaps.head = rammap;
map->flink = g_rammaps.head;
g_rammaps.head = map;
sem_post(g_rammaps.exclsem);
return rammap->addr;
sem_post(&g_rammaps.exclsem);
return map->addr;
errout_with_region:
kfree(alloc);
@@ -195,8 +231,8 @@ errout:
return MAP_FAILED;
errout_with_errno:
kfree(alloc)
returm MAP_FAILED;
kfree(alloc);
return MAP_FAILED;
}
#endif /* CONFIG_FS_RAMMAP */
+32 -10
View File
@@ -64,25 +64,31 @@
* blocks of a file.
*
* This copied file has many of the properties of a standard memory mapped
* file except for all of the file must be present in memory. This limits
* the size of files that may be memory mapped (especially on MCUs with
* no significant RAM resources).
* file except:
*
* - All of the file must be present in memory. This limits the size of
* files that may be memory mapped (especially on MCUs with no significant
* RAM resources).
* - All mapped files are read-only. You can write to the in-memory image,
* but the file contents will not change.
* - There are not access privileges.
*/
struct fs_rammap_s
{
struct fs_rammap_s *flink; /* Implements a singly linked list */
FAR void *addr; /* Start of allocated memory */
size_t length; /* Length of region */
off_t offset; /* File offset */
struct fs_rammap_s *flink; /* Implements a singly linked list */
FAR void *addr; /* Start of allocated memory */
size_t length; /* Length of region */
off_t offset; /* File offset */
};
/* This structure defines all "mapped" files */
struct fs_allmaps_s
{
sem_t exclsem; /* Provides exclusive access the list */
struct fs_rammap_s *maps; /* List of mapped files */
bool initialized; /* True: This structure has been initialized */
sem_t exclsem; /* Provides exclusive access the list */
struct fs_rammap_s *head; /* List of mapped files */
};
/****************************************************************************
@@ -97,6 +103,22 @@ extern struct fs_allmaps_s g_rammaps;
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: rammap_initialize
*
* Description:
* Verified that this capability has been initialized.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
extern void rammap_initialize(void);
/****************************************************************************
* Name: rammmap
*
@@ -122,7 +144,7 @@ extern struct fs_allmaps_s g_rammaps;
*
****************************************************************************/
extern int rammap(int fd, size_t length, off_t offset, FAR void **addr);
extern FAR void *rammap(int fd, size_t length, off_t offset);
#endif /* CONFIG_FS_RAMMAP */
#endif /* __FS_MMAP_RAMMAP_H */