Compare commits

...

16 Commits

Author SHA1 Message Date
psucien 42f6ab7670 amdgpu: added ASC commands processor 2024-06-21 20:40:16 +02:00
psucien b8290ea521 amdgpu: indirect buffer, release mem and some additional irq modes 2024-06-21 20:37:30 +02:00
psucien 966ff741d1 kernel: file_system: gmoralis's dirents implementation 2024-06-20 21:45:58 +02:00
georgemoralis 022e0c2fbb misc hle functions 2024-06-18 18:45:14 +03:00
georgemoralis 8760abd6b5 added missing NIDS ,scePthreadAttrSetstackaddr,scePthreadAttrSetguardsize 2024-06-18 16:01:09 +03:00
psucien 48fdf0d9e9 libraries: trophy: a better stubs implementation 2024-06-18 15:04:05 +02:00
psucien f375e0cfb0 common: slot_vector: added `IsAllocated` to check if a slot already exists 2024-06-18 15:02:01 +02:00
psucien 723e3cd0f9 common: `Common` namespace for the slot vector container 2024-06-18 14:05:11 +02:00
georgemoralis 6f69b32555 sceAudioOutGetPortState added 2024-06-18 14:28:09 +03:00
psucien e92d636018 gnm_driver: correct vqid index range 2024-06-18 10:15:04 +02:00
psucien 53dd407ae3 kernel: event_queue: initial `sceKernelAddHRTimerEvent` added 2024-06-18 10:10:27 +02:00
psucien a5d22b8151 kernel: event_queue: check for filter match when triggering an event 2024-06-18 10:02:28 +02:00
psucien b23d17696b kernel: event_queue: trace wait added 2024-06-18 09:47:02 +02:00
psucien fe30369349 kernel: event_queue: slight event class refactoring 2024-06-18 09:22:51 +02:00
psucien 76c92a9dfb video_out: `sceVideoOutGetDeviceCapabilityInfo` for sdk runtime 2024-06-17 22:17:31 +02:00
psucien 307560a3fd gnm_driver: added `sceGnmRegisterOwner` and `sceGnmRegisterResource` 2024-06-17 21:33:10 +02:00
32 changed files with 546 additions and 77 deletions

View File

@ -145,4 +145,13 @@ bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) {
return true; return true;
} }
bool SDLAudio::AudioOutGetStatus(s32 handle, int* type, int* channels_num) {
std::scoped_lock lock{m_mutex};
auto& port = portsOut[handle - 1];
*type = port.type;
*channels_num = port.channels_num;
return true;
}
} // namespace Audio } // namespace Audio

View File

