Files

632 lines
20 KiB
C++
Raw Permalink Normal View History

2025-10-02 00:20:28 -06:00
#include "memoryapi.h"
2025-10-02 00:20:28 -06:00
#include "common.h"
#include "context.h"
2025-10-02 00:20:28 -06:00
#include "errors.h"
#include "handles.h"
2025-11-02 20:18:23 -07:00
#include "heap.h"
2025-10-02 00:20:28 -06:00
#include "internal.h"
#include "strutil.h"
2025-11-04 22:07:51 -07:00
#include "types.h"
2025-10-02 00:20:28 -06:00
#include <cerrno>
2025-10-30 02:23:09 -06:00
#include <cstring>
2025-10-02 00:20:28 -06:00
#include <fcntl.h>
#include <iterator>
#include <limits>
#include <map>
#include <mutex>
#include <sys/mman.h>
#include <unistd.h>
#include <utility>
namespace {
constexpr size_t kVirtualAllocationGranularity = 64 * 1024;
2025-10-02 17:11:28 -06:00
constexpr uintptr_t kProcessAddressLimit = 0x80000000;
2025-10-02 00:20:28 -06:00
struct MappingObject : ObjectBase {
static constexpr ObjectType kType = ObjectType::Mapping;
std::mutex m;
2025-10-02 00:20:28 -06:00
int fd = -1;
size_t maxSize = 0;
DWORD protect = 0;
bool anonymous = false;
bool closed = false;
explicit MappingObject() : ObjectBase(kType) {}
~MappingObject() override;
2025-10-02 00:20:28 -06:00
};
MappingObject::~MappingObject() {
if (fd != -1) {
close(fd);
fd = -1;
}
}
2025-10-02 00:20:28 -06:00
struct ViewInfo {
2025-10-02 17:11:28 -06:00
uintptr_t viewBase = 0;
size_t viewLength = 0;
uintptr_t allocationBase = 0;
size_t allocationLength = 0;
Pin<MappingObject> owner;
2025-10-02 17:11:28 -06:00
DWORD protect = PAGE_NOACCESS;
DWORD allocationProtect = PAGE_NOACCESS;
DWORD type = MEM_PRIVATE;
2025-11-02 20:18:23 -07:00
bool managed = false;
2025-10-02 00:20:28 -06:00
};
2025-10-02 17:11:28 -06:00
std::map<uintptr_t, ViewInfo> g_viewInfo;
std::mutex g_viewInfoMutex;
2025-10-02 00:20:28 -06:00
uintptr_t alignDown(uintptr_t value, size_t alignment) {
const uintptr_t mask = static_cast<uintptr_t>(alignment) - 1;
return value & ~mask;
}
uintptr_t alignUp(uintptr_t value, size_t alignment) {
const uintptr_t mask = static_cast<uintptr_t>(alignment) - 1;
if (mask == std::numeric_limits<uintptr_t>::max()) {
return value;
}
if (value > std::numeric_limits<uintptr_t>::max() - mask) {
return std::numeric_limits<uintptr_t>::max();
}
return (value + mask) & ~mask;
}
2025-10-02 17:11:28 -06:00
DWORD desiredAccessToProtect(DWORD desiredAccess, DWORD mappingProtect) {
DWORD access = desiredAccess;
if ((access & FILE_MAP_ALL_ACCESS) == FILE_MAP_ALL_ACCESS) {
access |= FILE_MAP_READ | FILE_MAP_WRITE;
}
bool wantExecute = (access & FILE_MAP_EXECUTE) != 0;
bool wantWrite = (access & FILE_MAP_WRITE) != 0;
bool wantCopy = (access & FILE_MAP_COPY) != 0;
bool wantRead = (access & (FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY)) != 0;
if (wantCopy) {
wantWrite = true;
}
const bool supportsWrite = mappingProtect == PAGE_READWRITE || mappingProtect == PAGE_EXECUTE_READWRITE ||
mappingProtect == PAGE_WRITECOPY || mappingProtect == PAGE_EXECUTE_WRITECOPY;
2025-10-02 17:11:28 -06:00
const bool supportsCopy = mappingProtect == PAGE_WRITECOPY || mappingProtect == PAGE_EXECUTE_WRITECOPY;
if (wantCopy && !supportsCopy) {
wantCopy = false;
}
if (wantWrite && !supportsWrite) {
if (supportsCopy) {
wantCopy = true;
wantWrite = false;
} else {
wantWrite = false;
}
}
if (!wantRead && (mappingProtect == PAGE_READONLY || mappingProtect == PAGE_EXECUTE_READ ||
mappingProtect == PAGE_WRITECOPY || mappingProtect == PAGE_EXECUTE_WRITECOPY)) {
2025-10-02 17:11:28 -06:00
wantRead = true;
}
DWORD protect = PAGE_NOACCESS;
if (wantCopy && supportsCopy) {
protect = wantExecute ? PAGE_EXECUTE_WRITECOPY : PAGE_WRITECOPY;
} else if (wantExecute) {
if (wantWrite) {
protect = PAGE_EXECUTE_READWRITE;
} else if (wantRead) {
protect = PAGE_EXECUTE_READ;
} else {
protect = PAGE_EXECUTE;
}
} else {
if (wantWrite) {
protect = PAGE_READWRITE;
} else if (wantRead) {
protect = PAGE_READONLY;
}
}
if ((mappingProtect & PAGE_NOCACHE) != 0) {
protect |= PAGE_NOCACHE;
}
if ((mappingProtect & PAGE_GUARD) != 0) {
protect |= PAGE_GUARD;
}
if ((mappingProtect & PAGE_WRITECOMBINE) != 0) {
protect |= PAGE_WRITECOMBINE;
}
return protect;
}
bool mappedViewRegionForAddress(uintptr_t request, uintptr_t pageBase, MEMORY_BASIC_INFORMATION &info) {
std::lock_guard guard(g_viewInfoMutex);
2025-10-02 17:11:28 -06:00
if (g_viewInfo.empty()) {
return false;
}
2025-11-02 20:18:23 -07:00
const size_t pageSize = wibo::heap::systemPageSize();
2025-10-02 17:11:28 -06:00
for (const auto &entry : g_viewInfo) {
const ViewInfo &view = entry.second;
if (view.viewLength == 0) {
continue;
}
uintptr_t allocationStart = view.allocationBase;
uintptr_t allocationEnd = allocationStart + view.allocationLength;
if (pageBase < allocationStart || pageBase >= allocationEnd) {
continue;
}
uintptr_t viewStart = view.viewBase;
uintptr_t viewEnd = view.viewBase + view.viewLength;
if (request != 0 && (request < viewStart || request >= viewEnd)) {
continue;
}
uintptr_t blockStart = viewStart;
uintptr_t blockEnd = alignUp(viewEnd, pageSize);
2025-11-04 22:07:51 -07:00
info.BaseAddress = toGuestPtr(reinterpret_cast<void *>(blockStart));
info.AllocationBase = toGuestPtr(reinterpret_cast<void *>(view.viewBase));
2025-10-02 17:11:28 -06:00
info.AllocationProtect = view.allocationProtect;
info.RegionSize = blockEnd > blockStart ? blockEnd - blockStart : 0;
info.State = MEM_COMMIT;
info.Protect = view.protect;
info.Type = view.type;
return true;
}
return false;
}
2025-10-02 00:20:28 -06:00
} // namespace
namespace kernel32 {
2025-10-30 02:23:09 -06:00
HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
2025-11-02 20:18:23 -07:00
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("CreateFileMappingA(%p, %p, %u, %u, %u, %s)\n", hFile, lpFileMappingAttributes, flProtect,
dwMaximumSizeHigh, dwMaximumSizeLow, lpName ? lpName : "(null)");
(void)lpFileMappingAttributes;
(void)lpName;
uint64_t size = (static_cast<uint64_t>(dwMaximumSizeHigh) << 32) | dwMaximumSizeLow;
if (flProtect != PAGE_READONLY && flProtect != PAGE_READWRITE && flProtect != PAGE_WRITECOPY) {
DEBUG_LOG("CreateFileMappingA: unsupported protection 0x%x\n", flProtect);
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-11-04 22:07:51 -07:00
return NO_HANDLE;
2025-10-02 00:20:28 -06:00
}
auto mapping = make_pin<MappingObject>();
mapping->protect = flProtect;
2025-10-02 00:20:28 -06:00
if (hFile == INVALID_HANDLE_VALUE) {
mapping->anonymous = true;
mapping->fd = -1;
if (size == 0) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-11-04 22:07:51 -07:00
return NO_HANDLE;
2025-10-02 00:20:28 -06:00
}
mapping->maxSize = size;
} else {
auto file = wibo::handles().getAs<FileObject>(hFile);
if (!file || !file->valid()) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_HANDLE);
2025-11-04 22:07:51 -07:00
return NO_HANDLE;
2025-10-02 00:20:28 -06:00
}
int dupFd = fcntl(file->fd, F_DUPFD_CLOEXEC, 0);
2025-10-02 00:20:28 -06:00
if (dupFd == -1) {
setLastErrorFromErrno();
2025-11-04 22:07:51 -07:00
return NO_HANDLE;
2025-10-02 00:20:28 -06:00
}
mapping->fd = dupFd;
if (size == 0) {
off_t fileSize = lseek(dupFd, 0, SEEK_END);
2025-10-02 00:20:28 -06:00
if (fileSize < 0) {
2025-11-04 22:07:51 -07:00
return NO_HANDLE;
2025-10-02 00:20:28 -06:00
}
size = static_cast<uint64_t>(fileSize);
}
mapping->maxSize = size;
}
return wibo::handles().alloc(std::move(mapping), 0, 0);
2025-10-02 00:20:28 -06:00
}
2025-10-30 02:23:09 -06:00
HANDLE WINAPI CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
2025-11-02 20:18:23 -07:00
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("CreateFileMappingW -> ");
std::string name = wideStringToString(lpName);
return CreateFileMappingA(hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow,
lpName ? name.c_str() : nullptr);
}
static LPVOID mapViewOfFileInternal(Pin<MappingObject> mapping, DWORD dwDesiredAccess, uint64_t offset,
SIZE_T dwNumberOfBytesToMap, LPVOID baseAddress) {
2025-10-02 00:20:28 -06:00
if (!mapping) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_HANDLE);
2025-10-02 00:20:28 -06:00
return nullptr;
}
if (mapping->closed) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_HANDLE);
2025-10-02 00:20:28 -06:00
return nullptr;
}
if (mapping->anonymous && offset != 0) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 00:20:28 -06:00
return nullptr;
}
size_t maxSize = mapping->maxSize;
uint64_t length = static_cast<uint64_t>(dwNumberOfBytesToMap);
if (length == 0) {
if (maxSize == 0 || offset > maxSize) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 00:20:28 -06:00
return nullptr;
}
length = maxSize - offset;
}
if (length == 0) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 00:20:28 -06:00
return nullptr;
}
if (maxSize != 0 && offset + length > maxSize) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 00:20:28 -06:00
return nullptr;
}
bool wantWrite = (dwDesiredAccess & FILE_MAP_WRITE) != 0;
bool wantExecute = (dwDesiredAccess & FILE_MAP_EXECUTE) != 0;
bool wantCopy = (dwDesiredAccess & FILE_MAP_COPY) != 0;
2025-10-02 17:11:28 -06:00
bool wantAllAccess = (dwDesiredAccess & FILE_MAP_ALL_ACCESS) == FILE_MAP_ALL_ACCESS;
if (wantAllAccess) {
wantWrite = true;
}
int prot = PROT_READ;
2025-10-02 00:20:28 -06:00
if (mapping->protect == PAGE_READWRITE) {
if (wantWrite || wantCopy) {
2025-10-02 00:20:28 -06:00
prot |= PROT_WRITE;
}
} else {
if (wantWrite && !wantCopy) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_ACCESS_DENIED);
2025-10-02 00:20:28 -06:00
return nullptr;
}
if (wantCopy) {
prot |= PROT_WRITE;
}
2025-10-02 00:20:28 -06:00
}
if (wantExecute) {
prot |= PROT_EXEC;
}
int flags = (mapping->anonymous ? MAP_ANONYMOUS : 0) | (wantCopy ? MAP_PRIVATE : MAP_SHARED);
2025-11-02 20:18:23 -07:00
const size_t pageSize = wibo::heap::systemPageSize();
2025-10-02 00:20:28 -06:00
off_t alignedOffset = mapping->anonymous ? 0 : static_cast<off_t>(offset & ~static_cast<uint64_t>(pageSize - 1));
size_t offsetDelta = static_cast<size_t>(offset - static_cast<uint64_t>(alignedOffset));
uint64_t requestedLength = length + offsetDelta;
if (requestedLength < length) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 00:20:28 -06:00
return nullptr;
}
size_t mapLength = static_cast<size_t>(requestedLength);
if (static_cast<uint64_t>(mapLength) != requestedLength) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 00:20:28 -06:00
return nullptr;
}
int mmapFd = mapping->anonymous ? -1 : mapping->fd;
void *requestedBase = nullptr;
int mapFlags = flags;
2025-11-02 20:18:23 -07:00
bool reservedMapping = false;
if (baseAddress) {
uintptr_t baseAddr = reinterpret_cast<uintptr_t>(baseAddress);
if (baseAddr == 0 || (baseAddr % kVirtualAllocationGranularity) != 0) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_ADDRESS);
return nullptr;
}
if (offsetDelta > baseAddr) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_ADDRESS);
return nullptr;
}
uintptr_t mapBaseAddr = baseAddr - offsetDelta;
if ((mapBaseAddr & (pageSize - 1)) != 0) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_ADDRESS);
return nullptr;
}
requestedBase = reinterpret_cast<void *>(mapBaseAddr);
#ifdef MAP_FIXED_NOREPLACE
mapFlags |= MAP_FIXED_NOREPLACE;
#else
mapFlags |= MAP_FIXED;
#endif
2025-11-02 20:18:23 -07:00
} else {
void *candidate = nullptr;
wibo::heap::VmStatus reserveStatus = wibo::heap::reserveViewRange(mapLength, 0, 0, &candidate);
if (reserveStatus != wibo::heap::VmStatus::Success) {
setLastError(wibo::heap::win32ErrorFromVmStatus(reserveStatus));
return nullptr;
}
reservedMapping = true;
requestedBase = candidate;
mapFlags |= MAP_FIXED;
}
errno = 0;
void *mapBase = mmap(requestedBase, mapLength, prot, mapFlags, mmapFd, alignedOffset);
2025-10-02 00:20:28 -06:00
if (mapBase == MAP_FAILED) {
int err = errno;
if (baseAddress && (err == ENOMEM || err == EEXIST || err == EINVAL || err == EPERM)) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_ADDRESS);
} else {
2025-10-28 10:01:21 -06:00
setLastError(wibo::winErrorFromErrno(err));
}
2025-11-02 20:18:23 -07:00
if (reservedMapping) {
wibo::heap::releaseViewRange(requestedBase);
}
2025-10-02 00:20:28 -06:00
return nullptr;
}
void *viewPtr = static_cast<uint8_t *>(mapBase) + offsetDelta;
if (baseAddress && viewPtr != baseAddress) {
munmap(mapBase, mapLength);
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_ADDRESS);
2025-11-02 20:18:23 -07:00
if (reservedMapping) {
wibo::heap::releaseViewRange(requestedBase);
}
return nullptr;
}
2025-10-02 17:11:28 -06:00
uintptr_t viewLength = static_cast<uintptr_t>(length);
uintptr_t alignedViewLength = alignUp(viewLength, pageSize);
if (alignedViewLength == std::numeric_limits<uintptr_t>::max()) {
alignedViewLength = viewLength;
}
DWORD protect = mapping->protect;
2025-10-02 17:11:28 -06:00
ViewInfo view{};
view.viewBase = reinterpret_cast<uintptr_t>(viewPtr);
view.viewLength = static_cast<size_t>(alignedViewLength);
view.allocationBase = reinterpret_cast<uintptr_t>(mapBase);
view.allocationLength = mapLength;
view.owner = std::move(mapping);
view.protect = desiredAccessToProtect(dwDesiredAccess, protect);
view.allocationProtect = protect;
2025-10-02 17:11:28 -06:00
view.type = MEM_MAPPED;
2025-11-02 20:18:23 -07:00
view.managed = reservedMapping;
if (reservedMapping) {
wibo::heap::registerViewRange(mapBase, mapLength, protect, view.protect);
}
2025-10-02 17:11:28 -06:00
{
std::lock_guard guard(g_viewInfoMutex);
g_viewInfo.emplace(view.viewBase, std::move(view));
2025-10-02 17:11:28 -06:00
}
2025-10-02 00:20:28 -06:00
return viewPtr;
}
2025-10-30 02:23:09 -06:00
LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
2025-11-02 20:18:23 -07:00
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("MapViewOfFile(%p, 0x%x, %u, %u, %zu)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
dwFileOffsetLow, dwNumberOfBytesToMap);
auto mapping = wibo::handles().getAs<MappingObject>(hFileMappingObject);
if (!mapping) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_HANDLE);
return nullptr;
}
uint64_t offset = (static_cast<uint64_t>(dwFileOffsetHigh) << 32) | dwFileOffsetLow;
return mapViewOfFileInternal(std::move(mapping), dwDesiredAccess, offset, dwNumberOfBytesToMap, nullptr);
}
2025-10-30 02:23:09 -06:00
LPVOID WINAPI MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
2025-11-02 20:18:23 -07:00
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("MapViewOfFileEx(%p, 0x%x, %u, %u, %zu, %p)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress);
auto mapping = wibo::handles().getAs<MappingObject>(hFileMappingObject);
if (!mapping) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_HANDLE);
return nullptr;
}
uint64_t offset = (static_cast<uint64_t>(dwFileOffsetHigh) << 32) | dwFileOffsetLow;
return mapViewOfFileInternal(std::move(mapping), dwDesiredAccess, offset, dwNumberOfBytesToMap, lpBaseAddress);
}
2025-10-30 02:23:09 -06:00
BOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("UnmapViewOfFile(%p)\n", lpBaseAddress);
std::unique_lock lk(g_viewInfoMutex);
2025-10-02 17:11:28 -06:00
auto it = g_viewInfo.find(reinterpret_cast<uintptr_t>(lpBaseAddress));
2025-10-02 00:20:28 -06:00
if (it == g_viewInfo.end()) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 00:20:28 -06:00
return FALSE;
}
void *base = reinterpret_cast<void *>(it->second.allocationBase);
size_t length = it->second.allocationLength;
2025-11-02 20:18:23 -07:00
bool managed = it->second.managed;
2025-10-02 00:20:28 -06:00
g_viewInfo.erase(it);
lk.unlock();
if (length != 0) {
munmap(base, length);
2025-10-02 00:20:28 -06:00
}
2025-11-02 20:18:23 -07:00
if (managed) {
wibo::heap::releaseViewRange(base);
}
2025-10-02 00:20:28 -06:00
return TRUE;
}
2025-10-30 02:23:09 -06:00
BOOL WINAPI FlushViewOfFile(LPCVOID lpBaseAddress, SIZE_T dwNumberOfBytesToFlush) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("FlushViewOfFile(%p, %zu)\n", lpBaseAddress, dwNumberOfBytesToFlush);
if (!lpBaseAddress) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
uintptr_t address = reinterpret_cast<uintptr_t>(lpBaseAddress);
uintptr_t viewBase = 0;
size_t viewLength = 0;
uintptr_t allocationBase = 0;
size_t allocationLength = 0;
{
std::lock_guard guard(g_viewInfoMutex);
auto it = g_viewInfo.upper_bound(address);
if (it == g_viewInfo.begin()) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
--it;
const auto &view = it->second;
if (address < view.viewBase || address >= view.viewBase + view.viewLength) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
viewBase = view.viewBase;
viewLength = view.viewLength;
allocationBase = view.allocationBase;
allocationLength = view.allocationLength;
}
size_t offsetIntoView = static_cast<size_t>(address - viewBase);
size_t bytesToFlush = dwNumberOfBytesToFlush;
size_t maxFlush = viewLength - offsetIntoView;
if (bytesToFlush == 0 || bytesToFlush > maxFlush) {
bytesToFlush = maxFlush;
}
if (bytesToFlush == 0) {
return TRUE;
}
uintptr_t flushStart = address;
uintptr_t flushEnd = flushStart + bytesToFlush;
2025-11-02 20:18:23 -07:00
const size_t pageSize = wibo::heap::systemPageSize();
uintptr_t alignedStart = alignDown(flushStart, pageSize);
uintptr_t alignedEnd = alignUp(flushEnd, pageSize);
if (alignedEnd == std::numeric_limits<uintptr_t>::max()) {
alignedEnd = flushEnd;
}
uintptr_t mappingEnd = allocationBase + allocationLength;
if (alignedEnd > mappingEnd) {
alignedEnd = mappingEnd;
}
if (alignedEnd < alignedStart) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
size_t length = static_cast<size_t>(alignedEnd - alignedStart);
if (length == 0) {
length = pageSize;
}
if (msync(reinterpret_cast<void *>(alignedStart), length, MS_SYNC) != 0) {
2025-10-28 10:01:21 -06:00
setLastError(wibo::winErrorFromErrno(errno));
return FALSE;
}
return TRUE;
}
2025-10-30 02:23:09 -06:00
LPVOID WINAPI VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("VirtualAlloc(%p, %zu, %u, %u)\n", lpAddress, dwSize, flAllocationType, flProtect);
2025-11-02 20:18:23 -07:00
void *base = lpAddress;
std::size_t size = static_cast<std::size_t>(dwSize);
wibo::heap::VmStatus status = wibo::heap::virtualAlloc(&base, &size, flAllocationType, flProtect);
if (status != wibo::heap::VmStatus::Success) {
DWORD err = wibo::heap::win32ErrorFromVmStatus(status);
DEBUG_LOG("-> failed (status=%u, err=%u)\n", static_cast<unsigned>(status), err);
setLastError(err);
2025-10-02 00:20:28 -06:00
return nullptr;
}
2025-11-03 23:22:29 -07:00
DEBUG_LOG("-> success (base=%p, size=%zu)\n", base, size);
2025-11-02 20:18:23 -07:00
return base;
2025-10-02 00:20:28 -06:00
}
2025-10-30 02:23:09 -06:00
BOOL WINAPI VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("VirtualFree(%p, %zu, %u)\n", lpAddress, dwSize, dwFreeType);
2025-11-02 20:18:23 -07:00
wibo::heap::VmStatus status = wibo::heap::virtualFree(lpAddress, static_cast<std::size_t>(dwSize), dwFreeType);
if (status != wibo::heap::VmStatus::Success) {
DWORD err = wibo::heap::win32ErrorFromVmStatus(status);
DEBUG_LOG("-> failed (status=%u, err=%u)\n", static_cast<unsigned>(status), err);
setLastError(err);
2025-10-02 00:20:28 -06:00
return FALSE;
}
return TRUE;
}
2025-10-30 02:23:09 -06:00
BOOL WINAPI VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("VirtualProtect(%p, %zu, %u)\n", lpAddress, dwSize, flNewProtect);
2025-11-02 20:18:23 -07:00
wibo::heap::VmStatus status =
wibo::heap::virtualProtect(lpAddress, static_cast<std::size_t>(dwSize), flNewProtect, lpflOldProtect);
if (status != wibo::heap::VmStatus::Success) {
DWORD err = wibo::heap::win32ErrorFromVmStatus(status);
DEBUG_LOG("-> failed (status=%u, err=%u)\n", static_cast<unsigned>(status), err);
setLastError(err);
2025-10-02 00:20:28 -06:00
return FALSE;
}
return TRUE;
}
2025-10-30 02:23:09 -06:00
SIZE_T WINAPI VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("VirtualQuery(%p, %p, %zu)\n", lpAddress, lpBuffer, dwLength);
2025-10-02 17:11:28 -06:00
if (!lpBuffer || dwLength < sizeof(MEMORY_BASIC_INFORMATION)) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
DEBUG_LOG("-> ERROR_INVALID_PARAMETER\n");
2025-10-02 00:20:28 -06:00
return 0;
}
std::memset(lpBuffer, 0, sizeof(MEMORY_BASIC_INFORMATION));
2025-11-02 20:18:23 -07:00
const size_t pageSize = wibo::heap::systemPageSize();
2025-10-02 17:11:28 -06:00
uintptr_t request = lpAddress ? reinterpret_cast<uintptr_t>(lpAddress) : 0;
2025-10-02 00:20:28 -06:00
uintptr_t pageBase = alignDown(request, pageSize);
2025-10-02 17:11:28 -06:00
if (pageBase >= kProcessAddressLimit) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 17:11:28 -06:00
DEBUG_LOG("-> ERROR_INVALID_PARAMETER (beyond address space)\n");
2025-10-02 00:20:28 -06:00
return 0;
}
2025-10-02 17:11:28 -06:00
MEMORY_BASIC_INFORMATION info{};
if (mappedViewRegionForAddress(request, pageBase, info)) {
*lpBuffer = info;
return sizeof(MEMORY_BASIC_INFORMATION);
2025-10-02 00:20:28 -06:00
}
2025-11-02 20:18:23 -07:00
wibo::heap::VmStatus status = wibo::heap::virtualQuery(lpAddress, &info);
if (status == wibo::heap::VmStatus::Success) {
2025-10-02 17:11:28 -06:00
*lpBuffer = info;
return sizeof(MEMORY_BASIC_INFORMATION);
2025-10-02 00:20:28 -06:00
}
2025-11-02 20:18:23 -07:00
DEBUG_LOG("VirtualQuery fallback failed status=%u\n", static_cast<unsigned>(status));
setLastError(wibo::heap::win32ErrorFromVmStatus(status));
DEBUG_LOG("-> VirtualQuery failed (status=%u)\n", static_cast<unsigned>(status));
2025-10-02 17:11:28 -06:00
return 0;
2025-10-02 00:20:28 -06:00
}
2025-10-30 02:23:09 -06:00
BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize,
2025-11-02 20:18:23 -07:00
PSIZE_T lpMaximumWorkingSetSize) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("GetProcessWorkingSetSize(%p, %p, %p)\n", hProcess, lpMinimumWorkingSetSize, lpMaximumWorkingSetSize);
(void)hProcess;
if (!lpMinimumWorkingSetSize || !lpMaximumWorkingSetSize) {
2025-10-28 10:01:21 -06:00
setLastError(ERROR_INVALID_PARAMETER);
2025-10-02 00:20:28 -06:00
return FALSE;
}
*lpMinimumWorkingSetSize = 32 * 1024 * 1024; // 32 MiB stub
*lpMaximumWorkingSetSize = 128 * 1024 * 1024; // 128 MiB stub
return TRUE;
}
2025-11-02 20:18:23 -07:00
BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize) {
HOST_CONTEXT_GUARD();
2025-10-02 00:20:28 -06:00
DEBUG_LOG("SetProcessWorkingSetSize(%p, %zu, %zu)\n", hProcess, dwMinimumWorkingSetSize, dwMaximumWorkingSetSize);
(void)hProcess;
(void)dwMinimumWorkingSetSize;
(void)dwMaximumWorkingSetSize;
return TRUE;
}
} // namespace kernel32