diff -r c7fec2cb91cb -r ed504c173212 src/arch/alpha/linux/linux.hh --- a/src/arch/alpha/linux/linux.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/arch/alpha/linux/linux.hh Fri Oct 21 15:28:40 2011 -0700 @@ -69,6 +69,7 @@ /// For mmap(). static const unsigned TGT_MAP_ANONYMOUS = 0x10; + static const unsigned TGT_MAP_FIXED = 0x100; //@{ /// For getsysinfo(). diff -r c7fec2cb91cb -r ed504c173212 src/arch/alpha/tru64/tru64.hh --- a/src/arch/alpha/tru64/tru64.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/arch/alpha/tru64/tru64.hh Fri Oct 21 15:28:40 2011 -0700 @@ -64,6 +64,7 @@ /// For mmap(). static const unsigned TGT_MAP_ANONYMOUS = 0x10; + static const unsigned TGT_MAP_FIXED = 0x100; //@{ /// For getsysinfo(). diff -r c7fec2cb91cb -r ed504c173212 src/arch/arm/linux/linux.hh --- a/src/arch/arm/linux/linux.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/arch/arm/linux/linux.hh Fri Oct 21 15:28:40 2011 -0700 @@ -91,6 +91,7 @@ /// For mmap(). static const unsigned TGT_MAP_ANONYMOUS = 0x20; + static const unsigned TGT_MAP_FIXED = 0x10; //@{ /// For getrusage(). diff -r c7fec2cb91cb -r ed504c173212 src/arch/mips/linux/linux.hh --- a/src/arch/mips/linux/linux.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/arch/mips/linux/linux.hh Fri Oct 21 15:28:40 2011 -0700 @@ -65,6 +65,7 @@ /// For mmap(). static const unsigned TGT_MAP_ANONYMOUS = 0x800; + static const unsigned TGT_MAP_FIXED = 0x10; //@{ /// For getsysinfo(). diff -r c7fec2cb91cb -r ed504c173212 src/arch/power/linux/linux.hh --- a/src/arch/power/linux/linux.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/arch/power/linux/linux.hh Fri Oct 21 15:28:40 2011 -0700 @@ -127,6 +127,7 @@ /// For mmap(). static const unsigned TGT_MAP_ANONYMOUS = 0x20; + static const unsigned TGT_MAP_FIXED = 0x10; //@{ /// ioctl() command codes. diff -r c7fec2cb91cb -r ed504c173212 src/arch/sparc/linux/linux.hh --- a/src/arch/sparc/linux/linux.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/arch/sparc/linux/linux.hh Fri Oct 21 15:28:40 2011 -0700 @@ -77,6 +77,7 @@ 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 -r c7fec2cb91cb -r ed504c173212 src/arch/sparc/solaris/solaris.hh --- a/src/arch/sparc/solaris/solaris.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/arch/sparc/solaris/solaris.hh Fri Oct 21 15:28:40 2011 -0700 @@ -59,6 +59,7 @@ static const int NUM_OPEN_FLAGS; static const unsigned TGT_MAP_ANONYMOUS = 0x100; + static const unsigned TGT_MAP_FIXED = 0x10; }; #endif diff -r c7fec2cb91cb -r ed504c173212 src/arch/x86/linux/linux.hh --- a/src/arch/x86/linux/linux.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/arch/x86/linux/linux.hh Fri Oct 21 15:28:40 2011 -0700 @@ -88,6 +88,7 @@ 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 @@ 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 -r c7fec2cb91cb -r ed504c173212 src/mem/page_table.hh --- a/src/mem/page_table.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/mem/page_table.hh Fri Oct 21 15:28:40 2011 -0700 @@ -79,11 +79,19 @@ 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 -r c7fec2cb91cb -r ed504c173212 src/mem/page_table.cc --- a/src/mem/page_table.cc Thu Oct 20 13:11:56 2011 -0700 +++ b/src/mem/page_table.cc Fri Oct 21 15:28:40 2011 -0700 @@ -67,7 +67,7 @@ } 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 @@ 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 @@ } 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 -r c7fec2cb91cb -r ed504c173212 src/sim/syscall_emul.hh --- a/src/sim/syscall_emul.hh Thu Oct 20 13:11:56 2011 -0700 +++ b/src/sim/syscall_emul.hh Fri Oct 21 15:28:40 2011 -0700 @@ -1027,20 +1027,45 @@ 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; }