@ -18,6 +18,7 @@ public:
Libraries::AudioOut::OrbisAudioOutParam format); Libraries::AudioOut::OrbisAudioOutParam format);
s32 AudioOutOutput(s32 handle, const void* ptr); s32 AudioOutOutput(s32 handle, const void* ptr);
bool AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume); bool AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume);
bool AudioOutGetStatus(s32 handle, int* type, int* channels_num);
private: private:
struct PortOut { struct PortOut {

View File

@ -41,6 +41,8 @@ enum MarkersPallete : int {
#define RENDERER_TRACE ZoneScopedC(RendererMarkerColor) #define RENDERER_TRACE ZoneScopedC(RendererMarkerColor)
#define HLE_TRACE ZoneScopedC(HleMarkerColor) #define HLE_TRACE ZoneScopedC(HleMarkerColor)
#define TRACE_HINT(str) ZoneText(str.c_str(), str.size())
#define TRACE_WARN(msg) \ #define TRACE_WARN(msg) \
[](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg); [](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg);
#define TRACE_ERROR(msg) \ #define TRACE_ERROR(msg) \

View File

@ -12,7 +12,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/types.h" #include "common/types.h"
namespace VideoCore { namespace Common {
struct SlotId { struct SlotId {
static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max(); static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max();
@ -54,6 +54,13 @@ public:
return values[id.index].object; return values[id.index].object;
} }
bool IsAllocated(SlotId id) const {
if (id && id.index / 64 < stored_bitset.size()) {
return ((stored_bitset[id.index / 64] >> (id.index % 64)) & 1) != 0;
}
return false;
}
template <typename... Args> template <typename... Args>
[[nodiscard]] SlotId insert(Args&&... args) noexcept { [[nodiscard]] SlotId insert(Args&&... args) noexcept {
const u32 index = FreeValueIndex(); const u32 index = FreeValueIndex();
@ -162,11 +169,11 @@ private:
std::vector<u32> free_list; std::vector<u32> free_list;
}; };
} // namespace VideoCore } // namespace Common
template <> template <>
struct std::hash<VideoCore::SlotId> { struct std::hash<Common::SlotId> {
std::size_t operator()(const VideoCore::SlotId& id) const noexcept { std::size_t operator()(const Common::SlotId& id) const noexcept {
return std::hash<u32>{}(id.index); return std::hash<u32>{}(id.index);
} }
}; };

View File

@ -28,15 +28,13 @@ void MntPoints::UnmountAll() {
std::string MntPoints::GetHostDirectory(const std::string& guest_directory) { std::string MntPoints::GetHostDirectory(const std::string& guest_directory) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
for (auto& pair : m_mnt_pairs) { for (auto& pair : m_mnt_pairs) {
if (pair.guest_path.starts_with(guest_directory)) { // horrible code but it works :D
return pair.host_path + guest_directory; int find = guest_directory.find(pair.guest_path);
} if (find == 0) {
} std::string npath =
// hack for relative path , get app0 and assuming it goes from there guest_directory.substr(pair.guest_path.size(), guest_directory.size() - 1);
for (auto& pair : m_mnt_pairs) {
if (pair.guest_path.starts_with("/app0")) {
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/'); std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
return pair.host_path + guest_directory; return pair.host_path + npath;
} }
} }
return ""; return "";

View File

@ -32,13 +32,18 @@ private:
std::mutex m_mutex; std::mutex m_mutex;
}; };
struct DirEntry {
std::string name;
bool isFile;
};
struct File { struct File {
std::atomic_bool is_opened{}; std::atomic_bool is_opened{};
std::atomic_bool is_directory{}; std::atomic_bool is_directory{};
std::string m_host_name; std::string m_host_name;
std::string m_guest_name; std::string m_guest_name;
Common::FS::IOFile f; Common::FS::IOFile f;
// std::vector<Common::FS::DirEntry> dirents; std::vector<DirEntry> dirents;
u32 dirents_index; u32 dirents_index;
std::mutex m_mutex; std::mutex m_mutex;
}; };

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <memory> #include <memory>
#include <common/assert.h>
#include <magic_enum.hpp> #include <magic_enum.hpp>
#include "audio_core/sdl_audio.h" #include "audio_core/sdl_audio.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@ -160,8 +161,38 @@ int PS4_SYSV_ABI sceAudioOutGetLastOutputTime() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioOutGetPortState() { int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state) {
LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
int type = 0;
int channels_num = 0;
if (!audio->AudioOutGetStatus(handle, &type, &channels_num)) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
state->rerouteCounter = 0;
state->volume = 127; // max volume
switch (type) {
case ORBIS_AUDIO_OUT_PORT_TYPE_MAIN:
case ORBIS_AUDIO_OUT_PORT_TYPE_BGM:
case ORBIS_AUDIO_OUT_PORT_TYPE_VOICE:
state->output = 1;
state->channel = (channels_num > 2 ? 2 : channels_num);
break;
case ORBIS_AUDIO_OUT_PORT_TYPE_PERSONAL:
case ORBIS_AUDIO_OUT_PORT_TYPE_PADSPK:
state->output = 4;
state->channel = 1;
break;
case ORBIS_AUDIO_OUT_PORT_TYPE_AUX:
state->output = 0;
state->channel = 0;
break;
default:
UNREACHABLE();
}
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -34,6 +34,16 @@ struct OrbisAudioOutOutputParam {
const void* ptr; const void* ptr;
}; };
struct OrbisAudioOutPortState {
u16 output;
u8 channel;
u8 reserved8_1[1];
s16 volume;
u16 rerouteCounter;
u64 flag;
u64 reserved64[2];
};
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen(); int PS4_SYSV_ABI sceAudioOutDeviceIdOpen();
int PS4_SYSV_ABI sceAudioDeviceControlGet(); int PS4_SYSV_ABI sceAudioDeviceControlGet();
int PS4_SYSV_ABI sceAudioDeviceControlSet(); int PS4_SYSV_ABI sceAudioDeviceControlSet();
@ -55,7 +65,7 @@ int PS4_SYSV_ABI sceAudioOutGetHandleStatusInfo();
int PS4_SYSV_ABI sceAudioOutGetInfo(); int PS4_SYSV_ABI sceAudioOutGetInfo();
int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum(); int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum();
int PS4_SYSV_ABI sceAudioOutGetLastOutputTime(); int PS4_SYSV_ABI sceAudioOutGetLastOutputTime();
int PS4_SYSV_ABI sceAudioOutGetPortState(); int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state);
int PS4_SYSV_ABI sceAudioOutGetSimulatedBusUsableStatusByBusType(); int PS4_SYSV_ABI sceAudioOutGetSimulatedBusUsableStatusByBusType();
int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo(); int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo();
int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo2(); int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo2();

View File

@ -252,6 +252,7 @@ constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_QUEUE_ID = 0x80D17001;
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_BASE_ADDR = 0x80D17003; constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_BASE_ADDR = 0x80D17003;
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_SIZE = 0x80D17002; constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_SIZE = 0x80D17002;
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_READ_PTR_ADDR = 0x80D17004; constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_READ_PTR_ADDR = 0x80D17004;
constexpr int ORBIS_GNM_ERROR_FAILURE = 0x8EEE00FF;
// Generic // Generic
constexpr int ORBIS_OK = 0x00000000; constexpr int ORBIS_OK = 0x00000000;
@ -445,3 +446,10 @@ constexpr int ORBIS_USER_SERVICE_ERROR_BUFFER_TOO_SHORT = 0x8096000A;
// SystemService library // SystemService library
constexpr int ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER = 0x80A10003; constexpr int ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER = 0x80A10003;
// NpTrophy library
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT = 0x80551604;
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE = 0x80551608;
constexpr int ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX = 0x80551624;
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_ALREADY_EXISTS = 0x80551613;
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_EXCEEDS_MAX = 0x80551622;

View File

@ -38,7 +38,7 @@ struct AscQueueInfo {
u32* read_addr; u32* read_addr;
u32 ring_size_dw; u32 ring_size_dw;
}; };
static VideoCore::SlotVector<AscQueueInfo> asc_queues{}; static Common::SlotVector<AscQueueInfo> asc_queues{};
static constexpr VAddr tessellation_factors_ring_addr = 0xFF0000000ULL; static constexpr VAddr tessellation_factors_ring_addr = 0xFF0000000ULL;
static void DumpCommandList(std::span<const u32> cmd_list, const std::string& postfix) { static void DumpCommandList(std::span<const u32> cmd_list, const std::string& postfix) {
@ -764,10 +764,12 @@ int PS4_SYSV_ABI sceGnmMapComputeQueue(u32 pipe_id, u32 queue_id, VAddr ring_bas
} }
auto vqid = asc_queues.insert(VAddr(ring_base_addr), read_ptr_addr, ring_size_dw); auto vqid = asc_queues.insert(VAddr(ring_base_addr), read_ptr_addr, ring_size_dw);
// We need to offset index as `dingDong` assumes it to be from the range [1..64]
const auto gnm_vqid = vqid.index + 1;
LOG_INFO(Lib_GnmDriver, "ASC pipe {} queue {} mapped to vqueue {}", pipe_id, queue_id, LOG_INFO(Lib_GnmDriver, "ASC pipe {} queue {} mapped to vqueue {}", pipe_id, queue_id,
vqid.index); gnm_vqid);
return vqid.index; return gnm_vqid;
} }
int PS4_SYSV_ABI sceGnmMapComputeQueueWithPriority(u32 pipe_id, u32 queue_id, VAddr ring_base_addr, int PS4_SYSV_ABI sceGnmMapComputeQueueWithPriority(u32 pipe_id, u32 queue_id, VAddr ring_base_addr,
@ -814,14 +816,16 @@ int PS4_SYSV_ABI sceGnmRegisterGnmLiveCallbackConfig() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceGnmRegisterOwner() { s32 PS4_SYSV_ABI sceGnmRegisterOwner(void* handle, const char* name) {
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); LOG_TRACE(Lib_GnmDriver, "called");
return ORBIS_OK; return ORBIS_GNM_ERROR_FAILURE; // PA Debug is always disabled in retail FW
} }
int PS4_SYSV_ABI sceGnmRegisterResource() { s32 PS4_SYSV_ABI sceGnmRegisterResource(void* res_handle, void* owner_handle, const void* addr,
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); size_t size, const char* name, int res_type,
return ORBIS_OK; u64 user_data) {
LOG_TRACE(Lib_GnmDriver, "called");
return ORBIS_GNM_ERROR_FAILURE; // PA Debug is always disabled in retail FW
} }
int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDone() { int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDone() {

View File

@ -125,8 +125,9 @@ int PS4_SYSV_ABI sceGnmQueryResourceRegistrationUserMemoryRequirements();
int PS4_SYSV_ABI sceGnmRaiseUserExceptionEvent(); int PS4_SYSV_ABI sceGnmRaiseUserExceptionEvent();
int PS4_SYSV_ABI sceGnmRegisterGdsResource(); int PS4_SYSV_ABI sceGnmRegisterGdsResource();
int PS4_SYSV_ABI sceGnmRegisterGnmLiveCallbackConfig(); int PS4_SYSV_ABI sceGnmRegisterGnmLiveCallbackConfig();
int PS4_SYSV_ABI sceGnmRegisterOwner(); s32 PS4_SYSV_ABI sceGnmRegisterOwner(void* handle, const char* name);
int PS4_SYSV_ABI sceGnmRegisterResource(); s32 PS4_SYSV_ABI sceGnmRegisterResource(void* res_handle, void* owner_handle, const void* addr,
size_t size, const char* name, int res_type, u64 user_data);
int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDone(); int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDone();
int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDoneForWorkload(); int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDoneForWorkload();
int PS4_SYSV_ABI sceGnmRequestMipStatsReportAndReset(); int PS4_SYSV_ABI sceGnmRequestMipStatsReportAndReset();

View File

@ -8,13 +8,19 @@ namespace Libraries::Kernel {
EqueueInternal::~EqueueInternal() = default; EqueueInternal::~EqueueInternal() = default;
int EqueueInternal::addEvent(const EqueueEvent& event) { int EqueueInternal::addEvent(EqueueEvent& event) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
ASSERT(!event.isTriggered); const auto start_clock = std::chrono::high_resolution_clock::now();
event.filter.added_time_us =
std::chrono::time_point_cast<std::chrono::microseconds>(start_clock);
// TODO check if event is already exists and return it. Currently we just add in m_events array const auto& it = std::ranges::find(m_events, event);
if (it != m_events.cend()) {
*it = event;
} else {
m_events.push_back(event); m_events.push_back(event);
}
return 0; return 0;
} }
@ -50,8 +56,8 @@ bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
for (auto& event : m_events) { for (auto& event : m_events) {
if (event.event.ident == ident) { // event filter? if (event.event.ident == ident && event.event.filter == filter) {
event.trigger(trigger_data); event.Trigger(trigger_data);
} }
} }
} }
@ -64,9 +70,9 @@ int EqueueInternal::getTriggeredEvents(SceKernelEvent* ev, int num) {
int ret = 0; int ret = 0;
for (auto& event : m_events) { for (auto& event : m_events) {
if (event.isTriggered) { if (event.IsTriggered()) {
ev[ret++] = event.event; ev[ret++] = event.event;
event.reset(); event.Reset();
} }
} }

View File

@ -70,24 +70,44 @@ struct SceKernelEvent {
struct Filter { struct Filter {
void* data = nullptr; void* data = nullptr;
std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds> added_time_us;
}; };
struct EqueueEvent { struct EqueueEvent {
bool isTriggered = false;
SceKernelEvent event; SceKernelEvent event;
Filter filter; Filter filter;
void reset() { void Reset() {
isTriggered = false; is_triggered = false;
event.fflags = 0; event.fflags = 0;
event.data = 0; event.data = 0;
} }
void trigger(void* data) { void Trigger(void* data) {
isTriggered = true; is_triggered = true;
event.fflags++; event.fflags++;
event.data = reinterpret_cast<uintptr_t>(data); event.data = reinterpret_cast<uintptr_t>(data);
} }
bool IsTriggered() const {
if (event.filter == Kernel::EVFILT_HRTIMER) {
// For HR timers we don't want to waste time on spawning waiters. Instead, we will check
// for time out condition every time caller fetches the event status.
const auto now_clock = std::chrono::high_resolution_clock::now();
const auto now_time_us =
std::chrono::time_point_cast<std::chrono::microseconds>(now_clock);
const auto delta = (now_time_us - filter.added_time_us).count();
return (s64(event.data) - delta) <= 0;
}
return is_triggered;
}
bool operator==(const EqueueEvent& ev) const {
return ev.event.ident == event.ident;
}
private:
bool is_triggered = false;
}; };
class EqueueInternal { class EqueueInternal {
@ -97,7 +117,10 @@ public:
void setName(const std::string& m_name) { void setName(const std::string& m_name) {
this->m_name = m_name; this->m_name = m_name;
} }
int addEvent(const EqueueEvent& event); const auto& GetName() const {
return m_name;
}
int addEvent(EqueueEvent& event);
int removeEvent(u64 id); int removeEvent(u64 id);
int waitForEvents(SceKernelEvent* ev, int num, u32 micros); int waitForEvents(SceKernelEvent* ev, int num, u32 micros);
bool triggerEvent(u64 ident, s16 filter, void* trigger_data); bool triggerEvent(u64 ident, s16 filter, void* trigger_data);

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h" #include "common/assert.h"
#include "common/debug.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/kernel/event_queues.h" #include "core/libraries/kernel/event_queues.h"
@ -43,7 +44,9 @@ int PS4_SYSV_ABI sceKernelDeleteEqueue(SceKernelEqueue eq) {
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out, int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out,
SceKernelUseconds* timo) { SceKernelUseconds* timo) {
LOG_INFO(Kernel_Event, "num = {}", num); HLE_TRACE;
TRACE_HINT(eq->GetName());
LOG_INFO(Kernel_Event, "equeue = {} num = {}", eq->GetName(), num);
if (eq == nullptr) { if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF; return ORBIS_KERNEL_ERROR_EBADF;
@ -84,7 +87,6 @@ int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
} }
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.isTriggered = false;
event.event.ident = id; event.event.ident = id;
event.event.filter = Kernel::EVFILT_USER; event.event.filter = Kernel::EVFILT_USER;
event.event.udata = 0; event.event.udata = 0;
@ -101,7 +103,6 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) {
} }
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.isTriggered = false;
event.event.ident = id; event.event.ident = id;
event.event.filter = Kernel::EVFILT_USER; event.event.filter = Kernel::EVFILT_USER;
event.event.udata = 0; event.event.udata = 0;
@ -112,6 +113,28 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) {
return eq->addEvent(event); return eq->addEvent(event);
} }
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
}
if (ts->tv_sec > 100 || ts->tv_nsec < 100'000) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
ASSERT(ts->tv_nsec > 1000); // assume 1us granularity
const auto total_us = ts->tv_sec * 1000'000 + ts->tv_nsec / 1000;
Kernel::EqueueEvent event{};
event.event.ident = id;
event.event.filter = Kernel::EVFILT_HRTIMER;
event.event.flags = 0x11;
event.event.fflags = 0;
event.event.data = total_us;
event.event.udata = udata;
return eq->addEvent(event);
}
void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev) { void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev) {
if (!ev) { if (!ev) {
return nullptr; return nullptr;

View File

@ -19,5 +19,6 @@ int PS4_SYSV_ABI sceKernelTriggerUserEvent(SceKernelEqueue eq, int id, void* uda
int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id); int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id);
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id); int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id);
int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id); int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id);
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata);
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -11,6 +11,27 @@
namespace Libraries::Kernel { namespace Libraries::Kernel {
std::vector<Core::FileSys::DirEntry> GetDirectoryEntries(const std::string& path) {
std::string curpath = path;
if (!curpath.ends_with("/")) {
curpath = std::string(curpath + "/");
}
std::vector<Core::FileSys::DirEntry> files;
for (const auto& entry : std::filesystem::directory_iterator(curpath)) {
Core::FileSys::DirEntry e = {};
if (std::filesystem::is_directory(entry.path().string())) {
e.name = entry.path().filename().string();
e.isFile = false;
} else {
e.name = entry.path().filename().string();
e.isFile = true;
}
files.push_back(e);
}
return files;
}
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", path, flags, mode); LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", path, flags, mode);
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
@ -32,14 +53,25 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0; bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
if (std::string_view{path} == "/dev/console" || std::string_view{path} == "/dev/deci_tty6") { if (std::string_view{path} == "/dev/console" || std::string_view{path} == "/dev/deci_tty6") {
return ORBIS_OK; return 2000;//return a high handler // TODO fix me
} }
if (directory) {
LOG_ERROR(Kernel_Fs, "called on directory");
} else {
u32 handle = h->CreateHandle(); u32 handle = h->CreateHandle();
auto* file = h->GetFile(handle); auto* file = h->GetFile(handle);
if (directory) {
file->is_directory = true;
file->m_guest_name = path;
file->m_host_name = mnt->GetHostDirectory(file->m_guest_name);
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
UNREACHABLE(); // not supported yet
} else {
if (create) {
return handle; // dir already exists
} else {
file->dirents = GetDirectoryEntries(file->m_host_name);
file->dirents_index = 0;
}
}
} else {
file->m_guest_name = path; file->m_guest_name = path;
file->m_host_name = mnt->GetHostFile(file->m_guest_name); file->m_host_name = mnt->GetHostFile(file->m_guest_name);
if (read) { if (read) {
@ -61,14 +93,13 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
h->DeleteHandle(handle); h->DeleteHandle(handle);
return SCE_KERNEL_ERROR_EACCES; return SCE_KERNEL_ERROR_EACCES;
} }
}
file->is_opened = true; file->is_opened = true;
return handle; return handle;
}
return -1; // dummy
} }
int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) { int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) {
LOG_INFO(Kernel_Fs, "posix open redirect to sceKernelOpen\n"); LOG_INFO(Kernel_Fs, "posix open redirect to sceKernelOpen");
int result = sceKernelOpen(path, flags, mode); int result = sceKernelOpen(path, flags, mode);
// Posix calls different only for their return values // Posix calls different only for their return values
ASSERT(result >= 0); ASSERT(result >= 0);
@ -310,6 +341,43 @@ s32 PS4_SYSV_ABI sceKernelFsync(int fd) {
return ORBIS_OK; return ORBIS_OK;
} }
int GetDents(int fd, char* buf, int nbytes, s64* basep) {
// TODO error codes
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(fd);
if (file->dirents_index == file->dirents.size()) {
return 0;
}
const auto& entry = file->dirents.at(file->dirents_index++);
auto str = entry.name;
auto str_size = str.size() - 1;
static int fileno = 1000; // random
OrbisKernelDirent* sce_ent = (OrbisKernelDirent*)buf;
sce_ent->d_fileno = fileno++; // TODO this should be unique but atm it changes maybe switch to a
// hash or something?
sce_ent->d_reclen = sizeof(OrbisKernelDirent);
sce_ent->d_type = (entry.isFile ? 8 : 4);
sce_ent->d_namlen = str_size;
strncpy(sce_ent->d_name, str.c_str(), ORBIS_MAX_PATH);
sce_ent->d_name[ORBIS_MAX_PATH] = '\0';
if (basep != nullptr) {
*basep = file->dirents_index;
}
return sizeof(OrbisKernelDirent);
}
int PS4_SYSV_ABI sceKernelGetdents(int fd, char* buf, int nbytes) {
return GetDents(fd, buf, nbytes, nullptr);
}
int PS4_SYSV_ABI sceKernelGetdirentries(int fd, char* buf, int nbytes, s64* basep) {
return GetDents(fd, buf, nbytes, basep);
}
void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) { void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen); LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen);
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open); LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open);
@ -333,6 +401,8 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread); LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread);
LIB_FUNCTION("uWyW3v98sU4", "libkernel", 1, "libkernel", 1, 1, sceKernelCheckReachability); LIB_FUNCTION("uWyW3v98sU4", "libkernel", 1, "libkernel", 1, 1, sceKernelCheckReachability);
LIB_FUNCTION("fTx66l5iWIA", "libkernel", 1, "libkernel", 1, 1, sceKernelFsync); LIB_FUNCTION("fTx66l5iWIA", "libkernel", 1, "libkernel", 1, 1, sceKernelFsync);
LIB_FUNCTION("j2AIqSqJP0w", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdents);
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
// openOrbis (to check if it is valid out of OpenOrbis // openOrbis (to check if it is valid out of OpenOrbis
LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1, LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1,

