diff options
Diffstat (limited to 'src/core')
44 files changed, 415 insertions, 153 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8cf9fb405..67ad6109a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -257,6 +257,10 @@ add_library(core STATIC hle/service/nvdrv/devices/nvhost_gpu.h hle/service/nvdrv/devices/nvhost_nvdec.cpp hle/service/nvdrv/devices/nvhost_nvdec.h + hle/service/nvdrv/devices/nvhost_nvjpg.cpp + hle/service/nvdrv/devices/nvhost_nvjpg.h + hle/service/nvdrv/devices/nvhost_vic.cpp + hle/service/nvdrv/devices/nvhost_vic.h hle/service/nvdrv/devices/nvmap.cpp hle/service/nvdrv/devices/nvmap.h hle/service/nvdrv/interface.cpp diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index ceb3f7683..20e5200a8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -86,7 +86,16 @@ public: } void AddTicks(u64 ticks) override { - CoreTiming::AddTicks(ticks - num_interpreted_instructions); + // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a + // rough approximation of the amount of executed ticks in the system, it may be thrown off + // if not all cores are doing a similar amount of work. Instead of doing this, we should + // device a way so that timing is consistent across all cores without increasing the ticks 4 + // times. + u64 amortized_ticks = (ticks - num_interpreted_instructions) / Core::NUM_CPU_CORES; + // Always execute at least one tick. + amortized_ticks = std::max<u64>(amortized_ticks, 1); + + CoreTiming::AddTicks(amortized_ticks); num_interpreted_instructions = 0; } u64 GetTicksRemaining() override { @@ -234,9 +243,7 @@ void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { } void ARM_Dynarmic::PrepareReschedule() { - if (jit->IsExecuting()) { - jit->HaltExecution(); - } + jit->HaltExecution(); } void ARM_Dynarmic::ClearInstructionCache() { diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index 46a522fcd..b042ee02b 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -14,6 +14,7 @@ #include "core/core_timing.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/lock.h" #include "core/settings.h" namespace Core { @@ -90,6 +91,7 @@ void Cpu::RunLoop(bool tight_loop) { LOG_TRACE(Core, "Core-{} idling", core_index); if (IsMainCore()) { + // TODO(Subv): Only let CoreTiming idle if all 4 cores are idling. CoreTiming::Idle(); CoreTiming::Advance(); } @@ -125,6 +127,8 @@ void Cpu::Reschedule() { } reschedule_pending = false; + // Lock the global kernel mutex when we manipulate the HLE state + std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); scheduler->Reschedule(); } diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index 976952903..56cdae194 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -79,7 +79,7 @@ private: std::shared_ptr<CpuBarrier> cpu_barrier; std::shared_ptr<Kernel::Scheduler> scheduler; - bool reschedule_pending{}; + std::atomic<bool> reschedule_pending = false; size_t core_index; }; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index d3bb6f818..7953c8720 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -56,6 +56,9 @@ static u64 event_fifo_id; // to the event_queue by the emu thread static Common::MPSCQueue<Event, false> ts_queue; +// the queue for unscheduling the events from other threads threadsafe +static Common::MPSCQueue<std::pair<const EventType*, u64>, false> unschedule_queue; + constexpr int MAX_SLICE_LENGTH = 20000; static s64 idled_cycles; @@ -135,11 +138,9 @@ void ClearPendingEvents() { void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) { ASSERT(event_type != nullptr); s64 timeout = GetTicks() + cycles_into_future; - // If this event needs to be scheduled before the next advance(), force one early if (!is_global_timer_sane) ForceExceptionCheck(cycles_into_future); - event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); } @@ -160,6 +161,10 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) { } } +void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) { + unschedule_queue.Push(std::make_pair(event_type, userdata)); +} + void RemoveEvent(const EventType* event_type) { auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { return e.type == event_type; }); @@ -196,6 +201,9 @@ void MoveEvents() { void Advance() { MoveEvents(); + for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) { + UnscheduleEvent(ev.first, ev.second); + } int cycles_executed = slice_length - downcount; global_timer += cycles_executed; diff --git a/src/core/core_timing.h b/src/core/core_timing.h index dfa161c0d..9ed757bd7 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -65,6 +65,7 @@ void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 user void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata); void UnscheduleEvent(const EventType* event_type, u64 userdata); +void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata); /// We only permit one event of each type in the queue at a time. void RemoveEvent(const EventType* event_type); diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 093c625ff..1d7c7fb10 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -4,11 +4,14 @@ #include <array> #include <string> -#include <core/loader/loader.h> + +#include <fmt/ostream.h> + #include "common/logging/log.h" #include "core/file_sys/card_image.h" #include "core/file_sys/partition_filesystem.h" #include "core/file_sys/vfs_offset.h" +#include "core/loader/loader.h" namespace FileSys { @@ -111,19 +114,19 @@ VirtualFile XCI::GetNCAFileByType(NCAContentType type) const { return nullptr; } -std::vector<std::shared_ptr<VfsFile>> XCI::GetFiles() const { +std::vector<VirtualFile> XCI::GetFiles() const { return {}; } -std::vector<std::shared_ptr<VfsDirectory>> XCI::GetSubdirectories() const { - return std::vector<std::shared_ptr<VfsDirectory>>(); +std::vector<VirtualDir> XCI::GetSubdirectories() const { + return {}; } std::string XCI::GetName() const { return file->GetName(); } -std::shared_ptr<VfsDirectory> XCI::GetParentDirectory() const { +VirtualDir XCI::GetParentDirectory() const { return file->GetContainingDirectory(); } @@ -146,7 +149,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { const u16 error_id = static_cast<u16>(nca->GetStatus()); LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})", partition_names[static_cast<size_t>(part)], nca->GetName(), error_id, - Loader::GetMessageForResultStatus(nca->GetStatus())); + nca->GetStatus()); } } diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 3514bdf6c..a03d5264e 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h @@ -72,13 +72,13 @@ public: std::shared_ptr<NCA> GetNCAByType(NCAContentType type) const; VirtualFile GetNCAFileByType(NCAContentType type) const; - std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; + std::vector<VirtualFile> GetFiles() const override; - std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; + std::vector<VirtualDir> GetSubdirectories() const override; std::string GetName() const override; - std::shared_ptr<VfsDirectory> GetParentDirectory() const override; + VirtualDir GetParentDirectory() const override; protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h index 7c7a75816..be7bc32a8 100644 --- a/src/core/file_sys/partition_filesystem.h +++ b/src/core/file_sys/partition_filesystem.h @@ -13,7 +13,7 @@ #include "core/file_sys/vfs.h" namespace Loader { -enum class ResultStatus; +enum class ResultStatus : u16; } namespace FileSys { diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h index 06a7315db..74a91052b 100644 --- a/src/core/file_sys/program_metadata.h +++ b/src/core/file_sys/program_metadata.h @@ -13,7 +13,7 @@ #include "partition_filesystem.h" namespace Loader { -enum class ResultStatus; +enum class ResultStatus : u16; } namespace FileSys { diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 24e158962..a5ec50b1a 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -74,15 +74,15 @@ VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view return new_file; } -VirtualFile VfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_); - const auto new_path = FileUtil::SanitizePath(new_path_); +VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view new_path) { + const auto sanitized_old_path = FileUtil::SanitizePath(old_path); + const auto sanitized_new_path = FileUtil::SanitizePath(new_path); // Again, non-default impls are highly encouraged to provide a more optimized version of this. - auto out = CopyFile(old_path_, new_path_); + auto out = CopyFile(sanitized_old_path, sanitized_new_path); if (out == nullptr) return nullptr; - if (DeleteFile(old_path)) + if (DeleteFile(sanitized_old_path)) return out; return nullptr; } @@ -137,15 +137,15 @@ VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_ return new_dir; } -VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_); - const auto new_path = FileUtil::SanitizePath(new_path_); +VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_view new_path) { + const auto sanitized_old_path = FileUtil::SanitizePath(old_path); + const auto sanitized_new_path = FileUtil::SanitizePath(new_path); // Non-default impls are highly encouraged to provide a more optimized version of this. - auto out = CopyDirectory(old_path_, new_path_); + auto out = CopyDirectory(sanitized_old_path, sanitized_new_path); if (out == nullptr) return nullptr; - if (DeleteDirectory(old_path)) + if (DeleteDirectory(sanitized_old_path)) return out; return nullptr; } diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 141a053ce..78a63c59b 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -15,9 +15,9 @@ namespace FileSys { -struct VfsFilesystem; -struct VfsFile; -struct VfsDirectory; +class VfsDirectory; +class VfsFile; +class VfsFilesystem; // Convenience typedefs to use Vfs* interfaces using VirtualFilesystem = std::shared_ptr<VfsFilesystem>; @@ -34,8 +34,9 @@ enum class VfsEntryType { // A class representing an abstract filesystem. A default implementation given the root VirtualDir // is provided for convenience, but if the Vfs implementation has any additional state or // functionality, they will need to override. -struct VfsFilesystem : NonCopyable { - VfsFilesystem(VirtualDir root); +class VfsFilesystem : NonCopyable { +public: + explicit VfsFilesystem(VirtualDir root); virtual ~VfsFilesystem(); // Gets the friendly name for the filesystem. @@ -81,7 +82,8 @@ protected: }; // A class representing a file in an abstract filesystem. -struct VfsFile : NonCopyable { +class VfsFile : NonCopyable { +public: virtual ~VfsFile(); // Retrieves the file name. @@ -179,7 +181,8 @@ struct VfsFile : NonCopyable { }; // A class representing a directory in an abstract filesystem. -struct VfsDirectory : NonCopyable { +class VfsDirectory : NonCopyable { +public: virtual ~VfsDirectory(); // Retrives the file located at path as if the current directory was root. Returns nullptr if @@ -295,7 +298,8 @@ protected: // A convenience partial-implementation of VfsDirectory that stubs out methods that should only work // if writable. This is to avoid redundant empty methods everywhere. -struct ReadOnlyVfsDirectory : public VfsDirectory { +class ReadOnlyVfsDirectory : public VfsDirectory { +public: bool IsWritable() const override; bool IsReadable() const override; std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h index 235970dc5..cb92d1570 100644 --- a/src/core/file_sys/vfs_offset.h +++ b/src/core/file_sys/vfs_offset.h @@ -15,7 +15,8 @@ namespace FileSys { // Similar to seeking to an offset. // If the file is writable, operations that would write past the end of the offset file will expand // the size of this wrapper. -struct OffsetVfsFile : public VfsFile { +class OffsetVfsFile : public VfsFile { +public: OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0, std::string new_name = "", VirtualDir new_parent = nullptr); diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index dc39c9f2f..179f62e4b 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h @@ -10,7 +10,8 @@ namespace FileSys { // An implementation of VfsDirectory that maintains two vectors for subdirectories and files. // Vector data is supplied upon construction. -struct VectorVfsDirectory : public VfsDirectory { +class VectorVfsDirectory : public VfsDirectory { +public: explicit VectorVfsDirectory(std::vector<VirtualFile> files = {}, std::vector<VirtualDir> dirs = {}, std::string name = "", VirtualDir parent = nullptr); diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 384dc7822..7006a37b3 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -34,9 +34,9 @@ class EmuWindow { public: /// Data structure to store emuwindow configuration struct WindowConfig { - bool fullscreen; - int res_width; - int res_height; + bool fullscreen = false; + int res_width = 0; + int res_height = 0; std::pair<unsigned, unsigned> min_client_area_size; }; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1b0cd0abf..8c19e86d3 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -11,7 +11,7 @@ namespace Kernel { -unsigned int Object::next_object_id; +std::atomic<u32> Object::next_object_id{0}; /// Initialize the kernel void Init() { diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 83df68dfd..526ac9cc3 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -4,6 +4,7 @@ #pragma once +#include <atomic> #include <string> #include <utility> @@ -42,8 +43,8 @@ public: virtual ~Object(); /// Returns a unique identifier for the object. For debugging purposes only. - unsigned int GetObjectId() const { - return object_id; + u32 GetObjectId() const { + return object_id.load(std::memory_order_relaxed); } virtual std::string GetTypeName() const { @@ -61,23 +62,23 @@ public: bool IsWaitable() const; public: - static unsigned int next_object_id; + static std::atomic<u32> next_object_id; private: friend void intrusive_ptr_add_ref(Object*); friend void intrusive_ptr_release(Object*); - unsigned int ref_count = 0; - unsigned int object_id = next_object_id++; + std::atomic<u32> ref_count{0}; + std::atomic<u32> object_id{next_object_id++}; }; // Special functions used by boost::instrusive_ptr to do automatic ref-counting inline void intrusive_ptr_add_ref(Object* object) { - ++object->ref_count; + object->ref_count.fetch_add(1, std::memory_order_relaxed); } inline void intrusive_ptr_release(Object* object) { - if (--object->ref_count == 0) { + if (object->ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) { delete object; } } diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 94065c736..e770b9103 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -25,7 +25,7 @@ Scheduler::~Scheduler() { } } -bool Scheduler::HaveReadyThreads() { +bool Scheduler::HaveReadyThreads() const { std::lock_guard<std::mutex> lock(scheduler_mutex); return ready_queue.get_first() != nullptr; } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 1a4ee8f36..6a61ef64e 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -21,7 +21,7 @@ public: ~Scheduler(); /// Returns whether there are any threads that are ready to run. - bool HaveReadyThreads(); + bool HaveReadyThreads() const; /// Reschedules to the next available thread (call after current thread is suspended) void Reschedule(); diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index d09ca5992..51a1ec160 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -152,7 +152,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the // end of the command such that only commands following this one are handled as domains if (convert_to_domain) { - ASSERT_MSG(domain_request_handlers.empty(), "already a domain"); + ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); domain_request_handlers = {hle_handler}; convert_to_domain = false; } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 2bce54fee..1a88e66b9 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -97,7 +97,12 @@ public: /// Returns true if the session has been converted to a domain, otherwise False bool IsDomain() const { - return !domain_request_handlers.empty(); + return !IsSession(); + } + + /// Returns true if this session has not been converted to a domain, otherwise false. + bool IsSession() const { + return domain_request_handlers.empty(); } /// Converts the session to a domain at the end of the current command diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 5db2db687..6be5c474e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -250,8 +250,11 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) { } /// Break program execution -static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { - LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); +static void Break(u64 reason, u64 info1, u64 info2) { + LOG_CRITICAL( + Debug_Emulated, + "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", + reason, info1, info2); ASSERT(false); } @@ -532,7 +535,6 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread)); *out_handle = thread->guest_handle; - Core::System::GetInstance().PrepareReschedule(); Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); LOG_TRACE(Kernel_SVC, @@ -706,8 +708,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); auto owner = g_handle_table.Get<Thread>(owner_handle); ASSERT(owner); - ASSERT(thread->status != ThreadStatus::Running); - thread->status = ThreadStatus::WaitMutex; + ASSERT(thread->status == ThreadStatus::WaitMutex); thread->wakeup_callback = nullptr; owner->AddMutexWaiter(thread); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index b9022feae..cf4f94822 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -23,6 +23,7 @@ #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" +#include "core/hle/lock.h" #include "core/hle/result.h" #include "core/memory.h" @@ -104,6 +105,10 @@ void ExitCurrentThread() { */ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { const auto proper_handle = static_cast<Handle>(thread_handle); + + // Lock the global kernel mutex when we enter the kernel HLE. + std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); + SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle); if (thread == nullptr) { LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); @@ -155,12 +160,14 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { if (nanoseconds == -1) return; - CoreTiming::ScheduleEvent(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType, - callback_handle); + // This function might be called from any thread so we have to be cautious and use the + // thread-safe version of ScheduleEvent. + CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType, + callback_handle); } void Thread::CancelWakeupTimer() { - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); + CoreTiming::UnscheduleEventThreadsafe(ThreadWakeupEventType, callback_handle); } static boost::optional<s32> GetNextProcessorId(u64 mask) { @@ -419,12 +426,33 @@ VAddr Thread::GetCommandBufferAddress() const { } void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { + if (thread->lock_owner == this) { + // If the thread is already waiting for this thread to release the mutex, ensure that the + // waiters list is consistent and return without doing anything. + auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); + ASSERT(itr != wait_mutex_threads.end()); + return; + } + + // A thread can't wait on two different mutexes at the same time. + ASSERT(thread->lock_owner == nullptr); + + // Ensure that the thread is not already in the list of mutex waiters + auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); + ASSERT(itr == wait_mutex_threads.end()); + thread->lock_owner = this; wait_mutex_threads.emplace_back(std::move(thread)); UpdatePriority(); } void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) { + ASSERT(thread->lock_owner == this); + + // Ensure that the thread is in the list of mutex waiters + auto itr = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); + ASSERT(itr != wait_mutex_threads.end()); + boost::remove_erase(wait_mutex_threads, thread); thread->lock_owner = nullptr; UpdatePriority(); diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 108a7c6eb..ce709ccf4 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -28,7 +28,7 @@ constexpr int DefaultSampleRate{48000}; class IAudioOut final : public ServiceFramework<IAudioOut> { public: IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) - : ServiceFramework("IAudioOut"), audio_params(audio_params), audio_core(audio_core) { + : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) { static const FunctionInfo functions[] = { {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index f99304de5..9e75eb3a6 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -20,9 +20,9 @@ public: explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params) : ServiceFramework("IAudioRenderer") { static const FunctionInfo functions[] = { - {0, nullptr, "GetAudioRendererSampleRate"}, - {1, nullptr, "GetAudioRendererSampleCount"}, - {2, nullptr, "GetAudioRendererMixBufferCount"}, + {0, &IAudioRenderer::GetAudioRendererSampleRate, "GetAudioRendererSampleRate"}, + {1, &IAudioRenderer::GetAudioRendererSampleCount, "GetAudioRendererSampleCount"}, + {2, &IAudioRenderer::GetAudioRendererMixBufferCount, "GetAudioRendererMixBufferCount"}, {3, nullptr, "GetAudioRendererState"}, {4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"}, {5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"}, @@ -45,6 +45,27 @@ private: system_event->Signal(); } + void GetAudioRendererSampleRate(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(renderer->GetSampleRate()); + LOG_DEBUG(Service_Audio, "called"); + } + + void GetAudioRendererSampleCount(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(renderer->GetSampleCount()); + LOG_DEBUG(Service_Audio, "called"); + } + + void GetAudioRendererMixBufferCount(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(renderer->GetMixBufferCount()); + LOG_DEBUG(Service_Audio, "called"); + } + void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); IPC::ResponseBuilder rb{ctx, 2}; @@ -169,7 +190,8 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") { {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"}, {2, &AudRenU::GetAudioDevice, "GetAudioDevice"}, {3, nullptr, "OpenAudioRendererAuto"}, - {4, nullptr, "GetAudioDeviceServiceWithRevisionInfo"}, + {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, + "GetAudioDeviceServiceWithRevisionInfo"}, }; RegisterHandlers(functions); } @@ -189,7 +211,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); - u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40); + u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); buffer_sz += params.unknown_c * 1024; buffer_sz += 0x940 * (params.unknown_c + 1); buffer_sz += 0x3F0 * params.voice_count; @@ -197,7 +219,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10); buffer_sz += Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) * - (params.unknown_8 + 6), + (params.mix_buffer_count + 6), 0x40); if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { @@ -253,6 +275,16 @@ void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); } +void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<Audio::IAudioDevice>(); + + LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different + // based on the current revision +} + bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap switch (feature) { diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 14907f8ae..8600ac6e4 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -22,6 +22,7 @@ private: void OpenAudioRenderer(Kernel::HLERequestContext& ctx); void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); void GetAudioDevice(Kernel::HLERequestContext& ctx); + void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx); enum class AudioFeatures : u32 { Splitter, diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 2b642c32f..f2b0e509a 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -26,7 +26,7 @@ public: {10600, nullptr, "DeclareOpenOnlinePlaySession"}, {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, - {10610, nullptr, "UpdateUserPresence"}, + {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"}, {10700, nullptr, "GetPlayHistoryRegistrationKey"}, {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, {10702, nullptr, "AddPlayHistory"}, @@ -99,6 +99,13 @@ private: IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } + + void UpdateUserPresence(Kernel::HLERequestContext& ctx) { + // Stub used by Retro City Rampage + LOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } }; void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index dcdfa0e19..970942d3f 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -291,6 +291,7 @@ private: class Hid final : public ServiceFramework<Hid> { public: Hid() : ServiceFramework("hid") { + // clang-format off static const FunctionInfo functions[] = { {0, &Hid::CreateAppletResource, "CreateAppletResource"}, {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, @@ -333,15 +334,13 @@ public: {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, {103, &Hid::ActivateNpad, "ActivateNpad"}, {104, nullptr, "DeactivateNpad"}, - {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, - "AcquireNpadStyleSetUpdateEventHandle"}, - {107, nullptr, "DisconnectNpad"}, + {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, + {107, &Hid::DisconnectNpad, "DisconnectNpad"}, {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, {109, nullptr, "ActivateNpadWithRevision"}, {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, - {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, - "SetNpadJoyAssignmentModeSingleByDefault"}, + {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, @@ -398,6 +397,8 @@ public: {1000, nullptr, "SetNpadCommunicationMode"}, {1001, nullptr, "GetNpadCommunicationMode"}, }; + // clang-format on + RegisterHandlers(functions); event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle"); @@ -496,6 +497,12 @@ private: LOG_WARNING(Service_HID, "(STUBBED) called"); } + void DisconnectNpad(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 2e99ddf51..098da2a41 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp @@ -92,7 +92,11 @@ private: // Parse out log metadata u32 line{}; - std::string message, filename, function; + std::string module; + std::string message; + std::string filename; + std::string function; + std::string thread; while (addr < end_addr) { const Field field{static_cast<Field>(Memory::Read8(addr++))}; const size_t length{Memory::Read8(addr++)}; @@ -102,6 +106,8 @@ private: } switch (field) { + case Field::Skip: + break; case Field::Message: message = Memory::ReadCString(addr, length); break; @@ -114,6 +120,12 @@ private: case Field::Function: function = Memory::ReadCString(addr, length); break; + case Field::Module: + module = Memory::ReadCString(addr, length); + break; + case Field::Thread: + thread = Memory::ReadCString(addr, length); + break; } addr += length; @@ -128,12 +140,18 @@ private: if (!filename.empty()) { log_stream << filename << ':'; } + if (!module.empty()) { + log_stream << module << ':'; + } if (!function.empty()) { log_stream << function << ':'; } if (line) { log_stream << std::to_string(line) << ':'; } + if (!thread.empty()) { + log_stream << thread << ':'; + } if (log_stream.str().length() > 0 && log_stream.str().back() == ':') { log_stream << ' '; } @@ -142,7 +160,7 @@ private: if (header.IsTailLog()) { switch (header.severity) { case MessageHeader::Severity::Trace: - LOG_TRACE(Debug_Emulated, "{}", log_stream.str()); + LOG_DEBUG(Debug_Emulated, "{}", log_stream.str()); break; case MessageHeader::Severity::Info: LOG_INFO(Debug_Emulated, "{}", log_stream.str()); diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index 08f45b78a..7b91bb258 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp @@ -9,42 +9,63 @@ namespace Service::MM { -void InstallInterfaces(SM::ServiceManager& service_manager) { - std::make_shared<MM_U>()->InstallAsService(service_manager); -} +class MM_U final : public ServiceFramework<MM_U> { +public: + explicit MM_U() : ServiceFramework{"mm:u"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &MM_U::Initialize, "InitializeOld"}, + {1, &MM_U::Finalize, "FinalizeOld"}, + {2, &MM_U::SetAndWait, "SetAndWaitOld"}, + {3, &MM_U::Get, "GetOld"}, + {4, &MM_U::Initialize, "Initialize"}, + {5, &MM_U::Finalize, "Finalize"}, + {6, &MM_U::SetAndWait, "SetAndWait"}, + {7, &MM_U::Get, "Get"}, + }; + // clang-format on -void MM_U::Initialize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_MM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} + RegisterHandlers(functions); + } -void MM_U::SetAndWait(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - min = rp.Pop<u32>(); - max = rp.Pop<u32>(); - current = min; +private: + void Initialize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } - LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} + void Finalize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } -void MM_U::Get(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_MM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push(current); -} + void SetAndWait(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + min = rp.Pop<u32>(); + max = rp.Pop<u32>(); + current = min; -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); + LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Get(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_MM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(current); + } + + u32 min{0}; + u32 max{0}; + u32 current{0}; +}; + +void InstallInterfaces(SM::ServiceManager& service_manager) { + std::make_shared<MM_U>()->InstallAsService(service_manager); } } // namespace Service::MM diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h index 79eeedf9c..5439fa653 100644 --- a/src/core/hle/service/mm/mm_u.h +++ b/src/core/hle/service/mm/mm_u.h @@ -8,21 +8,6 @@ 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); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp new file mode 100644 index 000000000..51f01077b --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -0,0 +1,34 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h" + +namespace Service::Nvidia::Devices { + +u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { + LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", + command.raw, input.size(), output.size()); + + switch (static_cast<IoctlCommand>(command.raw)) { + case IoctlCommand::IocSetNVMAPfdCommand: + return SetNVMAPfd(input, output); + } + + UNIMPLEMENTED_MSG("Unimplemented ioctl"); + return 0; +} + +u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlSetNvmapFD params{}; + std::memcpy(¶ms, input.data(), input.size()); + LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); + nvmap_fd = params.nvmap_fd; + return 0; +} + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h new file mode 100644 index 000000000..2b0eb43ee --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -0,0 +1,36 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/service/nvdrv/devices/nvdevice.h" + +namespace Service::Nvidia::Devices { + +class nvhost_nvjpg final : public nvdevice { +public: + nvhost_nvjpg() = default; + ~nvhost_nvjpg() override = default; + + u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; + +private: + enum class IoctlCommand : u32_le { + IocSetNVMAPfdCommand = 0x40044801, + }; + + struct IoctlSetNvmapFD { + u32_le nvmap_fd; + }; + static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); + + u32_le nvmap_fd{}; + + u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); +}; + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp new file mode 100644 index 000000000..fcb488d50 --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -0,0 +1,34 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/service/nvdrv/devices/nvhost_vic.h" + +namespace Service::Nvidia::Devices { + +u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { + LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", + command.raw, input.size(), output.size()); + + switch (static_cast<IoctlCommand>(command.raw)) { + case IoctlCommand::IocSetNVMAPfdCommand: + return SetNVMAPfd(input, output); + } + + UNIMPLEMENTED_MSG("Unimplemented ioctl"); + return 0; +} + +u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlSetNvmapFD params{}; + std::memcpy(¶ms, input.data(), input.size()); + LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); + nvmap_fd = params.nvmap_fd; + return 0; +} + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h new file mode 100644 index 000000000..c7d681e52 --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -0,0 +1,36 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/service/nvdrv/devices/nvdevice.h" + +namespace Service::Nvidia::Devices { + +class nvhost_vic final : public nvdevice { +public: + nvhost_vic() = default; + ~nvhost_vic() override = default; + + u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; + +private: + enum class IoctlCommand : u32_le { + IocSetNVMAPfdCommand = 0x40044801, + }; + + struct IoctlSetNvmapFD { + u32_le nvmap_fd; + }; + static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); + + u32_le nvmap_fd{}; + + u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); +}; + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 427f4b574..2de39822f 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -12,6 +12,8 @@ #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" +#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h" +#include "core/hle/service/nvdrv/devices/nvhost_vic.h" #include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -39,6 +41,8 @@ Module::Module() { devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(); devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(); + devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(); + devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(); } u32 Module::Open(const std::string& device_name) { diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 8a294c0f2..cd9c74f3d 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -23,7 +23,7 @@ class HLERequestContext; } // namespace Kernel namespace FileSys { -struct VfsFilesystem; +class VfsFilesystem; } namespace Service { diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 518a0cc46..1cef73216 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -10,7 +10,7 @@ namespace Service::SM { void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { - ASSERT_MSG(!ctx.Session()->IsDomain(), "session is alread a domain"); + ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); ctx.Session()->ConvertToDomain(); IPC::ResponseBuilder rb{ctx, 3}; @@ -41,7 +41,7 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(0x500); + rb.Push<u16>(0x500); LOG_WARNING(Service, "(STUBBED) called"); } diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index de05f21d8..d575a9bea 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -118,7 +118,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( process->program_id = metadata.GetTitleID(); process->svc_access_mask.set(); - process->address_mappings = default_address_mappings; process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 401cad3ab..6420a7f11 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -398,7 +398,6 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) { process->LoadModule(codeset, codeset->entrypoint); process->svc_access_mask.set(); - process->address_mappings = default_address_mappings; // Attach the default resource limit (APPLICATION) to the process process->resource_limit = diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 0e690abb3..70ef5d240 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <memory> +#include <ostream> #include <string> #include "common/logging/log.h" #include "common/string_util.h" @@ -17,12 +18,6 @@ namespace Loader { -const std::initializer_list<Kernel::AddressMapping> default_address_mappings = { - {0x1FF50000, 0x8000, true}, // part of DSP RAM - {0x1FF70000, 0x8000, true}, // part of DSP RAM - {0x1F000000, 0x600000, false}, // entire VRAM -}; - FileType IdentifyFile(FileSys::VirtualFile file) { FileType type; @@ -127,14 +122,9 @@ constexpr std::array<const char*, 36> RESULT_MESSAGES{ "There is no control data available.", }; -std::string GetMessageForResultStatus(ResultStatus status) { - return GetMessageForResultStatus(static_cast<size_t>(status)); -} - -std::string GetMessageForResultStatus(u16 status) { - if (status >= 36) - return ""; - return RESULT_MESSAGES[status]; +std::ostream& operator<<(std::ostream& os, ResultStatus status) { + os << RESULT_MESSAGES.at(static_cast<size_t>(status)); + return os; } /** diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index cfdadbee3..b74cfbf8a 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -5,7 +5,7 @@ #pragma once #include <algorithm> -#include <initializer_list> +#include <iosfwd> #include <memory> #include <string> #include <utility> @@ -56,7 +56,7 @@ FileType GuessFromFilename(const std::string& name); std::string GetFileTypeString(FileType type); /// Return type for functions in Loader namespace -enum class ResultStatus { +enum class ResultStatus : u16 { Success, ErrorAlreadyLoaded, ErrorNotImplemented, @@ -95,8 +95,7 @@ enum class ResultStatus { ErrorNoControl, }; -std::string GetMessageForResultStatus(ResultStatus status); -std::string GetMessageForResultStatus(u16 status); +std::ostream& operator<<(std::ostream& os, ResultStatus status); /// Interface for loading an application class AppLoader : NonCopyable { @@ -208,12 +207,6 @@ protected: }; /** - * Common address mappings found in most games, used for binary formats that don't have this - * information. - */ -extern const std::initializer_list<Kernel::AddressMapping> default_address_mappings; - -/** * Identifies a bootable file and return a suitable loader * @param file The bootable file * @return the best loader for this file diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 908d91eab..2179cf2ea 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -186,7 +186,6 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) { } process->svc_access_mask.set(); - process->address_mappings = default_address_mappings; process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index fee7d58c6..a94558ac5 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -152,7 +152,6 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); process->svc_access_mask.set(); - process->address_mappings = default_address_mappings; process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); |