diff options
Diffstat (limited to 'src/core/hle')
25 files changed, 645 insertions, 99 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp new file mode 100644 index 000000000..e9c8369d7 --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -0,0 +1,173 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/core.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/thread.h" +#include "core/hle/lock.h" +#include "core/memory.h" + +namespace Kernel { +namespace AddressArbiter { + +// Performs actual address waiting logic. +static ResultCode WaitForAddress(VAddr address, s64 timeout) { + SharedPtr<Thread> current_thread = GetCurrentThread(); + current_thread->arb_wait_address = address; + current_thread->status = THREADSTATUS_WAIT_ARB; + current_thread->wakeup_callback = nullptr; + + current_thread->WakeAfterDelay(timeout); + + Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); + return RESULT_TIMEOUT; +} + +// Gets the threads waiting on an address. +static void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_threads, + VAddr address) { + auto RetrieveWaitingThreads = + [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) { + const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); + auto& thread_list = scheduler->GetThreadList(); + + for (auto& thread : thread_list) { + if (thread->arb_wait_address == arb_addr) + waiting_threads.push_back(thread); + } + }; + + // Retrieve a list of all threads that are waiting for this address. + RetrieveWaitingThreads(0, waiting_threads, address); + RetrieveWaitingThreads(1, waiting_threads, address); + RetrieveWaitingThreads(2, waiting_threads, address); + RetrieveWaitingThreads(3, waiting_threads, address); + // Sort them by priority, such that the highest priority ones come first. + std::sort(waiting_threads.begin(), waiting_threads.end(), + [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { + return lhs->current_priority < rhs->current_priority; + }); +} + +// Wake up num_to_wake (or all) threads in a vector. +static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { + // Only process up to 'target' threads, unless 'target' is <= 0, in which case process + // them all. + size_t last = waiting_threads.size(); + if (num_to_wake > 0) + last = num_to_wake; + + // Signal the waiting threads. + for (size_t i = 0; i < last; i++) { + ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB); + waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); + waiting_threads[i]->arb_wait_address = 0; + waiting_threads[i]->ResumeFromWait(); + } +} + +// Signals an address being waited on. +ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { + // Get threads waiting on the address. + std::vector<SharedPtr<Thread>> waiting_threads; + GetThreadsWaitingOnAddress(waiting_threads, address); + + WakeThreads(waiting_threads, num_to_wake); + return RESULT_SUCCESS; +} + +// Signals an address being waited on and increments its value if equal to the value argument. +ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + // Ensure that we can write to the address. + if (!Memory::IsValidVirtualAddress(address)) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (static_cast<s32>(Memory::Read32(address)) == value) { + Memory::Write32(address, static_cast<u32>(value + 1)); + } else { + return ERR_INVALID_STATE; + } + + return SignalToAddress(address, num_to_wake); +} + +// Signals an address being waited on and modifies its value based on waiting thread count if equal +// to the value argument. +ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, + s32 num_to_wake) { + // Ensure that we can write to the address. + if (!Memory::IsValidVirtualAddress(address)) { + return ERR_INVALID_ADDRESS_STATE; + } + + // Get threads waiting on the address. + std::vector<SharedPtr<Thread>> waiting_threads; + GetThreadsWaitingOnAddress(waiting_threads, address); + + // Determine the modified value depending on the waiting count. + s32 updated_value; + if (waiting_threads.size() == 0) { + updated_value = value - 1; + } else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) { + updated_value = value + 1; + } else { + updated_value = value; + } + + if (static_cast<s32>(Memory::Read32(address)) == value) { + Memory::Write32(address, static_cast<u32>(updated_value)); + } else { + return ERR_INVALID_STATE; + } + + WakeThreads(waiting_threads, num_to_wake); + return RESULT_SUCCESS; +} + +// Waits on an address if the value passed is less than the argument value, optionally decrementing. +ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { + // Ensure that we can read the address. + if (!Memory::IsValidVirtualAddress(address)) { + return ERR_INVALID_ADDRESS_STATE; + } + + s32 cur_value = static_cast<s32>(Memory::Read32(address)); + if (cur_value < value) { + Memory::Write32(address, static_cast<u32>(cur_value - 1)); + } else { + return ERR_INVALID_STATE; + } + // Short-circuit without rescheduling, if timeout is zero. + if (timeout == 0) { + return RESULT_TIMEOUT; + } + + return WaitForAddress(address, timeout); +} + +// Waits on an address if the value passed is equal to the argument value. +ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { + // Ensure that we can read the address. + if (!Memory::IsValidVirtualAddress(address)) { + return ERR_INVALID_ADDRESS_STATE; + } + // Only wait for the address if equal. + if (static_cast<s32>(Memory::Read32(address)) != value) { + return ERR_INVALID_STATE; + } + // Short-circuit without rescheduling, if timeout is zero. + if (timeout == 0) { + return RESULT_TIMEOUT; + } + + return WaitForAddress(address, timeout); +} +} // namespace AddressArbiter +} // namespace Kernel diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h new file mode 100644 index 000000000..f20f3dbc0 --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.h @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" + +namespace Kernel { + +namespace AddressArbiter { +enum class ArbitrationType { + WaitIfLessThan = 0, + DecrementAndWaitIfLessThan = 1, + WaitIfEqual = 2, +}; + +enum class SignalType { + Signal = 0, + IncrementAndSignalIfEqual = 1, + ModifyByWaitingCountAndSignalIfEqual = 2, +}; + +ResultCode SignalToAddress(VAddr address, s32 num_to_wake); +ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); +ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); + +ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement); +ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); +} // namespace AddressArbiter + +} // namespace Kernel diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index e1b5430bf..221cb1bb5 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -20,13 +20,16 @@ enum { MaxConnectionsReached = 52, // Confirmed Switch OS error codes - MisalignedAddress = 102, + InvalidAddress = 102, + InvalidMemoryState = 106, InvalidProcessorId = 113, InvalidHandle = 114, InvalidCombination = 116, Timeout = 117, SynchronizationCanceled = 118, TooLarge = 119, + InvalidEnumValue = 120, + InvalidState = 125, }; } @@ -39,14 +42,15 @@ constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); constexpr ResultCode ERR_PORT_NAME_TOO_LONG(-1); constexpr ResultCode ERR_WRONG_PERMISSION(-1); constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1); -constexpr ResultCode ERR_INVALID_ENUM_VALUE(-1); +constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue); constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(-1); constexpr ResultCode ERR_INVALID_COMBINATION(-1); constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1); constexpr ResultCode ERR_OUT_OF_MEMORY(-1); -constexpr ResultCode ERR_INVALID_ADDRESS(-1); -constexpr ResultCode ERR_INVALID_ADDRESS_STATE(-1); +constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress); +constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); +constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); constexpr ResultCode ERR_INVALID_POINTER(-1); constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); constexpr ResultCode ERR_NOT_AUTHORIZED(-1); diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 01904467e..b0d83f401 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -271,6 +271,11 @@ std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { } size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffer_index) const { + if (size == 0) { + NGLOG_WARNING(Core, "skip empty buffer write"); + return 0; + } + const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; const size_t buffer_size{GetWriteBufferSize(buffer_index)}; if (size > buffer_size) { diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index bc144f3de..65560226d 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -59,7 +59,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, Handle requesting_thread_handle) { // The mutex address must be 4-byte aligned if ((address % sizeof(u32)) != 0) { - return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); + return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); } SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); @@ -97,7 +97,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, ResultCode Mutex::Release(VAddr address) { // The mutex address must be 4-byte aligned if ((address % sizeof(u32)) != 0) { - return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); + return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); } auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index ec3601e8b..1a36e0d02 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -11,6 +11,7 @@ #include "common/string_util.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/event.h" @@ -316,6 +317,11 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) "(STUBBED) Attempted to query privileged process id bounds, returned 0"); *result = 0; break; + case GetInfoType::UserExceptionContextAddr: + NGLOG_WARNING(Kernel_SVC, + "(STUBBED) Attempted to query user exception context address, returned 0"); + *result = 0; + break; default: UNIMPLEMENTED(); } @@ -575,7 +581,7 @@ static void SleepThread(s64 nanoseconds) { Core::System::GetInstance().PrepareReschedule(); } -/// Signal process wide key atomic +/// Wait process wide key atomic static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, Handle thread_handle, s64 nano_seconds) { NGLOG_TRACE( @@ -684,6 +690,58 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target return RESULT_SUCCESS; } +// Wait for an address (via Address Arbiter) +static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout) { + NGLOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", + address, type, value, timeout); + // If the passed address is a kernel virtual address, return invalid memory state. + if (Memory::IsKernelVirtualAddress(address)) { + return ERR_INVALID_ADDRESS_STATE; + } + // If the address is not properly aligned to 4 bytes, return invalid address. + if (address % sizeof(u32) != 0) { + return ERR_INVALID_ADDRESS; + } + + switch (static_cast<AddressArbiter::ArbitrationType>(type)) { + case AddressArbiter::ArbitrationType::WaitIfLessThan: + return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false); + case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: + return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true); + case AddressArbiter::ArbitrationType::WaitIfEqual: + return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); + default: + return ERR_INVALID_ENUM_VALUE; + } +} + +// Signals to an address (via Address Arbiter) +static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to_wake) { + NGLOG_WARNING(Kernel_SVC, + "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", address, + type, value, num_to_wake); + // If the passed address is a kernel virtual address, return invalid memory state. + if (Memory::IsKernelVirtualAddress(address)) { + return ERR_INVALID_ADDRESS_STATE; + } + // If the address is not properly aligned to 4 bytes, return invalid address. + if (address % sizeof(u32) != 0) { + return ERR_INVALID_ADDRESS; + } + + switch (static_cast<AddressArbiter::SignalType>(type)) { + case AddressArbiter::SignalType::Signal: + return AddressArbiter::SignalToAddress(address, num_to_wake); + case AddressArbiter::SignalType::IncrementAndSignalIfEqual: + return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); + case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: + return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, + num_to_wake); + default: + return ERR_INVALID_ENUM_VALUE; + } +} + /// This returns the total CPU ticks elapsed since the CPU was powered-on static u64 GetSystemTick() { const u64 result{CoreTiming::GetTicks()}; @@ -744,7 +802,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT); // Set the target CPU to the one specified in the process' exheader. core = thread->owner_process->ideal_processor; - mask = 1 << core; + mask = 1ull << core; } if (mask == 0) { @@ -761,7 +819,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { } // Error out if the input core isn't enabled in the input mask. - if (core < Core::NUM_CPU_CORES && (mask & (1 << core)) == 0) { + if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); } @@ -856,8 +914,8 @@ static const FunctionDef SVC_Table[] = { {0x31, nullptr, "GetResourceLimitCurrentValue"}, {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, - {0x34, nullptr, "WaitForAddress"}, - {0x35, nullptr, "SignalToAddress"}, + {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, + {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"}, {0x36, nullptr, "Unknown"}, {0x37, nullptr, "Unknown"}, {0x38, nullptr, "Unknown"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 40aa88cc1..79c3fe31b 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -179,6 +179,20 @@ void SvcWrap() { 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); +} + +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)) + .raw); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Function wrappers that return type u32 diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index cffa7ca83..2f333ec34 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -140,6 +140,11 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { } } + if (thread->arb_wait_address != 0) { + ASSERT(thread->status == THREADSTATUS_WAIT_ARB); + thread->arb_wait_address = 0; + } + if (resume) thread->ResumeFromWait(); } @@ -179,6 +184,7 @@ void Thread::ResumeFromWait() { case THREADSTATUS_WAIT_SLEEP: case THREADSTATUS_WAIT_IPC: case THREADSTATUS_WAIT_MUTEX: + case THREADSTATUS_WAIT_ARB: break; case THREADSTATUS_READY: diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 1d2da6d50..f1e759802 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -45,6 +45,7 @@ enum ThreadStatus { THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc + THREADSTATUS_WAIT_ARB, ///< Waiting due to a SignalToAddress/WaitForAddress svc THREADSTATUS_DORMANT, ///< Created but not yet made ready THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated }; @@ -230,6 +231,9 @@ public: VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address Handle wait_handle; ///< The handle used to wait for the mutex. + // If waiting for an AddressArbiter, this is the address being waited on. + VAddr arb_wait_address{0}; + std::string name; /// Handle used by guest emulated application to access this thread diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 12954556d..b8d6b8d4d 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -561,7 +561,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF {32, nullptr, "BeginBlockingHomeButton"}, {33, nullptr, "EndBlockingHomeButton"}, {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, - {50, nullptr, "GetPseudoDeviceId"}, + {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, {60, nullptr, "SetMediaPlaybackStateForApplication"}, {65, nullptr, "IsGamePlayRecordingSupported"}, {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, @@ -684,6 +684,17 @@ void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { NGLOG_WARNING(Service_AM, "(STUBBED) called"); } +void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + + // Returns a 128-bit UUID + rb.Push<u64>(0); + rb.Push<u64>(0); + + NGLOG_WARNING(Service_AM, "(STUBBED) called"); +} + void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 301a6c798..1da79fd01 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -138,6 +138,7 @@ private: void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx); void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx); void NotifyRunning(Kernel::HLERequestContext& ctx); + void GetPseudoDeviceId(Kernel::HLERequestContext& ctx); }; class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 6e8002bc9..44b7ef216 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -57,27 +57,26 @@ private: } void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { - NGLOG_DEBUG(Service_Audio, "{}", ctx.Description()); - AudioRendererResponseData response_data{}; - - response_data.section_0_size = - static_cast<u32>(response_data.state_entries.size() * sizeof(AudioRendererStateEntry)); - response_data.section_1_size = static_cast<u32>(response_data.section_1.size()); - response_data.section_2_size = static_cast<u32>(response_data.section_2.size()); - response_data.section_3_size = static_cast<u32>(response_data.section_3.size()); - response_data.section_4_size = static_cast<u32>(response_data.section_4.size()); - response_data.section_5_size = static_cast<u32>(response_data.section_5.size()); - response_data.total_size = sizeof(AudioRendererResponseData); - - for (unsigned i = 0; i < response_data.state_entries.size(); i++) { - // 4 = Busy and 5 = Ready? - response_data.state_entries[i].state = 5; + AudioRendererConfig config; + auto buf = ctx.ReadBuffer(); + std::memcpy(&config, buf.data(), sizeof(AudioRendererConfig)); + + AudioRendererResponse response_data{config}; + + ASSERT(ctx.GetWriteBufferSize() == response_data.total_size); + + std::vector<u8> output(response_data.total_size); + std::memcpy(output.data(), &response_data, sizeof(AudioRendererResponse)); + std::vector<MemoryPoolEntry> memory_pool(config.memory_pools_size / 0x20); + for (auto& entry : memory_pool) { + entry.state = 5; } + std::memcpy(output.data() + sizeof(AudioRendererResponse), memory_pool.data(), + response_data.memory_pools_size); - ctx.WriteBuffer(&response_data, response_data.total_size); + ctx.WriteBuffer(output); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); NGLOG_WARNING(Service_Audio, "(STUBBED) called"); @@ -109,43 +108,55 @@ private: NGLOG_WARNING(Service_Audio, "(STUBBED) called"); } - struct AudioRendererStateEntry { + struct MemoryPoolEntry { u32_le state; u32_le unknown_4; u32_le unknown_8; u32_le unknown_c; }; - static_assert(sizeof(AudioRendererStateEntry) == 0x10, - "AudioRendererStateEntry has wrong size"); - - struct AudioRendererResponseData { - u32_le unknown_0; - u32_le section_5_size; - u32_le section_0_size; - u32_le section_1_size; + static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size"); + + struct AudioRendererConfig { + u32 revision; + u32 behavior_size; + u32 memory_pools_size; + u32 voices_size; + u32 voice_resource_size; + u32 effects_size; + u32 mixes_size; + u32 sinks_size; + u32 performance_buffer_size; + INSERT_PADDING_WORDS(6); + u32 total_size; + }; + static_assert(sizeof(AudioRendererConfig) == 0x40, "AudioRendererConfig has wrong size"); + + struct AudioRendererResponse { + AudioRendererResponse(const AudioRendererConfig& config) { + revision = config.revision; + error_info_size = 0xb0; + memory_pools_size = (config.memory_pools_size / 0x20) * 0x10; + voices_size = (config.voices_size / 0x170) * 0x10; + effects_size = (config.effects_size / 0xC0) * 0x10; + sinks_size = (config.sinks_size / 0x140) * 0x20; + performance_manager_size = 0x10; + total_size = sizeof(AudioRendererResponse) + error_info_size + memory_pools_size + + voices_size + effects_size + sinks_size + performance_manager_size; + } + + u32_le revision; + u32_le error_info_size; + u32_le memory_pools_size; + u32_le voices_size; u32_le unknown_10; - u32_le section_2_size; + u32_le effects_size; u32_le unknown_18; - u32_le section_3_size; - u32_le section_4_size; - u32_le unknown_24; - u32_le unknown_28; - u32_le unknown_2c; - u32_le unknown_30; - u32_le unknown_34; - u32_le unknown_38; + u32_le sinks_size; + u32_le performance_manager_size; + INSERT_PADDING_WORDS(6); u32_le total_size; - - std::array<AudioRendererStateEntry, 0x18e> state_entries; - - std::array<u8, 0x600> section_1; - std::array<u8, 0xe0> section_2; - std::array<u8, 0x20> section_3; - std::array<u8, 0x10> section_4; - std::array<u8, 0xb0> section_5; }; - static_assert(sizeof(AudioRendererResponseData) == 0x20e0, - "AudioRendererResponseData has wrong size"); + static_assert(sizeof(AudioRendererResponse) == 0x40, "AudioRendererResponse has wrong size"); /// This is used to trigger the audio event callback. CoreTiming::EventType* audio_event; @@ -258,7 +269,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto params = rp.PopRaw<WorkerBufferParameters>(); + auto params = rp.PopRaw<AudioRendererParameters>(); u64 buffer_sz = Common::AlignUp(4 * params.unknown8, 0x40); buffer_sz += params.unknownC * 1024; @@ -328,7 +339,7 @@ bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap switch (feature) { case AudioFeatures::Splitter: - return version_num >= 2; + return version_num >= 2u; default: return false; } diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index fe53de4ce..7dbd9b74d 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -22,7 +22,7 @@ private: void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); void GetAudioDevice(Kernel::HLERequestContext& ctx); - struct WorkerBufferParameters { + struct AudioRendererParameters { u32_le sample_rate; u32_le sample_count; u32_le unknown8; @@ -38,8 +38,8 @@ private: u8 padding2[4]; u32_le magic; }; - static_assert(sizeof(WorkerBufferParameters) == 52, - "WorkerBufferParameters is an invalid size"); + static_assert(sizeof(AudioRendererParameters) == 52, + "AudioRendererParameters is an invalid size"); enum class AudioFeatures : u32 { Splitter, diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 8a47bb7af..1cf97e876 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -4,6 +4,7 @@ #include <cinttypes> #include "common/logging/log.h" +#include "common/string_util.h" #include "core/core.h" #include "core/file_sys/directory.h" #include "core/file_sys/filesystem.h" @@ -258,9 +259,7 @@ public: IPC::RequestParser rp{ctx}; auto file_buffer = ctx.ReadBuffer(); - auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); - - std::string name(file_buffer.begin(), end); + std::string name = Common::StringFromBuffer(file_buffer); u64 mode = rp.Pop<u64>(); u32 size = rp.Pop<u32>(); @@ -275,9 +274,7 @@ public: IPC::RequestParser rp{ctx}; auto file_buffer = ctx.ReadBuffer(); - auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); - - std::string name(file_buffer.begin(), end); + std::string name = Common::StringFromBuffer(file_buffer); NGLOG_DEBUG(Service_FS, "called file {}", name); @@ -289,9 +286,7 @@ public: IPC::RequestParser rp{ctx}; auto file_buffer = ctx.ReadBuffer(); - auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); - - std::string name(file_buffer.begin(), end); + std::string name = Common::StringFromBuffer(file_buffer); NGLOG_DEBUG(Service_FS, "called directory {}", name); @@ -305,13 +300,11 @@ public: std::vector<u8> buffer; buffer.resize(ctx.BufferDescriptorX()[0].Size()); Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size()); - auto end = std::find(buffer.begin(), buffer.end(), '\0'); - std::string src_name(buffer.begin(), end); + std::string src_name = Common::StringFromBuffer(buffer); buffer.resize(ctx.BufferDescriptorX()[1].Size()); Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size()); - end = std::find(buffer.begin(), buffer.end(), '\0'); - std::string dst_name(buffer.begin(), end); + std::string dst_name = Common::StringFromBuffer(buffer); NGLOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); @@ -323,9 +316,7 @@ public: IPC::RequestParser rp{ctx}; auto file_buffer = ctx.ReadBuffer(); - auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); - - std::string name(file_buffer.begin(), end); + std::string name = Common::StringFromBuffer(file_buffer); auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); @@ -349,9 +340,7 @@ public: IPC::RequestParser rp{ctx}; auto file_buffer = ctx.ReadBuffer(); - auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); - - std::string name(file_buffer.begin(), end); + std::string name = Common::StringFromBuffer(file_buffer); // TODO(Subv): Implement this filter. u32 filter_flags = rp.Pop<u32>(); @@ -376,9 +365,7 @@ public: IPC::RequestParser rp{ctx}; auto file_buffer = ctx.ReadBuffer(); - auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); - - std::string name(file_buffer.begin(), end); + std::string name = Common::StringFromBuffer(file_buffer); NGLOG_DEBUG(Service_FS, "called file {}", name); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 00c5308ba..2696a8bf0 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -84,6 +84,10 @@ private: for (size_t controller = 0; controller < mem.controllers.size(); controller++) { for (int index = 0; index < HID_NUM_LAYOUTS; index++) { + // TODO(DarkLordZach): Is this layout/controller config actually invalid? + if (controller == Controller_Handheld && index == Layout_Single) + continue; + ControllerLayout& layout = mem.controllers[controller].layouts[index]; layout.header.num_entries = HID_NUM_ENTRIES; layout.header.max_entry_index = HID_NUM_ENTRIES - 1; @@ -94,7 +98,6 @@ private: layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES; ControllerInputEntry& entry = layout.entries[layout.header.latest_entry]; - entry.connection_state = ConnectionState_Connected | ConnectionState_Wired; entry.timestamp++; // TODO(shinyquagsire23): Is this always identical to timestamp? entry.timestamp_2++; @@ -103,6 +106,8 @@ private: if (controller != Controller_Handheld) continue; + entry.connection_state = ConnectionState_Connected | ConnectionState_Wired; + // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future? // For now everything is just the default handheld layout, but split Joy-Con will // rotate the face buttons and directions for certain layouts. diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 15eee8f01..b499308d6 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -12,7 +12,7 @@ namespace Service::HID { // Begin enums and output structs constexpr u32 HID_NUM_ENTRIES = 17; -constexpr u32 HID_NUM_LAYOUTS = 2; +constexpr u32 HID_NUM_LAYOUTS = 7; constexpr s32 HID_JOYSTICK_MAX = 0x8000; constexpr s32 HID_JOYSTICK_MIN = -0x8000; diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp new file mode 100644 index 000000000..b3a85b818 --- /dev/null +++ b/src/core/hle/service/mm/mm_u.cpp @@ -0,0 +1,50 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/service/mm/mm_u.h" + +namespace Service::MM { + +void InstallInterfaces(SM::ServiceManager& service_manager) { + std::make_shared<MM_U>()->InstallAsService(service_manager); +} + +void MM_U::Initialize(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void MM_U::SetAndWait(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + min = rp.Pop<u32>(); + max = rp.Pop<u32>(); + current = min; + + NGLOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void MM_U::Get(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(current); +} + +MM_U::MM_U() : ServiceFramework("mm:u") { + static const FunctionInfo functions[] = { + {0, nullptr, "InitializeOld"}, {1, nullptr, "FinalizeOld"}, + {2, nullptr, "SetAndWaitOld"}, {3, nullptr, "GetOld"}, + {4, &MM_U::Initialize, "Initialize"}, {5, nullptr, "Finalize"}, + {6, &MM_U::SetAndWait, "SetAndWait"}, {7, &MM_U::Get, "Get"}, + }; + RegisterHandlers(functions); +} + +} // namespace Service::MM diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h new file mode 100644 index 000000000..79eeedf9c --- /dev/null +++ b/src/core/hle/service/mm/mm_u.h @@ -0,0 +1,29 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::MM { + +class MM_U final : public ServiceFramework<MM_U> { +public: + MM_U(); + ~MM_U() = default; + +private: + void Initialize(Kernel::HLERequestContext& ctx); + void SetAndWait(Kernel::HLERequestContext& ctx); + void Get(Kernel::HLERequestContext& ctx); + + u32 min{0}; + u32 max{0}; + u32 current{0}; +}; + +/// Registers all MM services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::MM diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 2af4465de..2a9f84037 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -4,6 +4,8 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" +#include "core/hle/service/hid/hid.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nfp/nfp_user.h" @@ -18,7 +20,7 @@ public: static const FunctionInfo functions[] = { {0, &IUser::Initialize, "Initialize"}, {1, nullptr, "Finalize"}, - {2, nullptr, "ListDevices"}, + {2, &IUser::ListDevices, "ListDevices"}, {3, nullptr, "StartDetection"}, {4, nullptr, "StopDetection"}, {5, nullptr, "Mount"}, @@ -33,24 +35,116 @@ public: {14, nullptr, "GetRegisterInfo"}, {15, nullptr, "GetCommonInfo"}, {16, nullptr, "GetModelInfo"}, - {17, nullptr, "AttachActivateEvent"}, - {18, nullptr, "AttachDeactivateEvent"}, - {19, nullptr, "GetState"}, - {20, nullptr, "GetDeviceState"}, - {21, nullptr, "GetNpadId"}, + {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, + {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, + {19, &IUser::GetState, "GetState"}, + {20, &IUser::GetDeviceState, "GetDeviceState"}, + {21, &IUser::GetNpadId, "GetNpadId"}, {22, nullptr, "GetApplicationArea2"}, - {23, nullptr, "AttachAvailabilityChangeEvent"}, + {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, {24, nullptr, "RecreateApplicationArea"}, }; RegisterHandlers(functions); + + activate_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:ActivateEvent"); + deactivate_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); + availability_change_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent"); } private: + enum class State : u32 { + NonInitialized = 0, + Initialized = 1, + }; + + enum class DeviceState : u32 { + Initialized = 0, + }; + void Initialize(Kernel::HLERequestContext& ctx) { NGLOG_WARNING(Service_NFP, "(STUBBED) called"); + + state = State::Initialized; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } + + void ListDevices(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u32 array_size = rp.Pop<u32>(); + + ctx.WriteBuffer(&device_handle, sizeof(device_handle)); + + NGLOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); + } + + void AttachActivateEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 dev_handle = rp.Pop<u64>(); + NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(activate_event); + } + + void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 dev_handle = rp.Pop<u64>(); + NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(deactivate_event); + } + + void GetState(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NFP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(state)); + } + + void GetDeviceState(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NFP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(device_state)); + } + + void GetNpadId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 dev_handle = rp.Pop<u64>(); + NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(npad_id); + } + + void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 dev_handle = rp.Pop<u64>(); + NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(availability_change_event); + } + + const u64 device_handle{0xDEAD}; + const HID::ControllerID npad_id{HID::Controller_Player1}; + State state{State::NonInitialized}; + DeviceState device_state{DeviceState::Initialized}; + Kernel::SharedPtr<Kernel::Event> activate_event; + Kernel::SharedPtr<Kernel::Event> deactivate_event; + Kernel::SharedPtr<Kernel::Event> availability_change_event; }; void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index eee92cfcd..62489c7fe 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -38,7 +38,7 @@ public: {8, nullptr, "SetPriority"}, {9, nullptr, "SetNetworkProfileId"}, {10, nullptr, "SetRejectable"}, - {11, nullptr, "SetConnectionConfirmationOption"}, + {11, &IRequest::SetConnectionConfirmationOption, "SetConnectionConfirmationOption"}, {12, nullptr, "SetPersistent"}, {13, nullptr, "SetInstant"}, {14, nullptr, "SetSustainable"}, @@ -67,23 +67,32 @@ private: rb.Push(RESULT_SUCCESS); rb.Push<u32>(0); } + void GetResult(Kernel::HLERequestContext& ctx) { NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } + void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2, 2}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(event1, event2); } + void Cancel(Kernel::HLERequestContext& ctx) { NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } + void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { + NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + Kernel::SharedPtr<Kernel::Event> event1, event2; }; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index a9538ff43..0abc0de83 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -26,6 +26,10 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec return ZCullGetInfo(input, output); case IoctlCommand::IocZbcSetTable: return ZBCSetTable(input, output); + case IoctlCommand::IocZbcQueryTable: + return ZBCQueryTable(input, output); + case IoctlCommand::IocFlushL2: + return FlushL2(input, output); } UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; @@ -136,4 +140,22 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& return 0; } +u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); + IoctlZbcQueryTable params{}; + std::memcpy(¶ms, input.data(), input.size()); + // TODO : To implement properly + std::memcpy(output.data(), ¶ms, output.size()); + return 0; +} + +u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); + IoctlFlushL2 params{}; + std::memcpy(¶ms, input.data(), input.size()); + // TODO : To implement properly + std::memcpy(output.data(), ¶ms, output.size()); + return 0; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 1d5ba2e67..f09113e67 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -26,6 +26,18 @@ private: IocZcullGetCtxSizeCommand = 0x80044701, IocZcullGetInfo = 0x80284702, IocZbcSetTable = 0x402C4703, + IocZbcQueryTable = 0xC0344704, + IocFlushL2 = 0x40084707, + IocInvalICache = 0x4008470D, + IocSetMmudebugMode = 0x4008470E, + IocSetSmDebugMode = 0x4010470F, + IocWaitForPause = 0xC0084710, + IocGetTcpExceptionEnStatus = 0x80084711, + IocNumVsms = 0x80084712, + IocVsmsMapping = 0xC0044713, + IocGetErrorChannelUserData = 0xC008471B, + IocGetGpuTime = 0xC010471C, + IocGetCpuTimeCorrelationInfo = 0xC108471D, }; struct IoctlGpuCharacteristics { @@ -127,12 +139,31 @@ private: }; static_assert(sizeof(IoctlZbcSetTable) == 44, "IoctlZbcSetTable is incorrect size"); + struct IoctlZbcQueryTable { + u32_le color_ds[4]; + u32_le color_l2[4]; + u32_le depth; + u32_le ref_cnt; + u32_le format; + u32_le type; + u32_le index_size; + }; + static_assert(sizeof(IoctlZbcQueryTable) == 52, "IoctlZbcQueryTable is incorrect size"); + + struct IoctlFlushL2 { + u32_le flush; // l2_flush | l2_invalidate << 1 | fb_flush << 2 + u32_le reserved; + }; + static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size"); + u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); + u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); + u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 79aab87f9..ed7b6dc03 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -121,8 +121,9 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< } u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { - if (input.size() < sizeof(IoctlSubmitGpfifo)) + if (input.size() < sizeof(IoctlSubmitGpfifo)) { UNIMPLEMENTED(); + } IoctlSubmitGpfifo params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 409fec470..bdd9eb5a5 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -26,6 +26,7 @@ #include "core/hle/service/friend/friend.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/lm/lm.h" +#include "core/hle/service/mm/mm_u.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nifm/nifm.h" #include "core/hle/service/ns/ns.h" @@ -191,6 +192,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { Friend::InstallInterfaces(*sm); HID::InstallInterfaces(*sm); LM::InstallInterfaces(*sm); + MM::InstallInterfaces(*sm); NFP::InstallInterfaces(*sm); NIFM::InstallInterfaces(*sm); NS::InstallInterfaces(*sm); diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index f0572bed6..baeecb0ec 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -12,9 +12,6 @@ namespace Service::Set { void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - u32 id = rp.Pop<u32>(); - static constexpr std::array<LanguageCode, 17> available_language_codes = {{ LanguageCode::JA, LanguageCode::EN_US, @@ -50,7 +47,7 @@ SET::SET() : ServiceFramework("set") { {2, nullptr, "MakeLanguageCode"}, {3, nullptr, "GetAvailableLanguageCodeCount"}, {4, nullptr, "GetRegionCode"}, - {5, nullptr, "GetAvailableLanguageCodes2"}, + {5, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes2"}, {6, nullptr, "GetAvailableLanguageCodeCount2"}, {7, nullptr, "GetKeyCodeMap"}, {8, nullptr, "GetQuestFlag"}, |