View File

@ -12,6 +12,8 @@ class SymbolsResolver;
namespace Libraries::Kernel { namespace Libraries::Kernel {
constexpr int ORBIS_MAX_PATH = 255;
struct SceKernelIovec { struct SceKernelIovec {
void* iov_base; void* iov_base;
std::size_t iov_len; std::size_t iov_len;
@ -39,6 +41,14 @@ struct OrbisKernelStat {
unsigned int : (8 / 2) * (16 - static_cast<int>(sizeof(OrbisKernelTimespec))); unsigned int : (8 / 2) * (16 - static_cast<int>(sizeof(OrbisKernelTimespec)));
}; };
struct OrbisKernelDirent {
u32 d_fileno; /* file number of entry */
u16 d_reclen; /* length of this record */
u8 d_type; /* file type, see below */
u8 d_namlen; /* length of string in d_name */
char d_name[ORBIS_MAX_PATH + 1]; /* name must be no longer than this */
};
// flags for Open // flags for Open
constexpr int ORBIS_KERNEL_O_RDONLY = 0x0000; constexpr int ORBIS_KERNEL_O_RDONLY = 0x0000;
constexpr int ORBIS_KERNEL_O_WRONLY = 0x0001; constexpr int ORBIS_KERNEL_O_WRONLY = 0x0001;

View File

@ -88,7 +88,7 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd,
void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) { void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) {
void* ptr; void* ptr;
LOG_INFO(Kernel_Vmm, "posix mmap redirect to sceKernelMmap\n"); LOG_INFO(Kernel_Vmm, "posix mmap redirect to sceKernelMmap");
// posix call the difference is that there is a different behaviour when it doesn't return 0 or // posix call the difference is that there is a different behaviour when it doesn't return 0 or
// SCE_OK // SCE_OK
const VAddr ret_addr = (VAddr)__builtin_return_address(0); const VAddr ret_addr = (VAddr)__builtin_return_address(0);
@ -288,9 +288,21 @@ int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
return 0; return 0;
} }
char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() {
char* path = "sys";
return path;
}
int PS4_SYSV_ABI connect() {
return -1;
}
void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
// obj // obj
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord);
LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, connect);
// memory // memory
LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException); LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException);
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory); LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory);
@ -308,6 +320,8 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", 1, 1, sceKernelMunmap); LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", 1, 1, sceKernelMunmap);
LIB_FUNCTION("mL8NDH86iQI", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedFlexibleMemory); LIB_FUNCTION("mL8NDH86iQI", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedFlexibleMemory);
LIB_FUNCTION("IWIBBdTHit4", "libkernel", 1, "libkernel", 1, 1, sceKernelMapFlexibleMemory); LIB_FUNCTION("IWIBBdTHit4", "libkernel", 1, "libkernel", 1, 1, sceKernelMapFlexibleMemory);
LIB_FUNCTION("aNz11fnnzi4", "libkernel", 1, "libkernel", 1, 1,
sceKernelAvailableFlexibleMemorySize);
LIB_FUNCTION("p5EcQeEeJAE", "libkernel", 1, "libkernel", 1, 1, LIB_FUNCTION("p5EcQeEeJAE", "libkernel", 1, "libkernel", 1, 1,
_sceKernelRtldSetApplicationHeapAPI); _sceKernelRtldSetApplicationHeapAPI);
LIB_FUNCTION("wzvqT4UqKX8", "libkernel", 1, "libkernel", 1, 1, sceKernelLoadStartModule); LIB_FUNCTION("wzvqT4UqKX8", "libkernel", 1, "libkernel", 1, 1, sceKernelLoadStartModule);
@ -324,6 +338,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData); LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData);
LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent); LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent);
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge); LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent); LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent); LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);

