blob: 27f72073c48dcda78906e1178d250d3c713b44bf [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) Rolland Dudemaine All rights reserved.
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "config.h"
#include "OSAllocator.h"
#include <INTEGRITY.h>
#include <memory_region.h>
#include <set>
#include <wtf/Assertions.h>
#include <wtf/UnusedParam.h>
#define ASP_PAGESIZE 0x1000
namespace WTF {
struct MRPair {
mutable MemoryRegion pmr;
mutable MemoryRegion vmr;
mutable bool mapped;
Address start;
MRPair(Address _start = 0) :
pmr(0),
vmr(0),
mapped(false),
start(_start)
{}
bool operator<(const MRPair& rhs) const
{
return this->start < rhs.start;
}
};
class MRContainer
{
private:
std::set<MRPair> mrset;
LocalMutex iteratorGuard;
public:
MRContainer() {
CheckSuccess(CreateLocalMutex(&iteratorGuard));
}
const MRPair* getMRPair(Address start) {
WaitForLocalMutex(iteratorGuard);
auto pairIterator = mrset.find(MRPair(start));
const MRPair* result = ((pairIterator == mrset.end()) ? NULL : &(*pairIterator));
ReleaseLocalMutex(iteratorGuard);
return result;
}
Error deleteMRPair(const MRPair* pair) {
int erased = 0;
WaitForLocalMutex(iteratorGuard);
erased = mrset.erase(*pair);
ReleaseLocalMutex(iteratorGuard);
if(erased == 1)
return Success;
else
return ArgumentError; /* An exception could be thrown in this case */
}
Error insertMRPair(MRPair* pair) {
WaitForLocalMutex(iteratorGuard);
auto inserted = mrset.insert(*pair);
ReleaseLocalMutex(iteratorGuard);
if(inserted.second == true)
return Success;
else
return Failure; /* An exception could be thrown in this case */
}
~MRContainer() {
CheckSuccess(CloseLocalMutex(iteratorGuard));
}
};
static MRContainer memoryRegionsContainer;
Error setAttributes(MemoryRegion mr, bool writable, bool executable)
{
Value attributes = MEMORY_READ;
if(writable)
attributes |= MEMORY_WRITE;
if(executable)
attributes |= MEMORY_EXEC;
return SetMemoryRegionAttributes(mr, attributes);
}
void OSAllocator::setMemoryAttributes(void* addr, size_t size, bool writable, bool executable)
{
Address addressIterator = Address(addr);
for(int i=0; i<(size + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
const MRPair* pair = memoryRegionsContainer.getMRPair(addressIterator);
CheckSuccess(setAttributes(pair->vmr, writable, executable));
addressIterator += ASP_PAGESIZE;
}
}
void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
{
MemoryRegion VMR;
Address virtualStart, length;
CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
Address addressIterator = virtualStart;
for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
MRPair pair;
pair.start = addressIterator;
CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
CheckSuccess(setAttributes(pair.vmr, writable, executable));
memoryRegionsContainer.insertMRPair(&pair);
addressIterator += ASP_PAGESIZE;
}
CheckSuccess(CloseMemoryRegion(VMR));
return (void*)virtualStart;
}
void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
{
MemoryRegion VMR;
Address virtualStart, length;
CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
Address addressIterator = virtualStart;
for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
MRPair pair;
pair.start = addressIterator;
CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
CheckSuccess(setAttributes(pair.vmr, writable, executable));
/* Do not map the first and the last pages if guard pages are required */
if(!includesGuardPages || (i!=0 && i!= (bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE -1))
{
CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair.pmr));
CheckSuccess(MapMemoryRegion(pair.vmr, pair.pmr));
pair.mapped = true;
}
memoryRegionsContainer.insertMRPair(&pair);
addressIterator += ASP_PAGESIZE;
}
CheckSuccess(CloseMemoryRegion(VMR));
return (void*)virtualStart;
}
void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
{
for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
{
const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
if(pair == NULL)
return;
CheckSuccess(setAttributes(pair->vmr, writable, executable));
CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair->pmr));
CheckSuccess(MapMemoryRegion(pair->vmr, pair->pmr));
pair->mapped = true;
address = (char*)address + ASP_PAGESIZE;
}
}
void OSAllocator::decommit(void* address, size_t bytes)
{
for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
{
const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
if(pair == NULL)
return;
if(pair->mapped == false)
continue;
CheckSuccess(UnmapMemoryRegion(pair->vmr));
CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
pair->mapped = false;
address = (char*)address + ASP_PAGESIZE;
}
}
void OSAllocator::releaseDecommitted(void* address, size_t bytes)
{
for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
{
const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
if(pair == NULL)
return;
/* Check if the memory is still committed */
if(pair->mapped == true)
{
CheckSuccess(UnmapMemoryRegion(pair->vmr));
CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
pair->mapped = false;
}
CheckSuccess(AddToMemoryPool(__ghs_VirtualMemoryRegionPool, pair->vmr));
address = (char*)address + ASP_PAGESIZE;
memoryRegionsContainer.deleteMRPair(pair);
}
}
bool OSAllocator::canAllocateExecutableMemory()
{
return true;
}
} // namespace WTF