diff options
Diffstat (limited to 'src/core/hle')
49 files changed, 1604 insertions, 1211 deletions
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp index 68d3071f5..b10c19d1d 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp @@ -3,60 +3,54 @@ // Refer to the license.txt file included. #include "common/common_types.h" -#include "common/logging/log.h" +#include "common/common_funcs.h" +#include "core/core.h" +#include "core/mem_map.h" #include "core/hle/config_mem.h" //////////////////////////////////////////////////////////////////////////////////////////////////// namespace ConfigMem { -enum { - KERNEL_VERSIONREVISION = 0x1FF80001, - KERNEL_VERSIONMINOR = 0x1FF80002, - KERNEL_VERSIONMAJOR = 0x1FF80003, - UPDATEFLAG = 0x1FF80004, - NSTID = 0x1FF80008, - SYSCOREVER = 0x1FF80010, - UNITINFO = 0x1FF80014, - KERNEL_CTRSDKVERSION = 0x1FF80018, - APPMEMTYPE = 0x1FF80030, - APPMEMALLOC = 0x1FF80040, - FIRM_VERSIONREVISION = 0x1FF80061, - FIRM_VERSIONMINOR = 0x1FF80062, - FIRM_VERSIONMAJOR = 0x1FF80063, - FIRM_SYSCOREVER = 0x1FF80064, - FIRM_CTRSDKVERSION = 0x1FF80068, +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 }; -template <typename T> -inline void Read(T &var, const u32 addr) { - switch (addr) { - - // Bit 0 set for Retail - case UNITINFO: - var = 0x00000001; - break; - - // Set app memory size to 64MB? - case APPMEMALLOC: - var = 0x04000000; - break; +static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong"); - // Unknown - normally set to: 0x08000000 - (APPMEMALLOC + *0x1FF80048) - // (Total FCRAM size - APPMEMALLOC - *0x1FF80048) - case 0x1FF80044: - var = 0x08000000 - (0x04000000 + 0x1400000); - break; +static ConfigMemDef config_mem; - // Unknown - normally set to: 0x1400000 (20MB) - case 0x1FF80048: - var = 0x1400000; - break; - - default: - LOG_ERROR(Kernel, "unknown addr=0x%08X", addr); - } +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: @@ -66,5 +60,21 @@ 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() { + 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 = 0; // Defualt app mem type + config_mem.unit_info = 0x1; // Bit 0 set for Retail + config_mem.app_mem_alloc = 0x04000000; // Default app memory size is 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); + config_mem.firm_unk = 0; + config_mem.firm_version_rev = 0; + config_mem.firm_version_min = 0x40; + config_mem.firm_version_maj = 0x2; + config_mem.firm_sys_core_ver = 0x2; +} } // namespace diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h index 3975af18f..94853901a 100644 --- a/src/core/hle/config_mem.h +++ b/src/core/hle/config_mem.h @@ -18,4 +18,6 @@ namespace ConfigMem { template <typename T> void Read(T &var, const u32 addr); +void Init(); + } // namespace diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 529133ca7..1aaeaa9c9 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -4,20 +4,22 @@ #include <vector> +#include "common/profiler.h" + #include "core/arm/arm_interface.h" #include "core/mem_map.h" #include "core/hle/hle.h" +#include "core/hle/config_mem.h" #include "core/hle/shared_page.h" #include "core/hle/kernel/thread.h" #include "core/hle/service/service.h" -#include "core/hle/service/fs/archive.h" -#include "core/hle/service/cfg/cfg.h" -#include "core/hle/service/hid/hid.h" //////////////////////////////////////////////////////////////////////////////////////////////////// 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 @@ -32,6 +34,8 @@ static const FunctionDef* GetSVCInfo(u32 opcode) { } void CallSVC(u32 opcode) { + Common::Profiling::ScopeTimer timer_svc(profiler_svc); + const FunctionDef *info = GetSVCInfo(opcode); if (!info) { @@ -69,21 +73,16 @@ static void RegisterAllModules() { void Init() { Service::Init(); - Service::FS::ArchiveInit(); - Service::CFG::CFGInit(); - Service::HID::HIDInit(); RegisterAllModules(); + ConfigMem::Init(); SharedPage::Init(); LOG_DEBUG(Kernel, "initialized OK"); } void Shutdown() { - Service::HID::HIDShutdown(); - Service::CFG::CFGShutdown(); - Service::FS::ArchiveShutdown(); Service::Shutdown(); g_module_db.clear(); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index f8c834a8d..be1aed615 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -7,6 +7,7 @@ #include <vector> #include "common/common.h" +#include "common/math_util.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" @@ -339,7 +340,7 @@ static void DebugThreadQueue() { ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, u32 arg, s32 processor_id, VAddr stack_top) { if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { - s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); + s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", name.c_str(), priority, new_priority); // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm @@ -387,7 +388,7 @@ static void ClampPriority(const Thread* thread, s32* priority) { if (*priority < THREADPRIO_HIGHEST || *priority > THREADPRIO_LOWEST) { DEBUG_ASSERT_MSG(false, "Application passed an out of range priority. An error should be returned."); - s32 new_priority = CLAMP(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); + s32 new_priority = MathUtil::Clamp<s32>(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", thread->name.c_str(), *priority, new_priority); // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 9dbd5a914..3648a168b 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -4,7 +4,6 @@ #pragma once -#include <cassert> #include <cstddef> #include <type_traits> #include <utility> @@ -209,11 +208,11 @@ union ResultCode { } }; -inline bool operator==(const ResultCode a, const ResultCode b) { +inline bool operator==(const ResultCode& a, const ResultCode& b) { return a.raw == b.raw; } -inline bool operator!=(const ResultCode a, const ResultCode b) { +inline bool operator!=(const ResultCode& a, const ResultCode& b) { return a.raw != b.raw; } @@ -267,7 +266,7 @@ public: ResultVal(ResultCode error_code = ResultCode(-1)) : result_code(error_code) { - assert(error_code.IsError()); + ASSERT(error_code.IsError()); UpdateDebugPtr(); } @@ -330,7 +329,7 @@ public: */ template <typename... Args> void emplace(ResultCode success_code, Args&&... args) { - assert(success_code.IsSuccess()); + ASSERT(success_code.IsSuccess()); if (!empty()) { GetPointer()->~T(); } @@ -362,7 +361,6 @@ public: /// Asserts that the result succeeded and returns a reference to it. T& Unwrap() { - // TODO(yuriks): Should be a release assert ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); return **this; } @@ -389,12 +387,12 @@ private: } const T* GetPointer() const { - assert(!empty()); + ASSERT(!empty()); return static_cast<const T*>(static_cast<const void*>(&storage)); } T* GetPointer() { - assert(!empty()); + ASSERT(!empty()); return static_cast<T*>(static_cast<void*>(&storage)); } }; diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp index 7ab89569f..b244190a2 100644 --- a/src/core/hle/service/am_sys.cpp +++ b/src/core/hle/service/am_sys.cpp @@ -5,19 +5,56 @@ #include "core/hle/hle.h" #include "core/hle/service/am_sys.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_SYS - namespace AM_SYS { -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; +/** + * Gets the number of installed titles in the requested media type + * Inputs: + * 0: Command header (0x00010040) + * 1: Media type to load the titles from + * Outputs: + * 1: Result, 0 on success, otherwise error code + * 2: The number of titles in the requested media type + */ +static void TitleIDListGetTotal(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 media_type = cmd_buff[1] & 0xFF; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + LOG_WARNING(Service_CFG, "(STUBBED) media_type %u", media_type); +} + +/** + * Loads information about the desired number of titles from the desired media type into an array + * Inputs: + * 0: Command header (0x00020082) + * 1: The maximum number of titles to load + * 2: Media type to load the titles from + * 3: Descriptor of the output buffer pointer + * 4: Address of the output buffer + * Outputs: + * 1: Result, 0 on success, otherwise error code + * 2: The number of titles loaded from the requested media type + */ +static void GetTitleIDList(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 num_titles = cmd_buff[1]; + u32 media_type = cmd_buff[2] & 0xFF; + u32 addr = cmd_buff[4]; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + LOG_WARNING(Service_CFG, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); +} -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, + {0x00020082, GetTitleIDList, "GetTitleIDList"}, +}; Interface::Interface() { - //Register(FunctionTable); + Register(FunctionTable); } } // namespace diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp new file mode 100644 index 000000000..5971f860b --- /dev/null +++ b/src/core/hle/service/apt/apt.cpp @@ -0,0 +1,285 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/file_util.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/apt/apt.h" +#include "core/hle/service/apt/apt_a.h" +#include "core/hle/service/apt/apt_s.h" +#include "core/hle/service/apt/apt_u.h" + +#include "core/hle/hle.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/thread.h" + +namespace Service { +namespace APT { + +// Address used for shared font (as observed on HW) +// TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via +// https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any +// address other than 0x18000000 due to internal pointers in the shared font dump that would need to +// be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then +// correctly mapping it in Citra, however we still do not understand how the mapping is determined. +static const VAddr SHARED_FONT_VADDR = 0x18000000; + +/// Handle to shared memory region designated to for shared system font +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 std::vector<u8> shared_font; + +void Initialize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); + + // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called. + notification_event->Clear(); + pause_event->Signal(); // Fire start event + + ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); + lock->Release(); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error +} + +void GetSharedFont(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + if (!shared_font.empty()) { + // TODO(bunnei): This function shouldn't copy the shared font every time it's called. + // Instead, it should probably map the shared font as RO memory. We don't currently have + // an easy way to do this, but the copy should be sufficient for now. + memcpy(Memory::GetPointer(SHARED_FONT_VADDR), shared_font.data(), shared_font.size()); + + cmd_buff[0] = 0x00440082; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = SHARED_FONT_VADDR; + cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); + } else { + cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware) + LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT); + } +} + +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(); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); +} + +void GetLockHandle(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + // Not sure what these parameters are used for, but retail apps check that they are 0 after + // GetLockHandle has been called. + cmd_buff[2] = 0; + cmd_buff[3] = 0; + cmd_buff[4] = 0; + + cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); + LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); +} + +void Enable(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); +} + +void GetAppletManInfo(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 unk = cmd_buff[1]; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 0; + cmd_buff[3] = 0; + cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID + cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly + + LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); +} + +void IsRegistered(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 1; // Set to registered + LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); +} + +void InquireNotification(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type + LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); +} + +void SendParameter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 src_app_id = cmd_buff[1]; + u32 dst_app_id = cmd_buff[2]; + u32 signal_type = cmd_buff[3]; + u32 buffer_size = cmd_buff[4]; + u32 value = cmd_buff[5]; + u32 handle = cmd_buff[6]; + u32 size = cmd_buff[7]; + u32 in_param_buffer_ptr = cmd_buff[8]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," + "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", + src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); +} + +void ReceiveParameter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + u32 buffer_size = cmd_buff[2]; + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 0; + cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type + cmd_buff[4] = 0x10; // Parameter buffer size (16) + cmd_buff[5] = 0; + cmd_buff[6] = 0; + cmd_buff[7] = 0; + LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); +} + +void GlanceParameter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + u32 buffer_size = cmd_buff[2]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = 0; + cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type + cmd_buff[4] = 0x10; // Parameter buffer size (16) + cmd_buff[5] = 0; + cmd_buff[6] = 0; + cmd_buff[7] = 0; + + LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); +} + +void CancelParameter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 flag1 = cmd_buff[1]; + u32 unk = cmd_buff[2]; + u32 flag2 = cmd_buff[3]; + u32 app_id = cmd_buff[4]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + 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); +} + +void AppletUtility(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // These are from 3dbrew - I'm not really sure what they're used for. + u32 unk = cmd_buff[1]; + u32 buffer1_size = cmd_buff[2]; + u32 buffer2_size = cmd_buff[3]; + u32 buffer1_addr = cmd_buff[5]; + u32 buffer2_addr = cmd_buff[65]; + + 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, + buffer1_addr, buffer2_addr); +} + +void SetAppCpuTimeLimit(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 value = cmd_buff[1]; + u32 percent = cmd_buff[2]; + + if (value != 1) { + LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); + } + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + + LOG_WARNING(Service_APT, "(STUBBED) called percent=0x%08X, value=0x%08x", percent, value); +} + +void GetAppCpuTimeLimit(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 value = cmd_buff[1]; + + 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% + + LOG_WARNING(Service_APT, "(STUBBED) called value=0x%08x", value); +} + +void APTInit() { + AddService(new APT_A_Interface); + AddService(new APT_S_Interface); + AddService(new APT_U_Interface); + + // Load the shared system font (if available). + // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header + // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided + // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file + // "shared_font.bin" in the Citra "sysdata" directory. + + shared_font.clear(); + std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; + + FileUtil::CreateFullPath(filepath); // Create path if not already created + FileUtil::IOFile file(filepath, "rb"); + + if (file.IsOpen()) { + // Read shared font data + shared_font.resize((size_t)file.GetSize()); + 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"); + } 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"); + + // 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"); +} + +void APTShutdown() { + +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h new file mode 100644 index 000000000..a39adbff9 --- /dev/null +++ b/src/core/hle/service/apt/apt.h @@ -0,0 +1,222 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include "core/hle/result.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace APT { + +/// Signals used by APT functions +enum class SignalType : u32 { + None = 0x0, + AppJustStarted = 0x1, + ReturningToApp = 0xB, + ExitingApp = 0xC, +}; + +/// App Id's used by APT functions +enum class AppID : u32 { + HomeMenu = 0x101, + AlternateMenu = 0x103, + Camera = 0x110, + FriendsList = 0x112, + GameNotes = 0x113, + InternetBrowser = 0x114, + InstructionManual = 0x115, + Notifications = 0x116, + Miiverse = 0x117, + SoftwareKeyboard1 = 0x201, + Ed = 0x202, + PnoteApp = 0x204, + SnoteApp = 0x205, + Error = 0x206, + Mint = 0x207, + Extrapad = 0x208, + Memolib = 0x209, + Application = 0x300, + SoftwareKeyboard2 = 0x401, +}; + +/** + * APT::Initialize service function + * Service function that initializes the APT process for the running application + * Outputs: + * 1 : Result of the function, 0 on success, otherwise error code + * 3 : Handle to the notification event + * 4 : Handle to the pause event + */ +void Initialize(Service::Interface* self); + +/** + * APT::GetSharedFont service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Virtual address of where shared font will be loaded in memory + * 4 : Handle to shared font memory + */ +void GetSharedFont(Service::Interface* self); + +/** + * APT::NotifyToWait service function + * Inputs: + * 1 : AppID + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void NotifyToWait(Service::Interface* self); + +void GetLockHandle(Service::Interface* self); + +void Enable(Service::Interface* self); + +/** + * APT::GetAppletManInfo service function. + * Inputs: + * 1 : Unknown + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unknown u32 value + * 3 : Unknown u8 value + * 4 : Home Menu AppId + * 5 : AppID of currently active app + */ +void GetAppletManInfo(Service::Interface* self); + +/** + * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. + * An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu uses this + * command to determine when the launched process is running and to determine when to stop using GSP etc, + * while displaying the "Nintendo 3DS" loading screen. + * Inputs: + * 1 : AppID + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Output, 0 = not registered, 1 = registered. + */ +void IsRegistered(Service::Interface* self); + +void InquireNotification(Service::Interface* self); + +/** + * APT::SendParameter service function. This sets the parameter data state. + * Inputs: + * 1 : Source AppID + * 2 : Destination AppID + * 3 : Signal type + * 4 : Parameter buffer size, max size is 0x1000 (this can be zero) + * 5 : Value + * 6 : Handle to the destination process, likely used for shared memory (this can be zero) + * 7 : (Size<<14) | 2 + * 8 : Input parameter buffer ptr + * Outputs: + * 0 : Return Header + * 1 : Result of function, 0 on success, otherwise error code +*/ +void SendParameter(Service::Interface* self); + +/** + * APT::ReceiveParameter service function. This returns the current parameter data from NS state, + * from the source process which set the parameters. Once finished, NS will clear a flag in the NS + * state so that this command will return an error if this command is used again if parameters were + * not set again. This is called when the second Initialize event is triggered. It returns a signal + * type indicating why it was triggered. + * Inputs: + * 1 : AppID + * 2 : Parameter buffer size, max size is 0x1000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : AppID of the process which sent these parameters + * 3 : Signal type + * 4 : Actual parameter buffer size, this is <= to the the input size + * 5 : Value + * 6 : Handle from the source process which set the parameters, likely used for shared memory + * 7 : Size + * 8 : Output parameter buffer ptr + */ +void ReceiveParameter(Service::Interface* self); + +/** + * APT::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter + * (except for the word value prior to the output handle), except this will not clear the flag + * (except when responseword[3]==8 || responseword[3]==9) in NS state. + * Inputs: + * 1 : AppID + * 2 : Parameter buffer size, max size is 0x1000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unknown, for now assume AppID of the process which sent these parameters + * 3 : Unknown, for now assume Signal type + * 4 : Actual parameter buffer size, this is <= to the the input size + * 5 : Value + * 6 : Handle from the source process which set the parameters, likely used for shared memory + * 7 : Size + * 8 : Output parameter buffer ptr + */ +void GlanceParameter(Service::Interface* self); + +/** + * APT::CancelParameter service function. When the parameter data is available, and when the above + * specified fields match the ones in NS state(for the ones where the checks are enabled), this + * clears the flag which indicates that parameter data is available + * (same flag cleared by APT:ReceiveParameter). + * Inputs: + * 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS state. + * 2 : Unknown, this is the same as the first unknown field returned by APT:ReceiveParameter. + * 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS state. + * 4 : AppID + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Status flag, 0 = failure due to no parameter data being available, or the above enabled + * fields don't match the fields in NS state. 1 = success. + */ +void CancelParameter(Service::Interface* self); + +/** + * APT::AppletUtility service function + * Inputs: + * 1 : Unknown, but clearly used for something + * 2 : Buffer 1 size (purpose is unknown) + * 3 : Buffer 2 size (purpose is unknown) + * 5 : Buffer 1 address (purpose is unknown) + * 65 : Buffer 2 address (purpose is unknown) + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void AppletUtility(Service::Interface* self); + +/** + * APT::SetAppCpuTimeLimit service function + * Inputs: + * 1 : Value, must be one + * 2 : Percentage of CPU time from 5 to 80 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void SetAppCpuTimeLimit(Service::Interface* self); + +/** + * APT::GetAppCpuTimeLimit service function + * Inputs: + * 1 : Value, must be one + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : System core CPU time percentage + */ +void GetAppCpuTimeLimit(Service::Interface* self); + +/// Initialize the APT service +void APTInit(); + +/// Shutdown the APT service +void APTShutdown(); + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp new file mode 100644 index 000000000..dbe5c1d87 --- /dev/null +++ b/src/core/hle/service/apt/apt_a.cpp @@ -0,0 +1,33 @@ +// 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/apt/apt.h" +#include "core/hle/service/apt/apt_a.h" + +namespace Service { +namespace APT { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, GetLockHandle, "GetLockHandle?"}, + {0x00020080, Initialize, "Initialize?"}, + {0x00030040, nullptr, "Enable?"}, + {0x00040040, nullptr, "Finalize?"}, + {0x00050040, nullptr, "GetAppletManInfo?"}, + {0x00060040, nullptr, "GetAppletInfo?"}, + {0x000D0080, ReceiveParameter, "ReceiveParameter?"}, + {0x000E0080, GlanceParameter, "GlanceParameter?"}, + {0x003B0040, nullptr, "CancelLibraryApplet?"}, + {0x00430040, nullptr, "NotifyToWait?"}, + {0x00440000, GetSharedFont, "GetSharedFont?"}, + {0x004B00C2, nullptr, "AppletUtility?"}, + {0x00550040, nullptr, "WriteInputToNsState?"}, +}; + +APT_A_Interface::APT_A_Interface() { + Register(FunctionTable); +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt_a.h b/src/core/hle/service/apt/apt_a.h index 6cbf1288f..331fb5586 100644 --- a/src/core/hle/service/apt_a.h +++ b/src/core/hle/service/apt/apt_a.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_A +namespace Service { +namespace APT { -namespace APT_A { - -class Interface : public Service::Interface { +class APT_A_Interface : public Service::Interface { public: - Interface(); + APT_A_Interface(); std::string GetPortName() const override { return "APT:A"; } }; -} // namespace +} // namespace APT +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp new file mode 100644 index 000000000..3fd348651 --- /dev/null +++ b/src/core/hle/service/apt/apt_s.cpp @@ -0,0 +1,104 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// 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" + +namespace Service { +namespace APT { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, GetLockHandle, "GetLockHandle"}, + {0x00020080, Initialize, "Initialize"}, + {0x00030040, Enable, "Enable"}, + {0x00040040, nullptr, "Finalize"}, + {0x00050040, nullptr, "GetAppletManInfo"}, + {0x00060040, nullptr, "GetAppletInfo"}, + {0x00070000, nullptr, "GetLastSignaledAppletId"}, + {0x00080000, nullptr, "CountRegisteredApplet"}, + {0x00090040, nullptr, "IsRegistered"}, + {0x000A0040, nullptr, "GetAttribute"}, + {0x000B0040, InquireNotification, "InquireNotification"}, + {0x000C0104, nullptr, "SendParameter"}, + {0x000D0080, ReceiveParameter, "ReceiveParameter"}, + {0x000E0080, GlanceParameter, "GlanceParameter"}, + {0x000F0100, nullptr, "CancelParameter"}, + {0x001000C2, nullptr, "DebugFunc"}, + {0x001100C0, nullptr, "MapProgramIdForDebug"}, + {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, + {0x00130000, nullptr, "GetPreparationState"}, + {0x00140040, nullptr, "SetPreparationState"}, + {0x00150140, nullptr, "PrepareToStartApplication"}, + {0x00160040, nullptr, "PreloadLibraryApplet"}, + {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, + {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, + {0x00190040, nullptr, "PrepareToStartSystemApplet"}, + {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, + {0x001B00C4, nullptr, "StartApplication"}, + {0x001C0000, nullptr, "WakeupApplication"}, + {0x001D0000, nullptr, "CancelApplication"}, + {0x001E0084, nullptr, "StartLibraryApplet"}, + {0x001F0084, nullptr, "StartSystemApplet"}, + {0x00200044, nullptr, "StartNewestHomeMenu"}, + {0x00210000, nullptr, "OrderToCloseApplication"}, + {0x00220040, nullptr, "PrepareToCloseApplication"}, + {0x00230040, nullptr, "PrepareToJumpToApplication"}, + {0x00240044, nullptr, "JumpToApplication"}, + {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, + {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, + {0x00270044, nullptr, "CloseApplication"}, + {0x00280044, nullptr, "CloseLibraryApplet"}, + {0x00290044, nullptr, "CloseSystemApplet"}, + {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, + {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, + {0x002C0044, nullptr, "JumpToHomeMenu"}, + {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, + {0x002E0044, nullptr, "LeaveHomeMenu"}, + {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, + {0x00300044, nullptr, "LeaveResidentApplet"}, + {0x00310100, nullptr, "PrepareToDoApplicationJump"}, + {0x00320084, nullptr, "DoApplicationJump"}, + {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, + {0x00340084, nullptr, "SendDeliverArg"}, + {0x00350080, nullptr, "ReceiveDeliverArg"}, + {0x00360040, nullptr, "LoadSysMenuArg"}, + {0x00370042, nullptr, "StoreSysMenuArg"}, + {0x00380040, nullptr, "PreloadResidentApplet"}, + {0x00390040, nullptr, "PrepareToStartResidentApplet"}, + {0x003A0044, nullptr, "StartResidentApplet"}, + {0x003B0040, nullptr, "CancelLibraryApplet"}, + {0x003C0042, nullptr, "SendDspSleep"}, + {0x003D0042, nullptr, "SendDspWakeUp"}, + {0x003E0080, nullptr, "ReplySleepQuery"}, + {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, + {0x00400042, nullptr, "SendCaptureBufferInfo"}, + {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, + {0x00420080, nullptr, "SleepSystem"}, + {0x00430040, NotifyToWait, "NotifyToWait"}, + {0x00440000, GetSharedFont, "GetSharedFont"}, + {0x00450040, nullptr, "GetWirelessRebootInfo"}, + {0x00460104, nullptr, "Wrap"}, + {0x00470104, nullptr, "Unwrap"}, + {0x00480100, nullptr, "GetProgramInfo"}, + {0x00490180, nullptr, "Reboot"}, + {0x004A0040, nullptr, "GetCaptureInfo"}, + {0x004B00C2, AppletUtility, "AppletUtility"}, + {0x004C0000, nullptr, "SetFatalErrDispMode"}, + {0x004D0080, nullptr, "GetAppletProgramInfo"}, + {0x004E0000, nullptr, "HardwareResetAsync"}, + {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"}, + {0x00500040, nullptr, "GetApplicationCpuTimeLimit"}, +}; + +APT_S_Interface::APT_S_Interface() { + Register(FunctionTable); +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt_s.h b/src/core/hle/service/apt/apt_s.h index f097c9747..8e87b69af 100644 --- a/src/core/hle/service/apt_s.h +++ b/src/core/hle/service/apt/apt_s.h @@ -6,10 +6,8 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_S - -namespace APT_S { +namespace Service { +namespace APT { // Application and title launching service. These services handle signaling for home/power button as // well. Only one session for either APT service can be open at a time, normally processes close the @@ -18,13 +16,14 @@ namespace APT_S { // svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services. /// Interface to "APT:S" service -class Interface : public Service::Interface { +class APT_S_Interface : public Service::Interface { public: - Interface(); + APT_S_Interface(); std::string GetPortName() const override { return "APT:S"; } }; -} // namespace +} // namespace APT +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp new file mode 100644 index 000000000..5ab23801e --- /dev/null +++ b/src/core/hle/service/apt/apt_u.cpp @@ -0,0 +1,103 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + + +#include "common/common.h" +#include "common/file_util.h" + +#include "core/hle/service/apt/apt.h" +#include "core/hle/service/apt/apt_u.h" + +namespace Service { +namespace APT { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, GetLockHandle, "GetLockHandle"}, + {0x00020080, Initialize, "Initialize"}, + {0x00030040, Enable, "Enable"}, + {0x00040040, nullptr, "Finalize"}, + {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, + {0x00060040, nullptr, "GetAppletInfo"}, + {0x00070000, nullptr, "GetLastSignaledAppletId"}, + {0x00080000, nullptr, "CountRegisteredApplet"}, + {0x00090040, IsRegistered, "IsRegistered"}, + {0x000A0040, nullptr, "GetAttribute"}, + {0x000B0040, InquireNotification, "InquireNotification"}, + {0x000C0104, SendParameter, "SendParameter"}, + {0x000D0080, ReceiveParameter, "ReceiveParameter"}, + {0x000E0080, GlanceParameter, "GlanceParameter"}, + {0x000F0100, CancelParameter, "CancelParameter"}, + {0x001000C2, nullptr, "DebugFunc"}, + {0x001100C0, nullptr, "MapProgramIdForDebug"}, + {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, + {0x00130000, nullptr, "GetPreparationState"}, + {0x00140040, nullptr, "SetPreparationState"}, + {0x00150140, nullptr, "PrepareToStartApplication"}, + {0x00160040, nullptr, "PreloadLibraryApplet"}, + {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, + {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, + {0x00190040, nullptr, "PrepareToStartSystemApplet"}, + {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, + {0x001B00C4, nullptr, "StartApplication"}, + {0x001C0000, nullptr, "WakeupApplication"}, + {0x001D0000, nullptr, "CancelApplication"}, + {0x001E0084, nullptr, "StartLibraryApplet"}, + {0x001F0084, nullptr, "StartSystemApplet"}, + {0x00200044, nullptr, "StartNewestHomeMenu"}, + {0x00210000, nullptr, "OrderToCloseApplication"}, + {0x00220040, nullptr, "PrepareToCloseApplication"}, + {0x00230040, nullptr, "PrepareToJumpToApplication"}, + {0x00240044, nullptr, "JumpToApplication"}, + {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, + {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, + {0x00270044, nullptr, "CloseApplication"}, + {0x00280044, nullptr, "CloseLibraryApplet"}, + {0x00290044, nullptr, "CloseSystemApplet"}, + {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, + {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, + {0x002C0044, nullptr, "JumpToHomeMenu"}, + {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, + {0x002E0044, nullptr, "LeaveHomeMenu"}, + {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, + {0x00300044, nullptr, "LeaveResidentApplet"}, + {0x00310100, nullptr, "PrepareToDoApplicationJump"}, + {0x00320084, nullptr, "DoApplicationJump"}, + {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, + {0x00340084, nullptr, "SendDeliverArg"}, + {0x00350080, nullptr, "ReceiveDeliverArg"}, + {0x00360040, nullptr, "LoadSysMenuArg"}, + {0x00370042, nullptr, "StoreSysMenuArg"}, + {0x00380040, nullptr, "PreloadResidentApplet"}, + {0x00390040, nullptr, "PrepareToStartResidentApplet"}, + {0x003A0044, nullptr, "StartResidentApplet"}, + {0x003B0040, nullptr, "CancelLibraryApplet"}, + {0x003C0042, nullptr, "SendDspSleep"}, + {0x003D0042, nullptr, "SendDspWakeUp"}, + {0x003E0080, nullptr, "ReplySleepQuery"}, + {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, + {0x00400042, nullptr, "SendCaptureBufferInfo"}, + {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, + {0x00420080, nullptr, "SleepSystem"}, + {0x00430040, NotifyToWait, "NotifyToWait"}, + {0x00440000, GetSharedFont, "GetSharedFont"}, + {0x00450040, nullptr, "GetWirelessRebootInfo"}, + {0x00460104, nullptr, "Wrap"}, + {0x00470104, nullptr, "Unwrap"}, + {0x00480100, nullptr, "GetProgramInfo"}, + {0x00490180, nullptr, "Reboot"}, + {0x004A0040, nullptr, "GetCaptureInfo"}, + {0x004B00C2, AppletUtility, "AppletUtility"}, + {0x004C0000, nullptr, "SetFatalErrDispMode"}, + {0x004D0080, nullptr, "GetAppletProgramInfo"}, + {0x004E0000, nullptr, "HardwareResetAsync"}, + {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, + {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, +}; + +APT_U_Interface::APT_U_Interface() { + Register(FunctionTable); +} + +} // namespace APT +} // namespace Service diff --git a/src/core/hle/service/apt_u.h b/src/core/hle/service/apt/apt_u.h index aad918cfc..8c7fe0ccb 100644 --- a/src/core/hle/service/apt_u.h +++ b/src/core/hle/service/apt/apt_u.h @@ -6,10 +6,8 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_U - -namespace APT_U { +namespace Service { +namespace APT { // Application and title launching service. These services handle signaling for home/power button as // well. Only one session for either APT service can be open at a time, normally processes close the @@ -18,13 +16,14 @@ namespace APT_U { // svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services. /// Interface to "APT:U" service -class Interface : public Service::Interface { +class APT_U_Interface : public Service::Interface { public: - Interface(); + APT_U_Interface(); std::string GetPortName() const override { return "APT:U"; } }; -} // namespace +} // namespace APT +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/apt_a.cpp b/src/core/hle/service/apt_a.cpp deleted file mode 100644 index 1c1d92572..000000000 --- a/src/core/hle/service/apt_a.cpp +++ /dev/null @@ -1,44 +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/apt_a.h" - -namespace APT_U { - extern void Initialize(Service::Interface* self); - extern void GetLockHandle(Service::Interface* self); - extern void ReceiveParameter(Service::Interface* self); - extern void GlanceParameter(Service::Interface* self); - extern void GetSharedFont(Service::Interface* self); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_A - -namespace APT_A { - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, APT_U::GetLockHandle, "GetLockHandle?"}, - {0x00020080, APT_U::Initialize, "Initialize?"}, - {0x00030040, nullptr, "Enable?"}, - {0x00040040, nullptr, "Finalize?"}, - {0x00050040, nullptr, "GetAppletManInfo?"}, - {0x00060040, nullptr, "GetAppletInfo?"}, - {0x000D0080, APT_U::ReceiveParameter, "ReceiveParameter?"}, - {0x000E0080, APT_U::GlanceParameter, "GlanceParameter?"}, - {0x003B0040, nullptr, "CancelLibraryApplet?"}, - {0x00430040, nullptr, "NotifyToWait?"}, - {0x00440000, APT_U::GetSharedFont, "GetSharedFont?"}, - {0x004B00C2, nullptr, "AppletUtility?"}, - {0x00550040, nullptr, "WriteInputToNsState?"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/apt_s.cpp b/src/core/hle/service/apt_s.cpp deleted file mode 100644 index 686335428..000000000 --- a/src/core/hle/service/apt_s.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - - -#include "common/common.h" -#include "common/file_util.h" - -#include "core/hle/hle.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/mutex.h" -#include "core/hle/kernel/shared_memory.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/service/apt_s.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_S - -namespace APT_U { - extern void GetLockHandle(Service::Interface* self); - extern void Initialize(Service::Interface* self); - extern void Enable(Service::Interface* self); - extern void InquireNotification(Service::Interface* self); - extern void NotifyToWait(Service::Interface* self); - extern void GetSharedFont(Service::Interface* self); - extern void AppletUtility(Service::Interface* self); - extern void GlanceParameter(Service::Interface* self); - extern void ReceiveParameter(Service::Interface* self); -} - -namespace APT_S { - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, APT_U::GetLockHandle, "GetLockHandle"}, - {0x00020080, APT_U::Initialize, "Initialize"}, - {0x00030040, APT_U::Enable, "Enable"}, - {0x00040040, nullptr, "Finalize"}, - {0x00050040, nullptr, "GetAppletManInfo"}, - {0x00060040, nullptr, "GetAppletInfo"}, - {0x00070000, nullptr, "GetLastSignaledAppletId"}, - {0x00080000, nullptr, "CountRegisteredApplet"}, - {0x00090040, nullptr, "IsRegistered"}, - {0x000A0040, nullptr, "GetAttribute"}, - {0x000B0040, APT_U::InquireNotification, "InquireNotification"}, - {0x000C0104, nullptr, "SendParameter"}, - {0x000D0080, APT_U::ReceiveParameter, "ReceiveParameter"}, - {0x000E0080, APT_U::GlanceParameter, "GlanceParameter"}, - {0x000F0100, nullptr, "CancelParameter"}, - {0x001000C2, nullptr, "DebugFunc"}, - {0x001100C0, nullptr, "MapProgramIdForDebug"}, - {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, - {0x00130000, nullptr, "GetPreparationState"}, - {0x00140040, nullptr, "SetPreparationState"}, - {0x00150140, nullptr, "PrepareToStartApplication"}, - {0x00160040, nullptr, "PreloadLibraryApplet"}, - {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, - {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, - {0x00190040, nullptr, "PrepareToStartSystemApplet"}, - {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, - {0x001B00C4, nullptr, "StartApplication"}, - {0x001C0000, nullptr, "WakeupApplication"}, - {0x001D0000, nullptr, "CancelApplication"}, - {0x001E0084, nullptr, "StartLibraryApplet"}, - {0x001F0084, nullptr, "StartSystemApplet"}, - {0x00200044, nullptr, "StartNewestHomeMenu"}, - {0x00210000, nullptr, "OrderToCloseApplication"}, - {0x00220040, nullptr, "PrepareToCloseApplication"}, - {0x00230040, nullptr, "PrepareToJumpToApplication"}, - {0x00240044, nullptr, "JumpToApplication"}, - {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, - {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, - {0x00270044, nullptr, "CloseApplication"}, - {0x00280044, nullptr, "CloseLibraryApplet"}, - {0x00290044, nullptr, "CloseSystemApplet"}, - {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, - {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, - {0x002C0044, nullptr, "JumpToHomeMenu"}, - {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, - {0x002E0044, nullptr, "LeaveHomeMenu"}, - {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, - {0x00300044, nullptr, "LeaveResidentApplet"}, - {0x00310100, nullptr, "PrepareToDoApplicationJump"}, - {0x00320084, nullptr, "DoApplicationJump"}, - {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, - {0x00340084, nullptr, "SendDeliverArg"}, - {0x00350080, nullptr, "ReceiveDeliverArg"}, - {0x00360040, nullptr, "LoadSysMenuArg"}, - {0x00370042, nullptr, "StoreSysMenuArg"}, - {0x00380040, nullptr, "PreloadResidentApplet"}, - {0x00390040, nullptr, "PrepareToStartResidentApplet"}, - {0x003A0044, nullptr, "StartResidentApplet"}, - {0x003B0040, nullptr, "CancelLibraryApplet"}, - {0x003C0042, nullptr, "SendDspSleep"}, - {0x003D0042, nullptr, "SendDspWakeUp"}, - {0x003E0080, nullptr, "ReplySleepQuery"}, - {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, - {0x00400042, nullptr, "SendCaptureBufferInfo"}, - {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, - {0x00420080, nullptr, "SleepSystem"}, - {0x00430040, APT_U::NotifyToWait, "NotifyToWait"}, - {0x00440000, APT_U::GetSharedFont, "GetSharedFont"}, - {0x00450040, nullptr, "GetWirelessRebootInfo"}, - {0x00460104, nullptr, "Wrap"}, - {0x00470104, nullptr, "Unwrap"}, - {0x00480100, nullptr, "GetProgramInfo"}, - {0x00490180, nullptr, "Reboot"}, - {0x004A0040, nullptr, "GetCaptureInfo"}, - {0x004B00C2, APT_U::AppletUtility, "AppletUtility"}, - {0x004C0000, nullptr, "SetFatalErrDispMode"}, - {0x004D0080, nullptr, "GetAppletProgramInfo"}, - {0x004E0000, nullptr, "HardwareResetAsync"}, - {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"}, - {0x00500040, nullptr, "GetApplicationCpuTimeLimit"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp deleted file mode 100644 index 2d605a767..000000000 --- a/src/core/hle/service/apt_u.cpp +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - - -#include "common/common.h" -#include "common/file_util.h" - -#include "core/hle/hle.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/mutex.h" -#include "core/hle/kernel/shared_memory.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/service/apt_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace APT_U - -namespace APT_U { - -// Address used for shared font (as observed on HW) -// TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via -// https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any -// address other than 0x18000000 due to internal pointers in the shared font dump that would need to -// be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then -// correctly mapping it in Citra, however we still do not understand how the mapping is determined. -static const VAddr SHARED_FONT_VADDR = 0x18000000; - -/// Handle to shared memory region designated to for shared system font -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 std::vector<u8> shared_font; - -/// Signals used by APT functions -enum class SignalType : u32 { - None = 0x0, - AppJustStarted = 0x1, - ReturningToApp = 0xB, - ExitingApp = 0xC, -}; - -/// App Id's used by APT functions -enum class AppID : u32 { - HomeMenu = 0x101, - AlternateMenu = 0x103, - Camera = 0x110, - FriendsList = 0x112, - GameNotes = 0x113, - InternetBrowser = 0x114, - InstructionManual = 0x115, - Notifications = 0x116, - Miiverse = 0x117, - SoftwareKeyboard1 = 0x201, - Ed = 0x202, - PnoteApp = 0x204, - SnoteApp = 0x205, - Error = 0x206, - Mint = 0x207, - Extrapad = 0x208, - Memolib = 0x209, - Application = 0x300, - SoftwareKeyboard2 = 0x401, -}; - -void Initialize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // 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"); - - cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); - cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); - - // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called. - notification_event->Clear(); - pause_event->Signal(); // Fire start event - - ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); - lock->Release(); - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error -} - -/** - * APT_U::NotifyToWait service function - * Inputs: - * 1 : AppID - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -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(); - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); -} - -void GetLockHandle(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - // Not sure what these parameters are used for, but retail apps check that they are 0 after - // GetLockHandle has been called. - cmd_buff[2] = 0; - cmd_buff[3] = 0; - cmd_buff[4] = 0; - - cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); - LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); -} - -void Enable(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); -} - -/** - * APT_U::GetAppletManInfo service function. - * Inputs: - * 1 : Unknown - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unknown u32 value - * 3 : Unknown u8 value - * 4 : Home Menu AppId - * 5 : AppID of currently active app - */ -void GetAppletManInfo(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 unk = cmd_buff[1]; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0; - cmd_buff[3] = 0; - cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID - cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly - - LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); -} - -/** - * APT_U::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. - * An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu uses this - * command to determine when the launched process is running and to determine when to stop using GSP etc, - * while displaying the "Nintendo 3DS" loading screen. - * Inputs: - * 1 : AppID - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Output, 0 = not registered, 1 = registered. - */ -static void IsRegistered(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 1; // Set to registered - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); -} - -void InquireNotification(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); -} - -/** - * APT_U::SendParameter service function. This sets the parameter data state. - * Inputs: - * 1 : Source AppID - * 2 : Destination AppID - * 3 : Signal type - * 4 : Parameter buffer size, max size is 0x1000 (this can be zero) - * 5 : Value - * 6 : Handle to the destination process, likely used for shared memory (this can be zero) - * 7 : (Size<<14) | 2 - * 8 : Input parameter buffer ptr - * Outputs: - * 0 : Return Header - * 1 : Result of function, 0 on success, otherwise error code -*/ -static void SendParameter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 src_app_id = cmd_buff[1]; - u32 dst_app_id = cmd_buff[2]; - u32 signal_type = cmd_buff[3]; - u32 buffer_size = cmd_buff[4]; - u32 value = cmd_buff[5]; - u32 handle = cmd_buff[6]; - u32 size = cmd_buff[7]; - u32 in_param_buffer_ptr = cmd_buff[8]; - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," - "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", - src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); -} - -/** - * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state, - * from the source process which set the parameters. Once finished, NS will clear a flag in the NS - * state so that this command will return an error if this command is used again if parameters were - * not set again. This is called when the second Initialize event is triggered. It returns a signal - * type indicating why it was triggered. - * Inputs: - * 1 : AppID - * 2 : Parameter buffer size, max size is 0x1000 - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : AppID of the process which sent these parameters - * 3 : Signal type - * 4 : Actual parameter buffer size, this is <= to the the input size - * 5 : Value - * 6 : Handle from the source process which set the parameters, likely used for shared memory - * 7 : Size - * 8 : Output parameter buffer ptr - */ -void ReceiveParameter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - u32 buffer_size = cmd_buff[2]; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0; - cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type - cmd_buff[4] = 0x10; // Parameter buffer size (16) - cmd_buff[5] = 0; - cmd_buff[6] = 0; - cmd_buff[7] = 0; - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); -} - -/** - * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter - * (except for the word value prior to the output handle), except this will not clear the flag - * (except when responseword[3]==8 || responseword[3]==9) in NS state. - * Inputs: - * 1 : AppID - * 2 : Parameter buffer size, max size is 0x1000 - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unknown, for now assume AppID of the process which sent these parameters - * 3 : Unknown, for now assume Signal type - * 4 : Actual parameter buffer size, this is <= to the the input size - * 5 : Value - * 6 : Handle from the source process which set the parameters, likely used for shared memory - * 7 : Size - * 8 : Output parameter buffer ptr - */ -void GlanceParameter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 app_id = cmd_buff[1]; - u32 buffer_size = cmd_buff[2]; - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = 0; - cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type - cmd_buff[4] = 0x10; // Parameter buffer size (16) - cmd_buff[5] = 0; - cmd_buff[6] = 0; - cmd_buff[7] = 0; - - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); -} - -/** - * APT_U::CancelParameter service function. When the parameter data is available, and when the above - * specified fields match the ones in NS state(for the ones where the checks are enabled), this - * clears the flag which indicates that parameter data is available - * (same flag cleared by APT:ReceiveParameter). - * Inputs: - * 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS state. - * 2 : Unknown, this is the same as the first unknown field returned by APT:ReceiveParameter. - * 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS state. - * 4 : AppID - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Status flag, 0 = failure due to no parameter data being available, or the above enabled - * fields don't match the fields in NS state. 1 = success. - */ -static void CancelParameter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 flag1 = cmd_buff[1]; - u32 unk = cmd_buff[2]; - u32 flag2 = cmd_buff[3]; - u32 app_id = cmd_buff[4]; - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - 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); -} - -/** - * APT_U::AppletUtility service function - * Inputs: - * 1 : Unknown, but clearly used for something - * 2 : Buffer 1 size (purpose is unknown) - * 3 : Buffer 2 size (purpose is unknown) - * 5 : Buffer 1 address (purpose is unknown) - * 65 : Buffer 2 address (purpose is unknown) - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -void AppletUtility(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // These are from 3dbrew - I'm not really sure what they're used for. - u32 unk = cmd_buff[1]; - u32 buffer1_size = cmd_buff[2]; - u32 buffer2_size = cmd_buff[3]; - u32 buffer1_addr = cmd_buff[5]; - u32 buffer2_addr = cmd_buff[65]; - - 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, - buffer1_addr, buffer2_addr); -} - -/** - * APT_U::GetSharedFont service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Virtual address of where shared font will be loaded in memory - * 4 : Handle to shared font memory - */ -void GetSharedFont(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - if (!shared_font.empty()) { - // TODO(bunnei): This function shouldn't copy the shared font every time it's called. - // Instead, it should probably map the shared font as RO memory. We don't currently have - // an easy way to do this, but the copy should be sufficient for now. - memcpy(Memory::GetPointer(SHARED_FONT_VADDR), shared_font.data(), shared_font.size()); - - cmd_buff[0] = 0x00440082; - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = SHARED_FONT_VADDR; - cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); - } else { - cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware) - LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT); - } -} - -/** - * APT_U::SetAppCpuTimeLimit service function - * Inputs: - * 1 : Value, must be one - * 2 : Percentage of CPU time from 5 to 80 - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void SetAppCpuTimeLimit(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 value = cmd_buff[1]; - u32 percent = cmd_buff[2]; - - if (value != 1) { - LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); - } - - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - - LOG_WARNING(Service_APT, "(STUBBED) called percent=0x%08X, value=0x%08x", percent, value); -} - -/** - * APT_U::GetAppCpuTimeLimit service function - * Inputs: - * 1 : Value, must be one - * Outputs: - * 0 : Return header - * 1 : Result of function, 0 on success, otherwise error code - * 2 : System core CPU time percentage - */ -static void GetAppCpuTimeLimit(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 value = cmd_buff[1]; - - 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% - - LOG_WARNING(Service_APT, "(STUBBED) called value=0x%08x", value); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, GetLockHandle, "GetLockHandle"}, - {0x00020080, Initialize, "Initialize"}, - {0x00030040, Enable, "Enable"}, - {0x00040040, nullptr, "Finalize"}, - {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, - {0x00060040, nullptr, "GetAppletInfo"}, - {0x00070000, nullptr, "GetLastSignaledAppletId"}, - {0x00080000, nullptr, "CountRegisteredApplet"}, - {0x00090040, IsRegistered, "IsRegistered"}, - {0x000A0040, nullptr, "GetAttribute"}, - {0x000B0040, InquireNotification, "InquireNotification"}, - {0x000C0104, SendParameter, "SendParameter"}, - {0x000D0080, ReceiveParameter, "ReceiveParameter"}, - {0x000E0080, GlanceParameter, "GlanceParameter"}, - {0x000F0100, CancelParameter, "CancelParameter"}, - {0x001000C2, nullptr, "DebugFunc"}, - {0x001100C0, nullptr, "MapProgramIdForDebug"}, - {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, - {0x00130000, nullptr, "GetPreparationState"}, - {0x00140040, nullptr, "SetPreparationState"}, - {0x00150140, nullptr, "PrepareToStartApplication"}, - {0x00160040, nullptr, "PreloadLibraryApplet"}, - {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, - {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, - {0x00190040, nullptr, "PrepareToStartSystemApplet"}, - {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, - {0x001B00C4, nullptr, "StartApplication"}, - {0x001C0000, nullptr, "WakeupApplication"}, - {0x001D0000, nullptr, "CancelApplication"}, - {0x001E0084, nullptr, "StartLibraryApplet"}, - {0x001F0084, nullptr, "StartSystemApplet"}, - {0x00200044, nullptr, "StartNewestHomeMenu"}, - {0x00210000, nullptr, "OrderToCloseApplication"}, - {0x00220040, nullptr, "PrepareToCloseApplication"}, - {0x00230040, nullptr, "PrepareToJumpToApplication"}, - {0x00240044, nullptr, "JumpToApplication"}, - {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, - {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, - {0x00270044, nullptr, "CloseApplication"}, - {0x00280044, nullptr, "CloseLibraryApplet"}, - {0x00290044, nullptr, "CloseSystemApplet"}, - {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, - {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, - {0x002C0044, nullptr, "JumpToHomeMenu"}, - {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, - {0x002E0044, nullptr, "LeaveHomeMenu"}, - {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, - {0x00300044, nullptr, "LeaveResidentApplet"}, - {0x00310100, nullptr, "PrepareToDoApplicationJump"}, - {0x00320084, nullptr, "DoApplicationJump"}, - {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, - {0x00340084, nullptr, "SendDeliverArg"}, - {0x00350080, nullptr, "ReceiveDeliverArg"}, - {0x00360040, nullptr, "LoadSysMenuArg"}, - {0x00370042, nullptr, "StoreSysMenuArg"}, - {0x00380040, nullptr, "PreloadResidentApplet"}, - {0x00390040, nullptr, "PrepareToStartResidentApplet"}, - {0x003A0044, nullptr, "StartResidentApplet"}, - {0x003B0040, nullptr, "CancelLibraryApplet"}, - {0x003C0042, nullptr, "SendDspSleep"}, - {0x003D0042, nullptr, "SendDspWakeUp"}, - {0x003E0080, nullptr, "ReplySleepQuery"}, - {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, - {0x00400042, nullptr, "SendCaptureBufferInfo"}, - {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, - {0x00420080, nullptr, "SleepSystem"}, - {0x00430040, NotifyToWait, "NotifyToWait"}, - {0x00440000, GetSharedFont, "GetSharedFont"}, - {0x00450040, nullptr, "GetWirelessRebootInfo"}, - {0x00460104, nullptr, "Wrap"}, - {0x00470104, nullptr, "Unwrap"}, - {0x00480100, nullptr, "GetProgramInfo"}, - {0x00490180, nullptr, "Reboot"}, - {0x004A0040, nullptr, "GetCaptureInfo"}, - {0x004B00C2, AppletUtility, "AppletUtility"}, - {0x004C0000, nullptr, "SetFatalErrDispMode"}, - {0x004D0080, nullptr, "GetAppletProgramInfo"}, - {0x004E0000, nullptr, "HardwareResetAsync"}, - {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, - {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - // Load the shared system font (if available). - // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header - // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided - // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file - // "shared_font.bin" in the Citra "sysdata" directory. - - shared_font.clear(); - std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; - - FileUtil::CreateFullPath(filepath); // Create path if not already created - FileUtil::IOFile file(filepath, "rb"); - - if (file.IsOpen()) { - // Read shared font data - shared_font.resize((size_t)file.GetSize()); - 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"); - } 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"); - - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 1a2104b48..1eb2562d8 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -3,9 +3,13 @@ // Refer to the license.txt file included. #include <algorithm> -#include "common/make_unique.h" -#include "core/file_sys/archive_systemsavedata.h" + +#include "core/hle/service/fs/archive.h" +#include "core/hle/service/service.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" namespace Service { namespace CFG { @@ -36,7 +40,8 @@ const std::array<float, 8> STEREO_CAMERA_SETTINGS = { static const u32 CONFIG_SAVEFILE_SIZE = 0x8000; static std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer; -static std::unique_ptr<FileSys::Archive_SystemSaveData> cfg_system_save_data; +static Service::FS::ArchiveHandle cfg_system_save_data_archive; +static const std::vector<u8> cfg_system_savedata_id = { 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00 }; ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { // Read the header @@ -97,19 +102,22 @@ ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const u8* data ResultCode DeleteConfigNANDSaveFile() { FileSys::Path path("config"); - if (cfg_system_save_data->DeleteFile(path)) - return RESULT_SUCCESS; - return ResultCode(-1); // TODO(Subv): Find the right error code + return Service::FS::DeleteFileFromArchive(cfg_system_save_data_archive, path); } ResultCode UpdateConfigNANDSavegame() { FileSys::Mode mode = {}; mode.write_flag = 1; mode.create_flag = 1; + FileSys::Path path("config"); - auto file = cfg_system_save_data->OpenFile(path, mode); - ASSERT_MSG(file != nullptr, "could not open file"); - file->Write(0, CONFIG_SAVEFILE_SIZE, 1, cfg_config_file_buffer.data()); + + auto config_result = Service::FS::OpenFileFromArchive(cfg_system_save_data_archive, path, mode); + ASSERT_MSG(config_result.Succeeded(), "could not open file"); + + auto config = config_result.MoveFrom(); + config->backend->Write(0, CONFIG_SAVEFILE_SIZE, 1, cfg_config_file_buffer.data()); + return RESULT_SUCCESS; } @@ -158,27 +166,37 @@ ResultCode FormatConfig() { } void CFGInit() { - // TODO(Subv): In the future we should use the FS service to query this archive, - // currently it is not possible because you can only have one open archive of the same type at any time - std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); - cfg_system_save_data = Common::make_unique<FileSys::Archive_SystemSaveData>( - nand_directory, CFG_SAVE_ID); - if (!cfg_system_save_data->Initialize()) { - LOG_CRITICAL(Service_CFG, "Could not initialize SystemSaveData archive for the CFG:U service"); - return; + AddService(new CFG_I_Interface); + AddService(new CFG_S_Interface); + AddService(new CFG_U_Interface); + + // Open the SystemSaveData archive 0x00010017 + FileSys::Path archive_path(cfg_system_savedata_id); + auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); + + // If the archive didn't exist, create the files inside + if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { + // Format the archive to create the directories + Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); + + // Open it again to get a valid archive now that the folder exists + archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); } - // TODO(Subv): All this code should be moved to cfg:i, - // it's only here because we do not currently emulate the lower level code that uses that service - // Try to open the file in read-only mode to check its existence - FileSys::Mode mode = {}; - mode.read_flag = 1; - FileSys::Path path("config"); - auto file = cfg_system_save_data->OpenFile(path, mode); + ASSERT_MSG(archive_result.Succeeded(), "Could not open the CFG SystemSaveData archive!"); + + cfg_system_save_data_archive = *archive_result; + + FileSys::Path config_path("config"); + FileSys::Mode open_mode = {}; + open_mode.read_flag = 1; - // Load the config if it already exists - if (file != nullptr) { - file->Read(0, CONFIG_SAVEFILE_SIZE, cfg_config_file_buffer.data()); + auto config_result = Service::FS::OpenFileFromArchive(*archive_result, config_path, open_mode); + + // Read the file if it already exists + if (config_result.Succeeded()) { + auto config = config_result.MoveFrom(); + config->backend->Read(0, CONFIG_SAVEFILE_SIZE, cfg_config_file_buffer.data()); return; } @@ -186,10 +204,12 @@ void CFGInit() { // TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals CONSOLE_USERNAME_BLOCK.ng_word = 0; CONSOLE_USERNAME_BLOCK.zero = 0; + // Copy string to buffer and pad with zeros at the end auto size = Common::UTF8ToUTF16(CONSOLE_USERNAME).copy(CONSOLE_USERNAME_BLOCK.username, 0x14); std::fill(std::begin(CONSOLE_USERNAME_BLOCK.username) + size, std::end(CONSOLE_USERNAME_BLOCK.username), 0); + FormatConfig(); } diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp index 20b09a8cb..6d1eee4e0 100644 --- a/src/core/hle/service/cfg/cfg_i.cpp +++ b/src/core/hle/service/cfg/cfg_i.cpp @@ -6,10 +6,8 @@ #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_i.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_I - -namespace CFG_I { +namespace Service { +namespace CFG { /** * CFG_I::GetConfigInfoBlk8 service function @@ -99,11 +97,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08180042, nullptr, "SecureInfoGetSerialNo"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +CFG_I_Interface::CFG_I_Interface() { Register(FunctionTable); } -} // namespace +} // namespace CFG +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/cfg/cfg_i.h b/src/core/hle/service/cfg/cfg_i.h index a498dd589..d0a2cce39 100644 --- a/src/core/hle/service/cfg/cfg_i.h +++ b/src/core/hle/service/cfg/cfg_i.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_I +namespace Service { +namespace CFG { -namespace CFG_I { - -class Interface : public Service::Interface { +class CFG_I_Interface : public Service::Interface { public: - Interface(); + CFG_I_Interface(); std::string GetPortName() const override { return "cfg:i"; } }; -} // namespace +} // namespace CFG +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index d80aeae8d..d9a3e5d51 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp @@ -6,10 +6,8 @@ #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_s.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_S - -namespace CFG_S { +namespace Service { +namespace CFG { /** * CFG_S::GetConfigInfoBlk2 service function @@ -87,11 +85,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x04090000, nullptr, "UpdateConfigBlk00040003"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +CFG_S_Interface::CFG_S_Interface() { Register(FunctionTable); } -} // namespace +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/cfg/cfg_s.h b/src/core/hle/service/cfg/cfg_s.h index d8b67137f..5568d6485 100644 --- a/src/core/hle/service/cfg/cfg_s.h +++ b/src/core/hle/service/cfg/cfg_s.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_S +namespace Service { +namespace CFG { -namespace CFG_S { - -class Interface : public Service::Interface { +class CFG_S_Interface : public Service::Interface { public: - Interface(); + CFG_S_Interface(); std::string GetPortName() const override { return "cfg:s"; } }; -} // namespace +} // 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 a65da90c5..c8c1c5b17 100644 --- a/src/core/hle/service/cfg/cfg_u.cpp +++ b/src/core/hle/service/cfg/cfg_u.cpp @@ -10,10 +10,8 @@ #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_u.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_U - -namespace CFG_U { +namespace Service { +namespace CFG { // TODO(Link Mauve): use a constexpr once MSVC starts supporting it. #define C(code) ((code)[0] | ((code)[1] << 8)) @@ -241,11 +239,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +CFG_U_Interface::CFG_U_Interface() { Register(FunctionTable); } -} // namespace +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/cfg/cfg_u.h b/src/core/hle/service/cfg/cfg_u.h index 9ad73f355..5303d8ac6 100644 --- a/src/core/hle/service/cfg/cfg_u.h +++ b/src/core/hle/service/cfg/cfg_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CFG_U +namespace Service { +namespace CFG { -namespace CFG_U { - -class Interface : public Service::Interface { +class CFG_U_Interface : public Service::Interface { public: - Interface(); + CFG_U_Interface(); std::string GetPortName() const override { return "cfg:u"; } }; -} // namespace +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp index 8d765acb5..58c5acd1e 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err_f.cpp @@ -10,8 +10,171 @@ namespace ERR_F { +enum { + ErrSpecifier0 = 0, + ErrSpecifier1 = 1, + ErrSpecifier3 = 3, + ErrSpecifier4 = 4, +}; + +// This is used instead of ResultCode from result.h +// because we can't have non-trivial data members in unions. +union RSL { + u32 raw; + + BitField<0, 10, u32> description; + BitField<10, 8, u32> module; + BitField<21, 6, u32> summary; + BitField<27, 5, u32> level; +}; + +union ErrInfo { + u8 specifier; + + struct { + u8 specifier; // 0x0 + u8 rev_high; // 0x1 + u16 rev_low; // 0x2 + RSL result_code; // 0x4 + u32 address; // 0x8 + INSERT_PADDING_BYTES(4); // 0xC + u32 pid_low; // 0x10 + u32 pid_high; // 0x14 + u32 aid_low; // 0x18 + u32 aid_high; // 0x1C + } errtype1; + + struct { + u8 specifier; // 0x0 + u8 rev_high; // 0x1 + u16 rev_low; // 0x2 + INSERT_PADDING_BYTES(0xC); // 0x4 + u32 pid_low; // 0x10 + u32 pid_high; // 0x14 + u32 aid_low; // 0x18 + u32 aid_high; // 0x1C + u8 error_type; // 0x20 + INSERT_PADDING_BYTES(3); // 0x21 + u32 fault_status_reg; // 0x24 + u32 fault_addr; // 0x28 + u32 fpexc; // 0x2C + u32 finst; // 0x30 + u32 finst2; // 0x34 + INSERT_PADDING_BYTES(0x34); // 0x38 + u32 sp; // 0x6C + u32 pc; // 0x70 + u32 lr; // 0x74 + u32 cpsr; // 0x78 + } errtype3; + + struct { + u8 specifier; // 0x0 + u8 rev_high; // 0x1 + u16 rev_low; // 0x2 + RSL result_code; // 0x4 + INSERT_PADDING_BYTES(8); // 0x8 + u32 pid_low; // 0x10 + u32 pid_high; // 0x14 + u32 aid_low; // 0x18 + u32 aid_high; // 0x1C + char debug_string1[0x2E]; // 0x20 + char debug_string2[0x2E]; // 0x4E + } errtype4; +}; + +enum { + PrefetchAbort = 0, + DataAbort = 1, + UndefInstr = 2, + VectorFP = 3 +}; + +static std::string GetErrInfo3Type(u8 type_code) { + switch (type_code) { + case PrefetchAbort: return "Prefetch Abort"; + case DataAbort: return "Data Abort"; + case UndefInstr: return "Undefined Instruction"; + case VectorFP: return "Vector Floating Point"; + default: return "unknown"; + } +} + +static void ThrowFatalError(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + LOG_CRITICAL(Service_ERR, "Fatal error!"); + const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); + + switch (errinfo->specifier) { + case ErrSpecifier0: + case ErrSpecifier1: + { + const auto& errtype = errinfo->errtype1; + LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); + LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); + LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); + LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errtype.address); + + LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw); + LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value()); + LOG_CRITICAL(Service_ERR, " Summary: %u", errtype.result_code.summary.Value()); + LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value()); + LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value()); + break; + } + + case ErrSpecifier3: + { + const auto& errtype = errinfo->errtype3; + LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); + LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); + LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); + LOG_CRITICAL(Service_ERR, "TYPE: %s", GetErrInfo3Type(errtype.error_type).c_str()); + + LOG_CRITICAL(Service_ERR, "PC: 0x%08X", errtype.pc); + LOG_CRITICAL(Service_ERR, "LR: 0x%08X", errtype.lr); + LOG_CRITICAL(Service_ERR, "SP: 0x%08X", errtype.sp); + LOG_CRITICAL(Service_ERR, "CPSR: 0x%08X", errtype.cpsr); + + switch (errtype.error_type) { + case PrefetchAbort: + case DataAbort: + LOG_CRITICAL(Service_ERR, "Fault Address: 0x%08X", errtype.fault_addr); + LOG_CRITICAL(Service_ERR, "Fault Status Register: 0x%08X", errtype.fault_status_reg); + break; + case VectorFP: + LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", errtype.fpexc); + LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", errtype.finst); + LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", errtype.finst2); + break; + } + break; + } + + case ErrSpecifier4: + { + const auto& errtype = errinfo->errtype4; + LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); + LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); + LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); + + LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw); + LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value()); + LOG_CRITICAL(Service_ERR, " Summary: %u", errtype.result_code.summary.Value()); + LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value()); + LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value()); + + LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string1); + LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string2); + break; + } + } + + cmd_buff[1] = 0; // No error +} + const Interface::FunctionInfo FunctionTable[] = { - {0x00010800, nullptr, "ThrowFatalError"} + {0x00010800, ThrowFatalError, "ThrowFatalError"} }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index a69c4f25b..9da2e7aa2 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -18,8 +18,11 @@ #include "core/file_sys/archive_savedata.h" #include "core/file_sys/archive_savedatacheck.h" #include "core/file_sys/archive_sdmc.h" +#include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" +#include "core/hle/service/service.h" #include "core/hle/service/fs/archive.h" +#include "core/hle/service/fs/fs_user.h" #include "core/hle/result.h" // Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. @@ -418,6 +421,8 @@ ResultCode CreateExtSaveData(u32 high, u32 low) { void ArchiveInit() { next_handle = 1; + AddService(new FS::Interface); + // TODO(Subv): Add the other archive types (see here for the known types: // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). @@ -449,6 +454,9 @@ void ArchiveInit() { // Create the SaveDataCheck archive, basically a small variation of the RomFS archive auto savedatacheck_factory = Common::make_unique<FileSys::ArchiveFactory_SaveDataCheck>(nand_directory); RegisterArchiveType(std::move(savedatacheck_factory), ArchiveIdCode::SaveDataCheck); + + auto systemsavedata_factory = Common::make_unique<FileSys::ArchiveFactory_SystemSaveData>(nand_directory); + RegisterArchiveType(std::move(systemsavedata_factory), ArchiveIdCode::SystemSaveData); } /// Shutdown archives diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 71ee4ff55..eb312496e 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -487,6 +487,15 @@ static void FormatThisUserSaveData(Service::Interface* self) { cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; } +/** + * FS_User::CreateExtSaveData service function + * Inputs: + * 0: 0x08510242 + * 1: High word of the saveid to create + * 2: Low word of the saveid to create + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ static void CreateExtSaveData(Service::Interface* self) { // TODO(Subv): Figure out the other parameters. u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -496,7 +505,22 @@ static void CreateExtSaveData(Service::Interface* self) { cmd_buff[1] = CreateExtSaveData(save_high, save_low).raw; } -const FSUserInterface::FunctionInfo FunctionTable[] = { +/** + * FS_User::CardSlotIsInserted service function. + * Inputs: + * 0: 0x08210000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Whether there is a game card inserted into the slot or not. + */ +static void CardSlotIsInserted(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + LOG_WARNING(Service_FS, "(STUBBED) called"); +} + +const Interface::FunctionInfo FunctionTable[] = { {0x000100C6, nullptr, "Dummy1"}, {0x040100C4, nullptr, "Control"}, {0x08010002, Initialize, "Initialize"}, @@ -531,7 +555,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { {0x081E0042, nullptr, "GetNandLog"}, {0x081F0000, nullptr, "ClearSdmcLog"}, {0x08200000, nullptr, "ClearNandLog"}, - {0x08210000, nullptr, "CardSlotIsInserted"}, + {0x08210000, CardSlotIsInserted, "CardSlotIsInserted"}, {0x08220000, nullptr, "CardSlotPowerOn"}, {0x08230000, nullptr, "CardSlotPowerOff"}, {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, @@ -590,7 +614,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { //////////////////////////////////////////////////////////////////////////////////////////////////// // Interface class -FSUserInterface::FSUserInterface() { +Interface::Interface() { Register(FunctionTable); } diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h index 2d896dd5f..bb6ab195e 100644 --- a/src/core/hle/service/fs/fs_user.h +++ b/src/core/hle/service/fs/fs_user.h @@ -6,16 +6,13 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FS_User - namespace Service { namespace FS { /// Interface to "fs:USER" service -class FSUserInterface : public Service::Interface { +class Interface : public Service::Interface { public: - FSUserInterface(); + Interface(); std::string GetPortName() const override { return "fs:USER"; diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 31e61391f..c23cfa3c8 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -368,28 +368,28 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { case CommandId::SET_MEMORY_FILL: { auto& params = command.memory_fill; - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)), - Memory::VirtualToPhysicalAddress(params.start1) >> 3); - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)), - Memory::VirtualToPhysicalAddress(params.end1) >> 3); - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].size)), params.end1 - params.start1); - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value)), params.value1); - - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)), - Memory::VirtualToPhysicalAddress(params.start2) >> 3); - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)), - Memory::VirtualToPhysicalAddress(params.end2) >> 3); - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].size)), params.end2 - params.start2); - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value)), params.value2); + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)), + Memory::VirtualToPhysicalAddress(params.start1) >> 3); + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)), + Memory::VirtualToPhysicalAddress(params.end1) >> 3); + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1); + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1); + + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)), + Memory::VirtualToPhysicalAddress(params.start2) >> 3); + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)), + Memory::VirtualToPhysicalAddress(params.end2) >> 3); + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2); + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2); break; } case CommandId::SET_DISPLAY_TRANSFER: { auto& params = command.image_copy; - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3); - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3); WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size); WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size); @@ -402,9 +402,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { case CommandId::SET_TEXTURE_COPY: { auto& params = command.image_copy; - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3); - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3); WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size); WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size); diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h index 65abb194a..a435d418a 100644 --- a/src/core/hle/service/gsp_gpu.h +++ b/src/core/hle/service/gsp_gpu.h @@ -109,9 +109,13 @@ struct Command { u32 start1; u32 value1; u32 end1; + u32 start2; u32 value2; u32 end2; + + u16 control1; + u16 control2; } memory_fill; struct { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 7cb01729e..e0689be2e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -2,7 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/service/service.h" #include "core/hle/service/hid/hid.h" +#include "core/hle/service/hid/hid_spvr.h" +#include "core/hle/service/hid/hid_user.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/event.h" @@ -35,6 +38,19 @@ static inline PadData* GetPadData() { return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); } +// TODO(peachum): +// Add a method for setting analog input from joystick device for the circle Pad. +// +// This method should: +// * Be called after both PadButton<Press, Release>(). +// * Be called before PadUpdateComplete() +// * Set current PadEntry.circle_pad_<axis> using analog data +// * Set PadData.raw_circle_pad_data +// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 +// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 +// * 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 + /** * Circle Pad from keys. * @@ -121,9 +137,25 @@ void PadUpdateComplete() { g_event_pad_or_touch_2->Signal(); } +void GetIPCHandles(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = 0; // No error + // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) + cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); + cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); + cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); + cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); + cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); +} + void HIDInit() { using namespace Kernel; + AddService(new HID_U_Interface); + AddService(new HID_SPVR_Interface); + g_shared_mem = SharedMemory::Create("HID:SharedMem"); // Create event handles diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 2116d2ca3..9c6e86f77 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -7,6 +7,7 @@ #include <array> #include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" #include "common/bit_field.h" namespace Kernel { @@ -47,6 +48,15 @@ struct PadState { BitField<10, 1, u32> x; BitField<11, 1, u32> y; + BitField<14, 1, u32> zl; + BitField<15, 1, u32> zr; + + BitField<20, 1, u32> touch; + + BitField<24, 1, u32> c_right; + BitField<25, 1, u32> c_left; + BitField<26, 1, u32> c_up; + BitField<27, 1, u32> c_down; BitField<28, 1, u32> circle_right; BitField<29, 1, u32> circle_left; BitField<30, 1, u32> circle_up; @@ -99,11 +109,37 @@ const PadState PAD_R = {{1u << 8}}; const PadState PAD_L = {{1u << 9}}; const PadState PAD_X = {{1u << 10}}; const PadState PAD_Y = {{1u << 11}}; + +const PadState PAD_ZL = {{1u << 14}}; +const PadState PAD_ZR = {{1u << 15}}; + +const PadState PAD_TOUCH = {{1u << 20}}; + +const PadState PAD_C_RIGHT = {{1u << 24}}; +const PadState PAD_C_LEFT = {{1u << 25}}; +const PadState PAD_C_UP = {{1u << 26}}; +const PadState PAD_C_DOWN = {{1u << 27}}; const PadState PAD_CIRCLE_RIGHT = {{1u << 28}}; const PadState PAD_CIRCLE_LEFT = {{1u << 29}}; const PadState PAD_CIRCLE_UP = {{1u << 30}}; const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; +/** + * HID::GetIPCHandles service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unused + * 3 : Handle to HID_User shared memory + * 4 : Event signaled by HID_User + * 5 : Event signaled by HID_User + * 6 : Event signaled by HID_User + * 7 : Gyroscope event + * 8 : Event signaled by HID_User + */ +void GetIPCHandles(Interface* self); + // Methods for updating the HID module's state void PadButtonPress(const PadState& pad_state); void PadButtonRelease(const PadState& pad_state); diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp index 8f06b224d..790dcabbf 100644 --- a/src/core/hle/service/hid/hid_spvr.cpp +++ b/src/core/hle/service/hid/hid_spvr.cpp @@ -3,19 +3,14 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" +#include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid_spvr.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_SPVR - -namespace HID_User { - extern void GetIPCHandles(Service::Interface* self); -} - -namespace HID_SPVR { +namespace Service { +namespace HID { const Interface::FunctionInfo FunctionTable[] = { - {0x000A0000, HID_User::GetIPCHandles, "GetIPCHandles"}, + {0x000A0000, GetIPCHandles, "GetIPCHandles"}, {0x000B0000, nullptr, "StartAnalogStickCalibration"}, {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, {0x00110000, nullptr, "EnableAccelerometer"}, @@ -27,11 +22,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00170000, nullptr, "GetSoundVolume"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +HID_SPVR_Interface::HID_SPVR_Interface() { Register(FunctionTable); } -} // namespace +} // namespace HID +} // namespace Service diff --git a/src/core/hle/service/hid/hid_spvr.h b/src/core/hle/service/hid/hid_spvr.h index 53ddc8569..ba61583d2 100644 --- a/src/core/hle/service/hid/hid_spvr.h +++ b/src/core/hle/service/hid/hid_spvr.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_SPVR +namespace Service { +namespace HID { -namespace HID_SPVR { - -class Interface : public Service::Interface { +class HID_SPVR_Interface : public Service::Interface { public: - Interface(); + HID_SPVR_Interface(); std::string GetPortName() const override { return "hid:SPVR"; } }; -} // namespace +} // namespace HID +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index 7f464705f..1d0accefe 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp @@ -6,54 +6,10 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/hid.h" -#include "hid_user.h" +#include "core/hle/service/hid/hid_user.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_User - -namespace HID_User { - - -// TODO(peachum): -// Add a method for setting analog input from joystick device for the circle Pad. -// -// This method should: -// * Be called after both PadButton<Press, Release>(). -// * Be called before PadUpdateComplete() -// * Set current PadEntry.circle_pad_<axis> using analog data -// * Set PadData.raw_circle_pad_data -// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 -// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 -// * 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 - - -/** - * HID_User::GetIPCHandles service function - * Inputs: - * None - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unused - * 3 : Handle to HID_User shared memory - * 4 : Event signaled by HID_User - * 5 : Event signaled by HID_User - * 6 : Event signaled by HID_User - * 7 : Gyroscope event - * 8 : Event signaled by HID_User - */ -void GetIPCHandles(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = 0; // No error - // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) - cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); - cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); - cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); - cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); - cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); - cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); -} +namespace Service { +namespace HID { const Interface::FunctionInfo FunctionTable[] = { {0x000A0000, GetIPCHandles, "GetIPCHandles"}, @@ -66,11 +22,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00170000, nullptr, "GetSoundVolume"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +HID_U_Interface::HID_U_Interface() { Register(FunctionTable); } -} // namespace +} // namespace HID +} // namespace Service diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h index 1d9929e67..0eeec2c25 100644 --- a/src/core/hle/service/hid/hid_user.h +++ b/src/core/hle/service/hid/hid_user.h @@ -6,24 +6,23 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_User - // This service is used for interfacing to physical user controls. // Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad. -namespace HID_User { - +namespace Service { +namespace HID { + /** * HID service interface. */ -class Interface : public Service::Interface { +class HID_U_Interface : public Service::Interface { public: - Interface(); + HID_U_Interface(); std::string GetPortName() const override { return "hid:USER"; } }; -} // namespace +} // namespace HID +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp new file mode 100644 index 000000000..56c918d4f --- /dev/null +++ b/src/core/hle/service/ptm/ptm.cpp @@ -0,0 +1,76 @@ +// 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/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" + +namespace Service { +namespace PTM { + +/// Values for the default gamecoin.dat file +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 battery_is_charging = true; + +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; +} + +u32 GetShellState() { + return shell_open ? 1 : 0; +} + +ChargeLevels GetBatteryLevel() { + // 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 +} + +void PTMInit() { + AddService(new PTM_Play_Interface); + AddService(new PTM_Sysm_Interface); + AddService(new PTM_U_Interface); + + // 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); + // If the archive didn't exist, create the files inside + if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { + // Format the archive to create the directories + Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + // Open it again to get a valid archive now that the folder exists + archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); + + FileSys::Path gamecoin_path("gamecoin.dat"); + FileSys::Mode open_mode = {}; + open_mode.write_flag = 1; + open_mode.create_flag = 1; + // Open the file and write the default gamecoin information + auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); + if (gamecoin_result.Succeeded()) { + auto gamecoin = gamecoin_result.MoveFrom(); + gamecoin->backend->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); + gamecoin->backend->Close(); + } + } +} + +void PTMShutdown() { + +} + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h new file mode 100644 index 000000000..f697aae4d --- /dev/null +++ b/src/core/hle/service/ptm/ptm.h @@ -0,0 +1,65 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include "core/hle/result.h" + +namespace Service { +namespace PTM { + +/// Charge levels used by PTM functions +enum class ChargeLevels : u32 { + CriticalBattery = 1, + LowBattery = 2, + HalfFull = 3, + MostlyFull = 4, + CompletelyFull = 5, +}; + +/** + * Represents the gamecoin file structure in the SharedExtData archive + * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) + */ +struct GameCoin { + u32 magic; ///< Magic number: 0x4F00 + u16 total_coins; ///< Total Play Coins + u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. + u32 step_count; ///< Total step count at the time a new Play Coin was obtained. + u32 last_step_count; ///< Step count for the day the last Play Coin was obtained + u16 year; + u8 month; + u8 day; +}; + +/** + * 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. + */ +u32 GetAdapterState(); + +/** + * Returns whether the 3DS's physical shell casing is open or closed + * @returns 1 if the shell is open, and 0 if otherwise + */ +u32 GetShellState(); + +/** + * Get the current battery's charge level. + * @returns The battery's charge level. + */ +ChargeLevels GetBatteryLevel(); + +/// Initialize the PTM service +void PTMInit(); + +/// Shutdown the PTM service +void PTMShutdown(); + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp index f21d9088e..8e8ae8558 100644 --- a/src/core/hle/service/ptm_play.cpp +++ b/src/core/hle/service/ptm/ptm_play.cpp @@ -3,12 +3,10 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/ptm_play.h" +#include "core/hle/service/ptm/ptm_play.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_PLAY - -namespace PTM_PLAY { +namespace Service { +namespace PTM { const Interface::FunctionInfo FunctionTable[] = { { 0x08070082, nullptr, "GetPlayHistory" }, @@ -17,11 +15,9 @@ const Interface::FunctionInfo FunctionTable[] = { { 0x080B0080, nullptr, "CalcPlayHistoryStart" }, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +PTM_Play_Interface::PTM_Play_Interface() { Register(FunctionTable); } -} // namespace +} // namespace PTM +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/ptm_play.h b/src/core/hle/service/ptm/ptm_play.h index 2f4f0d6fd..e5c3e04df 100644 --- a/src/core/hle/service/ptm_play.h +++ b/src/core/hle/service/ptm/ptm_play.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_PLAY +namespace Service { +namespace PTM { -namespace PTM_PLAY { - -class Interface : public Service::Interface { +class PTM_Play_Interface : public Service::Interface { public: - Interface(); + PTM_Play_Interface(); std::string GetPortName() const override { return "ptm:play"; } }; -} // namespace +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp index 96ef2dce0..2d841f69c 100644 --- a/src/core/hle/service/ptm_sysm.cpp +++ b/src/core/hle/service/ptm/ptm_sysm.cpp @@ -5,12 +5,22 @@ #include "common/make_unique.h" #include "core/file_sys/archive_extsavedata.h" #include "core/hle/hle.h" -#include "core/hle/service/ptm_sysm.h" +#include "core/hle/service/ptm/ptm_sysm.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_SYSM +namespace Service { +namespace PTM { -namespace PTM_SYSM { +/** + * 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"}, @@ -37,7 +47,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x080C0080, nullptr, "SetUserTime"}, {0x080D0000, nullptr, "InvalidateSystemTime"}, {0x080E0140, nullptr, "NotifyPlayEvent"}, - {0x080F0000, nullptr, "IsLegacyPowerOff"}, + {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"}, {0x08100000, nullptr, "ClearLegacyPowerOff"}, {0x08110000, nullptr, "GetShellStatus"}, {0x08120000, nullptr, "IsShutdownByBatteryEmpty"}, @@ -45,11 +55,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"} }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +PTM_Sysm_Interface::PTM_Sysm_Interface() { Register(FunctionTable); } -} // namespace +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm_sysm.h b/src/core/hle/service/ptm/ptm_sysm.h index 0f267b214..e37f20546 100644 --- a/src/core/hle/service/ptm_sysm.h +++ b/src/core/hle/service/ptm/ptm_sysm.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_SYSM +namespace Service { +namespace PTM { -namespace PTM_SYSM { - -class Interface : public Service::Interface { +class PTM_Sysm_Interface : public Interface { public: - Interface(); + PTM_Sysm_Interface(); std::string GetPortName() const override { return "ptm:sysm"; } }; -} // namespace +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp new file mode 100644 index 000000000..0af7c8bf6 --- /dev/null +++ b/src/core/hle/service/ptm/ptm_u.cpp @@ -0,0 +1,99 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/make_unique.h" + +#include "core/hle/hle.h" +#include "core/hle/service/ptm/ptm.h" +#include "core/hle/service/ptm/ptm_u.h" + +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"}, + {0x00030000, nullptr, "GetRtcAlarm"}, + {0x00040000, nullptr, "CancelRtcAlarm"}, + {0x00050000, GetAdapterState, "GetAdapterState"}, + {0x00060000, GetShellState, "GetShellState"}, + {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, + {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, + {0x00090000, nullptr, "GetPedometerState"}, + {0x000A0042, nullptr, "GetStepHistoryEntry"}, + {0x000B00C2, nullptr, "GetStepHistory"}, + {0x000C0000, nullptr, "GetTotalStepCount"}, + {0x000D0040, nullptr, "SetPedometerRecordingMode"}, + {0x000E0000, nullptr, "GetPedometerRecordingMode"}, + {0x000F0084, nullptr, "GetStepHistoryAll"}, +}; + +PTM_U_Interface::PTM_U_Interface() { + Register(FunctionTable); +} + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm/ptm_u.h index a44624fd5..bf132f610 100644 --- a/src/core/hle/service/ptm_u.h +++ b/src/core/hle/service/ptm/ptm_u.h @@ -6,20 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_U +namespace Service { +namespace PTM { -// ptm service - -namespace PTM_U { - -class Interface : public Service::Interface { +class PTM_U_Interface : public Interface { public: - Interface(); + PTM_U_Interface(); std::string GetPortName() const override { return "ptm:u"; } }; -} // namespace +} // namespace PTM +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp deleted file mode 100644 index 7121d837c..000000000 --- a/src/core/hle/service/ptm_u.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/make_unique.h" - -#include "core/hle/hle.h" -#include "core/hle/service/fs/archive.h" -#include "core/hle/service/ptm_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PTM_U - -namespace PTM_U { - -/** - * Represents the gamecoin file structure in the SharedExtData archive - * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) - */ -struct GameCoin { - u32 magic; ///< Magic number: 0x4F00 - u16 total_coins; ///< Total Play Coins - u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. - u32 step_count; ///< Total step count at the time a new Play Coin was obtained. - u32 last_step_count; ///< Step count for the day the last Play Coin was obtained - u16 year; - u8 month; - u8 day; -}; -static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; -static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; - -/// Charge levels used by PTM functions -enum class ChargeLevels : u32 { - CriticalBattery = 1, - LowBattery = 2, - HalfFull = 3, - MostlyFull = 4, - CompletelyFull = 5, -}; - -static bool shell_open = true; - -static bool battery_is_charging = true; - -/** - * 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. - * 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(); - - // TODO(purpasmart96): This function is only a stub, - // it returns a valid result without implementing full functionality. - - cmd_buff[1] = 0; // No error - cmd_buff[2] = battery_is_charging ? 1 : 0; - - 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] = 0; - cmd_buff[2] = shell_open ? 1 : 0; -} - -/** - * 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(); - - // TODO(purpasmart96): This function is only a stub, - // it returns a valid result without implementing full functionality. - - cmd_buff[1] = 0; // No error - cmd_buff[2] = static_cast<u32>(ChargeLevels::CompletelyFull); // Set to a completely full battery - - 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] = 0; // No error - cmd_buff[2] = battery_is_charging ? 1 : 0; - - LOG_WARNING(Service_PTM, "(STUBBED) called"); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010002, nullptr, "RegisterAlarmClient"}, - {0x00020080, nullptr, "SetRtcAlarm"}, - {0x00030000, nullptr, "GetRtcAlarm"}, - {0x00040000, nullptr, "CancelRtcAlarm"}, - {0x00050000, GetAdapterState, "GetAdapterState"}, - {0x00060000, GetShellState, "GetShellState"}, - {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, - {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, - {0x00090000, nullptr, "GetPedometerState"}, - {0x000A0042, nullptr, "GetStepHistoryEntry"}, - {0x000B00C2, nullptr, "GetStepHistory"}, - {0x000C0000, nullptr, "GetTotalStepCount"}, - {0x000D0040, nullptr, "SetPedometerRecordingMode"}, - {0x000E0000, nullptr, "GetPedometerRecordingMode"}, - {0x000F0084, nullptr, "GetStepHistoryAll"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); - - // Open the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file - FileSys::Path archive_path(ptm_shared_extdata_id); - auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); - // If the archive didn't exist, create the files inside - if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { - // Format the archive to create the directories - Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); - // Open it again to get a valid archive now that the folder exists - archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); - ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); - - FileSys::Path gamecoin_path("gamecoin.dat"); - FileSys::Mode open_mode = {}; - open_mode.write_flag = 1; - open_mode.create_flag = 1; - // Open the file and write the default gamecoin information - auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); - if (gamecoin_result.Succeeded()) { - auto gamecoin = gamecoin_result.MoveFrom(); - gamecoin->backend->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); - gamecoin->backend->Close(); - } - } -} - -} // namespace diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5dce8068e..91f13cd7e 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -11,26 +11,17 @@ #include "core/hle/service/am_app.h" #include "core/hle/service/am_net.h" #include "core/hle/service/am_sys.h" -#include "core/hle/service/apt_a.h" -#include "core/hle/service/apt_s.h" -#include "core/hle/service/apt_u.h" #include "core/hle/service/boss_p.h" #include "core/hle/service/boss_u.h" #include "core/hle/service/cam_u.h" #include "core/hle/service/cecd_u.h" #include "core/hle/service/cecd_s.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/csnd_snd.h" #include "core/hle/service/dsp_dsp.h" #include "core/hle/service/err_f.h" -#include "core/hle/service/fs/fs_user.h" #include "core/hle/service/frd_a.h" #include "core/hle/service/frd_u.h" #include "core/hle/service/gsp_gpu.h" -#include "core/hle/service/hid/hid_spvr.h" -#include "core/hle/service/hid/hid_user.h" #include "core/hle/service/gsp_lcd.h" #include "core/hle/service/http_c.h" #include "core/hle/service/ir_rst.h" @@ -44,14 +35,17 @@ #include "core/hle/service/ns_s.h" #include "core/hle/service/nwm_uds.h" #include "core/hle/service/pm_app.h" -#include "core/hle/service/ptm_play.h" -#include "core/hle/service/ptm_u.h" -#include "core/hle/service/ptm_sysm.h" #include "core/hle/service/soc_u.h" #include "core/hle/service/srv.h" #include "core/hle/service/ssl_c.h" #include "core/hle/service/y2r_u.h" +#include "core/hle/service/apt/apt.h" +#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/ptm/ptm.h" + namespace Service { std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; @@ -60,12 +54,12 @@ std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; //////////////////////////////////////////////////////////////////////////////////////////////////// // Module interface -static void AddNamedPort(Interface* interface) { - g_kernel_named_ports.emplace(interface->GetPortName(), interface); +static void AddNamedPort(Interface* interface_) { + g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); } -static void AddService(Interface* interface) { - g_srv_services.emplace(interface->GetPortName(), interface); +void AddService(Interface* interface_) { + g_srv_services.emplace(interface_->GetPortName(), interface_); } /// Initialize ServiceManager @@ -73,31 +67,28 @@ void Init() { AddNamedPort(new SRV::Interface); AddNamedPort(new ERR_F::Interface); + Service::FS::ArchiveInit(); + Service::CFG::CFGInit(); + Service::APT::APTInit(); + Service::PTM::PTMInit(); + Service::HID::HIDInit(); + AddService(new AC_U::Interface); AddService(new ACT_U::Interface); AddService(new AM_APP::Interface); AddService(new AM_NET::Interface); AddService(new AM_SYS::Interface); - AddService(new APT_A::Interface); - AddService(new APT_S::Interface); - AddService(new APT_U::Interface); AddService(new BOSS_P::Interface); AddService(new BOSS_U::Interface); AddService(new CAM_U::Interface); AddService(new CECD_S::Interface); AddService(new CECD_U::Interface); - AddService(new CFG_I::Interface); - AddService(new CFG_S::Interface); - AddService(new CFG_U::Interface); AddService(new CSND_SND::Interface); AddService(new DSP_DSP::Interface); AddService(new FRD_A::Interface); AddService(new FRD_U::Interface); - AddService(new FS::FSUserInterface); AddService(new GSP_GPU::Interface); AddService(new GSP_LCD::Interface); - AddService(new HID_User::Interface); - AddService(new HID_SPVR::Interface); AddService(new HTTP_C::Interface); AddService(new IR_RST::Interface); AddService(new IR_U::Interface); @@ -110,9 +101,6 @@ void Init() { AddService(new NS_S::Interface); AddService(new NWM_UDS::Interface); AddService(new PM_APP::Interface); - AddService(new PTM_PLAY::Interface); - AddService(new PTM_U::Interface); - AddService(new PTM_SYSM::Interface); AddService(new SOC_U::Interface); AddService(new SSL_C::Interface); AddService(new Y2R_U::Interface); @@ -122,6 +110,12 @@ void Init() { /// Shutdown ServiceManager void Shutdown() { + Service::HID::HIDShutdown(); + Service::PTM::PTMShutdown(); + Service::APT::APTShutdown(); + Service::CFG::CFGShutdown(); + Service::FS::ArchiveShutdown(); + g_srv_services.clear(); g_kernel_named_ports.clear(); LOG_DEBUG(Service, "shutdown OK"); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 3370f9f9b..bfe16ebad 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -120,4 +120,7 @@ extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_na /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; +/// Adds a service to the services table +void AddService(Interface* interface_); + } // namespace diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index a58e04d6d..6607965e1 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -11,6 +11,8 @@ namespace Y2R_U { +static Kernel::SharedPtr<Kernel::Event> completion_event = 0; + /** * Y2R_U::IsBusyConversion service function * Outputs: @@ -26,13 +28,26 @@ static void IsBusyConversion(Service::Interface* self) { LOG_WARNING(Service, "(STUBBED) called"); } +/** + * Y2R_U::GetTransferEndEvent service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 3 : The handle of the completion event + */ +static void GetTransferEndEvent(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).MoveFrom(); +} + const Interface::FunctionInfo FunctionTable[] = { {0x00010040, nullptr, "SetInputFormat"}, {0x00030040, nullptr, "SetOutputFormat"}, {0x00050040, nullptr, "SetRotation"}, {0x00070040, nullptr, "SetBlockAlignment"}, {0x000D0040, nullptr, "SetTransferEndInterrupt"}, - {0x000F0000, nullptr, "GetTransferEndEvent"}, + {0x000F0000, GetTransferEndEvent, "GetTransferEndEvent"}, {0x00100102, nullptr, "SetSendingY"}, {0x00110102, nullptr, "SetSendingU"}, {0x00120102, nullptr, "SetSendingV"}, @@ -53,6 +68,8 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { + completion_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "Y2R:Completed"); + Register(FunctionTable); } diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index f0726ef09..568dad684 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/common_types.h" +#include "common/common_funcs.h" #include "core/core.h" #include "core/mem_map.h" @@ -13,13 +14,6 @@ namespace SharedPage { -// helper macro to properly align structure members. -// Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121", -// depending on the current source line to make sure variable names are unique. -#define INSERT_PADDING_BYTES_HELPER1(x, y) x ## y -#define INSERT_PADDING_BYTES_HELPER2(x, y) INSERT_PADDING_BYTES_HELPER1(x, y) -#define INSERT_PADDING_BYTES(num_words) u8 INSERT_PADDING_BYTES_HELPER2(pad, __LINE__)[(num_words)] - // see http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes #pragma pack(1) |
