summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Reinhardt <steve.reinhardt@amd.com>2011-10-22 22:30:07 -0700
committerSteve Reinhardt <steve.reinhardt@amd.com>2011-10-22 22:30:07 -0700
commit4d5f2c28a88f83d390e80407f55a8a02ead33878 (patch)
tree59f8aca2bd6995a396aade765156272998fc8bbf
parentc6dd122feef8cfb4785b8d45f40907bd6c73e04a (diff)
downloadgem5-4d5f2c28a88f83d390e80407f55a8a02ead33878.tar.xz
syscall_emul: implement MAP_FIXED option to mmap()
-rw-r--r--src/arch/alpha/linux/linux.hh1
-rw-r--r--src/arch/alpha/tru64/tru64.hh1
-rw-r--r--src/arch/arm/linux/linux.hh1
-rw-r--r--src/arch/mips/linux/linux.hh1
-rw-r--r--src/arch/power/linux/linux.hh1
-rw-r--r--src/arch/sparc/linux/linux.hh1
-rw-r--r--src/arch/sparc/solaris/solaris.hh1
-rw-r--r--src/arch/x86/linux/linux.hh2
-rw-r--r--src/mem/page_table.cc26
-rw-r--r--src/mem/page_table.hh10
-rw-r--r--src/sim/syscall_emul.hh47
11 files changed, 73 insertions, 19 deletions
diff --git a/src/arch/alpha/linux/linux.hh b/src/arch/alpha/linux/linux.hh
index c728ce1fb..3304816c3 100644
--- a/src/arch/alpha/linux/linux.hh
+++ b/src/arch/alpha/linux/linux.hh
@@ -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().
diff --git a/src/arch/alpha/tru64/tru64.hh b/src/arch/alpha/tru64/tru64.hh
index 0ee12973c..f0cad8289 100644
--- a/src/arch/alpha/tru64/tru64.hh
+++ b/src/arch/alpha/tru64/tru64.hh
@@ -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().
diff --git a/src/arch/arm/linux/linux.hh b/src/arch/arm/linux/linux.hh
index 33e48fc93..40d586aaf 100644
--- a/src/arch/arm/linux/linux.hh
+++ b/src/arch/arm/linux/linux.hh
@@ -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().
diff --git a/src/arch/mips/linux/linux.hh b/src/arch/mips/linux/linux.hh
index a2418cfb6..949cce8aa 100644
--- a/src/arch/mips/linux/linux.hh
+++ b/src/arch/mips/linux/linux.hh
@@ -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().
diff --git a/src/arch/power/linux/linux.hh b/src/arch/power/linux/linux.hh
index 1bfc9cbd8..45ca048a0 100644
--- a/src/arch/power/linux/linux.hh
+++ b/src/arch/power/linux/linux.hh
@@ -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.
diff --git a/src/arch/sparc/linux/linux.hh b/src/arch/sparc/linux/linux.hh
index 1f7567d43..8ac408812 100644
--- a/src/arch/sparc/linux/linux.hh
+++ b/src/arch/sparc/linux/linux.hh
@@ -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 */
diff --git a/src/arch/sparc/solaris/solaris.hh b/src/arch/sparc/solaris/solaris.hh
index df2565027..8222addab 100644
--- a/src/arch/sparc/solaris/solaris.hh
+++ b/src/arch/sparc/solaris/solaris.hh
@@ -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
diff --git a/src/arch/x86/linux/linux.hh b/src/arch/x86/linux/linux.hh
index 99b09f405..4e5d43d45 100644
--- a/src/arch/x86/linux/linux.hh
+++ b/src/arch/x86/linux/linux.hh
@@ -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 */
diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc
index a94d92480..745872319 100644
--- a/src/mem/page_table.cc
+++ b/src/mem/page_table.cc
@@ -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]);
}
}
@@ -128,6 +125,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)
{
Addr page_addr = pageAlign(vaddr);
diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh
index 61da5f322..d60f4a433 100644
--- a/src/mem/page_table.hh
+++ b/src/mem/page_table.hh
@@ -79,11 +79,19 @@ 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.
* @return entry The page table entry corresponding to vaddr.
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index d119adc24..9bcf58844 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -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;
}