diff options
Diffstat (limited to 'src/core/hle')
35 files changed, 1137 insertions, 380 deletions
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 0a7142ada..0d6c85aed 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -18,7 +18,7 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" namespace IPC { diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index c114eaf99..704e82824 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -8,6 +8,7 @@ #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" #include "core/hle/kernel/thread.h" +#include "core/hle/result.h" namespace Kernel { diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 439fbdb35..4c18de69c 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -6,9 +6,9 @@ #include <memory> #include <string> -#include "common/common_types.h" #include "core/hle/kernel/object.h" -#include "core/hle/result.h" + +union ResultCode; namespace Kernel { diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 8b58d701d..d17eb0cb6 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -11,6 +11,7 @@ namespace Kernel { // Confirmed Switch kernel error codes constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7}; +constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14}; constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105}; @@ -27,9 +28,10 @@ constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118}; constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119}; constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120}; constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121}; -constexpr ResultCode ERR_ALREADY_REGISTERED{ErrorModule::Kernel, 122}; +constexpr ResultCode ERR_BUSY{ErrorModule::Kernel, 122}; constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123}; constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125}; +constexpr ResultCode ERR_RESERVED_VALUE{ErrorModule::Kernel, 126}; constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132}; } // namespace Kernel diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 6b7927fd8..89a3bc740 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -43,6 +43,9 @@ enum KernelHandle : Handle { */ class HandleTable final : NonCopyable { public: + /// This is the maximum limit of handles allowed per process in Horizon + static constexpr std::size_t MAX_COUNT = 1024; + HandleTable(); ~HandleTable(); @@ -91,9 +94,6 @@ public: void Clear(); private: - /// This is the maximum limit of handles allowed per process in Horizon - static constexpr std::size_t MAX_COUNT = 1024; - /// Stores the Object referenced by the handle or null if the slot is empty. std::array<SharedPtr<Object>, MAX_COUNT> objects; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 61ce7d7e4..5dd855db8 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -22,11 +22,16 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/memory.h" namespace Kernel { +SessionRequestHandler::SessionRequestHandler() = default; + +SessionRequestHandler::~SessionRequestHandler() = default; + void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) { server_session->SetHleHandler(shared_from_this()); connected_sessions.push_back(std::move(server_session)); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index e5c0610cd..cb1c5aff3 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -14,8 +14,6 @@ #include "common/swap.h" #include "core/hle/ipc.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/thread.h" namespace Service { class ServiceFrameworkBase; @@ -27,9 +25,13 @@ class Domain; class HandleTable; class HLERequestContext; class Process; +class ServerSession; +class Thread; class ReadableEvent; class WritableEvent; +enum class ThreadWakeupReason; + /** * Interface implemented by HLE Session handlers. * This can be provided to a ServerSession in order to hook into several relevant events @@ -37,7 +39,8 @@ class WritableEvent; */ class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { public: - virtual ~SessionRequestHandler() = default; + SessionRequestHandler(); + virtual ~SessionRequestHandler(); /** * Handles a sync request from the emulated application. diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1c2290651..67674cd47 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <array> #include <atomic> #include <memory> #include <mutex> diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 5356a4a3f..c5aa19afa 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -20,6 +20,35 @@ #include "core/settings.h" namespace Kernel { +namespace { +/** + * Sets up the primary application thread + * + * @param owner_process The parent process for the main thread + * @param kernel The kernel instance to create the main thread under. + * @param entry_point The address at which the thread should start execution + * @param priority The priority to give the main thread + */ +void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_point, u32 priority) { + // Setup page table so we can write to memory + SetCurrentPageTable(&owner_process.VMManager().page_table); + + // Initialize new "main" thread + const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress(); + auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, + owner_process.GetIdealCore(), stack_top, owner_process); + + SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); + + // Register 1 must be a handle to the main thread + const Handle guest_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); + thread->SetGuestHandle(guest_handle); + thread->GetContext().cpu_registers[1] = guest_handle; + + // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires + thread->ResumeFromWait(); +} +} // Anonymous namespace CodeSet::CodeSet() = default; CodeSet::~CodeSet() = default; @@ -28,13 +57,11 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { SharedPtr<Process> process(new Process(kernel)); process->name = std::move(name); - process->flags.raw = 0; - process->flags.memory_region.Assign(MemoryRegion::APPLICATION); process->resource_limit = kernel.GetSystemResourceLimit(); process->status = ProcessStatus::Created; process->program_id = 0; process->process_id = kernel.CreateNewProcessID(); - process->svc_access_mask.set(); + process->capabilities.InitializeForMetadatalessProcess(); std::mt19937 rng(Settings::values.rng_seed.value_or(0)); std::uniform_int_distribution<u64> distribution; @@ -64,83 +91,15 @@ ResultCode Process::ClearSignalState() { return RESULT_SUCCESS; } -void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { +ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { program_id = metadata.GetTitleID(); - ideal_processor = metadata.GetMainThreadCore(); + ideal_core = metadata.GetMainThreadCore(); is_64bit_process = metadata.Is64BitProgram(); - vm_manager.Reset(metadata.GetAddressSpaceType()); -} - -void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { - for (std::size_t i = 0; i < len; ++i) { - u32 descriptor = kernel_caps[i]; - u32 type = descriptor >> 20; - - if (descriptor == 0xFFFFFFFF) { - // Unused descriptor entry - continue; - } else if ((type & 0xF00) == 0xE00) { // 0x0FFF - // Allowed interrupts list - LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored"); - } else if ((type & 0xF80) == 0xF00) { // 0x07FF - // Allowed syscalls mask - unsigned int index = ((descriptor >> 24) & 7) * 24; - u32 bits = descriptor & 0xFFFFFF; - - while (bits && index < svc_access_mask.size()) { - svc_access_mask.set(index, bits & 1); - ++index; - bits >>= 1; - } - } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF - // Handle table size - handle_table_size = descriptor & 0x3FF; - } else if ((type & 0xFF8) == 0xFF0) { // 0x007F - // Misc. flags - flags.raw = descriptor & 0xFFFF; - } else if ((type & 0xFFE) == 0xFF8) { // 0x001F - // Mapped memory range - if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) { - LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); - continue; - } - u32 end_desc = kernel_caps[i + 1]; - ++i; // Skip over the second descriptor on the next iteration - AddressMapping mapping; - mapping.address = descriptor << 12; - VAddr end_address = end_desc << 12; - - if (mapping.address < end_address) { - mapping.size = end_address - mapping.address; - } else { - mapping.size = 0; - } + vm_manager.Reset(metadata.GetAddressSpaceType()); - mapping.read_only = (descriptor & (1 << 20)) != 0; - mapping.unk_flag = (end_desc & (1 << 20)) != 0; - - address_mappings.push_back(mapping); - } else if ((type & 0xFFF) == 0xFFE) { // 0x000F - // Mapped memory page - AddressMapping mapping; - mapping.address = descriptor << 12; - mapping.size = Memory::PAGE_SIZE; - mapping.read_only = false; - mapping.unk_flag = false; - - address_mappings.push_back(mapping); - } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF - // Kernel version - kernel_version = descriptor & 0xFFFF; - - int minor = kernel_version & 0xFF; - int major = (kernel_version >> 8) & 0xFF; - LOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor); - } else { - LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor); - } - } + const auto& caps = metadata.GetKernelCapabilities(); + return capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager); } void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { @@ -156,7 +115,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { vm_manager.LogLayout(); ChangeStatus(ProcessStatus::Running); - Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this); + SetupMainThread(*this, kernel, entry_point, main_thread_priority); } void Process::PrepareForTermination() { @@ -268,22 +227,6 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); } -ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { - return vm_manager.HeapAllocate(target, size, perms); -} - -ResultCode Process::HeapFree(VAddr target, u32 size) { - return vm_manager.HeapFree(target, size); -} - -ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) { - return vm_manager.MirrorMemory(dst_addr, src_addr, size, state); -} - -ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { - return vm_manager.UnmapRange(dst_addr, size); -} - Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {} Kernel::Process::~Process() {} diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 7da367251..dcc57ae9f 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -11,10 +11,9 @@ #include <string> #include <vector> #include <boost/container/static_vector.hpp> -#include "common/bit_field.h" #include "common/common_types.h" #include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/thread.h" +#include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" @@ -27,6 +26,7 @@ namespace Kernel { class KernelCore; class ResourceLimit; +class Thread; struct AddressMapping { // Address and size must be page-aligned @@ -42,24 +42,6 @@ enum class MemoryRegion : u16 { BASE = 3, }; -union ProcessFlags { - u16 raw; - - BitField<0, 1, u16> - allow_debug; ///< Allows other processes to attach to and debug this process. - BitField<1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they - /// don't have allow_debug set. - BitField<2, 1, u16> allow_nonalphanum; - BitField<3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions. - BitField<4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24. - BitField<5, 1, u16> allow_main_args; - BitField<6, 1, u16> shared_device_mem; - BitField<7, 1, u16> runnable_on_sleep; - BitField<8, 4, MemoryRegion> - memory_region; ///< Default region for memory allocations for this process - BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). -}; - /** * Indicates the status of a Process instance. * @@ -186,19 +168,19 @@ public: /// Gets the resource limit descriptor for this process SharedPtr<ResourceLimit> GetResourceLimit() const; - /// Gets the default CPU ID for this process - u8 GetDefaultProcessorID() const { - return ideal_processor; + /// Gets the ideal CPU core ID for this process + u8 GetIdealCore() const { + return ideal_core; } - /// Gets the bitmask of allowed CPUs that this process' threads can run on. - u32 GetAllowedProcessorMask() const { - return allowed_processor_mask; + /// Gets the bitmask of allowed cores that this process' threads can run on. + u64 GetCoreMask() const { + return capabilities.GetCoreMask(); } /// Gets the bitmask of allowed thread priorities. - u32 GetAllowedThreadPriorityMask() const { - return allowed_thread_priority_mask; + u64 GetPriorityMask() const { + return capabilities.GetPriorityMask(); } u32 IsVirtualMemoryEnabled() const { @@ -239,15 +221,12 @@ public: * Loads process-specifics configuration info with metadata provided * by an executable. * - * @param metadata The provided metadata to load process specific info. - */ - void LoadFromMetadata(const FileSys::ProgramMetadata& metadata); - - /** - * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them - * to this process. + * @param metadata The provided metadata to load process specific info from. + * + * @returns RESULT_SUCCESS if all relevant metadata was able to be + * loaded and parsed. Otherwise, an error code is returned. */ - void ParseKernelCaps(const u32* kernel_caps, std::size_t len); + ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata); /** * Applies address space changes and launches the process main thread. @@ -263,7 +242,7 @@ public: void LoadModule(CodeSet module_, VAddr base_addr); /////////////////////////////////////////////////////////////////////////////////////////////// - // Memory Management + // Thread-local storage management // Marks the next available region as used and returns the address of the slot. VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread); @@ -271,13 +250,6 @@ public: // Frees a used TLS slot identified by the given address void FreeTLSSlot(VAddr tls_address); - ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); - ResultCode HeapFree(VAddr target, u32 size); - - ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state); - - ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); - private: explicit Process(KernelCore& kernel); ~Process() override; @@ -308,22 +280,8 @@ private: /// Resource limit descriptor for this process SharedPtr<ResourceLimit> resource_limit; - /// The process may only call SVCs which have the corresponding bit set. - std::bitset<0x80> svc_access_mask; - /// Maximum size of the handle table for the process. - u32 handle_table_size = 0x200; - /// Special memory ranges mapped into this processes address space. This is used to give - /// processes access to specific I/O regions and device memory. - boost::container::static_vector<AddressMapping, 8> address_mappings; - ProcessFlags flags; - /// Kernel compatibility version for this process - u16 kernel_version = 0; - /// The default CPU for this process, threads are scheduled on this cpu by default. - u8 ideal_processor = 0; - /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse - /// this value from the process header. - u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; - u32 allowed_thread_priority_mask = 0xFFFFFFFF; + /// The ideal CPU core for this process, threads are scheduled on this core by default. + u8 ideal_core = 0; u32 is_virtual_address_memory_enabled = 0; /// The Thread Local Storage area is allocated as processes create threads, @@ -333,6 +291,9 @@ private: /// This vector will grow as more pages are allocated for new threads. std::vector<std::bitset<8>> tls_slots; + /// Contains the parsed process capability descriptors. + ProcessCapabilities capabilities; + /// Whether or not this process is AArch64, or AArch32. /// By default, we currently assume this is true, unless otherwise /// specified by metadata provided to the process during loading. diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp new file mode 100644 index 000000000..3a2164b25 --- /dev/null +++ b/src/core/hle/kernel/process_capability.cpp @@ -0,0 +1,355 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/bit_util.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/process_capability.h" +#include "core/hle/kernel/vm_manager.h" + +namespace Kernel { +namespace { + +// clang-format off + +// Shift offsets for kernel capability types. +enum : u32 { + CapabilityOffset_PriorityAndCoreNum = 3, + CapabilityOffset_Syscall = 4, + CapabilityOffset_MapPhysical = 6, + CapabilityOffset_MapIO = 7, + CapabilityOffset_Interrupt = 11, + CapabilityOffset_ProgramType = 13, + CapabilityOffset_KernelVersion = 14, + CapabilityOffset_HandleTableSize = 15, + CapabilityOffset_Debug = 16, +}; + +// Combined mask of all parameters that may be initialized only once. +constexpr u32 InitializeOnceMask = (1U << CapabilityOffset_PriorityAndCoreNum) | + (1U << CapabilityOffset_ProgramType) | + (1U << CapabilityOffset_KernelVersion) | + (1U << CapabilityOffset_HandleTableSize) | + (1U << CapabilityOffset_Debug); + +// Packed kernel version indicating 10.4.0 +constexpr u32 PackedKernelVersion = 0x520000; + +// Indicates possible types of capabilities that can be specified. +enum class CapabilityType : u32 { + Unset = 0U, + PriorityAndCoreNum = (1U << CapabilityOffset_PriorityAndCoreNum) - 1, + Syscall = (1U << CapabilityOffset_Syscall) - 1, + MapPhysical = (1U << CapabilityOffset_MapPhysical) - 1, + MapIO = (1U << CapabilityOffset_MapIO) - 1, + Interrupt = (1U << CapabilityOffset_Interrupt) - 1, + ProgramType = (1U << CapabilityOffset_ProgramType) - 1, + KernelVersion = (1U << CapabilityOffset_KernelVersion) - 1, + HandleTableSize = (1U << CapabilityOffset_HandleTableSize) - 1, + Debug = (1U << CapabilityOffset_Debug) - 1, + Ignorable = 0xFFFFFFFFU, +}; + +// clang-format on + +constexpr CapabilityType GetCapabilityType(u32 value) { + return static_cast<CapabilityType>((~value & (value + 1)) - 1); +} + +u32 GetFlagBitOffset(CapabilityType type) { + const auto value = static_cast<u32>(type); + return static_cast<u32>(Common::BitSize<u32>() - Common::CountLeadingZeroes32(value)); +} + +} // Anonymous namespace + +ResultCode ProcessCapabilities::InitializeForKernelProcess(const u32* capabilities, + std::size_t num_capabilities, + VMManager& vm_manager) { + Clear(); + + // Allow all cores and priorities. + core_mask = 0xF; + priority_mask = 0xFFFFFFFFFFFFFFFF; + kernel_version = PackedKernelVersion; + + return ParseCapabilities(capabilities, num_capabilities, vm_manager); +} + +ResultCode ProcessCapabilities::InitializeForUserProcess(const u32* capabilities, + std::size_t num_capabilities, + VMManager& vm_manager) { + Clear(); + + return ParseCapabilities(capabilities, num_capabilities, vm_manager); +} + +void ProcessCapabilities::InitializeForMetadatalessProcess() { + // Allow all cores and priorities + core_mask = 0xF; + priority_mask = 0xFFFFFFFFFFFFFFFF; + kernel_version = PackedKernelVersion; + + // Allow all system calls and interrupts. + svc_capabilities.set(); + interrupt_capabilities.set(); + + // Allow using the maximum possible amount of handles + handle_table_size = static_cast<u32>(HandleTable::MAX_COUNT); + + // Allow all debugging capabilities. + is_debuggable = true; + can_force_debug = true; +} + +ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities, + std::size_t num_capabilities, + VMManager& vm_manager) { + u32 set_flags = 0; + u32 set_svc_bits = 0; + + for (std::size_t i = 0; i < num_capabilities; ++i) { + const u32 descriptor = capabilities[i]; + const auto type = GetCapabilityType(descriptor); + + if (type == CapabilityType::MapPhysical) { + i++; + + // The MapPhysical type uses two descriptor flags for its parameters. + // If there's only one, then there's a problem. + if (i >= num_capabilities) { + return ERR_INVALID_COMBINATION; + } + + const auto size_flags = capabilities[i]; + if (GetCapabilityType(size_flags) != CapabilityType::MapPhysical) { + return ERR_INVALID_COMBINATION; + } + + const auto result = HandleMapPhysicalFlags(descriptor, size_flags, vm_manager); + if (result.IsError()) { + return result; + } + } else { + const auto result = + ParseSingleFlagCapability(set_flags, set_svc_bits, descriptor, vm_manager); + if (result.IsError()) { + return result; + } + } + } + + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits, + u32 flag, VMManager& vm_manager) { + const auto type = GetCapabilityType(flag); + + if (type == CapabilityType::Unset) { + return ERR_INVALID_CAPABILITY_DESCRIPTOR; + } + + // Bail early on ignorable entries, as one would expect, + // ignorable descriptors can be ignored. + if (type == CapabilityType::Ignorable) { + return RESULT_SUCCESS; + } + + // Ensure that the give flag hasn't already been initialized before. + // If it has been, then bail. + const u32 flag_length = GetFlagBitOffset(type); + const u32 set_flag = 1U << flag_length; + if ((set_flag & set_flags & InitializeOnceMask) != 0) { + return ERR_INVALID_COMBINATION; + } + set_flags |= set_flag; + + switch (type) { + case CapabilityType::PriorityAndCoreNum: + return HandlePriorityCoreNumFlags(flag); + case CapabilityType::Syscall: + return HandleSyscallFlags(set_svc_bits, flag); + case CapabilityType::MapIO: + return HandleMapIOFlags(flag, vm_manager); + case CapabilityType::Interrupt: + return HandleInterruptFlags(flag); + case CapabilityType::ProgramType: + return HandleProgramTypeFlags(flag); + case CapabilityType::KernelVersion: + return HandleKernelVersionFlags(flag); + case CapabilityType::HandleTableSize: + return HandleHandleTableFlags(flag); + case CapabilityType::Debug: + return HandleDebugFlags(flag); + default: + break; + } + + return ERR_INVALID_CAPABILITY_DESCRIPTOR; +} + +void ProcessCapabilities::Clear() { + svc_capabilities.reset(); + interrupt_capabilities.reset(); + + core_mask = 0; + priority_mask = 0; + + handle_table_size = 0; + kernel_version = 0; + + program_type = ProgramType::SysModule; + + is_debuggable = false; + can_force_debug = false; +} + +ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) { + if (priority_mask != 0 || core_mask != 0) { + return ERR_INVALID_CAPABILITY_DESCRIPTOR; + } + + const u32 core_num_min = (flags >> 16) & 0xFF; + const u32 core_num_max = (flags >> 24) & 0xFF; + if (core_num_min > core_num_max) { + return ERR_INVALID_COMBINATION; + } + + const u32 priority_min = (flags >> 10) & 0x3F; + const u32 priority_max = (flags >> 4) & 0x3F; + if (priority_min > priority_max) { + return ERR_INVALID_COMBINATION; + } + + // The switch only has 4 usable cores. + if (core_num_max >= 4) { + return ERR_INVALID_PROCESSOR_ID; + } + + const auto make_mask = [](u64 min, u64 max) { + const u64 range = max - min + 1; + const u64 mask = (1ULL << range) - 1; + + return mask << min; + }; + + core_mask = make_mask(core_num_min, core_num_max); + priority_mask = make_mask(priority_min, priority_max); + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags) { + const u32 index = flags >> 29; + const u32 svc_bit = 1U << index; + + // If we've already set this svc before, bail. + if ((set_svc_bits & svc_bit) != 0) { + return ERR_INVALID_COMBINATION; + } + set_svc_bits |= svc_bit; + + const u32 svc_mask = (flags >> 5) & 0xFFFFFF; + for (u32 i = 0; i < 24; ++i) { + const u32 svc_number = index * 24 + i; + + if ((svc_mask & (1U << i)) == 0) { + continue; + } + + if (svc_number >= svc_capabilities.size()) { + return ERR_OUT_OF_RANGE; + } + + svc_capabilities[svc_number] = true; + } + + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::HandleMapPhysicalFlags(u32 flags, u32 size_flags, + VMManager& vm_manager) { + // TODO(Lioncache): Implement once the memory manager can handle this. + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, VMManager& vm_manager) { + // TODO(Lioncache): Implement once the memory manager can handle this. + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) { + constexpr u32 interrupt_ignore_value = 0x3FF; + const u32 interrupt0 = (flags >> 12) & 0x3FF; + const u32 interrupt1 = (flags >> 22) & 0x3FF; + + for (u32 interrupt : {interrupt0, interrupt1}) { + if (interrupt == interrupt_ignore_value) { + continue; + } + + // NOTE: + // This should be checking a generic interrupt controller value + // as part of the calculation, however, given we don't currently + // emulate that, it's sufficient to mark every interrupt as defined. + + if (interrupt >= interrupt_capabilities.size()) { + return ERR_OUT_OF_RANGE; + } + + interrupt_capabilities[interrupt] = true; + } + + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) { + const u32 reserved = flags >> 17; + if (reserved != 0) { + return ERR_RESERVED_VALUE; + } + + program_type = static_cast<ProgramType>((flags >> 14) & 0b111); + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) { + // Yes, the internal member variable is checked in the actual kernel here. + // This might look odd for options that are only allowed to be initialized + // just once, however the kernel has a separate initialization function for + // kernel processes and userland processes. The kernel variant sets this + // member variable ahead of time. + + const u32 major_version = kernel_version >> 19; + + if (major_version != 0 || flags < 0x80000) { + return ERR_INVALID_CAPABILITY_DESCRIPTOR; + } + + kernel_version = flags; + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) { + const u32 reserved = flags >> 26; + if (reserved != 0) { + return ERR_RESERVED_VALUE; + } + + handle_table_size = (flags >> 16) & 0x3FF; + return RESULT_SUCCESS; +} + +ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) { + const u32 reserved = flags >> 19; + if (reserved != 0) { + return ERR_RESERVED_VALUE; + } + + is_debuggable = (flags & 0x20000) != 0; + can_force_debug = (flags & 0x40000) != 0; + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h new file mode 100644 index 000000000..fbc8812a3 --- /dev/null +++ b/src/core/hle/kernel/process_capability.h @@ -0,0 +1,264 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <bitset> + +#include "common/common_types.h" + +union ResultCode; + +namespace Kernel { + +class VMManager; + +/// The possible types of programs that may be indicated +/// by the program type capability descriptor. +enum class ProgramType { + SysModule, + Application, + Applet, +}; + +/// Handles kernel capability descriptors that are provided by +/// application metadata. These descriptors provide information +/// that alters certain parameters for kernel process instance +/// that will run said application (or applet). +/// +/// Capabilities are a sequence of flag descriptors, that indicate various +/// configurations and constraints for a particular process. +/// +/// Flag types are indicated by a sequence of set low bits. E.g. the +/// types are indicated with the low bits as follows (where x indicates "don't care"): +/// +/// - Priority and core mask : 0bxxxxxxxxxxxx0111 +/// - Allowed service call mask: 0bxxxxxxxxxxx01111 +/// - Map physical memory : 0bxxxxxxxxx0111111 +/// - Map IO memory : 0bxxxxxxxx01111111 +/// - Interrupts : 0bxxxx011111111111 +/// - Application type : 0bxx01111111111111 +/// - Kernel version : 0bx011111111111111 +/// - Handle table size : 0b0111111111111111 +/// - Debugger flags : 0b1111111111111111 +/// +/// These are essentially a bit offset subtracted by 1 to create a mask. +/// e.g. The first entry in the above list is simply bit 3 (value 8 -> 0b1000) +/// subtracted by one (7 -> 0b0111) +/// +/// An example of a bit layout (using the map physical layout): +/// <example> +/// The MapPhysical type indicates a sequence entry pair of: +/// +/// [initial, memory_flags], where: +/// +/// initial: +/// bits: +/// 7-24: Starting page to map memory at. +/// 25 : Indicates if the memory should be mapped as read only. +/// +/// memory_flags: +/// bits: +/// 7-20 : Number of pages to map +/// 21-25: Seems to be reserved (still checked against though) +/// 26 : Whether or not the memory being mapped is IO memory, or physical memory +/// </example> +/// +class ProcessCapabilities { +public: + using InterruptCapabilities = std::bitset<1024>; + using SyscallCapabilities = std::bitset<128>; + + ProcessCapabilities() = default; + ProcessCapabilities(const ProcessCapabilities&) = delete; + ProcessCapabilities(ProcessCapabilities&&) = default; + + ProcessCapabilities& operator=(const ProcessCapabilities&) = delete; + ProcessCapabilities& operator=(ProcessCapabilities&&) = default; + + /// Initializes this process capabilities instance for a kernel process. + /// + /// @param capabilities The capabilities to parse + /// @param num_capabilities The number of capabilities to parse. + /// @param vm_manager The memory manager to use for handling any mapping-related + /// operations (such as mapping IO memory, etc). + /// + /// @returns RESULT_SUCCESS if this capabilities instance was able to be initialized, + /// otherwise, an error code upon failure. + /// + ResultCode InitializeForKernelProcess(const u32* capabilities, std::size_t num_capabilities, + VMManager& vm_manager); + + /// Initializes this process capabilities instance for a userland process. + /// + /// @param capabilities The capabilities to parse. + /// @param num_capabilities The total number of capabilities to parse. + /// @param vm_manager The memory manager to use for handling any mapping-related + /// operations (such as mapping IO memory, etc). + /// + /// @returns RESULT_SUCCESS if this capabilities instance was able to be initialized, + /// otherwise, an error code upon failure. + /// + ResultCode InitializeForUserProcess(const u32* capabilities, std::size_t num_capabilities, + VMManager& vm_manager); + + /// Initializes this process capabilities instance for a process that does not + /// have any metadata to parse. + /// + /// This is necessary, as we allow running raw executables, and the internal + /// kernel process capabilities also determine what CPU cores the process is + /// allowed to run on, and what priorities are allowed for threads. It also + /// determines the max handle table size, what the program type is, whether or + /// not the process can be debugged, or whether it's possible for a process to + /// forcibly debug another process. + /// + /// Given the above, this essentially enables all capabilities across the board + /// for the process. It allows the process to: + /// + /// - Run on any core + /// - Use any thread priority + /// - Use the maximum amount of handles a process is allowed to. + /// - Be debuggable + /// - Forcibly debug other processes. + /// + /// Note that this is not a behavior that the kernel allows a process to do via + /// a single function like this. This is yuzu-specific behavior to handle + /// executables with no capability descriptors whatsoever to derive behavior from. + /// It being yuzu-specific is why this is also not the default behavior and not + /// done by default in the constructor. + /// + void InitializeForMetadatalessProcess(); + + /// Gets the allowable core mask + u64 GetCoreMask() const { + return core_mask; + } + + /// Gets the allowable priority mask + u64 GetPriorityMask() const { + return priority_mask; + } + + /// Gets the SVC access permission bits + const SyscallCapabilities& GetServiceCapabilities() const { + return svc_capabilities; + } + + /// Gets the valid interrupt bits. + const InterruptCapabilities& GetInterruptCapabilities() const { + return interrupt_capabilities; + } + + /// Gets the program type for this process. + ProgramType GetProgramType() const { + return program_type; + } + + /// Gets the number of total allowable handles for the process' handle table. + u32 GetHandleTableSize() const { + return handle_table_size; + } + + /// Gets the kernel version value. + u32 GetKernelVersion() const { + return kernel_version; + } + + /// Whether or not this process can be debugged. + bool IsDebuggable() const { + return is_debuggable; + } + + /// Whether or not this process can forcibly debug another + /// process, even if that process is not considered debuggable. + bool CanForceDebug() const { + return can_force_debug; + } + +private: + /// Attempts to parse a given sequence of capability descriptors. + /// + /// @param capabilities The sequence of capability descriptors to parse. + /// @param num_capabilities The number of descriptors within the given sequence. + /// @param vm_manager The memory manager that will perform any memory + /// mapping if necessary. + /// + /// @return RESULT_SUCCESS if no errors occur, otherwise an error code. + /// + ResultCode ParseCapabilities(const u32* capabilities, std::size_t num_capabilities, + VMManager& vm_manager); + + /// Attempts to parse a capability descriptor that is only represented by a + /// single flag set. + /// + /// @param set_flags Running set of flags that are used to catch + /// flags being initialized more than once when they shouldn't be. + /// @param set_svc_bits Running set of bits representing the allowed supervisor calls mask. + /// @param flag The flag to attempt to parse. + /// @param vm_manager The memory manager that will perform any memory + /// mapping if necessary. + /// + /// @return RESULT_SUCCESS if no errors occurred, otherwise an error code. + /// + ResultCode ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits, u32 flag, + VMManager& vm_manager); + + /// Clears the internal state of this process capability instance. Necessary, + /// to have a sane starting point due to us allowing running executables without + /// configuration metadata. We assume a process is not going to have metadata, + /// and if it turns out that the process does, in fact, have metadata, then + /// we attempt to parse it. Thus, we need this to reset data members back to + /// a good state. + /// + /// DO NOT ever make this a public member function. This isn't an invariant + /// anything external should depend upon (and if anything comes to rely on it, + /// you should immediately be questioning the design of that thing, not this + /// class. If the kernel itself can run without depending on behavior like that, + /// then so can yuzu). + /// + void Clear(); + + /// Handles flags related to the priority and core number capability flags. + ResultCode HandlePriorityCoreNumFlags(u32 flags); + + /// Handles flags related to determining the allowable SVC mask. + ResultCode HandleSyscallFlags(u32& set_svc_bits, u32 flags); + + /// Handles flags related to mapping physical memory pages. + ResultCode HandleMapPhysicalFlags(u32 flags, u32 size_flags, VMManager& vm_manager); + + /// Handles flags related to mapping IO pages. + ResultCode HandleMapIOFlags(u32 flags, VMManager& vm_manager); + + /// Handles flags related to the interrupt capability flags. + ResultCode HandleInterruptFlags(u32 flags); + + /// Handles flags related to the program type. + ResultCode HandleProgramTypeFlags(u32 flags); + + /// Handles flags related to the handle table size. + ResultCode HandleHandleTableFlags(u32 flags); + + /// Handles flags related to the kernel version capability flags. + ResultCode HandleKernelVersionFlags(u32 flags); + + /// Handles flags related to debug-specific capabilities. + ResultCode HandleDebugFlags(u32 flags); + + SyscallCapabilities svc_capabilities; + InterruptCapabilities interrupt_capabilities; + + u64 core_mask = 0; + u64 priority_mask = 0; + + u32 handle_table_size = 0; + u32 kernel_version = 0; + + ProgramType program_type = ProgramType::SysModule; + + bool is_debuggable = false; + bool can_force_debug = false; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 80897f3a4..027434f92 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -6,6 +6,7 @@ #include <utility> #include "common/assert.h" +#include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index e068db2bf..e0e9d64c8 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -8,7 +8,6 @@ #include <string> #include <vector> -#include "common/common_types.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 28268e112..6588bd3b8 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -190,10 +190,16 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { return ERR_INVALID_SIZE; } - auto& process = *Core::CurrentProcess(); - const VAddr heap_base = process.VMManager().GetHeapRegionBaseAddress(); - CASCADE_RESULT(*heap_addr, - process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite)); + auto& vm_manager = Core::CurrentProcess()->VMManager(); + const VAddr heap_base = vm_manager.GetHeapRegionBaseAddress(); + const auto alloc_result = + vm_manager.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite); + + if (alloc_result.Failed()) { + return alloc_result.Code(); + } + + *heap_addr = *alloc_result; return RESULT_SUCCESS; } @@ -307,15 +313,14 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); - auto* const current_process = Core::CurrentProcess(); - const auto& vm_manager = current_process->VMManager(); - + auto& vm_manager = Core::CurrentProcess()->VMManager(); const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); - if (result != RESULT_SUCCESS) { + + if (result.IsError()) { return result; } - return current_process->MirrorMemory(dst_addr, src_addr, size, MemoryState::Stack); + return vm_manager.MirrorMemory(dst_addr, src_addr, size, MemoryState::Stack); } /// Unmaps a region that was previously mapped with svcMapMemory @@ -323,15 +328,14 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); - auto* const current_process = Core::CurrentProcess(); - const auto& vm_manager = current_process->VMManager(); - + auto& vm_manager = Core::CurrentProcess()->VMManager(); const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); - if (result != RESULT_SUCCESS) { + + if (result.IsError()) { return result; } - return current_process->UnmapMemory(dst_addr, src_addr, size); + return vm_manager.UnmapRange(dst_addr, size); } /// Connect to an OS service given the port name, returns the handle to the port to out @@ -680,6 +684,9 @@ static void Break(u32 reason, u64 info1, u64 info2) { "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", reason, info1, info2); handle_debug_buffer(info1, info2); + Core::System::GetInstance() + .ArmInterface(static_cast<std::size_t>(GetCurrentThread()->GetProcessorID())) + .LogBacktrace(); ASSERT(false); Core::CurrentProcess()->PrepareForTermination(); @@ -708,8 +715,8 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) enum class GetInfoType : u64 { // 1.0.0+ - AllowedCpuIdBitmask = 0, - AllowedThreadPrioBitmask = 1, + AllowedCPUCoreMask = 0, + AllowedThreadPriorityMask = 1, MapRegionBaseAddr = 2, MapRegionSize = 3, HeapRegionBaseAddr = 4, @@ -740,8 +747,8 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) const auto info_id_type = static_cast<GetInfoType>(info_id); switch (info_id_type) { - case GetInfoType::AllowedCpuIdBitmask: - case GetInfoType::AllowedThreadPrioBitmask: + case GetInfoType::AllowedCPUCoreMask: + case GetInfoType::AllowedThreadPriorityMask: case GetInfoType::MapRegionBaseAddr: case GetInfoType::MapRegionSize: case GetInfoType::HeapRegionBaseAddr: @@ -767,12 +774,12 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) } switch (info_id_type) { - case GetInfoType::AllowedCpuIdBitmask: - *result = process->GetAllowedProcessorMask(); + case GetInfoType::AllowedCPUCoreMask: + *result = process->GetCoreMask(); return RESULT_SUCCESS; - case GetInfoType::AllowedThreadPrioBitmask: - *result = process->GetAllowedThreadPriorityMask(); + case GetInfoType::AllowedThreadPriorityMask: + *result = process->GetPriorityMask(); return RESULT_SUCCESS; case GetInfoType::MapRegionBaseAddr: @@ -932,8 +939,35 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) } /// Sets the thread activity -static ResultCode SetThreadActivity(Handle handle, u32 unknown) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle, unknown); +static ResultCode SetThreadActivity(Handle handle, u32 activity) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); + if (activity > static_cast<u32>(ThreadActivity::Paused)) { + return ERR_INVALID_ENUM_VALUE; + } + + const auto* current_process = Core::CurrentProcess(); + const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); + return ERR_INVALID_HANDLE; + } + + if (thread->GetOwnerProcess() != current_process) { + LOG_ERROR(Kernel_SVC, + "The current process does not own the current thread, thread_handle={:08X} " + "thread_pid={}, " + "current_process_pid={}", + handle, thread->GetOwnerProcess()->GetProcessID(), + current_process->GetProcessID()); + return ERR_INVALID_HANDLE; + } + + if (thread == GetCurrentThread()) { + LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); + return ERR_BUSY; + } + + thread->SetActivity(static_cast<ThreadActivity>(activity)); return RESULT_SUCCESS; } @@ -960,7 +994,7 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { if (thread == GetCurrentThread()) { LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); - return ERR_ALREADY_REGISTERED; + return ERR_BUSY; } Core::ARM_Interface::ThreadContext ctx = thread->GetContext(); @@ -1185,31 +1219,37 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", entry_point, arg, stack_top, priority, processor_id, *out_handle); - if (priority > THREADPRIO_LOWEST) { - LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}", - THREADPRIO_LOWEST, priority); - return ERR_INVALID_THREAD_PRIORITY; - } - auto* const current_process = Core::CurrentProcess(); - if (processor_id == THREADPROCESSORID_DEFAULT) { - // Set the target CPU to the one specified in the process' exheader. - processor_id = current_process->GetDefaultProcessorID(); - ASSERT(processor_id != THREADPROCESSORID_DEFAULT); + if (processor_id == THREADPROCESSORID_IDEAL) { + // Set the target CPU to the one specified by the process. + processor_id = current_process->GetIdealCore(); + ASSERT(processor_id != THREADPROCESSORID_IDEAL); } - switch (processor_id) { - case THREADPROCESSORID_0: - case THREADPROCESSORID_1: - case THREADPROCESSORID_2: - case THREADPROCESSORID_3: - break; - default: + if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) { LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id); return ERR_INVALID_PROCESSOR_ID; } + const u64 core_mask = current_process->GetCoreMask(); + if ((core_mask | (1ULL << processor_id)) != core_mask) { + LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id); + return ERR_INVALID_PROCESSOR_ID; + } + + if (priority > THREADPRIO_LOWEST) { + LOG_ERROR(Kernel_SVC, + "Invalid thread priority specified ({}). Must be within the range 0-64", + priority); + return ERR_INVALID_THREAD_PRIORITY; + } + + if (((1ULL << priority) & current_process->GetPriorityMask()) == 0) { + LOG_ERROR(Kernel_SVC, "Invalid thread priority specified ({})", priority); + return ERR_INVALID_THREAD_PRIORITY; + } + const std::string name = fmt::format("thread-{:X}", entry_point); auto& kernel = Core::System::GetInstance().Kernel(); CASCADE_RESULT(SharedPtr<Thread> thread, @@ -1245,7 +1285,10 @@ static ResultCode StartThread(Handle thread_handle) { ASSERT(thread->GetStatus() == ThreadStatus::Dormant); thread->ResumeFromWait(); - Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); + + if (thread->GetStatus() == ThreadStatus::Ready) { + Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); + } return RESULT_SUCCESS; } @@ -1602,13 +1645,13 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { return ERR_INVALID_HANDLE; } - if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) { - const u8 default_processor_id = thread->GetOwnerProcess()->GetDefaultProcessorID(); + if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) { + const u8 ideal_cpu_core = thread->GetOwnerProcess()->GetIdealCore(); - ASSERT(default_processor_id != static_cast<u8>(THREADPROCESSORID_DEFAULT)); + ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL)); - // Set the target CPU to the one specified in the process' exheader. - core = default_processor_id; + // Set the target CPU to the ideal core specified by the process. + core = ideal_cpu_core; mask = 1ULL << core; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 63f8923fd..d3984dfc4 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -12,7 +12,6 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" -#include "common/math_util.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" #include "core/core.h" @@ -50,7 +49,7 @@ void Thread::Stop() { // Clean up thread from ready queue // This is only needed when the thread is terminated forcefully (SVC TerminateProcess) - if (status == ThreadStatus::Ready) { + if (status == ThreadStatus::Ready || status == ThreadStatus::Paused) { scheduler->UnscheduleThread(this, current_priority); } @@ -140,6 +139,11 @@ void Thread::ResumeFromWait() { wakeup_callback = nullptr; + if (activity == ThreadActivity::Paused) { + status = ThreadStatus::Paused; + return; + } + status = ThreadStatus::Ready; ChangeScheduler(); @@ -227,29 +231,6 @@ void Thread::BoostPriority(u32 priority) { current_priority = priority; } -SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, - Process& owner_process) { - // Setup page table so we can write to memory - SetCurrentPageTable(&owner_process.VMManager().page_table); - - // Initialize new "main" thread - const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress(); - auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, - stack_top, owner_process); - - SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); - - // Register 1 must be a handle to the main thread - const Handle guest_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); - thread->SetGuestHandle(guest_handle); - thread->GetContext().cpu_registers[1] = guest_handle; - - // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires - thread->ResumeFromWait(); - - return thread; -} - void Thread::SetWaitSynchronizationResult(ResultCode result) { context.cpu_registers[0] = result.raw; } @@ -391,6 +372,23 @@ bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> t return wakeup_callback(reason, std::move(thread), std::move(object), index); } +void Thread::SetActivity(ThreadActivity value) { + activity = value; + + if (value == ThreadActivity::Paused) { + // Set status if not waiting + if (status == ThreadStatus::Ready) { + status = ThreadStatus::Paused; + } else if (status == ThreadStatus::Running) { + status = ThreadStatus::Paused; + Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); + } + } else if (status == ThreadStatus::Paused) { + // Ready to reschedule + ResumeFromWait(); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////// /** diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index d6e7981d3..c48b21aba 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -30,12 +30,12 @@ enum ThreadPriority : u32 { }; enum ThreadProcessorId : s32 { - THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader - THREADPROCESSORID_0 = 0, ///< Run thread on core 0 - THREADPROCESSORID_1 = 1, ///< Run thread on core 1 - THREADPROCESSORID_2 = 2, ///< Run thread on core 2 - THREADPROCESSORID_3 = 3, ///< Run thread on core 3 - THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this + THREADPROCESSORID_IDEAL = -2, ///< Run thread on the ideal core specified by the process. + THREADPROCESSORID_0 = 0, ///< Run thread on core 0 + THREADPROCESSORID_1 = 1, ///< Run thread on core 1 + THREADPROCESSORID_2 = 2, ///< Run thread on core 2 + THREADPROCESSORID_3 = 3, ///< Run thread on core 3 + THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this /// Allowed CPU mask THREADPROCESSORID_DEFAULT_MASK = (1 << THREADPROCESSORID_0) | (1 << THREADPROCESSORID_1) | @@ -45,6 +45,7 @@ enum ThreadProcessorId : s32 { enum class ThreadStatus { Running, ///< Currently running Ready, ///< Ready to run + Paused, ///< Paused by SetThreadActivity or debug WaitHLEEvent, ///< Waiting for hle event to finish WaitSleep, ///< Waiting due to a SleepThread SVC WaitIPC, ///< Waiting for the reply from an IPC request @@ -61,6 +62,11 @@ enum class ThreadWakeupReason { Timeout // The thread was woken up due to a wait timeout. }; +enum class ThreadActivity : u32 { + Normal = 0, + Paused = 1, +}; + class Thread final : public WaitObject { public: using TLSMemory = std::vector<u8>; @@ -371,6 +377,12 @@ public: return affinity_mask; } + ThreadActivity GetActivity() const { + return activity; + } + + void SetActivity(ThreadActivity value); + private: explicit Thread(KernelCore& kernel); ~Thread() override; @@ -439,18 +451,9 @@ private: TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>(); std::string name; -}; -/** - * Sets up the primary application thread - * @param kernel The kernel instance to create the main thread under. - * @param entry_point The address at which the thread should start execution - * @param priority The priority to give the main thread - * @param owner_process The parent process for the main thread - * @return A shared pointer to the main thread - */ -SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, - Process& owner_process); + ThreadActivity activity = ThreadActivity::Normal; +}; /** * Gets the current thread diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index f39e096ca..10ad94aa6 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -190,6 +190,7 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) { vma.type = VMAType::Free; vma.permissions = VMAPermission::None; vma.state = MemoryState::Unmapped; + vma.attribute = MemoryAttribute::None; vma.backing_block = nullptr; vma.offset = 0; diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 530ee6af7..90580ed93 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -4,11 +4,11 @@ #include <algorithm> #include "common/assert.h" +#include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" -#include "core/hle/kernel/timer.h" namespace Kernel { diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index f4367ee28..d70b67893 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h @@ -6,7 +6,6 @@ #include <vector> #include <boost/smart_ptr/intrusive_ptr.hpp> -#include "common/common_types.h" #include "core/hle/kernel/object.h" namespace Kernel { diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h index 8fa8d68ee..c9068dd3d 100644 --- a/src/core/hle/kernel/writable_event.h +++ b/src/core/hle/kernel/writable_event.h @@ -4,9 +4,7 @@ #pragma once -#include "common/common_types.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/wait_object.h" namespace Kernel { diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 5fc02a521..d13ce4dca 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -8,6 +8,7 @@ #include <stack> #include "audio_core/audio_renderer.h" #include "core/core.h" +#include "core/file_sys/savedata_factory.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -865,8 +866,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, {24, nullptr, "GetLaunchStorageInfoForDebug"}, - {25, nullptr, "ExtendSaveData"}, - {26, nullptr, "GetSaveDataSize"}, + {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, + {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, @@ -1043,6 +1044,48 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { rb.Push<u64>(0); } +void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto type{rp.PopRaw<FileSys::SaveDataType>()}; + rp.Skip(1, false); + const auto user_id{rp.PopRaw<u128>()}; + const auto new_normal_size{rp.PopRaw<u64>()}; + const auto new_journal_size{rp.PopRaw<u64>()}; + + LOG_DEBUG(Service_AM, + "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " + "new_journal={:016X}", + static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); + + FileSystem::WriteSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id, + {new_normal_size, new_journal_size}); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + + // The following value is used upon failure to help the system recover. + // Since we always succeed, this should be 0. + rb.Push<u64>(0); +} + +void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto type{rp.PopRaw<FileSys::SaveDataType>()}; + rp.Skip(1, false); + const auto user_id{rp.PopRaw<u128>()}; + + LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), + user_id[1], user_id[0]); + + const auto size = + FileSystem::ReadSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.Push(size.normal); + rb.Push(size.journal); +} + void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { auto message_queue = std::make_shared<AppletMessageQueue>(); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 34c45fadf..b6113cfdd 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -206,6 +206,8 @@ private: void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx); void NotifyRunning(Kernel::HLERequestContext& ctx); void GetPseudoDeviceId(Kernel::HLERequestContext& ctx); + void ExtendSaveData(Kernel::HLERequestContext& ctx); + void GetSaveDataSize(Kernel::HLERequestContext& ctx); void BeginBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7698ca819..a6064c63f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -6,7 +6,7 @@ #include "common/assert.h" #include "core/core.h" #include "core/hle/kernel/readable_event.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index b0a8913c3..37424c379 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -7,7 +7,7 @@ #include <memory> #include <queue> #include "common/swap.h" -#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/object.h" #include "core/hle/kernel/writable_event.h" union ResultCode; diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 2f15ac2a6..770590d0b 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -111,7 +111,8 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { } static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) { - LOG_ERROR(Service_Fatal, "Threw fatal error type {}", static_cast<u32>(fatal_type)); + LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", + static_cast<u32>(fatal_type), error_code.raw); switch (fatal_type) { case FatalType::ErrorReportAndScreen: GenerateErrorReport(error_code, info); diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index b1490e6fa..c6da2df43 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -8,18 +8,23 @@ #include "common/file_util.h" #include "core/core.h" #include "core/file_sys/bis_factory.h" +#include "core/file_sys/control_metadata.h" #include "core/file_sys/errors.h" #include "core/file_sys/mode.h" +#include "core/file_sys/partition_filesystem.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/sdmc_factory.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_offset.h" +#include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_ldr.h" #include "core/hle/service/filesystem/fsp_pr.h" #include "core/hle/service/filesystem/fsp_srv.h" +#include "core/loader/loader.h" namespace Service::FileSystem { @@ -28,6 +33,10 @@ namespace Service::FileSystem { // TODO(DarkLordZach): Eventually make this configurable in settings. constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000; +// A default size for normal/journal save data size if application control metadata cannot be found. +// This should be large enough to satisfy even the most extreme requirements (~4.2GB) +constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000; + static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, std::string_view dir_name_) { std::string dir_name(FileUtil::SanitizePath(dir_name_)); @@ -341,6 +350,44 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() { return sdmc_factory->Open(); } +FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) { + if (save_data_factory == nullptr) { + return {0, 0}; + } + + const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id); + + if (value.normal == 0 && value.journal == 0) { + FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; + + FileSys::NACP nacp; + const auto res = Core::System::GetInstance().GetAppLoader().ReadControlData(nacp); + + if (res != Loader::ResultStatus::Success) { + FileSys::PatchManager pm{Core::CurrentProcess()->GetTitleID()}; + auto [nacp_unique, discard] = pm.GetControlMetadata(); + + if (nacp_unique != nullptr) { + new_size = {nacp_unique->GetDefaultNormalSaveSize(), + nacp_unique->GetDefaultJournalSaveSize()}; + } + } else { + new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()}; + } + + WriteSaveDataSize(type, title_id, user_id, new_size); + return new_size; + } + + return value; +} + +void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, + FileSys::SaveDataSize new_value) { + if (save_data_factory != nullptr) + save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value); +} + FileSys::RegisteredCacheUnion GetUnionContents() { return FileSys::RegisteredCacheUnion{ {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}}; diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 965414be0..6fd5e7b23 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -21,9 +21,11 @@ class SDMCFactory; enum class ContentRecordType : u8; enum class Mode : u32; enum class SaveDataSpaceId : u8; +enum class SaveDataType : u8; enum class StorageId : u8; struct SaveDataDescriptor; +struct SaveDataSize; } // namespace FileSys namespace Service { @@ -48,6 +50,10 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space); ResultVal<FileSys::VirtualDir> OpenSDMC(); +FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id); +void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, + FileSys::SaveDataSize new_value); + FileSys::RegisteredCacheUnion GetUnionContents(); FileSys::RegisteredCache* GetSystemNANDContents(); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index d6829d0b8..75fdb861a 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -339,52 +339,6 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; - if (hold_type == NpadHoldType::Horizontal) { - ControllerPadState state{}; - AnalogPosition temp_lstick_entry{}; - AnalogPosition temp_rstick_entry{}; - if (controller_type == NPadControllerType::JoyLeft) { - state.d_down.Assign(pad_state.pad_states.d_left.Value()); - state.d_left.Assign(pad_state.pad_states.d_up.Value()); - state.d_right.Assign(pad_state.pad_states.d_down.Value()); - state.d_up.Assign(pad_state.pad_states.d_right.Value()); - state.l.Assign(pad_state.pad_states.l.Value() | - pad_state.pad_states.left_sl.Value()); - state.r.Assign(pad_state.pad_states.r.Value() | - pad_state.pad_states.left_sr.Value()); - - state.zl.Assign(pad_state.pad_states.zl.Value()); - state.plus.Assign(pad_state.pad_states.minus.Value()); - - temp_lstick_entry = pad_state.l_stick; - temp_rstick_entry = pad_state.r_stick; - std::swap(temp_lstick_entry.x, temp_lstick_entry.y); - std::swap(temp_rstick_entry.x, temp_rstick_entry.y); - temp_lstick_entry.y *= -1; - } else if (controller_type == NPadControllerType::JoyRight) { - state.x.Assign(pad_state.pad_states.a.Value()); - state.a.Assign(pad_state.pad_states.b.Value()); - state.b.Assign(pad_state.pad_states.y.Value()); - state.y.Assign(pad_state.pad_states.b.Value()); - - state.l.Assign(pad_state.pad_states.l.Value() | - pad_state.pad_states.right_sl.Value()); - state.r.Assign(pad_state.pad_states.r.Value() | - pad_state.pad_states.right_sr.Value()); - state.zr.Assign(pad_state.pad_states.zr.Value()); - state.plus.Assign(pad_state.pad_states.plus.Value()); - - temp_lstick_entry = pad_state.l_stick; - temp_rstick_entry = pad_state.r_stick; - std::swap(temp_lstick_entry.x, temp_lstick_entry.y); - std::swap(temp_rstick_entry.x, temp_rstick_entry.y); - temp_rstick_entry.x *= -1; - } - pad_state.pad_states.raw = state.raw; - pad_state.l_stick = temp_lstick_entry; - pad_state.r_stick = temp_rstick_entry; - } - libnx_entry.connection_status.raw = 0; switch (controller_type) { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 2ec38c726..268409257 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -306,7 +306,10 @@ private: std::shared_ptr<IAppletResource> applet_resource; void CreateAppletResource(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); if (applet_resource == nullptr) { applet_resource = std::make_shared<IAppletResource>(); @@ -318,7 +321,12 @@ private: } void ActivateXpad(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto basic_xpad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", + basic_xpad_id, applet_resource_user_id); applet_resource->ActivateController(HidController::XPad); IPC::ResponseBuilder rb{ctx, 2}; @@ -326,7 +334,10 @@ private: } void ActivateDebugPad(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); applet_resource->ActivateController(HidController::DebugPad); IPC::ResponseBuilder rb{ctx, 2}; @@ -334,7 +345,10 @@ private: } void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); applet_resource->ActivateController(HidController::Touchscreen); IPC::ResponseBuilder rb{ctx, 2}; @@ -342,7 +356,10 @@ private: } void ActivateMouse(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); applet_resource->ActivateController(HidController::Mouse); IPC::ResponseBuilder rb{ctx, 2}; @@ -350,7 +367,10 @@ private: } void ActivateKeyboard(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); applet_resource->ActivateController(HidController::Keyboard); IPC::ResponseBuilder rb{ctx, 2}; @@ -358,7 +378,12 @@ private: } void ActivateGesture(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, + applet_resource_user_id); applet_resource->ActivateController(HidController::Gesture); IPC::ResponseBuilder rb{ctx, 2}; @@ -367,7 +392,12 @@ private: void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { // Should have no effect with how our npad sets up the data - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, + applet_resource_user_id); applet_resource->ActivateController(HidController::NPad); IPC::ResponseBuilder rb{ctx, 2}; @@ -376,22 +406,37 @@ private: void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto handle = rp.PopRaw<u32>(); - LOG_WARNING(Service_HID, "(STUBBED) called with handle={}", handle); + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto drift_mode{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", + handle, drift_mode, applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); @@ -401,8 +446,9 @@ private: void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto supported_styleset = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with supported_styleset={}", supported_styleset); + const auto supported_styleset{rp.Pop<u32>()}; + + LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); applet_resource->GetController<Controller_NPad>(HidController::NPad) .SetSupportedStyleSet({supported_styleset}); @@ -412,7 +458,10 @@ private: } void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); @@ -422,7 +471,10 @@ private: } void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); applet_resource->GetController<Controller_NPad>(HidController::NPad) .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); @@ -431,7 +483,10 @@ private: } void ActivateNpad(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -440,8 +495,12 @@ private: void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto npad_id = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto unknown{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", + npad_id, applet_resource_user_id, unknown); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); @@ -451,8 +510,11 @@ private: void DisconnectNpad(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto npad_id = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); applet_resource->GetController<Controller_NPad>(HidController::NPad) .DisconnectNPad(npad_id); @@ -462,8 +524,9 @@ private: void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto npad_id = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); + const auto npad_id{rp.Pop<u32>()}; + + LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); @@ -474,8 +537,11 @@ private: void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto hold_type = rp.PopRaw<u64>(); - LOG_DEBUG(Service_HID, "called with hold_type={}", hold_type); + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto hold_type{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", + applet_resource_user_id, hold_type); auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); @@ -485,7 +551,10 @@ private: } void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); @@ -496,15 +565,21 @@ private: void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto npad_id = rp.PopRaw<u32>(); - LOG_WARNING(Service_HID, "(STUBBED) called with npad_id={}", npad_id); + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", + npad_id, applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); applet_resource->GetController<Controller_NPad>(HidController::NPad) .SetVibrationEnabled(true); @@ -523,9 +598,12 @@ private: void SendVibrationValue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto controller_id = rp.PopRaw<u32>(); - const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); - LOG_DEBUG(Service_HID, "called with controller_id={}", controller_id); + const auto controller_id{rp.Pop<u32>()}; + const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", + controller_id, applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -535,7 +613,10 @@ private: } void SendVibrationValues(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); const auto controllers = ctx.ReadBuffer(0); const auto vibrations = ctx.ReadBuffer(1); @@ -557,7 +638,12 @@ private: } void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto controller_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", + controller_id, applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); @@ -568,8 +654,11 @@ private: void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); @@ -579,7 +668,14 @@ private: } void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto unknown_1{rp.Pop<u32>()}; + const auto unknown_2{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", + unknown_1, unknown_2, applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -587,8 +683,11 @@ private: void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto mode = rp.PopRaw<u32>(); - LOG_WARNING(Service_HID, "(STUBBED) called with mode={}", mode); + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto mode{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", + applet_resource_user_id, mode); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -612,35 +711,55 @@ private: } void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto unknown{rp.Pop<u32>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}", + applet_resource_user_id, unknown); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 13bcefe07..9df7ac50f 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -318,14 +318,18 @@ public: return; } - ASSERT(process->MirrorMemory(*map_address, nro_addr, nro_size, - Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); - ASSERT(process->UnmapMemory(nro_addr, 0, nro_size) == RESULT_SUCCESS); + ASSERT(vm_manager + .MirrorMemory(*map_address, nro_addr, nro_size, + Kernel::MemoryState::ModuleCodeStatic) + .IsSuccess()); + ASSERT(vm_manager.UnmapRange(nro_addr, nro_size).IsSuccess()); if (bss_size > 0) { - ASSERT(process->MirrorMemory(*map_address + nro_size, bss_addr, bss_size, - Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); - ASSERT(process->UnmapMemory(bss_addr, 0, bss_size) == RESULT_SUCCESS); + ASSERT(vm_manager + .MirrorMemory(*map_address + nro_size, bss_addr, bss_size, + Kernel::MemoryState::ModuleCodeStatic) + .IsSuccess()); + ASSERT(vm_manager.UnmapRange(bss_addr, bss_size).IsSuccess()); } vm_manager.ReprotectRange(*map_address, header.text_size, @@ -380,13 +384,14 @@ public: return; } - auto* process = Core::CurrentProcess(); - auto& vm_manager = process->VMManager(); + auto& vm_manager = Core::CurrentProcess()->VMManager(); const auto& nro_size = iter->second.size; - ASSERT(process->MirrorMemory(heap_addr, mapped_addr, nro_size, - Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); - ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS); + ASSERT(vm_manager + .MirrorMemory(heap_addr, mapped_addr, nro_size, + Kernel::MemoryState::ModuleCodeStatic) + .IsSuccess()); + ASSERT(vm_manager.UnmapRange(mapped_addr, nro_size).IsSuccess()); Core::System::GetInstance().InvalidateCpuInstructionCaches(); diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index a7bed0040..2254fb46b 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -9,9 +9,9 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" -#include "core/hle/service/hid/hid.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nfp/nfp_user.h" diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 60b201d06..16564de24 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -264,14 +264,12 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Time, "called"); IPC::RequestParser rp{ctx}; - auto unknown_u8 = rp.PopRaw<u8>(); - - ClockSnapshot clock_snapshot{}; + const auto initial_type = rp.PopRaw<u8>(); const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch()) .count()}; - CalendarTime calendar_time{}; + const std::time_t time(time_since_epoch); const std::tm* tm = std::localtime(&time); if (tm == nullptr) { @@ -280,16 +278,19 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code return; } - SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / - 1000}; - LocationName location_name{"UTC"}; + const SteadyClockTimePoint steady_clock_time_point{ + CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000, {}}; + + CalendarTime calendar_time{}; calendar_time.year = tm->tm_year + 1900; calendar_time.month = tm->tm_mon + 1; calendar_time.day = tm->tm_mday; calendar_time.hour = tm->tm_hour; calendar_time.minute = tm->tm_min; calendar_time.second = tm->tm_sec; + + ClockSnapshot clock_snapshot{}; clock_snapshot.system_posix_time = time_since_epoch; clock_snapshot.network_posix_time = time_since_epoch; clock_snapshot.system_calendar_time = calendar_time; @@ -302,9 +303,10 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { clock_snapshot.network_calendar_info = additional_info; clock_snapshot.steady_clock_timepoint = steady_clock_time_point; - clock_snapshot.location_name = location_name; + clock_snapshot.location_name = LocationName{"UTC"}; clock_snapshot.clock_auto_adjustment_enabled = 1; - clock_snapshot.ipc_u8 = unknown_u8; + clock_snapshot.type = initial_type; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot)); diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index ea43fbea7..f11affe95 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -22,7 +22,6 @@ struct CalendarTime { u8 hour; u8 minute; u8 second; - INSERT_PADDING_BYTES(1); }; static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size"); @@ -30,7 +29,7 @@ struct CalendarAdditionalInfo { u32_le day_of_week; u32_le day_of_year; std::array<u8, 8> name; - INSERT_PADDING_BYTES(1); + u8 is_dst; s32_le utc_offset; }; static_assert(sizeof(CalendarAdditionalInfo) == 0x18, @@ -42,8 +41,10 @@ struct TimeZoneRule { }; struct SteadyClockTimePoint { + using SourceID = std::array<u8, 16>; + u64_le value; - INSERT_PADDING_WORDS(4); + SourceID source_id; }; static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); @@ -66,8 +67,9 @@ struct ClockSnapshot { SteadyClockTimePoint steady_clock_timepoint; LocationName location_name; u8 clock_auto_adjustment_enabled; - u8 ipc_u8; - INSERT_PADDING_BYTES(2); + u8 type; + u8 version; + INSERT_PADDING_BYTES(1); }; static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size"); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 311b0c765..a4c3a4753 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -19,6 +19,7 @@ #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" |