syscall_emul: implement MAP_FIXED option to mmap()

This commit is contained in:
Steve Reinhardt 2011-10-22 22:30:07 -07:00
parent c6dd122fee
commit 4d5f2c28a8
11 changed files with 73 additions and 19 deletions

View file

@ -69,6 +69,7 @@ class AlphaLinux : public Linux
/// For mmap(). /// For mmap().
static const unsigned TGT_MAP_ANONYMOUS = 0x10; static const unsigned TGT_MAP_ANONYMOUS = 0x10;
static const unsigned TGT_MAP_FIXED = 0x100;
//@{ //@{
/// For getsysinfo(). /// For getsysinfo().

View file

@ -64,6 +64,7 @@ class AlphaTru64 : public Tru64
/// For mmap(). /// For mmap().
static const unsigned TGT_MAP_ANONYMOUS = 0x10; static const unsigned TGT_MAP_ANONYMOUS = 0x10;
static const unsigned TGT_MAP_FIXED = 0x100;
//@{ //@{
/// For getsysinfo(). /// For getsysinfo().

View file

@ -91,6 +91,7 @@ class ArmLinux : public Linux
/// For mmap(). /// For mmap().
static const unsigned TGT_MAP_ANONYMOUS = 0x20; static const unsigned TGT_MAP_ANONYMOUS = 0x20;
static const unsigned TGT_MAP_FIXED = 0x10;
//@{ //@{
/// For getrusage(). /// For getrusage().

View file

@ -65,6 +65,7 @@ class MipsLinux : public Linux
/// For mmap(). /// For mmap().
static const unsigned TGT_MAP_ANONYMOUS = 0x800; static const unsigned TGT_MAP_ANONYMOUS = 0x800;
static const unsigned TGT_MAP_FIXED = 0x10;
//@{ //@{
/// For getsysinfo(). /// For getsysinfo().

View file

@ -127,6 +127,7 @@ class PowerLinux : public Linux
/// For mmap(). /// For mmap().
static const unsigned TGT_MAP_ANONYMOUS = 0x20; static const unsigned TGT_MAP_ANONYMOUS = 0x20;
static const unsigned TGT_MAP_FIXED = 0x10;
//@{ //@{
/// ioctl() command codes. /// ioctl() command codes.

View file

@ -77,6 +77,7 @@ class SparcLinux : public Linux
static const int NUM_OPEN_FLAGS; static const int NUM_OPEN_FLAGS;
static const unsigned TGT_MAP_ANONYMOUS = 0x20; static const unsigned TGT_MAP_ANONYMOUS = 0x20;
static const unsigned TGT_MAP_FIXED = 0x10;
typedef struct { typedef struct {
int64_t uptime; /* Seconds since boot */ int64_t uptime; /* Seconds since boot */

View file

@ -59,6 +59,7 @@ class SparcSolaris : public Solaris
static const int NUM_OPEN_FLAGS; static const int NUM_OPEN_FLAGS;
static const unsigned TGT_MAP_ANONYMOUS = 0x100; static const unsigned TGT_MAP_ANONYMOUS = 0x100;
static const unsigned TGT_MAP_FIXED = 0x10;
}; };
#endif #endif

View file

@ -88,6 +88,7 @@ class X86Linux64 : public Linux
static const int NUM_OPEN_FLAGS; static const int NUM_OPEN_FLAGS;
static const unsigned TGT_MAP_ANONYMOUS = 0x20; static const unsigned TGT_MAP_ANONYMOUS = 0x20;
static const unsigned TGT_MAP_FIXED = 0x10;
typedef struct { typedef struct {
uint64_t iov_base; // void * uint64_t iov_base; // void *
@ -158,6 +159,7 @@ class X86Linux32 : public Linux
static const int NUM_OPEN_FLAGS; static const int NUM_OPEN_FLAGS;
static const unsigned TGT_MAP_ANONYMOUS = 0x20; static const unsigned TGT_MAP_ANONYMOUS = 0x20;
static const unsigned TGT_MAP_FIXED = 0x10;
typedef struct { typedef struct {
int32_t uptime; /* Seconds since boot */ int32_t uptime; /* Seconds since boot */

View file

@ -67,7 +67,7 @@ PageTable::~PageTable()
} }
void void
PageTable::allocate(Addr vaddr, int64_t size) PageTable::allocate(Addr vaddr, int64_t size, bool clobber)
{ {
// starting address must be page aligned // starting address must be page aligned
assert(pageOffset(vaddr) == 0); 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); DPRINTF(MMU, "Allocating Page: %#x-%#x\n", vaddr, vaddr+ size);
for (; size > 0; size -= pageSize, vaddr += pageSize) { for (; size > 0; size -= pageSize, vaddr += pageSize) {
PTableItr iter = pTable.find(vaddr); if (!clobber && (pTable.find(vaddr) != pTable.end())) {
if (iter != pTable.end()) {
// already mapped // already mapped
fatal("PageTable::allocate: address 0x%x already mapped", fatal("PageTable::allocate: address 0x%x already mapped", vaddr);
vaddr);
} }
pTable[vaddr] = TheISA::TlbEntry(process->M5_pid, vaddr, pTable[vaddr] = TheISA::TlbEntry(process->M5_pid, vaddr,
process->system->new_page()); process->system->new_page());
updateCache(vaddr, pTable[vaddr]); 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 bool
PageTable::lookup(Addr vaddr, TheISA::TlbEntry &entry) PageTable::lookup(Addr vaddr, TheISA::TlbEntry &entry)
{ {

View file

@ -79,10 +79,18 @@ class PageTable
Addr pageAlign(Addr a) { return (a & ~offsetMask); } Addr pageAlign(Addr a) { return (a & ~offsetMask); }
Addr pageOffset(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 remap(Addr vaddr, int64_t size, Addr new_vaddr);
void deallocate(Addr vaddr, int64_t size); 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 * Lookup function
* @param vaddr The virtual address. * @param vaddr The virtual address.

View file

@ -1027,20 +1027,45 @@ mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
return -EINVAL; return -EINVAL;
} }
if (start != 0) { // are we ok with clobbering existing mappings? only set this to
warn("mmap: ignoring suggested map address 0x%x, using 0x%x", // true if the user has been warned.
start, p->mmap_end); 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 (!use_provided_address) {
if (OS::mmapGrowsDown()) { // no address provided, or provided address unusable:
start = p->mmap_end - length; // pick next address from our "mmap region"
p->mmap_end = start; if (OS::mmapGrowsDown()) {
} else { start = p->mmap_end - length;
start = p->mmap_end; p->mmap_end = start;
p->mmap_end += length; } else {
start = p->mmap_end;
p->mmap_end += length;
}
} }
p->pTable->allocate(start, length);
p->pTable->allocate(start, length, clobber);
return start; return start;
} }