syscall_emul: implement MAP_FIXED option to mmap()
authorSteve Reinhardt <steve.reinhardt@amd.com>
Sun, 23 Oct 2011 05:30:07 +0000 (22:30 -0700)
committerSteve Reinhardt <steve.reinhardt@amd.com>
Sun, 23 Oct 2011 05:30:07 +0000 (22:30 -0700)
src/arch/alpha/linux/linux.hh
src/arch/alpha/tru64/tru64.hh
src/arch/arm/linux/linux.hh
src/arch/mips/linux/linux.hh
src/arch/power/linux/linux.hh
src/arch/sparc/linux/linux.hh
src/arch/sparc/solaris/solaris.hh
src/arch/x86/linux/linux.hh
src/mem/page_table.cc
src/mem/page_table.hh
src/sim/syscall_emul.hh

index c728ce1fbe7af85deffe8c7b88ab11c3c073219d..3304816c34864f3c62d458b34ece7557f6ad2f5f 100644 (file)
@@ -69,6 +69,7 @@ class AlphaLinux : public Linux
 
     /// For mmap().
     static const unsigned TGT_MAP_ANONYMOUS = 0x10;
+    static const unsigned TGT_MAP_FIXED     = 0x100;
 
     //@{
     /// For getsysinfo().
index 0ee12973cbe833223a09217f7d383419c24d1d27..f0cad82896df583bac644e29d5955767196a1805 100644 (file)
@@ -64,6 +64,7 @@ class AlphaTru64 : public Tru64
 
     /// For mmap().
     static const unsigned TGT_MAP_ANONYMOUS = 0x10;
+    static const unsigned TGT_MAP_FIXED     = 0x100;
 
     //@{
     /// For getsysinfo().
index 33e48fc939014a24fd620b1dc3eeaec5927980f4..40d586aaffdf5b523752537a08681ce7f80efad9 100644 (file)
@@ -91,6 +91,7 @@ class ArmLinux : public Linux
 
     /// For mmap().
     static const unsigned TGT_MAP_ANONYMOUS = 0x20;
+    static const unsigned TGT_MAP_FIXED     = 0x10;
 
     //@{
     /// For getrusage().
index a2418cfb65a52f9ec8c836d84c64b536278cd517..949cce8aac32d2028f0d66be59c77fa9dfe9f47a 100644 (file)
@@ -65,6 +65,7 @@ class MipsLinux : public Linux
 
     /// For mmap().
     static const unsigned TGT_MAP_ANONYMOUS = 0x800;
+    static const unsigned TGT_MAP_FIXED     = 0x10;
 
     //@{
     /// For getsysinfo().
index 1bfc9cbd8be1bc3c251df1c900e9a6957d9b83b5..45ca048a043ddb85335277c26b68e5659e659464 100644 (file)
@@ -127,6 +127,7 @@ class PowerLinux : public Linux
 
     /// For mmap().
     static const unsigned TGT_MAP_ANONYMOUS = 0x20;
+    static const unsigned TGT_MAP_FIXED     = 0x10;
 
     //@{
     /// ioctl() command codes.
index 1f7567d43da334d941bc75aebfe65e7c973b1d3f..8ac4088126b82597d942f79f11bc77cff2032f3d 100644 (file)
@@ -77,6 +77,7 @@ class SparcLinux : public Linux
     static const int NUM_OPEN_FLAGS;
 
     static const unsigned TGT_MAP_ANONYMOUS = 0x20;
+    static const unsigned TGT_MAP_FIXED     = 0x10;
    
     typedef struct {   
         int64_t  uptime;    /* Seconds since boot */
index df256502726d1a0fe69b955077f55a2bc6f6b550..8222addabcc593e131ee074cfeafae8c1c5e38ec 100644 (file)
@@ -59,6 +59,7 @@ class SparcSolaris : public Solaris
     static const int NUM_OPEN_FLAGS;
 
     static const unsigned TGT_MAP_ANONYMOUS = 0x100;
+    static const unsigned TGT_MAP_FIXED     = 0x10;
 };
 
 #endif
index 99b09f4050a473966a40a9833ec38b3f01395bab..4e5d43d45c97cafebd86afc94ec1c8076628da86 100644 (file)
@@ -88,6 +88,7 @@ class X86Linux64 : public Linux
     static const int NUM_OPEN_FLAGS;
 
     static const unsigned TGT_MAP_ANONYMOUS = 0x20;
