|
|
@@ -10,14 +10,15 @@
|
|
|
|
|
|
#include "common/alignment.h"
|
|
|
#include "common/assert.h"
|
|
|
+#include "common/fiber.h"
|
|
|
#include "common/logging/log.h"
|
|
|
#include "common/microprofile.h"
|
|
|
#include "common/string_util.h"
|
|
|
#include "core/arm/exclusive_monitor.h"
|
|
|
#include "core/core.h"
|
|
|
-#include "core/core_manager.h"
|
|
|
#include "core/core_timing.h"
|
|
|
#include "core/core_timing_util.h"
|
|
|
+#include "core/cpu_manager.h"
|
|
|
#include "core/hle/kernel/address_arbiter.h"
|
|
|
#include "core/hle/kernel/client_port.h"
|
|
|
#include "core/hle/kernel/client_session.h"
|
|
|
@@ -27,6 +28,7 @@
|
|
|
#include "core/hle/kernel/memory/memory_block.h"
|
|
|
#include "core/hle/kernel/memory/page_table.h"
|
|
|
#include "core/hle/kernel/mutex.h"
|
|
|
+#include "core/hle/kernel/physical_core.h"
|
|
|
#include "core/hle/kernel/process.h"
|
|
|
#include "core/hle/kernel/readable_event.h"
|
|
|
#include "core/hle/kernel/resource_limit.h"
|
|
|
@@ -37,6 +39,7 @@
|
|
|
#include "core/hle/kernel/svc_wrap.h"
|
|
|
#include "core/hle/kernel/synchronization.h"
|
|
|
#include "core/hle/kernel/thread.h"
|
|
|
+#include "core/hle/kernel/time_manager.h"
|
|
|
#include "core/hle/kernel/transfer_memory.h"
|
|
|
#include "core/hle/kernel/writable_event.h"
|
|
|
#include "core/hle/lock.h"
|
|
|
@@ -133,6 +136,7 @@ enum class ResourceLimitValueType {
|
|
|
|
|
|
ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
|
|
|
u32 resource_type, ResourceLimitValueType value_type) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
const auto type = static_cast<ResourceType>(resource_type);
|
|
|
if (!IsValidResourceType(type)) {
|
|
|
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
|
|
|
@@ -160,6 +164,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
|
|
|
|
|
|
/// Set the process heap to a given Size. It can both extend and shrink the heap.
|
|
|
static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
|
|
|
|
|
|
// Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB.
|
|
|
@@ -190,6 +195,7 @@ static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_s
|
|
|
|
|
|
static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask,
|
|
|
u32 attribute) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_DEBUG(Kernel_SVC,
|
|
|
"called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
|
|
|
size, mask, attribute);
|
|
|
@@ -226,8 +232,15 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si
|
|
|
static_cast<Memory::MemoryAttribute>(attribute));
|
|
|
}
|
|
|
|
|
|
+static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask,
|
|
|
+ u32 attribute) {
|
|
|
+ return SetMemoryAttribute(system, static_cast<VAddr>(address), static_cast<std::size_t>(size),
|
|
|
+ mask, attribute);
|
|
|
+}
|
|
|
+
|
|
|
/// Maps a memory range into a different range.
|
|
|
static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
|
|
src_addr, size);
|
|
|
|
|
|
@@ -241,8 +254,14 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr
|
|
|
return page_table.Map(dst_addr, src_addr, size);
|
|
|
}
|
|
|
|
|
|
+static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
|
|
|
+ return MapMemory(system, static_cast<VAddr>(dst_addr), static_cast<VAddr>(src_addr),
|
|
|
+ static_cast<std::size_t>(size));
|
|
|
+}
|
|
|
+
|
|
|
/// Unmaps a region that was previously mapped with svcMapMemory
|
|
|
static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
|
|
src_addr, size);
|
|
|
|
|
|
@@ -256,9 +275,15 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad
|
|
|
return page_table.Unmap(dst_addr, src_addr, size);
|
|
|
}
|
|
|
|
|
|
+static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
|
|
|
+ return UnmapMemory(system, static_cast<VAddr>(dst_addr), static_cast<VAddr>(src_addr),
|
|
|
+ static_cast<std::size_t>(size));
|
|
|
+}
|
|
|
+
|
|
|
/// Connect to an OS service given the port name, returns the handle to the port to out
|
|
|
static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
|
|
|
VAddr port_name_address) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
auto& memory = system.Memory();
|
|
|
|
|
|
if (!memory.IsValidVirtualAddress(port_name_address)) {
|
|
|
@@ -317,11 +342,30 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
|
|
|
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
|
|
|
|
|
|
auto thread = system.CurrentScheduler().GetCurrentThread();
|
|
|
- thread->InvalidateWakeupCallback();
|
|
|
- thread->SetStatus(ThreadStatus::WaitIPC);
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
+ {
|
|
|
+ SchedulerLock lock(system.Kernel());
|
|
|
+ thread->InvalidateHLECallback();
|
|
|
+ thread->SetStatus(ThreadStatus::WaitIPC);
|
|
|
+ session->SendSyncRequest(SharedFrom(thread), system.Memory());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (thread->HasHLECallback()) {
|
|
|
+ Handle event_handle = thread->GetHLETimeEvent();
|
|
|
+ if (event_handle != InvalidHandle) {
|
|
|
+ auto& time_manager = system.Kernel().TimeManager();
|
|
|
+ time_manager.UnscheduleTimeEvent(event_handle);
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ SchedulerLock lock(system.Kernel());
|
|
|
+ auto* sync_object = thread->GetHLESyncObject();
|
|
|
+ sync_object->RemoveWaitingThread(SharedFrom(thread));
|
|
|
+ }
|
|
|
+
|
|
|
+ thread->InvokeHLECallback(SharedFrom(thread));
|
|
|
+ }
|
|
|
|
|
|
- return session->SendSyncRequest(SharedFrom(thread), system.Memory());
|
|
|
+ return thread->GetSignalingResult();
|
|
|
}
|
|
|
|
|
|
static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
|
|
|
@@ -383,6 +427,15 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
}
|
|
|
|
|
|
+static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high,
|
|
|
+ Handle handle) {
|
|
|
+ u64 process_id{};
|
|
|
+ const auto result = GetProcessId(system, &process_id, handle);
|
|
|
+ *process_id_low = static_cast<u32>(process_id);
|
|
|
+ *process_id_high = static_cast<u32>(process_id >> 32);
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
|
|
|
static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address,
|
|
|
u64 handle_count, s64 nano_seconds) {
|
|
|
@@ -447,10 +500,13 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
|
|
|
}
|
|
|
|
|
|
thread->CancelWait();
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) {
|
|
|
+ return CancelSynchronization(system, thread_handle);
|
|
|
+}
|
|
|
+
|
|
|
/// Attempts to locks a mutex, creating it if it does not already exist
|
|
|
static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_handle,
|
|
|
VAddr mutex_addr, Handle requesting_thread_handle) {
|
|
|
@@ -475,6 +531,12 @@ static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_hand
|
|
|
requesting_thread_handle);
|
|
|
}
|
|
|
|
|
|
+static ResultCode ArbitrateLock32(Core::System& system, Handle holding_thread_handle,
|
|
|
+ u32 mutex_addr, Handle requesting_thread_handle) {
|
|
|
+ return ArbitrateLock(system, holding_thread_handle, static_cast<VAddr>(mutex_addr),
|
|
|
+ requesting_thread_handle);
|
|
|
+}
|
|
|
+
|
|
|
/// Unlock a mutex
|
|
|
static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) {
|
|
|
LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
|
|
|
@@ -494,6 +556,10 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) {
|
|
|
return current_process->GetMutex().Release(mutex_addr);
|
|
|
}
|
|
|
|
|
|
+static ResultCode ArbitrateUnlock32(Core::System& system, u32 mutex_addr) {
|
|
|
+ return ArbitrateUnlock(system, static_cast<VAddr>(mutex_addr));
|
|
|
+}
|
|
|
+
|
|
|
enum class BreakType : u32 {
|
|
|
Panic = 0,
|
|
|
AssertionFailed = 1,
|
|
|
@@ -594,6 +660,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
|
|
|
info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
|
|
|
|
|
|
if (!break_reason.signal_debugger) {
|
|
|
+ SchedulerLock lock(system.Kernel());
|
|
|
LOG_CRITICAL(
|
|
|
Debug_Emulated,
|
|
|
"Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
|
|
|
@@ -605,14 +672,16 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
|
|
|
const auto thread_processor_id = current_thread->GetProcessorID();
|
|
|
system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
|
|
|
|
|
|
- system.Kernel().CurrentProcess()->PrepareForTermination();
|
|
|
-
|
|
|
// Kill the current thread
|
|
|
+ system.Kernel().ExceptionalExit();
|
|
|
current_thread->Stop();
|
|
|
- system.PrepareReschedule();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) {
|
|
|
+ Break(system, reason, static_cast<u64>(info1), static_cast<u64>(info2));
|
|
|
+}
|
|
|
+
|
|
|
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
|
|
|
static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) {
|
|
|
if (len == 0) {
|
|
|
@@ -627,6 +696,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre
|
|
|
/// Gets system/memory information for the current process
|
|
|
static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle,
|
|
|
u64 info_sub_id) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
|
|
|
info_sub_id, handle);
|
|
|
|
|
|
@@ -863,9 +933,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
|
|
|
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
|
|
|
const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
|
|
|
|
|
|
- out_ticks = thread_ticks + (core_timing.GetTicks() - prev_ctx_ticks);
|
|
|
+ out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
|
|
|
} else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
|
|
|
- out_ticks = core_timing.GetTicks() - prev_ctx_ticks;
|
|
|
+ out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks;
|
|
|
}
|
|
|
|
|
|
*result = out_ticks;
|
|
|
@@ -892,6 +962,7 @@ static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_h
|
|
|
|
|
|
/// Maps memory at a desired address
|
|
|
static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
|
|
|
|
|
|
if (!Common::Is4KBAligned(addr)) {
|
|
|
@@ -939,8 +1010,13 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
|
|
|
return page_table.MapPhysicalMemory(addr, size);
|
|
|
}
|
|
|
|
|
|
+static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) {
|
|
|
+ return MapPhysicalMemory(system, static_cast<VAddr>(addr), static_cast<std::size_t>(size));
|
|
|
+}
|
|
|
+
|
|
|
/// Unmaps memory previously mapped via MapPhysicalMemory
|
|
|
static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
|
|
|
|
|
|
if (!Common::Is4KBAligned(addr)) {
|
|
|
@@ -988,6 +1064,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
|
|
|
return page_table.UnmapPhysicalMemory(addr, size);
|
|
|
}
|
|
|
|
|
|
+static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) {
|
|
|
+ return UnmapPhysicalMemory(system, static_cast<VAddr>(addr), static_cast<std::size_t>(size));
|
|
|
+}
|
|
|
+
|
|
|
/// Sets the thread activity
|
|
|
static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) {
|
|
|
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity);
|
|
|
@@ -1017,10 +1097,11 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act
|
|
|
return ERR_BUSY;
|
|
|
}
|
|
|
|
|
|
- thread->SetActivity(static_cast<ThreadActivity>(activity));
|
|
|
+ return thread->SetActivity(static_cast<ThreadActivity>(activity));
|
|
|
+}
|
|
|
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
- return RESULT_SUCCESS;
|
|
|
+static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) {
|
|
|
+ return SetThreadActivity(system, handle, activity);
|
|
|
}
|
|
|
|
|
|
/// Gets the thread context
|
|
|
@@ -1064,6 +1145,10 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) {
|
|
|
+ return GetThreadContext(system, static_cast<VAddr>(thread_context), handle);
|
|
|
+}
|
|
|
+
|
|
|
/// Gets the priority for the specified thread
|
|
|
static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) {
|
|
|
LOG_TRACE(Kernel_SVC, "called");
|
|
|
@@ -1071,6 +1156,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
|
|
const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle);
|
|
|
if (!thread) {
|
|
|
+ *priority = 0;
|
|
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
}
|
|
|
@@ -1105,18 +1191,26 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
|
|
|
|
|
|
thread->SetPriority(priority);
|
|
|
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) {
|
|
|
+ return SetThreadPriority(system, handle, priority);
|
|
|
+}
|
|
|
+
|
|
|
/// Get which CPU core is executing the current thread
|
|
|
static u32 GetCurrentProcessorNumber(Core::System& system) {
|
|
|
LOG_TRACE(Kernel_SVC, "called");
|
|
|
- return system.CurrentScheduler().GetCurrentThread()->GetProcessorID();
|
|
|
+ return static_cast<u32>(system.CurrentPhysicalCore().CoreIndex());
|
|
|
+}
|
|
|
+
|
|
|
+static u32 GetCurrentProcessorNumber32(Core::System& system) {
|
|
|
+ return GetCurrentProcessorNumber(system);
|
|
|
}
|
|
|
|
|
|
static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr,
|
|
|
u64 size, u32 permissions) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_TRACE(Kernel_SVC,
|
|
|
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
|
|
|
shared_memory_handle, addr, size, permissions);
|
|
|
@@ -1187,9 +1281,16 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han
|
|
|
return shared_memory->Map(*current_process, addr, size, permission_type);
|
|
|
}
|
|
|
|
|
|
+static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr,
|
|
|
+ u32 size, u32 permissions) {
|
|
|
+ return MapSharedMemory(system, shared_memory_handle, static_cast<VAddr>(addr),
|
|
|
+ static_cast<std::size_t>(size), permissions);
|
|
|
+}
|
|
|
+
|
|
|
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
|
|
|
VAddr page_info_address, Handle process_handle,
|
|
|
VAddr address) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
|
|
std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle);
|
|
|
@@ -1372,6 +1473,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
|
|
|
/// Exits the current process
|
|
|
static void ExitProcess(Core::System& system) {
|
|
|
auto* current_process = system.Kernel().CurrentProcess();
|
|
|
+ UNIMPLEMENTED();
|
|
|
|
|
|
LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
|
|
|
ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
|
|
|
@@ -1381,8 +1483,10 @@ static void ExitProcess(Core::System& system) {
|
|
|
|
|
|
// Kill the current thread
|
|
|
system.CurrentScheduler().GetCurrentThread()->Stop();
|
|
|
+}
|
|
|
|
|
|
- system.PrepareReschedule();
|
|
|
+static void ExitProcess32(Core::System& system) {
|
|
|
+ ExitProcess(system);
|
|
|
}
|
|
|
|
|
|
/// Creates a new thread
|
|
|
@@ -1428,9 +1532,10 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
|
|
|
|
|
|
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
|
|
|
|
|
|
+ ThreadType type = THREADTYPE_USER;
|
|
|
CASCADE_RESULT(std::shared_ptr<Thread> thread,
|
|
|
- Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top,
|
|
|
- *current_process));
|
|
|
+ Thread::Create(system, type, "", entry_point, priority, arg, processor_id,
|
|
|
+ stack_top, current_process));
|
|
|
|
|
|
const auto new_thread_handle = current_process->GetHandleTable().Create(thread);
|
|
|
if (new_thread_handle.Failed()) {
|
|
|
@@ -1444,11 +1549,15 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
|
|
|
thread->SetName(
|
|
|
fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle));
|
|
|
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
-
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 priority,
|
|
|
+ u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) {
|
|
|
+ return CreateThread(system, out_handle, static_cast<VAddr>(entry_point), static_cast<u64>(arg),
|
|
|
+ static_cast<VAddr>(stack_top), priority, processor_id);
|
|
|
+}
|
|
|
+
|
|
|
/// Starts the thread for the provided handle
|
|
|
static ResultCode StartThread(Core::System& system, Handle thread_handle) {
|
|
|
LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
|
|
@@ -1463,13 +1572,11 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
|
|
|
|
|
|
ASSERT(thread->GetStatus() == ThreadStatus::Dormant);
|
|
|
|
|
|
- thread->ResumeFromWait();
|
|
|
-
|
|
|
- if (thread->GetStatus() == ThreadStatus::Ready) {
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
- }
|
|
|
+ return thread->Start();
|
|
|
+}
|
|
|
|
|
|
- return RESULT_SUCCESS;
|
|
|
+static ResultCode StartThread32(Core::System& system, Handle thread_handle) {
|
|
|
+ return StartThread(system, thread_handle);
|
|
|
}
|
|
|
|
|
|
/// Called when a thread exits
|
|
|
@@ -1477,9 +1584,12 @@ static void ExitThread(Core::System& system) {
|
|
|
LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
|
|
|
|
|
|
auto* const current_thread = system.CurrentScheduler().GetCurrentThread();
|
|
|
- current_thread->Stop();
|
|
|
system.GlobalScheduler().RemoveThread(SharedFrom(current_thread));
|
|
|
- system.PrepareReschedule();
|
|
|
+ current_thread->Stop();
|
|
|
+}
|
|
|
+
|
|
|
+static void ExitThread32(Core::System& system) {
|
|
|
+ ExitThread(system);
|
|
|
}
|
|
|
|
|
|
/// Sleep the current thread
|
|
|
@@ -1498,15 +1608,21 @@ static void SleepThread(Core::System& system, s64 nanoseconds) {
|
|
|
|
|
|
if (nanoseconds <= 0) {
|
|
|
switch (static_cast<SleepType>(nanoseconds)) {
|
|
|
- case SleepType::YieldWithoutLoadBalancing:
|
|
|
- is_redundant = current_thread->YieldSimple();
|
|
|
+ case SleepType::YieldWithoutLoadBalancing: {
|
|
|
+ auto pair = current_thread->YieldSimple();
|
|
|
+ is_redundant = pair.second;
|
|
|
break;
|
|
|
- case SleepType::YieldWithLoadBalancing:
|
|
|
- is_redundant = current_thread->YieldAndBalanceLoad();
|
|
|
+ }
|
|
|
+ case SleepType::YieldWithLoadBalancing: {
|
|
|
+ auto pair = current_thread->YieldAndBalanceLoad();
|
|
|
+ is_redundant = pair.second;
|
|
|
break;
|
|
|
- case SleepType::YieldAndWaitForLoadBalancing:
|
|
|
- is_redundant = current_thread->YieldAndWaitForLoadBalancing();
|
|
|
+ }
|
|
|
+ case SleepType::YieldAndWaitForLoadBalancing: {
|
|
|
+ auto pair = current_thread->YieldAndWaitForLoadBalancing();
|
|
|
+ is_redundant = pair.second;
|
|
|
break;
|
|
|
+ }
|
|
|
default:
|
|
|
UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
|
|
}
|
|
|
@@ -1514,13 +1630,18 @@ static void SleepThread(Core::System& system, s64 nanoseconds) {
|
|
|
current_thread->Sleep(nanoseconds);
|
|
|
}
|
|
|
|
|
|
- if (is_redundant) {
|
|
|
- // If it's redundant, the core is pretty much idle. Some games keep idling
|
|
|
- // a core while it's doing nothing, we advance timing to avoid costly continuous
|
|
|
- // calls.
|
|
|
- system.CoreTiming().AddTicks(2000);
|
|
|
+ if (is_redundant && !system.Kernel().IsMulticore()) {
|
|
|
+ system.Kernel().ExitSVCProfile();
|
|
|
+ system.CoreTiming().AddTicks(1000U);
|
|
|
+ system.GetCpuManager().PreemptSingleCore();
|
|
|
+ system.Kernel().EnterSVCProfile();
|
|
|
}
|
|
|
- system.PrepareReschedule(current_thread->GetProcessorID());
|
|
|
+}
|
|
|
+
|
|
|
+static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) {
|
|
|
+ const s64 nanoseconds = static_cast<s64>(static_cast<u64>(nanoseconds_low) |
|
|
|
+ (static_cast<u64>(nanoseconds_high) << 32));
|
|
|
+ SleepThread(system, nanoseconds);
|
|
|
}
|
|
|
|
|
|
/// Wait process wide key atomic
|
|
|
@@ -1547,31 +1668,69 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
|
|
|
}
|
|
|
|
|
|
ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
|
|
|
-
|
|
|
+ auto& kernel = system.Kernel();
|
|
|
+ Handle event_handle;
|
|
|
+ Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
|
|
|
auto* const current_process = system.Kernel().CurrentProcess();
|
|
|
- const auto& handle_table = current_process->GetHandleTable();
|
|
|
- std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
|
|
- ASSERT(thread);
|
|
|
+ {
|
|
|
+ SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds);
|
|
|
+ const auto& handle_table = current_process->GetHandleTable();
|
|
|
+ std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
|
|
+ ASSERT(thread);
|
|
|
+
|
|
|
+ current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
|
|
+
|
|
|
+ if (thread->IsPendingTermination()) {
|
|
|
+ lock.CancelSleep();
|
|
|
+ return ERR_THREAD_TERMINATING;
|
|
|
+ }
|
|
|
+
|
|
|
+ const auto release_result = current_process->GetMutex().Release(mutex_addr);
|
|
|
+ if (release_result.IsError()) {
|
|
|
+ lock.CancelSleep();
|
|
|
+ return release_result;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nano_seconds == 0) {
|
|
|
+ lock.CancelSleep();
|
|
|
+ return RESULT_TIMEOUT;
|
|
|
+ }
|
|
|
|
|
|
- const auto release_result = current_process->GetMutex().Release(mutex_addr);
|
|
|
- if (release_result.IsError()) {
|
|
|
- return release_result;
|
|
|
+ current_thread->SetCondVarWaitAddress(condition_variable_addr);
|
|
|
+ current_thread->SetMutexWaitAddress(mutex_addr);
|
|
|
+ current_thread->SetWaitHandle(thread_handle);
|
|
|
+ current_thread->SetStatus(ThreadStatus::WaitCondVar);
|
|
|
+ current_process->InsertConditionVariableThread(SharedFrom(current_thread));
|
|
|
}
|
|
|
|
|
|
- Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
|
|
|
- current_thread->SetCondVarWaitAddress(condition_variable_addr);
|
|
|
- current_thread->SetMutexWaitAddress(mutex_addr);
|
|
|
- current_thread->SetWaitHandle(thread_handle);
|
|
|
- current_thread->SetStatus(ThreadStatus::WaitCondVar);
|
|
|
- current_thread->InvalidateWakeupCallback();
|
|
|
- current_process->InsertConditionVariableThread(SharedFrom(current_thread));
|
|
|
+ if (event_handle != InvalidHandle) {
|
|
|
+ auto& time_manager = kernel.TimeManager();
|
|
|
+ time_manager.UnscheduleTimeEvent(event_handle);
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ SchedulerLock lock(kernel);
|
|
|
|
|
|
- current_thread->WakeAfterDelay(nano_seconds);
|
|
|
+ auto* owner = current_thread->GetLockOwner();
|
|
|
+ if (owner != nullptr) {
|
|
|
+ owner->RemoveMutexWaiter(SharedFrom(current_thread));
|
|
|
+ }
|
|
|
|
|
|
+ current_process->RemoveConditionVariableThread(SharedFrom(current_thread));
|
|
|
+ }
|
|
|
// Note: Deliberately don't attempt to inherit the lock owner's priority.
|
|
|
|
|
|
- system.PrepareReschedule(current_thread->GetProcessorID());
|
|
|
- return RESULT_SUCCESS;
|
|
|
+ return current_thread->GetSignalingResult();
|
|
|
+}
|
|
|
+
|
|
|
+static ResultCode WaitProcessWideKeyAtomic32(Core::System& system, u32 mutex_addr,
|
|
|
+ u32 condition_variable_addr, Handle thread_handle,
|
|
|
+ u32 nanoseconds_low, u32 nanoseconds_high) {
|
|
|
+ const s64 nanoseconds =
|
|
|
+ static_cast<s64>(nanoseconds_low | (static_cast<u64>(nanoseconds_high) << 32));
|
|
|
+ return WaitProcessWideKeyAtomic(system, static_cast<VAddr>(mutex_addr),
|
|
|
+ static_cast<VAddr>(condition_variable_addr), thread_handle,
|
|
|
+ nanoseconds);
|
|
|
}
|
|
|
|
|
|
/// Signal process wide key
|
|
|
@@ -1582,7 +1741,9 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
|
|
ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
|
|
|
|
|
|
// Retrieve a list of all threads that are waiting for this condition variable.
|
|
|
- auto* const current_process = system.Kernel().CurrentProcess();
|
|
|
+ auto& kernel = system.Kernel();
|
|
|
+ SchedulerLock lock(kernel);
|
|
|
+ auto* const current_process = kernel.CurrentProcess();
|
|
|
std::vector<std::shared_ptr<Thread>> waiting_threads =
|
|
|
current_process->GetConditionVariableThreads(condition_variable_addr);
|
|
|
|
|
|
@@ -1591,7 +1752,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
|
|
std::size_t last = waiting_threads.size();
|
|
|
if (target > 0)
|
|
|
last = std::min(waiting_threads.size(), static_cast<std::size_t>(target));
|
|
|
-
|
|
|
+ auto& time_manager = kernel.TimeManager();
|
|
|
for (std::size_t index = 0; index < last; ++index) {
|
|
|
auto& thread = waiting_threads[index];
|
|
|
|
|
|
@@ -1599,7 +1760,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
|
|
|
|
|
// liberate Cond Var Thread.
|
|
|
current_process->RemoveConditionVariableThread(thread);
|
|
|
- thread->SetCondVarWaitAddress(0);
|
|
|
|
|
|
const std::size_t current_core = system.CurrentCoreIndex();
|
|
|
auto& monitor = system.Monitor();
|
|
|
@@ -1610,10 +1770,8 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
|
|
u32 update_val = 0;
|
|
|
const VAddr mutex_address = thread->GetMutexWaitAddress();
|
|
|
do {
|
|
|
- monitor.SetExclusive(current_core, mutex_address);
|
|
|
-
|
|
|
// If the mutex is not yet acquired, acquire it.
|
|
|
- mutex_val = memory.Read32(mutex_address);
|
|
|
+ mutex_val = monitor.ExclusiveRead32(current_core, mutex_address);
|
|
|
|
|
|
if (mutex_val != 0) {
|
|
|
update_val = mutex_val | Mutex::MutexHasWaitersFlag;
|
|
|
@@ -1621,33 +1779,28 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
|
|
update_val = thread->GetWaitHandle();
|
|
|
}
|
|
|
} while (!monitor.ExclusiveWrite32(current_core, mutex_address, update_val));
|
|
|
+ monitor.ClearExclusive();
|
|
|
if (mutex_val == 0) {
|
|
|
// We were able to acquire the mutex, resume this thread.
|
|
|
- ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
|
|
|
- thread->ResumeFromWait();
|
|
|
-
|
|
|
auto* const lock_owner = thread->GetLockOwner();
|
|
|
if (lock_owner != nullptr) {
|
|
|
lock_owner->RemoveMutexWaiter(thread);
|
|
|
}
|
|
|
|
|
|
thread->SetLockOwner(nullptr);
|
|
|
- thread->SetMutexWaitAddress(0);
|
|
|
- thread->SetWaitHandle(0);
|
|
|
- thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
+ thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
|
|
+ thread->ResumeFromWait();
|
|
|
} else {
|
|
|
// The mutex is already owned by some other thread, make this thread wait on it.
|
|
|
const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
|
|
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
|
|
auto owner = handle_table.Get<Thread>(owner_handle);
|
|
|
ASSERT(owner);
|
|
|
- ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
|
|
|
- thread->InvalidateWakeupCallback();
|
|
|
- thread->SetStatus(ThreadStatus::WaitMutex);
|
|
|
+ if (thread->GetStatus() == ThreadStatus::WaitCondVar) {
|
|
|
+ thread->SetStatus(ThreadStatus::WaitMutex);
|
|
|
+ }
|
|
|
|
|
|
owner->AddMutexWaiter(thread);
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -1678,12 +1831,15 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type,
|
|
|
auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter();
|
|
|
const ResultCode result =
|
|
|
address_arbiter.WaitForAddress(address, arbitration_type, value, timeout);
|
|
|
- if (result == RESULT_SUCCESS) {
|
|
|
- system.PrepareReschedule();
|
|
|
- }
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+static ResultCode WaitForAddress32(Core::System& system, u32 address, u32 type, s32 value,
|
|
|
+ u32 timeout_low, u32 timeout_high) {
|
|
|
+ s64 timeout = static_cast<s64>(timeout_low | (static_cast<u64>(timeout_high) << 32));
|
|
|
+ return WaitForAddress(system, static_cast<VAddr>(address), type, value, timeout);
|
|
|
+}
|
|
|
+
|
|
|
// Signals to an address (via Address Arbiter)
|
|
|
static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value,
|
|
|
s32 num_to_wake) {
|
|
|
@@ -1707,6 +1863,11 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type,
|
|
|
return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake);
|
|
|
}
|
|
|
|
|
|
+static ResultCode SignalToAddress32(Core::System& system, u32 address, u32 type, s32 value,
|
|
|
+ s32 num_to_wake) {
|
|
|
+ return SignalToAddress(system, static_cast<VAddr>(address), type, value, num_to_wake);
|
|
|
+}
|
|
|
+
|
|
|
static void KernelDebug([[maybe_unused]] Core::System& system,
|
|
|
[[maybe_unused]] u32 kernel_debug_type, [[maybe_unused]] u64 param1,
|
|
|
[[maybe_unused]] u64 param2, [[maybe_unused]] u64 param3) {
|
|
|
@@ -1725,14 +1886,21 @@ static u64 GetSystemTick(Core::System& system) {
|
|
|
auto& core_timing = system.CoreTiming();
|
|
|
|
|
|
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
|
|
|
- const u64 result{Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks())};
|
|
|
+ const u64 result{system.CoreTiming().GetClockTicks()};
|
|
|
|
|
|
- // Advance time to defeat dumb games that busy-wait for the frame to end.
|
|
|
- core_timing.AddTicks(400);
|
|
|
+ if (!system.Kernel().IsMulticore()) {
|
|
|
+ core_timing.AddTicks(400U);
|
|
|
+ }
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) {
|
|
|
+ u64 time = GetSystemTick(system);
|
|
|
+ *time_low = static_cast<u32>(time);
|
|
|
+ *time_high = static_cast<u32>(time >> 32);
|
|
|
+}
|
|
|
+
|
|
|
/// Close a handle
|
|
|
static ResultCode CloseHandle(Core::System& system, Handle handle) {
|
|
|
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
|
|
|
@@ -1765,9 +1933,14 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) {
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
}
|
|
|
|
|
|
+static ResultCode ResetSignal32(Core::System& system, Handle handle) {
|
|
|
+ return ResetSignal(system, handle);
|
|
|
+}
|
|
|
+
|
|
|
/// Creates a TransferMemory object
|
|
|
static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size,
|
|
|
u32 permissions) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size,
|
|
|
permissions);
|
|
|
|
|
|
@@ -1812,6 +1985,12 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size,
|
|
|
+ u32 permissions) {
|
|
|
+ return CreateTransferMemory(system, handle, static_cast<VAddr>(addr),
|
|
|
+ static_cast<std::size_t>(size), permissions);
|
|
|
+}
|
|
|
+
|
|
|
static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core,
|
|
|
u64* mask) {
|
|
|
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
|
|
|
@@ -1821,6 +2000,8 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
|
|
|
if (!thread) {
|
|
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
|
|
thread_handle);
|
|
|
+ *core = 0;
|
|
|
+ *mask = 0;
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
}
|
|
|
|
|
|
@@ -1830,6 +2011,15 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core,
|
|
|
+ u32* mask_low, u32* mask_high) {
|
|
|
+ u64 mask{};
|
|
|
+ const auto result = GetThreadCoreMask(system, thread_handle, core, &mask);
|
|
|
+ *mask_high = static_cast<u32>(mask >> 32);
|
|
|
+ *mask_low = static_cast<u32>(mask);
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core,
|
|
|
u64 affinity_mask) {
|
|
|
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}",
|
|
|
@@ -1861,7 +2051,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
|
|
|
return ERR_INVALID_COMBINATION;
|
|
|
}
|
|
|
|
|
|
- if (core < Core::NUM_CPU_CORES) {
|
|
|
+ if (core < Core::Hardware::NUM_CPU_CORES) {
|
|
|
if ((affinity_mask & (1ULL << core)) == 0) {
|
|
|
LOG_ERROR(Kernel_SVC,
|
|
|
"Core is not enabled for the current mask, core={}, mask={:016X}", core,
|
|
|
@@ -1883,11 +2073,14 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
}
|
|
|
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
- thread->ChangeCore(core, affinity_mask);
|
|
|
- system.PrepareReschedule(thread->GetProcessorID());
|
|
|
+ return thread->SetCoreAndAffinityMask(core, affinity_mask);
|
|
|
+}
|
|
|
|
|
|
- return RESULT_SUCCESS;
|
|
|
+static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core,
|
|
|
+ u32 affinity_mask_low, u32 affinity_mask_high) {
|
|
|
+ const u64 affinity_mask =
|
|
|
+ static_cast<u64>(affinity_mask_low) | (static_cast<u64>(affinity_mask_high) << 32);
|
|
|
+ return SetThreadCoreMask(system, thread_handle, core, affinity_mask);
|
|
|
}
|
|
|
|
|
|
static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) {
|
|
|
@@ -1918,6 +2111,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) {
|
|
|
+ return CreateEvent(system, write_handle, read_handle);
|
|
|
+}
|
|
|
+
|
|
|
static ResultCode ClearEvent(Core::System& system, Handle handle) {
|
|
|
LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
|
|
|
|
|
|
@@ -1939,6 +2136,10 @@ static ResultCode ClearEvent(Core::System& system, Handle handle) {
|
|
|
return ERR_INVALID_HANDLE;
|
|
|
}
|
|
|
|
|
|
+static ResultCode ClearEvent32(Core::System& system, Handle handle) {
|
|
|
+ return ClearEvent(system, handle);
|
|
|
+}
|
|
|
+
|
|
|
static ResultCode SignalEvent(Core::System& system, Handle handle) {
|
|
|
LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle);
|
|
|
|
|
|
@@ -1951,10 +2152,13 @@ static ResultCode SignalEvent(Core::System& system, Handle handle) {
|
|
|
}
|
|
|
|
|
|
writable_event->Signal();
|
|
|
- system.PrepareReschedule();
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode SignalEvent32(Core::System& system, Handle handle) {
|
|
|
+ return SignalEvent(system, handle);
|
|
|
+}
|
|
|
+
|
|
|
static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) {
|
|
|
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type);
|
|
|
|
|
|
@@ -1982,6 +2186,7 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
|
|
|
}
|
|
|
|
|
|
static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) {
|
|
|
+ std::lock_guard lock{HLE::g_hle_lock};
|
|
|
LOG_DEBUG(Kernel_SVC, "called");
|
|
|
|
|
|
auto& kernel = system.Kernel();
|
|
|
@@ -2139,6 +2344,15 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static ResultCode FlushProcessDataCache32(Core::System& system, Handle handle, u32 address,
|
|
|
+ u32 size) {
|
|
|
+ // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a nope
|
|
|
+ // as all emulation is done in the same cache level in host architecture, thus data cache
|
|
|
+ // does not need flushing.
|
|
|
+ LOG_DEBUG(Kernel_SVC, "called");
|
|
|
+ return RESULT_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
namespace {
|
|
|
struct FunctionDef {
|
|
|
using Func = void(Core::System&);
|
|
|
@@ -2153,57 +2367,57 @@ static const FunctionDef SVC_Table_32[] = {
|
|
|
{0x00, nullptr, "Unknown"},
|
|
|
{0x01, SvcWrap32<SetHeapSize32>, "SetHeapSize32"},
|
|
|
{0x02, nullptr, "Unknown"},
|
|
|
- {0x03, nullptr, "SetMemoryAttribute32"},
|
|
|
- {0x04, nullptr, "MapMemory32"},
|
|
|
- {0x05, nullptr, "UnmapMemory32"},
|
|
|
+ {0x03, SvcWrap32<SetMemoryAttribute32>, "SetMemoryAttribute32"},
|
|
|
+ {0x04, SvcWrap32<MapMemory32>, "MapMemory32"},
|
|
|
+ {0x05, SvcWrap32<UnmapMemory32>, "UnmapMemory32"},
|
|
|
{0x06, SvcWrap32<QueryMemory32>, "QueryMemory32"},
|
|
|
- {0x07, nullptr, "ExitProcess32"},
|
|
|
- {0x08, nullptr, "CreateThread32"},
|
|
|
- {0x09, nullptr, "StartThread32"},
|
|
|
- {0x0a, nullptr, "ExitThread32"},
|
|
|
- {0x0b, nullptr, "SleepThread32"},
|
|
|
+ {0x07, SvcWrap32<ExitProcess32>, "ExitProcess32"},
|
|
|
+ {0x08, SvcWrap32<CreateThread32>, "CreateThread32"},
|
|
|
+ {0x09, SvcWrap32<StartThread32>, "StartThread32"},
|
|
|
+ {0x0a, SvcWrap32<ExitThread32>, "ExitThread32"},
|
|
|
+ {0x0b, SvcWrap32<SleepThread32>, "SleepThread32"},
|
|
|
{0x0c, SvcWrap32<GetThreadPriority32>, "GetThreadPriority32"},
|
|
|
- {0x0d, nullptr, "SetThreadPriority32"},
|
|
|
- {0x0e, nullptr, "GetThreadCoreMask32"},
|
|
|
- {0x0f, nullptr, "SetThreadCoreMask32"},
|
|
|
- {0x10, nullptr, "GetCurrentProcessorNumber32"},
|
|
|
- {0x11, nullptr, "SignalEvent32"},
|
|
|
- {0x12, nullptr, "ClearEvent32"},
|
|
|
- {0x13, nullptr, "MapSharedMemory32"},
|
|
|
+ {0x0d, SvcWrap32<SetThreadPriority32>, "SetThreadPriority32"},
|
|
|
+ {0x0e, SvcWrap32<GetThreadCoreMask32>, "GetThreadCoreMask32"},
|
|
|
+ {0x0f, SvcWrap32<SetThreadCoreMask32>, "SetThreadCoreMask32"},
|
|
|
+ {0x10, SvcWrap32<GetCurrentProcessorNumber32>, "GetCurrentProcessorNumber32"},
|
|
|
+ {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"},
|
|
|
+ {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"},
|
|
|
+ {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"},
|
|
|
{0x14, nullptr, "UnmapSharedMemory32"},
|
|
|
- {0x15, nullptr, "CreateTransferMemory32"},
|
|
|
+ {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"},
|
|
|
{0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"},
|
|
|
- {0x17, nullptr, "ResetSignal32"},
|
|
|
+ {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"},
|
|
|
{0x18, SvcWrap32<WaitSynchronization32>, "WaitSynchronization32"},
|
|
|
- {0x19, nullptr, "CancelSynchronization32"},
|
|
|
- {0x1a, nullptr, "ArbitrateLock32"},
|
|
|
- {0x1b, nullptr, "ArbitrateUnlock32"},
|
|
|
- {0x1c, nullptr, "WaitProcessWideKeyAtomic32"},
|
|
|
+ {0x19, SvcWrap32<CancelSynchronization32>, "CancelSynchronization32"},
|
|
|
+ {0x1a, SvcWrap32<ArbitrateLock32>, "ArbitrateLock32"},
|
|
|
+ {0x1b, SvcWrap32<ArbitrateUnlock32>, "ArbitrateUnlock32"},
|
|
|
+ {0x1c, SvcWrap32<WaitProcessWideKeyAtomic32>, "WaitProcessWideKeyAtomic32"},
|
|
|
{0x1d, SvcWrap32<SignalProcessWideKey32>, "SignalProcessWideKey32"},
|
|
|
- {0x1e, nullptr, "GetSystemTick32"},
|
|
|
+ {0x1e, SvcWrap32<GetSystemTick32>, "GetSystemTick32"},
|
|
|
{0x1f, SvcWrap32<ConnectToNamedPort32>, "ConnectToNamedPort32"},
|
|
|
{0x20, nullptr, "Unknown"},
|
|
|
{0x21, SvcWrap32<SendSyncRequest32>, "SendSyncRequest32"},
|
|
|
{0x22, nullptr, "SendSyncRequestWithUserBuffer32"},
|
|
|
{0x23, nullptr, "Unknown"},
|
|
|
- {0x24, nullptr, "GetProcessId32"},
|
|
|
+ {0x24, SvcWrap32<GetProcessId32>, "GetProcessId32"},
|
|
|
{0x25, SvcWrap32<GetThreadId32>, "GetThreadId32"},
|
|
|
- {0x26, nullptr, "Break32"},
|
|
|
+ {0x26, SvcWrap32<Break32>, "Break32"},
|
|
|
{0x27, nullptr, "OutputDebugString32"},
|
|
|
{0x28, nullptr, "Unknown"},
|
|
|
{0x29, SvcWrap32<GetInfo32>, "GetInfo32"},
|
|
|
{0x2a, nullptr, "Unknown"},
|
|
|
{0x2b, nullptr, "Unknown"},
|
|
|
- {0x2c, nullptr, "MapPhysicalMemory32"},
|
|
|
- {0x2d, nullptr, "UnmapPhysicalMemory32"},
|
|
|
+ {0x2c, SvcWrap32<MapPhysicalMemory32>, "MapPhysicalMemory32"},
|
|
|
+ {0x2d, SvcWrap32<UnmapPhysicalMemory32>, "UnmapPhysicalMemory32"},
|
|
|
{0x2e, nullptr, "Unknown"},
|
|
|
{0x2f, nullptr, "Unknown"},
|
|
|
{0x30, nullptr, "Unknown"},
|
|
|
{0x31, nullptr, "Unknown"},
|
|
|
- {0x32, nullptr, "SetThreadActivity32"},
|
|
|
- {0x33, nullptr, "GetThreadContext32"},
|
|
|
- {0x34, nullptr, "WaitForAddress32"},
|
|
|
- {0x35, nullptr, "SignalToAddress32"},
|
|
|
+ {0x32, SvcWrap32<SetThreadActivity32>, "SetThreadActivity32"},
|
|
|
+ {0x33, SvcWrap32<GetThreadContext32>, "GetThreadContext32"},
|
|
|
+ {0x34, SvcWrap32<WaitForAddress32>, "WaitForAddress32"},
|
|
|
+ {0x35, SvcWrap32<SignalToAddress32>, "SignalToAddress32"},
|
|
|
{0x36, nullptr, "Unknown"},
|
|
|
{0x37, nullptr, "Unknown"},
|
|
|
{0x38, nullptr, "Unknown"},
|
|
|
@@ -2219,7 +2433,7 @@ static const FunctionDef SVC_Table_32[] = {
|
|
|
{0x42, nullptr, "Unknown"},
|
|
|
{0x43, nullptr, "ReplyAndReceive32"},
|
|
|
{0x44, nullptr, "Unknown"},
|
|
|
- {0x45, nullptr, "CreateEvent32"},
|
|
|
+ {0x45, SvcWrap32<CreateEvent32>, "CreateEvent32"},
|
|
|
{0x46, nullptr, "Unknown"},
|
|
|
{0x47, nullptr, "Unknown"},
|
|
|
{0x48, nullptr, "Unknown"},
|
|
|
@@ -2245,7 +2459,7 @@ static const FunctionDef SVC_Table_32[] = {
|
|
|
{0x5c, nullptr, "Unknown"},
|
|
|
{0x5d, nullptr, "Unknown"},
|
|
|
{0x5e, nullptr, "Unknown"},
|
|
|
- {0x5F, nullptr, "FlushProcessDataCache32"},
|
|
|
+ {0x5F, SvcWrap32<FlushProcessDataCache32>, "FlushProcessDataCache32"},
|
|
|
{0x60, nullptr, "Unknown"},
|
|
|
{0x61, nullptr, "Unknown"},
|
|
|
{0x62, nullptr, "Unknown"},
|
|
|
@@ -2423,13 +2637,10 @@ static const FunctionDef* GetSVCInfo64(u32 func_num) {
|
|
|
return &SVC_Table_64[func_num];
|
|
|
}
|
|
|
|
|
|
-MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
|
|
|
-
|
|
|
void Call(Core::System& system, u32 immediate) {
|
|
|
- MICROPROFILE_SCOPE(Kernel_SVC);
|
|
|
-
|
|
|
- // Lock the global kernel mutex when we enter the kernel HLE.
|
|
|
- std::lock_guard lock{HLE::g_hle_lock};
|
|
|
+ system.ExitDynarmicProfile();
|
|
|
+ auto& kernel = system.Kernel();
|
|
|
+ kernel.EnterSVCProfile();
|
|
|
|
|
|
const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate)
|
|
|
: GetSVCInfo32(immediate);
|
|
|
@@ -2442,6 +2653,9 @@ void Call(Core::System& system, u32 immediate) {
|
|
|
} else {
|
|
|
LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate);
|
|
|
}
|
|
|
+
|
|
|
+ kernel.ExitSVCProfile();
|
|
|
+ system.EnterDynarmicProfile();
|
|
|
}
|
|
|
|
|
|
} // namespace Kernel::Svc
|