diff options
Diffstat (limited to 'src/core/hle')
66 files changed, 1517 insertions, 708 deletions
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp index 40bae9346..aea936d2d 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp @@ -2,71 +2,30 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> + +#include "common/assert.h" #include "common/common_types.h" #include "common/common_funcs.h" #include "core/core.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/config_mem.h" //////////////////////////////////////////////////////////////////////////////////////////////////// namespace ConfigMem { -struct ConfigMemDef { - u8 kernel_unk; // 0 - u8 kernel_version_rev; // 1 - u8 kernel_version_min; // 2 - u8 kernel_version_maj; // 3 - u32 update_flag; // 4 - u64 ns_tid; // 8 - u32 sys_core_ver; // 10 - u8 unit_info; // 14 - u8 boot_firm; // 15 - u8 prev_firm; // 16 - INSERT_PADDING_BYTES(0x1); // 17 - u32 ctr_sdk_ver; // 18 - INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C - u32 app_mem_type; // 30 - INSERT_PADDING_BYTES(0x40 - 0x34); // 34 - u32 app_mem_alloc; // 40 - u32 sys_mem_alloc; // 44 - u32 base_mem_alloc; // 48 - INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C - u8 firm_unk; // 60 - u8 firm_version_rev; // 61 - u8 firm_version_min; // 62 - u8 firm_version_maj; // 63 - u32 firm_sys_core_ver; // 64 - u32 firm_ctr_sdk_ver; // 68 - INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C -}; - -static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong"); - -static ConfigMemDef config_mem; - -template <typename T> -inline void Read(T &var, const u32 addr) { - u32 offset = addr - Memory::CONFIG_MEMORY_VADDR; - ASSERT(offset < Memory::CONFIG_MEMORY_SIZE); - var = *(reinterpret_cast<T*>(((uintptr_t)&config_mem) + offset)); -} - -// Explicitly instantiate template functions because we aren't defining this in the header: - -template void Read<u64>(u64 &var, const u32 addr); -template void Read<u32>(u32 &var, const u32 addr); -template void Read<u16>(u16 &var, const u32 addr); -template void Read<u8>(u8 &var, const u32 addr); +ConfigMemDef config_mem; void Init() { + std::memset(&config_mem, 0, sizeof(config_mem)); + config_mem.update_flag = 0; // No update config_mem.sys_core_ver = 0x2; config_mem.unit_info = 0x1; // Bit 0 set for Retail config_mem.prev_firm = 0; config_mem.app_mem_type = 0x2; // Default app mem type is 0 - config_mem.unit_info = 0x1; // Bit 0 set for Retail config_mem.app_mem_alloc = 0x06000000; // Set to 96MB, since some games use more than the default (64MB) config_mem.base_mem_alloc = 0x01400000; // Default base memory is 20MB config_mem.sys_mem_alloc = Memory::FCRAM_SIZE - (config_mem.app_mem_alloc + config_mem.base_mem_alloc); @@ -77,4 +36,7 @@ void Init() { config_mem.firm_sys_core_ver = 0x2; } +void Shutdown() { +} + } // namespace diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h index 94853901a..9825a09e8 100644 --- a/src/core/hle/config_mem.h +++ b/src/core/hle/config_mem.h @@ -9,15 +9,49 @@ // bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm // putting this as a subset of HLE for now. +#include "common/common_funcs.h" #include "common/common_types.h" +#include "common/swap.h" + +#include "core/memory.h" //////////////////////////////////////////////////////////////////////////////////////////////////// namespace ConfigMem { -template <typename T> -void Read(T &var, const u32 addr); +struct ConfigMemDef { + u8 kernel_unk; // 0 + u8 kernel_version_rev; // 1 + u8 kernel_version_min; // 2 + u8 kernel_version_maj; // 3 + u32_le update_flag; // 4 + u64_le ns_tid; // 8 + u32_le sys_core_ver; // 10 + u8 unit_info; // 14 + u8 boot_firm; // 15 + u8 prev_firm; // 16 + INSERT_PADDING_BYTES(0x1); // 17 + u32_le ctr_sdk_ver; // 18 + INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C + u32_le app_mem_type; // 30 + INSERT_PADDING_BYTES(0x40 - 0x34); // 34 + u32_le app_mem_alloc; // 40 + u32_le sys_mem_alloc; // 44 + u32_le base_mem_alloc; // 48 + INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C + u8 firm_unk; // 60 + u8 firm_version_rev; // 61 + u8 firm_version_min; // 62 + u8 firm_version_maj; // 63 + u32_le firm_sys_core_ver; // 64 + u32_le firm_ctr_sdk_ver; // 68 + INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C +}; +static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong"); + +extern ConfigMemDef config_mem; void Init(); +void Shutdown(); } // namespace diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 0b6b6f518..eb52c8fb1 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -7,7 +7,7 @@ #include "common/common_types.h" #include "core/arm/arm_interface.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/hle.h" namespace HLE { @@ -46,6 +46,13 @@ template<ResultCode func(u32*, u32, u32, u32, u32, u32)> void Wrap(){ FuncReturn(retval); } +template<ResultCode func(u32*, s32, u32, u32, u32, s32)> void Wrap() { + u32 param_1 = 0; + u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; + Core::g_app_core->SetReg(1, param_1); + FuncReturn(retval); +} + template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() { s32 param_1 = 0; s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), @@ -102,7 +109,7 @@ template<ResultCode func(s64*, u32, void*, s32)> void Wrap(){ template<ResultCode func(u32*, const char*)> void Wrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, Memory::GetCharPointer(PARAM(1))).raw; + u32 retval = func(¶m_1, (char*)Memory::GetPointer(PARAM(1))).raw; Core::g_app_core->SetReg(1, param_1); FuncReturn(retval); } @@ -156,7 +163,7 @@ template<void func(s64)> void Wrap() { } template<void func(const char*)> void Wrap() { - func(Memory::GetCharPointer(PARAM(0))); + func((char*)Memory::GetPointer(PARAM(0))); } #undef PARAM diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 1aaeaa9c9..fdeb9a028 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -2,12 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <vector> - -#include "common/profiler.h" +#include "common/assert.h" +#include "common/logging/log.h" #include "core/arm/arm_interface.h" -#include "core/mem_map.h" +#include "core/core.h" #include "core/hle/hle.h" #include "core/hle/config_mem.h" #include "core/hle/shared_page.h" @@ -18,35 +17,7 @@ namespace HLE { -Common::Profiling::TimingCategory profiler_svc("SVC Calls"); - -static std::vector<ModuleDef> g_module_db; - -bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread - -static const FunctionDef* GetSVCInfo(u32 opcode) { - u32 func_num = opcode & 0xFFFFFF; // 8 bits - if (func_num > 0xFF) { - LOG_ERROR(Kernel_SVC,"unknown svc=0x%02X", func_num); - return nullptr; - } - return &g_module_db[0].func_table[func_num]; -} - -void CallSVC(u32 opcode) { - Common::Profiling::ScopeTimer timer_svc(profiler_svc); - - const FunctionDef *info = GetSVCInfo(opcode); - - if (!info) { - return; - } - if (info->func) { - info->func(); - } else { - LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name.c_str()); - } -} +bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread void Reschedule(const char *reason) { DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256, "Reschedule: Invalid or too long reason."); @@ -62,31 +33,21 @@ void Reschedule(const char *reason) { g_reschedule = true; } -void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) { - ModuleDef module = {name, num_functions, func_table}; - g_module_db.push_back(module); -} - -static void RegisterAllModules() { - SVC::Register(); -} - void Init() { Service::Init(); - - RegisterAllModules(); - ConfigMem::Init(); SharedPage::Init(); + g_reschedule = false; + LOG_DEBUG(Kernel, "initialized OK"); } void Shutdown() { + ConfigMem::Shutdown(); + SharedPage::Shutdown(); Service::Shutdown(); - g_module_db.clear(); - LOG_DEBUG(Kernel, "shutdown OK"); } diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h index 3f6f9a4b5..e0b97797c 100644 --- a/src/core/hle/hle.h +++ b/src/core/hle/hle.h @@ -4,40 +4,20 @@ #pragma once -#include <string> - #include "common/common_types.h" -#include "core/core.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// +typedef u32 Handle; +typedef s32 Result; + +const Handle INVALID_HANDLE = 0; namespace HLE { extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread -typedef u32 Addr; -typedef void (*Func)(); - -struct FunctionDef { - u32 id; - Func func; - std::string name; -}; - -struct ModuleDef { - std::string name; - int num_funcs; - const FunctionDef* func_table; -}; - -void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table); - -void CallSVC(u32 opcode); - void Reschedule(const char *reason); void Init(); - void Shutdown(); } // namespace diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 42f8ce2d9..a1221766e 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -3,8 +3,9 @@ // Refer to the license.txt file included. #include "common/common_types.h" +#include "common/logging/log.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/hle.h" #include "core/hle/kernel/address_arbiter.h" @@ -46,14 +47,12 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, case ArbitrationType::WaitIfLessThan: if ((s32)Memory::Read32(address) <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); - HLE::Reschedule(__func__); } break; case ArbitrationType::WaitIfLessThanWithTimeout: if ((s32)Memory::Read32(address) <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); GetCurrentThread()->WakeAfterDelay(nanoseconds); - HLE::Reschedule(__func__); } break; case ArbitrationType::DecrementAndWaitIfLessThan: @@ -62,7 +61,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, Memory::Write32(address, memory_value); if (memory_value <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); - HLE::Reschedule(__func__); } break; } @@ -73,7 +71,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, if (memory_value <= value) { Kernel::WaitCurrentThread_ArbitrateAddress(address); GetCurrentThread()->WakeAfterDelay(nanoseconds); - HLE::Reschedule(__func__); } break; } diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 420906ec0..f338f3266 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -6,7 +6,7 @@ #include <algorithm> #include <vector> -#include "common/common.h" +#include "common/assert.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/event.h" diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 498b2ec98..b5c98b249 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -4,21 +4,20 @@ #include <algorithm> -#include "common/common.h" +#include "common/assert.h" +#include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" namespace Kernel { -unsigned int Object::next_object_id = 0; - -SharedPtr<Thread> g_main_thread = nullptr; +unsigned int Object::next_object_id; HandleTable g_handle_table; -u64 g_program_id = 0; void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); @@ -116,8 +115,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { return GetCurrentThread(); } else if (handle == CurrentProcess) { - LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess); - return nullptr; + return g_current_process; } if (!IsValid(handle)) { @@ -138,6 +136,11 @@ void HandleTable::Clear() { void Init() { Kernel::ThreadingInit(); Kernel::TimersInit(); + + Object::next_object_id = 0; + // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are + // reserved for low-level services + Process::next_process_id = 10; } /// Shutdown the kernel @@ -145,18 +148,7 @@ void Shutdown() { Kernel::ThreadingShutdown(); Kernel::TimersShutdown(); g_handle_table.Clear(); // Free all kernel objects -} - -/** - * Loads executable stored at specified address - * @entry_point Entry point in memory of loaded executable - * @return True on success, otherwise false - */ -bool LoadExec(u32 entry_point) { - // 0x30 is the typical main thread priority I've seen used so far - g_main_thread = Kernel::SetupMainThread(Kernel::DEFAULT_STACK_SIZE, entry_point, 0x30); - - return true; + g_current_process = nullptr; } } // namespace diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2d295ea00..7c106d37c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -7,21 +7,16 @@ #include <boost/intrusive_ptr.hpp> #include <array> +#include <memory> #include <string> #include <vector> -#include "common/common.h" -#include "core/hle/result.h" - -typedef u32 Handle; -typedef s32 Result; +#include "common/common_types.h" -// TODO: It would be nice to eventually replace these with strong types that prevent accidental -// conversion between each other. -typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. -typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. +#include "core/hle/hle.h" +#include "core/hle/result.h" -const Handle INVALID_HANDLE = 0; +struct ApplicationInfo; namespace Kernel { @@ -95,12 +90,13 @@ public: return false; } +public: + static unsigned int next_object_id; + private: friend void intrusive_ptr_add_ref(Object*); friend void intrusive_ptr_release(Object*); - static unsigned int next_object_id; - unsigned int ref_count = 0; unsigned int object_id = next_object_id++; }; @@ -277,23 +273,10 @@ private: extern HandleTable g_handle_table; -/// The ID code of the currently running game -/// TODO(Subv): This variable should not be here, -/// we need a way to store information about the currently loaded application -/// for later query during runtime, maybe using the LDR service? -extern u64 g_program_id; - /// Initialize the kernel void Init(); /// Shutdown the kernel void Shutdown(); -/** - * Loads executable stored at specified address - * @entry_point Entry point in memory of loaded executable - * @return True on success, otherwise false - */ -bool LoadExec(u32 entry_point); - } // namespace diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index be2c49706..f530217fd 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -7,7 +7,7 @@ #include <boost/range/algorithm_ext/erase.hpp> -#include "common/common.h" +#include "common/assert.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/mutex.h" @@ -56,7 +56,15 @@ SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { } bool Mutex::ShouldWait() { - return lock_count > 0 && holding_thread != GetCurrentThread();; + auto thread = GetCurrentThread(); + bool wait = lock_count > 0 && holding_thread != thread; + + // If the holding thread of the mutex is lower priority than this thread, that thread should + // temporarily inherit this thread's priority + if (wait && thread->current_priority < holding_thread->current_priority) + holding_thread->BoostPriority(thread->current_priority); + + return wait; } void Mutex::Acquire() { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp new file mode 100644 index 000000000..0cdfa58d7 --- /dev/null +++ b/src/core/hle/kernel/process.cpp @@ -0,0 +1,98 @@ +// Copyright 2015 Citra Emulator Project +// 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/logging/log.h" + +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/thread.h" +#include "core/memory.h" + +namespace Kernel { + +u32 Process::next_process_id; + +SharedPtr<Process> Process::Create(std::string name, u64 program_id) { + SharedPtr<Process> process(new Process); + + process->name = std::move(name); + process->program_id = program_id; + + process->flags.raw = 0; + process->flags.memory_region = MemoryRegion::APPLICATION; + + return process; +} + +void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { + for (int i = 0; i < len; ++i) { + u32 descriptor = kernel_caps[i]; + u32 type = descriptor >> 20; + + if (descriptor == 0xFFFFFFFF) { + // Unused descriptor entry + continue; + } else if ((type & 0xF00) == 0xE00) { // 0x0FFF + // Allowed interrupts list + LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored"); + } else if ((type & 0xF80) == 0xF00) { // 0x07FF + // Allowed syscalls mask + unsigned int index = ((descriptor >> 24) & 7) * 24; + u32 bits = descriptor & 0xFFFFFF; + + while (bits && index < svc_access_mask.size()) { + svc_access_mask.set(index, bits & 1); + ++index; bits >>= 1; + } + } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF + // Handle table size + handle_table_size = descriptor & 0x3FF; + } else if ((type & 0xFF8) == 0xFF0) { // 0x007F + // Misc. flags + flags.raw = descriptor & 0xFFFF; + } else if ((type & 0xFFE) == 0xFF8) { // 0x001F + // Mapped memory range + if (i+1 >= len || ((kernel_caps[i+1] >> 20) & 0xFFE) != 0xFF8) { + LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); + continue; + } + u32 end_desc = kernel_caps[i+1]; + ++i; // Skip over the second descriptor on the next iteration + + AddressMapping mapping; + mapping.address = descriptor << 12; + mapping.size = (end_desc << 12) - mapping.address; + mapping.writable = descriptor & (1 << 20); + mapping.unk_flag = end_desc & (1 << 20); + + address_mappings.push_back(mapping); + } else if ((type & 0xFFF) == 0xFFE) { // 0x000F + // Mapped memory page + AddressMapping mapping; + mapping.address = descriptor << 12; + mapping.size = Memory::PAGE_SIZE; + mapping.writable = true; // TODO: Not sure if correct + mapping.unk_flag = false; + } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF + // Kernel version + int minor = descriptor & 0xFF; + int major = (descriptor >> 8) & 0xFF; + LOG_INFO(Loader, "ExHeader kernel version ignored: %d.%d", major, minor); + } else { + LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor); + } + } +} + +void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { + Kernel::SetupMainThread(entry_point, main_thread_priority); +} + +Kernel::Process::Process() {} +Kernel::Process::~Process() {} + +SharedPtr<Process> g_current_process; + +} diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h new file mode 100644 index 000000000..90881054c --- /dev/null +++ b/src/core/hle/kernel/process.h @@ -0,0 +1,98 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <bitset> + +#include <boost/container/static_vector.hpp> + +#include "common/bit_field.h" +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" + +namespace Kernel { + +struct AddressMapping { + // Address and size must be page-aligned + VAddr address; + u32 size; + bool writable; + bool unk_flag; +}; + +enum class MemoryRegion : u16 { + APPLICATION = 1, + SYSTEM = 2, + BASE = 3, +}; + +union ProcessFlags { + u16 raw; + + BitField< 0, 1, u16> allow_debug; ///< Allows other processes to attach to and debug this process. + BitField< 1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they don't have allow_debug set. + BitField< 2, 1, u16> allow_nonalphanum; + BitField< 3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions. + BitField< 4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24. + BitField< 5, 1, u16> allow_main_args; + BitField< 6, 1, u16> shared_device_mem; + BitField< 7, 1, u16> runnable_on_sleep; + BitField< 8, 4, MemoryRegion> memory_region; ///< Default region for memory allocations for this process + BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). +}; + +class Process final : public Object { +public: + static SharedPtr<Process> Create(std::string name, u64 program_id); + + std::string GetTypeName() const override { return "Process"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::Process; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + static u32 next_process_id; + + /// Name of the process + std::string name; + /// Title ID corresponding to the process + u64 program_id; + + /// The process may only call SVCs which have the corresponding bit set. + std::bitset<0x80> svc_access_mask; + /// Maximum size of the handle table for the process. + unsigned int handle_table_size = 0x200; + /// Special memory ranges mapped into this processes address space. This is used to give + /// processes access to specific I/O regions and device memory. + boost::container::static_vector<AddressMapping, 8> address_mappings; + ProcessFlags flags; + + /// The id of this process + u32 process_id = next_process_id++; + + /// Bitmask of the used TLS slots + std::bitset<300> used_tls_slots; + + /** + * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them + * to this process. + */ + void ParseKernelCaps(const u32* kernel_caps, size_t len); + + /** + * Applies address space changes and launches the process main thread. + */ + void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size); + +private: + Process(); + ~Process() override; +}; + +extern SharedPtr<Process> g_current_process; + +} diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 6aecc24aa..5d6543ef4 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/common.h" +#include "common/assert.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/semaphore.h" diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 9e9288e0f..54a062971 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -5,19 +5,23 @@ #pragma once #include "core/hle/kernel/kernel.h" -#include "core/mem_map.h" +#include "core/hle/kernel/thread.h" +#include "core/memory.h" namespace Kernel { static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header /** - * Returns a pointer to the command buffer in kernel memory + * Returns a pointer to the command buffer in the current thread's TLS + * TODO(Subv): This is not entirely correct, the command buffer should be copied from + * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to + * the service handler process' memory. * @param offset Optional offset into command buffer * @return Pointer to command buffer */ -inline static u32* GetCommandBuffer(const int offset=0) { - return (u32*)Memory::GetPointer(Memory::KERNEL_MEMORY_VADDR + kCommandHeaderOffset + offset); +inline static u32* GetCommandBuffer(const int offset = 0) { + return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset); } /** diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 4211fcf04..4137683b5 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -2,9 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/common.h" +#include <cstring> -#include "core/mem_map.h" +#include "common/logging/log.h" + +#include "core/memory.h" #include "core/hle/kernel/shared_memory.h" namespace Kernel { @@ -12,10 +14,15 @@ namespace Kernel { SharedMemory::SharedMemory() {} SharedMemory::~SharedMemory() {} -SharedPtr<SharedMemory> SharedMemory::Create(std::string name) { +SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions, + MemoryPermission other_permissions, std::string name) { SharedPtr<SharedMemory> shared_memory(new SharedMemory); shared_memory->name = std::move(name); + shared_memory->base_address = 0x0; + shared_memory->size = size; + shared_memory->permissions = permissions; + shared_memory->other_permissions = other_permissions; return shared_memory; } @@ -23,7 +30,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(std::string name) { ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions) { - if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { + if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!", GetObjectId(), address); // TODO: Verify error code with hardware @@ -31,21 +38,25 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } + // TODO: Test permissions + + // HACK: Since there's no way to write to the memory block without mapping it onto the game + // process yet, at least initialize memory the first time it's mapped. + if (address != this->base_address) { + std::memset(Memory::GetPointer(address), 0, size); + } + this->base_address = address; - this->permissions = permissions; - this->other_permissions = other_permissions; return RESULT_SUCCESS; } -ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { +u8* SharedMemory::GetPointer(u32 offset) { if (base_address != 0) - return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); + return Memory::GetPointer(base_address + offset); LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId()); - // TODO(yuriks): Verify error code. - return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, - ErrorSummary::InvalidState, ErrorLevel::Permanent); + return nullptr; } } // namespace diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 5833b411c..204266896 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -27,11 +27,16 @@ class SharedMemory final : public Object { public: /** * Creates a shared memory object - * @param name Optional object name, used only for debugging purposes. + * @param size Size of the memory block. Must be page-aligned. + * @param permissions Permission restrictions applied to the process which created the block. + * @param other_permissions Permission restrictions applied to other processes mapping the block. + * @param name Optional object name, used for debugging purposes. */ - static SharedPtr<SharedMemory> Create(std::string name = "Unknown"); + static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions, + MemoryPermission other_permissions, std::string name = "Unknown"); std::string GetTypeName() const override { return "SharedMemory"; } + std::string GetName() const override { return name; } static const HandleType HANDLE_TYPE = HandleType::SharedMemory; HandleType GetHandleType() const override { return HANDLE_TYPE; } @@ -49,12 +54,18 @@ public: * @param offset Offset from the start of the shared memory block to get pointer * @return Pointer to the shared memory block from the specified offset */ - ResultVal<u8*> GetPointer(u32 offset = 0); + u8* GetPointer(u32 offset = 0); - VAddr base_address; ///< Address of shared memory block in RAM - MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) - MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) - std::string name; ///< Name of shared memory object (optional) + /// Address of shared memory block in the process. + VAddr base_address; + /// Size of the memory block. Page-aligned. + u32 size; + /// Permission restrictions applied to the process which created the block. + MemoryPermission permissions; + /// Permission restrictions applied to other processes mapping the block. + MemoryPermission other_permissions; + /// Name of shared memory object. + std::string name; private: SharedMemory(); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index be1aed615..a5f1904d7 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -6,7 +6,9 @@ #include <list> #include <vector> -#include "common/common.h" +#include "common/assert.h" +#include "common/common_types.h" +#include "common/logging/log.h" #include "common/math_util.h" #include "common/thread_queue_list.h" @@ -15,15 +17,16 @@ #include "core/core_timing.h" #include "core/hle/hle.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/mutex.h" #include "core/hle/result.h" -#include "core/mem_map.h" +#include "core/memory.h" namespace Kernel { /// Event type for the thread wake up event -static int ThreadWakeupEventType = -1; +static int ThreadWakeupEventType; bool Thread::ShouldWait() { return status != THREADSTATUS_DEAD; @@ -42,7 +45,7 @@ static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue; static Thread* current_thread; // The first available thread id at startup -static u32 next_thread_id = 1; +static u32 next_thread_id; /** * Creates a new thread ID @@ -104,6 +107,8 @@ void Thread::Stop() { for (auto& wait_object : wait_objects) { wait_object->RemoveWaitingThread(this); } + + Kernel::g_current_process->used_tls_slots[tls_index] = false; } Thread* ArbitrateHighestPriorityThread(u32 address) { @@ -140,17 +145,38 @@ void ArbitrateAllThreads(u32 address) { } } +/// Boost low priority threads (temporarily) that have been starved +static void PriorityBoostStarvedThreads() { + u64 current_ticks = CoreTiming::GetTicks(); + + for (auto& thread : thread_list) { + // TODO(bunnei): Threads that have been waiting to be scheduled for `boost_ticks` (or + // longer) will have their priority temporarily adjusted to 1 higher than the highest + // priority thread to prevent thread starvation. This general behavior has been verified + // on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler + // should probably be reversed to verify this. + + const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long + + u64 delta = current_ticks - thread->last_running_ticks; + + if (thread->status == THREADSTATUS_READY && delta > boost_timeout) { + const s32 priority = std::max(ready_queue.get_first()->current_priority - 1, 0); + thread->BoostPriority(priority); + } + } +} + /** * Switches the CPU's active thread context to that of the specified thread * @param new_thread The thread to switch to */ static void SwitchContext(Thread* new_thread) { - DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); - Thread* previous_thread = GetCurrentThread(); // Save context for previous thread if (previous_thread) { + previous_thread->last_running_ticks = CoreTiming::GetTicks(); Core::g_app_core->SaveContext(previous_thread->context); if (previous_thread->status == THREADSTATUS_RUNNING) { @@ -163,12 +189,18 @@ static void SwitchContext(Thread* new_thread) { // Load context of new thread if (new_thread) { + DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); + current_thread = new_thread; ready_queue.remove(new_thread->current_priority, new_thread); new_thread->status = THREADSTATUS_RUNNING; + // Restores thread to its nominal priority if it has been temporarily changed + new_thread->current_priority = new_thread->nominal_priority; + Core::g_app_core->LoadContext(new_thread->context); + Core::g_app_core->SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress()); } else { current_thread = nullptr; } @@ -186,6 +218,10 @@ static Thread* PopNextReadyThread() { // We have to do better than the current thread. // This call returns null when that's not possible. next = ready_queue.pop_first_better(thread->current_priority); + if (!next) { + // Otherwise just keep going with the current thread + next = thread; + } } else { next = ready_queue.pop_first(); } @@ -364,7 +400,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->status = THREADSTATUS_DORMANT; thread->entry_point = entry_point; thread->stack_top = stack_top; - thread->initial_priority = thread->current_priority = priority; + thread->nominal_priority = thread->current_priority = priority; + thread->last_running_ticks = CoreTiming::GetTicks(); thread->processor_id = processor_id; thread->wait_set_output = false; thread->wait_all = false; @@ -372,6 +409,20 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->wait_address = 0; thread->name = std::move(name); thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); + thread->owner_process = g_current_process; + thread->tls_index = -1; + + // Find the next available TLS index, and mark it as used + auto& used_tls_slots = Kernel::g_current_process->used_tls_slots; + for (unsigned int i = 0; i < used_tls_slots.size(); ++i) { + if (used_tls_slots[i] == false) { + thread->tls_index = i; + used_tls_slots[i] = true; + break; + } + } + + ASSERT_MSG(thread->tls_index != -1, "Out of TLS space"); // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context @@ -400,35 +451,26 @@ static void ClampPriority(const Thread* thread, s32* priority) { void Thread::SetPriority(s32 priority) { ClampPriority(this, &priority); - if (current_priority == priority) { - return; - } - - if (status == THREADSTATUS_READY) { - // If thread was ready, adjust queues - ready_queue.remove(current_priority, this); + // If thread was ready, adjust queues + if (status == THREADSTATUS_READY) + ready_queue.move(this, current_priority, priority); + else ready_queue.prepare(priority); - ready_queue.push_back(priority, this); - } - - current_priority = priority; -} -SharedPtr<Thread> SetupIdleThread() { - // We need to pass a few valid values to get around parameter checking in Thread::Create. - auto thread = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, - THREADPROCESSORID_0, 0).MoveFrom(); + nominal_priority = current_priority = priority; +} - thread->idle = true; - return thread; +void Thread::BoostPriority(s32 priority) { + ready_queue.move(this, current_priority, priority); + current_priority = priority; } -SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority) { +SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) { DEBUG_ASSERT(!GetCurrentThread()); // Initialize new "main" thread auto thread_res = Thread::Create("main", entry_point, priority, 0, - THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END); + THREADPROCESSORID_0, Memory::HEAP_VADDR_END); SharedPtr<Thread> thread = thread_res.MoveFrom(); @@ -439,21 +481,25 @@ SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority) } void Reschedule() { - Thread* prev = GetCurrentThread(); + PriorityBoostStarvedThreads(); + + Thread* cur = GetCurrentThread(); Thread* next = PopNextReadyThread(); HLE::g_reschedule = false; - if (next != nullptr) { - LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId()); - SwitchContext(next); - } else { - LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId()); + // Don't bother switching to the same thread + if (next == cur) + return; - for (auto& thread : thread_list) { - LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(), - thread->current_priority, thread->status); - } + if (cur && next) { + LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); + } else if (cur) { + LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); + } else if (next) { + LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); } + + SwitchContext(next); } void Thread::SetWaitSynchronizationResult(ResultCode result) { @@ -464,13 +510,20 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { context.cpu_registers[1] = output; } +VAddr Thread::GetTLSAddress() const { + return Memory::TLS_AREA_VADDR + tls_index * 0x200; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void ThreadingInit() { ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); - // Setup the idle thread - SetupIdleThread(); + current_thread = nullptr; + next_thread_id = 1; + + thread_list.clear(); + ready_queue.clear(); } void ThreadingShutdown() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index cfd073a70..389928178 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -12,22 +12,23 @@ #include "common/common_types.h" #include "core/core.h" -#include "core/mem_map.h" #include "core/hle/kernel/kernel.h" #include "core/hle/result.h" -enum ThreadPriority { - THREADPRIO_HIGHEST = 0, ///< Highest thread priority - THREADPRIO_DEFAULT = 16, ///< Default thread priority for userland apps - THREADPRIO_LOW = 31, ///< Low range of thread priority for userland apps - THREADPRIO_LOWEST = 63, ///< Thread priority max checked by svcCreateThread +enum ThreadPriority : s32{ + THREADPRIO_HIGHEST = 0, ///< Highest thread priority + THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps + THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps + THREADPRIO_LOWEST = 63, ///< Lowest thread priority }; -enum ThreadProcessorId { - THREADPROCESSORID_0 = 0xFFFFFFFE, ///< Enables core appcode - THREADPROCESSORID_1 = 0xFFFFFFFD, ///< Enables core syscore - THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores +enum ThreadProcessorId : s32 { + THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader + THREADPROCESSORID_ALL = -1, ///< Run thread on either core + THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore) + THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore) + THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this }; enum ThreadStatus { @@ -43,6 +44,7 @@ enum ThreadStatus { namespace Kernel { class Mutex; +class Process; class Thread final : public WaitObject { public: @@ -70,12 +72,6 @@ public: void Acquire() override; /** - * Checks if the thread is an idle (stub) thread - * @return True if the thread is an idle (stub) thread, false otherwise - */ - inline bool IsIdle() const { return idle; } - - /** * Gets the thread's current priority * @return The current thread's priority */ @@ -88,6 +84,12 @@ public: void SetPriority(s32 priority); /** + * Temporarily boosts the thread's priority until the next time it is scheduled + * @param priority The new priority + */ + void BoostPriority(s32 priority); + + /** * Gets the thread's thread ID * @return The thread's ID */ @@ -127,6 +129,12 @@ public: */ void Stop(); + /* + * Returns the Thread Local Storage address of the current thread + * @returns VAddr of the thread's TLS + */ + VAddr GetTLSAddress() const; + Core::ThreadContext context; u32 thread_id; @@ -135,14 +143,19 @@ public: u32 entry_point; u32 stack_top; - s32 initial_priority; - s32 current_priority; + s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application + s32 current_priority; ///< Current thread priority, can be temporarily changed + + u64 last_running_ticks; ///< CPU tick when thread was last running s32 processor_id; + s32 tls_index; ///< Index of the Thread Local Storage of the thread + /// Mutexes currently held by this thread, which will be released when it exits. boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; + SharedPtr<Process> owner_process; ///< Process that owns this thread std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address bool wait_all; ///< True if the thread is waiting on all objects before resuming @@ -150,9 +163,6 @@ public: std::string name; - /// Whether this thread is intended to never actually be executed, i.e. always idle - bool idle = false; - private: Thread(); ~Thread() override; @@ -161,16 +171,13 @@ private: Handle callback_handle; }; -extern SharedPtr<Thread> g_main_thread; - /** * Sets up the primary application thread - * @param stack_size The size of the thread's stack * @param entry_point The address at which the thread should start execution * @param priority The priority to give the main thread * @return A shared pointer to the main thread */ -SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority); +SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority); /** * Reschedules to the next available thread (call after current thread is suspended) @@ -214,14 +221,6 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); /** - * Sets up the idle thread, this is a thread that is intended to never execute instructions, - * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue - * and will try to yield on every call. - * @return The handle of the idle thread - */ -SharedPtr<Thread> SetupIdleThread(); - -/** * Initialize threading */ void ThreadingInit(); diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 610e26a3c..e69fece65 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -2,7 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/common.h" +#include "common/assert.h" +#include "common/logging/log.h" #include "core/core_timing.h" #include "core/hle/kernel/kernel.h" @@ -12,7 +13,7 @@ namespace Kernel { /// The event type of the generic timer callback event -static int timer_callback_event_type = -1; +static int timer_callback_event_type; // TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing // us to simply use a pool index or similar. static Kernel::HandleTable timer_callback_handle_table; @@ -66,7 +67,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle)); if (timer == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); + LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08lX", timer_handle); return; } @@ -89,6 +90,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { } void TimersInit() { + timer_callback_handle_table.Clear(); timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); } diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 3648a168b..ce633d841 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -8,6 +8,7 @@ #include <type_traits> #include <utility> +#include "common/assert.h" #include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp index b244190a2..f9e3fe4b7 100644 --- a/src/core/hle/service/am_sys.cpp +++ b/src/core/hle/service/am_sys.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" + #include "core/hle/hle.h" #include "core/hle/service/am_sys.h" diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 5971f860b..09d463dd5 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -2,7 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/common_paths.h" #include "common/file_util.h" +#include "common/logging/log.h" #include "core/hle/service/service.h" #include "core/hle/service/apt/apt.h" @@ -32,23 +34,31 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; static Kernel::SharedPtr<Kernel::Mutex> lock; static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event -static Kernel::SharedPtr<Kernel::Event> pause_event = 0; ///< APT pause event +static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event + static std::vector<u8> shared_font; +static u32 cpu_percent; ///< CPU time available to the running application + void Initialize(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + u32 flags = cmd_buff[2]; + cmd_buff[2] = 0x04000000; // According to 3dbrew, this value should be 0x04000000 cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); - cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom(); - // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called. + // TODO(bunnei): Check if these events are cleared every time Initialize is called. notification_event->Clear(); - pause_event->Signal(); // Fire start event + start_event->Clear(); ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); lock->Release(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); } void GetSharedFont(Service::Interface* self) { @@ -74,7 +84,7 @@ void NotifyToWait(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 app_id = cmd_buff[1]; // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further. - pause_event->Signal(); + start_event->Signal(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); @@ -190,7 +200,38 @@ void CancelParameter(Service::Interface* self) { cmd_buff[2] = 1; // Set to Success LOG_WARNING(Service_APT, "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", - flag1, unk, flag2, app_id); + flag1, unk, flag2, app_id); +} + +void PrepareToStartApplication(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 title_info1 = cmd_buff[1]; + u32 title_info2 = cmd_buff[2]; + u32 title_info3 = cmd_buff[3]; + u32 title_info4 = cmd_buff[4]; + u32 flags = cmd_buff[5]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_APT, "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X," + "title_info4=0x%08X, flags=0x%08X", title_info1, title_info2, title_info3, title_info4, flags); +} + +void StartApplication(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 buffer1_size = cmd_buff[1]; + u32 buffer2_size = cmd_buff[2]; + u32 flag = cmd_buff[3]; + u32 size1 = cmd_buff[4]; + u32 buffer1_ptr = cmd_buff[5]; + u32 size2 = cmd_buff[6]; + u32 buffer2_ptr = cmd_buff[7]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_APT, "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X," + "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X", + buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr); } void AppletUtility(Service::Interface* self) { @@ -205,15 +246,15 @@ void AppletUtility(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " - "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, + LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " + "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr); } void SetAppCpuTimeLimit(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 value = cmd_buff[1]; - u32 percent = cmd_buff[2]; + u32 value = cmd_buff[1]; + cpu_percent = cmd_buff[2]; if (value != 1) { LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); @@ -221,27 +262,26 @@ void SetAppCpuTimeLimit(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_APT, "(STUBBED) called percent=0x%08X, value=0x%08x", percent, value); + LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value); } void GetAppCpuTimeLimit(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 value = cmd_buff[1]; + ASSERT(cpu_percent != 0); + if (value != 1) { LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); } - // TODO(purpasmart96): This is incorrect, I'm pretty sure the percentage should - // be set by the application. - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0x80; // Set to 80% + cmd_buff[2] = cpu_percent; - LOG_WARNING(Service_APT, "(STUBBED) called value=0x%08x", value); + LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); } -void APTInit() { +void Init() { AddService(new APT_A_Interface); AddService(new APT_S_Interface); AddService(new APT_U_Interface); @@ -264,21 +304,29 @@ void APTInit() { file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); // Create shared font memory object - shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem"); + using Kernel::MemoryPermission; + shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB + MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem"); } else { LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); shared_font_mem = nullptr; } lock = Kernel::Mutex::Create(false, "APT_U:Lock"); - + + cpu_percent = 0; + // TODO(bunnei): Check if these are created in Initialize or on APT process startup. notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); - pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause"); + start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); } -void APTShutdown() { - +void Shutdown() { + shared_font.clear(); + shared_font_mem = nullptr; + lock = nullptr; + notification_event = nullptr; + start_event = nullptr; } } // namespace APT diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index a39adbff9..e7fa39325 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -13,10 +13,13 @@ namespace APT { /// Signals used by APT functions enum class SignalType : u32 { - None = 0x0, - AppJustStarted = 0x1, - ReturningToApp = 0xB, - ExitingApp = 0xC, + None = 0x0, + AppJustStarted = 0x1, + LibAppJustStarted = 0x2, + LibAppFinished = 0x3, + LibAppClosed = 0xA, + ReturningToApp = 0xB, + ExitingApp = 0xC, }; /// App Id's used by APT functions @@ -179,6 +182,40 @@ void GlanceParameter(Service::Interface* self); void CancelParameter(Service::Interface* self); /** + * APT::PrepareToStartApplication service function. When the input title-info programID is zero, + * NS will load the actual program ID via AMNet:GetTitleIDList. After doing some checks with the + * programID, NS will then set a NS state flag to value 1, then set the programID for AppID + * 0x300(application) to the input program ID(or the one from GetTitleIDList). A media-type field + * in the NS state is also set to the input media-type value + * (other state fields are set at this point as well). With 8.0.0-18, NS will set an u8 NS state + * field to value 1 when input flags bit8 is set + * Inputs: + * 1-4 : 0x10-byte title-info struct + * 4 : Flags + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +void PrepareToStartApplication(Service::Interface* self); + +/** + * APT::StartApplication service function. Buf0 is copied to NS FIRMparams+0x0, then Buf1 is copied + * to the NS FIRMparams+0x480. Then the application is launched. + * Inputs: + * 1 : Buffer 0 size, max size is 0x300 + * 2 : Buffer 1 size, max size is 0x20 (this can be zero) + * 3 : u8 flag + * 4 : (Size0<<14) | 2 + * 5 : Buffer 0 pointer + * 6 : (Size1<<14) | 0x802 + * 7 : Buffer 1 pointer + * Outputs: + * 0 : Return Header + * 1 : Result of function, 0 on success, otherwise error code +*/ +void StartApplication(Service::Interface* self); + +/** * APT::AppletUtility service function * Inputs: * 1 : Unknown, but clearly used for something @@ -213,10 +250,10 @@ void SetAppCpuTimeLimit(Service::Interface* self); void GetAppCpuTimeLimit(Service::Interface* self); /// Initialize the APT service -void APTInit(); +void Init(); /// Shutdown the APT service -void APTShutdown(); +void Shutdown(); } // namespace APT } // namespace Service diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index dbe5c1d87..864934245 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -12,16 +12,16 @@ namespace APT { const Interface::FunctionInfo FunctionTable[] = { {0x00010040, GetLockHandle, "GetLockHandle?"}, {0x00020080, Initialize, "Initialize?"}, - {0x00030040, nullptr, "Enable?"}, + {0x00030040, Enable, "Enable?"}, {0x00040040, nullptr, "Finalize?"}, {0x00050040, nullptr, "GetAppletManInfo?"}, {0x00060040, nullptr, "GetAppletInfo?"}, {0x000D0080, ReceiveParameter, "ReceiveParameter?"}, {0x000E0080, GlanceParameter, "GlanceParameter?"}, {0x003B0040, nullptr, "CancelLibraryApplet?"}, - {0x00430040, nullptr, "NotifyToWait?"}, + {0x00430040, NotifyToWait, "NotifyToWait?"}, {0x00440000, GetSharedFont, "GetSharedFont?"}, - {0x004B00C2, nullptr, "AppletUtility?"}, + {0x004B00C2, AppletUtility, "AppletUtility?"}, {0x00550040, nullptr, "WriteInputToNsState?"}, }; diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index 3fd348651..396d1f04a 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -3,9 +3,6 @@ // Refer to the license.txt file included. -#include "common/common.h" -#include "common/file_util.h" - #include "core/hle/hle.h" #include "core/hle/service/apt/apt.h" #include "core/hle/service/apt/apt_s.h" diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index 5ab23801e..d006b5930 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. -#include "common/common.h" #include "common/file_util.h" #include "core/hle/service/apt/apt.h" diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 6adadb224..2d26c9330 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -4,12 +4,16 @@ #include <algorithm> -#include "core/hle/service/fs/archive.h" -#include "core/hle/service/service.h" +#include "common/logging/log.h" +#include "common/string_util.h" + +#include "core/file_sys/file_backend.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_i.h" #include "core/hle/service/cfg/cfg_s.h" #include "core/hle/service/cfg/cfg_u.h" +#include "core/hle/service/fs/archive.h" +#include "core/hle/service/service.h" namespace Service { namespace CFG { @@ -53,12 +57,12 @@ ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { }); if (itr == std::end(config->block_entries)) { - LOG_ERROR(Service_CFG, "Config block %u with flags %u was not found", block_id, flag); + LOG_ERROR(Service_CFG, "Config block 0x%X with flags %u and size %u was not found", block_id, flag, size); return ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent); } if (itr->size != size) { - LOG_ERROR(Service_CFG, "Invalid size %u for config block %u with flags %u", size, block_id, flag); + LOG_ERROR(Service_CFG, "Invalid size %u for config block 0x%X with flags %u", size, block_id, flag); return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent); } @@ -170,7 +174,7 @@ ResultCode FormatConfig() { return RESULT_SUCCESS; } -void CFGInit() { +void Init() { AddService(new CFG_I_Interface); AddService(new CFG_S_Interface); AddService(new CFG_U_Interface); @@ -207,6 +211,7 @@ void CFGInit() { // Initialize the Username block // TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals + memset(&CONSOLE_USERNAME_BLOCK, 0, sizeof(CONSOLE_USERNAME_BLOCK)); CONSOLE_USERNAME_BLOCK.ng_word = 0; CONSOLE_USERNAME_BLOCK.zero = 0; @@ -218,8 +223,7 @@ void CFGInit() { FormatConfig(); } -void CFGShutdown() { - +void Shutdown() { } } // namespace CFG diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h index e818d7bdc..3488c40d0 100644 --- a/src/core/hle/service/cfg/cfg.h +++ b/src/core/hle/service/cfg/cfg.h @@ -135,10 +135,10 @@ ResultCode UpdateConfigNANDSavegame(); ResultCode FormatConfig(); /// Initialize the config service -void CFGInit(); +void Init(); /// Shutdown the config service -void CFGShutdown(); +void Shutdown(); } // namespace CFG } // namespace Service diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp index c8c1c5b17..221de9918 100644 --- a/src/core/hle/service/cfg/cfg_u.cpp +++ b/src/core/hle/service/cfg/cfg_u.cpp @@ -3,7 +3,9 @@ // Refer to the license.txt file included. #include "common/file_util.h" +#include "common/logging/log.h" #include "common/string_util.h" + #include "core/settings.h" #include "core/file_sys/archive_systemsavedata.h" #include "core/hle/hle.h" diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 0b3603ce1..fafb43a2f 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" + #include "core/hle/hle.h" #include "core/hle/kernel/event.h" #include "core/hle/service/dsp_dsp.h" @@ -11,7 +13,7 @@ namespace DSP_DSP { -static u32 read_pipe_count = 0; +static u32 read_pipe_count; static Kernel::SharedPtr<Kernel::Event> semaphore_event; static Kernel::SharedPtr<Kernel::Event> interrupt_event; @@ -40,9 +42,9 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) { u32 addr = cmd_buff[1]; cmd_buff[1] = 0; // No error - cmd_buff[2] = (addr << 1) + (Memory::DSP_MEMORY_VADDR + 0x40000); + cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000); - LOG_WARNING(Service_DSP, "(STUBBED) called with address %u", addr); + LOG_WARNING(Service_DSP, "(STUBBED) called with address 0x%08X", addr); } /** @@ -60,12 +62,19 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) { static void LoadComponent(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 size = cmd_buff[1]; + u32 unk1 = cmd_buff[2]; + u32 unk2 = cmd_buff[3]; + u32 new_size = cmd_buff[4]; + u32 buffer = cmd_buff[5]; + cmd_buff[1] = 0; // No error cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware // TODO(bunnei): Implement real DSP firmware loading - LOG_WARNING(Service_DSP, "(STUBBED) called"); + LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, unk1=0x%08X, unk2=0x%08X, new_size=0x%X, buffer=0x%08X", + size, unk1, unk2, new_size, buffer); } /** @@ -84,6 +93,33 @@ static void GetSemaphoreEventHandle(Service::Interface* self) { } /** + * DSP_DSP::FlushDataCache service function + * + * This Function is a no-op, We aren't emulating the CPU cache any time soon. + * + * Inputs: + * 1 : Address + * 2 : Size + * 3 : Value 0, some descriptor for the KProcess Handle + * 4 : KProcess handle + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void FlushDataCache(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 address = cmd_buff[1]; + u32 size = cmd_buff[2]; + u32 process = cmd_buff[4]; + + // TODO(purpasmart96): Verify return header on HW + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X", + address, size, process); +} + +/** * DSP_DSP::RegisterInterruptEvents service function * Inputs: * 1 : Parameter 0 (purpose unknown) @@ -95,6 +131,10 @@ static void GetSemaphoreEventHandle(Service::Interface* self) { static void RegisterInterruptEvents(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 param0 = cmd_buff[1]; + u32 param1 = cmd_buff[2]; + u32 event_handle = cmd_buff[4]; + auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); if (evt != nullptr) { interrupt_event = evt; @@ -106,7 +146,7 @@ static void RegisterInterruptEvents(Service::Interface* self) { cmd_buff[1] = -1; } - LOG_WARNING(Service_DSP, "(STUBBED) called"); + LOG_WARNING(Service_DSP, "(STUBBED) called param0=%u, param1=%u, event_handle=0x%08X", param0, param1, event_handle); } /** @@ -147,7 +187,7 @@ static void WriteProcessPipe(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%08X, new_size=0x%08X, buffer=0x%08X", + LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%X, new_size=0x%X, buffer=0x%08X", number, size, new_size, buffer); } @@ -165,6 +205,8 @@ static void WriteProcessPipe(Service::Interface* self) { static void ReadPipeIfPossible(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 unk1 = cmd_buff[1]; + u32 unk2 = cmd_buff[2]; u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size VAddr addr = cmd_buff[0x41]; @@ -190,7 +232,8 @@ static void ReadPipeIfPossible(Service::Interface* self) { cmd_buff[1] = 0; // No error cmd_buff[2] = (read_pipe_count - initial_size) * sizeof(u16); - LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%08X, buffer=0x%08X", size, addr); + LOG_WARNING(Service_DSP, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", + unk1, unk2, size, addr); } /** @@ -225,7 +268,7 @@ static void GetHeadphoneStatus(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = 0; // Not using headphones? - LOG_WARNING(Service_DSP, "(STUBBED) called"); + LOG_DEBUG(Service_DSP, "(STUBBED) called"); } const Interface::FunctionInfo FunctionTable[] = { @@ -242,7 +285,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"}, {0x001100C2, LoadComponent, "LoadComponent"}, {0x00120000, nullptr, "UnloadComponent"}, - {0x00130082, nullptr, "FlushDataCache"}, + {0x00130082, FlushDataCache, "FlushDataCache"}, {0x00140082, nullptr, "InvalidateDCache"}, {0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"}, {0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"}, diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp index 58c5acd1e..e8c06c1cf 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err_f.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" + #include "core/hle/hle.h" #include "core/hle/service/err_f.h" diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index b0fd834c7..6d4a9c7c9 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -9,6 +9,7 @@ #include "common/common_types.h" #include "common/file_util.h" +#include "common/logging/log.h" #include "common/make_unique.h" #include "common/math_util.h" @@ -78,6 +79,11 @@ enum class DirectoryCommand : u32 { Close = 0x08020000, }; +File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path & path) + : path(path), priority(0), backend(std::move(backend)) {} + +File::~File() {} + ResultVal<bool> File::SyncRequest() { u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); @@ -172,6 +178,11 @@ ResultVal<bool> File::SyncRequest() { return MakeResult<bool>(false); } +Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path & path) + : path(path), backend(std::move(backend)) {} + +Directory::~Directory() {} + ResultVal<bool> Directory::SyncRequest() { u32* cmd_buff = Kernel::GetCommandBuffer(); DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index b00f0fd60..faab0cb79 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -45,31 +45,27 @@ typedef u64 ArchiveHandle; class File : public Kernel::Session { public: - File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path) - : path(path), priority(0), backend(std::move(backend)) { - } + File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); + ~File(); std::string GetName() const override { return "Path: " + path.DebugStr(); } + ResultVal<bool> SyncRequest() override; FileSys::Path path; ///< Path of the file u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface - - ResultVal<bool> SyncRequest() override; }; class Directory : public Kernel::Session { public: - Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path) - : path(path), backend(std::move(backend)) { - } + Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); + ~Directory(); std::string GetName() const override { return "Directory: " + path.DebugStr(); } + ResultVal<bool> SyncRequest() override; FileSys::Path path; ///< Path of the directory std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface - - ResultVal<bool> SyncRequest() override; }; /** diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index d8d1d5547..0d2a426b0 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -2,10 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/common.h" +#include "common/assert.h" +#include "common/common_types.h" #include "common/file_util.h" +#include "common/logging/log.h" #include "common/scope_exit.h" #include "common/string_util.h" + #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" @@ -20,6 +23,8 @@ using Kernel::Session; namespace Service { namespace FS { +static u32 priority = -1; ///< For SetPriority and GetPriority service functions + static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) { return (u64)low_word | ((u64)high_word << 32); } @@ -215,7 +220,7 @@ static void DeleteDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - + cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw; } @@ -424,7 +429,7 @@ static void IsSdmcWriteable(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // If the SD isn't enabled, it can't be writeable...else, stubbed true cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0; - + LOG_DEBUG(Service_FS, " (STUBBED)"); } @@ -511,7 +516,7 @@ static void CreateExtSaveData(Service::Interface* self) { MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF); u32 save_low = cmd_buff[2]; u32 save_high = cmd_buff[3]; - + LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low, @@ -573,7 +578,7 @@ static void DeleteSystemSaveData(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 savedata_high = cmd_buff[1]; u32 savedata_low = cmd_buff[2]; - + cmd_buff[1] = DeleteSystemSaveData(savedata_high, savedata_low).raw; } @@ -601,12 +606,72 @@ static void CreateSystemSaveData(Service::Interface* self) { LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " - "cmd_buff[9]=%08X", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5], + "cmd_buff[9]=%08X", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9]); cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw; } +/** + * FS_User::InitializeWithSdkVersion service function. + * Inputs: + * 0 : 0x08610042 + * 1 : Unknown + * 2 : Unknown + * 3 : Unknown + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void InitializeWithSdkVersion(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 unk1 = cmd_buff[1]; + u32 unk2 = cmd_buff[2]; + u32 unk3 = cmd_buff[3]; + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_FS, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, unk3=0x%08X", + unk1, unk2, unk3); +} + +/** + * FS_User::SetPriority service function. + * Inputs: + * 0 : 0x08620040 + * 1 : priority + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void SetPriority(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + priority = cmd_buff[1]; + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_DEBUG(Service_FS, "called priority=0x%08X", priority); +} + +/** + * FS_User::GetPriority service function. + * Inputs: + * 0 : 0x08630000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : priority + */ +static void GetPriority(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + ASSERT(priority != -1); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = priority; + + LOG_DEBUG(Service_FS, "called priority=0x%08X", priority); +} + const Interface::FunctionInfo FunctionTable[] = { {0x000100C6, nullptr, "Dummy1"}, {0x040100C4, nullptr, "Control"}, @@ -695,15 +760,17 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08560240, CreateSystemSaveData, "CreateSystemSaveData"}, {0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"}, {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, - {0x08610042, nullptr, "InitializeWithSdkVersion"}, - {0x08620040, nullptr, "SetPriority"}, - {0x08630000, nullptr, "GetPriority"}, + {0x08610042, InitializeWithSdkVersion, "InitializeWithSdkVersion"}, + {0x08620040, SetPriority, "SetPriority"}, + {0x08630000, GetPriority, "GetPriority"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// // Interface class Interface::Interface() { + + priority = -1; Register(FunctionTable); } diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index cff585698..c11c5faba 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -5,6 +5,7 @@ #include "common/bit_field.h" #include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/result.h" @@ -30,13 +31,12 @@ namespace GSP_GPU { Kernel::SharedPtr<Kernel::Event> g_interrupt_event; /// GSP shared memoryings Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory; -/// Thread index into interrupt relay queue, 1 is arbitrary -u32 g_thread_id = 1; +/// Thread index into interrupt relay queue +u32 g_thread_id = 0; /// Gets a pointer to a thread command buffer in GSP shared memory static inline u8* GetCommandBuffer(u32 thread_id) { - ResultVal<u8*> ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); - return ptr.ValueOr(nullptr); + return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); } static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { @@ -44,14 +44,14 @@ static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_in // For each thread there are two FrameBufferUpdate fields u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); - ResultVal<u8*> ptr = g_shared_memory->GetPointer(offset); - return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr)); + u8* ptr = g_shared_memory->GetPointer(offset); + return reinterpret_cast<FrameBufferUpdate*>(ptr); } /// Gets a pointer to the interrupt relay queue for a given thread index static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { - ResultVal<u8*> ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id); - return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); + u8* ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id); + return reinterpret_cast<InterruptRelayQueue*>(ptr); } /** @@ -204,16 +204,18 @@ static void ReadHWRegs(Service::Interface* self) { static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { u32 base_address = 0x400000; + PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); + PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); if (info.active_fb == 0) { WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, - &info.address_left); + &phys_address_left); WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, - &info.address_right); + &phys_address_right); } else { WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, - &info.address_left); + &phys_address_left); WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, - &info.address_right); + &phys_address_right); } WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, &info.stride); @@ -265,6 +267,9 @@ static void FlushDataCache(Service::Interface* self) { // TODO(purpasmart96): Verify return header on HW cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_DEBUG(Service_GSP, "(STUBBED) called address=0x%08X, size=0x%08X, process=0x%08X", + address, size, process); } /** @@ -273,7 +278,7 @@ static void FlushDataCache(Service::Interface* self) { * 1 : "Flags" field, purpose is unknown * 3 : Handle to GSP synchronization event * Outputs: - * 0 : Result of function, 0 on success, otherwise error code + * 1 : Result of function, 0x2A07 on success, otherwise error code * 2 : Thread index into GSP command buffer * 4 : Handle to GSP shared memory */ @@ -283,11 +288,12 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) { g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!"); - g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem"); Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); - cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init + // This specific code is required for a successful initialization, rather than 0 + cmd_buff[1] = ResultCode((ErrorDescription)519, ErrorModule::GX, + ErrorSummary::Success, ErrorLevel::Success).raw; cmd_buff[2] = g_thread_id++; // Thread ID cmd_buff[4] = shmem_handle; // GSP shared memory @@ -522,8 +528,12 @@ Interface::Interface() { Register(FunctionTable); g_interrupt_event = 0; - g_shared_memory = 0; - g_thread_id = 1; + + using Kernel::MemoryPermission; + g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, + MemoryPermission::ReadWrite, "GSPSharedMem"); + + g_thread_id = 0; } } // namespace diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 138603d9b..9695f7e56 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" + #include "core/hle/service/service.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid_spvr.h" @@ -20,17 +22,17 @@ namespace HID { static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position // Handle to shared memory region designated to HID_User service -static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr; +static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; // Event handles -static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr; -static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr; -static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr; -static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr; -static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr; +static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1; +static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2; +static Kernel::SharedPtr<Kernel::Event> event_accelerometer; +static Kernel::SharedPtr<Kernel::Event> event_gyroscope; +static Kernel::SharedPtr<Kernel::Event> event_debug_pad; -static u32 next_pad_index = 0; -static u32 next_touch_index = 0; +static u32 next_pad_index; +static u32 next_touch_index; // TODO(peachum): // Add a method for setting analog input from joystick device for the circle Pad. @@ -45,8 +47,8 @@ static u32 next_touch_index = 0; // * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 // * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 -void HIDUpdate() { - SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr)); +void Update() { + SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); const PadState state = VideoCore::g_emu_window->GetPadState(); if (mem == nullptr) { @@ -155,13 +157,15 @@ void GetSoundVolume(Service::Interface* self) { LOG_WARNING(Service_HID, "(STUBBED) called"); } -void HIDInit() { +void Init() { using namespace Kernel; AddService(new HID_U_Interface); AddService(new HID_SPVR_Interface); - shared_mem = SharedMemory::Create("HID:SharedMem"); + using Kernel::MemoryPermission; + shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, + MemoryPermission::Read, "HID:SharedMem"); next_pad_index = 0; next_touch_index = 0; @@ -174,7 +178,13 @@ void HIDInit() { event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad"); } -void HIDShutdown() { +void Shutdown() { + shared_mem = nullptr; + event_pad_or_touch_1 = nullptr; + event_pad_or_touch_2 = nullptr; + event_accelerometer = nullptr; + event_gyroscope = nullptr; + event_debug_pad = nullptr; } } // namespace HID diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 97462c7f8..897bd6764 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -200,13 +200,13 @@ void EnableGyroscopeLow(Interface* self); void GetSoundVolume(Interface* self); /// Checks for user input updates -void HIDUpdate(); +void Update(); /// Initialize HID service -void HIDInit(); +void Init(); /// Shutdown HID service -void HIDShutdown(); +void Shutdown(); } } diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp new file mode 100644 index 000000000..adfbb258d --- /dev/null +++ b/src/core/hle/service/ir/ir.cpp @@ -0,0 +1,52 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/service.h" +#include "core/hle/service/ir/ir.h" +#include "core/hle/service/ir/ir_rst.h" +#include "core/hle/service/ir/ir_u.h" +#include "core/hle/service/ir/ir_user.h" + +#include "core/hle/hle.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" + +namespace Service { +namespace IR { + +static Kernel::SharedPtr<Kernel::Event> handle_event; +static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; + +void GetHandles(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0x4000000; + cmd_buff[3] = Kernel::g_handle_table.Create(Service::IR::shared_memory).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(Service::IR::handle_event).MoveFrom(); +} + +void Init() { + using namespace Kernel; + + AddService(new IR_RST_Interface); + AddService(new IR_U_Interface); + AddService(new IR_User_Interface); + + using Kernel::MemoryPermission; + shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite, + Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory"); + + // Create event handle(s) + handle_event = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent"); +} + +void Shutdown() { + shared_memory = nullptr; + handle_event = nullptr; +} + +} // namespace IR + +} // namespace Service diff --git a/src/core/hle/service/ir/ir.h b/src/core/hle/service/ir/ir.h new file mode 100644 index 000000000..c16d963e7 --- /dev/null +++ b/src/core/hle/service/ir/ir.h @@ -0,0 +1,30 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace IR { + +/** + * IR::GetHandles service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Translate header, used by the ARM11-kernel + * 3 : Shared memory handle + * 4 : Event handle + */ +void GetHandles(Interface* self); + +/// Initialize IR service +void Init(); + +/// Shutdown IR service +void Shutdown(); + +} // namespace IR +} // namespace Service diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp new file mode 100644 index 000000000..96ae63420 --- /dev/null +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -0,0 +1,24 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/ir/ir.h" +#include "core/hle/service/ir/ir_rst.h" + +namespace Service { +namespace IR { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, GetHandles, "GetHandles"}, + {0x00020080, nullptr, "Initialize"}, + {0x00030000, nullptr, "Shutdown"}, + {0x00090000, nullptr, "WriteToTwoFields"}, +}; + +IR_RST_Interface::IR_RST_Interface() { + Register(FunctionTable); +} + +} // namespace IR +} // namespace Service diff --git a/src/core/hle/service/ir_rst.h b/src/core/hle/service/ir/ir_rst.h index deef701c5..a492e15c9 100644 --- a/src/core/hle/service/ir_rst.h +++ b/src/core/hle/service/ir/ir_rst.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace IR_RST +namespace Service { +namespace IR { -namespace IR_RST { - -class Interface : public Service::Interface { +class IR_RST_Interface : public Service::Interface { public: - Interface(); + IR_RST_Interface(); std::string GetPortName() const override { return "ir:rst"; } }; -} // namespace +} // namespace IR +} // namespace Service diff --git a/src/core/hle/service/ir_u.cpp b/src/core/hle/service/ir/ir_u.cpp index 608ed3c06..1b1e3078b 100644 --- a/src/core/hle/service/ir_u.cpp +++ b/src/core/hle/service/ir/ir_u.cpp @@ -3,12 +3,11 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/ir_u.h" +#include "core/hle/service/ir/ir.h" +#include "core/hle/service/ir/ir_u.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace IR_U - -namespace IR_U { +namespace Service { +namespace IR { const Interface::FunctionInfo FunctionTable[] = { {0x00010000, nullptr, "Initialize"}, @@ -31,11 +30,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00120040, nullptr, "SetSleepModeState"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +IR_U_Interface::IR_U_Interface() { Register(FunctionTable); } -} // namespace +} // namespace IR +} // namespace Service diff --git a/src/core/hle/service/ir/ir_u.h b/src/core/hle/service/ir/ir_u.h new file mode 100644 index 000000000..056d2ce1a --- /dev/null +++ b/src/core/hle/service/ir/ir_u.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace IR { + +class IR_U_Interface : public Service::Interface { +public: + IR_U_Interface(); + + std::string GetPortName() const override { + return "ir:u"; + } +}; + +} // namespace IR +} // namespace Service diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp new file mode 100644 index 000000000..8e3ff140f --- /dev/null +++ b/src/core/hle/service/ir/ir_user.cpp @@ -0,0 +1,34 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/ir/ir.h" +#include "core/hle/service/ir/ir_user.h" + +namespace Service { +namespace IR { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010182, nullptr, "InitializeIrNop"}, + {0x00020000, nullptr, "FinalizeIrNop"}, + {0x00030000, nullptr, "ClearReceiveBuffer"}, + {0x00040000, nullptr, "ClearSendBuffer"}, + {0x00060040, nullptr, "RequireConnection"}, + {0x00090000, nullptr, "Disconnect"}, + {0x000A0000, nullptr, "GetReceiveEvent"}, + {0x000B0000, nullptr, "GetSendEvent"}, + {0x000C0000, nullptr, "GetConnectionStatusEvent"}, + {0x000D0042, nullptr, "SendIrNop"}, + {0x000E0042, nullptr, "SendIrNopLarge"}, + {0x00180182, nullptr, "InitializeIrNopShared"}, + {0x00190040, nullptr, "ReleaseReceivedData"}, + {0x001A0040, nullptr, "SetOwnMachineId"}, +}; + +IR_User_Interface::IR_User_Interface() { + Register(FunctionTable); +} + +} // namespace IR +} // namespace Service diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h new file mode 100644 index 000000000..71c932ffa --- /dev/null +++ b/src/core/hle/service/ir/ir_user.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace IR { + +class IR_User_Interface : public Service::Interface { +public: + IR_User_Interface(); + + std::string GetPortName() const override { + return "ir:USER"; + } +}; + +} // namespace IR +} // namespace Service diff --git a/src/core/hle/service/ir_rst.cpp b/src/core/hle/service/ir_rst.cpp deleted file mode 100644 index 4c26c2f03..000000000 --- a/src/core/hle/service/ir_rst.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/ir_rst.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace IR_RST - -namespace IR_RST { - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010000, nullptr, "GetHandles"}, - {0x00020080, nullptr, "Initialize"}, - {0x00030000, nullptr, "Shutdown"}, - {0x00090000, nullptr, "WriteToTwoFields"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp index c0c4a2344..155b97f69 100644 --- a/src/core/hle/service/ldr_ro.cpp +++ b/src/core/hle/service/ldr_ro.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" + #include "core/hle/hle.h" #include "core/hle/service/ldr_ro.h" diff --git a/src/core/hle/service/nim_u.cpp b/src/core/hle/service/nim_u.cpp new file mode 100644 index 000000000..5f13bd98e --- /dev/null +++ b/src/core/hle/service/nim_u.cpp @@ -0,0 +1,48 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/hle.h" +#include "core/hle/service/nim_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace NIM_U + +namespace NIM_U { + +/** + * NIM_U::CheckSysUpdateAvailable service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : flag, 0 = no system update available, 1 = system update available. + */ +static void CheckSysUpdateAvailable(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; // No update available + + LOG_WARNING(Service_NWM, "(STUBBED) called"); +} + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "StartSysUpdate"}, + {0x00020000, nullptr, "GetUpdateDownloadProgress"}, + {0x00040000, nullptr, "FinishTitlesInstall"}, + {0x00050000, nullptr, "CheckForSysUpdateEvent"}, + {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"}, + {0x000A0000, nullptr, "GetState"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable); +} + +} // namespace diff --git a/src/core/hle/service/ir_u.h b/src/core/hle/service/nim_u.h index ec47a1524..57a1f6acf 100644 --- a/src/core/hle/service/ir_u.h +++ b/src/core/hle/service/nim_u.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2015 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -7,16 +7,16 @@ #include "core/hle/service/service.h" //////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace IR_U +// Namespace NIM_U -namespace IR_U { +namespace NIM_U { class Interface : public Service::Interface { public: Interface(); std::string GetPortName() const override { - return "ir:u"; + return "nim:u"; } }; diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp index 5cf3e2039..6b3ef6ece 100644 --- a/src/core/hle/service/ns_s.cpp +++ b/src/core/hle/service/ns_s.cpp @@ -3,8 +3,6 @@ // Refer to the license.txt file included. -#include "common/common.h" - #include "core/hle/hle.h" #include "core/hle/service/ns_s.h" diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp index 88be6c8d9..25b01860e 100644 --- a/src/core/hle/service/nwm_uds.cpp +++ b/src/core/hle/service/nwm_uds.cpp @@ -2,7 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" + #include "core/hle/hle.h" +#include "core/hle/kernel/event.h" #include "core/hle/service/nwm_uds.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -10,21 +13,115 @@ namespace NWM_UDS { +static Kernel::SharedPtr<Kernel::Event> handle_event; + +/** + * NWM_UDS::Shutdown service function + * Inputs: + * 1 : None + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void Shutdown(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(purpasmart): Verify return header on HW + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_NWM, "(STUBBED) called"); +} + +/** + * NWM_UDS::RecvBeaconBroadcastData service function + * Inputs: + * 1 : Output buffer max size + * 2 : Unknown + * 3 : Unknown + * 4 : MAC address? + * 6-14 : Unknown, usually zero / uninitialized? + * 15 : WLan Comm ID + * 16 : This is the ID also located at offset 0xE in the CTR-generation structure. + * 17 : Value 0 + * 18 : Input handle + * 19 : (Size<<4) | 12 + * 20 : Output buffer ptr + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void RecvBeaconBroadcastData(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 out_buffer_size = cmd_buff[1]; + u32 unk1 = cmd_buff[2]; + u32 unk2 = cmd_buff[3]; + u32 mac_address = cmd_buff[4]; + + u32 unk3 = cmd_buff[6]; + + u32 wlan_comm_id = cmd_buff[15]; + u32 ctr_gen_id = cmd_buff[16]; + u32 value = cmd_buff[17]; + u32 input_handle = cmd_buff[18]; + u32 new_buffer_size = cmd_buff[19]; + u32 out_buffer_ptr = cmd_buff[20]; + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_NWM, "(STUBBED) called out_buffer_size=0x%08X, unk1=0x%08X, unk2=0x%08X," + "mac_address=0x%08X, unk3=0x%08X, wlan_comm_id=0x%08X, ctr_gen_id=0x%08X," + "value=%u, input_handle=0x%08X, new_buffer_size=0x%08X, out_buffer_ptr=0x%08X", + out_buffer_size, unk1, unk2, mac_address, unk3, wlan_comm_id, ctr_gen_id, value, + input_handle, new_buffer_size, out_buffer_ptr); +} + +/** + * NWM_UDS::Initialize service function + * Inputs: + * 1 : Unknown + * 2-11 : Input Structure + * 12 : Unknown u16 + * 13 : Value 0 + * 14 : Handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Value 0 + * 3 : Output handle + */ +static void Initialize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 unk1 = cmd_buff[1]; + u32 unk2 = cmd_buff[12]; + u32 value = cmd_buff[13]; + u32 handle = cmd_buff[14]; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + cmd_buff[3] = Kernel::g_handle_table.Create(handle_event).MoveFrom(); //TODO(purpasmart): Verify if this is a event handle + + LOG_WARNING(Service_NWM, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, value=%u, handle=0x%08X", + unk1, unk2, value, handle); +} + const Interface::FunctionInfo FunctionTable[] = { - {0x00030000, nullptr, "Shutdown"}, - {0x000F0404, nullptr, "RecvBeaconBroadcastData"}, - {0x00100042, nullptr, "SetBeaconAdditionalData"}, - {0x001400C0, nullptr, "RecvBroadcastDataFrame"}, - {0x001B0302, nullptr, "Initialize"}, - {0x001D0044, nullptr, "BeginHostingNetwork"}, - {0x001E0084, nullptr, "ConnectToNetwork"}, - {0x001F0006, nullptr, "DecryptBeaconData"}, + {0x00030000, Shutdown, "Shutdown"}, + {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"}, + {0x00100042, nullptr, "SetBeaconAdditionalData"}, + {0x001400C0, nullptr, "RecvBroadcastDataFrame"}, + {0x001B0302, Initialize, "Initialize"}, + {0x001D0044, nullptr, "BeginHostingNetwork"}, + {0x001E0084, nullptr, "ConnectToNetwork"}, + {0x001F0006, nullptr, "DecryptBeaconData"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// // Interface class Interface::Interface() { + handle_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "NWM_UDS::handle_event"); + Register(FunctionTable); } diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h index 9043f5aa7..82abdff28 100644 --- a/src/core/hle/service/nwm_uds.h +++ b/src/core/hle/service/nwm_uds.h @@ -18,7 +18,7 @@ public: Interface(); std::string GetPortName() const override { - return "nwm:UDS"; + return "nwm::UDS"; } }; diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 56c918d4f..2c7d49c9f 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp @@ -2,12 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/service/service.h" +#include "common/logging/log.h" + +#include "core/file_sys/file_backend.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/ptm/ptm.h" #include "core/hle/service/ptm/ptm_play.h" #include "core/hle/service/ptm/ptm_sysm.h" #include "core/hle/service/ptm/ptm_u.h" +#include "core/hle/service/service.h" namespace Service { namespace PTM { @@ -18,31 +21,70 @@ static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; /// Id of the SharedExtData archive used by the PTM process static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; -static bool shell_open = true; +static bool shell_open; -static bool battery_is_charging = true; +static bool battery_is_charging; + +void GetAdapterState(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); -u32 GetAdapterState() { // TODO(purpasmart96): This function is only a stub, // it returns a valid result without implementing full functionality. - return battery_is_charging ? 1 : 0; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = battery_is_charging ? 1 : 0; + + LOG_WARNING(Service_PTM, "(STUBBED) called"); } -u32 GetShellState() { - return shell_open ? 1 : 0; +void GetShellState(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = shell_open ? 1 : 0; +} + +void GetBatteryLevel(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(purpasmart96): This function is only a stub, + // it returns a valid result without implementing full functionality. + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = static_cast<u32>(ChargeLevels::CompletelyFull); // Set to a completely full battery + + LOG_WARNING(Service_PTM, "(STUBBED) called"); } -ChargeLevels GetBatteryLevel() { +void GetBatteryChargeState(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + // TODO(purpasmart96): This function is only a stub, // it returns a valid result without implementing full functionality. - return ChargeLevels::CompletelyFull; // Set to a completely full battery + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = battery_is_charging ? 1 : 0; + + LOG_WARNING(Service_PTM, "(STUBBED) called"); } -void PTMInit() { +void IsLegacyPowerOff(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + + LOG_WARNING(Service_PTM, "(STUBBED) called"); +} + +void Init() { AddService(new PTM_Play_Interface); AddService(new PTM_Sysm_Interface); AddService(new PTM_U_Interface); + shell_open = true; + battery_is_charging = true; + // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't exist FileSys::Path archive_path(ptm_shared_extdata_id); auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); @@ -68,7 +110,7 @@ void PTMInit() { } } -void PTMShutdown() { +void Shutdown() { } diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h index f697aae4d..493e6a11f 100644 --- a/src/core/hle/service/ptm/ptm.h +++ b/src/core/hle/service/ptm/ptm.h @@ -5,6 +5,7 @@ #pragma once #include <array> +#include "core/hle/service/service.h" #include "core/hle/result.h" namespace Service { @@ -35,31 +36,54 @@ struct GameCoin { }; /** - * Returns whether the battery is charging or not. * It is unknown if GetAdapterState is the same as GetBatteryChargeState, * it is likely to just be a duplicate function of GetBatteryChargeState * that controls another part of the HW. - * @returns 1 if the battery is charging, and 0 otherwise. + * PTM::GetAdapterState service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Output of function, 0 = not charging, 1 = charging. */ -u32 GetAdapterState(); +void GetAdapterState(Interface* self); /** - * Returns whether the 3DS's physical shell casing is open or closed - * @returns 1 if the shell is open, and 0 if otherwise + * PTM::GetShellState service function. + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0) */ -u32 GetShellState(); +void GetShellState(Interface* self); /** - * Get the current battery's charge level. - * @returns The battery's charge level. + * PTM::GetBatteryLevel service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery, + * 3 = half full battery, 2 = low battery, 1 = critical battery. */ -ChargeLevels GetBatteryLevel(); +void GetBatteryLevel(Interface* self); + +/** + * PTM::GetBatteryChargeState service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Output of function, 0 = not charging, 1 = charging. + */ +void GetBatteryChargeState(Interface* self); + +/** + * PTM::IsLegacyPowerOff service function + * Outputs: + * 1: Result code, 0 on success, otherwise error code + * 2: Whether the system is going through a power off + */ +void IsLegacyPowerOff(Interface* self); /// Initialize the PTM service -void PTMInit(); +void Init(); /// Shutdown the PTM service -void PTMShutdown(); +void Shutdown(); } // namespace PTM } // namespace Service diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp index 8e8ae8558..48e68a3d8 100644 --- a/src/core/hle/service/ptm/ptm_play.cpp +++ b/src/core/hle/service/ptm/ptm_play.cpp @@ -9,10 +9,10 @@ namespace Service { namespace PTM { const Interface::FunctionInfo FunctionTable[] = { - { 0x08070082, nullptr, "GetPlayHistory" }, - { 0x08080000, nullptr, "GetPlayHistoryStart" }, - { 0x08090000, nullptr, "GetPlayHistoryLength" }, - { 0x080B0080, nullptr, "CalcPlayHistoryStart" }, + {0x08070082, nullptr, "GetPlayHistory"}, + {0x08080000, nullptr, "GetPlayHistoryStart"}, + {0x08090000, nullptr, "GetPlayHistoryLength"}, + {0x080B0080, nullptr, "CalcPlayHistoryStart"}, }; PTM_Play_Interface::PTM_Play_Interface() { diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp index 2d841f69c..655658f3b 100644 --- a/src/core/hle/service/ptm/ptm_sysm.cpp +++ b/src/core/hle/service/ptm/ptm_sysm.cpp @@ -2,57 +2,44 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/make_unique.h" -#include "core/file_sys/archive_extsavedata.h" #include "core/hle/hle.h" +#include "core/hle/service/ptm/ptm.h" #include "core/hle/service/ptm/ptm_sysm.h" namespace Service { namespace PTM { -/** - * Returns whether the system is powering off (?) - * Outputs: - * 1: Result code, 0 on success, otherwise error code - * 2: Whether the system is going through a power off - */ -void IsLegacyPowerOff(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0; -} - const Interface::FunctionInfo FunctionTable[] = { - {0x040100C0, nullptr, "SetRtcAlarmEx"}, - {0x04020042, nullptr, "ReplySleepQuery"}, - {0x04030042, nullptr, "NotifySleepPreparationComplete"}, - {0x04040102, nullptr, "SetWakeupTrigger"}, - {0x04050000, nullptr, "GetAwakeReason"}, - {0x04060000, nullptr, "RequestSleep"}, - {0x040700C0, nullptr, "ShutdownAsync"}, - {0x04080000, nullptr, "Awake"}, - {0x04090080, nullptr, "RebootAsync"}, - {0x040A0000, nullptr, "CheckNew3DS"}, - {0x08010640, nullptr, "SetInfoLEDPattern"}, - {0x08020040, nullptr, "SetInfoLEDPatternHeader"}, - {0x08030000, nullptr, "GetInfoLEDStatus"}, - {0x08040040, nullptr, "SetBatteryEmptyLEDPattern"}, - {0x08050000, nullptr, "ClearStepHistory"}, - {0x080600C2, nullptr, "SetStepHistory"}, - {0x08070082, nullptr, "GetPlayHistory"}, - {0x08080000, nullptr, "GetPlayHistoryStart"}, - {0x08090000, nullptr, "GetPlayHistoryLength"}, - {0x080A0000, nullptr, "ClearPlayHistory"}, - {0x080B0080, nullptr, "CalcPlayHistoryStart"}, - {0x080C0080, nullptr, "SetUserTime"}, - {0x080D0000, nullptr, "InvalidateSystemTime"}, - {0x080E0140, nullptr, "NotifyPlayEvent"}, - {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"}, - {0x08100000, nullptr, "ClearLegacyPowerOff"}, - {0x08110000, nullptr, "GetShellStatus"}, - {0x08120000, nullptr, "IsShutdownByBatteryEmpty"}, - {0x08130000, nullptr, "FormatSavedata"}, - {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"} + {0x040100C0, nullptr, "SetRtcAlarmEx"}, + {0x04020042, nullptr, "ReplySleepQuery"}, + {0x04030042, nullptr, "NotifySleepPreparationComplete"}, + {0x04040102, nullptr, "SetWakeupTrigger"}, + {0x04050000, nullptr, "GetAwakeReason"}, + {0x04060000, nullptr, "RequestSleep"}, + {0x040700C0, nullptr, "ShutdownAsync"}, + {0x04080000, nullptr, "Awake"}, + {0x04090080, nullptr, "RebootAsync"}, + {0x040A0000, nullptr, "CheckNew3DS"}, + {0x08010640, nullptr, "SetInfoLEDPattern"}, + {0x08020040, nullptr, "SetInfoLEDPatternHeader"}, + {0x08030000, nullptr, "GetInfoLEDStatus"}, + {0x08040040, nullptr, "SetBatteryEmptyLEDPattern"}, + {0x08050000, nullptr, "ClearStepHistory"}, + {0x080600C2, nullptr, "SetStepHistory"}, + {0x08070082, nullptr, "GetPlayHistory"}, + {0x08080000, nullptr, "GetPlayHistoryStart"}, + {0x08090000, nullptr, "GetPlayHistoryLength"}, + {0x080A0000, nullptr, "ClearPlayHistory"}, + {0x080B0080, nullptr, "CalcPlayHistoryStart"}, + {0x080C0080, nullptr, "SetUserTime"}, + {0x080D0000, nullptr, "InvalidateSystemTime"}, + {0x080E0140, nullptr, "NotifyPlayEvent"}, + {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"}, + {0x08100000, nullptr, "ClearLegacyPowerOff"}, + {0x08110000, nullptr, "GetShellStatus"}, + {0x08120000, nullptr, "IsShutdownByBatteryEmpty"}, + {0x08130000, nullptr, "FormatSavedata"}, + {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"} }; PTM_Sysm_Interface::PTM_Sysm_Interface() { diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp index 0af7c8bf6..3f5e9c7c1 100644 --- a/src/core/hle/service/ptm/ptm_u.cpp +++ b/src/core/hle/service/ptm/ptm_u.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/make_unique.h" +#include "common/logging/log.h" #include "core/hle/hle.h" #include "core/hle/service/ptm/ptm.h" @@ -11,68 +11,6 @@ namespace Service { namespace PTM { -/** - * PTM_U::GetAdapterState service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Output of function, 0 = not charging, 1 = charging. - */ -static void GetAdapterState(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = GetAdapterState(); - - LOG_WARNING(Service_PTM, "(STUBBED) called"); -} - -/* - * PTM_User::GetShellState service function. - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0) - */ -static void GetShellState(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = GetShellState(); -} - -/** - * PTM_U::GetBatteryLevel service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery, - * 3 = half full battery, 2 = low battery, 1 = critical battery. - */ -static void GetBatteryLevel(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = static_cast<u32>(GetBatteryLevel()); - - LOG_WARNING(Service_PTM, "(STUBBED) called"); -} - -/** - * PTM_U::GetBatteryChargeState service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Output of function, 0 = not charging, 1 = charging. - */ -static void GetBatteryChargeState(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(purpasmart96): This function is only a stub, - // it returns a valid result without implementing full functionality. - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = GetAdapterState(); - - LOG_WARNING(Service_PTM, "(STUBBED) called"); -} - const Interface::FunctionInfo FunctionTable[] = { {0x00010002, nullptr, "RegisterAlarmClient"}, {0x00020080, nullptr, "SetRtcAlarm"}, diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 91f13cd7e..64185c62e 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/common.h" +#include "common/logging/log.h" #include "common/string_util.h" #include "core/hle/service/service.h" @@ -24,14 +24,13 @@ #include "core/hle/service/gsp_gpu.h" #include "core/hle/service/gsp_lcd.h" #include "core/hle/service/http_c.h" -#include "core/hle/service/ir_rst.h" -#include "core/hle/service/ir_u.h" #include "core/hle/service/ldr_ro.h" #include "core/hle/service/mic_u.h" #include "core/hle/service/ndm_u.h" #include "core/hle/service/news_s.h" #include "core/hle/service/news_u.h" #include "core/hle/service/nim_aoc.h" +#include "core/hle/service/nim_u.h" #include "core/hle/service/ns_s.h" #include "core/hle/service/nwm_uds.h" #include "core/hle/service/pm_app.h" @@ -44,6 +43,7 @@ #include "core/hle/service/fs/archive.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/hid/hid.h" +#include "core/hle/service/ir/ir.h" #include "core/hle/service/ptm/ptm.h" namespace Service { @@ -51,6 +51,49 @@ namespace Service { std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; +/** + * Creates a function string for logging, complete with the name (or header code, depending + * on what's passed in) the port name, and all the cmd_buff arguments. + */ +static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { + // Number of params == bits 0-5 + bits 6-11 + int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); + + std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name); + for (int i = 1; i <= num_params; ++i) { + function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]); + } + return function_string; +} + +ResultVal<bool> Interface::SyncRequest() { + u32* cmd_buff = Kernel::GetCommandBuffer(); + auto itr = m_functions.find(cmd_buff[0]); + + if (itr == m_functions.end() || itr->second.func == nullptr) { + std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name; + LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str()); + + // TODO(bunnei): Hack - ignore error + cmd_buff[1] = 0; + return MakeResult<bool>(false); + } else { + LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); + } + + itr->second.func(this); + + return MakeResult<bool>(false); // TODO: Implement return from actual function +} + +void Interface::Register(const FunctionInfo* functions, size_t n) { + m_functions.reserve(n); + for (size_t i = 0; i < n; ++i) { + // Usually this array is sorted by id already, so hint to instead at the end + m_functions.emplace_hint(m_functions.cend(), functions[i].id, functions[i]); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Module interface @@ -68,10 +111,11 @@ void Init() { AddNamedPort(new ERR_F::Interface); Service::FS::ArchiveInit(); - Service::CFG::CFGInit(); - Service::APT::APTInit(); - Service::PTM::PTMInit(); - Service::HID::HIDInit(); + Service::CFG::Init(); + Service::APT::Init(); + Service::PTM::Init(); + Service::HID::Init(); + Service::IR::Init(); AddService(new AC_U::Interface); AddService(new ACT_U::Interface); @@ -90,14 +134,13 @@ void Init() { AddService(new GSP_GPU::Interface); AddService(new GSP_LCD::Interface); AddService(new HTTP_C::Interface); - AddService(new IR_RST::Interface); - AddService(new IR_U::Interface); AddService(new LDR_RO::Interface); AddService(new MIC_U::Interface); AddService(new NDM_U::Interface); AddService(new NEWS_S::Interface); AddService(new NEWS_U::Interface); AddService(new NIM_AOC::Interface); + AddService(new NIM_U::Interface); AddService(new NS_S::Interface); AddService(new NWM_UDS::Interface); AddService(new PM_APP::Interface); @@ -110,10 +153,11 @@ void Init() { /// Shutdown ServiceManager void Shutdown() { - Service::HID::HIDShutdown(); - Service::PTM::PTMShutdown(); - Service::APT::APTShutdown(); - Service::CFG::CFGShutdown(); + Service::IR::Shutdown(); + Service::HID::Shutdown(); + Service::PTM::Shutdown(); + Service::APT::Shutdown(); + Service::CFG::Shutdown(); Service::FS::ArchiveShutdown(); g_srv_services.clear(); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index bfe16ebad..77bfb9ff1 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -4,20 +4,15 @@ #pragma once -#include <algorithm> #include <string> #include <unordered_map> -#include <vector> #include <boost/container/flat_map.hpp> -#include "common/common.h" -#include "common/string_util.h" -#include "core/mem_map.h" +#include "common/common_types.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/session.h" -#include "core/hle/svc.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Service @@ -26,31 +21,11 @@ namespace Service { static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) -class Manager; - /// Interface to a CTROS service class Interface : public Kernel::Session { // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be // just something that encapsulates a session and acts as a helper to implement service // processes. - - friend class Manager; - - /** - * Creates a function string for logging, complete with the name (or header code, depending - * on what's passed in) the port name, and all the cmd_buff arguments. - */ - std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { - // Number of params == bits 0-5 + bits 6-11 - int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); - - std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name); - for (int i = 1; i <= num_params; ++i) { - function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]); - } - return function_string; - } - public: std::string GetName() const override { return GetPortName(); } @@ -70,25 +45,7 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultVal<bool> SyncRequest() override { - u32* cmd_buff = Kernel::GetCommandBuffer(); - auto itr = m_functions.find(cmd_buff[0]); - - if (itr == m_functions.end() || itr->second.func == nullptr) { - std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name; - LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str()); - - // TODO(bunnei): Hack - ignore error - cmd_buff[1] = 0; - return MakeResult<bool>(false); - } else { - LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); - } - - itr->second.func(this); - - return MakeResult<bool>(false); // TODO: Implement return from actual function - } + ResultVal<bool> SyncRequest() override; protected: @@ -96,14 +53,12 @@ protected: * Registers the functions in the service */ template <size_t N> - void Register(const FunctionInfo (&functions)[N]) { - m_functions.reserve(N); - for (auto& fn : functions) { - // Usually this array is sorted by id already, so hint to instead at the end - m_functions.emplace_hint(m_functions.cend(), fn.id, fn); - } + inline void Register(const FunctionInfo (&functions)[N]) { + Register(functions, N); } + void Register(const FunctionInfo* functions, size_t n); + private: boost::container::flat_map<u32, FunctionInfo> m_functions; diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 231ead185..39b8d65fd 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" #include "common/platform.h" #if EMU_PLATFORM == PLATFORM_WINDOWS diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index cc59a03ce..6c49fa6cf 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" + #include "core/hle/hle.h" #include "core/hle/service/srv.h" #include "core/hle/kernel/event.h" diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index 6607965e1..085192a07 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/logging/log.h" + #include "core/hle/hle.h" #include "core/hle/kernel/event.h" #include "core/hle/service/y2r_u.h" @@ -11,7 +13,7 @@ namespace Y2R_U { -static Kernel::SharedPtr<Kernel::Event> completion_event = 0; +static Kernel::SharedPtr<Kernel::Event> completion_event; /** * Y2R_U::IsBusyConversion service function diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index 568dad684..4014eee98 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp @@ -2,11 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> + #include "common/common_types.h" #include "common/common_funcs.h" #include "core/core.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/config_mem.h" #include "core/hle/shared_page.h" @@ -14,61 +16,15 @@ namespace SharedPage { -// see http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes - -#pragma pack(1) -struct DateTime { - u64 date_time; // 0x0 - u64 update_tick; // 0x8 - INSERT_PADDING_BYTES(0x20 - 0x10); // 0x10 -}; - -struct SharedPageDef { - // most of these names are taken from the 3dbrew page linked above. - u32 date_time_selector; // 0x0 - u8 running_hw; // 0x4 - u8 mcu_hw_info; // 0x5: don't know what the acronyms mean - INSERT_PADDING_BYTES(0x20 - 0x6); // 0x6 - DateTime date_time_0; // 0x20 - DateTime date_time_1; // 0x40 - u8 wifi_macaddr[6]; // 0x60 - u8 wifi_unknown1; // 0x66: 3dbrew says these are "Likely wifi hardware related" - u8 wifi_unknown2; // 0x67 - INSERT_PADDING_BYTES(0x80 - 0x68); // 0x68 - float sliderstate_3d; // 0x80 - u8 ledstate_3d; // 0x84 - INSERT_PADDING_BYTES(0xA0 - 0x85); // 0x85 - u64 menu_title_id; // 0xA0 - u64 active_menu_title_id; // 0xA8 - INSERT_PADDING_BYTES(0x1000 - 0xB0); // 0xB0 -}; -#pragma pack() +SharedPageDef shared_page; -static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); -static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page structure size is wrong"); - -static SharedPageDef shared_page; - -template <typename T> -inline void Read(T &var, const u32 addr) { - u32 offset = addr - Memory::SHARED_PAGE_VADDR; - var = *(reinterpret_cast<T*>(((uintptr_t)&shared_page) + offset)); -} - -// Explicitly instantiate template functions because we aren't defining this in the header: -template void Read<u64>(u64 &var, const u32 addr); -template void Read<u32>(u32 &var, const u32 addr); -template void Read<u16>(u16 &var, const u32 addr); -template void Read<u8>(u8 &var, const u32 addr); +void Init() { + std::memset(&shared_page, 0, sizeof(shared_page)); -void Set3DSlider(float amount) { - shared_page.sliderstate_3d = amount; - shared_page.ledstate_3d = (amount == 0.0f); // off when non-zero + shared_page.running_hw = 0x1; // product } -void Init() { - shared_page.running_hw = 0x1; // product - Set3DSlider(0.0f); +void Shutdown() { } } // namespace diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h index 8f93545ec..fd2ab66a2 100644 --- a/src/core/hle/shared_page.h +++ b/src/core/hle/shared_page.h @@ -11,16 +11,46 @@ */ #include "common/common_types.h" +#include "common/swap.h" //////////////////////////////////////////////////////////////////////////////////////////////////// namespace SharedPage { -template <typename T> -void Read(T &var, const u32 addr); - -void Set3DSlider(float amount); +// See http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes + +struct DateTime { + u64_le date_time; // 0 + u64_le update_tick; // 8 + INSERT_PADDING_BYTES(0x20 - 0x10); // 10 +}; +static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); + +struct SharedPageDef { + // Most of these names are taken from the 3dbrew page linked above. + u32_le date_time_selector; // 0 + u8 running_hw; // 4 + /// "Microcontroller hardware info" + u8 mcu_hw_info; // 5 + INSERT_PADDING_BYTES(0x20 - 0x6); // 6 + DateTime date_time_0; // 20 + DateTime date_time_1; // 40 + u8 wifi_macaddr[6]; // 60 + u8 wifi_unknown1; // 66 + u8 wifi_unknown2; // 67 + INSERT_PADDING_BYTES(0x80 - 0x68); // 68 + float_le sliderstate_3d; // 80 + u8 ledstate_3d; // 84 + INSERT_PADDING_BYTES(0xA0 - 0x85); // 85 + u64_le menu_title_id; // A0 + u64_le active_menu_title_id; // A8 + INSERT_PADDING_BYTES(0x1000 - 0xB0); // B0 +}; +static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page structure size is wrong"); + +extern SharedPageDef shared_page; void Init(); +void Shutdown(); } // namespace diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index bbb4eb9cd..9bf886256 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -4,6 +4,8 @@ #include <map> +#include "common/logging/log.h" +#include "common/profiler.h" #include "common/string_util.h" #include "common/symbols.h" @@ -14,6 +16,7 @@ #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/process.h" #include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" @@ -283,8 +286,13 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val if (arbiter == nullptr) return ERR_INVALID_HANDLE; - return arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), - address, value, nanoseconds); + auto res = arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), + address, value, nanoseconds); + + if (res == RESULT_SUCCESS) + HLE::Reschedule(__func__); + + return res; } /// Used to output a message on a debug hardware unit - does nothing on a retail unit @@ -305,14 +313,14 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) { /// Get resource limit current values static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, s32 name_count) { - LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", + LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%p, name_count=%d", resource_limit, names, name_count); - Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now + values[0] = 0; // Normmatt: Set used memory to 0 for now return RESULT_SUCCESS; } /// Creates a new thread -static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { +static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { using Kernel::Thread; std::string name; @@ -323,6 +331,27 @@ static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u name = Common::StringFromFormat("unknown-%08x", entry_point); } + // TODO(bunnei): Implement resource limits to return an error code instead of the below assert. + // The error code should be: Description::NotAuthorized, Module::OS, Summary::WrongArgument, + // Level::Permanent + ASSERT_MSG(priority >= THREADPRIO_USERLAND_MAX, "Unexpected thread priority!"); + + if (priority > THREADPRIO_LOWEST) { + return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); + } + + switch (processor_id) { + case THREADPROCESSORID_DEFAULT: + case THREADPROCESSORID_0: + case THREADPROCESSORID_1: + break; + default: + // TODO(bunnei): Implement support for other processor IDs + ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id); + break; + } + CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create( name, entry_point, priority, arg, processor_id, stack_top)); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); @@ -331,10 +360,7 @@ static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, name.c_str(), arg, stack_top, priority, processor_id, *out_handle); - if (THREADPROCESSORID_1 == processor_id) { - LOG_WARNING(Kernel_SVC, - "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling"); - } + HLE::Reschedule(__func__); return RESULT_SUCCESS; } @@ -374,8 +400,11 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); + HLE::Reschedule(__func__); + LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", initial_locked ? "true" : "false", *out_handle); + return RESULT_SUCCESS; } @@ -390,6 +419,37 @@ static ResultCode ReleaseMutex(Handle handle) { return ERR_INVALID_HANDLE; mutex->Release(); + + HLE::Reschedule(__func__); + + return RESULT_SUCCESS; +} + +/// Get the ID of the specified process +static ResultCode GetProcessId(u32* process_id, Handle process_handle) { + LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); + + const SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle); + if (process == nullptr) + return ERR_INVALID_HANDLE; + + *process_id = process->process_id; + return RESULT_SUCCESS; +} + +/// Get the ID of the process that owns the specified thread +static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { + LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); + + const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle); + if (thread == nullptr) + return ERR_INVALID_HANDLE; + + const SharedPtr<Kernel::Process> process = thread->owner_process; + + ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle); + + *process_id = process->process_id; return RESULT_SUCCESS; } @@ -428,6 +488,9 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) return ERR_INVALID_HANDLE; CASCADE_RESULT(*count, semaphore->Release(release_count)); + + HLE::Reschedule(__func__); + return RESULT_SUCCESS; } @@ -520,6 +583,9 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { return ERR_INVALID_HANDLE; timer->Set(initial, interval); + + HLE::Reschedule(__func__); + return RESULT_SUCCESS; } @@ -534,6 +600,9 @@ static ResultCode CancelTimer(Handle handle) { return ERR_INVALID_HANDLE; timer->Cancel(); + + HLE::Reschedule(__func__); + return RESULT_SUCCESS; } @@ -561,14 +630,26 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 using Kernel::SharedMemory; // TODO(Subv): Implement this function - SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(); + using Kernel::MemoryPermission; + SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size, + (MemoryPermission)my_permission, (MemoryPermission)other_permission); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); return RESULT_SUCCESS; } -const HLE::FunctionDef SVC_Table[] = { +namespace { + struct FunctionDef { + using Func = void(); + + u32 id; + Func* func; + const char* name; + }; +} + +static const FunctionDef SVC_Table[] = { {0x00, nullptr, "Unknown"}, {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"}, {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"}, @@ -622,8 +703,8 @@ const HLE::FunctionDef SVC_Table[] = { {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"}, {0x33, nullptr, "OpenProcess"}, {0x34, nullptr, "OpenThread"}, - {0x35, nullptr, "GetProcessId"}, - {0x36, nullptr, "GetProcessIdOfThread"}, + {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"}, + {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"}, {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"}, {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"}, {0x39, nullptr, "GetResourceLimitLimitValues"}, @@ -697,8 +778,28 @@ const HLE::FunctionDef SVC_Table[] = { {0x7D, nullptr, "QueryProcessMemory"}, }; -void Register() { - HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table); +Common::Profiling::TimingCategory profiler_svc("SVC Calls"); + +static const FunctionDef* GetSVCInfo(u32 opcode) { + u32 func_num = opcode & 0xFFFFFF; // 8 bits + if (func_num >= ARRAY_SIZE(SVC_Table)) { + LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num); + return nullptr; + } + return &SVC_Table[func_num]; +} + +void CallSVC(u32 opcode) { + Common::Profiling::ScopeTimer timer_svc(profiler_svc); + + const FunctionDef *info = GetSVCInfo(opcode); + if (info) { + if (info->func) { + info->func(); + } else { + LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name); + } + } } } // namespace diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h index 5d020a5ba..4389aa73d 100644 --- a/src/core/hle/svc.h +++ b/src/core/hle/svc.h @@ -41,6 +41,6 @@ enum ArbitrationType { namespace SVC { -void Register(); +void CallSVC(u32 opcode); } // namespace |
