#pragma once #include #include #include #include #include namespace montauk::abi::UserMemory { static constexpr uint64_t USER_SPACE_END = 0x0000800000000000ULL; inline bool IsUserPtr(uint64_t addr) { return addr == 0 || addr < USER_SPACE_END; } inline bool ValidUserPtr(uint64_t addr) { return addr != 0 && addr < USER_SPACE_END; } inline uint64_t CurrentPml4() { auto* proc = Sched::GetCurrentProcessPtr(); return proc ? proc->pml4Phys : 0; } inline bool Range(uint64_t addr, uint64_t size, bool requireWrite = false) { if (size == 0) return true; if (!ValidUserPtr(addr)) return false; if (addr + size < addr) return false; if (addr + size > USER_SPACE_END) return false; uint64_t pml4Phys = CurrentPml4(); if (pml4Phys == 0) return false; if (Memory::VMM::Paging::IsUserRangeAccessible(pml4Phys, addr, size, requireWrite)) return true; // Anonymous VMAs are demand-committed. Validation precedes the actual // kernel copy, so materialize missing pages here with the same access // type that the copy will perform. uint64_t page = addr & ~0xFFFULL; uint64_t last = (addr + size - 1) & ~0xFFFULL; for (;;) { if (!Memory::VMM::Paging::IsUserRangeAccessible(pml4Phys, page, 1, requireWrite) && !TryHandleAnonymousPageFault(page, requireWrite ? 2ULL : 0ULL)) return false; if (page == last) break; page += 0x1000ULL; } return Memory::VMM::Paging::IsUserRangeAccessible(pml4Phys, addr, size, requireWrite); } inline bool OptionalRange(uint64_t addr, uint64_t size, bool requireWrite = false) { return addr == 0 || Range(addr, size, requireWrite); } template inline bool Readable(uint64_t addr) { return Range(addr, sizeof(T), false); } template inline bool Writable(uint64_t addr) { return Range(addr, sizeof(T), true); } inline bool String(uint64_t addr, uint64_t maxLen) { if (!ValidUserPtr(addr) || maxLen == 0) return false; uint64_t pml4Phys = CurrentPml4(); if (pml4Phys == 0) return false; const char* str = (const char*)addr; for (uint64_t i = 0; i < maxLen; i++) { if (!Memory::VMM::Paging::IsUserRangeAccessible(pml4Phys, addr + i, 1, false)) { if (!TryHandleAnonymousPageFault(addr + i, 0)) return false; } if (str[i] == '\0') return true; } return false; } }