/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuProcessSectionView.Unix.hpp Date: 2022-08-10 Author: Reece ***/ #include #include "AuProcessSectionView.Unix.hpp" #include "Process.hpp" #include #include "AuProcessSectionFileMapView.Unix.hpp" #include #include #include #include #include namespace Aurora::Process { AuUInt ProcessSectionView::GetStart() { return AuNumericLimits::min(); } AuUInt ProcessSectionView::GetEnd() { return AuNumericLimits::max(); } AuSPtr ProcessSectionView::Allocate(AuUInt uLength) { if (!uLength) { SysPushErrorArg("invalid uLength"); return {}; } auto map = ::mmap(nullptr, uLength, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (map == MAP_FAILED) { SysPushErrorIO(); return {}; } auto newObject = AuMakeShared(AuUInt(map), uLength, false); if (!newObject) { SysPushErrorMem(); ::munmap(map, uLength); return {}; } return newObject; } AuSPtr ProcessSectionView::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 {}; } AuSPtr ProcessSectionView::MapFileByObject(const AuSPtr &stream, AuUInt64 uOffset, AuUInt uLength, AuFS::EFileOpenMode mode, AuFS::EFileAdvisoryLockLevel processLockLevel) { return this->MapFileByObjectEx(0, stream, uOffset, uLength, mode, processLockLevel); } AuSPtr ProcessSectionView::MapIPCMemory(const AuString &handleString, AuUInt64 uOffset, AuUInt uLength, AuFS::EFileOpenMode mode) { return this->MapIPCMemoryEx(0, handleString, uOffset, uLength, mode); } AuSPtr ProcessSectionView::AllocateEx(AuUInt uLength, AuUInt uOffset) { PageTable table {}; table.NX = true; table.readable = true; table.writable = true; return this->AllocateEx2(uLength, uOffset, table); } AuSPtr ProcessSectionView::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 = ::mmap((void *)uOffset, uLength, uProtFlags, MAP_ANONYMOUS | MAP_PRIVATE | (uOffset ? MAP_FIXED : 0), 0, 0); if (map == MAP_FAILED) { SysPushErrorIO(); return {}; } auto newObject = AuMakeShared(AuUInt(map), uLength, false); if (!newObject) { SysPushErrorMem(); ::munmap(map, uLength); return {}; } return newObject; } AuSPtr ProcessSectionView::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 {}; } AuSPtr ProcessSectionView::MapFileByObjectEx(AuUInt viewOffset, const AuSPtr &pStream, AuUInt64 uOffset, AuUInt uLength, Aurora::IO::FS::EFileOpenMode mode, Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel) { if (!pStream) { return {}; } if (!uLength) { SysPushErrorArg("invalid uLength"); return {}; } auto ok = AuStaticCast(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 = ::mmap((void *)viewOffset, uLength, prot, MAP_SHARED | (viewOffset ? MAP_FIXED : 0), fd, uOffset); if (map == MAP_FAILED) { SysPushErrorIO(); ::close(fd); return {}; } auto newObject = AuMakeShared(AuUInt(map), uLength, true, fd); if (!newObject) { SysPushErrorMem(); ::close(fd); ::munmap(map, uLength); return {}; } return newObject; } AuSPtr ProcessSectionView::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 (!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 = ::mmap((void *)viewOffset, uLength, prot, MAP_SHARED | (viewOffset ? MAP_FIXED : 0), fd, uOffset); if (map == MAP_FAILED) { SysPushErrorIO(); ::close(fd); return {}; } auto newObject = AuMakeShared(AuUInt(map), uLength, true, fd); if (!newObject) { SysPushErrorMem(); ::close(fd); ::munmap(map, val->token.word); return {}; } return newObject; } AuList> ProcessSectionView::GetAllocations() { AU_LOCK_GUARD(this->spinlock); return allocations; } AUKN_SYM AuSPtr GetGlobalProcessSpace() { static ProcessSectionView gSingleton; return AuUnsafeRaiiToShared(&gSingleton); } }