diff options
Diffstat (limited to 'src/core/hle/service')
40 files changed, 1140 insertions, 673 deletions
diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp index aa270a2c3..e3dd23949 100644 --- a/src/core/hle/service/ac/ac.cpp +++ b/src/core/hle/service/ac/ac.cpp @@ -4,11 +4,16 @@ #include <array> +#include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/result.h" #include "core/hle/service/ac/ac.h" #include "core/hle/service/ac/ac_i.h" #include "core/hle/service/ac/ac_u.h" +#include "core/memory.h" namespace Service { namespace AC { diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d344a622f..961305e9f 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -2,8 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <array> #include <cinttypes> +#include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/ipc.h" +#include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/am_app.h" #include "core/hle/service/am/am_net.h" @@ -176,8 +180,6 @@ void GetTicketList(Service::Interface* self) { } void Init() { - using namespace Kernel; - AddService(new AM_APP_Interface); AddService(new AM_NET_Interface); AddService(new AM_SYS_Interface); diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 366d1eacf..4c587e3c8 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -5,6 +5,7 @@ #include "common/common_paths.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/applets/applet.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" @@ -74,6 +75,7 @@ void GetSharedFont(Service::Interface* self) { LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); rb.Push<u32>(-1); // TODO: Find the right error code rb.Skip(1 + 2, true); + Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSharedFont); return; } diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index e63b61450..ee80926d2 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -4,6 +4,8 @@ #pragma once +#include <vector> +#include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" #include "core/hle/kernel/kernel.h" diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp index e0de037f8..2bba3aff6 100644 --- a/src/core/hle/service/boss/boss.cpp +++ b/src/core/hle/service/boss/boss.cpp @@ -3,6 +3,9 @@ // Refer to the license.txt file included. #include <cinttypes> +#include "common/logging/log.h" +#include "core/hle/ipc.h" +#include "core/hle/result.h" #include "core/hle/service/boss/boss.h" #include "core/hle/service/boss/boss_p.h" #include "core/hle/service/boss/boss_u.h" @@ -24,9 +27,7 @@ void InitializeSession(Service::Interface* self) { if (translation != IPC::CallingPidDesc()) { cmd_buff[0] = IPC::MakeHeader(0, 0x1, 0); // 0x40 - cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, - ErrorSummary::WrongArgument, ErrorLevel::Permanent) - .raw; + cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; LOG_ERROR(Service_BOSS, "The translation was invalid, translation=0x%08X", translation); return; } diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp index 95665e754..7394c844f 100644 --- a/src/core/hle/service/cam/cam.cpp +++ b/src/core/hle/service/cam/cam.cpp @@ -11,13 +11,17 @@ #include "common/logging/log.h" #include "core/core_timing.h" #include "core/frontend/camera/factory.h" +#include "core/hle/ipc.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" +#include "core/hle/result.h" #include "core/hle/service/cam/cam.h" #include "core/hle/service/cam/cam_c.h" #include "core/hle/service/cam/cam_q.h" #include "core/hle/service/cam/cam_s.h" #include "core/hle/service/cam/cam_u.h" #include "core/hle/service/service.h" +#include "core/memory.h" #include "core/settings.h" namespace Service { @@ -55,7 +59,7 @@ struct PortConfig { u16 x1; // x-coordinate of ending position for trimming u16 y1; // y-coordinate of ending position for trimming - u32 transfer_bytes; + u16 transfer_bytes; Kernel::SharedPtr<Kernel::Event> completion_event; Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event; @@ -225,8 +229,7 @@ static void ActivatePort(int port_id, int camera_id) { template <int max_index> class CommandParamBitSet : public BitSet8 { public: - explicit CommandParamBitSet(u32 command_param) - : BitSet8(static_cast<u8>(command_param & 0xFF)) {} + explicit CommandParamBitSet(u8 command_param) : BitSet8(command_param) {} bool IsValid() const { return m_val < (1 << max_index); @@ -244,9 +247,10 @@ using CameraSet = CommandParamBitSet<3>; } // namespace void StartCapture(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 1, 0); + const PortSet port_select(rp.Pop<u8>()); - const PortSet port_select(cmd_buff[1]); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { @@ -267,21 +271,20 @@ void StartCapture(Service::Interface* self) { LOG_WARNING(Service_CAM, "port %u already started", i); } } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } void StopCapture(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 1, 0); + const PortSet port_select(rp.Pop<u8>()); - const PortSet port_select(cmd_buff[1]); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { @@ -293,21 +296,20 @@ void StopCapture(Service::Interface* self) { LOG_WARNING(Service_CAM, "port %u already stopped", i); } } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } void IsBusy(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0); + const PortSet port_select(rp.Pop<u8>()); - const PortSet port_select(cmd_buff[1]); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); if (port_select.IsValid()) { bool is_busy = true; @@ -315,80 +317,74 @@ void IsBusy(Service::Interface* self) { for (int i : port_select) { is_busy &= ports[i].is_busy; } - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = is_busy ? 1 : 0; + rb.Push(RESULT_SUCCESS); + rb.Push(is_busy); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); + rb.Skip(1, false); } - cmd_buff[0] = IPC::MakeHeader(0x3, 2, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } void ClearBuffer(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x04, 1, 0); + const PortSet port_select(rp.Pop<u8>()); - cmd_buff[0] = IPC::MakeHeader(0x4, 1, 0); - cmd_buff[1] = RESULT_SUCCESS.raw; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); } void GetVsyncInterruptEvent(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 1, 0); + const PortSet port_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); if (port_select.IsSingle()) { int port = *port_select.begin(); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = IPC::CopyHandleDesc(); - cmd_buff[3] = Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).MoveFrom(); + rb.Push(RESULT_SUCCESS); + rb.PushCopyHandles( + Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).MoveFrom()); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; - cmd_buff[2] = IPC::CopyHandleDesc(); - cmd_buff[2] = 0; + rb.Push(ERROR_INVALID_ENUM_VALUE); + rb.PushCopyHandles(0); } - cmd_buff[0] = IPC::MakeHeader(0x5, 1, 2); - LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); } void GetBufferErrorInterruptEvent(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0); + const PortSet port_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); if (port_select.IsSingle()) { int port = *port_select.begin(); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = IPC::CopyHandleDesc(); - cmd_buff[3] = - Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).MoveFrom(); + rb.Push(RESULT_SUCCESS); + rb.PushCopyHandles( + Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).MoveFrom()); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; - cmd_buff[2] = IPC::CopyHandleDesc(); - cmd_buff[2] = 0; + rb.Push(ERROR_INVALID_ENUM_VALUE); + rb.PushCopyHandles(0); } LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); } void SetReceiving(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const VAddr dest = cmd_buff[1]; - const PortSet port_select(cmd_buff[2]); - const u32 image_size = cmd_buff[3]; - const u32 trans_unit = cmd_buff[4] & 0xFFFF; - + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 4, 2); + const VAddr dest = rp.Pop<u32>(); + const PortSet port_select(rp.Pop<u8>()); + const u32 image_size = rp.Pop<u32>(); + const u16 trans_unit = rp.Pop<u16>(); + rp.PopHandle(); // Handle to destination process. not used + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); if (port_select.IsSingle()) { int port_id = *port_select.begin(); PortConfig& port = ports[port_id]; @@ -403,149 +399,145 @@ void SetReceiving(Service::Interface* self) { port.is_pending_receiving = true; } - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = IPC::CopyHandleDesc(); - cmd_buff[3] = Kernel::g_handle_table.Create(port.completion_event).MoveFrom(); + rb.Push(RESULT_SUCCESS); + rb.PushCopyHandles(Kernel::g_handle_table.Create(port.completion_event).MoveFrom()); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); + rb.PushCopyHandles(0); } - cmd_buff[0] = IPC::MakeHeader(0x7, 1, 2); - LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest, port_select.m_val, image_size, trans_unit); } void IsFinishedReceiving(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 0); + const PortSet port_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); if (port_select.IsSingle()) { int port = *port_select.begin(); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = (ports[port].is_receiving || ports[port].is_pending_receiving) ? 0 : 1; + bool is_busy = ports[port].is_receiving || ports[port].is_pending_receiving; + rb.Push(RESULT_SUCCESS); + rb.Push(!is_busy); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); + rb.Skip(1, false); } - cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } void SetTransferLines(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); - const u32 transfer_lines = cmd_buff[2] & 0xFFFF; - const u32 width = cmd_buff[3] & 0xFFFF; - const u32 height = cmd_buff[4] & 0xFFFF; + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x09, 4, 0); + const PortSet port_select(rp.Pop<u8>()); + const u16 transfer_lines = rp.Pop<u16>(); + const u16 width = rp.Pop<u16>(); + const u16 height = rp.Pop<u16>(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { ports[i].transfer_bytes = transfer_lines * width * 2; } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0); - LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u", port_select.m_val, transfer_lines, width, height); } void GetMaxLines(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0A, 2, 0); + const u16 width = rp.Pop<u16>(); + const u16 height = rp.Pop<u16>(); - const u32 width = cmd_buff[1] & 0xFFFF; - const u32 height = cmd_buff[2] & 0xFFFF; + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 constexpr u32 MIN_TRANSFER_UNIT = 256; constexpr u32 MAX_BUFFER_SIZE = 2560; if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { - cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; + rb.Push(ERROR_OUT_OF_RANGE); + rb.Skip(1, false); } else { u32 lines = MAX_BUFFER_SIZE / width; if (lines > height) { lines = height; } - cmd_buff[1] = RESULT_SUCCESS.raw; + ResultCode result = RESULT_SUCCESS; while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) { --lines; if (lines == 0) { - cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; + result = ERROR_OUT_OF_RANGE; break; } } - cmd_buff[2] = lines; + rb.Push(result); + rb.Push(lines); } - cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0); - LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); } void SetTransferBytes(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); - const u32 transfer_bytes = cmd_buff[2] & 0xFFFF; - const u32 width = cmd_buff[3] & 0xFFFF; - const u32 height = cmd_buff[4] & 0xFFFF; + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0B, 4, 0); + const PortSet port_select(rp.Pop<u8>()); + const u16 transfer_bytes = rp.Pop<u16>(); + const u16 width = rp.Pop<u16>(); + const u16 height = rp.Pop<u16>(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { ports[i].transfer_bytes = transfer_bytes; } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0xB, 1, 0); - LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u", port_select.m_val, transfer_bytes, width, height); } void GetTransferBytes(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0C, 1, 0); + const PortSet port_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); if (port_select.IsSingle()) { int port = *port_select.begin(); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = ports[port].transfer_bytes; + rb.Push(RESULT_SUCCESS); + rb.Push(ports[port].transfer_bytes); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); + rb.Skip(1, false); } - cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0); - LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val); } void GetMaxBytes(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 2, 0); + const u16 width = rp.Pop<u16>(); + const u16 height = rp.Pop<u16>(); - const u32 width = cmd_buff[1] & 0xFFFF; - const u32 height = cmd_buff[2] & 0xFFFF; + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 constexpr u32 MIN_TRANSFER_UNIT = 256; constexpr u32 MAX_BUFFER_SIZE = 2560; if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { - cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; + rb.Push(ERROR_OUT_OF_RANGE); + rb.Skip(1, false); } else { u32 bytes = MAX_BUFFER_SIZE; @@ -553,63 +545,59 @@ void GetMaxBytes(Service::Interface* self) { bytes -= MIN_TRANSFER_UNIT; } - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = bytes; + rb.Push(RESULT_SUCCESS); + rb.Push(bytes); } - cmd_buff[0] = IPC::MakeHeader(0xD, 2, 0); LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); } void SetTrimming(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); - const bool trim = (cmd_buff[2] & 0xFF) != 0; + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0E, 2, 0); + const PortSet port_select(rp.Pop<u8>()); + const bool trim = rp.Pop<bool>(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { ports[i].is_trimming = trim; } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0xE, 1, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim); } void IsTrimming(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 1, 0); + const PortSet port_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); if (port_select.IsSingle()) { int port = *port_select.begin(); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = ports[port].is_trimming; + rb.Push(RESULT_SUCCESS); + rb.Push(ports[port].is_trimming); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); + rb.Skip(1, false); } - cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } void SetTrimmingParams(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); - const u16 x0 = static_cast<u16>(cmd_buff[2] & 0xFFFF); - const u16 y0 = static_cast<u16>(cmd_buff[3] & 0xFFFF); - const u16 x1 = static_cast<u16>(cmd_buff[4] & 0xFFFF); - const u16 y1 = static_cast<u16>(cmd_buff[5] & 0xFFFF); - + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x10, 5, 0); + const PortSet port_select(rp.Pop<u8>()); + const u16 x0 = rp.Pop<u16>(); + const u16 y0 = rp.Pop<u16>(); + const u16 x1 = rp.Pop<u16>(); + const u16 y1 = rp.Pop<u16>(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { ports[i].x0 = x0; @@ -617,49 +605,46 @@ void SetTrimmingParams(Service::Interface* self) { ports[i].x1 = x1; ports[i].y1 = y1; } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val, x0, y0, x1, y1); } void GetTrimmingParams(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x11, 1, 0); + const PortSet port_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); if (port_select.IsSingle()) { int port = *port_select.begin(); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = ports[port].x0; - cmd_buff[3] = ports[port].y0; - cmd_buff[4] = ports[port].x1; - cmd_buff[5] = ports[port].y1; + rb.Push(RESULT_SUCCESS); + rb.Push(ports[port].x0); + rb.Push(ports[port].y0); + rb.Push(ports[port].x1); + rb.Push(ports[port].y1); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); + rb.Skip(4, false); } - cmd_buff[0] = IPC::MakeHeader(0x11, 5, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); } void SetTrimmingParamsCenter(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const PortSet port_select(cmd_buff[1]); - const u16 trim_w = static_cast<u16>(cmd_buff[2] & 0xFFFF); - const u16 trim_h = static_cast<u16>(cmd_buff[3] & 0xFFFF); - const u16 cam_w = static_cast<u16>(cmd_buff[4] & 0xFFFF); - const u16 cam_h = static_cast<u16>(cmd_buff[5] & 0xFFFF); - + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 5, 0); + const PortSet port_select(rp.Pop<u8>()); + const u16 trim_w = rp.Pop<u16>(); + const u16 trim_h = rp.Pop<u16>(); + const u16 cam_w = rp.Pop<u16>(); + const u16 cam_h = rp.Pop<u16>(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (port_select.IsValid()) { for (int i : port_select) { ports[i].x0 = (cam_w - trim_w) / 2; @@ -667,23 +652,21 @@ void SetTrimmingParamsCenter(Service::Interface* self) { ports[i].x1 = ports[i].x0 + trim_w; ports[i].y1 = ports[i].y0 + trim_h; } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0); - LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u", port_select.m_val, trim_w, trim_h, cam_w, cam_h); } void Activate(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const CameraSet camera_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x13, 1, 0); + const CameraSet camera_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid()) { if (camera_select.m_val == 0) { // deactive all for (int i = 0; i < 2; ++i) { @@ -694,10 +677,10 @@ void Activate(Service::Interface* self) { } ports[i].is_active = false; } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else if (camera_select[0] && camera_select[1]) { LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated"); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } else { if (camera_select[0]) { ActivatePort(0, 0); @@ -708,24 +691,22 @@ void Activate(Service::Interface* self) { if (camera_select[2]) { ActivatePort(1, 2); } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0); - LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val); } void SwitchContext(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const CameraSet camera_select(cmd_buff[1]); - const ContextSet context_select(cmd_buff[2]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 2, 0); + const CameraSet camera_select(rp.Pop<u8>()); + const ContextSet context_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid() && context_select.IsSingle()) { int context = *context_select.begin(); for (int camera : camera_select) { @@ -736,26 +717,24 @@ void SwitchContext(Service::Interface* self) { cameras[camera].impl->SetFormat(context_config.format); cameras[camera].impl->SetResolution(context_config.resolution); } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, context_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x14, 1, 0); - LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val, context_select.m_val); } void FlipImage(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const CameraSet camera_select(cmd_buff[1]); - const Flip flip = static_cast<Flip>(cmd_buff[2] & 0xFF); - const ContextSet context_select(cmd_buff[3]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 3, 0); + const CameraSet camera_select(rp.Pop<u8>()); + const Flip flip = static_cast<Flip>(rp.Pop<u8>()); + const ContextSet context_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { @@ -765,32 +744,30 @@ void FlipImage(Service::Interface* self) { } } } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, context_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x1D, 1, 0); - LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u", camera_select.m_val, static_cast<int>(flip), context_select.m_val); } void SetDetailSize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const CameraSet camera_select(cmd_buff[1]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 8, 0); + const CameraSet camera_select(rp.Pop<u8>()); Resolution resolution; - resolution.width = static_cast<u16>(cmd_buff[2] & 0xFFFF); - resolution.height = static_cast<u16>(cmd_buff[3] & 0xFFFF); - resolution.crop_x0 = static_cast<u16>(cmd_buff[4] & 0xFFFF); - resolution.crop_y0 = static_cast<u16>(cmd_buff[5] & 0xFFFF); - resolution.crop_x1 = static_cast<u16>(cmd_buff[6] & 0xFFFF); - resolution.crop_y1 = static_cast<u16>(cmd_buff[7] & 0xFFFF); - const ContextSet context_select(cmd_buff[8]); - + resolution.width = rp.Pop<u16>(); + resolution.height = rp.Pop<u16>(); + resolution.crop_x0 = rp.Pop<u16>(); + resolution.crop_y0 = rp.Pop<u16>(); + resolution.crop_x1 = rp.Pop<u16>(); + resolution.crop_y1 = rp.Pop<u16>(); + const ContextSet context_select(rp.Pop<u8>()); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { @@ -800,15 +777,13 @@ void SetDetailSize(Service::Interface* self) { } } } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, context_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x1E, 1, 0); - LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, " "crop_x1=%u, crop_y1=%u, context_select=%u", camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0, @@ -816,12 +791,12 @@ void SetDetailSize(Service::Interface* self) { } void SetSize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const CameraSet camera_select(cmd_buff[1]); - const u32 size = cmd_buff[2] & 0xFF; - const ContextSet context_select(cmd_buff[3]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 3, 0); + const CameraSet camera_select(rp.Pop<u8>()); + const u8 size = rp.Pop<u8>(); + const ContextSet context_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { @@ -831,49 +806,45 @@ void SetSize(Service::Interface* self) { } } } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, context_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x1F, 1, 0); - LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u", camera_select.m_val, size, context_select.m_val); } void SetFrameRate(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const CameraSet camera_select(cmd_buff[1]); - const FrameRate frame_rate = static_cast<FrameRate>(cmd_buff[2] & 0xFF); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x20, 2, 0); + const CameraSet camera_select(rp.Pop<u8>()); + const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid()) { for (int camera : camera_select) { cameras[camera].frame_rate = frame_rate; // TODO(wwylele): consider hinting the actual camera with the expected frame rate } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0); - LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d", camera_select.m_val, static_cast<int>(frame_rate)); } void SetEffect(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const CameraSet camera_select(cmd_buff[1]); - const Effect effect = static_cast<Effect>(cmd_buff[2] & 0xFF); - const ContextSet context_select(cmd_buff[3]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x22, 3, 0); + const CameraSet camera_select(rp.Pop<u8>()); + const Effect effect = static_cast<Effect>(rp.Pop<u8>()); + const ContextSet context_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { @@ -883,26 +854,24 @@ void SetEffect(Service::Interface* self) { } } } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, context_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x22, 1, 0); - LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u", camera_select.m_val, static_cast<int>(effect), context_select.m_val); } void SetOutputFormat(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - const CameraSet camera_select(cmd_buff[1]); - const OutputFormat format = static_cast<OutputFormat>(cmd_buff[2] & 0xFF); - const ContextSet context_select(cmd_buff[3]); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0); + const CameraSet camera_select(rp.Pop<u8>()); + const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>()); + const ContextSet context_select(rp.Pop<u8>()); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (camera_select.IsValid() && context_select.IsValid()) { for (int camera : camera_select) { for (int context : context_select) { @@ -912,34 +881,32 @@ void SetOutputFormat(Service::Interface* self) { } } } - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, context_select.m_val); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + rb.Push(ERROR_INVALID_ENUM_VALUE); } - cmd_buff[0] = IPC::MakeHeader(0x25, 1, 0); - LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u", camera_select.m_val, static_cast<int>(format), context_select.m_val); } void SynchronizeVsyncTiming(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x29, 2, 0); + const u8 camera_select1 = rp.Pop<u8>(); + const u8 camera_select2 = rp.Pop<u8>(); - const u32 camera_select1 = cmd_buff[1] & 0xFF; - const u32 camera_select2 = cmd_buff[2] & 0xFF; - - cmd_buff[0] = IPC::MakeHeader(0x29, 1, 0); - cmd_buff[1] = RESULT_SUCCESS.raw; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u", camera_select1, camera_select2); } void GetStereoCameraCalibrationData(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestBuilder rb = + IPC::RequestParser(Kernel::GetCommandBuffer(), 0x2B, 0, 0).MakeBuilder(17, 0); // Default values taken from yuriks' 3DS. Valid data is required here or games using the // calibration get stuck in an infinite CPU loop. @@ -958,34 +925,28 @@ void GetStereoCameraCalibrationData(Service::Interface* self) { data.imageWidth = 640; data.imageHeight = 480; - cmd_buff[0] = IPC::MakeHeader(0x2B, 17, 0); - cmd_buff[1] = RESULT_SUCCESS.raw; - memcpy(&cmd_buff[2], &data, sizeof(data)); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(data); LOG_TRACE(Service_CAM, "called"); } void SetPackageParameterWithoutContext(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x33, 11, 0); PackageParameterWithoutContext package; - std::memcpy(&package, cmd_buff + 1, sizeof(package)); + rp.PopRaw(package); - cmd_buff[0] = IPC::MakeHeader(0x33, 1, 0); - cmd_buff[1] = RESULT_SUCCESS.raw; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_CAM, "(STUBBED) called"); } -template <typename PackageParameterType, int command_id> -static void SetPackageParameter() { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - PackageParameterType package; - std::memcpy(&package, cmd_buff + 1, sizeof(package)); - - const CameraSet camera_select(static_cast<u32>(package.camera_select)); - const ContextSet context_select(static_cast<u32>(package.context_select)); +template <typename PackageParameterType> +static ResultCode SetPackageParameter(const PackageParameterType& package) { + const CameraSet camera_select(package.camera_select); + const ContextSet context_select(package.context_select); if (camera_select.IsValid() && context_select.IsValid()) { for (int camera_id : camera_select) { @@ -1002,53 +963,66 @@ static void SetPackageParameter() { } } } - cmd_buff[1] = RESULT_SUCCESS.raw; + return RESULT_SUCCESS; } else { LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select, package.context_select); - cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; + return ERROR_INVALID_ENUM_VALUE; } - - cmd_buff[0] = IPC::MakeHeader(command_id, 1, 0); - - LOG_DEBUG(Service_CAM, "called"); } -Resolution PackageParameterWithContext::GetResolution() { +Resolution PackageParameterWithContext::GetResolution() const { return PRESET_RESOLUTION[static_cast<int>(size)]; } void SetPackageParameterWithContext(Service::Interface* self) { - SetPackageParameter<PackageParameterWithContext, 0x34>(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x34, 5, 0); + + PackageParameterWithContext package; + rp.PopRaw(package); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + ResultCode result = SetPackageParameter(package); + rb.Push(result); + + LOG_DEBUG(Service_CAM, "called"); } void SetPackageParameterWithContextDetail(Service::Interface* self) { - SetPackageParameter<PackageParameterWithContextDetail, 0x35>(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x35, 7, 0); + + PackageParameterWithContextDetail package; + rp.PopRaw(package); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + ResultCode result = SetPackageParameter(package); + rb.Push(result); + + LOG_DEBUG(Service_CAM, "called"); } void GetSuitableY2rStandardCoefficient(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[0] = IPC::MakeHeader(0x36, 2, 0); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0; + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x36, 0, 0); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); LOG_WARNING(Service_CAM, "(STUBBED) called"); } void PlayShutterSound(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - u8 sound_id = cmd_buff[1] & 0xFF; + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x38, 1, 0); + u8 sound_id = rp.Pop<u8>(); - cmd_buff[0] = IPC::MakeHeader(0x38, 1, 0); - cmd_buff[1] = RESULT_SUCCESS.raw; + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id); } void DriverInitialize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x39, 0, 0); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); for (int camera_id = 0; camera_id < NumCameras; ++camera_id) { CameraConfig& camera = cameras[camera_id]; @@ -1074,14 +1048,14 @@ void DriverInitialize(Service::Interface* self) { port.Clear(); } - cmd_buff[0] = IPC::MakeHeader(0x39, 1, 0); - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_CAM, "called"); } void DriverFinalize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3A, 0, 0); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); CancelReceiving(0); CancelReceiving(1); @@ -1090,8 +1064,7 @@ void DriverFinalize(Service::Interface* self) { camera.impl = nullptr; } - cmd_buff[0] = IPC::MakeHeader(0x3A, 1, 0); - cmd_buff[1] = RESULT_SUCCESS.raw; + rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_CAM, "called"); } diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h index 34a9c8479..b6da721d8 100644 --- a/src/core/hle/service/cam/cam.h +++ b/src/core/hle/service/cam/cam.h @@ -184,9 +184,10 @@ struct PackageParameterWithoutContext { s16 auto_white_balance_window_y; s16 auto_white_balance_window_width; s16 auto_white_balance_window_height; + INSERT_PADDING_WORDS(4); }; -static_assert(sizeof(PackageParameterWithoutContext) == 28, +static_assert(sizeof(PackageParameterWithoutContext) == 44, "PackageParameterCameraWithoutContext structure size is wrong"); struct PackageParameterWithContext { @@ -196,11 +197,12 @@ struct PackageParameterWithContext { Effect effect; Size size; INSERT_PADDING_BYTES(3); + INSERT_PADDING_WORDS(3); - Resolution GetResolution(); + Resolution GetResolution() const; }; -static_assert(sizeof(PackageParameterWithContext) == 8, +static_assert(sizeof(PackageParameterWithContext) == 20, "PackageParameterWithContext structure size is wrong"); struct PackageParameterWithContextDetail { @@ -209,13 +211,14 @@ struct PackageParameterWithContextDetail { Flip flip; Effect effect; Resolution resolution; + INSERT_PADDING_WORDS(3); - Resolution GetResolution() { + Resolution GetResolution() const { return resolution; } }; -static_assert(sizeof(PackageParameterWithContextDetail) == 16, +static_assert(sizeof(PackageParameterWithContextDetail) == 28, "PackageParameterWithContextDetail structure size is wrong"); /** diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index eb04273db..bd9814244 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -3,7 +3,10 @@ // Refer to the license.txt file included. #include "common/logging/log.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/result.h" #include "core/hle/service/cecd/cecd.h" #include "core/hle/service/cecd/cecd_ndm.h" #include "core/hle/service/cecd/cecd_s.h" diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 8c8c1ec77..5a7878b31 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -11,7 +11,10 @@ #include "common/string_util.h" #include "common/swap.h" #include "core/file_sys/archive_systemsavedata.h" +#include "core/file_sys/errors.h" #include "core/file_sys/file_backend.h" +#include "core/hle/ipc.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/result.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_i.h" @@ -20,6 +23,7 @@ #include "core/hle/service/cfg/cfg_u.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/service.h" +#include "core/memory.h" #include "core/settings.h" namespace Service { @@ -411,7 +415,7 @@ ResultCode UpdateConfigNANDSavegame() { ResultCode FormatConfig() { ResultCode res = DeleteConfigNANDSaveFile(); // The delete command fails if the file doesn't exist, so we have to check that too - if (!res.IsSuccess() && res.description != ErrorDescription::FS_FileNotFound) { + if (!res.IsSuccess() && res != FileSys::ERROR_FILE_NOT_FOUND) { return res; } // Delete the old data @@ -534,7 +538,7 @@ ResultCode LoadConfigNANDSaveFile() { 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) { + if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { // Format the archive to create the directories Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, FileSys::ArchiveFormatInfo(), archive_path); diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp index 6cf62f9bc..1455f20ca 100644 --- a/src/core/hle/service/csnd_snd.cpp +++ b/src/core/hle/service/csnd_snd.cpp @@ -4,9 +4,12 @@ #include <cstring> #include "common/alignment.h" +#include "core/hle/ipc.h" +#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/csnd_snd.h" +#include "core/memory.h" namespace Service { namespace CSND { diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp index 25c07f401..32cfa2c44 100644 --- a/src/core/hle/service/dlp/dlp_srvr.cpp +++ b/src/core/hle/service/dlp/dlp_srvr.cpp @@ -4,6 +4,7 @@ #include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/ipc.h" #include "core/hle/result.h" #include "core/hle/service/dlp/dlp_srvr.h" diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 39711ea97..363066d14 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -3,12 +3,18 @@ // Refer to the license.txt file included. #include <algorithm> +#include <array> #include <cinttypes> #include "audio_core/hle/pipe.h" +#include "common/assert.h" #include "common/hash.h" #include "common/logging/log.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/result.h" #include "core/hle/service/dsp_dsp.h" +#include "core/memory.h" using DspPipe = DSP::HLE::DspPipe; @@ -289,9 +295,7 @@ static void WriteProcessPipe(Service::Interface* self) { "size=0x%X, buffer=0x%08X", cmd_buff[3], pipe_index, size, buffer); cmd_buff[0] = IPC::MakeHeader(0, 1, 0); - cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, - ErrorSummary::WrongArgument, ErrorLevel::Permanent) - .raw; + cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; return; } diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp index 9da55f328..7c8f4339f 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err_f.cpp @@ -6,10 +6,11 @@ #include <chrono> #include <iomanip> #include <sstream> - #include "common/bit_field.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "core/core.h" +#include "core/hle/ipc.h" #include "core/hle/result.h" #include "core/hle/service/err_f.h" @@ -172,6 +173,7 @@ static void ThrowFatalError(Interface* self) { const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); LOG_CRITICAL(Service_ERR, "Fatal error type: %s", GetErrType(errinfo->errinfo_common.specifier).c_str()); + Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorUnknown); // Generic Info LogGenericInfo(errinfo->errinfo_common); diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp index 34fdf7f53..76ecda8b7 100644 --- a/src/core/hle/service/frd/frd.cpp +++ b/src/core/hle/service/frd/frd.cpp @@ -2,11 +2,16 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/assert.h" +#include "common/logging/log.h" #include "common/string_util.h" +#include "core/hle/ipc.h" +#include "core/hle/result.h" #include "core/hle/service/frd/frd.h" #include "core/hle/service/frd/frd_a.h" #include "core/hle/service/frd/frd_u.h" #include "core/hle/service/service.h" +#include "core/memory.h" namespace Service { namespace FRD { diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 6cddc1fdb..3605ef175 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -22,8 +22,13 @@ #include "core/file_sys/archive_sdmcwriteonly.h" #include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" +#include "core/file_sys/errors.h" #include "core/file_sys/file_backend.h" +#include "core/hle/ipc.h" +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" @@ -50,16 +55,6 @@ static constexpr Kernel::Handle INVALID_HANDLE{}; namespace Service { namespace FS { -// TODO: Verify code -/// Returned when a function is passed an invalid handle. -const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::FS, - ErrorSummary::InvalidArgument, ErrorLevel::Permanent); - -/// Returned when a function is passed an invalid archive handle. -const ResultCode ERR_INVALID_ARCHIVE_HANDLE(ErrorDescription::FS_ArchiveNotMounted, ErrorModule::FS, - ErrorSummary::NotFound, - ErrorLevel::Status); // 0xC8804465 - // Command to access archive file enum class FileCommand : u32 { Dummy1 = 0x000100C6, @@ -92,6 +87,10 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& File::~File() {} void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { + using Kernel::ClientSession; + using Kernel::ServerSession; + using Kernel::SharedPtr; + u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); switch (cmd) { @@ -170,10 +169,9 @@ void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_ses case FileCommand::OpenLinkFile: { LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); - auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); - ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); - cmd_buff[3] = Kernel::g_handle_table - .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + auto sessions = ServerSession::CreateSessionPair(GetName()); + ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)) .ValueOr(INVALID_HANDLE); break; } @@ -267,9 +265,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi auto itr = id_code_map.find(id_code); if (itr == id_code_map.end()) { - // TODO: Verify error against hardware - return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound, - ErrorLevel::Permanent); + return FileSys::ERROR_NOT_FOUND; } CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); @@ -284,7 +280,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi ResultCode CloseArchive(ArchiveHandle handle) { if (handle_map.erase(handle) == 0) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; else return RESULT_SUCCESS; } @@ -309,7 +305,7 @@ ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handl const FileSys::Mode mode) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; auto backend = archive->OpenFile(path, mode); if (backend.Failed()) @@ -322,7 +318,7 @@ ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handl ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; return archive->DeleteFile(path); } @@ -334,7 +330,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, ArchiveBackend* src_archive = GetArchive(src_archive_handle); ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; if (src_archive == dest_archive) { return src_archive->RenameFile(src_path, dest_path); @@ -347,7 +343,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; return archive->DeleteDirectory(path); } @@ -356,7 +352,7 @@ ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; return archive->DeleteDirectoryRecursively(path); } @@ -365,7 +361,7 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path u64 file_size) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; return archive->CreateFile(path, file_size); } @@ -373,7 +369,7 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; return archive->CreateDirectory(path); } @@ -385,7 +381,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, ArchiveBackend* src_archive = GetArchive(src_archive_handle); ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; if (src_archive == dest_archive) { return src_archive->RenameDirectory(src_path, dest_path); @@ -399,7 +395,7 @@ ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle arc const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; auto backend = archive->OpenDirectory(path); if (backend.Failed()) @@ -412,7 +408,7 @@ ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle arc ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) - return ERR_INVALID_ARCHIVE_HANDLE; + return FileSys::ERR_INVALID_ARCHIVE_HANDLE; return MakeResult<u64>(archive->GetFreeBytes()); } diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 2ea956e0b..3a3371c88 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -8,7 +8,7 @@ #include <string> #include "common/common_types.h" #include "core/file_sys/archive_backend.h" -#include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/hle_ipc.h" #include "core/hle/result.h" namespace FileSys { @@ -43,7 +43,7 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; typedef u64 ArchiveHandle; -class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> { +class File final : public Kernel::SessionRequestHandler { public: File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); ~File(); @@ -60,7 +60,7 @@ protected: void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; }; -class Directory final : public SessionRequestHandler { +class Directory final : public Kernel::SessionRequestHandler { public: Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); ~Directory(); diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 33b290699..34e1783ec 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -8,7 +8,13 @@ #include "common/logging/log.h" #include "common/scope_exit.h" #include "common/string_util.h" +#include "core/core.h" +#include "core/file_sys/errors.h" +#include "core/hle/ipc.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" @@ -17,8 +23,9 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace FS_User -using Kernel::SharedPtr; +using Kernel::ClientSession; using Kernel::ServerSession; +using Kernel::SharedPtr; namespace Service { namespace FS { @@ -76,11 +83,11 @@ static void OpenFile(Service::Interface* self) { rb.Push(file_res.Code()); if (file_res.Succeeded()) { std::shared_ptr<File> file = *file_res; - auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); - file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); - rb.PushMoveHandles(Kernel::g_handle_table - .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) - .MoveFrom()); + auto sessions = ServerSession::CreateSessionPair(file->GetName()); + file->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); + + rb.PushMoveHandles( + Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom()); } else { rb.PushMoveHandles(0); LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); @@ -129,7 +136,7 @@ static void OpenFileDirectly(Service::Interface* self) { ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); if (archive_handle.Failed()) { LOG_ERROR(Service_FS, - "failed to get a handle for archive archive_id=0x%08X archive_path=%s", + "Failed to get a handle for archive archive_id=0x%08X archive_path=%s", static_cast<u32>(archive_id), archive_path.DebugStr().c_str()); cmd_buff[1] = archive_handle.Code().raw; cmd_buff[3] = 0; @@ -142,11 +149,11 @@ static void OpenFileDirectly(Service::Interface* self) { cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { std::shared_ptr<File> file = *file_res; - auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); - file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); - cmd_buff[3] = Kernel::g_handle_table - .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) - .MoveFrom(); + auto sessions = ServerSession::CreateSessionPair(file->GetName()); + file->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); + + cmd_buff[3] = + Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", @@ -409,11 +416,11 @@ static void OpenDirectory(Service::Interface* self) { cmd_buff[1] = dir_res.Code().raw; if (dir_res.Succeeded()) { std::shared_ptr<Directory> directory = *dir_res; - auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); - directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); - cmd_buff[3] = Kernel::g_handle_table - .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) - .MoveFrom(); + auto sessions = ServerSession::CreateSessionPair(directory->GetName()); + directory->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); + + cmd_buff[3] = + Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom(); } else { LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); @@ -539,9 +546,7 @@ static void FormatSaveData(Service::Interface* self) { if (archive_id != FS::ArchiveIdCode::SaveData) { LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", static_cast<u32>(archive_id)); - cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS, - ErrorSummary::InvalidArgument, ErrorLevel::Usage) - .raw; + cmd_buff[1] = FileSys::ERROR_INVALID_PATH.raw; return; } @@ -802,9 +807,7 @@ static void InitializeWithSdkVersion(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; } else { LOG_ERROR(Service_FS, "ProcessId Header must be 0x20"); - cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, - ErrorSummary::WrongArgument, ErrorLevel::Permanent) - .raw; + cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; } } diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index a960778a7..6ff0f4812 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -5,14 +5,16 @@ #include "common/bit_field.h" #include "common/microprofile.h" #include "core/core.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/result.h" +#include "core/hle/service/gsp_gpu.h" #include "core/hw/gpu.h" #include "core/hw/hw.h" #include "core/hw/lcd.h" #include "core/memory.h" -#include "gsp_gpu.h" #include "video_core/debug_utils/debug_utils.h" #include "video_core/gpu_debugger.h" @@ -25,13 +27,24 @@ namespace GSP { // Beginning address of HW regs const u32 REGS_BEGIN = 0x1EB00000; -const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED( - ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX, ErrorSummary::InvalidArgument, - ErrorLevel::Usage); // 0xE0E02A01 -const ResultCode ERR_GSP_REGS_MISALIGNED(ErrorDescription::MisalignedSize, ErrorModule::GX, +namespace ErrCodes { +enum { + // TODO(purpasmart): Check if this name fits its actual usage + OutofRangeOrMisalignedAddress = 513, + FirstInitialization = 519, +}; +} + +constexpr ResultCode RESULT_FIRST_INITIALIZATION(ErrCodes::FirstInitialization, ErrorModule::GX, + ErrorSummary::Success, ErrorLevel::Success); +constexpr ResultCode ERR_REGS_OUTOFRANGE_OR_MISALIGNED(ErrCodes::OutofRangeOrMisalignedAddress, + ErrorModule::GX, + ErrorSummary::InvalidArgument, + ErrorLevel::Usage); // 0xE0E02A01 +constexpr ResultCode ERR_REGS_MISALIGNED(ErrorDescription::MisalignedSize, ErrorModule::GX, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BF2 -const ResultCode ERR_GSP_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorModule::GX, +constexpr ResultCode ERR_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorModule::GX, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BEC @@ -93,11 +106,11 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_va LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)", base_address, size_in_bytes); - return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED; + return ERR_REGS_OUTOFRANGE_OR_MISALIGNED; } else if (size_in_bytes <= max_size_in_bytes) { if (size_in_bytes & 3) { LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes); - return ERR_GSP_REGS_MISALIGNED; + return ERR_REGS_MISALIGNED; } else { while (size_in_bytes > 0) { WriteSingleHWReg(base_address, Memory::Read32(data_vaddr)); @@ -111,7 +124,7 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_va } else { LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes); - return ERR_GSP_REGS_INVALID_SIZE; + return ERR_REGS_INVALID_SIZE; } } @@ -134,11 +147,11 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)", base_address, size_in_bytes); - return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED; + return ERR_REGS_OUTOFRANGE_OR_MISALIGNED; } else if (size_in_bytes <= max_size_in_bytes) { if (size_in_bytes & 3) { LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes); - return ERR_GSP_REGS_MISALIGNED; + return ERR_REGS_MISALIGNED; } else { while (size_in_bytes > 0) { const u32 reg_address = base_address + REGS_BEGIN; @@ -164,7 +177,7 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr } else { LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes); - return ERR_GSP_REGS_INVALID_SIZE; + return ERR_REGS_INVALID_SIZE; } } @@ -372,9 +385,7 @@ static void RegisterInterruptRelayQueue(Interface* self) { if (first_initialization) { // This specific code is required for a successful initialization, rather than 0 first_initialization = false; - cmd_buff[1] = ResultCode(ErrorDescription::GPU_FirstInitialization, ErrorModule::GX, - ErrorSummary::Success, ErrorLevel::Success) - .raw; + cmd_buff[1] = RESULT_FIRST_INITIALIZATION.raw; } else { cmd_buff[1] = RESULT_SUCCESS.raw; } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 64d01cdd7..5255f6dc8 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -10,7 +10,9 @@ #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/frontend/input.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid_spvr.h" diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index 53807cd91..0de698003 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -6,6 +6,7 @@ #include "common/bit_field.h" #include "core/core_timing.h" #include "core/frontend/input.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/hid.h" diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp index 226af0083..fdecdce64 100644 --- a/src/core/hle/service/ir/ir_user.cpp +++ b/src/core/hle/service/ir/ir_user.cpp @@ -7,6 +7,7 @@ #include <boost/optional.hpp> #include "common/string_util.h" #include "common/swap.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/ir/extra_hid.h" @@ -267,8 +268,7 @@ static void InitializeIrNopShared(Interface* self) { shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle); if (!shared_memory) { LOG_CRITICAL(Service_IR, "invalid shared memory handle 0x%08X", handle); - rb.Push(ResultCode(ErrorDescription::InvalidHandle, ErrorModule::OS, - ErrorSummary::WrongArgument, ErrorLevel::Permanent)); + rb.Push(IPC::ERR_INVALID_HANDLE); return; } shared_memory->name = "IR_USER: shared memory"; diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp index d1e6d869f..7255ea026 100644 --- a/src/core/hle/service/ldr_ro/ldr_ro.cpp +++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp @@ -7,6 +7,7 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/service/ldr_ro/cro_helper.h" diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp index e98388560..35212b59b 100644 --- a/src/core/hle/service/mic_u.cpp +++ b/src/core/hle/service/mic_u.cpp @@ -3,7 +3,9 @@ // Refer to the license.txt file included. #include "common/logging/log.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/mic_u.h" diff --git a/src/core/hle/service/ndm/ndm.cpp b/src/core/hle/service/ndm/ndm.cpp index 5eb97f0d3..096c0cdac 100644 --- a/src/core/hle/service/ndm/ndm.cpp +++ b/src/core/hle/service/ndm/ndm.cpp @@ -2,8 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <array> #include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/ipc.h" #include "core/hle/service/ndm/ndm.h" #include "core/hle/service/ndm/ndm_u.h" #include "core/hle/service/service.h" diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index fd3c7d9c2..b44a9f668 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -2,7 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/ipc.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/handle_table.h" #include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfc/nfc_m.h" #include "core/hle/service/nfc/nfc_u.h" diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 63c334cb2..d5624fe54 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -4,6 +4,7 @@ #include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/ipc.h" #include "core/hle/service/nim/nim.h" #include "core/hle/service/nim/nim_aoc.h" #include "core/hle/service/nim/nim_s.h" diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 581816e81..6c4600f25 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -9,6 +9,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core_timing.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/result.h" @@ -422,6 +423,102 @@ static void SetApplicationData(Interface* self) { rb.Push(RESULT_SUCCESS); } +/** + * NWM_UDS::DecryptBeaconData service function. + * Decrypts the encrypted data tags contained in the 802.11 beacons. + * Inputs: + * 1 : Input network struct buffer descriptor. + * 2 : Input network struct buffer ptr. + * 3 : Input tag0 encrypted buffer descriptor. + * 4 : Input tag0 encrypted buffer ptr. + * 5 : Input tag1 encrypted buffer descriptor. + * 6 : Input tag1 encrypted buffer ptr. + * 64 : Output buffer descriptor. + * 65 : Output buffer ptr. + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void DecryptBeaconData(Interface* self) { + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 0, 6); + + size_t desc_size; + const VAddr network_struct_addr = rp.PopStaticBuffer(&desc_size); + ASSERT(desc_size == sizeof(NetworkInfo)); + + size_t data0_size; + const VAddr encrypted_data0_addr = rp.PopStaticBuffer(&data0_size); + + size_t data1_size; + const VAddr encrypted_data1_addr = rp.PopStaticBuffer(&data1_size); + + size_t output_buffer_size; + const VAddr output_buffer_addr = rp.PeekStaticBuffer(0, &output_buffer_size); + + // This size is hardcoded in the 3DS UDS code. + ASSERT(output_buffer_size == sizeof(NodeInfo) * UDSMaxNodes); + + LOG_WARNING(Service_NWM, "called in0=%08X in1=%08X out=%08X", encrypted_data0_addr, + encrypted_data1_addr, output_buffer_addr); + + NetworkInfo net_info; + Memory::ReadBlock(network_struct_addr, &net_info, sizeof(net_info)); + + // Read the encrypted data. + // The first 4 bytes should be the OUI and the OUI Type of the tags. + std::array<u8, 3> oui; + Memory::ReadBlock(encrypted_data0_addr, oui.data(), oui.size()); + ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI"); + Memory::ReadBlock(encrypted_data1_addr, oui.data(), oui.size()); + ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI"); + + ASSERT_MSG(Memory::Read8(encrypted_data0_addr + 3) == + static_cast<u8>(NintendoTagId::EncryptedData0), + "Unexpected tag id"); + ASSERT_MSG(Memory::Read8(encrypted_data1_addr + 3) == + static_cast<u8>(NintendoTagId::EncryptedData1), + "Unexpected tag id"); + + std::vector<u8> beacon_data(data0_size + data1_size); + Memory::ReadBlock(encrypted_data0_addr + 4, beacon_data.data(), data0_size); + Memory::ReadBlock(encrypted_data1_addr + 4, beacon_data.data() + data0_size, data1_size); + + // Decrypt the data + DecryptBeaconData(net_info, beacon_data); + + // The beacon data header contains the MD5 hash of the data. + BeaconData beacon_header; + std::memcpy(&beacon_header, beacon_data.data(), sizeof(beacon_header)); + + // TODO(Subv): Verify the MD5 hash of the data and return 0xE1211005 if invalid. + + u8 num_nodes = net_info.max_nodes; + + std::vector<NodeInfo> nodes; + + for (int i = 0; i < num_nodes; ++i) { + BeaconNodeInfo info; + std::memcpy(&info, beacon_data.data() + sizeof(beacon_header) + i * sizeof(info), + sizeof(info)); + + // Deserialize the node information. + NodeInfo node{}; + node.friend_code_seed = info.friend_code_seed; + node.network_node_id = info.network_node_id; + for (int i = 0; i < info.username.size(); ++i) + node.username[i] = info.username[i]; + + nodes.push_back(node); + } + + Memory::ZeroBlock(output_buffer_addr, sizeof(NodeInfo) * UDSMaxNodes); + Memory::WriteBlock(output_buffer_addr, nodes.data(), sizeof(NodeInfo) * nodes.size()); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.PushStaticBuffer(output_buffer_addr, output_buffer_size, 0); + rb.Push(RESULT_SUCCESS); +} + // Sends a 802.11 beacon frame with information about the current network. static void BeaconBroadcastCallback(u64 userdata, int cycles_late) { // Don't do anything if we're not actually hosting a network @@ -462,7 +559,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x001B0302, InitializeWithVersion, "InitializeWithVersion"}, {0x001D0044, BeginHostingNetwork, "BeginHostingNetwork"}, {0x001E0084, nullptr, "ConnectToNetwork"}, - {0x001F0006, nullptr, "DecryptBeaconData"}, + {0x001F0006, DecryptBeaconData, "DecryptBeaconData"}, {0x00200040, nullptr, "Flush"}, {0x00210080, nullptr, "SetProbeResponseParam"}, {0x00220402, nullptr, "ScanOnConnection"}, diff --git a/src/core/hle/service/nwm/uds_beacon.cpp b/src/core/hle/service/nwm/uds_beacon.cpp index c6e5bc5f1..6332b404c 100644 --- a/src/core/hle/service/nwm/uds_beacon.cpp +++ b/src/core/hle/service/nwm/uds_beacon.cpp @@ -3,14 +3,13 @@ // Refer to the license.txt file included. #include <cstring> - -#include "core/hle/service/nwm/nwm_uds.h" -#include "core/hle/service/nwm/uds_beacon.h" - #include <cryptopp/aes.h> #include <cryptopp/md5.h> #include <cryptopp/modes.h> #include <cryptopp/sha.h> +#include "common/assert.h" +#include "core/hle/service/nwm/nwm_uds.h" +#include "core/hle/service/nwm/uds_beacon.h" namespace Service { namespace NWM { diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 319e8c946..39382ef09 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/logging/log.h" +#include "core/file_sys/errors.h" #include "core/file_sys/file_backend.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/ptm/ptm.h" @@ -134,7 +135,7 @@ void Init() { 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) { + if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { // Format the archive to create the directories Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, FileSys::ArchiveFormatInfo(), archive_path); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 0672ac2e3..d34968428 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -2,11 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <boost/range/algorithm_ext/erase.hpp> - +#include <fmt/format.h> #include "common/logging/log.h" #include "common/string_util.h" +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/service/ac/ac.h" #include "core/hle/service/act/act.h" #include "core/hle/service/am/am.h" @@ -39,15 +40,20 @@ #include "core/hle/service/ptm/ptm.h" #include "core/hle/service/qtm/qtm.h" #include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/sm/srv.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" +using Kernel::ClientPort; +using Kernel::ServerPort; +using Kernel::ServerSession; +using Kernel::SharedPtr; + namespace Service { -std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; -std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; +std::unordered_map<std::string, SharedPtr<ClientPort>> g_kernel_named_ports; /** * Creates a function string for logging, complete with the name (or header code, depending @@ -66,20 +72,10 @@ static std::string MakeFunctionString(const char* name, const char* port_name, return function_string; } -void SessionRequestHandler::ClientConnected( - Kernel::SharedPtr<Kernel::ServerSession> server_session) { - connected_sessions.push_back(server_session); -} - -void SessionRequestHandler::ClientDisconnected( - Kernel::SharedPtr<Kernel::ServerSession> server_session) { - boost::range::remove_erase(connected_sessions, server_session); -} - Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} Interface::~Interface() = default; -void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { +void Interface::HandleSyncRequest(SharedPtr<ServerSession> server_session) { // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which // session triggered each command. @@ -113,27 +109,106 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { } //////////////////////////////////////////////////////////////////////////////////////////////////// + +ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions, + InvokerFn* handler_invoker) + : service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {} + +ServiceFrameworkBase::~ServiceFrameworkBase() = default; + +void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { + ASSERT(port == nullptr); + port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); + port->SetHleHandler(shared_from_this()); +} + +void ServiceFrameworkBase::InstallAsNamedPort() { + ASSERT(port == nullptr); + SharedPtr<ServerPort> server_port; + SharedPtr<ClientPort> client_port; + std::tie(server_port, client_port) = ServerPort::CreatePortPair(max_sessions, service_name); + server_port->SetHleHandler(shared_from_this()); + AddNamedPort(service_name, std::move(client_port)); +} + +void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, size_t n) { + handlers.reserve(handlers.size() + n); + for (size_t i = 0; i < n; ++i) { + // Usually this array is sorted by id already, so hint to insert at the end + handlers.emplace_hint(handlers.cend(), functions[i].expected_header, functions[i]); + } +} + +void ServiceFrameworkBase::ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info) { + IPC::Header header{cmd_buf[0]}; + int num_params = header.normal_params_size + header.translate_params_size; + std::string function_name = info == nullptr ? fmt::format("{:#08x}", cmd_buf[0]) : info->name; + + fmt::MemoryWriter w; + w.write("function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name, + cmd_buf[0]); + for (int i = 1; i <= num_params; ++i) { + w.write(", [{}]={:#x}", i, cmd_buf[i]); + } + w << '}'; + + LOG_ERROR(Service, "unknown / unimplemented %s", w.c_str()); + // TODO(bunnei): Hack - ignore error + cmd_buf[1] = 0; +} + +void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_session) { + u32* cmd_buf = Kernel::GetCommandBuffer(); + + // TODO(yuriks): The kernel should be the one handling this as part of translation after + // everything else is migrated + Kernel::HLERequestContext context; + context.cmd_buf = cmd_buf; + context.session = std::move(server_session); + + u32 header_code = cmd_buf[0]; + auto itr = handlers.find(header_code); + const FunctionInfoBase* info = itr == handlers.end() ? nullptr : &itr->second; + if (info == nullptr || info->handler_callback == nullptr) { + return ReportUnimplementedFunction(cmd_buf, info); + } + + LOG_TRACE(Service, "%s", + MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf).c_str()); + handler_invoker(this, info->handler_callback, context); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// // Module interface +// TODO(yuriks): Move to kernel +void AddNamedPort(std::string name, SharedPtr<ClientPort> port) { + g_kernel_named_ports.emplace(std::move(name), std::move(port)); +} + static void AddNamedPort(Interface* interface_) { - auto ports = - Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), - std::shared_ptr<Interface>(interface_)); - auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); - g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); + SharedPtr<ServerPort> server_port; + SharedPtr<ClientPort> client_port; + std::tie(server_port, client_port) = + ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); + + server_port->SetHleHandler(std::shared_ptr<Interface>(interface_)); + AddNamedPort(interface_->GetPortName(), std::move(client_port)); } void AddService(Interface* interface_) { - auto ports = - Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), - std::shared_ptr<Interface>(interface_)); - auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); - g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); + auto server_port = + SM::g_service_manager + ->RegisterService(interface_->GetPortName(), interface_->GetMaxSessions()) + .MoveFrom(); + server_port->SetHleHandler(std::shared_ptr<Interface>(interface_)); } /// Initialize ServiceManager void Init() { - AddNamedPort(new SRV::SRV); + SM::g_service_manager = std::make_shared<SM::ServiceManager>(); + SM::ServiceManager::InstallInterfaces(SM::g_service_manager); + AddNamedPort(new ERR::ERR_F); FS::ArchiveInit(); @@ -194,7 +269,7 @@ void Shutdown() { AC::Shutdown(); FS::ArchiveShutdown(); - g_srv_services.clear(); + SM::g_service_manager = nullptr; 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 e6a5f1417..281ff99bb 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -8,70 +8,38 @@ #include <string> #include <unordered_map> #include <boost/container/flat_map.hpp> +#include "common/bit_field.h" #include "common/common_types.h" -#include "core/hle/ipc.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/result.h" -#include "core/memory.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/kernel.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace Service namespace Kernel { +class ClientPort; +class ServerPort; class ServerSession; } -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace Service - namespace Service { +namespace SM { +class ServiceManager; +} + static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) /// Arbitrary default number of maximum connections to an HLE service. static const u32 DefaultMaxSessions = 10; /** - * Interface implemented by HLE Session handlers. - * This can be provided to a ServerSession in order to hook into several relevant events - * (such as a new connection or a SyncRequest) so they can be implemented in the emulator. - */ -class SessionRequestHandler { -public: - /** - * Handles a sync request from the emulated application. - * @param server_session The ServerSession that was triggered for this sync request, - * it should be used to differentiate which client (As in ClientSession) we're answering to. - * TODO(Subv): Use a wrapper structure to hold all the information relevant to - * this request (ServerSession, Originator thread, Translated command buffer, etc). - * @returns ResultCode the result code of the translate operation. - */ - virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0; - - /** - * Signals that a client has just connected to this HLE handler and keeps the - * associated ServerSession alive for the duration of the connection. - * @param server_session Owning pointer to the ServerSession associated with the connection. - */ - void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); - - /** - * Signals that a client has just disconnected from this HLE handler and releases the - * associated ServerSession. - * @param server_session ServerSession associated with the connection. - */ - void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); - -protected: - /// List of sessions that are connected to this handler. - /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list - // for the duration of the connection. - std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions; -}; - -/** * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a * table mapping header ids to handler functions. + * + * @deprecated Use ServiceFramework for new services instead. It allows services to be stateful and + * is more extensible going forward. */ -class Interface : public SessionRequestHandler { +class Interface : public Kernel::SessionRequestHandler { public: /** * Creates an HLE interface with the specified max sessions. @@ -141,6 +109,146 @@ private: boost::container::flat_map<u32, FunctionInfo> m_functions; }; +/** + * This is an non-templated base of ServiceFramework to reduce code bloat and compilation times, it + * is not meant to be used directly. + * + * @see ServiceFramework + */ +class ServiceFrameworkBase : public Kernel::SessionRequestHandler { +public: + /// Returns the string identifier used to connect to the service. + std::string GetServiceName() const { + return service_name; + } + + /** + * Returns the maximum number of sessions that can be connected to this service at the same + * time. + */ + u32 GetMaxSessions() const { + return max_sessions; + } + + /// Creates a port pair and registers this service with the given ServiceManager. + void InstallAsService(SM::ServiceManager& service_manager); + /// Creates a port pair and registers it on the kernel's global port registry. + void InstallAsNamedPort(); + + void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; + +protected: + /// Member-function pointer type of SyncRequest handlers. + template <typename Self> + using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); + +private: + template <typename T> + friend class ServiceFramework; + + struct FunctionInfoBase { + u32 expected_header; + HandlerFnP<ServiceFrameworkBase> handler_callback; + const char* name; + }; + + using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, + Kernel::HLERequestContext& ctx); + + ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker); + ~ServiceFrameworkBase(); + + void RegisterHandlersBase(const FunctionInfoBase* functions, size_t n); + void ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info); + + /// Identifier string used to connect to the service. + std::string service_name; + /// Maximum number of concurrent sessions that this service can handle. + u32 max_sessions; + + /** + * Port where incoming connections will be received. Only created when InstallAsService() or + * InstallAsNamedPort() are called. + */ + Kernel::SharedPtr<Kernel::ServerPort> port; + + /// Function used to safely up-cast pointers to the derived class before invoking a handler. + InvokerFn* handler_invoker; + boost::container::flat_map<u32, FunctionInfoBase> handlers; +}; + +/** + * Framework for implementing HLE services. Dispatches on the header id of incoming SyncRequests + * based on a table mapping header ids to handler functions. Service implementations should inherit + * from ServiceFramework using the CRTP (`class Foo : public ServiceFramework<Foo> { ... };`) and + * populate it with handlers by calling #RegisterHandlers. + * + * In order to avoid duplicating code in the binary and exposing too many implementation details in + * the header, this class is split into a non-templated base (ServiceFrameworkBase) and a template + * deriving from it (ServiceFramework). The functions in this class will mostly only erase the type + * of the passed in function pointers and then delegate the actual work to the implementation in the + * base class. + */ +template <typename Self> +class ServiceFramework : public ServiceFrameworkBase { +protected: + /// Contains information about a request type which is handled by the service. + struct FunctionInfo : FunctionInfoBase { + // TODO(yuriks): This function could be constexpr, but clang is the only compiler that + // doesn't emit an ICE or a wrong diagnostic because of the static_cast. + + /** + * Constructs a FunctionInfo for a function. + * + * @param expected_header request header in the command buffer which will trigger dispatch + * to this handler + * @param handler_callback member function in this service which will be called to handle + * the request + * @param name human-friendly name for the request. Used mostly for logging purposes. + */ + FunctionInfo(u32 expected_header, HandlerFnP<Self> handler_callback, const char* name) + : FunctionInfoBase{ + expected_header, + // Type-erase member function pointer by casting it down to the base class. + static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback), name} {} + }; + + /** + * Initializes the handler with no functions installed. + * @param max_sessions Maximum number of sessions that can be + * connected to this service at the same time. + */ + ServiceFramework(const char* service_name, u32 max_sessions = DefaultMaxSessions) + : ServiceFrameworkBase(service_name, max_sessions, Invoker) {} + + /// Registers handlers in the service. + template <size_t N> + void RegisterHandlers(const FunctionInfo (&functions)[N]) { + RegisterHandlers(functions, N); + } + + /** + * Registers handlers in the service. Usually prefer using the other RegisterHandlers + * overload in order to avoid needing to specify the array size. + */ + void RegisterHandlers(const FunctionInfo* functions, size_t n) { + RegisterHandlersBase(functions, n); + } + +private: + /** + * This function is used to allow invocation of pointers to handlers stored in the base class + * without needing to expose the type of this derived class. Pointers-to-member may require a + * fixup when being up or downcast, and thus code that does that needs to know the concrete type + * of the derived class in order to invoke one of it's functions through a pointer. + */ + static void Invoker(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, + Kernel::HLERequestContext& ctx) { + // Cast back up to our original types and call the member function + (static_cast<Self*>(object)->*static_cast<HandlerFnP<Self>>(member))(ctx); + } +}; + /// Initialize ServiceManager void Init(); @@ -149,9 +257,9 @@ void Shutdown(); /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; -/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. -extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; +/// Adds a port to the named port table +void AddNamedPort(std::string name, Kernel::SharedPtr<Kernel::ClientPort> port); /// Adds a service to the services table void AddService(Interface* interface_); diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp new file mode 100644 index 000000000..5e7fc68f9 --- /dev/null +++ b/src/core/hle/service/sm/sm.cpp @@ -0,0 +1,69 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <tuple> +#include "common/assert.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_port.h" +#include "core/hle/result.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/sm/srv.h" + +namespace Service { +namespace SM { + +static ResultCode ValidateServiceName(const std::string& name) { + if (name.size() <= 0 || name.size() > 8) { + return ERR_INVALID_NAME_SIZE; + } + if (name.find('\0') != std::string::npos) { + return ERR_NAME_CONTAINS_NUL; + } + return RESULT_SUCCESS; +} + +void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self) { + ASSERT(self->srv_interface.expired()); + + auto srv = std::make_shared<SRV>(self); + srv->InstallAsNamedPort(); + self->srv_interface = srv; +} + +ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService( + std::string name, unsigned int max_sessions) { + + CASCADE_CODE(ValidateServiceName(name)); + Kernel::SharedPtr<Kernel::ServerPort> server_port; + Kernel::SharedPtr<Kernel::ClientPort> client_port; + std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name); + + registered_services.emplace(std::move(name), std::move(client_port)); + return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); +} + +ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( + const std::string& name) { + + CASCADE_CODE(ValidateServiceName(name)); + auto it = registered_services.find(name); + if (it == registered_services.end()) { + return ERR_SERVICE_NOT_REGISTERED; + } + + return MakeResult<Kernel::SharedPtr<Kernel::ClientPort>>(it->second); +} + +ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToService( + const std::string& name) { + + CASCADE_RESULT(auto client_port, GetServicePort(name)); + return client_port->Connect(); +} + +std::shared_ptr<ServiceManager> g_service_manager; + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h new file mode 100644 index 000000000..8f0dbf2db --- /dev/null +++ b/src/core/hle/service/sm/sm.h @@ -0,0 +1,55 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <unordered_map> +#include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class ClientPort; +class ClientSession; +class ServerPort; +class SessionRequestHandler; +} // namespace Kernel + +namespace Service { +namespace SM { + +class SRV; + +constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(1, ErrorModule::SRV, ErrorSummary::WouldBlock, + ErrorLevel::Temporary); // 0xD0406401 +constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(2, ErrorModule::SRV, ErrorSummary::WouldBlock, + ErrorLevel::Temporary); // 0xD0406402 +constexpr ResultCode ERR_INVALID_NAME_SIZE(5, ErrorModule::SRV, ErrorSummary::WrongArgument, + ErrorLevel::Permanent); // 0xD9006405 +constexpr ResultCode ERR_ACCESS_DENIED(6, ErrorModule::SRV, ErrorSummary::InvalidArgument, + ErrorLevel::Permanent); // 0xD8E06406 +constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::WrongArgument, + ErrorLevel::Permanent); // 0xD9006407 + +class ServiceManager { +public: + static void InstallInterfaces(std::shared_ptr<ServiceManager> self); + + ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, + unsigned int max_sessions); + ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); + ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); + +private: + std::weak_ptr<SRV> srv_interface; + + /// Map of registered services, retrieved using GetServicePort or ConnectToService. + std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services; +}; + +extern std::shared_ptr<ServiceManager> g_service_manager; + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp new file mode 100644 index 000000000..b8b62b068 --- /dev/null +++ b/src/core/hle/service/sm/srv.cpp @@ -0,0 +1,204 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <tuple> + +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/hle/ipc.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/semaphore.h" +#include "core/hle/kernel/server_session.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/sm/srv.h" + +namespace Service { +namespace SM { + +constexpr int MAX_PENDING_NOTIFICATIONS = 16; + +/** + * SRV::RegisterClient service function + * Inputs: + * 0: 0x00010002 + * 1: ProcessId Header (must be 0x20) + * Outputs: + * 0: 0x00010040 + * 1: ResultCode + */ +void SRV::RegisterClient(Kernel::HLERequestContext& ctx) { + u32* cmd_buff = ctx.CommandBuffer(); + + if (cmd_buff[1] != IPC::CallingPidDesc()) { + cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); // 0x40 + cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; + return; + } + cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); // 0x10040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called"); +} + +/** + * SRV::EnableNotification service function + * Inputs: + * 0: 0x00020000 + * Outputs: + * 0: 0x00020042 + * 1: ResultCode + * 2: Translation descriptor: 0x20 + * 3: Handle to semaphore signaled on process notification + */ +void SRV::EnableNotification(Kernel::HLERequestContext& ctx) { + u32* cmd_buff = ctx.CommandBuffer(); + + notification_semaphore = + Kernel::Semaphore::Create(0, MAX_PENDING_NOTIFICATIONS, "SRV:Notification").Unwrap(); + + cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = IPC::CopyHandleDesc(1); + cmd_buff[3] = Kernel::g_handle_table.Create(notification_semaphore).MoveFrom(); + LOG_WARNING(Service_SRV, "(STUBBED) called"); +} + +/** + * SRV::GetServiceHandle service function + * Inputs: + * 0: 0x00050100 + * 1-2: 8-byte UTF-8 service name + * 3: Name length + * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable) + * Outputs: + * 1: ResultCode + * 3: Service handle + */ +void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) { + ResultCode res = RESULT_SUCCESS; + u32* cmd_buff = ctx.CommandBuffer(); + + size_t name_len = cmd_buff[3]; + if (name_len > Service::kMaxPortSize) { + cmd_buff[1] = ERR_INVALID_NAME_SIZE.raw; + LOG_ERROR(Service_SRV, "called name_len=0x%X, failed with code=0x%08X", name_len, + cmd_buff[1]); + return; + } + std::string name(reinterpret_cast<const char*>(&cmd_buff[1]), name_len); + bool return_port_on_failure = (cmd_buff[4] & 1) == 0; + + // TODO(yuriks): Permission checks go here + + auto client_port = service_manager->GetServicePort(name); + if (client_port.Failed()) { + cmd_buff[1] = client_port.Code().raw; + LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(), + cmd_buff[1]); + return; + } + + auto session = client_port.Unwrap()->Connect(); + cmd_buff[1] = session.Code().raw; + if (session.Succeeded()) { + cmd_buff[3] = Kernel::g_handle_table.Create(session.MoveFrom()).MoveFrom(); + LOG_DEBUG(Service_SRV, "called service=%s, session handle=0x%08X", name.c_str(), + cmd_buff[3]); + } else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED && return_port_on_failure) { + cmd_buff[1] = ERR_MAX_CONNECTIONS_REACHED.raw; + cmd_buff[3] = Kernel::g_handle_table.Create(client_port.MoveFrom()).MoveFrom(); + LOG_WARNING(Service_SRV, "called service=%s, *port* handle=0x%08X", name.c_str(), + cmd_buff[3]); + } else { + LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(), + cmd_buff[1]); + } +} + +/** + * SRV::Subscribe service function + * Inputs: + * 0: 0x00090040 + * 1: Notification ID + * Outputs: + * 0: 0x00090040 + * 1: ResultCode + */ +void SRV::Subscribe(Kernel::HLERequestContext& ctx) { + u32* cmd_buff = ctx.CommandBuffer(); + + u32 notification_id = cmd_buff[1]; + + cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); +} + +/** + * SRV::Unsubscribe service function + * Inputs: + * 0: 0x000A0040 + * 1: Notification ID + * Outputs: + * 0: 0x000A0040 + * 1: ResultCode + */ +void SRV::Unsubscribe(Kernel::HLERequestContext& ctx) { + u32* cmd_buff = ctx.CommandBuffer(); + + u32 notification_id = cmd_buff[1]; + + cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); +} + +/** + * SRV::PublishToSubscriber service function + * Inputs: + * 0: 0x000C0080 + * 1: Notification ID + * 2: Flags (bit0: only fire if not fired, bit1: report errors) + * Outputs: + * 0: 0x000C0040 + * 1: ResultCode + */ +void SRV::PublishToSubscriber(Kernel::HLERequestContext& ctx) { + u32* cmd_buff = ctx.CommandBuffer(); + + u32 notification_id = cmd_buff[1]; + u8 flags = cmd_buff[2] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, + flags); +} + +SRV::SRV(std::shared_ptr<ServiceManager> service_manager) + : ServiceFramework("srv:", 4), service_manager(std::move(service_manager)) { + static const FunctionInfo functions[] = { + {0x00010002, &SRV::RegisterClient, "RegisterClient"}, + {0x00020000, &SRV::EnableNotification, "EnableNotification"}, + {0x00030100, nullptr, "RegisterService"}, + {0x000400C0, nullptr, "UnregisterService"}, + {0x00050100, &SRV::GetServiceHandle, "GetServiceHandle"}, + {0x000600C2, nullptr, "RegisterPort"}, + {0x000700C0, nullptr, "UnregisterPort"}, + {0x00080100, nullptr, "GetPort"}, + {0x00090040, &SRV::Subscribe, "Subscribe"}, + {0x000A0040, &SRV::Unsubscribe, "Unsubscribe"}, + {0x000B0000, nullptr, "ReceiveNotification"}, + {0x000C0080, &SRV::PublishToSubscriber, "PublishToSubscriber"}, + {0x000D0040, nullptr, "PublishAndGetSubscriber"}, + {0x000E00C0, nullptr, "IsServiceRegistered"}, + }; + RegisterHandlers(functions); +} + +SRV::~SRV() = default; + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h new file mode 100644 index 000000000..75cca5184 --- /dev/null +++ b/src/core/hle/service/sm/srv.h @@ -0,0 +1,37 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +class Semaphore; +} + +namespace Service { +namespace SM { + +/// Interface to "srv:" service +class SRV final : public ServiceFramework<SRV> { +public: + explicit SRV(std::shared_ptr<ServiceManager> service_manager); + ~SRV(); + +private: + void RegisterClient(Kernel::HLERequestContext& ctx); + void EnableNotification(Kernel::HLERequestContext& ctx); + void GetServiceHandle(Kernel::HLERequestContext& ctx); + void Subscribe(Kernel::HLERequestContext& ctx); + void Unsubscribe(Kernel::HLERequestContext& ctx); + void PublishToSubscriber(Kernel::HLERequestContext& ctx); + + std::shared_ptr<ServiceManager> service_manager; + Kernel::SharedPtr<Kernel::Semaphore> notification_semaphore; +}; + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 530614e6f..3d215d42d 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -11,6 +11,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/scope_exit.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/server_session.h" #include "core/hle/result.h" #include "core/hle/service/soc_u.h" diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp deleted file mode 100644 index 3bd787147..000000000 --- a/src/core/hle/service/srv.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <tuple> - -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/service/srv.h" - -namespace Service { -namespace SRV { - -static Kernel::SharedPtr<Kernel::Event> event_handle; - -/** - * SRV::RegisterClient service function - * Inputs: - * 0: 0x00010002 - * 1: ProcessId Header (must be 0x20) - * Outputs: - * 0: 0x00010040 - * 1: ResultCode - */ -static void RegisterClient(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - if (cmd_buff[1] != IPC::CallingPidDesc()) { - cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); // 0x40 - cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, - ErrorSummary::WrongArgument, ErrorLevel::Permanent) - .raw; - return; - } - cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); // 0x10040 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called"); -} - -/** - * SRV::EnableNotification service function - * Inputs: - * 0: 0x00020000 - * Outputs: - * 0: 0x00020042 - * 1: ResultCode - * 2: Translation descriptor: 0x20 - * 3: Handle to semaphore signaled on process notification - */ -static void EnableNotification(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(bunnei): Change to a semaphore once these have been implemented - event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); - event_handle->Clear(); - - cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = IPC::CopyHandleDesc(1); - cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); - LOG_WARNING(Service_SRV, "(STUBBED) called"); -} - -/** - * SRV::GetServiceHandle service function - * Inputs: - * 0: 0x00050100 - * 1-2: 8-byte UTF-8 service name - * 3: Name length - * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable) - * Outputs: - * 1: ResultCode - * 3: Service handle - */ -static void GetServiceHandle(Interface* self) { - ResultCode res = RESULT_SUCCESS; - u32* cmd_buff = Kernel::GetCommandBuffer(); - - std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); - auto it = Service::g_srv_services.find(port_name); - - if (it != Service::g_srv_services.end()) { - auto client_port = it->second; - - auto client_session = client_port->Connect(); - res = client_session.Code(); - - if (client_session.Succeeded()) { - // Return the client session - cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); - } - LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); - } else { - LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); - res = UnimplementedFunction(ErrorModule::SRV); - } - cmd_buff[1] = res.raw; -} - -/** - * SRV::Subscribe service function - * Inputs: - * 0: 0x00090040 - * 1: Notification ID - * Outputs: - * 0: 0x00090040 - * 1: ResultCode - */ -static void Subscribe(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - u32 notification_id = cmd_buff[1]; - - cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); -} - -/** - * SRV::Unsubscribe service function - * Inputs: - * 0: 0x000A0040 - * 1: Notification ID - * Outputs: - * 0: 0x000A0040 - * 1: ResultCode - */ -static void Unsubscribe(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - u32 notification_id = cmd_buff[1]; - - cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); -} - -/** - * SRV::PublishToSubscriber service function - * Inputs: - * 0: 0x000C0080 - * 1: Notification ID - * 2: Flags (bit0: only fire if not fired, bit1: report errors) - * Outputs: - * 0: 0x000C0040 - * 1: ResultCode - */ -static void PublishToSubscriber(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - u32 notification_id = cmd_buff[1]; - u8 flags = cmd_buff[2] & 0xFF; - - cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, - flags); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010002, RegisterClient, "RegisterClient"}, - {0x00020000, EnableNotification, "EnableNotification"}, - {0x00030100, nullptr, "RegisterService"}, - {0x000400C0, nullptr, "UnregisterService"}, - {0x00050100, GetServiceHandle, "GetServiceHandle"}, - {0x000600C2, nullptr, "RegisterPort"}, - {0x000700C0, nullptr, "UnregisterPort"}, - {0x00080100, nullptr, "GetPort"}, - {0x00090040, Subscribe, "Subscribe"}, - {0x000A0040, Unsubscribe, "Unsubscribe"}, - {0x000B0000, nullptr, "ReceiveNotification"}, - {0x000C0080, PublishToSubscriber, "PublishToSubscriber"}, - {0x000D0040, nullptr, "PublishAndGetSubscriber"}, - {0x000E00C0, nullptr, "IsServiceRegistered"}, -}; - -SRV::SRV() { - Register(FunctionTable); - event_handle = nullptr; -} - -SRV::~SRV() { - event_handle = nullptr; -} - -} // namespace SRV -} // namespace Service diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h deleted file mode 100644 index d3a9de879..000000000 --- a/src/core/hle/service/srv.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -namespace Service { -namespace SRV { - -/// Interface to "srv:" service -class SRV final : public Interface { -public: - SRV(); - ~SRV() override; - - std::string GetPortName() const override { - return "srv:"; - } -}; - -} // namespace SRV -} // namespace Service diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp index 09ced9d7a..300acca75 100644 --- a/src/core/hle/service/ssl_c.cpp +++ b/src/core/hle/service/ssl_c.cpp @@ -4,7 +4,9 @@ #include <random> #include "common/common_types.h" +#include "core/hle/ipc.h" #include "core/hle/service/ssl_c.h" +#include "core/memory.h" namespace Service { namespace SSL { diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index c0837d49d..bb7bf2d67 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -6,6 +6,8 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/ipc.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/y2r_u.h" |