View File

@ -173,6 +173,12 @@ int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInf
return memory->DirectMemoryQuery(offset, flags == 1, query_info); return memory->DirectMemoryQuery(offset, flags == 1, query_info);
} }
s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut) {
auto* memory = Core::Memory::Instance();
*sizeOut = 448_MB - memory->GetTotalFlexibleUsage();
return ORBIS_OK;
}
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func) { void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func) {
auto* linker = Common::Singleton<Core::Linker>::Instance(); auto* linker = Common::Singleton<Core::Linker>::Instance();
linker->SetHeapApiFunc(func); linker->SetHeapApiFunc(func);

View File

@ -78,6 +78,7 @@ int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void**
int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info, int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info,
size_t infoSize); size_t infoSize);
s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut);
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func); void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func);
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -1312,6 +1312,9 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Ru36fiTtJzA", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstackaddr); LIB_FUNCTION("Ru36fiTtJzA", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstackaddr);
LIB_FUNCTION("-fA+7ZlGDQs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstacksize); LIB_FUNCTION("-fA+7ZlGDQs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstacksize);
LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, scePthreadOnce); LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, scePthreadOnce);
LIB_FUNCTION("F+yfmduIBB8", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetstackaddr);
LIB_FUNCTION("El+cQ20DynU", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetguardsize);
// mutex calls // mutex calls
LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexInit); LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexInit);

