377 lines
12 KiB
C++
377 lines
12 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuProcessSectionViewReserved.Unix.cpp
|
|
Date: 2022-11-15
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuProcessSectionViewReserved.Unix.hpp"
|
|
#include "Process.hpp"
|
|
#include <Source/IO/FS/FileStream.Unix.hpp>
|
|
#include "AuProcessSectionFileMapView.Unix.hpp"
|
|
#include <Source/IO/IPC/AuIPCHandle.hpp>
|
|
#include <Source/IO/IPC/AuIPCMemory.Unix.hpp>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
namespace Aurora::Process
|
|
{
|
|
ProcessSectionViewReserved::~ProcessSectionViewReserved()
|
|
{
|
|
if (this->pBaseAddress)
|
|
{
|
|
::munmap(this->pBaseAddress, this->uMaxLength);
|
|
}
|
|
}
|
|
|
|
AuUInt ProcessSectionViewReserved::GetStart()
|
|
{
|
|
return (AuUInt)this->pBaseAddress;
|
|
}
|
|
|
|
AuUInt ProcessSectionViewReserved::GetEnd()
|
|
{
|
|
return this->GetStart() + this->uMaxLength;
|
|
}
|
|
|
|
bool ProcessSectionViewReserved::Init(AuUInt uLength)
|
|
{
|
|
this->uMaxLength = uLength;
|
|
|
|
if (!(this->pBaseAddress = (char *)::mmap(0, uLength, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0)))
|
|
{
|
|
this->pBaseAddress = (char *)::mmap(0, uLength, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
|
}
|
|
|
|
return bool(this->pBaseAddress);
|
|
}
|
|
|
|
void ProcessSectionViewReserved::Release(AuUInt address)
|
|
{
|
|
auto uOffset = address - (AuUInt)this->pBaseAddress;
|
|
this->ReleaseAddress(uOffset);
|
|
}
|
|
|
|
void *ProcessSectionViewReserved::MapAddress(AuUInt uOffset, AuUInt uLength,
|
|
AuUInt prot, AuUInt share, int fd, AuUInt offset)
|
|
{
|
|
bool bCompleteBlock {};
|
|
AuUInt uFoundOffset {};
|
|
|
|
if (!this->GetAddress(uOffset, uLength, uFoundOffset, bCompleteBlock))
|
|
{
|
|
SysPushErrorMemory("Reserved address space has no available space");
|
|
return {};
|
|
}
|
|
|
|
auto pRet = ::mmap(this->pBaseAddress + uFoundOffset,
|
|
uLength,
|
|
prot,
|
|
share | MAP_FIXED,
|
|
fd,
|
|
offset);
|
|
|
|
if (!pRet)
|
|
{
|
|
SysPushErrorMemory("mmap failed");
|
|
ReleaseAddress(uFoundOffset);
|
|
return {};
|
|
}
|
|
|
|
return pRet;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::Allocate(AuUInt uLength)
|
|
{
|
|
return this->AllocateEx(uLength, -1);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapFileByPath(const AuString &str,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode,
|
|
AuFS::EFileAdvisoryLockLevel sectionLock)
|
|
{
|
|
auto file = AuFS::OpenShared(str, mode, AuFS::EFileAdvisoryLockLevel::eNoSafety);
|
|
return file ? this->MapFileByObject(file, uOffset, uLength, mode, sectionLock) : AuSPtr<IProcessSectionMapView> {};
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapFileByObject(const AuSPtr<AuFS::IFileStream> &stream,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode,
|
|
AuFS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
return this->MapFileByObjectEx(-1, stream, uOffset, uLength, mode, processLockLevel);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapIPCMemory(const AuString &handleString,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode)
|
|
{
|
|
return this->MapIPCMemoryEx(-1, handleString, uOffset, uLength, mode);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::AllocateEx(AuUInt uLength, AuUInt uOffset)
|
|
{
|
|
PageTable table {};
|
|
table.NX = true;
|
|
table.readable = true;
|
|
table.writable = true;
|
|
return this->AllocateEx2(uLength, uOffset, table);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::AllocateEx2(AuUInt uLength, AuUInt uOffset, PageTable permissions)
|
|
{
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
AuUInt32 uProtFlags {};
|
|
|
|
if (!permissions.NX)
|
|
{
|
|
uProtFlags |= PROT_EXEC;
|
|
}
|
|
|
|
if (permissions.writable)
|
|
{
|
|
uProtFlags |= PROT_WRITE;
|
|
}
|
|
|
|
if (permissions.readable)
|
|
{
|
|
uProtFlags |= PROT_READ;
|
|
}
|
|
|
|
auto map = this->MapAddress(uOffset, uLength, uProtFlags, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
|
if (map == MAP_FAILED)
|
|
{
|
|
SysPushErrorIO();
|
|
return {};
|
|
}
|
|
|
|
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
|
|
uLength,
|
|
false);
|
|
if (!pNewObject)
|
|
{
|
|
SysPushErrorMem();
|
|
return {};
|
|
}
|
|
|
|
pNewObject->pSharedSectionHint = AuSharedFromThis();
|
|
return pNewObject;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapFileByPathEx(AuUInt viewOffset,
|
|
const AuString &str,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode,
|
|
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
auto file = AuFS::OpenShared(str, mode, AuFS::EFileAdvisoryLockLevel::eNoSafety);
|
|
return file ? this->MapFileByObjectEx(viewOffset, file, uOffset, uLength, mode, processLockLevel) : AuSPtr<IProcessSectionMapView> {};
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapFileByObjectEx(AuUInt viewOffset,
|
|
const AuSPtr<Aurora::IO::FS::IFileStream> &pStream,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode,
|
|
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
if (!pStream)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
if (this->IsAddressValid(viewOffset))
|
|
{
|
|
SysPushErrorMemory("Address space is in use");
|
|
return {};
|
|
}
|
|
|
|
auto ok = AuStaticCast<AuFS::PosixFileStream>(pStream);
|
|
int fd = ::dup(ok->GetHandle());
|
|
if (fd == -1)
|
|
{
|
|
SysPushErrorIO();
|
|
return {};
|
|
}
|
|
|
|
// TODO (Reece): lock garbage
|
|
|
|
int prot {};
|
|
switch (mode)
|
|
{
|
|
case AuFS::EFileOpenMode::eRead:
|
|
{
|
|
prot = PROT_READ;
|
|
break;
|
|
}
|
|
case AuFS::EFileOpenMode::eWrite:
|
|
case AuFS::EFileOpenMode::eReadWrite:
|
|
{
|
|
prot = PROT_READ | PROT_WRITE;
|
|
break;
|
|
}
|
|
default:
|
|
SysPushErrorGeneric();
|
|
return {};
|
|
};
|
|
|
|
auto map = this->MapAddress(viewOffset, uLength, prot, MAP_SHARED, fd, uOffset);
|
|
if (map == MAP_FAILED)
|
|
{
|
|
SysPushErrorIO();
|
|
::close(fd);
|
|
return {};
|
|
}
|
|
|
|
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
|
|
uLength,
|
|
false,
|
|
fd);
|
|
if (!pNewObject)
|
|
{
|
|
SysPushErrorMem();
|
|
::close(fd);
|
|
return {};
|
|
}
|
|
|
|
pNewObject->pSharedSectionHint = AuSharedFromThis();
|
|
return pNewObject;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapIPCMemoryEx(AuUInt viewOffset,
|
|
const AuString &handleString,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode)
|
|
{
|
|
AuIPC::IPCHandle handle;
|
|
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
if (this->IsAddressValid(viewOffset))
|
|
{
|
|
SysPushErrorMemory("Address space is in use");
|
|
return {};
|
|
}
|
|
|
|
if (!handle.FromString(handleString))
|
|
{
|
|
SysPushErrorParseError("Invalid handle: {}", handleString);
|
|
return {};
|
|
}
|
|
|
|
auto val = handle.GetToken(AuIPC::EIPCHandleType::eIPCMemory, 0);
|
|
if (!val)
|
|
{
|
|
SysPushErrorParseError("Invalid handle: {}", handleString);
|
|
return {};
|
|
}
|
|
|
|
auto actualLength = val->token.word;
|
|
auto path = AuIPC::GetServerPath(val->token);
|
|
|
|
if (actualLength < uOffset + uLength)
|
|
{
|
|
SysPushErrorIO("Out of range");
|
|
return {};
|
|
}
|
|
|
|
int fd = ::shm_open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
|
|
if (fd == -1)
|
|
{
|
|
SysPushErrorIO();
|
|
return {};
|
|
}
|
|
|
|
// TODO (Reece): lock garbage ( ??? )
|
|
|
|
int prot {};
|
|
switch (mode)
|
|
{
|
|
case AuFS::EFileOpenMode::eRead:
|
|
{
|
|
prot = PROT_READ;
|
|
break;
|
|
}
|
|
case AuFS::EFileOpenMode::eWrite:
|
|
case AuFS::EFileOpenMode::eReadWrite:
|
|
{
|
|
prot = PROT_READ | PROT_WRITE;
|
|
break;
|
|
}
|
|
default:
|
|
SysPushErrorGeneric();
|
|
return {};
|
|
};
|
|
|
|
auto map = this->MapAddress(viewOffset, uLength, prot, MAP_SHARED, fd, uOffset);
|
|
if (map == MAP_FAILED)
|
|
{
|
|
SysPushErrorIO();
|
|
::close(fd);
|
|
return {};
|
|
}
|
|
|
|
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
|
|
uLength,
|
|
false,
|
|
fd);
|
|
if (!pNewObject)
|
|
{
|
|
SysPushErrorMem();
|
|
::close(fd);
|
|
return {};
|
|
}
|
|
|
|
pNewObject->pSharedSectionHint = AuSharedFromThis();
|
|
return pNewObject;
|
|
}
|
|
|
|
AuList<AuPair<AuUInt, AuUInt>> ProcessSectionViewReserved::GetAllocations()
|
|
{
|
|
AU_LOCK_GUARD(this->spinlock);
|
|
return this->allocations;
|
|
}
|
|
|
|
AUKN_SYM AuSPtr<IProcessSectionView> ReserveAddressSpace(AuUInt uLength)
|
|
{
|
|
auto &platform = AuSwInfo::GetPlatformInfo();
|
|
|
|
auto pSectionView = AuMakeShared<ProcessSectionViewReserved>();
|
|
if (!pSectionView)
|
|
{
|
|
SysPushErrorMemory();
|
|
return {};
|
|
}
|
|
|
|
if (!pSectionView->Init(uLength))
|
|
{
|
|
SysPushErrorMemory();
|
|
return {};
|
|
}
|
|
|
|
return pSectionView;
|
|
}
|
|
} |