diff options
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 970 |
1 files changed, 475 insertions, 495 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4ffc113c2..e3b770d66 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -10,30 +10,36 @@ #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" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" +#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" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_types.h" #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" @@ -42,7 +48,7 @@ #include "core/memory.h" #include "core/reporter.h" -namespace Kernel { +namespace Kernel::Svc { namespace { // Checks if address + size is greater than the given address @@ -52,14 +58,11 @@ constexpr bool IsValidAddressRange(VAddr address, u64 size) { return address + size > address; } -// 8 GiB -constexpr u64 MAIN_MEMORY_SIZE = 0x200000000; - // Helper function that performs the common sanity checks for svcMapMemory // and svcUnmapMemory. This is doable, as both functions perform their sanitizing // in the same order. -ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, - u64 size) { +ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr dst_addr, + VAddr src_addr, u64 size) { if (!Common::Is4KBAligned(dst_addr)) { LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr); return ERR_INVALID_ADDRESS; @@ -93,36 +96,33 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add return ERR_INVALID_ADDRESS_STATE; } - if (!vm_manager.IsWithinAddressSpace(src_addr, size)) { + if (!manager.IsInsideAddressSpace(src_addr, size)) { LOG_ERROR(Kernel_SVC, "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", src_addr, size); return ERR_INVALID_ADDRESS_STATE; } - if (!vm_manager.IsWithinStackRegion(dst_addr, size)) { + if (manager.IsOutsideStackRegion(dst_addr, size)) { LOG_ERROR(Kernel_SVC, "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", dst_addr, size); return ERR_INVALID_MEMORY_RANGE; } - const VAddr dst_end_address = dst_addr + size; - if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && - vm_manager.GetHeapRegionEndAddress() > dst_addr) { + if (manager.IsInsideHeapRegion(dst_addr, size)) { LOG_ERROR(Kernel_SVC, "Destination does not fit within the heap region, addr=0x{:016X}, " - "size=0x{:016X}, end_addr=0x{:016X}", - dst_addr, size, dst_end_address); + "size=0x{:016X}", + dst_addr, size); return ERR_INVALID_MEMORY_RANGE; } - if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && - vm_manager.GetMapRegionEndAddress() > dst_addr) { + if (manager.IsInsideAliasRegion(dst_addr, size)) { LOG_ERROR(Kernel_SVC, "Destination does not fit within the map region, addr=0x{:016X}, " - "size=0x{:016X}, end_addr=0x{:016X}", - dst_addr, size, dst_end_address); + "size=0x{:016X}", + dst_addr, size); return ERR_INVALID_MEMORY_RANGE; } @@ -136,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); @@ -163,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. @@ -177,13 +179,10 @@ static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_s return ERR_INVALID_SIZE; } - auto& vm_manager = system.Kernel().CurrentProcess()->VMManager(); - const auto alloc_result = vm_manager.SetHeapSize(heap_size); - if (alloc_result.Failed()) { - return alloc_result.Code(); - } + auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; + + CASCADE_RESULT(*heap_addr, page_table.SetHeapSize(heap_size)); - *heap_addr = *alloc_result; return RESULT_SUCCESS; } @@ -194,65 +193,9 @@ static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_s return result; } -static ResultCode SetMemoryPermission(Core::System& system, VAddr addr, u64 size, u32 prot) { - LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot); - - if (!Common::Is4KBAligned(addr)) { - LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); - return ERR_INVALID_ADDRESS; - } - - if (size == 0) { - LOG_ERROR(Kernel_SVC, "Size is 0"); - return ERR_INVALID_SIZE; - } - - if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); - return ERR_INVALID_SIZE; - } - - if (!IsValidAddressRange(addr, size)) { - LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", - addr, size); - return ERR_INVALID_ADDRESS_STATE; - } - - const auto permission = static_cast<MemoryPermission>(prot); - if (permission != MemoryPermission::None && permission != MemoryPermission::Read && - permission != MemoryPermission::ReadWrite) { - LOG_ERROR(Kernel_SVC, "Invalid memory permission specified, Got memory permission=0x{:08X}", - static_cast<u32>(permission)); - return ERR_INVALID_MEMORY_PERMISSIONS; - } - - auto* const current_process = system.Kernel().CurrentProcess(); - auto& vm_manager = current_process->VMManager(); - - if (!vm_manager.IsWithinAddressSpace(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, - size); - return ERR_INVALID_ADDRESS_STATE; - } - - const VMManager::VMAHandle iter = vm_manager.FindVMA(addr); - if (!vm_manager.IsValidHandle(iter)) { - LOG_ERROR(Kernel_SVC, "Unable to find VMA for address=0x{:016X}", addr); - return ERR_INVALID_ADDRESS_STATE; - } - - LOG_WARNING(Kernel_SVC, "Uniformity check on protected memory is not implemented."); - // TODO: Performs a uniformity check to make sure only protected memory is changed (it doesn't - // make sense to allow changing permissions on kernel memory itself, etc). - - const auto converted_permissions = SharedMemory::ConvertPermissions(permission); - - return vm_manager.ReprotectRange(addr, size, converted_permissions); -} - 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); @@ -274,72 +217,73 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si return ERR_INVALID_ADDRESS_STATE; } - const auto mem_attribute = static_cast<MemoryAttribute>(attribute); - const auto mem_mask = static_cast<MemoryAttribute>(mask); - const auto attribute_with_mask = mem_attribute | mem_mask; - - if (attribute_with_mask != mem_mask) { + const auto attributes{static_cast<Memory::MemoryAttribute>(mask | attribute)}; + if (attributes != static_cast<Memory::MemoryAttribute>(mask) || + (attributes | Memory::MemoryAttribute::Uncached) != Memory::MemoryAttribute::Uncached) { LOG_ERROR(Kernel_SVC, "Memory attribute doesn't match the given mask (Attribute: 0x{:X}, Mask: {:X}", attribute, mask); return ERR_INVALID_COMBINATION; } - if ((attribute_with_mask | MemoryAttribute::Uncached) != MemoryAttribute::Uncached) { - LOG_ERROR(Kernel_SVC, "Specified attribute isn't equal to MemoryAttributeUncached (8)."); - return ERR_INVALID_COMBINATION; - } + auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; - auto& vm_manager = system.Kernel().CurrentProcess()->VMManager(); - if (!vm_manager.IsWithinAddressSpace(address, size)) { - LOG_ERROR(Kernel_SVC, - "Given address (0x{:016X}) is outside the bounds of the address space.", address); - return ERR_INVALID_ADDRESS_STATE; - } + return page_table.SetMemoryAttribute(address, size, static_cast<Memory::MemoryAttribute>(mask), + static_cast<Memory::MemoryAttribute>(attribute)); +} - return vm_manager.SetMemoryAttribute(address, size, mem_mask, mem_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); - auto& vm_manager = system.Kernel().CurrentProcess()->VMManager(); - const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); + auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; - if (result.IsError()) { + if (const ResultCode result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; + result.IsError()) { return result; } - return vm_manager.MirrorMemory(dst_addr, src_addr, size, MemoryState::Stack); + 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); - auto& vm_manager = system.Kernel().CurrentProcess()->VMManager(); - const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); + auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; - if (result.IsError()) { + if (const ResultCode result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; + result.IsError()) { return result; } - const auto unmap_res = vm_manager.UnmapRange(dst_addr, size); - - // Reprotect the source mapping on success - if (unmap_res.IsSuccess()) { - ASSERT(vm_manager.ReprotectRange(src_addr, size, VMAPermission::ReadWrite).IsSuccess()); - } + return page_table.Unmap(dst_addr, src_addr, size); +} - return unmap_res; +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)) { @@ -367,6 +311,8 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, return ERR_NOT_FOUND; } + ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Sessions, 1)); + auto client_port = it->second; std::shared_ptr<ClientSession> client_session; @@ -396,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(), system.CoreTiming()); + } + + 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) { @@ -462,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) { @@ -484,9 +458,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr return ERR_OUT_OF_RANGE; } - auto* const thread = system.CurrentScheduler().GetCurrentThread(); auto& kernel = system.Kernel(); - using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type; Thread::ThreadSynchronizationObjects objects(handle_count); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); @@ -526,10 +498,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) { @@ -538,7 +513,7 @@ static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_hand "requesting_current_thread_handle=0x{:08X}", holding_thread_handle, mutex_addr, requesting_thread_handle); - if (Memory::IsKernelVirtualAddress(mutex_addr)) { + if (Core::Memory::IsKernelVirtualAddress(mutex_addr)) { LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}", mutex_addr); return ERR_INVALID_ADDRESS_STATE; @@ -554,11 +529,17 @@ 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); - if (Memory::IsKernelVirtualAddress(mutex_addr)) { + if (Core::Memory::IsKernelVirtualAddress(mutex_addr)) { LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}", mutex_addr); return ERR_INVALID_ADDRESS_STATE; @@ -573,6 +554,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, @@ -673,6 +658,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}", @@ -683,18 +669,19 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); const auto thread_processor_id = current_thread->GetProcessorID(); system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); - ASSERT(false); - - 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) { +static void OutputDebugString(Core::System& system, VAddr address, u64 len) { if (len == 0) { return; } @@ -707,6 +694,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); @@ -765,6 +753,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource: case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource: { if (info_sub_id != 0) { + LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id, + info_sub_id); return ERR_INVALID_ENUM_VALUE; } @@ -772,6 +762,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha system.Kernel().CurrentProcess()->GetHandleTable(); const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle)); if (!process) { + LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", + info_id, info_sub_id, handle); return ERR_INVALID_HANDLE; } @@ -785,35 +777,35 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return RESULT_SUCCESS; case GetInfoType::MapRegionBaseAddr: - *result = process->VMManager().GetMapRegionBaseAddress(); + *result = process->PageTable().GetAliasRegionStart(); return RESULT_SUCCESS; case GetInfoType::MapRegionSize: - *result = process->VMManager().GetMapRegionSize(); + *result = process->PageTable().GetAliasRegionSize(); return RESULT_SUCCESS; case GetInfoType::HeapRegionBaseAddr: - *result = process->VMManager().GetHeapRegionBaseAddress(); + *result = process->PageTable().GetHeapRegionStart(); return RESULT_SUCCESS; case GetInfoType::HeapRegionSize: - *result = process->VMManager().GetHeapRegionSize(); + *result = process->PageTable().GetHeapRegionSize(); return RESULT_SUCCESS; case GetInfoType::ASLRRegionBaseAddr: - *result = process->VMManager().GetASLRRegionBaseAddress(); + *result = process->PageTable().GetAliasCodeRegionStart(); return RESULT_SUCCESS; case GetInfoType::ASLRRegionSize: - *result = process->VMManager().GetASLRRegionSize(); + *result = process->PageTable().GetAliasCodeRegionSize(); return RESULT_SUCCESS; case GetInfoType::StackRegionBaseAddr: - *result = process->VMManager().GetStackRegionBaseAddress(); + *result = process->PageTable().GetStackRegionStart(); return RESULT_SUCCESS; case GetInfoType::StackRegionSize: - *result = process->VMManager().GetStackRegionSize(); + *result = process->PageTable().GetStackRegionSize(); return RESULT_SUCCESS; case GetInfoType::TotalPhysicalMemoryAvailable: @@ -853,7 +845,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha break; } - LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id); + LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id); return ERR_INVALID_ENUM_VALUE; } @@ -863,10 +855,13 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha case GetInfoType::RegisterResourceLimit: { if (handle != 0) { + LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle); return ERR_INVALID_HANDLE; } if (info_sub_id != 0) { + LOG_ERROR(Kernel, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id, + info_sub_id); return ERR_INVALID_COMBINATION; } @@ -936,9 +931,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; @@ -946,7 +941,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha } default: - LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id); + LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id); return ERR_INVALID_ENUM_VALUE; } } @@ -965,6 +960,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)) { @@ -987,24 +983,38 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) return ERR_INVALID_MEMORY_RANGE; } - Process* const current_process = system.Kernel().CurrentProcess(); - auto& vm_manager = current_process->VMManager(); + Process* const current_process{system.Kernel().CurrentProcess()}; + auto& page_table{current_process->PageTable()}; if (current_process->GetSystemResourceSize() == 0) { LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); return ERR_INVALID_STATE; } - if (!vm_manager.IsWithinMapRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, "Range not within map region"); + if (!page_table.IsInsideAddressSpace(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, + size); + return ERR_INVALID_MEMORY_RANGE; + } + + if (page_table.IsOutsideAliasRegion(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, + size); return ERR_INVALID_MEMORY_RANGE; } - return vm_manager.MapPhysicalMemory(addr, 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)) { @@ -1027,20 +1037,33 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size return ERR_INVALID_MEMORY_RANGE; } - Process* const current_process = system.Kernel().CurrentProcess(); - auto& vm_manager = current_process->VMManager(); + Process* const current_process{system.Kernel().CurrentProcess()}; + auto& page_table{current_process->PageTable()}; if (current_process->GetSystemResourceSize() == 0) { LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); return ERR_INVALID_STATE; } - if (!vm_manager.IsWithinMapRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, "Range not within map region"); + if (!page_table.IsInsideAddressSpace(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, + size); + return ERR_INVALID_MEMORY_RANGE; + } + + if (page_table.IsOutsideAliasRegion(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, + size); return ERR_INVALID_MEMORY_RANGE; } - return vm_manager.UnmapPhysicalMemory(addr, 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 @@ -1072,10 +1095,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 @@ -1119,6 +1143,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"); @@ -1126,6 +1154,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; } @@ -1160,18 +1189,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); @@ -1197,79 +1234,61 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han return ERR_INVALID_ADDRESS_STATE; } - const auto permissions_type = static_cast<MemoryPermission>(permissions); - if (permissions_type != MemoryPermission::Read && - permissions_type != MemoryPermission::ReadWrite) { + const auto permission_type = static_cast<Memory::MemoryPermission>(permissions); + if ((permission_type | Memory::MemoryPermission::Write) != + Memory::MemoryPermission::ReadAndWrite) { LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", permissions); return ERR_INVALID_MEMORY_PERMISSIONS; } - auto* const current_process = system.Kernel().CurrentProcess(); - auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); - if (!shared_memory) { - LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", - shared_memory_handle); - return ERR_INVALID_HANDLE; - } + auto* const current_process{system.Kernel().CurrentProcess()}; + auto& page_table{current_process->PageTable()}; - const auto& vm_manager = current_process->VMManager(); - if (!vm_manager.IsWithinASLRRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}", + if (page_table.IsInvalidRegion(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Addr does not fit within the valid region, addr=0x{:016X}, " + "size=0x{:016X}", addr, size); return ERR_INVALID_MEMORY_RANGE; } - return shared_memory->Map(*current_process, addr, permissions_type, MemoryPermission::DontCare); -} - -static ResultCode UnmapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, - u64 size) { - LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", - shared_memory_handle, addr, size); - - if (!Common::Is4KBAligned(addr)) { - LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); - return ERR_INVALID_ADDRESS; - } - - if (size == 0) { - LOG_ERROR(Kernel_SVC, "Size is 0"); - return ERR_INVALID_SIZE; - } - - if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); - return ERR_INVALID_SIZE; + if (page_table.IsInsideHeapRegion(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Addr does not fit within the heap region, addr=0x{:016X}, " + "size=0x{:016X}", + addr, size); + return ERR_INVALID_MEMORY_RANGE; } - if (!IsValidAddressRange(addr, size)) { - LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", + if (page_table.IsInsideAliasRegion(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address does not fit within the map region, addr=0x{:016X}, " + "size=0x{:016X}", addr, size); - return ERR_INVALID_ADDRESS_STATE; + return ERR_INVALID_MEMORY_RANGE; } - auto* const current_process = system.Kernel().CurrentProcess(); - auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); + auto shared_memory{current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle)}; if (!shared_memory) { LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", shared_memory_handle); return ERR_INVALID_HANDLE; } - const auto& vm_manager = current_process->VMManager(); - if (!vm_manager.IsWithinASLRRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}", - addr, size); - return ERR_INVALID_MEMORY_RANGE; - } + return shared_memory->Map(*current_process, addr, size, permission_type); +} - return shared_memory->Unmap(*current_process, addr, size); +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); @@ -1279,18 +1298,17 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add return ERR_INVALID_HANDLE; } - auto& memory = system.Memory(); - const auto& vm_manager = process->VMManager(); - const MemoryInfo memory_info = vm_manager.QueryMemory(address); - - memory.Write64(memory_info_address, memory_info.base_address); - memory.Write64(memory_info_address + 8, memory_info.size); - memory.Write32(memory_info_address + 16, memory_info.state); - memory.Write32(memory_info_address + 20, memory_info.attributes); - memory.Write32(memory_info_address + 24, memory_info.permission); - memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count); - memory.Write32(memory_info_address + 28, memory_info.device_ref_count); - memory.Write32(memory_info_address + 36, 0); + auto& memory{system.Memory()}; + const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()}; + + memory.Write64(memory_info_address + 0x00, memory_info.addr); + memory.Write64(memory_info_address + 0x08, memory_info.size); + memory.Write32(memory_info_address + 0x10, static_cast<u32>(memory_info.state) & 0xff); + memory.Write32(memory_info_address + 0x14, static_cast<u32>(memory_info.attr)); + memory.Write32(memory_info_address + 0x18, static_cast<u32>(memory_info.perm)); + memory.Write32(memory_info_address + 0x1c, memory_info.ipc_refcount); + memory.Write32(memory_info_address + 0x20, memory_info.device_refcount); + memory.Write32(memory_info_address + 0x24, 0); // Page info appears to be currently unused by the kernel and is always set to zero. memory.Write32(page_info_address, 0); @@ -1362,8 +1380,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand return ERR_INVALID_HANDLE; } - auto& vm_manager = process->VMManager(); - if (!vm_manager.IsWithinAddressSpace(src_address, size)) { + auto& page_table = process->PageTable(); + if (!page_table.IsInsideAddressSpace(src_address, size)) { LOG_ERROR(Kernel_SVC, "Source address range is not within the address space (src_address=0x{:016X}, " "size=0x{:016X}).", @@ -1371,7 +1389,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand return ERR_INVALID_ADDRESS_STATE; } - if (!vm_manager.IsWithinASLRRegion(dst_address, size)) { + if (!page_table.IsInsideASLRRegion(dst_address, size)) { LOG_ERROR(Kernel_SVC, "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " "size=0x{:016X}).", @@ -1379,7 +1397,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand return ERR_INVALID_MEMORY_RANGE; } - return vm_manager.MapCodeMemory(dst_address, src_address, size); + return page_table.MapProcessCodeMemory(dst_address, src_address, size); } static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, @@ -1430,8 +1448,8 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha return ERR_INVALID_HANDLE; } - auto& vm_manager = process->VMManager(); - if (!vm_manager.IsWithinAddressSpace(src_address, size)) { + auto& page_table = process->PageTable(); + if (!page_table.IsInsideAddressSpace(src_address, size)) { LOG_ERROR(Kernel_SVC, "Source address range is not within the address space (src_address=0x{:016X}, " "size=0x{:016X}).", @@ -1439,7 +1457,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha return ERR_INVALID_ADDRESS_STATE; } - if (!vm_manager.IsWithinASLRRegion(dst_address, size)) { + if (!page_table.IsInsideASLRRegion(dst_address, size)) { LOG_ERROR(Kernel_SVC, "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " "size=0x{:016X}).", @@ -1447,12 +1465,13 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha return ERR_INVALID_MEMORY_RANGE; } - return vm_manager.UnmapCodeMemory(dst_address, src_address, size); + return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); } /// 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, @@ -1462,8 +1481,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 @@ -1506,9 +1527,13 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e } auto& kernel = system.Kernel(); + + 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()) { @@ -1522,11 +1547,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); @@ -1541,13 +1570,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 @@ -1555,9 +1582,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 @@ -1576,15 +1606,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); } @@ -1592,13 +1628,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 @@ -1610,7 +1651,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", mutex_addr, condition_variable_addr, thread_handle, nano_seconds); - if (Memory::IsKernelVirtualAddress(mutex_addr)) { + if (Core::Memory::IsKernelVirtualAddress(mutex_addr)) { LOG_ERROR( Kernel_SVC, "Given mutex address must not be within the kernel address space. address=0x{:016X}", @@ -1625,31 +1666,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; + } - const auto release_result = current_process->GetMutex().Release(mutex_addr); - if (release_result.IsError()) { - return release_result; + if (nano_seconds == 0) { + lock.CancelSleep(); + return RESULT_TIMEOUT; + } + + 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 @@ -1660,16 +1739,18 @@ 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); // Only process up to 'target' threads, unless 'target' is less equal 0, in which case process // them all. std::size_t last = waiting_threads.size(); - if (target > 0) + if (target > 0) { last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); - + } for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; @@ -1677,21 +1758,17 @@ 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(); - auto& memory = system.Memory(); // Atomically read the value of the mutex. u32 mutex_val = 0; 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; @@ -1699,33 +1776,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()); } } } @@ -1741,7 +1813,7 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, type, value, timeout); // If the passed address is a kernel virtual address, return invalid memory state. - if (Memory::IsKernelVirtualAddress(address)) { + if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); return ERR_INVALID_ADDRESS_STATE; } @@ -1756,12 +1828,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) { @@ -1769,7 +1844,7 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, address, type, value, num_to_wake); // If the passed address is a kernel virtual address, return invalid memory state. - if (Memory::IsKernelVirtualAddress(address)) { + if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); return ERR_INVALID_ADDRESS_STATE; } @@ -1785,6 +1860,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) { @@ -1803,14 +1883,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); @@ -1843,9 +1930,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); @@ -1865,9 +1957,9 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd return ERR_INVALID_ADDRESS_STATE; } - const auto perms = static_cast<MemoryPermission>(permissions); - if (perms != MemoryPermission::None && perms != MemoryPermission::Read && - perms != MemoryPermission::ReadWrite) { + const auto perms{static_cast<Memory::MemoryPermission>(permissions)}; + if (perms > Memory::MemoryPermission::ReadAndWrite || + perms == Memory::MemoryPermission::Write) { LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", permissions); return ERR_INVALID_MEMORY_PERMISSIONS; @@ -1890,109 +1982,10 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd return RESULT_SUCCESS; } -static ResultCode MapTransferMemory(Core::System& system, Handle handle, VAddr address, u64 size, - u32 permission_raw) { - LOG_DEBUG(Kernel_SVC, - "called. handle=0x{:08X}, address=0x{:016X}, size=0x{:016X}, permissions=0x{:08X}", - handle, address, size, permission_raw); - - if (!Common::Is4KBAligned(address)) { - LOG_ERROR(Kernel_SVC, "Transfer memory addresses must be 4KB aligned (size=0x{:016X}).", - address); - return ERR_INVALID_ADDRESS; - } - - if (size == 0 || !Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, - "Transfer memory sizes must be 4KB aligned and not be zero (size=0x{:016X}).", - size); - return ERR_INVALID_SIZE; - } - - if (!IsValidAddressRange(address, size)) { - LOG_ERROR(Kernel_SVC, - "Given address and size overflows the 64-bit range (address=0x{:016X}, " - "size=0x{:016X}).", - address, size); - return ERR_INVALID_ADDRESS_STATE; - } - - const auto permissions = static_cast<MemoryPermission>(permission_raw); - if (permissions != MemoryPermission::None && permissions != MemoryPermission::Read && - permissions != MemoryPermission::ReadWrite) { - LOG_ERROR(Kernel_SVC, "Invalid transfer memory permissions given (permissions=0x{:08X}).", - permission_raw); - return ERR_INVALID_STATE; - } - - const auto& kernel = system.Kernel(); - const auto* const current_process = kernel.CurrentProcess(); - const auto& handle_table = current_process->GetHandleTable(); - - auto transfer_memory = handle_table.Get<TransferMemory>(handle); - if (!transfer_memory) { - LOG_ERROR(Kernel_SVC, "Nonexistent transfer memory handle given (handle=0x{:08X}).", - handle); - return ERR_INVALID_HANDLE; - } - - if (!current_process->VMManager().IsWithinASLRRegion(address, size)) { - LOG_ERROR(Kernel_SVC, - "Given address and size don't fully fit within the ASLR region " - "(address=0x{:016X}, size=0x{:016X}).", - address, size); - return ERR_INVALID_MEMORY_RANGE; - } - - return transfer_memory->MapMemory(address, size, permissions); -} - -static ResultCode UnmapTransferMemory(Core::System& system, Handle handle, VAddr address, - u64 size) { - LOG_DEBUG(Kernel_SVC, "called. handle=0x{:08X}, address=0x{:016X}, size=0x{:016X}", handle, - address, size); - - if (!Common::Is4KBAligned(address)) { - LOG_ERROR(Kernel_SVC, "Transfer memory addresses must be 4KB aligned (size=0x{:016X}).", - address); - return ERR_INVALID_ADDRESS; - } - - if (size == 0 || !Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, - "Transfer memory sizes must be 4KB aligned and not be zero (size=0x{:016X}).", - size); - return ERR_INVALID_SIZE; - } - - if (!IsValidAddressRange(address, size)) { - LOG_ERROR(Kernel_SVC, - "Given address and size overflows the 64-bit range (address=0x{:016X}, " - "size=0x{:016X}).", - address, size); - return ERR_INVALID_ADDRESS_STATE; - } - - const auto& kernel = system.Kernel(); - const auto* const current_process = kernel.CurrentProcess(); - const auto& handle_table = current_process->GetHandleTable(); - - auto transfer_memory = handle_table.Get<TransferMemory>(handle); - if (!transfer_memory) { - LOG_ERROR(Kernel_SVC, "Nonexistent transfer memory handle given (handle=0x{:08X}).", - handle); - return ERR_INVALID_HANDLE; - } - - if (!current_process->VMManager().IsWithinASLRRegion(address, size)) { - LOG_ERROR(Kernel_SVC, - "Given address and size don't fully fit within the ASLR region " - "(address=0x{:016X}, size=0x{:016X}).", - address, size); - return ERR_INVALID_MEMORY_RANGE; - } - - return transfer_memory->UnmapMemory(address, size); +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, @@ -2004,6 +1997,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; } @@ -2013,6 +2008,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}", @@ -2044,7 +2048,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, @@ -2066,57 +2070,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 RESULT_SUCCESS; + return thread->SetCoreAndAffinityMask(core, affinity_mask); } -static ResultCode CreateSharedMemory(Core::System& system, Handle* handle, u64 size, - u32 local_permissions, u32 remote_permissions) { - LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, - local_permissions, remote_permissions); - if (size == 0) { - LOG_ERROR(Kernel_SVC, "Size is 0"); - return ERR_INVALID_SIZE; - } - if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size); - return ERR_INVALID_SIZE; - } - - if (size >= MAIN_MEMORY_SIZE) { - LOG_ERROR(Kernel_SVC, "Size is not less than 8GB, 0x{:016X}", size); - return ERR_INVALID_SIZE; - } - - const auto local_perms = static_cast<MemoryPermission>(local_permissions); - if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { - LOG_ERROR(Kernel_SVC, - "Invalid local memory permissions, expected Read or ReadWrite but got " - "local_permissions={}", - static_cast<u32>(local_permissions)); - return ERR_INVALID_MEMORY_PERMISSIONS; - } - - const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); - if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && - remote_perms != MemoryPermission::DontCare) { - LOG_ERROR(Kernel_SVC, - "Invalid remote memory permissions, expected Read, ReadWrite or DontCare but got " - "remote_permissions={}", - static_cast<u32>(remote_permissions)); - return ERR_INVALID_MEMORY_PERMISSIONS; - } - - auto& kernel = system.Kernel(); - auto process = kernel.CurrentProcess(); - auto& handle_table = process->GetHandleTable(); - auto shared_mem_handle = SharedMemory::Create(kernel, process, size, local_perms, remote_perms); - - CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); - 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) { @@ -2147,6 +2108,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); @@ -2168,6 +2133,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); @@ -2180,10 +2149,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); @@ -2211,6 +2183,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(); @@ -2305,11 +2278,10 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes, } const auto& kernel = system.Kernel(); - const auto& vm_manager = kernel.CurrentProcess()->VMManager(); const auto total_copy_size = out_process_ids_size * sizeof(u64); - if (out_process_ids_size > 0 && - !vm_manager.IsWithinAddressSpace(out_process_ids, total_copy_size)) { + if (out_process_ids_size > 0 && !kernel.CurrentProcess()->PageTable().IsInsideAddressSpace( + out_process_ids, total_copy_size)) { LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", out_process_ids, out_process_ids + total_copy_size); return ERR_INVALID_ADDRESS_STATE; @@ -2345,11 +2317,10 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd } const auto* const current_process = system.Kernel().CurrentProcess(); - const auto& vm_manager = current_process->VMManager(); const auto total_copy_size = out_thread_ids_size * sizeof(u64); if (out_thread_ids_size > 0 && - !vm_manager.IsWithinAddressSpace(out_thread_ids, total_copy_size)) { + !current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) { LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", out_thread_ids, out_thread_ids + total_copy_size); return ERR_INVALID_ADDRESS_STATE; @@ -2370,6 +2341,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&); @@ -2384,57 +2364,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"}, @@ -2450,7 +2430,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"}, @@ -2476,7 +2456,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"}, @@ -2510,7 +2490,7 @@ static const FunctionDef SVC_Table_32[] = { static const FunctionDef SVC_Table_64[] = { {0x00, nullptr, "Unknown"}, {0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"}, - {0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"}, + {0x02, nullptr, "SetMemoryPermission"}, {0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"}, {0x04, SvcWrap64<MapMemory>, "MapMemory"}, {0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"}, @@ -2528,7 +2508,7 @@ static const FunctionDef SVC_Table_64[] = { {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, - {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"}, + {0x14, nullptr, "UnmapSharedMemory"}, {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, @@ -2588,9 +2568,9 @@ static const FunctionDef SVC_Table_64[] = { {0x4D, nullptr, "SleepSystem"}, {0x4E, nullptr, "ReadWriteRegister"}, {0x4F, nullptr, "SetProcessActivity"}, - {0x50, SvcWrap64<CreateSharedMemory>, "CreateSharedMemory"}, - {0x51, SvcWrap64<MapTransferMemory>, "MapTransferMemory"}, - {0x52, SvcWrap64<UnmapTransferMemory>, "UnmapTransferMemory"}, + {0x50, nullptr, "CreateSharedMemory"}, + {0x51, nullptr, "MapTransferMemory"}, + {0x52, nullptr, "UnmapTransferMemory"}, {0x53, nullptr, "CreateInterruptEvent"}, {0x54, nullptr, "QueryPhysicalAddress"}, {0x55, nullptr, "QueryIoMapping"}, @@ -2654,13 +2634,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 CallSVC(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}; +void Call(Core::System& system, u32 immediate) { + system.ExitDynarmicProfile(); + auto& kernel = system.Kernel(); + kernel.EnterSVCProfile(); const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); @@ -2673,6 +2650,9 @@ void CallSVC(Core::System& system, u32 immediate) { } else { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } + + kernel.ExitSVCProfile(); + system.EnterDynarmicProfile(); } -} // namespace Kernel +} // namespace Kernel::Svc |
