mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-28 12:05:06 +00:00
203 lines
7.8 KiB
C++
203 lines
7.8 KiB
C++
#include "prx/libkernel_sys/include/Api.hpp"
|
|
#include "prx/libkernel/include/Api.hpp"
|
|
#include "prx/libc/include/Api.hpp"
|
|
#include "SceTypes.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <limits>
|
|
#include <source_location>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
void AioHoldWorkerForTest_nid_no_patch(bool hold);
|
|
}
|
|
|
|
namespace {
|
|
|
|
constexpr int Ebadf = 9;
|
|
constexpr int Efault = 14;
|
|
constexpr int Einval = 22;
|
|
constexpr int Eagain = 35;
|
|
constexpr int Einprogress = 36;
|
|
constexpr int Eopnotsupp = 45;
|
|
constexpr int Ecanceled = 85;
|
|
constexpr int ORdonly = 0;
|
|
constexpr int ORdwr = 2;
|
|
constexpr int OCreat = 0x200;
|
|
constexpr int OSync = 0x80;
|
|
constexpr int ODsync = 0x1000000;
|
|
constexpr int AioCanceled = 1;
|
|
constexpr int AioAllDone = 3;
|
|
|
|
void Require(bool condition, std::source_location location = std::source_location::current()) {
|
|
if (condition) return;
|
|
std::fprintf(stderr, "check failed at line %u\n", static_cast<unsigned>(location.line()));
|
|
std::exit(1);
|
|
}
|
|
|
|
int Error() {
|
|
return *__error_nid_postfix();
|
|
}
|
|
|
|
GuestAiocb Request(int descriptor, void* buffer, std::uint64_t bytes, std::int64_t offset = 0) {
|
|
GuestAiocb request{};
|
|
request.fildes = descriptor;
|
|
request.buf = buffer;
|
|
request.nbytes = bytes;
|
|
request.offset = offset;
|
|
return request;
|
|
}
|
|
|
|
void Wait(GuestAiocb& request) {
|
|
const GuestAiocb* list[] = {&request};
|
|
Require(aio_suspend_nid_postfix(list, 1, nullptr) == 0);
|
|
}
|
|
|
|
void BeforeUse() {
|
|
GuestAiocb request{};
|
|
const GuestAiocb* list[] = {&request};
|
|
Require(aio_error_nid_postfix(&request) == Einval);
|
|
Require(aio_return_nid_postfix(&request) == -1 && Error() == Einval);
|
|
Require(aio_suspend_nid_postfix(list, 1, nullptr) == -1 && Error() == Eagain);
|
|
}
|
|
|
|
void Validation(int file, int readOnly) {
|
|
char buffer[8] = {};
|
|
Require(aio_read_nid_postfix(nullptr) == -1 && Error() == Efault);
|
|
|
|
auto bad = Request(-1, buffer, sizeof(buffer));
|
|
Require(aio_read_nid_postfix(&bad) == -1 && Error() == Ebadf);
|
|
Require(bad.status == -1 && bad.error == Ebadf && aio_error_nid_postfix(&bad) == Ebadf);
|
|
|
|
auto readOnlyWrite = Request(readOnly, buffer, sizeof(buffer));
|
|
Require(aio_write_nid_postfix(&readOnlyWrite) == -1 && Error() == Ebadf);
|
|
|
|
auto negative = Request(file, buffer, sizeof(buffer), -1);
|
|
Require(aio_read_nid_postfix(&negative) == -1 && Error() == Einval && negative.error == Einval);
|
|
|
|
auto huge = Request(file, buffer, std::uint64_t{std::numeric_limits<int>::max()} + 1);
|
|
Require(aio_read_nid_postfix(&huge) == -1 && Error() == Einval && huge.error == 0);
|
|
|
|
auto notify = Request(file, buffer, sizeof(buffer));
|
|
notify.sigevent.notify = 2;
|
|
Require(aio_read_nid_postfix(¬ify) == -1 && Error() == Einval && notify.error == Einval);
|
|
notify.sigevent = {1, 0, 0, {}};
|
|
Require(aio_read_nid_postfix(¬ify) == -1 && Error() == Einval);
|
|
|
|
int pipe[2] = {-1, -1};
|
|
Require(pipe_nid_postfix(pipe) == 0);
|
|
auto piped = Request(pipe[0], buffer, sizeof(buffer));
|
|
Require(aio_read_nid_postfix(&piped) == -1 && Error() == Eopnotsupp && piped.error == Eopnotsupp);
|
|
auto pipeSync = Request(pipe[1], nullptr, 0);
|
|
Require(aio_fsync_nid_postfix(OSync, &pipeSync) == -1 && Error() == Einval);
|
|
Require(close_nid_postfix(pipe[0]) == 0 && close_nid_postfix(pipe[1]) == 0);
|
|
|
|
auto sync = Request(file, nullptr, 0);
|
|
Require(aio_fsync_nid_postfix(0, &sync) == -1 && Error() == Einval);
|
|
Require(aio_fsync_nid_postfix(ODsync, &sync) == -1 && Error() == Einval);
|
|
}
|
|
|
|
void ReadAndWrite(int file) {
|
|
char text[] = "asynchronous";
|
|
auto write = Request(file, text, 12, 4);
|
|
Require(aio_write_nid_postfix(&write) == 0);
|
|
Wait(write);
|
|
Require(aio_error_nid_postfix(&write) == 0);
|
|
Require(aio_return_nid_postfix(&write) == 12 && write.status == 12 && write.error == 0);
|
|
Require(aio_return_nid_postfix(&write) == -1 && Error() == Einval);
|
|
Require(aio_error_nid_postfix(&write) == Einval);
|
|
|
|
char read[16] = {};
|
|
auto request = Request(file, read, sizeof(read), 6);
|
|
Require(aio_read_nid_postfix(&request) == 0);
|
|
Wait(request);
|
|
Require(aio_return_nid_postfix(&request) == 10 && std::memcmp(read, "ynchronous", 10) == 0);
|
|
|
|
auto empty = Request(file, read, 0, 0);
|
|
Require(aio_read_nid_postfix(&empty) == 0);
|
|
Wait(empty);
|
|
Require(aio_return_nid_postfix(&empty) == 0);
|
|
|
|
const GuestAiocb* none[] = {&request};
|
|
Require(aio_suspend_nid_postfix(none, 1, nullptr) == 0);
|
|
Require(aio_suspend_nid_postfix(none, 0, nullptr) == 0);
|
|
Require(aio_suspend_nid_postfix(none, -1, nullptr) == -1 && Error() == Einval);
|
|
Require(aio_suspend_nid_postfix(none, 257, nullptr) == -1 && Error() == Einval);
|
|
const KernelTimespec badTime{0, 1000000000};
|
|
Require(aio_suspend_nid_postfix(none, 1, &badTime) == -1 && Error() == Einval);
|
|
}
|
|
|
|
void Cancel(int file) {
|
|
char buffer[4] = {};
|
|
AioHoldWorkerForTest_nid_no_patch(true);
|
|
auto first = Request(file, buffer, sizeof(buffer));
|
|
auto second = Request(file, buffer, sizeof(buffer));
|
|
Require(aio_read_nid_postfix(&first) == 0 && aio_read_nid_postfix(&second) == 0);
|
|
Require(first.error == Einprogress && aio_error_nid_postfix(&first) == Einprogress);
|
|
const GuestAiocb* list[] = {&first};
|
|
const KernelTimespec brief{0, 5000000};
|
|
Require(aio_suspend_nid_postfix(list, 1, &brief) == -1 && Error() == Eagain);
|
|
|
|
Require(aio_cancel_nid_postfix(file, &first) == AioCanceled);
|
|
Require(aio_error_nid_postfix(&first) == Ecanceled && aio_error_nid_postfix(&second) == Einprogress);
|
|
Require(aio_suspend_nid_postfix(list, 1, &brief) == 0);
|
|
Require(aio_return_nid_postfix(&first) == -1 && Error() == Ecanceled);
|
|
Require(first.status == -1 && first.error == Ecanceled);
|
|
Require(aio_return_nid_postfix(&first) == -1 && Error() == Einval);
|
|
Require(aio_cancel_nid_postfix(file, &first) == AioAllDone);
|
|
|
|
Require(aio_cancel_nid_postfix(file, nullptr) == AioCanceled);
|
|
Require(aio_return_nid_postfix(&second) == -1 && Error() == Ecanceled);
|
|
Require(aio_cancel_nid_postfix(file, nullptr) == AioAllDone);
|
|
Require(aio_cancel_nid_postfix(-1, nullptr) == -1 && Error() == Ebadf);
|
|
AioHoldWorkerForTest_nid_no_patch(false);
|
|
}
|
|
|
|
void SyncOrder(int file) {
|
|
char text[] = "ordered";
|
|
AioHoldWorkerForTest_nid_no_patch(true);
|
|
auto write = Request(file, text, 7, 0);
|
|
auto sync = Request(file, nullptr, 0);
|
|
Require(aio_write_nid_postfix(&write) == 0 && aio_fsync_nid_postfix(OSync, &sync) == 0);
|
|
Require(aio_error_nid_postfix(&sync) == Einprogress);
|
|
AioHoldWorkerForTest_nid_no_patch(false);
|
|
|
|
GuestAiocb* done = nullptr;
|
|
Require(aio_waitcomplete_nid_postfix(&done, nullptr) == 7 && done == &write);
|
|
Require(aio_waitcomplete_nid_postfix(&done, nullptr) == 0 && done == &sync && sync.status == 0);
|
|
const KernelTimespec zero{0, 0};
|
|
Require(aio_waitcomplete_nid_postfix(&done, &zero) == -1 && Error() == Eagain && done == nullptr);
|
|
const KernelTimespec brief{0, 5000000};
|
|
Require(aio_waitcomplete_nid_postfix(&done, &brief) == -1 && Error() == Eagain);
|
|
const KernelTimespec badTime{0, -1};
|
|
Require(aio_waitcomplete_nid_postfix(&done, &badTime) == -1 && Error() == Einval);
|
|
}
|
|
|
|
}
|
|
|
|
int main() {
|
|
const auto path = "anyps5-kernel-sys-aio-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + ".bin";
|
|
BeforeUse();
|
|
const int file = open_nid_postfix(path.c_str(), ORdwr | OCreat, 0600);
|
|
const int readOnly = open_nid_postfix(path.c_str(), ORdonly, 0);
|
|
Require(file >= 0 && readOnly >= 0);
|
|
Validation(file, readOnly);
|
|
ReadAndWrite(file);
|
|
Cancel(file);
|
|
SyncOrder(file);
|
|
Require(close_nid_postfix(readOnly) == 0 && close_nid_postfix(file) == 0);
|
|
Require(std::filesystem::remove(path));
|
|
std::puts("guest_kernel_sys_aio passed");
|
|
return 0;
|
|
}
|