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().
static const unsigned TGT_MAP_ANONYMOUS = 0x10;
static const unsigned TGT_MAP_FIXED = 0x100;
//@{
/// For getsysinfo().

View 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().

View 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().

View 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().

View 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.

View 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 */

View 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

View 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 */

View 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)
{

View 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.

View 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;
}