mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-06-07 02:05:00 -06:00
Merge remote-tracking branch 'upstream' into calculate-flex-memory-size
This commit is contained in:
commit
f459e8ba76
@ -70,7 +70,7 @@ public:
|
|||||||
~FileBackend() = default;
|
~FileBackend() = default;
|
||||||
|
|
||||||
void Write(const Entry& entry) {
|
void Write(const Entry& entry) {
|
||||||
if (!enabled) {
|
if (!enabled && entry.log_level != Level::Critical) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,28 +12,28 @@ void* PS4_SYSV_ABI AvPlayer::Allocate(void* handle, u32 alignment, u32 size) {
|
|||||||
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
||||||
const auto allocate = self->m_init_data_original.memory_replacement.allocate;
|
const auto allocate = self->m_init_data_original.memory_replacement.allocate;
|
||||||
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
||||||
return allocate(ptr, alignment, size);
|
return Core::ExecuteGuest(allocate, ptr, alignment, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS4_SYSV_ABI AvPlayer::Deallocate(void* handle, void* memory) {
|
void PS4_SYSV_ABI AvPlayer::Deallocate(void* handle, void* memory) {
|
||||||
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
||||||
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate;
|
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate;
|
||||||
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
||||||
return deallocate(ptr, memory);
|
return Core::ExecuteGuest(deallocate, ptr, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* PS4_SYSV_ABI AvPlayer::AllocateTexture(void* handle, u32 alignment, u32 size) {
|
void* PS4_SYSV_ABI AvPlayer::AllocateTexture(void* handle, u32 alignment, u32 size) {
|
||||||
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
||||||
const auto allocate = self->m_init_data_original.memory_replacement.allocate_texture;
|
const auto allocate = self->m_init_data_original.memory_replacement.allocate_texture;
|
||||||
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
||||||
return allocate(ptr, alignment, size);
|
return Core::ExecuteGuest(allocate, ptr, alignment, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS4_SYSV_ABI AvPlayer::DeallocateTexture(void* handle, void* memory) {
|
void PS4_SYSV_ABI AvPlayer::DeallocateTexture(void* handle, void* memory) {
|
||||||
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
const auto* const self = reinterpret_cast<AvPlayer*>(handle);
|
||||||
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate_texture;
|
const auto deallocate = self->m_init_data_original.memory_replacement.deallocate_texture;
|
||||||
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.memory_replacement.object_ptr;
|
||||||
return deallocate(ptr, memory);
|
return Core::ExecuteGuest(deallocate, ptr, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
|
int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
|
||||||
@ -42,7 +42,7 @@ int PS4_SYSV_ABI AvPlayer::OpenFile(void* handle, const char* filename) {
|
|||||||
|
|
||||||
const auto open = self->m_init_data_original.file_replacement.open;
|
const auto open = self->m_init_data_original.file_replacement.open;
|
||||||
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
||||||
return open(ptr, filename);
|
return Core::ExecuteGuest(open, ptr, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
|
int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
|
||||||
@ -51,7 +51,7 @@ int PS4_SYSV_ABI AvPlayer::CloseFile(void* handle) {
|
|||||||
|
|
||||||
const auto close = self->m_init_data_original.file_replacement.close;
|
const auto close = self->m_init_data_original.file_replacement.close;
|
||||||
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
||||||
return close(ptr);
|
return Core::ExecuteGuest(close, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length) {
|
int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position, u32 length) {
|
||||||
@ -60,7 +60,7 @@ int PS4_SYSV_ABI AvPlayer::ReadOffsetFile(void* handle, u8* buffer, u64 position
|
|||||||
|
|
||||||
const auto read_offset = self->m_init_data_original.file_replacement.read_offset;
|
const auto read_offset = self->m_init_data_original.file_replacement.read_offset;
|
||||||
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
||||||
return read_offset(ptr, buffer, position, length);
|
return Core::ExecuteGuest(read_offset, ptr, buffer, position, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
|
u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
|
||||||
@ -69,7 +69,7 @@ u64 PS4_SYSV_ABI AvPlayer::SizeFile(void* handle) {
|
|||||||
|
|
||||||
const auto size = self->m_init_data_original.file_replacement.size;
|
const auto size = self->m_init_data_original.file_replacement.size;
|
||||||
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
const auto ptr = self->m_init_data_original.file_replacement.object_ptr;
|
||||||
return size(ptr);
|
return Core::ExecuteGuest(size, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
AvPlayerInitData AvPlayer::StubInitData(const AvPlayerInitData& data) {
|
AvPlayerInitData AvPlayer::StubInitData(const AvPlayerInitData& data) {
|
||||||
|
|||||||
@ -92,7 +92,7 @@ void AvPlayerState::DefaultEventCallback(void* opaque, AvPlayerEvents event_id,
|
|||||||
const auto callback = self->m_event_replacement.event_callback;
|
const auto callback = self->m_event_replacement.event_callback;
|
||||||
const auto ptr = self->m_event_replacement.object_ptr;
|
const auto ptr = self->m_event_replacement.object_ptr;
|
||||||
if (callback != nullptr) {
|
if (callback != nullptr) {
|
||||||
callback(ptr, event_id, 0, event_data);
|
Core::ExecuteGuest(callback, ptr, event_id, 0, event_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -99,16 +99,16 @@ public:
|
|||||||
if (m_ime_mode) {
|
if (m_ime_mode) {
|
||||||
OrbisImeParam param = m_param.ime;
|
OrbisImeParam param = m_param.ime;
|
||||||
if (use_param_handler) {
|
if (use_param_handler) {
|
||||||
param.handler(param.arg, event);
|
Core::ExecuteGuest(param.handler, param.arg, event);
|
||||||
} else {
|
} else {
|
||||||
handler(param.arg, event);
|
Core::ExecuteGuest(handler, param.arg, event);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
OrbisImeKeyboardParam param = m_param.key;
|
OrbisImeKeyboardParam param = m_param.key;
|
||||||
if (use_param_handler) {
|
if (use_param_handler) {
|
||||||
param.handler(param.arg, event);
|
Core::ExecuteGuest(param.handler, param.arg, event);
|
||||||
} else {
|
} else {
|
||||||
handler(param.arg, event);
|
Core::ExecuteGuest(handler, param.arg, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -131,7 +131,8 @@ bool ImeDialogState::CallTextFilter() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = text_filter(out_text, &out_text_length, src_text, src_text_length);
|
int ret =
|
||||||
|
Core::ExecuteGuest(text_filter, out_text, &out_text_length, src_text, src_text_length);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -152,7 +153,7 @@ bool ImeDialogState::CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16*
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = keyboard_filter(src_keycode, out_keycode, out_status, nullptr);
|
int ret = Core::ExecuteGuest(keyboard_filter, src_keycode, out_keycode, out_status, nullptr);
|
||||||
return ret == 0;
|
return ret == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/kernel/equeue.h"
|
#include "core/libraries/kernel/equeue.h"
|
||||||
#include "core/libraries/kernel/orbis_error.h"
|
#include "core/libraries/kernel/orbis_error.h"
|
||||||
|
#include "core/libraries/kernel/time.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
@ -15,23 +16,39 @@ namespace Libraries::Kernel {
|
|||||||
extern boost::asio::io_context io_context;
|
extern boost::asio::io_context io_context;
|
||||||
extern void KernelSignalRequest();
|
extern void KernelSignalRequest();
|
||||||
|
|
||||||
static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
|
static constexpr auto HrTimerSpinlockThresholdNs = 1200000u;
|
||||||
|
|
||||||
// Events are uniquely identified by id and filter.
|
// Events are uniquely identified by id and filter.
|
||||||
|
|
||||||
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
|
// Calculate timer interval
|
||||||
event.time_added = std::chrono::steady_clock::now();
|
event.time_added = std::chrono::steady_clock::now();
|
||||||
if (event.event.filter == SceKernelEvent::Filter::Timer ||
|
if (event.event.filter == SceKernelEvent::Filter::Timer ||
|
||||||
event.event.filter == SceKernelEvent::Filter::HrTimer) {
|
event.event.filter == SceKernelEvent::Filter::HrTimer) {
|
||||||
// HrTimer events are offset by the threshold of time at the end that we spinlock for
|
// Set timer interval
|
||||||
// greater accuracy.
|
event.timer_interval = std::chrono::nanoseconds(event.event.data);
|
||||||
const auto offset =
|
|
||||||
event.event.filter == SceKernelEvent::Filter::HrTimer ? HrTimerSpinlockThresholdUs : 0u;
|
|
||||||
event.timer_interval = std::chrono::microseconds(event.event.data - offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, check if there's already an event with the same id and filter.
|
||||||
|
u64 id = event.event.ident;
|
||||||
|
SceKernelEvent::Filter filter = event.event.filter;
|
||||||
|
const auto& find_it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||||
|
return ev.event.ident == id && ev.event.filter == filter;
|
||||||
|
});
|
||||||
|
// If there is a duplicate event, we need to update that instead.
|
||||||
|
if (find_it != m_events.cend()) {
|
||||||
|
// Specifically, update user data and timer_interval.
|
||||||
|
// Trigger status and event data should remain intact.
|
||||||
|
auto& old_event = *find_it;
|
||||||
|
old_event.timer_interval = event.timer_interval;
|
||||||
|
old_event.event.udata = event.event.udata;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear input data from event.
|
||||||
|
event.event.data = 0;
|
||||||
|
|
||||||
// Remove add flag from event
|
// Remove add flag from event
|
||||||
event.event.flags &= ~SceKernelEvent::Flags::Add;
|
event.event.flags &= ~SceKernelEvent::Flags::Add;
|
||||||
|
|
||||||
@ -157,6 +174,9 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|||||||
event.TriggerDisplay(trigger_data);
|
event.TriggerDisplay(trigger_data);
|
||||||
} else if (filter == SceKernelEvent::Filter::User) {
|
} else if (filter == SceKernelEvent::Filter::User) {
|
||||||
event.TriggerUser(trigger_data);
|
event.TriggerUser(trigger_data);
|
||||||
|
} else if (filter == SceKernelEvent::Filter::Timer ||
|
||||||
|
filter == SceKernelEvent::Filter::HrTimer) {
|
||||||
|
event.TriggerTimer();
|
||||||
} else {
|
} else {
|
||||||
event.Trigger(trigger_data);
|
event.Trigger(trigger_data);
|
||||||
}
|
}
|
||||||
@ -197,7 +217,7 @@ bool EqueueInternal::AddSmallTimer(EqueueEvent& ev) {
|
|||||||
SmallTimer st;
|
SmallTimer st;
|
||||||
st.event = ev.event;
|
st.event = ev.event;
|
||||||
st.added = std::chrono::steady_clock::now();
|
st.added = std::chrono::steady_clock::now();
|
||||||
st.interval = std::chrono::microseconds{ev.event.data};
|
st.interval = std::chrono::nanoseconds{ev.event.data};
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
m_small_timers[st.event.ident] = std::move(st);
|
m_small_timers[st.event.ident] = std::move(st);
|
||||||
@ -307,30 +327,23 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void HrTimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
static void HrTimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
||||||
static EqueueEvent event;
|
|
||||||
event.event = kevent;
|
|
||||||
event.event.data = HrTimerSpinlockThresholdUs;
|
|
||||||
eq->AddSmallTimer(event);
|
|
||||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
|
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, OrbisKernelTimespec* ts,
|
||||||
|
void* udata) {
|
||||||
if (eq == nullptr) {
|
if (eq == nullptr) {
|
||||||
return ORBIS_KERNEL_ERROR_EBADF;
|
return ORBIS_KERNEL_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts->tv_sec > 100 || ts->tv_nsec < 100'000) {
|
const auto total_ns = ts->tv_sec * 1000000000 + ts->tv_nsec;
|
||||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
|
||||||
}
|
|
||||||
ASSERT(ts->tv_nsec > 1000); // assume 1us resolution
|
|
||||||
const auto total_us = ts->tv_sec * 1000'000 + ts->tv_nsec / 1000;
|
|
||||||
|
|
||||||
EqueueEvent event{};
|
EqueueEvent event{};
|
||||||
event.event.ident = id;
|
event.event.ident = id;
|
||||||
event.event.filter = SceKernelEvent::Filter::HrTimer;
|
event.event.filter = SceKernelEvent::Filter::HrTimer;
|
||||||
event.event.flags = SceKernelEvent::Flags::Add | SceKernelEvent::Flags::OneShot;
|
event.event.flags = SceKernelEvent::Flags::Add | SceKernelEvent::Flags::OneShot;
|
||||||
event.event.fflags = 0;
|
event.event.fflags = 0;
|
||||||
event.event.data = total_us;
|
event.event.data = total_ns;
|
||||||
event.event.udata = udata;
|
event.event.udata = udata;
|
||||||
|
|
||||||
// HR timers cannot be implemented within the existing event queue architecture due to the
|
// HR timers cannot be implemented within the existing event queue architecture due to the
|
||||||
@ -340,12 +353,7 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec*
|
|||||||
// `HrTimerSpinlockThresholdUs`) and fall back to boost asio timers if the time to tick is
|
// `HrTimerSpinlockThresholdUs`) and fall back to boost asio timers if the time to tick is
|
||||||
// large. Even for large delays, we truncate a small portion to complete the wait
|
// large. Even for large delays, we truncate a small portion to complete the wait
|
||||||
// using the spinlock, prioritizing precision.
|
// using the spinlock, prioritizing precision.
|
||||||
|
if (total_ns < HrTimerSpinlockThresholdNs) {
|
||||||
if (eq->EventExists(event.event.ident, event.event.filter)) {
|
|
||||||
eq->RemoveEvent(id, SceKernelEvent::Filter::HrTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total_us < HrTimerSpinlockThresholdUs) {
|
|
||||||
return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM;
|
return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,16 +399,9 @@ int PS4_SYSV_ABI sceKernelAddTimerEvent(SceKernelEqueue eq, int id, SceKernelUse
|
|||||||
event.event.filter = SceKernelEvent::Filter::Timer;
|
event.event.filter = SceKernelEvent::Filter::Timer;
|
||||||
event.event.flags = SceKernelEvent::Flags::Add;
|
event.event.flags = SceKernelEvent::Flags::Add;
|
||||||
event.event.fflags = 0;
|
event.event.fflags = 0;
|
||||||
event.event.data = usec;
|
event.event.data = usec * 1000;
|
||||||
event.event.udata = udata;
|
event.event.udata = udata;
|
||||||
|
|
||||||
if (eq->EventExists(event.event.ident, event.event.filter)) {
|
|
||||||
eq->RemoveEvent(id, SceKernelEvent::Filter::Timer);
|
|
||||||
LOG_DEBUG(Kernel_Event,
|
|
||||||
"Timer event already exists, removing it: queue name={}, queue id={}",
|
|
||||||
eq->GetName(), event.event.ident);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG(Kernel_Event, "Added timing event: queue name={}, queue id={}, usec={}, pointer={:x}",
|
LOG_DEBUG(Kernel_Event, "Added timing event: queue name={}, queue id={}, usec={}, pointer={:x}",
|
||||||
eq->GetName(), event.event.ident, usec, reinterpret_cast<uintptr_t>(udata));
|
eq->GetName(), event.event.ident, usec, reinterpret_cast<uintptr_t>(udata));
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,7 @@ struct EqueueEvent {
|
|||||||
SceKernelEvent event;
|
SceKernelEvent event;
|
||||||
void* data = nullptr;
|
void* data = nullptr;
|
||||||
std::chrono::steady_clock::time_point time_added;
|
std::chrono::steady_clock::time_point time_added;
|
||||||
std::chrono::microseconds timer_interval;
|
std::chrono::nanoseconds timer_interval;
|
||||||
std::unique_ptr<boost::asio::steady_timer> timer;
|
std::unique_ptr<boost::asio::steady_timer> timer;
|
||||||
|
|
||||||
void Clear() {
|
void Clear() {
|
||||||
@ -92,7 +92,6 @@ struct EqueueEvent {
|
|||||||
|
|
||||||
void Trigger(void* data) {
|
void Trigger(void* data) {
|
||||||
is_triggered = true;
|
is_triggered = true;
|
||||||
event.fflags++;
|
|
||||||
event.data = reinterpret_cast<uintptr_t>(data);
|
event.data = reinterpret_cast<uintptr_t>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +100,11 @@ struct EqueueEvent {
|
|||||||
event.udata = data;
|
event.udata = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TriggerTimer() {
|
||||||
|
is_triggered = true;
|
||||||
|
event.data++;
|
||||||
|
}
|
||||||
|
|
||||||
void TriggerDisplay(void* data) {
|
void TriggerDisplay(void* data) {
|
||||||
is_triggered = true;
|
is_triggered = true;
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
@ -135,7 +139,7 @@ class EqueueInternal {
|
|||||||
struct SmallTimer {
|
struct SmallTimer {
|
||||||
SceKernelEvent event;
|
SceKernelEvent event;
|
||||||
std::chrono::steady_clock::time_point added;
|
std::chrono::steady_clock::time_point added;
|
||||||
std::chrono::microseconds interval;
|
std::chrono::nanoseconds interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -194,21 +194,6 @@ int PS4_SYSV_ABI posix_pthread_detach(PthreadT pthread) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __clang__
|
|
||||||
__attribute__((optnone))
|
|
||||||
#else
|
|
||||||
__attribute__((optimize("O0")))
|
|
||||||
#endif
|
|
||||||
void ClearStack(const PthreadAttr& attr) {
|
|
||||||
void* sp;
|
|
||||||
asm("mov %%rsp, %0" : "=rm"(sp));
|
|
||||||
// leave a safety net of 128 bytes for memset
|
|
||||||
const u64 size = (u64)sp - (u64)attr.stackaddr_attr - 128;
|
|
||||||
volatile void* buf = alloca(size);
|
|
||||||
memset(const_cast<void*>(buf), 0, size);
|
|
||||||
buf = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RunThread(void* arg) {
|
static void RunThread(void* arg) {
|
||||||
auto* curthread = static_cast<Pthread*>(arg);
|
auto* curthread = static_cast<Pthread*>(arg);
|
||||||
g_curthread = curthread;
|
g_curthread = curthread;
|
||||||
@ -217,12 +202,7 @@ static void RunThread(void* arg) {
|
|||||||
|
|
||||||
/* Run the current thread's start routine with argument: */
|
/* Run the current thread's start routine with argument: */
|
||||||
curthread->native_thr.Initialize();
|
curthread->native_thr.Initialize();
|
||||||
Core::EnsureThreadInitialized();
|
void* ret = Core::ExecuteGuest(curthread->start_routine, curthread->arg);
|
||||||
|
|
||||||
// Clear the stack before running the guest thread
|
|
||||||
ClearStack(curthread->attr);
|
|
||||||
|
|
||||||
void* ret = curthread->start_routine(curthread->arg);
|
|
||||||
|
|
||||||
/* Remove thread from tracking */
|
/* Remove thread from tracking */
|
||||||
DebugState.RemoveCurrentThreadFromGuestList();
|
DebugState.RemoveCurrentThreadFromGuestList();
|
||||||
|
|||||||
@ -84,7 +84,7 @@ void _thread_cleanupspecific() {
|
|||||||
* destructor:
|
* destructor:
|
||||||
*/
|
*/
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
destructor(data);
|
Core::ExecuteGuest(destructor, data);
|
||||||
lk.lock();
|
lk.lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,7 +50,7 @@ void NetCtlInternal::CheckCallback() {
|
|||||||
: ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED;
|
: ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED;
|
||||||
for (const auto [func, arg] : callbacks) {
|
for (const auto [func, arg] : callbacks) {
|
||||||
if (func != nullptr) {
|
if (func != nullptr) {
|
||||||
func(event, arg);
|
Core::ExecuteGuest(func, event, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ void NetCtlInternal::CheckNpToolkitCallback() {
|
|||||||
: ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED;
|
: ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED;
|
||||||
for (const auto [func, arg] : nptool_callbacks) {
|
for (const auto [func, arg] : nptool_callbacks) {
|
||||||
if (func != nullptr) {
|
if (func != nullptr) {
|
||||||
func(event, arg);
|
Core::ExecuteGuest(func, event, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -160,13 +160,13 @@ s32 PS4_SYSV_ABI sceNgs2SystemCreateWithAllocator(const OrbisNgs2SystemOption* o
|
|||||||
result = SystemSetup(option, &bufferInfo, 0, 0);
|
result = SystemSetup(option, &bufferInfo, 0, 0);
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
uintptr_t sysUserData = allocator->userData;
|
uintptr_t sysUserData = allocator->userData;
|
||||||
result = hostAlloc(&bufferInfo);
|
result = Core::ExecuteGuest(hostAlloc, &bufferInfo);
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
OrbisNgs2Handle* handleCopy = outHandle;
|
OrbisNgs2Handle* handleCopy = outHandle;
|
||||||
result = SystemSetup(option, &bufferInfo, hostFree, handleCopy);
|
result = SystemSetup(option, &bufferInfo, hostFree, handleCopy);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
if (hostFree) {
|
if (hostFree) {
|
||||||
hostFree(&bufferInfo);
|
Core::ExecuteGuest(hostFree, &bufferInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#include "dimensions.h"
|
#include "dimensions.h"
|
||||||
|
|
||||||
#include "core/tls.h"
|
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@ -624,8 +622,6 @@ libusb_transfer_status DimensionsBackend::HandleAsyncTransfer(libusb_transfer* t
|
|||||||
s32 DimensionsBackend::SubmitTransfer(libusb_transfer* transfer) {
|
s32 DimensionsBackend::SubmitTransfer(libusb_transfer* transfer) {
|
||||||
if (transfer->endpoint == 0x01) {
|
if (transfer->endpoint == 0x01) {
|
||||||
std::thread write_thread([this, transfer] {
|
std::thread write_thread([this, transfer] {
|
||||||
Core::EnsureThreadInitialized();
|
|
||||||
|
|
||||||
HandleAsyncTransfer(transfer);
|
HandleAsyncTransfer(transfer);
|
||||||
|
|
||||||
const u8 flags = transfer->flags;
|
const u8 flags = transfer->flags;
|
||||||
|
|||||||
@ -315,20 +315,25 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
|||||||
{
|
{
|
||||||
// Needs lock here as can be concurrently read by `sceVideoOutGetVblankStatus`
|
// Needs lock here as can be concurrently read by `sceVideoOutGetVblankStatus`
|
||||||
std::scoped_lock lock{main_port.vo_mutex};
|
std::scoped_lock lock{main_port.vo_mutex};
|
||||||
|
|
||||||
|
// Trigger flip events for the port
|
||||||
|
for (auto& event : main_port.vblank_events) {
|
||||||
|
if (event != nullptr) {
|
||||||
|
event->TriggerEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
||||||
|
Kernel::SceKernelEvent::Filter::VideoOut,
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
static_cast<u64>(OrbisVideoOutInternalEventId::Vblank) |
|
||||||
|
(vblank_status.count << 16)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update vblank status
|
||||||
vblank_status.count++;
|
vblank_status.count++;
|
||||||
vblank_status.process_time = Libraries::Kernel::sceKernelGetProcessTime();
|
vblank_status.process_time = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
||||||
main_port.vblank_cv.notify_all();
|
main_port.vblank_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger flip events for the port.
|
|
||||||
for (auto& event : main_port.vblank_events) {
|
|
||||||
if (event != nullptr) {
|
|
||||||
event->TriggerEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
|
||||||
Kernel::SceKernelEvent::Filter::VideoOut, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.End();
|
timer.End();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -135,8 +135,7 @@ void Linker::Execute(const std::vector<std::string>& args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
params.entry_addr = module->GetEntryAddress();
|
params.entry_addr = module->GetEntryAddress();
|
||||||
Core::EnsureThreadInitialized();
|
ExecuteGuest(RunMainEntry, ¶ms);
|
||||||
RunMainEntry(¶ms);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +379,8 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
|
|||||||
if (!addr) {
|
if (!addr) {
|
||||||
// Module was just loaded by above code. Allocate TLS block for it.
|
// Module was just loaded by above code. Allocate TLS block for it.
|
||||||
const u32 init_image_size = module->tls.init_image_size;
|
const u32 init_image_size = module->tls.init_image_size;
|
||||||
u8* dest = reinterpret_cast<u8*>(heap_api->heap_malloc(module->tls.image_size));
|
u8* dest = reinterpret_cast<u8*>(
|
||||||
|
Core::ExecuteGuest(heap_api->heap_malloc, module->tls.image_size));
|
||||||
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
|
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
|
||||||
std::memcpy(dest, src, init_image_size);
|
std::memcpy(dest, src, init_image_size);
|
||||||
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);
|
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);
|
||||||
@ -412,7 +412,7 @@ void* Linker::AllocateTlsForThread(bool is_primary) {
|
|||||||
ASSERT_MSG(ret == 0, "Unable to allocate TLS+TCB for the primary thread");
|
ASSERT_MSG(ret == 0, "Unable to allocate TLS+TCB for the primary thread");
|
||||||
} else {
|
} else {
|
||||||
if (heap_api) {
|
if (heap_api) {
|
||||||
addr_out = heap_api->heap_malloc(total_tls_size);
|
addr_out = Core::ExecuteGuest(heap_api->heap_malloc, total_tls_size);
|
||||||
} else {
|
} else {
|
||||||
addr_out = std::malloc(total_tls_size);
|
addr_out = std::malloc(total_tls_size);
|
||||||
}
|
}
|
||||||
@ -422,7 +422,7 @@ void* Linker::AllocateTlsForThread(bool is_primary) {
|
|||||||
|
|
||||||
void Linker::FreeTlsForNonPrimaryThread(void* pointer) {
|
void Linker::FreeTlsForNonPrimaryThread(void* pointer) {
|
||||||
if (heap_api) {
|
if (heap_api) {
|
||||||
heap_api->heap_free(pointer);
|
Core::ExecuteGuest(heap_api->heap_free, pointer);
|
||||||
} else {
|
} else {
|
||||||
std::free(pointer);
|
std::free(pointer);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,8 +97,7 @@ Module::~Module() = default;
|
|||||||
s32 Module::Start(u64 args, const void* argp, void* param) {
|
s32 Module::Start(u64 args, const void* argp, void* param) {
|
||||||
LOG_INFO(Core_Linker, "Module started : {}", name);
|
LOG_INFO(Core_Linker, "Module started : {}", name);
|
||||||
const VAddr addr = dynamic_info.init_virtual_addr + GetBaseAddress();
|
const VAddr addr = dynamic_info.init_virtual_addr + GetBaseAddress();
|
||||||
Core::EnsureThreadInitialized();
|
return ExecuteGuest(reinterpret_cast<EntryFunc>(addr), args, argp, param);
|
||||||
return reinterpret_cast<EntryFunc>(addr)(args, argp, param);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::LoadModuleToMemory(u32& max_tls_index) {
|
void Module::LoadModuleToMemory(u32& max_tls_index) {
|
||||||
|
|||||||
@ -45,6 +45,29 @@ Tcb* GetTcbBase();
|
|||||||
/// Makes sure TLS is initialized for the thread before entering guest.
|
/// Makes sure TLS is initialized for the thread before entering guest.
|
||||||
void EnsureThreadInitialized();
|
void EnsureThreadInitialized();
|
||||||
|
|
||||||
|
template <size_t size>
|
||||||
|
#ifdef __clang__
|
||||||
|
__attribute__((optnone))
|
||||||
|
#else
|
||||||
|
__attribute__((optimize("O0")))
|
||||||
|
#endif
|
||||||
|
void ClearStack() {
|
||||||
|
volatile void* buf = alloca(size);
|
||||||
|
memset(const_cast<void*>(buf), 0, size);
|
||||||
|
buf = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ReturnType, class... FuncArgs, class... CallArgs>
|
||||||
|
ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) {
|
||||||
|
EnsureThreadInitialized();
|
||||||
|
// clear stack to avoid trash from EnsureThreadInitialized
|
||||||
|
auto* tcb = GetTcbBase();
|
||||||
|
if (tcb != nullptr && tcb->tcb_fiber == nullptr) {
|
||||||
|
ClearStack<12_KB>();
|
||||||
|
}
|
||||||
|
return func(std::forward<CallArgs>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
template <class F, F f>
|
template <class F, F f>
|
||||||
struct HostCallWrapperImpl;
|
struct HostCallWrapperImpl;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user