View File

@ -2,14 +2,34 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// Generated By moduleGenerator // Generated By moduleGenerator
#include <unordered_map>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/slot_vector.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "np_trophy.h" #include "np_trophy.h"
namespace Libraries::NpTrophy { namespace Libraries::NpTrophy {
int PS4_SYSV_ABI sceNpTrophyAbortHandle() { static constexpr auto MaxTrophyHandles = 4u;
static constexpr auto MaxTrophyContexts = 8u;
using ContextKey = std::pair<u32, u32>; // <user_id, service label>
struct ContextKeyHash {
size_t operator()(const ContextKey& key) const {
return key.first + (u64(key.second) << 32u);
}
};
struct TrophyContext {
u32 context_id;
};
static Common::SlotVector<u32> trophy_handles{};
static Common::SlotVector<ContextKey> trophy_contexts{};
static std::unordered_map<ContextKey, TrophyContext, ContextKeyHash> contexts_internal{};
static int PS4_SYSV_ABI sceNpTrophyAbortHandle() {
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
@ -64,14 +84,43 @@ int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyCreateContext() { s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label,
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); u64 options) {
ASSERT(options == 0ull);
if (!context) {
return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
}
if (trophy_contexts.size() >= MaxTrophyContexts) {
return ORBIS_NP_TROPHY_ERROR_CONTEXT_EXCEEDS_MAX;
}
const auto& key = ContextKey{service_label, user_id};
if (contexts_internal.contains(key)) {
return ORBIS_NP_TROPHY_ERROR_CONTEXT_ALREADY_EXISTS;
}
const auto ctx_id = trophy_contexts.insert(user_id, service_label);
contexts_internal[key].context_id = ctx_id.index;
LOG_INFO(Lib_NpTrophy, "New context = {}, service label = {} user_id = {}", ctx_id.index,
service_label, user_id);
*context = ctx_id.index;
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyCreateHandle() { s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle) {
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); if (!handle) {
return -1; return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
}
if (trophy_handles.size() >= MaxTrophyHandles) {
return ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX;
}
const auto handle_id = trophy_handles.insert();
LOG_INFO(Lib_NpTrophy, "New handle = {}", handle_id.index);
*handle = handle_id.index;
return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyDestroyContext() { int PS4_SYSV_ABI sceNpTrophyDestroyContext() {
@ -79,8 +128,13 @@ int PS4_SYSV_ABI sceNpTrophyDestroyContext() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyDestroyHandle() { s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle) {
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); if (!trophy_handles.IsAllocated({handle})) {
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
}
trophy_handles.erase({handle});
LOG_INFO(Lib_NpTrophy, "Handle {} destroyed", handle);
return ORBIS_OK; return ORBIS_OK;
} }
@ -114,8 +168,10 @@ int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState() { s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, u32* flags, u32* count) {
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
*flags = 0u;
*count = 0;
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -22,17 +22,18 @@ int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetInfoInGroup();
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetVersion(); int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetVersion();
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyTitleDetails(); int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyTitleDetails();
int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature(); int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature();
int PS4_SYSV_ABI sceNpTrophyCreateContext(); s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label,
int PS4_SYSV_ABI sceNpTrophyCreateHandle(); u64 options);
s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle);
int PS4_SYSV_ABI sceNpTrophyDestroyContext(); int PS4_SYSV_ABI sceNpTrophyDestroyContext();
int PS4_SYSV_ABI sceNpTrophyDestroyHandle(); s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle);
int PS4_SYSV_ABI sceNpTrophyGetGameIcon(); int PS4_SYSV_ABI sceNpTrophyGetGameIcon();
int PS4_SYSV_ABI sceNpTrophyGetGameInfo(); int PS4_SYSV_ABI sceNpTrophyGetGameInfo();
int PS4_SYSV_ABI sceNpTrophyGetGroupIcon(); int PS4_SYSV_ABI sceNpTrophyGetGroupIcon();
int PS4_SYSV_ABI sceNpTrophyGetGroupInfo(); int PS4_SYSV_ABI sceNpTrophyGetGroupInfo();
int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon(); int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon();
int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(); int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo();
int PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(); s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, u32* flags, u32* count);
int PS4_SYSV_ABI sceNpTrophyGroupArrayGetNum(); int PS4_SYSV_ABI sceNpTrophyGroupArrayGetNum();
int PS4_SYSV_ABI sceNpTrophyIntAbortHandle(); int PS4_SYSV_ABI sceNpTrophyIntAbortHandle();
int PS4_SYSV_ABI sceNpTrophyIntCheckNetSyncTitles(); int PS4_SYSV_ABI sceNpTrophyIntCheckNetSyncTitles();

View File

@ -48,7 +48,6 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
} }
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.isTriggered = false;
event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP; event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP;
event.event.filter = Kernel::EVFILT_VIDEO_OUT; event.event.filter = Kernel::EVFILT_VIDEO_OUT;
event.event.udata = udata; event.event.udata = udata;
@ -73,7 +72,6 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
} }
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.isTriggered = false;
event.event.ident = SCE_VIDEO_OUT_EVENT_VBLANK; event.event.ident = SCE_VIDEO_OUT_EVENT_VBLANK;
event.event.filter = Kernel::EVFILT_VIDEO_OUT; event.event.filter = Kernel::EVFILT_VIDEO_OUT;
event.event.udata = udata; event.event.udata = udata;
@ -288,6 +286,8 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("uquVH4-Du78", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutClose); LIB_FUNCTION("uquVH4-Du78", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutClose);
LIB_FUNCTION("1FZBKy8HeNU", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, LIB_FUNCTION("1FZBKy8HeNU", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
sceVideoOutGetVblankStatus); sceVideoOutGetVblankStatus);
LIB_FUNCTION("kGVLc3htQE8", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
sceVideoOutGetDeviceCapabilityInfo);
// openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1 // openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen); LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen);

