Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "Optimization/ResourceProgram.hpp"
#include "Optimization/ShaderStageInputInfo.hpp"
#include "Optimization/SrtWalker/SrtEvaluator.hpp"
#include "Optimization/SrtWalker/SrtInstructionPredicates.hpp"
#include "Optimization/SrtWalker/SrtFlatSlotClasses.hpp"
#include "SpirvBackend/SpirvAnalysis.hpp"
#if ANYPS5_ENABLE_SPIRV_TOOLS
Expand Down Expand Up @@ -85,6 +86,28 @@ void verifyRegisterSources() {
require(!EquivalentValue(plan, &samplerRegister, &firstVector), "different register types were merged");
}

void verifySignedMinimum() {
using namespace ShaderRecompiler;
IrResourcePlan plan;
IrValue reg(IrOpcode::Void, IrType::ScalarReg, 0);
reg.SetRegister({RegisterBank::Scalar, 0});
IrValue input(IrOpcode::GetUserData, IrType::U32, 1);
input.AddArgument(&reg);
IrValue limit(IrOpcode::Void, IrType::U32, 2);
limit.SetImmediateU32(8);
IrValue minimum(IrOpcode::SMin32, IrType::U32, 3);
minimum.AddArgument(&input);
minimum.AddArgument(&limit);
require(Detail::IsRuntimeUniformOp(IrOpcode::SMin32), "signed minimum must be a runtime uniform operation");
for (const auto& [value, expected] : std::array<std::pair<std::uint32_t, std::uint32_t>, 6>{{{0, 0}, {4, 4}, {20, 8}, {0x7fffffffu, 8}, {0xffffffffu, 0xffffffffu}, {0x80000000u, 0x80000000u}}}) {
std::array<std::uint32_t, 1> data{value};
SrtRuntime runtime{data};
Detail::Evaluator evaluator(plan, runtime);
std::uint32_t result = 0;
require(evaluator.Evaluate(&minimum, result) && result == expected, "SRT signed minimum used unsigned ordering or failed evaluation");
}
}