+    static const unsigned TGT_MAP_FIXED     = 0x10;
 
     typedef struct {
         uint64_t iov_base; // void *
@@ -158,6 +159,7 @@ class X86Linux32 : public Linux
     static const int NUM_OPEN_FLAGS;
 
     static const unsigned TGT_MAP_ANONYMOUS = 0x20;
+    static const unsigned TGT_MAP_FIXED     = 0x10;
 
     typedef struct {
        int32_t  uptime;    /* Seconds since boot */
index a94d9248021a91e53a987e9f35ca2c2b2ebef773..745872319e293520292382ec0373132271e9ada5 100644 (file)
@@ -67,7 +67,7 @@ PageTable::~PageTable()
 }
 
 void
-PageTable::allocate(Addr vaddr, int64_t size)
+PageTable::allocate(Addr vaddr, int64_t size, bool clobber)
 {
     // starting address must be page aligned
     assert(pageOffset(vaddr) == 0);
@@ -75,16 +75,13 @@ PageTable::allocate(Addr vaddr, int64_t size)
     DPRINTF(MMU, "Allocating Page: %#x-%#x\n", vaddr, vaddr+ size);
 
     for (; size > 0; size -= pageSize, vaddr += pageSize) {
-        PTableItr iter = pTable.find(vaddr);
-
-        if (iter != pTable.end()) {
+        if (!clobber && (pTable.find(vaddr) != pTable.end())) {
             // already mapped
-            fatal("PageTable::allocate: address 0x%x already mapped",
-                    vaddr);
+            fatal("PageTable::allocate: address 0x%x already mapped", vaddr);
         }
 
         pTable[vaddr] = TheISA::TlbEntry(process->M5_pid, vaddr,
-                process->system->new_page());
+                                         process->system->new_page());
         updateCache(vaddr, pTable[vaddr]);
     }
 }
@@ -127,6 +124,21 @@ PageTable::deallocate(Addr vaddr, int64_t size)
 
 }
 
+bool
+PageTable::isUnmapped(Addr vaddr, int64_t size)
+{
+    // starting address must be page aligned
+    assert(pageOffset(vaddr) == 0);
+
+    for (; size > 0; size -= pageSize, vaddr += pageSize) {
+        if (pTable.find(vaddr) != pTable.end()) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 bool
 PageTable::lookup(Addr vaddr, TheISA::TlbEntry &entry)
 {
index 61da5f322a57d9119c54cec19bc6ddb21c46f0aa..d60f4a433be013e45cdfbbfd9bead5ee95be8bd0 100644 (file)
@@ -79,10 +79,18 @@ class PageTable
     Addr pageAlign(Addr a)  { return (a & ~offsetMask); }
     Addr pageOffset(Addr a) { return (a &  offsetMask); }
 
-    void allocate(Addr vaddr, int64_t size);
+    void allocate(Addr vaddr, int64_t size, bool clobber = false);
     void remap(Addr vaddr, int64_t size, Addr new_vaddr);
     void deallocate(Addr vaddr, int64_t size);
 
+    /**
+     * Check if any pages in a region are already allocated
+     * @param vaddr The starting virtual address of the region.
+     * @param size The length of the region.
+     * @return True if no pages in the region are mapped.
+     */
+    bool isUnmapped(Addr vaddr, int64_t size);
+
     /**
      * Lookup function
      * @param vaddr The virtual address.
index d119adc247e1522a7249012ebdc65fa5c6f2356f..9bcf58844f5c3caf61f617a682db720c01a1331a 100644 (file)
@@ -1027,20 +1027,45 @@ mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
         return -EINVAL;
     }
 
-    if (start != 0) {
-        warn("mmap: ignoring suggested map address 0x%x, using 0x%x",
-             start, p->mmap_end);
+    // are we ok with clobbering existing mappings?  only set this to
+    // true if the user has been warned.
+    bool clobber = false;
+
+    // try to use the caller-provided address if there is one
+    bool use_provided_address = (start != 0);
+
+    if (use_provided_address) {
+        // check to see if the desired address is already in use
+        if (!p->pTable->isUnmapped(start, length)) {
+            // there are existing mappings in the desired range
+            // whether we clobber them or not depends on whether the caller
+            // specified MAP_FIXED
+            if (flags & OS::TGT_MAP_FIXED) {
+                // MAP_FIXED specified: clobber existing mappings
+                warn("mmap: MAP_FIXED at 0x%x overwrites existing mappings\n",
+                     start);
+                clobber = true;
+            } else {
+                // MAP_FIXED not specified: ignore suggested start address
+                warn("mmap: ignoring suggested map address 0x%x\n", start);
+                use_provided_address = false;
+            }
+        }
     }
 
-    // pick next address from our "mmap region"
-    if (OS::mmapGrowsDown()) {
-        start = p->mmap_end - length;
-        p->mmap_end = start;
-    } else {
-        start = p->mmap_end;
-        p->mmap_end += length;
+    if (!use_provided_address) {
+        // no address provided, or provided address unusable:
+        // pick next address from our "mmap region"
+        if (OS::mmapGrowsDown()) {
+            start = p->mmap_end - length;
+            p->mmap_end = start;
+        } else {
+            start = p->mmap_end;
+            p->mmap_end += length;
+        }
     }
-    p->pTable->allocate(start, length);
+
+    p->pTable->allocate(start, length, clobber);
 
     return start;
 }