View File

@ -124,6 +124,10 @@ public:
instance = instance_; instance = instance_;
} }
size_t GetTotalFlexibleUsage() const noexcept {
return total_flexible_usage;
}
PAddr Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment, PAddr Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment,
int memory_type); int memory_type);

View File

@ -139,7 +139,7 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file) {
const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir); const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
for (const auto& entry : std::filesystem::directory_iterator(sys_module_path)) { for (const auto& entry : std::filesystem::directory_iterator(sys_module_path)) {
if (entry.path().filename() == "libSceNgs2.sprx" || if (entry.path().filename() == "libSceNgs2.sprx" ||
entry.path().filename() == "libSceLibcInternal.sprx") { entry.path().filename() == "libSceLibcInternal.sprx" || entry.path().filename() == "libSceDiscMap.sprx") {
LOG_INFO(Loader, "Loading {}", entry.path().string().c_str()); LOG_INFO(Loader, "Loading {}", entry.path().string().c_str());
linker->LoadModule(entry.path()); linker->LoadModule(entry.path());
} }

View File

@ -12,7 +12,7 @@ namespace AmdGpu {
static const char* dcb_task_name{"DCB_TASK"}; static const char* dcb_task_name{"DCB_TASK"};
static const char* ccb_task_name{"CCB_TASK"}; static const char* ccb_task_name{"CCB_TASK"};
static const char* asc_task_name{"ACB_TASK"}; static const char* acb_task_name{"ACB_TASK"};
std::array<u8, 48_KB> Liverpool::ConstantEngine::constants_heap; std::array<u8, 48_KB> Liverpool::ConstantEngine::constants_heap;
@ -381,6 +381,8 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
} }
Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb) { Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb) {
TracyFiberEnter(acb_task_name);
while (!acb.empty()) { while (!acb.empty()) {
const auto* header = reinterpret_cast<const PM4Header*>(acb.data()); const auto* header = reinterpret_cast<const PM4Header*>(acb.data());
const u32 type = header->type; const u32 type = header->type;
@ -393,6 +395,69 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb) {
const PM4ItOpcode opcode = header->type3.opcode; const PM4ItOpcode opcode = header->type3.opcode;
const auto* it_body = reinterpret_cast<const u32*>(header) + 1; const auto* it_body = reinterpret_cast<const u32*>(header) + 1;
switch (opcode) { switch (opcode) {
case PM4ItOpcode::Nop: {
const auto* nop = reinterpret_cast<const PM4CmdNop*>(header);
break;
}
case PM4ItOpcode::IndirectBuffer: {
const auto* indirect_buffer = reinterpret_cast<const PM4CmdIndirectBuffer*>(header);
auto task =
ProcessCompute({indirect_buffer->Address<const u32>(), indirect_buffer->ib_size});
while (!task.handle.done()) {
task.handle.resume();
TracyFiberLeave;
co_yield {};
TracyFiberEnter(acb_task_name);
};
break;
}
case PM4ItOpcode::AcquireMem: {
break;
}
case PM4ItOpcode::SetShReg: {
const auto* set_data = reinterpret_cast<const PM4CmdSetData*>(header);
std::memcpy(&regs.reg_array[ShRegWordOffset + set_data->reg_offset], header + 2,
(count - 1) * sizeof(u32));
break;
}
case PM4ItOpcode::DispatchDirect: {
const auto* dispatch_direct = reinterpret_cast<const PM4CmdDispatchDirect*>(header);
regs.cs_program.dim_x = dispatch_direct->dim_x;
regs.cs_program.dim_y = dispatch_direct->dim_y;
regs.cs_program.dim_z = dispatch_direct->dim_z;
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
rasterizer->DispatchDirect();
}
break;
}
case PM4ItOpcode::WriteData: {
const auto* write_data = reinterpret_cast<const PM4CmdWriteData*>(header);
ASSERT(write_data->dst_sel.Value() == 2 || write_data->dst_sel.Value() == 5);
const u32 data_size = (header->type3.count.Value() - 2) * 4;
if (!write_data->wr_one_addr.Value()) {
std::memcpy(write_data->Address<void*>(), write_data->data, data_size);
} else {
UNREACHABLE();
}
break;
}
case PM4ItOpcode::WaitRegMem: {
const auto* wait_reg_mem = reinterpret_cast<const PM4CmdWaitRegMem*>(header);
ASSERT(wait_reg_mem->engine.Value() == PM4CmdWaitRegMem::Engine::Me);
while (!wait_reg_mem->Test()) {
TracyFiberLeave;
co_yield {};
TracyFiberEnter(acb_task_name);
}
break;
}
case PM4ItOpcode::ReleaseMem: {
const auto* release_mem = reinterpret_cast<const PM4CmdReleaseMem*>(header);
release_mem->SignalFence(Platform::InterruptId::Compute0RelMem); // <---
break;
}
default: default:
UNREACHABLE_MSG("Unknown PM4 type 3 opcode {:#x} with count {}", UNREACHABLE_MSG("Unknown PM4 type 3 opcode {:#x} with count {}",
static_cast<u32>(opcode), count); static_cast<u32>(opcode), count);
@ -401,7 +466,7 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb) {
acb = acb.subspan(header->type3.NumWords() + 1); acb = acb.subspan(header->type3.NumWords() + 1);
} }
return {}; // Not a coroutine yet TracyFiberLeave;
} }
void Liverpool::SubmitGfx(std::span<const u32> dcb, std::span<const u32> ccb) { void Liverpool::SubmitGfx(std::span<const u32> dcb, std::span<const u32> ccb) {

View File

@ -265,6 +265,7 @@ enum class InterruptSelect : u32 {
None = 0, None = 0,
IrqOnly = 1, IrqOnly = 1,
IrqWhenWriteConfirm = 2, IrqWhenWriteConfirm = 2,
IrqUndocumented = 3,
}; };
struct PM4CmdEventWriteEop { struct PM4CmdEventWriteEop {
@ -299,6 +300,9 @@ struct PM4CmdEventWriteEop {
void SignalFence() const { void SignalFence() const {
switch (data_sel.Value()) { switch (data_sel.Value()) {
case DataSelect::None: {
break;
}
case DataSelect::Data32Low: { case DataSelect::Data32Low: {
*Address<u32>() = DataDWord(); *Address<u32>() = DataDWord();
break; break;
@ -321,6 +325,9 @@ struct PM4CmdEventWriteEop {
// No interrupt // No interrupt
break; break;
} }
case InterruptSelect::IrqOnly:
ASSERT(data_sel == DataSelect::None);
[[fallthrough]];
case InterruptSelect::IrqWhenWriteConfirm: { case InterruptSelect::IrqWhenWriteConfirm: {
Platform::IrqC::Instance()->Signal(Platform::InterruptId::GfxEop); Platform::IrqC::Instance()->Signal(Platform::InterruptId::GfxEop);
break; break;
@ -559,4 +566,105 @@ struct PM4CmdDrawIndexBase {
u32 addr_hi; u32 addr_hi;
}; };
struct PM4CmdIndirectBuffer {
PM4Type3Header header;
u32 ibase_lo; ///< Indirect buffer base address, must be 4 byte aligned
union {
BitField<0, 16, u32> ibase_hi; ///< Indirect buffer base address
u32 dw1;
};
union {
BitField<0, 20, u32> ib_size; ///< Indirect buffer size
BitField<20, 1, u32> chain; ///< set to chain to IB allocations
BitField<24, 8, u32> vmid; ///< Virtual memory domain ID for command buffer
u32 dw2;
};
template <typename T>
T* Address() const {
return reinterpret_cast<T*>((u64(ibase_hi) << 32u) | ibase_lo);
}
};
struct PM4CmdReleaseMem {
PM4Type3Header header;
union {
BitField<0, 6, u32> event_type; ///< Event type written to VGT_EVENT_INITIATOR
BitField<8, 4, u32> event_index; ///< Event index
BitField<12, 1, u32> tcl1_vol_action_ena;
BitField<13, 1, u32> tc_vol_action_ena;
BitField<15, 1, u32> tc_wb_action_ena;
BitField<16, 1, u32> tcl1__action_ena;
BitField<17, 1, u32> tc_action_ena;
BitField<25, 2, u32> cache_policy; ///< Cache Policy setting used for writing fences and
///< timestamps to the TCL2
u32 dw1;
};
union {
BitField<16, 2, u32> dst_sel; ///< destination select
BitField<24, 3, InterruptSelect> int_sel; ///< selects interrupt action for end-of-pipe
BitField<29, 3, DataSelect> data_sel; ///< selects source of data
u32 dw2;
};
u32 address_lo; ///< low bits of address
u32 address_hi; ///< high bits of address
union {
struct {
u16 gds_index; ///< Byte offset into GDS to copy from
u16 num_dw; ///< Number of DWORDS of GDS to copy
};
u32 data_lo; ///< value that will be written to memory when event occurs
};
u32 data_hi;
template <typename T>
T* Address() const {
return reinterpret_cast<T*>(address_lo | u64(address_hi) << 32);
}
u32 DataDWord() const {
return data_lo;
}
u64 DataQWord() const {
return data_lo | u64(data_hi) << 32;
}
void SignalFence(Platform::InterruptId irq_id) const {
switch (data_sel.Value()) {
case DataSelect::Data32Low: {
*Address<u32>() = DataDWord();
break;
}
case DataSelect::Data64: {
*Address<u64>() = DataQWord();
break;
}
case DataSelect::PerfCounter: {
*Address<u64>() = Common::FencedRDTSC();
break;
}
default: {
UNREACHABLE();
}
}
switch (int_sel.Value()) {
case InterruptSelect::None: {
// No interrupt
break;
}
case InterruptSelect::IrqUndocumented:
[[fallthrough]];
case InterruptSelect::IrqWhenWriteConfirm: {
Platform::IrqC::Instance()->Signal(irq_id);
break;
}
default: {
UNREACHABLE();
}
}
}
};
} // namespace AmdGpu } // namespace AmdGpu

View File

@ -46,6 +46,7 @@ enum class PM4ItOpcode : u32 {
EventWrite = 0x46, EventWrite = 0x46,
EventWriteEop = 0x47, EventWriteEop = 0x47,
EventWriteEos = 0x48, EventWriteEos = 0x48,
ReleaseMem = 0x49,
PremableCntl = 0x4A, PremableCntl = 0x4A,
DmaData = 0x50, DmaData = 0x50,
ContextRegRmw = 0x51, ContextRegRmw = 0x51,

View File

@ -90,7 +90,7 @@ private:
vk::Image image{}; vk::Image image{};
}; };
constexpr SlotId NULL_IMAGE_ID{0}; constexpr Common::SlotId NULL_IMAGE_ID{0};
struct Image { struct Image {
explicit Image(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, explicit Image(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,

View File

@ -140,8 +140,8 @@ private:
Vulkan::Scheduler& scheduler; Vulkan::Scheduler& scheduler;
Vulkan::StreamBuffer staging; Vulkan::StreamBuffer staging;
TileManager tile_manager; TileManager tile_manager;
SlotVector<Image> slot_images; Common::SlotVector<Image> slot_images;
SlotVector<ImageView> slot_image_views; Common::SlotVector<ImageView> slot_image_views;
tsl::robin_map<u64, Sampler> samplers; tsl::robin_map<u64, Sampler> samplers;
tsl::robin_pg_map<u64, std::vector<ImageId>> page_table; tsl::robin_pg_map<u64, std::vector<ImageId>> page_table;
boost::icl::interval_map<VAddr, s32> cached_pages; boost::icl::interval_map<VAddr, s32> cached_pages;

View File

@ -8,8 +8,8 @@
namespace VideoCore { namespace VideoCore {
using ImageId = SlotId; using ImageId = Common::SlotId;
using ImageViewId = SlotId; using ImageViewId = Common::SlotId;
struct Offset2D { struct Offset2D {
s32 x; s32 x;