AnyPS5/core/libs/tests/GuestMsync.cpp

86 lines
2.9 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <limits>
#include <source_location>
#include <stdexcept>
extern "C" {
void* APS5_VABI mmap_nid_postfix(void*, std::size_t, int, int, int, std::int64_t) noexcept;
int APS5_VABI munmap_nid_postfix(void*, std::size_t) noexcept;
int APS5_VABI msync_nid_postfix(void*, std::size_t, int);
int APS5_VABI sceKernelReserveVirtualRange(void**, std::size_t, int, std::size_t);
int* APS5_VABI __error_nid_postfix();
}
namespace {
constexpr std::size_t Page = 0x4000;
constexpr int ReadWrite = 3;
constexpr int PrivateAnonymous = 0x1002;
constexpr int Sync = 0x0;
constexpr int Async = 0x1;
constexpr int Invalidate = 0x2;
constexpr int Invalid = 22;
constexpr int NoMemory = 12;
void Require(bool condition, std::source_location location = std::source_location::current()) {
if (condition) return;
std::fprintf(stderr, "msync check failed at line %u\n", static_cast<unsigned>(location.line()));
std::abort();
}
bool Succeeds(void* address, std::size_t length, int flags) {
*__error_nid_postfix() = 77;
return msync_nid_postfix(address, length, flags) == 0 && *__error_nid_postfix() == 77;
}
bool Fails(void* address, std::size_t length, int flags, int error) {
*__error_nid_postfix() = 0;
return msync_nid_postfix(address, length, flags) == -1 && *__error_nid_postfix() == error;
}
bool Throws(void* address, std::size_t length, int flags) {
try {
msync_nid_postfix(address, length, flags);
} catch (const std::runtime_error&) {
return true;
}
return false;
}
char* Map(std::size_t pages) {
void* mapped = mmap_nid_postfix(nullptr, pages * Page, ReadWrite, PrivateAnonymous, -1, 0);
Require(mapped != reinterpret_cast<void*>(static_cast<std::uintptr_t>(-1)));
return static_cast<char*>(mapped);
}
}
int main() {
char* mapped = Map(3);
mapped[0] = 1;
Require(Succeeds(mapped, 3 * Page, Sync));
Require(Succeeds(mapped, 3 * Page, Async));
Require(Succeeds(mapped + 100, 10, Sync));
Require(Succeeds(mapped + Page - 1, 2, Sync));
Require(Succeeds(mapped + Page, 0, Sync));
Require(Succeeds(mapped, Page, 0x4));
Require(Fails(mapped, Page, Async | Invalidate, Invalid));
const auto top = std::numeric_limits<std::uintptr_t>::max() & ~(Page - 1);
Require(Fails(reinterpret_cast<void*>(top), 2 * Page, Sync, Invalid));
Require(Throws(mapped, Page, Invalidate));
Require(munmap_nid_postfix(mapped, 3 * Page) == 0);
Require(Fails(mapped, Page, Sync, NoMemory));
Require(Fails(mapped + Page, 3 * Page, Async, NoMemory));
Require(Fails(mapped + Page, 0, Sync, NoMemory));
Require(Fails(mapped, Page, Invalidate, NoMemory));
void* reserved = nullptr;
Require(sceKernelReserveVirtualRange(&reserved, 2 * Page, 0, 0) == 0);
Require(Succeeds(reserved, 2 * Page, Sync));
Require(Succeeds(reserved, 0, Async));
return 0;
}