/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuProcessSectionViewReserved.Unix.cpp Date: 2022-11-15 Author: Reece ***/ #include #include "AuProcessSectionViewReserved.Unix.hpp" #include "Process.hpp" #include #include "AuProcessSectionFileMapView.Unix.hpp" #include #include #include #include #include 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 ProcessSectionViewReserved::Allocate(AuUInt uLength) { return this->AllocateEx(uLength, -1); } AuSPtr ProcessSectionViewReserved::MapFileByPath(const AuString &str, AuUInt64 uOffset, AuUInt uLength, AuFS::EFileOpenMode mode, AuFS::EFileAdvisoryLockLevel sectionLock) { return this->MapFileByPathEx(-1, str, uOffset, uLength, mode, sectionLock); } AuSPtr ProcessSectionViewReserved::MapFileByObject(const AuSPtr &pIOHandle, AuUInt64 uOffset, AuUInt uLength, AuFS::EFileOpenMode mode, AuFS::EFileAdvisoryLockLevel processLockLevel) { return this->MapFileByObjectEx(-1, pIOHandle, uOffset, uLength, mode, processLockLevel); } AuSPtr ProcessSectionViewReserved::MapIPCMemory(const AuString &handleString, AuUInt64 uOffset, AuUInt uLength, AuFS::EFileOpenMode mode) { return this->MapIPCMemoryEx(-1, handleString, uOffset, uLength, mode); } AuSPtr ProcessSectionViewReserved::AllocateEx(AuUInt uLength, AuUInt uOffset) { PageTable table {}; table.NX = true; table.readable = true; table.writable = true; return this->AllocateEx2(uLength, uOffset, table); } AuSPtr 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(AuUInt(map), uLength, false); if (!pNewObject) { SysPushErrorMem(); return {}; } pNewObject->pSharedSectionHint = AuSharedFromThis(); return pNewObject; } AuSPtr ProcessSectionViewReserved::MapFileByPathEx(AuUInt viewOffset, const AuString &str, AuUInt64 uOffset, AuUInt uLength, Aurora::IO::FS::EFileOpenMode mode, Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel) { auto pHandle = AuIO::IOHandleShared(); if (!pHandle) { SysPushErrorMemory(); return nullptr; } AuIO::IIOHandle::HandleCreate createhandle(str); createhandle.eAdvisoryLevel = AuFS::EFileAdvisoryLockLevel::eNoSafety; createhandle.eMode = mode; createhandle.bFailIfNonEmptyFile = false; createhandle.bDirectIOMode = false; createhandle.bAsyncHandle = false; if (!pHandle->InitFromPath(createhandle)) { return nullptr; } return this->MapFileByObjectEx(viewOffset, pHandle, uOffset, uLength, mode, processLockLevel); } AuSPtr ProcessSectionViewReserved::MapFileByObjectEx(AuUInt viewOffset, const AuSPtr &pIOHandle, AuUInt64 uOffset, AuUInt uLength, Aurora::IO::FS::EFileOpenMode mode, Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel) { if (!pIOHandle) { return {}; } if (!uLength) { SysPushErrorArg("invalid uLength"); return {}; } if (this->IsAddressValid(viewOffset)) { SysPushErrorMemory("Address space is in use"); return {}; } int fd = ::dup(pIOHandle->GetOSHandle()); 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(AuUInt(map), uLength, false, fd); if (!pNewObject) { SysPushErrorMem(); ::close(fd); return {}; } pNewObject->pSharedSectionHint = AuSharedFromThis(); return pNewObject; } AuSPtr 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(AuUInt(map), uLength, false, fd); if (!pNewObject) { SysPushErrorMem(); ::close(fd); return {}; } pNewObject->pSharedSectionHint = AuSharedFromThis(); return pNewObject; } AuList> ProcessSectionViewReserved::GetAllocations() { AU_LOCK_GUARD(this->spinlock); return this->allocations; } AUKN_SYM AuSPtr ReserveAddressSpace(AuUInt uLength) { auto &platform = AuSwInfo::GetPlatformInfo(); auto pSectionView = AuMakeShared(); if (!pSectionView) { SysPushErrorMemory(); return {}; } if (!pSectionView->Init(uLength)) { SysPushErrorMemory(); return {}; } return pSectionView; } }