void verifyEvaluatedValues() {
using namespace ShaderRecompiler;
std::vector<std::unique_ptr<IrValue>> values;
Expand Down Expand Up @@ -1708,6 +1731,7 @@ int main() {
using namespace ShaderRecompiler;
verifyRegisterSources();
verifyEvaluatedValues();
verifySignedMinimum();
verifyPureFlatSlots();
verifyBindlessTable();
verifyDescriptorPhis();
Expand Down
10 changes: 7 additions & 3 deletions core/libs/prx/libSceAmpr/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,11 @@ int APS5_VABI sceAmprAprCommandBufferReadFileGather(Apr::CommandBufferObject* bu
(void)mapState;
(void)scatterGatherState;
if (!ValidReadLength(size) || !ValidReadOffset(offset)) return SCE_KERNEL_ERROR_EINVAL;
return AppendRead(buffer, Apr::Opcode::ReadFileGather, 0, nullptr, size, offset);
if (!buffer || (buffer->recording & Apr::ScatterGatherValid) == 0u) return SCE_KERNEL_ERROR_EINVAL;
const Apr::CompactReadFileGatherCommand command{
static_cast<std::uint32_t>(Apr::Opcode::CompactReadFileGather) | static_cast<std::uint32_t>(offset >> 32u) << 8u,
static_cast<std::uint32_t>(size - 1u), static_cast<std::uint32_t>(offset)};
return Append(buffer, &command, sizeof(command));
}

int APS5_VABI sceAmprAprCommandBufferReadFileGatherScatter(Apr::CommandBufferObject* buffer, std::uint64_t* mapState, std::uint64_t* scatterGatherState, void* destination, std::uint64_t size, std::uint64_t offset) {
Expand Down Expand Up @@ -357,7 +361,7 @@ int APS5_VABI sceAmprCommandBufferConstructNop(Apr::CommandBufferObject* buffer,
}

int APS5_VABI sceAmprCommandBufferConstructor(Apr::CommandBufferObject* buffer) {
*buffer = {nullptr, 0, 0, 0, Apr::BufferType::Generic};
*buffer = {Apr::BufferType::Generic, 0, 0, 0, 0, nullptr};
return 0;
}

Expand Down Expand Up @@ -520,7 +524,7 @@ uint32_t APS5_VABI sceAmprMeasureCommandSizeReadFile(void) {

std::uint64_t APS5_VABI sceAmprMeasureCommandSizeReadFileGather(std::uint64_t size, std::uint64_t offset) {
if (!ValidReadLength(size) || !ValidReadOffset(offset)) return MeasureInvalid;
return sizeof(Apr::ReadFileCommand);
return sizeof(Apr::CompactReadFileGatherCommand);
}

std::uint64_t APS5_VABI sceAmprMeasureCommandSizeReadFileGatherScatter(void* destination, std::uint64_t size, std::uint64_t offset) {
Expand Down
19 changes: 16 additions & 3 deletions core/libs/prx/libSceHttp/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@
#include "prx/libSceHttp/src/HttpErrors.hpp"
#include <atomic>
#include <limits>
#include <map>
#include <mutex>
#include <stdexcept>
#include <string_view>

// No network is emulated: contexts, templates and requests can be created, but any request
// that would touch the network fails with the library's network error.
static std::atomic<int> g_nextHandle{1};
using HttpRequestStatusCallback = void (APS5_VABI *)(int, int, void*);
struct RequestStatusRegistration {
HttpRequestStatusCallback callback;
void* argument;
};
static std::mutex g_statusMutex;
static std::map<int, RequestStatusRegistration> g_statusCallbacks;

extern "C" {

Expand Down Expand Up @@ -80,7 +89,8 @@ int APS5_VABI sceHttpDeleteConnection(int conn_id) {
}

int APS5_VABI sceHttpDeleteRequest(int req_id) {
(void)req_id;
std::lock_guard lock(g_statusMutex);
g_statusCallbacks.erase(req_id);
return 0;
}

Expand Down Expand Up @@ -273,8 +283,11 @@ int APS5_VABI sceHttpSetInflateGZIPEnabled(int id, int enable) {
return 0;
}

int APS5_VABI sceHttpSetRequestStatusCallback(void) {
NotImplemented_nid_no_patch(__func__);
int APS5_VABI sceHttpSetRequestStatusCallback(int id, HttpRequestStatusCallback callback, void* argument) {
if (id <= 0 || id >= g_nextHandle.load(std::memory_order_relaxed)) return static_cast<int>(0x80431100u);
std::lock_guard lock(g_statusMutex);
if (callback) g_statusCallbacks[id] = {callback, argument};
else g_statusCallbacks.erase(id);
return 0;
}

Expand Down
21 changes: 16 additions & 5 deletions core/libs/prx/libkernel/Apr/include/AprCommandBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <cstdint>

// Shared between libSceAmpr (which records commands) and libkernel (which executes them).
// The guest treats both the command buffer object and its memory as opaque, so the encoding is ours.
namespace Apr {

enum class BufferType : std::uint16_t {
Expand All @@ -14,15 +13,19 @@ enum class BufferType : std::uint16_t {
};

struct CommandBufferObject {
std::uint8_t* base;
std::uint32_t size;
std::uint32_t offset;
std::uint32_t numCommands;
BufferType type;
std::uint16_t recording;
std::uint32_t offset;
std::uint32_t numCommands;
std::uint32_t size;
std::uint8_t* base;
};
static_assert(sizeof(CommandBufferObject) == 0x18, "guest reserves 0x18 bytes for sce::Ampr::CommandBuffer");

static_assert(offsetof(CommandBufferObject, offset) == 0x04);
static_assert(offsetof(CommandBufferObject, size) == 0x0c);
static_assert(offsetof(CommandBufferObject, base) == 0x10);

inline constexpr std::uint16_t ScatterGatherValid = 1;
inline constexpr std::uint16_t MapActive = 2;

Expand Down Expand Up @@ -56,6 +59,7 @@ enum class Opcode : std::uint32_t {
AmmAllocatePaForPrt = 26,
AmmRemapIntoPrt = 27,
AmmUnmapToPrt = 28,
CompactReadFileGather = 29,
};

struct CommandHeader {
Expand All @@ -72,6 +76,13 @@ struct ReadFileCommand {
std::uint64_t offset;
};

struct CompactReadFileGatherCommand {
std::uint32_t opcodeAndOffsetHigh;
std::uint32_t sizeMinusOne;
std::uint32_t offsetLow;
};
static_assert(sizeof(CompactReadFileGatherCommand) == 12);

struct ResetGatherScatterStateCommand {
CommandHeader header;
};
Expand Down
24 changes: 21 additions & 3 deletions core/libs/prx/libkernel/Apr/src/Apr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <windows.h>
#endif

extern "C" int* APS5_VABI __error_nid_postfix();

namespace {

constexpr int GUEST_ENOENT = 2;
Expand Down Expand Up @@ -98,7 +100,7 @@ bool _fileSize(const std::filesystem::path& path, std::uint64_t& bytes) {
}

int _fail(int guestErrno) {
errno = guestErrno;
*__error_nid_postfix() = guestErrno;
return -1;
}

Expand Down Expand Up @@ -130,16 +132,18 @@ constexpr int SCE_KERNEL_ERROR_ENOENT = static_cast<int>(0x80020002);

int _resolveForEach(const char* prefix, const char** paths, uint32_t count, uint32_t* ids, uint64_t* sizes, int* results) {
if (!paths || !ids) return _fail(GUEST_EINVAL);
std::uint32_t resolvedCount = 0;
for (uint32_t index = 0; index < count; ++index) {
const std::string path = prefix ? (paths[index] ? std::string(prefix) + paths[index] : std::string()) : (paths[index] ? std::string(paths[index]) : std::string());
const bool resolved = !path.empty() && _resolve(path.c_str(), &ids[index], sizes ? &sizes[index] : nullptr);
if (!resolved) {
ids[index] = INVALID_FILE_ID;
if (sizes) sizes[index] = 0;
}
if (resolved) ++resolvedCount;
if (results) results[index] = resolved ? 0 : SCE_KERNEL_ERROR_ENOENT;
}
return 0;
return static_cast<int>(resolvedCount);
}

void _readFile(const Apr::ReadFileCommand& command) {
Expand Down Expand Up @@ -520,6 +524,15 @@ void _execute(const Apr::CommandBufferObject& buffer) {
if (cursor + sizeof(Apr::CommandHeader) > buffer.offset) throw std::runtime_error("APR: truncated command buffer");
Apr::CommandHeader header;
std::memcpy(&header, buffer.base + cursor, sizeof(header));
if ((static_cast<std::uint32_t>(header.opcode) & 0xffu) == static_cast<std::uint32_t>(Apr::Opcode::CompactReadFileGather)) {
if (sizeof(Apr::CompactReadFileGatherCommand) > buffer.offset - cursor) throw std::runtime_error("APR: truncated compact gather command");
const auto command = _read<Apr::CompactReadFileGatherCommand>(buffer, cursor);
const auto offset = static_cast<std::uint64_t>(command.opcodeAndOffsetHigh >> 8u) << 32u | command.offsetLow;
if (offset >= 0x10000000000ull) throw std::runtime_error("APR: malformed compact gather offset");
_readResolved(Apr::Opcode::ReadFileGather, Apr::ReadFileCommand{{}, 0, 0, 0, static_cast<std::uint64_t>(command.sizeMinusOne) + 1u, offset}, read);
cursor += sizeof(command);
continue;
}
if (header.bytes < sizeof(header) || cursor + header.bytes > buffer.offset) throw std::runtime_error("APR: malformed command");
switch (header.opcode) {
case Apr::Opcode::Nop:
Expand Down Expand Up @@ -640,7 +653,7 @@ void AmmVirtualAddressRanges_nid_no_patch(std::uint64_t* start, std::uint64_t* e
}

std::uint32_t AmmSubmit_nid_no_patch(void* base, std::uint32_t bytes) {
_execute(Apr::CommandBufferObject{static_cast<std::uint8_t*>(base), bytes, bytes, 0, Apr::BufferType::Generic, 0});
_execute(Apr::CommandBufferObject{Apr::BufferType::Generic, 0, bytes, 0, bytes, static_cast<std::uint8_t*>(base)});
auto& last = _amm().lastSubmit;
std::uint32_t id = last.fetch_add(1) + 1;
while (id == 0) id = last.fetch_add(1) + 1;
Expand All @@ -656,6 +669,7 @@ int APS5_VABI sceKernelAprResolveFilepathsToIds(const char** paths, uint32_t cou
if (!paths || !ids) return _fail(GUEST_EINVAL);
for (uint32_t index = 0; index < count; ++index) {
if (!_resolve(paths[index], &ids[index], nullptr)) {
ids[index] = INVALID_FILE_ID;
if (error_index) *error_index = index;
return _fail(GUEST_ENOENT);
}
Expand All @@ -667,6 +681,8 @@ int APS5_VABI sceKernelAprResolveFilepathsToIdsAndFileSizes(const char** paths,
if (!paths || !ids || !sizes) return _fail(GUEST_EINVAL);
for (uint32_t index = 0; index < count; ++index) {
if (!_resolve(paths[index], &ids[index], &sizes[index])) {
ids[index] = INVALID_FILE_ID;
if (sizes) sizes[index] = 0;
if (error_index) *error_index = index;
return _fail(GUEST_ENOENT);
}
Expand All @@ -679,6 +695,8 @@ int APS5_VABI sceKernelAprResolveFilepathsWithPrefixToIdsAndFileSizes(const char
for (uint32_t index = 0; index < count; ++index) {
const std::string path = paths[index] ? std::string(prefix) + paths[index] : std::string();
if (path.empty() || !_resolve(path.c_str(), &ids[index], sizes ? &sizes[index] : nullptr)) {
ids[index] = INVALID_FILE_ID;
if (sizes) sizes[index] = 0;
if (error_index) *error_index = index;
return _fail(GUEST_ENOENT);
}
Expand Down
27 changes: 15 additions & 12 deletions core/libs/prx/libkernel/File/src/Stdio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,9 @@ static int PathError(const char* path) {
extern "C" {

int APS5_VABI chmod_nid_postfix(const char* path, int mode) {
if (path == nullptr) {
APS5_INVALID_ARG_EX;
}
auto native = ResolvePath_nid_no_patch(path);
if (NativeChmod(native, mode) != 0) {
throw std::runtime_error(std::string(__func__) + ": chmod failed for " + native.string() + ", errno=" + std::to_string(errno));
}
if (const int error = PathError(path)) return PosixFailure(error);
const auto native = ResolvePath_nid_no_patch(path);
if (NativeChmod(native, mode & 07777) != 0) return PosixResult(SceErrorFromErrno(errno));
return 0;
}

Expand Down Expand Up @@ -664,7 +660,10 @@ int APS5_VABI rmdir_nid_postfix(const char* path) {
extern "C" {

int APS5_VABI sceKernelChmod_nid_postfix(const char* path, std::uint16_t mode) {
return chmod_nid_postfix(path, mode);
if (!path) return SceErrorFromErrno(GUEST_EFAULT);
const auto native = ResolvePath_nid_no_patch(path);
if (NativeChmod(native, mode & 07777) != 0) return SceErrorFromErrno(errno);
return 0;
}

int APS5_VABI sceKernelFchmod(int d, std::uint16_t mode) {
Expand Down Expand Up @@ -701,17 +700,21 @@ int APS5_VABI utimes_nid_postfix(const char* path, const KernelTimeval* times) {
return PosixResult(sceKernelUtimes_nid_postfix(path, times));
}

int APS5_VABI futimes_nid_postfix(int d, const KernelTimeval* times) {
if (d >= GuestSockets::FirstDescriptor) return PosixFailure(GuestSockets::IsOpen(d) ? GUEST_EINVAL : GUEST_EBADF);
int APS5_VABI sceKernelFutimes(int d, const KernelTimeval* times) {
if (d >= GuestSockets::FirstDescriptor) return SceErrorFromErrno(GuestSockets::IsOpen(d) ? GUEST_EINVAL : GUEST_EBADF);
if (times != nullptr) {
for (int i = 0; i < 2; ++i) {
if (times[i].tv_usec < 0 || times[i].tv_usec >= 1000000) return PosixFailure(GUEST_EINVAL);
if (times[i].tv_usec < 0 || times[i].tv_usec >= 1000000) return SceErrorFromErrno(GUEST_EINVAL);
}
}
if (NativeFutimes(d, times) != 0) return PosixResult(SceErrorFromErrno(errno));
if (NativeFutimes(d, times) != 0) return SceErrorFromErrno(errno);
return 0;
}

int APS5_VABI futimes_nid_postfix(int d, const KernelTimeval* times) {
return PosixResult(sceKernelFutimes(d, times));
}

int APS5_VABI fsync_nid_postfix(int fd) {
if (sceKernelFsync(fd) != 0) return PosixFailure(errno);
return 0;
Expand Down
4 changes: 3 additions & 1 deletion core/libs/prx/libkernel/Module/src/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ extern "C" {

int APS5_VABI sceKernelDlsym(KernelModule handle, const char* symbol, void** addr) {
if (!symbol || !addr) return SCE_KERNEL_ERROR_EFAULT;
void* found = dlsym_nid_postfix(reinterpret_cast<void*>(static_cast<intptr_t>(handle)), symbol);
void* module = handle == 0 ? dlopen_nid_postfix(nullptr, kRtldNow) : reinterpret_cast<void*>(static_cast<intptr_t>(handle));
void* found = dlsym_nid_postfix(module, symbol);
if (handle == 0 && module) dlclose_nid_postfix(module);
if (!found) return SCE_KERNEL_ERROR_ESRCH;
*addr = found;
return 0;
Expand Down
Loading
Loading