Files
MontaukOS/kernel/src/Api/UserMemory.hpp
T

85 lines
2.7 KiB
C++

#pragma once
#include <cstddef>
#include <cstdint>
#include <Sched/Scheduler.hpp>
#include <Memory/Paging.hpp>
#include <Api/Heap.hpp>
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<typename T>
inline bool Readable(uint64_t addr) {
return Range(addr, sizeof(T), false);
}
template<typename T>
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;
}
}