diff options
Diffstat (limited to 'src/core/hle')
26 files changed, 472 insertions, 211 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index ebf193930..57157beb4 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -39,7 +39,7 @@ static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) { const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); - const auto& thread_list = scheduler->GetThreadList(); + const auto& thread_list = scheduler.GetThreadList(); for (const auto& thread : thread_list) { if (thread->GetArbiterWaitAddress() == arb_addr) diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index e5fa67ae8..885259618 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -22,6 +22,7 @@ enum { HandleTableFull = 105, InvalidMemoryState = 106, InvalidMemoryPermissions = 108, + InvalidMemoryRange = 110, InvalidThreadPriority = 112, InvalidProcessorId = 113, InvalidHandle = 114, @@ -56,6 +57,7 @@ constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidA constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, ErrCodes::InvalidMemoryPermissions); +constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange); constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 98eb74298..bd680adfe 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -116,7 +116,7 @@ struct KernelCore::Impl { next_thread_id = 1; process_list.clear(); - current_process.reset(); + current_process = nullptr; handle_table.Clear(); resource_limits.fill(nullptr); @@ -207,7 +207,7 @@ struct KernelCore::Impl { // Lists all processes that exist in the current session. std::vector<SharedPtr<Process>> process_list; - SharedPtr<Process> current_process; + Process* current_process = nullptr; Kernel::HandleTable handle_table; std::array<SharedPtr<ResourceLimit>, 4> resource_limits; @@ -266,15 +266,15 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) { impl->process_list.push_back(std::move(process)); } -void KernelCore::MakeCurrentProcess(SharedPtr<Process> process) { - impl->current_process = std::move(process); +void KernelCore::MakeCurrentProcess(Process* process) { + impl->current_process = process; } -SharedPtr<Process>& KernelCore::CurrentProcess() { +Process* KernelCore::CurrentProcess() { return impl->current_process; } -const SharedPtr<Process>& KernelCore::CurrentProcess() const { +const Process* KernelCore::CurrentProcess() const { return impl->current_process; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c0771ecf0..41554821f 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -66,13 +66,13 @@ public: void AppendNewProcess(SharedPtr<Process> process); /// Makes the given process the new current process. - void MakeCurrentProcess(SharedPtr<Process> process); + void MakeCurrentProcess(Process* process); - /// Retrieves a reference to the current process. - SharedPtr<Process>& CurrentProcess(); + /// Retrieves a pointer to the current process. + Process* CurrentProcess(); - /// Retrieves a const reference to the current process. - const SharedPtr<Process>& CurrentProcess() const; + /// Retrieves a const pointer to the current process. + const Process* CurrentProcess() const; /// Adds a port to the named port table void AddNamedPort(std::string name, SharedPtr<ClientPort> port); diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index d51562d92..d87a62bb9 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -25,7 +25,6 @@ bool Object::IsWaitable() const { case HandleType::Process: case HandleType::AddressArbiter: case HandleType::ResourceLimit: - case HandleType::CodeSet: case HandleType::ClientPort: case HandleType::ClientSession: return false; diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 9eb72315c..c9f4d0bb3 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -26,7 +26,6 @@ enum class HandleType : u32 { AddressArbiter, Timer, ResourceLimit, - CodeSet, ClientPort, ServerPort, ClientSession, diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index fb0027a71..073dd5a7d 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -20,13 +20,7 @@ namespace Kernel { -SharedPtr<CodeSet> CodeSet::Create(KernelCore& kernel, std::string name) { - SharedPtr<CodeSet> codeset(new CodeSet(kernel)); - codeset->name = std::move(name); - return codeset; -} - -CodeSet::CodeSet(KernelCore& kernel) : Object{kernel} {} +CodeSet::CodeSet() = default; CodeSet::~CodeSet() = default; SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { @@ -159,11 +153,11 @@ void Process::PrepareForTermination() { } }; - auto& system = Core::System::GetInstance(); - stop_threads(system.Scheduler(0)->GetThreadList()); - stop_threads(system.Scheduler(1)->GetThreadList()); - stop_threads(system.Scheduler(2)->GetThreadList()); - stop_threads(system.Scheduler(3)->GetThreadList()); + const auto& system = Core::System::GetInstance(); + stop_threads(system.Scheduler(0).GetThreadList()); + stop_threads(system.Scheduler(1).GetThreadList()); + stop_threads(system.Scheduler(2).GetThreadList()); + stop_threads(system.Scheduler(3).GetThreadList()); } /** @@ -224,20 +218,20 @@ void Process::FreeTLSSlot(VAddr tls_address) { tls_slots[tls_page].reset(tls_slot); } -void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { +void Process::LoadModule(CodeSet module_, VAddr base_addr) { const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { - auto vma = vm_manager - .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset, - segment.size, memory_state) - .Unwrap(); + const auto vma = vm_manager + .MapMemoryBlock(segment.addr + base_addr, module_.memory, + segment.offset, segment.size, memory_state) + .Unwrap(); vm_manager.Reprotect(vma, permissions); }; // Map CodeSet segments - MapSegment(module_->CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); - MapSegment(module_->RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); - MapSegment(module_->DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); + MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); + MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); + MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); } ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 590e0c73d..f2816943a 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -24,6 +24,7 @@ class ProgramMetadata; namespace Kernel { class KernelCore; +class ResourceLimit; struct AddressMapping { // Address and size must be page-aligned @@ -57,30 +58,33 @@ union ProcessFlags { BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). }; -enum class ProcessStatus { Created, Running, Exited }; - -class ResourceLimit; +/** + * Indicates the status of a Process instance. + * + * @note These match the values as used by kernel, + * so new entries should only be added if RE + * shows that a new value has been introduced. + */ +enum class ProcessStatus { + Created, + CreatedWithDebuggerAttached, + Running, + WaitingForDebuggerToAttach, + DebuggerAttached, + Exiting, + Exited, + DebugBreak, +}; -struct CodeSet final : public Object { +struct CodeSet final { struct Segment { std::size_t offset = 0; VAddr addr = 0; u32 size = 0; }; - static SharedPtr<CodeSet> Create(KernelCore& kernel, std::string name); - - std::string GetTypeName() const override { - return "CodeSet"; - } - std::string GetName() const override { - return name; - } - - static const HandleType HANDLE_TYPE = HandleType::CodeSet; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } + explicit CodeSet(); + ~CodeSet(); Segment& CodeSegment() { return segments[0]; @@ -109,14 +113,7 @@ struct CodeSet final : public Object { std::shared_ptr<std::vector<u8>> memory; std::array<Segment, 3> segments; - VAddr entrypoint; - - /// Name of the process - std::string name; - -private: - explicit CodeSet(KernelCore& kernel); - ~CodeSet() override; + VAddr entrypoint = 0; }; class Process final : public Object { @@ -219,7 +216,7 @@ public: */ void PrepareForTermination(); - void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr); + void LoadModule(CodeSet module_, VAddr base_addr); /////////////////////////////////////////////////////////////////////////////////////////////// // Memory Management diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index cfd6e1bad..1342c597e 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -9,7 +9,7 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/core_timing.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" @@ -78,16 +78,16 @@ void Scheduler::SwitchContext(Thread* new_thread) { // Cancel any outstanding wakeup events for this thread new_thread->CancelWakeupTimer(); - auto previous_process = Core::CurrentProcess(); + auto* const previous_process = Core::CurrentProcess(); current_thread = new_thread; ready_queue.remove(new_thread->GetPriority(), new_thread); new_thread->SetStatus(ThreadStatus::Running); - const auto thread_owner_process = current_thread->GetOwnerProcess(); + auto* const thread_owner_process = current_thread->GetOwnerProcess(); if (previous_process != thread_owner_process) { - Core::CurrentProcess() = thread_owner_process; + Core::System::GetInstance().Kernel().MakeCurrentProcess(thread_owner_process); SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b488b508d..d08b84bde 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -39,6 +39,73 @@ namespace { constexpr bool Is4KBAligned(VAddr address) { return (address & 0xFFF) == 0; } + +// Checks if address + size is greater than the given address +// This can return false if the size causes an overflow of a 64-bit type +// or if the given size is zero. +constexpr bool IsValidAddressRange(VAddr address, u64 size) { + return address + size > address; +} + +// Checks if a given address range lies within a larger address range. +constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin, + VAddr address_range_end) { + const VAddr end_address = address + size - 1; + return address_range_begin <= address && end_address <= address_range_end - 1; +} + +bool IsInsideAddressSpace(const VMManager& vm, VAddr address, u64 size) { + return IsInsideAddressRange(address, size, vm.GetAddressSpaceBaseAddress(), + vm.GetAddressSpaceEndAddress()); +} + +bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) { + return IsInsideAddressRange(address, size, vm.GetNewMapRegionBaseAddress(), + vm.GetNewMapRegionEndAddress()); +} + +// 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) { + if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + + if (!IsValidAddressRange(dst_addr, size)) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (!IsValidAddressRange(src_addr, size)) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (!IsInsideNewMapRegion(vm_manager, 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) { + return ERR_INVALID_MEMORY_RANGE; + } + + if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && + vm_manager.GetMapRegionEndAddress() > dst_addr) { + return ERR_INVALID_MEMORY_RANGE; + } + + return RESULT_SUCCESS; +} } // Anonymous namespace /// Set the process heap to a given Size. It can both extend and shrink the heap. @@ -69,15 +136,15 @@ 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); - if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { - return ERR_INVALID_ADDRESS; - } + auto* const current_process = Core::CurrentProcess(); + const auto& vm_manager = current_process->VMManager(); - if (size == 0 || !Is4KBAligned(size)) { - return ERR_INVALID_SIZE; + const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); + if (result != RESULT_SUCCESS) { + return result; } - return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); + return current_process->MirrorMemory(dst_addr, src_addr, size); } /// Unmaps a region that was previously mapped with svcMapMemory @@ -85,15 +152,15 @@ 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); - if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { - return ERR_INVALID_ADDRESS; - } + auto* const current_process = Core::CurrentProcess(); + const auto& vm_manager = current_process->VMManager(); - if (size == 0 || !Is4KBAligned(size)) { - return ERR_INVALID_SIZE; + const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); + if (result != RESULT_SUCCESS) { + return result; } - return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); + return current_process->UnmapMemory(dst_addr, src_addr, size); } /// Connect to an OS service given the port name, returns the handle to the port to out @@ -303,15 +370,15 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) { struct BreakReason { union { - u64 raw; - BitField<31, 1, u64> dont_kill_application; + u32 raw; + BitField<31, 1, u32> signal_debugger; }; }; /// Break program execution -static void Break(u64 reason, u64 info1, u64 info2) { +static void Break(u32 reason, u64 info1, u64 info2) { BreakReason break_reason{reason}; - if (break_reason.dont_kill_application) { + if (break_reason.signal_debugger) { LOG_ERROR( Debug_Emulated, "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", @@ -322,6 +389,12 @@ static void Break(u64 reason, u64 info1, u64 info2) { "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", reason, info1, info2); ASSERT(false); + + Core::CurrentProcess()->PrepareForTermination(); + + // Kill the current thread + GetCurrentThread()->Stop(); + Core::System::GetInstance().PrepareReschedule(); } } @@ -341,7 +414,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, info_sub_id, handle); - const auto& current_process = Core::CurrentProcess(); + const auto* current_process = Core::CurrentProcess(); const auto& vm_manager = current_process->VMManager(); switch (static_cast<GetInfoType>(info_id)) { @@ -375,25 +448,12 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) case GetInfoType::RandomEntropy: *result = 0; break; - case GetInfoType::AddressSpaceBaseAddr: - *result = vm_manager.GetCodeRegionBaseAddress(); + case GetInfoType::ASLRRegionBaseAddr: + *result = vm_manager.GetASLRRegionBaseAddress(); break; - case GetInfoType::AddressSpaceSize: { - const u64 width = vm_manager.GetAddressSpaceWidth(); - - switch (width) { - case 32: - *result = 0xFFE00000; - break; - case 36: - *result = 0xFF8000000; - break; - case 39: - *result = 0x7FF8000000; - break; - } + case GetInfoType::ASLRRegionSize: + *result = vm_manager.GetASLRRegionSize(); break; - } case GetInfoType::NewMapRegionBaseAddr: *result = vm_manager.GetNewMapRegionBaseAddress(); break; @@ -439,7 +499,7 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { return ERR_INVALID_HANDLE; } - const auto current_process = Core::CurrentProcess(); + const auto* current_process = Core::CurrentProcess(); if (thread->GetOwnerProcess() != current_process) { return ERR_INVALID_HANDLE; } @@ -531,7 +591,7 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s return ERR_INVALID_HANDLE; } - return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, + return shared_memory->Map(Core::CurrentProcess(), addr, permissions_type, MemoryPermission::DontCare); } @@ -550,7 +610,7 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 auto& kernel = Core::System::GetInstance().Kernel(); auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); - return shared_memory->Unmap(Core::CurrentProcess().get(), addr); + return shared_memory->Unmap(Core::CurrentProcess(), addr); } /// Query process memory @@ -588,7 +648,7 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd /// Exits the current process static void ExitProcess() { - auto& current_process = Core::CurrentProcess(); + auto* current_process = Core::CurrentProcess(); LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running, @@ -636,7 +696,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V auto& kernel = Core::System::GetInstance().Kernel(); CASCADE_RESULT(SharedPtr<Thread> thread, Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top, - Core::CurrentProcess())); + *Core::CurrentProcess())); const auto new_guest_handle = kernel.HandleTable().Create(thread); if (new_guest_handle.Failed()) { return new_guest_handle.Code(); @@ -736,7 +796,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) { const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); - const auto& thread_list = scheduler->GetThreadList(); + const auto& thread_list = scheduler.GetThreadList(); for (const auto& thread : thread_list) { if (thread->GetCondVarWaitAddress() == condvar_addr) @@ -1025,6 +1085,29 @@ static ResultCode ClearEvent(Handle handle) { return RESULT_SUCCESS; } +static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); + + // This function currently only allows retrieving a process' status. + enum class InfoType { + Status, + }; + + const auto& kernel = Core::System::GetInstance().Kernel(); + const auto process = kernel.HandleTable().Get<Process>(process_handle); + if (!process) { + return ERR_INVALID_HANDLE; + } + + const auto info_type = static_cast<InfoType>(type); + if (info_type != InfoType::Status) { + return ERR_INVALID_ENUM_VALUE; + } + + *out = static_cast<u64>(process->GetStatus()); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(); @@ -1160,7 +1243,7 @@ static const FunctionDef SVC_Table[] = { {0x79, nullptr, "CreateProcess"}, {0x7A, nullptr, "StartProcess"}, {0x7B, nullptr, "TerminateProcess"}, - {0x7C, nullptr, "GetProcessInfo"}, + {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, {0x7D, nullptr, "CreateResourceLimit"}, {0x7E, nullptr, "SetResourceLimitLimitValue"}, {0x7F, nullptr, "CallSecureMonitor"}, diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h index 70148c4fe..554a5e328 100644 --- a/src/core/hle/kernel/svc.h +++ b/src/core/hle/kernel/svc.h @@ -41,8 +41,8 @@ enum class GetInfoType : u64 { RandomEntropy = 11, PerformanceCounter = 0xF0000002, // 2.0.0+ - AddressSpaceBaseAddr = 12, - AddressSpaceSize = 13, + ASLRRegionBaseAddr = 12, + ASLRRegionSize = 13, NewMapRegionBaseAddr = 14, NewMapRegionSize = 15, // 3.0.0+ diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 22712e64f..b09753c80 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -35,18 +35,18 @@ void SvcWrap() { template <ResultCode func(u32)> void SvcWrap() { - FuncReturn(func((u32)Param(0)).raw); + FuncReturn(func(static_cast<u32>(Param(0))).raw); } template <ResultCode func(u32, u32)> void SvcWrap() { - FuncReturn(func((u32)Param(0), (u32)Param(1)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); } template <ResultCode func(u32*, u32)> void SvcWrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, (u32)Param(1)).raw; + u32 retval = func(¶m_1, static_cast<u32>(Param(1))).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -61,7 +61,7 @@ void SvcWrap() { template <ResultCode func(u64, s32)> void SvcWrap() { - FuncReturn(func(Param(0), (s32)Param(1)).raw); + FuncReturn(func(Param(0), static_cast<s32>(Param(1))).raw); } template <ResultCode func(u64, u32)> @@ -77,21 +77,29 @@ void SvcWrap() { FuncReturn(retval); } +template <ResultCode func(u64*, u32, u32)> +void SvcWrap() { + u64 param_1 = 0; + u32 retval = func(¶m_1, static_cast<u32>(Param(1)), static_cast<u32>(Param(2))).raw; + Core::CurrentArmInterface().SetReg(1, param_1); + FuncReturn(retval); +} + template <ResultCode func(u32, u64)> void SvcWrap() { - FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), Param(1)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), Param(1)).raw); } template <ResultCode func(u32, u32, u64)> void SvcWrap() { - FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), (u32)(Param(1) & 0xFFFFFFFF), Param(2)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1)), Param(2)).raw); } template <ResultCode func(u32, u32*, u64*)> void SvcWrap() { u32 param_1 = 0; u64 param_2 = 0; - ResultCode retval = func((u32)(Param(2) & 0xFFFFFFFF), ¶m_1, ¶m_2); + ResultCode retval = func(static_cast<u32>(Param(2)), ¶m_1, ¶m_2); Core::CurrentArmInterface().SetReg(1, param_1); Core::CurrentArmInterface().SetReg(2, param_2); FuncReturn(retval.raw); @@ -100,12 +108,12 @@ void SvcWrap() { template <ResultCode func(u64, u64, u32, u32)> void SvcWrap() { FuncReturn( - func(Param(0), Param(1), (u32)(Param(3) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw); + func(Param(0), Param(1), static_cast<u32>(Param(3)), static_cast<u32>(Param(3))).raw); } template <ResultCode func(u32, u64, u32)> void SvcWrap() { - FuncReturn(func((u32)Param(0), Param(1), (u32)Param(2)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw); } template <ResultCode func(u64, u64, u64)> @@ -115,25 +123,28 @@ void SvcWrap() { template <ResultCode func(u32, u64, u64, u32)> void SvcWrap() { - FuncReturn(func((u32)Param(0), Param(1), Param(2), (u32)Param(3)).raw); + FuncReturn( + func(static_cast<u32>(Param(0)), Param(1), Param(2), static_cast<u32>(Param(3))).raw); } template <ResultCode func(u32, u64, u64)> void SvcWrap() { - FuncReturn(func((u32)Param(0), Param(1), Param(2)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), Param(1), Param(2)).raw); } template <ResultCode func(u32*, u64, u64, s64)> void SvcWrap() { u32 param_1 = 0; - ResultCode retval = func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (s64)Param(3)); + ResultCode retval = + func(¶m_1, Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))); Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval.raw); } template <ResultCode func(u64, u64, u32, s64)> void SvcWrap() { - FuncReturn(func(Param(0), Param(1), (u32)Param(2), (s64)Param(3)).raw); + FuncReturn( + func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))).raw); } template <ResultCode func(u64*, u64, u64, u64)> @@ -147,9 +158,9 @@ void SvcWrap() { template <ResultCode func(u32*, u64, u64, u64, u32, s32)> void SvcWrap() { u32 param_1 = 0; - u32 retval = - func(¶m_1, Param(1), Param(2), Param(3), (u32)Param(4), (s32)(Param(5) & 0xFFFFFFFF)) - .raw; + u32 retval = func(¶m_1, Param(1), Param(2), Param(3), static_cast<u32>(Param(4)), + static_cast<s32>(Param(5))) + .raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -172,7 +183,7 @@ void SvcWrap() { template <ResultCode func(u32*, u64, u64, u32)> void SvcWrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, Param(1), Param(2), (u32)(Param(3) & 0xFFFFFFFF)).raw; + u32 retval = func(¶m_1, Param(1), Param(2), static_cast<u32>(Param(3))).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -181,22 +192,22 @@ template <ResultCode func(Handle*, u64, u32, u32)> void SvcWrap() { u32 param_1 = 0; u32 retval = - func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw; + func(¶m_1, Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } template <ResultCode func(u64, u32, s32, s64)> void SvcWrap() { - FuncReturn( - func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), (s64)Param(3)) - .raw); + FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)), + static_cast<s64>(Param(3))) + .raw); } template <ResultCode func(u64, u32, s32, s32)> void SvcWrap() { - FuncReturn(func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), - (s32)(Param(3) & 0xFFFFFFFF)) + FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)), + static_cast<s32>(Param(3))) .raw); } @@ -226,7 +237,7 @@ void SvcWrap() { template <void func(s64)> void SvcWrap() { - func((s64)Param(0)); + func(static_cast<s64>(Param(0))); } template <void func(u64, u64 len)> @@ -239,4 +250,9 @@ void SvcWrap() { func(Param(0), Param(1), Param(2)); } +template <void func(u32, u64, u64)> +void SvcWrap() { + func(static_cast<u32>(Param(0)), Param(1), Param(2)); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8e514cf9a..35ec98c1a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -97,7 +97,7 @@ void Thread::CancelWakeupTimer() { static boost::optional<s32> GetNextProcessorId(u64 mask) { for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) { if (mask & (1ULL << index)) { - if (!Core::System::GetInstance().Scheduler(index)->GetCurrentThread()) { + if (!Core::System::GetInstance().Scheduler(index).GetCurrentThread()) { // Core is enabled and not running any threads, use this one return index; } @@ -147,14 +147,14 @@ void Thread::ResumeFromWait() { new_processor_id = processor_id; } if (ideal_core != -1 && - Core::System::GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) { + Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) { new_processor_id = ideal_core; } ASSERT(*new_processor_id < 4); // Add thread to new core's scheduler - auto& next_scheduler = Core::System::GetInstance().Scheduler(*new_processor_id); + auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id); if (*new_processor_id != processor_id) { // Remove thread from previous core's scheduler @@ -169,7 +169,7 @@ void Thread::ResumeFromWait() { next_scheduler->ScheduleThread(this, current_priority); // Change thread's scheduler - scheduler = next_scheduler.get(); + scheduler = next_scheduler; Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); } @@ -183,18 +183,15 @@ void Thread::ResumeFromWait() { */ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAddr stack_top, VAddr entry_point, u64 arg) { - memset(&context, 0, sizeof(Core::ARM_Interface::ThreadContext)); - + context = {}; context.cpu_registers[0] = arg; context.pc = entry_point; context.sp = stack_top; - context.pstate = 0; - context.fpcr = 0; } ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point, u32 priority, u64 arg, s32 processor_id, - VAddr stack_top, SharedPtr<Process> owner_process) { + VAddr stack_top, Process& owner_process) { // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > THREADPRIO_LOWEST) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); @@ -208,7 +205,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name // TODO(yuriks): Other checks, returning 0xD9001BEA - if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { + if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) { LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); // TODO (bunnei): Find the correct error code to use here return ResultCode(-1); @@ -232,8 +229,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name thread->wait_handle = 0; thread->name = std::move(name); thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); - thread->owner_process = owner_process; - thread->scheduler = Core::System::GetInstance().Scheduler(processor_id).get(); + thread->owner_process = &owner_process; + thread->scheduler = &Core::System::GetInstance().Scheduler(processor_id); thread->scheduler->AddThread(thread, priority); thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread); @@ -264,7 +261,7 @@ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri // 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); + stack_top, owner_process); SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); @@ -378,14 +375,14 @@ void Thread::ChangeCore(u32 core, u64 mask) { new_processor_id = processor_id; } if (ideal_core != -1 && - Core::System::GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) { + Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) { new_processor_id = ideal_core; } ASSERT(*new_processor_id < 4); // Add thread to new core's scheduler - auto& next_scheduler = Core::System::GetInstance().Scheduler(*new_processor_id); + auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id); if (*new_processor_id != processor_id) { // Remove thread from previous core's scheduler @@ -400,7 +397,7 @@ void Thread::ChangeCore(u32 core, u64 mask) { next_scheduler->ScheduleThread(this, current_priority); // Change thread's scheduler - scheduler = next_scheduler.get(); + scheduler = next_scheduler; Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c6ffbd28c..f4d7bd235 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -89,7 +89,7 @@ public: static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name, VAddr entry_point, u32 priority, u64 arg, s32 processor_id, VAddr stack_top, - SharedPtr<Process> owner_process); + Process& owner_process); std::string GetName() const override { return name; @@ -262,11 +262,11 @@ public: return processor_id; } - SharedPtr<Process>& GetOwnerProcess() { + Process* GetOwnerProcess() { return owner_process; } - const SharedPtr<Process>& GetOwnerProcess() const { + const Process* GetOwnerProcess() const { return owner_process; } @@ -386,7 +386,7 @@ private: u64 tpidr_el0 = 0; ///< TPIDR_EL0 read/write system register. /// Process that owns this thread - SharedPtr<Process> owner_process; + Process* owner_process; /// Objects that the thread is waiting on, in the same order as they were /// passed to WaitSynchronization1/N. diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index e412309fd..1e28ccbda 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -393,30 +393,35 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty switch (type) { case FileSys::ProgramAddressSpaceType::Is32Bit: + case FileSys::ProgramAddressSpaceType::Is32BitNoMap: address_space_width = 32; code_region_base = 0x200000; code_region_end = code_region_base + 0x3FE00000; - map_region_size = 0x40000000; - heap_region_size = 0x40000000; + aslr_region_base = 0x200000; + aslr_region_end = aslr_region_base + 0xFFE00000; + if (type == FileSys::ProgramAddressSpaceType::Is32Bit) { + map_region_size = 0x40000000; + heap_region_size = 0x40000000; + } else { + map_region_size = 0; + heap_region_size = 0x80000000; + } break; case FileSys::ProgramAddressSpaceType::Is36Bit: address_space_width = 36; code_region_base = 0x8000000; code_region_end = code_region_base + 0x78000000; + aslr_region_base = 0x8000000; + aslr_region_end = aslr_region_base + 0xFF8000000; map_region_size = 0x180000000; heap_region_size = 0x180000000; break; - case FileSys::ProgramAddressSpaceType::Is32BitNoMap: - address_space_width = 32; - code_region_base = 0x200000; - code_region_end = code_region_base + 0x3FE00000; - map_region_size = 0; - heap_region_size = 0x80000000; - break; case FileSys::ProgramAddressSpaceType::Is39Bit: address_space_width = 39; code_region_base = 0x8000000; code_region_end = code_region_base + 0x80000000; + aslr_region_base = 0x8000000; + aslr_region_end = aslr_region_base + 0x7FF8000000; map_region_size = 0x1000000000; heap_region_size = 0x180000000; new_map_region_size = 0x80000000; @@ -490,6 +495,18 @@ u64 VMManager::GetAddressSpaceWidth() const { return address_space_width; } +VAddr VMManager::GetASLRRegionBaseAddress() const { + return aslr_region_base; +} + +VAddr VMManager::GetASLRRegionEndAddress() const { + return aslr_region_end; +} + +u64 VMManager::GetASLRRegionSize() const { + return aslr_region_end - aslr_region_base; +} + VAddr VMManager::GetCodeRegionBaseAddress() const { return code_region_base; } diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 015559a64..4accde6b3 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -205,6 +205,15 @@ public: /// Gets the address space width in bits. u64 GetAddressSpaceWidth() const; + /// Gets the base address of the ASLR region. + VAddr GetASLRRegionBaseAddress() const; + + /// Gets the end address of the ASLR region. + VAddr GetASLRRegionEndAddress() const; + + /// Gets the size of the ASLR region + u64 GetASLRRegionSize() const; + /// Gets the base address of the code region. VAddr GetCodeRegionBaseAddress() const; @@ -306,6 +315,9 @@ private: VAddr address_space_base = 0; VAddr address_space_end = 0; + VAddr aslr_region_base = 0; + VAddr aslr_region_end = 0; + VAddr code_region_base = 0; VAddr code_region_end = 0; diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 0ecfb5af1..518161bf7 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -7,8 +7,10 @@ #include <vector> #include "common/logging/log.h" #include "core/file_sys/content_archive.h" +#include "core/file_sys/control_metadata.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/partition_filesystem.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/process.h" @@ -19,7 +21,7 @@ namespace Service::AOC { constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; -constexpr u64 DLC_BASE_TO_AOC_ID_MASK = 0x1000; +constexpr u64 DLC_BASE_TO_AOC_ID = 0x1000; static bool CheckAOCTitleIDMatchesBase(u64 base, u64 aoc) { return (aoc & DLC_BASE_TITLE_ID_MASK) == base; @@ -97,14 +99,24 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { ctx.WriteBuffer(out); - IPC::ResponseBuilder rb{ctx, 2}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); + rb.Push(count); } void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push(Core::System::GetInstance().CurrentProcess()->GetTitleID() | DLC_BASE_TO_AOC_ID_MASK); + const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + FileSys::PatchManager pm{title_id}; + + const auto res = pm.GetControlMetadata(); + if (res.first == nullptr) { + rb.Push(title_id + DLC_BASE_TO_AOC_ID); + return; + } + + rb.Push(res.first->GetDLCBaseTitleId()); } void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index fc6067e59..7168c6a10 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -2,8 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <chrono> #include <cstring> #include <memory> +#include <optional> #include <vector> #include <opus.h> @@ -33,7 +35,8 @@ public: {1, nullptr, "SetContext"}, {2, nullptr, "DecodeInterleavedForMultiStream"}, {3, nullptr, "SetContextForMultiStream"}, - {4, nullptr, "Unknown4"}, + {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerformance, + "DecodeInterleavedWithPerformance"}, {5, nullptr, "Unknown5"}, {6, nullptr, "Unknown6"}, {7, nullptr, "Unknown7"}, @@ -59,8 +62,31 @@ private: ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); } - bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input, - std::vector<opus_int16>& output) { + void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) { + u32 consumed = 0; + u32 sample_count = 0; + u64 performance = 0; + std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); + if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples, + performance)) { + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(ogniK): Use correct error code + rb.Push(ResultCode(-1)); + return; + } + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(consumed); + rb.Push<u64>(performance); + rb.Push<u32>(sample_count); + ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); + } + + bool Decoder_DecodeInterleaved( + u32& consumed, u32& sample_count, const std::vector<u8>& input, + std::vector<opus_int16>& output, + std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) { + const auto start_time = std::chrono::high_resolution_clock::now(); std::size_t raw_output_sz = output.size() * sizeof(opus_int16); if (sizeof(OpusHeader) > input.size()) return false; @@ -80,8 +106,13 @@ private: (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0); if (out_sample_count < 0) return false; + const auto end_time = std::chrono::high_resolution_clock::now() - start_time; sample_count = out_sample_count; consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); + if (performance_time.has_value()) { + performance_time->get() = + std::chrono::duration_cast<std::chrono::milliseconds>(end_time).count(); + } return true; } diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 439e62d27..e32a7c48e 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -319,13 +319,12 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() { return sdmc_factory->Open(); } -std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { - return std::make_shared<FileSys::RegisteredCacheUnion>( - std::vector<std::shared_ptr<FileSys::RegisteredCache>>{ - GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}); +std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { + return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{ + GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}); } -std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() { +FileSys::RegisteredCache* GetSystemNANDContents() { LOG_TRACE(Service_FS, "Opening System NAND Contents"); if (bis_factory == nullptr) @@ -334,7 +333,7 @@ std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() { return bis_factory->GetSystemNANDContents(); } -std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents() { +FileSys::RegisteredCache* GetUserNANDContents() { LOG_TRACE(Service_FS, "Opening User NAND Contents"); if (bis_factory == nullptr) @@ -343,7 +342,7 @@ std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents() { return bis_factory->GetUserNANDContents(); } -std::shared_ptr<FileSys::RegisteredCache> GetSDMCContents() { +FileSys::RegisteredCache* GetSDMCContents() { LOG_TRACE(Service_FS, "Opening SDMC Contents"); if (sdmc_factory == nullptr) @@ -361,19 +360,19 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) { return bis_factory->GetModificationLoadRoot(title_id); } -void CreateFactories(const FileSys::VirtualFilesystem& vfs, bool overwrite) { +void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { if (overwrite) { bis_factory = nullptr; save_data_factory = nullptr; sdmc_factory = nullptr; } - auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), - FileSys::Mode::ReadWrite); - auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), - FileSys::Mode::ReadWrite); - auto load_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), - FileSys::Mode::ReadWrite); + auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), + FileSys::Mode::ReadWrite); + auto sd_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), + FileSys::Mode::ReadWrite); + auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), + FileSys::Mode::ReadWrite); if (bis_factory == nullptr) bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory); @@ -383,7 +382,7 @@ void CreateFactories(const FileSys::VirtualFilesystem& vfs, bool overwrite) { sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); } -void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) { +void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { romfs_factory = nullptr; CreateFactories(vfs, false); std::make_shared<FSP_LDR>()->InstallAsService(service_manager); diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 53b01bb01..6ca5c5636 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -47,19 +47,19 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct); ResultVal<FileSys::VirtualDir> OpenSDMC(); -std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); +std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); -std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents(); -std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents(); -std::shared_ptr<FileSys::RegisteredCache> GetSDMCContents(); +FileSys::RegisteredCache* GetSystemNANDContents(); +FileSys::RegisteredCache* GetUserNANDContents(); +FileSys::RegisteredCache* GetSDMCContents(); FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function // above is called. -void CreateFactories(const FileSys::VirtualFilesystem& vfs, bool overwrite = true); +void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); -void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs); +void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs); // A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of // pointers and booleans. This makes using a VfsDirectory with switch services much easier and diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 4b2f758a8..44accecb7 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -161,7 +161,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { }; RegisterHandlers(functions); // Attempt to load shared font data from disk - const auto nand = FileSystem::GetSystemNANDContents(); + const auto* nand = FileSystem::GetSystemNANDContents(); std::size_t offset = 0; // Rebuild shared fonts from data ncas if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 7555bbe7d..c41ef7058 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -15,6 +15,11 @@ #include "video_core/renderer_base.h" namespace Service::Nvidia::Devices { +namespace NvErrCodes { +enum { + InvalidNmapHandle = -22, +}; +} nvhost_as_gpu::nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} nvhost_as_gpu::~nvhost_as_gpu() = default; @@ -79,14 +84,16 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) std::memcpy(entries.data(), input.data(), input.size()); auto& gpu = Core::System::GetInstance().GPU(); - for (const auto& entry : entries) { LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", entry.offset, entry.nvmap_handle, entry.pages); Tegra::GPUVAddr offset = static_cast<Tegra::GPUVAddr>(entry.offset) << 0x10; - auto object = nvmap_dev->GetObject(entry.nvmap_handle); - ASSERT(object); + if (!object) { + LOG_CRITICAL(Service_NVDRV, "nvmap {} is an invalid handle!", entry.nvmap_handle); + std::memcpy(output.data(), entries.data(), output.size()); + return static_cast<u32>(NvErrCodes::InvalidNmapHandle); + } ASSERT(object->status == nvmap::Object::Status::Allocated); @@ -167,10 +174,11 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou auto& system_instance = Core::System::GetInstance(); // Remove this memory region from the rasterizer cache. - system_instance.Renderer().Rasterizer().FlushAndInvalidateRegion(params.offset, - itr->second.size); - auto& gpu = system_instance.GPU(); + auto cpu_addr = gpu.MemoryManager().GpuToCpuAddress(params.offset); + ASSERT(cpu_addr); + system_instance.Renderer().Rasterizer().FlushAndInvalidateRegion(*cpu_addr, itr->second.size); + params.offset = gpu.MemoryManager().UnmapBuffer(params.offset, itr->second.size); buffer_mappings.erase(itr->second.offset); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index a2287cc1b..43651d8a6 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -11,6 +11,13 @@ namespace Service::Nvidia::Devices { +namespace NvErrCodes { +enum { + OperationNotPermitted = -1, + InvalidValue = -22, +}; +} + nvmap::nvmap() = default; nvmap::~nvmap() = default; @@ -44,7 +51,11 @@ u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& o u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { IocCreateParams params; std::memcpy(¶ms, input.data(), sizeof(params)); + LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); + if (!params.size) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } // Create a new nvmap object and obtain a handle to it. auto object = std::make_shared<Object>(); object->id = next_id++; @@ -55,8 +66,6 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { u32 handle = next_handle++; handles[handle] = std::move(object); - LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); - params.handle = handle; std::memcpy(output.data(), ¶ms, sizeof(params)); @@ -66,9 +75,29 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { IocAllocParams params; std::memcpy(¶ms, input.data(), sizeof(params)); + LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); + + if (!params.handle) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } + + if ((params.align - 1) & params.align) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } + + const u32 min_alignment = 0x1000; + if (params.align < min_alignment) { + params.align = min_alignment; + } auto object = GetObject(params.handle); - ASSERT(object); + if (!object) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } + + if (object->status == Object::Status::Allocated) { + return static_cast<u32>(NvErrCodes::OperationNotPermitted); + } object->flags = params.flags; object->align = params.align; @@ -76,8 +105,6 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { object->addr = params.addr; object->status = Object::Status::Allocated; - LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); - std::memcpy(output.data(), ¶ms, sizeof(params)); return 0; } @@ -88,8 +115,14 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { LOG_WARNING(Service_NVDRV, "called"); + if (!params.handle) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } + auto object = GetObject(params.handle); - ASSERT(object); + if (!object) { + return static_cast<u32>(NvErrCodes::OperationNotPermitted); + } params.id = object->id; @@ -105,7 +138,14 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { auto itr = std::find_if(handles.begin(), handles.end(), [&](const auto& entry) { return entry.second->id == params.id; }); - ASSERT(itr != handles.end()); + if (itr == handles.end()) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } + + auto& object = itr->second; + if (object->status != Object::Status::Allocated) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } itr->second->refcount++; @@ -125,8 +165,13 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param); auto object = GetObject(params.handle); - ASSERT(object); - ASSERT(object->status == Object::Status::Allocated); + if (!object) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } + + if (object->status != Object::Status::Allocated) { + return static_cast<u32>(NvErrCodes::OperationNotPermitted); + } switch (static_cast<ParamTypes>(params.param)) { case ParamTypes::Size: @@ -163,9 +208,12 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); auto itr = handles.find(params.handle); - ASSERT(itr != handles.end()); - - ASSERT(itr->second->refcount > 0); + if (itr == handles.end()) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } + if (!itr->second->refcount) { + return static_cast<u32>(NvErrCodes::InvalidValue); + } itr->second->refcount--; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 62f049660..a225cb4cb 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -197,7 +197,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co // Module interface /// Initialize ServiceManager -void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesystem& rfs) { +void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs) { // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it // here and pass it into the respective InstallInterfaces functions. auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); @@ -220,7 +220,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesys EUPLD::InstallInterfaces(*sm); Fatal::InstallInterfaces(*sm); FGM::InstallInterfaces(*sm); - FileSystem::InstallInterfaces(*sm, rfs); + FileSystem::InstallInterfaces(*sm, vfs); Friend::InstallInterfaces(*sm); GRC::InstallInterfaces(*sm); HID::InstallInterfaces(*sm); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 2fc57a82e..98483ecf1 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -180,8 +180,7 @@ private: }; /// Initialize ServiceManager -void Init(std::shared_ptr<SM::ServiceManager>& sm, - const std::shared_ptr<FileSys::VfsFilesystem>& vfs); +void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs); /// Shutdown ServiceManager void Shutdown(); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index bbc02abcc..184537daa 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -968,6 +968,54 @@ private: rb.PushCopyObjects(vsync_event); } + enum class ConvertedScaleMode : u64 { + None = 0, // VI seems to name this as "Unknown" but lots of games pass it, assume it's no + // scaling/default + Freeze = 1, + ScaleToWindow = 2, + Crop = 3, + NoCrop = 4, + }; + + // This struct is different, currently it's 1:1 but this might change in the future. + enum class NintendoScaleMode : u32 { + None = 0, + Freeze = 1, + ScaleToWindow = 2, + Crop = 3, + NoCrop = 4, + }; + + void ConvertScalingMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto mode = rp.PopEnum<NintendoScaleMode>(); + LOG_DEBUG(Service_VI, "called mode={}", static_cast<u32>(mode)); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + switch (mode) { + case NintendoScaleMode::None: + rb.PushEnum(ConvertedScaleMode::None); + break; + case NintendoScaleMode::Freeze: + rb.PushEnum(ConvertedScaleMode::Freeze); + break; + case NintendoScaleMode::ScaleToWindow: + rb.PushEnum(ConvertedScaleMode::ScaleToWindow); + break; + case NintendoScaleMode::Crop: + rb.PushEnum(ConvertedScaleMode::Crop); + break; + case NintendoScaleMode::NoCrop: + rb.PushEnum(ConvertedScaleMode::NoCrop); + break; + default: + UNIMPLEMENTED_MSG("Unknown scaling mode {}", static_cast<u32>(mode)); + rb.PushEnum(ConvertedScaleMode::None); + break; + } + } + std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; }; @@ -991,7 +1039,7 @@ IApplicationDisplayService::IApplicationDisplayService( {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"}, {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"}, {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"}, - {2102, nullptr, "ConvertScalingMode"}, + {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"}, {2450, nullptr, "GetIndirectLayerImageMap"}, {2451, nullptr, "GetIndirectLayerImageCropMap"}, {2460, nullptr, "GetIndirectLayerImageRequiredMemoryInfo"}, |
