diff options
Diffstat (limited to 'src/core/hle/service/apt/apt.cpp')
-rw-r--r-- | src/core/hle/service/apt/apt.cpp | 285 |
1 files changed, 285 insertions, 0 deletions
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 |