From 5dacf92fd73a9abe721a6525dda633d7b0c6133c Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Thu, 26 Jul 2018 00:54:11 -0400 Subject: [PATCH 01/21] service/cecd: Stub some functions --- src/core/hle/service/cecd/cecd.cpp | 194 ++++++++++++++++ src/core/hle/service/cecd/cecd.h | 321 +++++++++++++++++++++++++-- src/core/hle/service/cecd/cecd_s.cpp | 24 +- src/core/hle/service/cecd/cecd_u.cpp | 24 +- 4 files changed, 528 insertions(+), 35 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index c7bb8c1aa..dcf9a8832 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -13,6 +13,162 @@ namespace Service { namespace CECD { +void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x01, 3, 2); + const u32 ncch_program_id = rp.Pop(); + const u32 path_type = rp.Pop(); + const u32 file_open_flag = rp.Pop(); + rp.PopPID(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(0); /// File size? + + LOG_WARNING(Service_CECD, + "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " + "file_open_flag={:#010x}", + ncch_program_id, path_type, file_open_flag); +} + +void Module::Interface::ReadRawFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x02, 1, 2); + const u32 buffer_size = rp.Pop(); + auto buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + rb.Push(RESULT_SUCCESS); + rb.Push(0); /// Read size + rb.PushStaticBuffer(buffer, 0); + + LOG_WARNING(Service_CECD, "(STUBBED) called, buffer_size={:#010x}", buffer_size); +} + +void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x03, 4, 4); + const u32 ncch_program_id = rp.Pop(); + const bool is_out_box = rp.Pop(); + const u32 message_id_size = rp.Pop(); + const u32 buffer_size = rp.Pop(); + const auto message_id_buffer = rp.PopStaticBuffer(); + auto write_buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 4); + rb.Push(RESULT_SUCCESS); + rb.Push(0); /// Read size + rb.PushStaticBuffer(message_id_buffer, 0); + rb.PushStaticBuffer(write_buffer, 1); + + LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", + ncch_program_id, is_out_box); +} + +void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x04, 4, 6); + const u32 ncch_program_id = rp.Pop(); + const bool is_out_box = rp.Pop(); + const u32 message_id_size = rp.Pop(); + const u32 buffer_size = rp.Pop(); + const auto message_id_buffer = rp.PopStaticBuffer(); + const auto hmac_key_buffer = rp.PopStaticBuffer(); + auto write_buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 6); + rb.Push(RESULT_SUCCESS); + rb.Push(0); /// Read size + rb.PushStaticBuffer(message_id_buffer, 0); + rb.PushStaticBuffer(hmac_key_buffer, 1); + rb.PushStaticBuffer(write_buffer, 2); + + LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", + ncch_program_id, is_out_box); +} + +void Module::Interface::WriteRawFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x05, 1, 2); + const u32 buffer_size = rp.Pop(); + const auto buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(buffer, 0); + + LOG_WARNING(Service_CECD, "(STUBBED) called, buffer_size={:#010x}", buffer_size); +} + +void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x06, 4, 4); + const u32 ncch_program_id = rp.Pop(); + const bool is_out_box = rp.Pop(); + const u32 message_id_size = rp.Pop(); + const u32 buffer_size = rp.Pop(); + const auto read_buffer = rp.PopStaticBuffer(); + auto message_id_buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(read_buffer, 0); + rb.PushStaticBuffer(message_id_buffer, 1); + + LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", + ncch_program_id, is_out_box); +} + +void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x07, 4, 6); + const u32 ncch_program_id = rp.Pop(); + const bool is_out_box = rp.Pop(); + const u32 message_id_size = rp.Pop(); + const u32 buffer_size = rp.Pop(); + const auto read_buffer = rp.PopStaticBuffer(); + const auto hmac_key_buffer = rp.PopStaticBuffer(); + auto message_id_buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 6); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(read_buffer, 0); + rb.PushStaticBuffer(hmac_key_buffer, 1); + rb.PushStaticBuffer(message_id_buffer, 2); + + LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", + ncch_program_id, is_out_box); +} + +void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x10, 4, 2); + const u32 ncch_program_id = rp.Pop(); + const u32 path_type = rp.Pop(); + const bool is_out_box = rp.Pop(); + const u32 message_id_size = rp.Pop(); + const auto message_id_buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(message_id_buffer, 0); + + LOG_WARNING(Service_CECD, + "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, is_out_box={}", + ncch_program_id, path_type, is_out_box); +} + +void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x10, 3, 4); + const u32 dest_buffer_size = rp.Pop(); + const u32 info_type = rp.Pop(); + const u32 param_buffer_size = rp.Pop(); + const auto param_buffer = rp.PopStaticBuffer(); + auto dest_buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(param_buffer, 0); + rb.PushStaticBuffer(dest_buffer, 1); + + LOG_WARNING(Service_CECD, + "(STUBBED) called, dest_buffer_size={:#010x}, info_type={:#010x}, " + "param_buffer_size={:#010x}", + dest_buffer_size, info_type, param_buffer_size); +} + void Module::Interface::GetCecStateAbbreviated(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0E, 0, 0); @@ -43,6 +199,44 @@ void Module::Interface::GetChangeStateEventHandle(Kernel::HLERequestContext& ctx LOG_WARNING(Service_CECD, "(STUBBED) called"); } +void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x11, 4, 4); + const u32 buffer_size = rp.Pop(); + const u32 ncch_program_id = rp.Pop(); + const u32 path_type = rp.Pop(); + const u32 file_open_flag = rp.Pop(); + rp.PopPID(); + const auto read_buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(read_buffer, 0); + + LOG_WARNING(Service_CECD, + "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " + "file_open_flag={:#010x}", + ncch_program_id, path_type, file_open_flag); +} + +void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x12, 4, 4); + const u32 buffer_size = rp.Pop(); + const u32 ncch_program_id = rp.Pop(); + const u32 path_type = rp.Pop(); + const u32 file_open_flag = rp.Pop(); + rp.PopPID(); + auto write_buffer = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(write_buffer, 0); + + LOG_WARNING(Service_CECD, + "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " + "file_open_flag={:#010x}", + ncch_program_id, path_type, file_open_flag); +} + Module::Interface::Interface(std::shared_ptr cecd, const char* name, u32 max_session) : ServiceFramework(name, max_session), cecd(std::move(cecd)) {} diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 9d4f659c1..707cc9ca3 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -10,31 +10,263 @@ namespace Service { namespace CECD { -enum class CecStateAbbreviated : u32 { - CEC_STATE_ABBREV_IDLE = 1, ///< Corresponds to CEC_STATE_IDLE - CEC_STATE_ABBREV_NOT_LOCAL = 2, ///< Corresponds to CEC_STATEs *FINISH*, *POST, and OVER_BOSS - CEC_STATE_ABBREV_SCANNING = 3, ///< Corresponds to CEC_STATE_SCANNING - CEC_STATE_ABBREV_WLREADY = - 4, ///< Corresponds to CEC_STATE_WIRELESS_READY when some unknown bool is true - CEC_STATE_ABBREV_OTHER = 5, ///< Corresponds to CEC_STATEs besides *FINISH*, *POST, and - /// OVER_BOSS and those listed here -}; - class Module final { public: Module(); ~Module() = default; + enum class CecStateAbbreviated : u32 { + CEC_STATE_ABBREV_IDLE = 1, /// Relates to CEC_STATE_IDLE + CEC_STATE_ABBREV_NOT_LOCAL = 2, /// Relates to CEC_STATEs *FINISH*, *POST, and OVER_BOSS + CEC_STATE_ABBREV_SCANNING = 3, /// Relates to CEC_STATE_SCANNING + CEC_STATE_ABBREV_WLREADY = 4, /// Relates to CEC_STATE_WIRELESS_READY when a bool is true + CEC_STATE_ABBREV_OTHER = 5, /// Relates to CEC_STATEs besides *FINISH*, *POST, and + }; /// OVER_BOSS and those listed here + + enum class CecCommand : u32 { + CEC_COMMAND_NONE = 0, + CEC_COMMAND_START = 1, + CEC_COMMAND_RESET_START = 2, + CEC_COMMAND_READYSCAN = 3, + CEC_COMMAND_READYSCANWAIT = 4, + CEC_COMMAND_STARTSCAN = 5, + CEC_COMMAND_RESCAN = 6, + CEC_COMMAND_NDM_RESUME = 7, + CEC_COMMAND_NDM_SUSPEND = 8, + CEC_COMMAND_NDM_SUSPEND_IMMEDIATE = 9, + CEC_COMMAND_STOPWAIT = 0x0A, + CEC_COMMAND_STOP = 0x0B, + CEC_COMMAND_STOP_FORCE = 0x0C, + CEC_COMMAND_STOP_FORCE_WAIT = 0x0D, + CEC_COMMAND_RESET_FILTER = 0x0E, + CEC_COMMAND_DAEMON_STOP = 0x0F, + CEC_COMMAND_DAEMON_START = 0x10, + CEC_COMMAND_EXIT = 0x11, + CEC_COMMAND_OVER_BOSS = 0x12, + CEC_COMMAND_OVER_BOSS_FORCE = 0x13, + CEC_COMMAND_OVER_BOSS_FORCE_WAIT = 0x14, + CEC_COMMAND_END = 0x15, + }; + class Interface : public ServiceFramework { public: Interface(std::shared_ptr cecd, const char* name, u32 max_session); ~Interface() = default; protected: + /** + * CECD::OpenRawFile service function + * Inputs: + * 0 : Header Code[0x000100C2] + * 1 : NCCH Program ID + * 2 : Path type + * 3 : File open flag + * 4 : Descriptor for process ID + * 5 : Placeholder for process ID + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : File size? + */ + void OpenRawFile(Kernel::HLERequestContext& ctx); + + /** + * CECD::ReadRawFile service function + * Inputs: + * 0 : Header Code[0x00020042] + * 1 : Buffer size (unused) + * 2 : Descriptor for mapping a write-only buffer in the target process + * 3 : Buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Read size + * 3 : Descriptor for mapping a write-only buffer in the target process + * 4 : Buffer address + */ + void ReadRawFile(Kernel::HLERequestContext& ctx); + + /** + * CECD::ReadMessage service function + * Inputs: + * 0 : Header Code[0x00030104] + * 1 : NCCH Program ID + * 2 : bool is_out_box? + * 3 : Message ID size (unused, always 8) + * 4 : Buffer size (unused) + * 5 : Descriptor for mapping a read-only buffer in the target process + * 6 : Message ID address + * 7 : Descriptor for mapping a write-only buffer in the target process + * 8 : Buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Read size + * 3 : Descriptor for mapping a read-only buffer in the target process + * 4 : Message ID address + * 5 : Descriptor for mapping a write-only buffer in the target process + * 6 : Buffer address + */ + void ReadMessage(Kernel::HLERequestContext& ctx); + + /** + * CECD::ReadMessageWithHMAC service function + * Inputs: + * 0 : Header Code[0x00040106] + * 1 : NCCH Program ID + * 2 : bool is_out_box? + * 3 : Message ID size(unused, always 8) + * 4 : Buffer size(unused) + * 5 : Descriptor for mapping a read-only buffer in the target process + * 6 : Message ID address + * 7 : Descriptor for mapping a read-only buffer in the target process + * 8 : HMAC key address + * 9 : Descriptor for mapping a write-only buffer in the target process + * 10 : Buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Read size + * 3 : Descriptor for mapping a read-only buffer in the target process + * 4 : Message ID address + * 5 : Descriptor for mapping a read-only buffer in the target process + * 6 : HMAC key address + * 7 : Descriptor for mapping a write-only buffer in the target process + * 8 : Buffer address + */ + void ReadMessageWithHMAC(Kernel::HLERequestContext& ctx); + + /** + * CECD::WriteRawFile service function + * Inputs: + * 0 : Header Code[0x00050042] + * 1 : Buffer size(unused) + * 2 : Descriptor for mapping a read-only buffer in the target process + * 3 : Buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Descriptor for mapping a read-only buffer in the target process + * 3 : Buffer address + */ + void WriteRawFile(Kernel::HLERequestContext& ctx); + + /** + * CECD::WriteMessage service function + * Inputs: + * 0 : Header Code[0x00060104] + * 1 : NCCH Program ID + * 2 : bool is_out_box? + * 3 : Message ID size(unused, always 8) + * 4 : Buffer size(unused) + * 5 : Descriptor for mapping a read-only buffer in the target process + * 6 : Buffer address + * 7 : Descriptor for mapping a read/write buffer in the target process + * 8 : Message ID address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Descriptor for mapping a read-only buffer in the target process + * 3 : Buffer address + * 4 : Descriptor for mapping a read/write buffer in the target process + * 5 : Message ID address + */ + void WriteMessage(Kernel::HLERequestContext& ctx); + + /** + * CECD::WriteMessageWithHMAC service function + * Inputs: + * 0 : Header Code[0x00070106] + * 1 : NCCH Program ID + * 2 : bool is_out_box? + * 3 : Message ID size(unused, always 8) + * 4 : Buffer size(unused) + * 5 : Descriptor for mapping a read-only buffer in the target process + * 6 : Buffer address + * 7 : Descriptor for mapping a read-only buffer in the target process + * 8 : HMAC key address + * 9 : Descriptor for mapping a read/write buffer in the target process + * 10 : Message ID address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Descriptor for mapping a read-only buffer in the target process + * 3 : Buffer address + * 4 : Descriptor for mapping a read-only buffer in the target process + * 5 : HMAC key address + * 6 : Descriptor for mapping a read/write buffer in the target process + * 7 : Message ID address + */ + void WriteMessageWithHMAC(Kernel::HLERequestContext& ctx); + + /** + * CECD::Delete service function + * Inputs: + * 0 : Header Code[0x00080102] + * 1 : NCCH Program ID + * 2 : Path type + * 3 : bool is_out_box? + * 4 : Message ID size (unused) + * 5 : Descriptor for mapping a read-only buffer in the target process + * 6 : Message ID address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Descriptor for mapping a read-only buffer in the target process + * 3 : Message ID address + */ + void Delete(Kernel::HLERequestContext& ctx); + + /** + * CECD::GetSystemInfo service function + * Inputs: + * 0 : Header Code[0x000A00C4] + * 1 : Destination buffer size (unused) + * 2 : Info type + * 3 : Param buffer size (unused) + * 4 : Descriptor for mapping a read-only buffer in the target process + * 5 : Param buffer address + * 6 : Descriptor for mapping a write-only buffer in the target process + * 7 : Destination buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Descriptor for mapping a read-only buffer in the target process + * 3 : Param buffer address + * 4 : Descriptor for mapping a write-only buffer in the target process + * 5 : Destination buffer address + */ + void GetSystemInfo(Kernel::HLERequestContext& ctx); + + /** + * CECD::RunCommand service function + * Inputs: + * 0 : Header Code[0x000B0040] + * 1 : Command + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void RunCommand(Kernel::HLERequestContext& ctx); + + /** + * CECD::RunCommandAlt service function + * Inputs: + * 0 : Header Code[0x000C0040] + * 1 : Command + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void RunCommandAlt(Kernel::HLERequestContext& ctx); + + /** + * CECD::GetCecInfoBuffer service function + * Inputs: + * 0 : Header Code[0x000D0082] + * 1 : unknown + * 2 : unknown + * 3 : buffer descriptor + * 4 : buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : + */ + void GetCecInfoBuffer(Kernel::HLERequestContext& ctx); + /** * GetCecStateAbbreviated service function * Inputs: - * 0: 0x000E0000 + * 0: Header Code[0x000E0000] * Outputs: * 1: ResultCode * 2: CecStateAbbreviated @@ -44,7 +276,7 @@ public: /** * GetCecInfoEventHandle service function * Inputs: - * 0: 0x000F0000 + * 0: Header Code[0x000F0000] * Outputs: * 1: ResultCode * 3: Event Handle @@ -54,13 +286,76 @@ public: /** * GetChangeStateEventHandle service function * Inputs: - * 0: 0x00100000 + * 0: Header Code[0x00100000] * Outputs: * 1: ResultCode * 3: Event Handle */ void GetChangeStateEventHandle(Kernel::HLERequestContext& ctx); + /** + * CECD::OpenAndWrite service function + * Inputs: + * 0 : Header Code[0x00110104] + * 1 : Buffer size (unused) + * 2 : NCCH Program ID + * 3 : Path type + * 4 : File open flag? + * 5 : Descriptor for process ID + * 6 : Placeholder for process ID + * 7 : Descriptor for mapping a read-only buffer in the target process + * 8 : Buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Descriptor for mapping a read-only buffer in the target process + * 3 : Buffer address + */ + void OpenAndWrite(Kernel::HLERequestContext& ctx); + + /** + * CECD::OpenAndRead service function + * Inputs: + * 0 : Header Code[0x00120104] + * 1 : Buffer size (unused) + * 2 : NCCH Program ID + * 3 : Path type + * 4 : File open flag? + * 5 : Descriptor for process ID + * 6 : Placeholder for process ID + * 7 : Descriptor for mapping a write-only buffer in the target process + * 8 : Buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Toal bytes read + * 3 : Descriptor for mapping a write-only buffer in the target process + * 4 : Buffer address + */ + void OpenAndRead(Kernel::HLERequestContext& ctx); + + /** + * CECD::GetEventLog service function + * Inputs: + * 0 : Header Code[0x001E0082] + * 1 : unknown + * 2 : unknown + * 3 : buffer descriptor + * 4 : buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : unknown + */ + void GetEventLog(Kernel::HLERequestContext& ctx); + + /** + * CECD::GetEventLogStart service function + * Inputs: + * 0 : Header Code[0x001F0000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : unknown + */ + void GetEventLogStart(Kernel::HLERequestContext& ctx); + private: std::shared_ptr cecd; }; diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp index f9cab854e..e8d6546c6 100644 --- a/src/core/hle/service/cecd/cecd_s.cpp +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -12,22 +12,24 @@ CECD_S::CECD_S(std::shared_ptr cecd) static const FunctionInfo functions[] = { // cecd:u shared commands // clang-format off - {0x000100C2, nullptr, "OpenRawFile"}, - {0x00020042, nullptr, "ReadRawFile"}, - {0x00030104, nullptr, "ReadMessage"}, - {0x00040106, nullptr, "ReadMessageWithHMAC"}, - {0x00050042, nullptr, "WriteRawFile"}, - {0x00060104, nullptr, "WriteMessage"}, - {0x00070106, nullptr, "WriteMessageWithHMAC"}, - {0x00080102, nullptr, "Delete"}, - {0x000A00C4, nullptr, "GetSystemInfo"}, + {0x000100C2, &CECD_S::OpenRawFile, "OpenRawFile"}, + {0x00020042, &CECD_S::ReadRawFile, "ReadRawFile"}, + {0x00030104, &CECD_S::ReadMessage, "ReadMessage"}, + {0x00040106, &CECD_S::ReadMessageWithHMAC, "ReadMessageWithHMAC"}, + {0x00050042, &CECD_S::WriteRawFile, "WriteRawFile"}, + {0x00060104, &CECD_S::WriteMessage, "WriteMessage"}, + {0x00070106, &CECD_S::WriteMessageWithHMAC, "WriteMessageWithHMAC"}, + {0x00080102, &CECD_S::Delete, "Delete"}, + {0x000A00C4, &CECD_S::GetSystemInfo, "GetSystemInfo"}, {0x000B0040, nullptr, "RunCommand"}, {0x000C0040, nullptr, "RunCommandAlt"}, {0x000E0000, &CECD_S::GetCecStateAbbreviated, "GetCecStateAbbreviated"}, {0x000F0000, &CECD_S::GetCecInfoEventHandle, "GetCecInfoEventHandle"}, {0x00100000, &CECD_S::GetChangeStateEventHandle, "GetChangeStateEventHandle"}, - {0x00110104, nullptr, "OpenAndWrite"}, - {0x00120104, nullptr, "OpenAndRead"}, + {0x00110104, &CECD_S::OpenAndWrite, "OpenAndWrite"}, + {0x00120104, &CECD_S::OpenAndRead, "OpenAndRead"}, + {0x001E0082, nullptr, "GetEventLog"}, + {0x001F0000, nullptr, "GetEventLogStart"}, // clang-format on }; diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp index d13c3ca09..f89563116 100644 --- a/src/core/hle/service/cecd/cecd_u.cpp +++ b/src/core/hle/service/cecd/cecd_u.cpp @@ -12,22 +12,24 @@ CECD_U::CECD_U(std::shared_ptr cecd) static const FunctionInfo functions[] = { // cecd:u shared commands // clang-format off - {0x000100C2, nullptr, "OpenRawFile"}, - {0x00020042, nullptr, "ReadRawFile"}, - {0x00030104, nullptr, "ReadMessage"}, - {0x00040106, nullptr, "ReadMessageWithHMAC"}, - {0x00050042, nullptr, "WriteRawFile"}, - {0x00060104, nullptr, "WriteMessage"}, - {0x00070106, nullptr, "WriteMessageWithHMAC"}, - {0x00080102, nullptr, "Delete"}, - {0x000A00C4, nullptr, "GetSystemInfo"}, + {0x000100C2, &CECD_U::OpenRawFile, "OpenRawFile"}, + {0x00020042, &CECD_U::ReadRawFile, "ReadRawFile"}, + {0x00030104, &CECD_U::ReadMessage, "ReadMessage"}, + {0x00040106, &CECD_U::ReadMessageWithHMAC, "ReadMessageWithHMAC"}, + {0x00050042, &CECD_U::WriteRawFile, "WriteRawFile"}, + {0x00060104, &CECD_U::WriteMessage, "WriteMessage"}, + {0x00070106, &CECD_U::WriteMessageWithHMAC, "WriteMessageWithHMAC"}, + {0x00080102, &CECD_U::Delete, "Delete"}, + {0x000A00C4, &CECD_U::GetSystemInfo, "GetSystemInfo"}, {0x000B0040, nullptr, "RunCommand"}, {0x000C0040, nullptr, "RunCommandAlt"}, {0x000E0000, &CECD_U::GetCecStateAbbreviated, "GetCecStateAbbreviated"}, {0x000F0000, &CECD_U::GetCecInfoEventHandle, "GetCecInfoEventHandle"}, {0x00100000, &CECD_U::GetChangeStateEventHandle, "GetChangeStateEventHandle"}, - {0x00110104, nullptr, "OpenAndWrite"}, - {0x00120104, nullptr, "OpenAndRead"}, + {0x00110104, &CECD_U::OpenAndWrite, "OpenAndWrite"}, + {0x00120104, &CECD_U::OpenAndRead, "OpenAndRead"}, + {0x001E0082, nullptr, "GetEventLog"}, + {0x001F0000, nullptr, "GetEventLogStart"}, // clang-format on }; From 2ee395d7ded105be2a487cac5b6b8ae07eb71010 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Sun, 29 Jul 2018 12:43:13 -0400 Subject: [PATCH 02/21] service/cecd: Implement functions --- src/core/hle/service/cecd/cecd.cpp | 190 ++++++++++++++++++++++------- src/core/hle/service/cecd/cecd.h | 29 ++++- 2 files changed, 174 insertions(+), 45 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index dcf9a8832..0dc801a39 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -2,7 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/file_util.h" #include "common/logging/log.h" +#include "common/string_util.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_helpers.h" #include "core/hle/result.h" #include "core/hle/service/cecd/cecd.h" @@ -16,7 +21,7 @@ namespace CECD { void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x01, 3, 2); const u32 ncch_program_id = rp.Pop(); - const u32 path_type = rp.Pop(); + const auto path_type = static_cast(rp.Pop()); const u32 file_open_flag = rp.Pop(); rp.PopPID(); @@ -27,18 +32,18 @@ void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " "file_open_flag={:#010x}", - ncch_program_id, path_type, file_open_flag); + ncch_program_id, static_cast(path_type), file_open_flag); } void Module::Interface::ReadRawFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x02, 1, 2); const u32 buffer_size = rp.Pop(); - auto buffer = rp.PopStaticBuffer(); + auto& buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); rb.Push(RESULT_SUCCESS); rb.Push(0); /// Read size - rb.PushStaticBuffer(buffer, 0); + rb.PushMappedBuffer(buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, buffer_size={:#010x}", buffer_size); } @@ -49,14 +54,14 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { const bool is_out_box = rp.Pop(); const u32 message_id_size = rp.Pop(); const u32 buffer_size = rp.Pop(); - const auto message_id_buffer = rp.PopStaticBuffer(); - auto write_buffer = rp.PopStaticBuffer(); + const auto& message_id_buffer = rp.PopMappedBuffer(); + auto& write_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(2, 4); rb.Push(RESULT_SUCCESS); rb.Push(0); /// Read size - rb.PushStaticBuffer(message_id_buffer, 0); - rb.PushStaticBuffer(write_buffer, 1); + rb.PushMappedBuffer(message_id_buffer); + rb.PushMappedBuffer(write_buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", ncch_program_id, is_out_box); @@ -68,16 +73,16 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { const bool is_out_box = rp.Pop(); const u32 message_id_size = rp.Pop(); const u32 buffer_size = rp.Pop(); - const auto message_id_buffer = rp.PopStaticBuffer(); - const auto hmac_key_buffer = rp.PopStaticBuffer(); - auto write_buffer = rp.PopStaticBuffer(); + const auto& message_id_buffer = rp.PopMappedBuffer(); + const auto& hmac_key_buffer = rp.PopMappedBuffer(); + auto& write_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(2, 6); rb.Push(RESULT_SUCCESS); rb.Push(0); /// Read size - rb.PushStaticBuffer(message_id_buffer, 0); - rb.PushStaticBuffer(hmac_key_buffer, 1); - rb.PushStaticBuffer(write_buffer, 2); + rb.PushMappedBuffer(message_id_buffer); + rb.PushMappedBuffer(hmac_key_buffer); + rb.PushMappedBuffer(write_buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", ncch_program_id, is_out_box); @@ -86,11 +91,11 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { void Module::Interface::WriteRawFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x05, 1, 2); const u32 buffer_size = rp.Pop(); - const auto buffer = rp.PopStaticBuffer(); + const auto& buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); - rb.PushStaticBuffer(buffer, 0); + rb.PushMappedBuffer(buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, buffer_size={:#010x}", buffer_size); } @@ -101,13 +106,13 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { const bool is_out_box = rp.Pop(); const u32 message_id_size = rp.Pop(); const u32 buffer_size = rp.Pop(); - const auto read_buffer = rp.PopStaticBuffer(); - auto message_id_buffer = rp.PopStaticBuffer(); + const auto& read_buffer = rp.PopMappedBuffer(); + auto& message_id_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); rb.Push(RESULT_SUCCESS); - rb.PushStaticBuffer(read_buffer, 0); - rb.PushStaticBuffer(message_id_buffer, 1); + rb.PushMappedBuffer(read_buffer); + rb.PushMappedBuffer(message_id_buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", ncch_program_id, is_out_box); @@ -119,15 +124,15 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { const bool is_out_box = rp.Pop(); const u32 message_id_size = rp.Pop(); const u32 buffer_size = rp.Pop(); - const auto read_buffer = rp.PopStaticBuffer(); - const auto hmac_key_buffer = rp.PopStaticBuffer(); - auto message_id_buffer = rp.PopStaticBuffer(); + const auto& read_buffer = rp.PopMappedBuffer(); + const auto& hmac_key_buffer = rp.PopMappedBuffer(); + auto& message_id_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 6); rb.Push(RESULT_SUCCESS); - rb.PushStaticBuffer(read_buffer, 0); - rb.PushStaticBuffer(hmac_key_buffer, 1); - rb.PushStaticBuffer(message_id_buffer, 2); + rb.PushMappedBuffer(read_buffer); + rb.PushMappedBuffer(hmac_key_buffer); + rb.PushMappedBuffer(message_id_buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", ncch_program_id, is_out_box); @@ -136,18 +141,18 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x10, 4, 2); const u32 ncch_program_id = rp.Pop(); - const u32 path_type = rp.Pop(); + const auto path_type = static_cast(rp.Pop()); const bool is_out_box = rp.Pop(); const u32 message_id_size = rp.Pop(); - const auto message_id_buffer = rp.PopStaticBuffer(); + const auto& message_id_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); - rb.PushStaticBuffer(message_id_buffer, 0); + rb.PushMappedBuffer(message_id_buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, is_out_box={}", - ncch_program_id, path_type, is_out_box); + ncch_program_id, static_cast(path_type), is_out_box); } void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { @@ -155,13 +160,13 @@ void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { const u32 dest_buffer_size = rp.Pop(); const u32 info_type = rp.Pop(); const u32 param_buffer_size = rp.Pop(); - const auto param_buffer = rp.PopStaticBuffer(); - auto dest_buffer = rp.PopStaticBuffer(); + const auto& param_buffer = rp.PopMappedBuffer(); + auto& dest_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); rb.Push(RESULT_SUCCESS); - rb.PushStaticBuffer(param_buffer, 0); - rb.PushStaticBuffer(dest_buffer, 1); + rb.PushMappedBuffer(param_buffer); + rb.PushMappedBuffer(dest_buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, dest_buffer_size={:#010x}, info_type={:#010x}, " @@ -203,38 +208,109 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x11, 4, 4); const u32 buffer_size = rp.Pop(); const u32 ncch_program_id = rp.Pop(); - const u32 path_type = rp.Pop(); + const auto path_type = static_cast(rp.Pop()); const u32 file_open_flag = rp.Pop(); rp.PopPID(); - const auto read_buffer = rp.PopStaticBuffer(); + auto& read_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(RESULT_SUCCESS); - rb.PushStaticBuffer(read_buffer, 0); + + FileSys::Path path(cecd->GetCecDataPathTypeAsString(path_type, ncch_program_id).data()); + FileSys::Mode write_mode = {}; + write_mode.create_flag.Assign(1); + write_mode.write_flag.Assign(1); + + auto file_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, + write_mode); + if (file_result.Succeeded()) { + std::vector buffer(buffer_size); + read_buffer.Read(buffer.data(), 0, buffer_size); + const u32 bytes_written = + file_result.Unwrap()->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); + + rb.Push(RESULT_SUCCESS); + } else { + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + } + rb.PushMappedBuffer(read_buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " "file_open_flag={:#010x}", - ncch_program_id, path_type, file_open_flag); + ncch_program_id, static_cast(path_type), file_open_flag); } void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x12, 4, 4); const u32 buffer_size = rp.Pop(); const u32 ncch_program_id = rp.Pop(); - const u32 path_type = rp.Pop(); + const auto path_type = static_cast(rp.Pop()); const u32 file_open_flag = rp.Pop(); rp.PopPID(); - auto write_buffer = rp.PopStaticBuffer(); + auto& write_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); - rb.Push(RESULT_SUCCESS); - rb.PushStaticBuffer(write_buffer, 0); + + FileSys::Path path(cecd->GetCecDataPathTypeAsString(path_type, ncch_program_id).data()); + FileSys::Mode read_mode = {}; + read_mode.read_flag.Assign(1); + + auto file_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, + read_mode); + if (file_result.Succeeded()) { + std::vector buffer(buffer_size); + const u32 bytes_read = + file_result.Unwrap()->backend->Read(0, buffer_size, buffer.data()).Unwrap(); + write_buffer.Write(buffer.data(), 0, buffer_size); + + rb.Push(RESULT_SUCCESS); + rb.Push(bytes_read); + } else { + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + rb.Push(0); /// No bytes read + } + rb.PushMappedBuffer(write_buffer); LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " "file_open_flag={:#010x}", - ncch_program_id, path_type, file_open_flag); + ncch_program_id, static_cast(path_type), file_open_flag); +} + +std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, + const std::vector& msg_id) { + switch(type) { + case CecDataPathType::CEC_PATH_MBOX_LIST: + return "/CEC/MBoxList____"; + case CecDataPathType::CEC_PATH_MBOX_INFO: + return Common::StringFromFormat("/CEC/%08x/MBoxInfo____", program_id); + case CecDataPathType::CEC_PATH_INBOX_INFO: + return Common::StringFromFormat("/CEC/%08x/InBox___/BoxInfo_____", program_id); + case CecDataPathType::CEC_PATH_OUTBOX_INFO: + return Common::StringFromFormat("/CEC/%08x/OutBox__/BoxInfo_____", program_id); + case CecDataPathType::CEC_PATH_OUTBOX_INDEX: + return Common::StringFromFormat("/CEC/%08x/OutBox__/OBIndex_____", program_id); + case CecDataPathType::CEC_PATH_INBOX_MSG: + return Common::StringFromFormat("/CEC/%08x/InBox___/_%08x", program_id, msg_id.data()); + case CecDataPathType::CEC_PATH_OUTBOX_MSG: + return Common::StringFromFormat("/CEC/%08x/OutBox__/_%08x", program_id, msg_id.data()); + case CecDataPathType::CEC_PATH_ROOT_DIR: + return "/CEC"; + case CecDataPathType::CEC_PATH_MBOX_DIR: + return Common::StringFromFormat("/CEC/%08x", program_id); + case CecDataPathType::CEC_PATH_INBOX_DIR: + return Common::StringFromFormat("/CEC/%08x/InBox___", program_id); + case CecDataPathType::CEC_PATH_OUTBOX_DIR: + return Common::StringFromFormat("/CEC/%08x/OutBox__", program_id); + case CecDataPathType::CEC_MBOX_DATA: + case CecDataPathType::CEC_MBOX_ICON: + case CecDataPathType::CEC_MBOX_TITLE: + default: + return Common::StringFromFormat("/CEC/%08x/MBoxData.%03d", program_id, + static_cast(type) - 100); + } } Module::Interface::Interface(std::shared_ptr cecd, const char* name, u32 max_session) @@ -244,6 +320,32 @@ Module::Module() { using namespace Kernel; cecinfo_event = Event::Create(Kernel::ResetType::OneShot, "CECD::cecinfo_event"); change_state_event = Event::Create(Kernel::ResetType::OneShot, "CECD::change_state_event"); + + // Open the SystemSaveData archive 0x00010026 + FileSys::Path archive_path(cecd_system_savedata_id); + auto archive_result = + Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); + + // If the archive didn't exist, create the files inside + if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { + // Format the archive to create the directories + Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, + FileSys::ArchiveFormatInfo(), archive_path); + + // Open it again to get a valid archive now that the folder exists + archive_result = + Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); + } + + ASSERT_MSG(archive_result.Succeeded(), "Could not open the CECD SystemSaveData archive!"); + + cecd_system_save_data_archive = *archive_result; +} + +Module::~Module() { + if (cecd_system_save_data_archive) { + Service::FS::CloseArchive(cecd_system_save_data_archive); + } } void InstallInterfaces(SM::ServiceManager& service_manager) { diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 707cc9ca3..ec7fb0a7e 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -6,6 +6,7 @@ #include "core/hle/kernel/event.h" #include "core/hle/service/service.h" +#include "core/hle/service/fs/archive.h" namespace Service { namespace CECD { @@ -13,7 +14,7 @@ namespace CECD { class Module final { public: Module(); - ~Module() = default; + ~Module(); enum class CecStateAbbreviated : u32 { CEC_STATE_ABBREV_IDLE = 1, /// Relates to CEC_STATE_IDLE @@ -48,6 +49,23 @@ public: CEC_COMMAND_END = 0x15, }; + enum class CecDataPathType : u32 { + CEC_PATH_MBOX_LIST = 1, + CEC_PATH_MBOX_INFO = 2, + CEC_PATH_INBOX_INFO = 3, + CEC_PATH_OUTBOX_INFO = 4, + CEC_PATH_OUTBOX_INDEX = 5, + CEC_PATH_INBOX_MSG = 6, + CEC_PATH_OUTBOX_MSG = 7, + CEC_PATH_ROOT_DIR = 10, + CEC_PATH_MBOX_DIR = 11, + CEC_PATH_INBOX_DIR = 12, + CEC_PATH_OUTBOX_DIR = 13, + CEC_MBOX_DATA = 100, + CEC_MBOX_ICON = 101, + CEC_MBOX_TITLE = 110, + }; + class Interface : public ServiceFramework { public: Interface(std::shared_ptr cecd, const char* name, u32 max_session); @@ -361,6 +379,15 @@ public: }; private: + std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, + const std::vector& message_id = std::vector()); + + const std::vector cecd_system_savedata_id = { + 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x01, 0x00 + }; + + Service::FS::ArchiveHandle cecd_system_save_data_archive; + Kernel::SharedPtr cecinfo_event; Kernel::SharedPtr change_state_event; }; From 413f1651b74f5c1137b98f25cb7581317716f236 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Mon, 6 Aug 2018 02:39:47 -0400 Subject: [PATCH 03/21] service/cecd: Implement basic file handling functions. --- src/core/hle/service/cecd/cecd.cpp | 426 ++++++++++++++++++++------- src/core/hle/service/cecd/cecd.h | 221 +++++++++++--- src/core/hle/service/cecd/cecd_s.cpp | 6 +- src/core/hle/service/cecd/cecd_u.cpp | 6 +- 4 files changed, 520 insertions(+), 139 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 0dc801a39..c003e547a 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -6,9 +6,11 @@ #include "common/logging/log.h" #include "common/string_util.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_helpers.h" +#include "core/hle/kernel/process.h" #include "core/hle/result.h" #include "core/hle/service/cecd/cecd.h" #include "core/hle/service/cecd/cecd_ndm.h" @@ -18,43 +20,124 @@ namespace Service { namespace CECD { +using CecDataPathType = Module::CecDataPathType; +using CecOpenMode = Module::CecOpenMode; +using CecSystemInfoType = Module::CecSystemInfoType; + void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x01, 3, 2); const u32 ncch_program_id = rp.Pop(); const auto path_type = static_cast(rp.Pop()); - const u32 file_open_flag = rp.Pop(); + CecOpenMode open_mode; + open_mode.raw = rp.Pop(); rp.PopPID(); - IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); - rb.Push(RESULT_SUCCESS); - rb.Push(0); /// File size? + FileSys::Path path(cecd->GetCecDataPathTypeAsString(path_type, ncch_program_id).data()); + FileSys::Mode mode; + mode.read_flag.Assign(1); + mode.write_flag.Assign(1); + mode.create_flag.Assign(1); - LOG_WARNING(Service_CECD, - "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " - "file_open_flag={:#010x}", - ncch_program_id, static_cast(path_type), file_open_flag); + SessionData* session_data = GetSessionData(ctx.Session()); + session_data->ncch_program_id = ncch_program_id; + session_data->open_mode.raw = open_mode.raw; + session_data->data_path_type = path_type; + session_data->path = path; + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + switch (path_type) { + case CecDataPathType::CEC_PATH_ROOT_DIR: + case CecDataPathType::CEC_PATH_MBOX_DIR: + case CecDataPathType::CEC_PATH_INBOX_DIR: + case CecDataPathType::CEC_PATH_OUTBOX_DIR: { + auto dir_result = + Service::FS::OpenDirectoryFromArchive(cecd->cecd_system_save_data_archive, path); + if (dir_result.Failed()) { + if (open_mode.make_dir) { + Service::FS::CreateDirectoryFromArchive(cecd->cecd_system_save_data_archive, path); + rb.Push(RESULT_SUCCESS); + } else { + LOG_ERROR(Service_CECD, "Failed to open directory: {}", path.AsString()); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, + ErrorSummary::NotFound, ErrorLevel::Status)); + } + rb.Push(0); /// Zero entries + } else { + auto directory = dir_result.Unwrap(); + rb.Push(RESULT_SUCCESS); + rb.Push(directory->backend->Read(0, nullptr)); /// Entry count + } + break; + } + default: { /// If not directory, then it is a file + auto file_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); + if (file_result.Failed()) { + LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + rb.Push(0); /// No file size + } else { + session_data->file = std::move(file_result.Unwrap()); + rb.Push(RESULT_SUCCESS); + rb.Push(session_data->file->backend->GetSize()); /// Return file size + } + + if (path_type == CecDataPathType::CEC_MBOX_PROGRAM_ID) { + std::vector program_id(8); + u64_le le_program_id = Kernel::g_current_process->codeset->program_id; + std::memcpy(program_id.data(), &le_program_id, sizeof(u64)); + session_data->file->backend->Write(0, sizeof(u64), true, program_id.data()); + } + } + } + + LOG_DEBUG(Service_CECD, + "called, ncch_program_id={:#010x}, path_type={:#04x}, open_mode={:#010x}, path={}", + ncch_program_id, static_cast(path_type), open_mode.raw, path.AsString()); } void Module::Interface::ReadRawFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x02, 1, 2); - const u32 buffer_size = rp.Pop(); - auto& buffer = rp.PopMappedBuffer(); + const u32 write_buffer_size = rp.Pop(); + auto& write_buffer = rp.PopMappedBuffer(); + + SessionData* session_data = GetSessionData(ctx.Session()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); - rb.Push(RESULT_SUCCESS); - rb.Push(0); /// Read size - rb.PushMappedBuffer(buffer); + switch (session_data->data_path_type) { + case CecDataPathType::CEC_PATH_ROOT_DIR: + case CecDataPathType::CEC_PATH_MBOX_DIR: + case CecDataPathType::CEC_PATH_INBOX_DIR: + case CecDataPathType::CEC_PATH_OUTBOX_DIR: + rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, + ErrorSummary::NotFound, ErrorLevel::Status)); + rb.Push(0); /// No bytes read + break; + default: /// If not directory, then it is a file + std::vector buffer(write_buffer_size); + const u32 bytes_read = + session_data->file->backend->Read(0, write_buffer_size, buffer.data()).Unwrap(); - LOG_WARNING(Service_CECD, "(STUBBED) called, buffer_size={:#010x}", buffer_size); + write_buffer.Write(buffer.data(), 0, write_buffer_size); + session_data->file->backend->Close(); + + rb.Push(RESULT_SUCCESS); + rb.Push(bytes_read); + } + rb.PushMappedBuffer(write_buffer); + + LOG_DEBUG(Service_CECD, "called, write_buffer_size={:#010x}, path={}", write_buffer_size, + session_data->path.AsString()); } void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x03, 4, 4); const u32 ncch_program_id = rp.Pop(); - const bool is_out_box = rp.Pop(); + const bool is_outbox = rp.Pop(); const u32 message_id_size = rp.Pop(); const u32 buffer_size = rp.Pop(); - const auto& message_id_buffer = rp.PopMappedBuffer(); + auto& message_id_buffer = rp.PopMappedBuffer(); auto& write_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(2, 4); @@ -63,18 +146,18 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(message_id_buffer); rb.PushMappedBuffer(write_buffer); - LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", - ncch_program_id, is_out_box); + LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_outbox={}", + ncch_program_id, is_outbox); } void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x04, 4, 6); const u32 ncch_program_id = rp.Pop(); - const bool is_out_box = rp.Pop(); + const bool is_outbox = rp.Pop(); const u32 message_id_size = rp.Pop(); const u32 buffer_size = rp.Pop(); - const auto& message_id_buffer = rp.PopMappedBuffer(); - const auto& hmac_key_buffer = rp.PopMappedBuffer(); + auto& message_id_buffer = rp.PopMappedBuffer(); + auto& hmac_key_buffer = rp.PopMappedBuffer(); auto& write_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(2, 6); @@ -84,29 +167,48 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(hmac_key_buffer); rb.PushMappedBuffer(write_buffer); - LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", - ncch_program_id, is_out_box); + LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_outbox={}", + ncch_program_id, is_outbox); } void Module::Interface::WriteRawFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x05, 1, 2); - const u32 buffer_size = rp.Pop(); - const auto& buffer = rp.PopMappedBuffer(); + const u32 read_buffer_size = rp.Pop(); + auto& read_buffer = rp.PopMappedBuffer(); + + SessionData* session_data = GetSessionData(ctx.Session()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(RESULT_SUCCESS); - rb.PushMappedBuffer(buffer); + switch (session_data->data_path_type) { + case CecDataPathType::CEC_PATH_ROOT_DIR: + case CecDataPathType::CEC_PATH_MBOX_DIR: + case CecDataPathType::CEC_PATH_INBOX_DIR: + case CecDataPathType::CEC_PATH_OUTBOX_DIR: + rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, + ErrorSummary::NotFound, ErrorLevel::Status)); + break; + default: /// If not directory, then it is a file + std::vector buffer(read_buffer_size); + read_buffer.Read(buffer.data(), 0, read_buffer_size); - LOG_WARNING(Service_CECD, "(STUBBED) called, buffer_size={:#010x}", buffer_size); + const u32 bytes_written = + session_data->file->backend->Write(0, read_buffer_size, true, buffer.data()).Unwrap(); + session_data->file->backend->Close(); + + rb.Push(RESULT_SUCCESS); + } + rb.PushMappedBuffer(read_buffer); + + LOG_DEBUG(Service_CECD, "called, read_buffer_size={:#010x}", read_buffer_size); } void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x06, 4, 4); const u32 ncch_program_id = rp.Pop(); - const bool is_out_box = rp.Pop(); + const bool is_outbox = rp.Pop(); const u32 message_id_size = rp.Pop(); const u32 buffer_size = rp.Pop(); - const auto& read_buffer = rp.PopMappedBuffer(); + auto& read_buffer = rp.PopMappedBuffer(); auto& message_id_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); @@ -114,18 +216,18 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(read_buffer); rb.PushMappedBuffer(message_id_buffer); - LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", - ncch_program_id, is_out_box); + LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_outbox={}", + ncch_program_id, is_outbox); } void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x07, 4, 6); const u32 ncch_program_id = rp.Pop(); - const bool is_out_box = rp.Pop(); + const bool is_outbox = rp.Pop(); const u32 message_id_size = rp.Pop(); const u32 buffer_size = rp.Pop(); - const auto& read_buffer = rp.PopMappedBuffer(); - const auto& hmac_key_buffer = rp.PopMappedBuffer(); + auto& read_buffer = rp.PopMappedBuffer(); + auto& hmac_key_buffer = rp.PopMappedBuffer(); auto& message_id_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 6); @@ -134,44 +236,99 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(hmac_key_buffer); rb.PushMappedBuffer(message_id_buffer); - LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_out_box={}", - ncch_program_id, is_out_box); + LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_outbox={}", + ncch_program_id, is_outbox); } void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x10, 4, 2); + IPC::RequestParser rp(ctx, 0x08, 4, 2); const u32 ncch_program_id = rp.Pop(); const auto path_type = static_cast(rp.Pop()); - const bool is_out_box = rp.Pop(); + const bool is_outbox = rp.Pop(); const u32 message_id_size = rp.Pop(); - const auto& message_id_buffer = rp.PopMappedBuffer(); + auto& message_id_buffer = rp.PopMappedBuffer(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushMappedBuffer(message_id_buffer); LOG_WARNING(Service_CECD, - "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, is_out_box={}", - ncch_program_id, static_cast(path_type), is_out_box); + "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#04x}, is_outbox={}", + ncch_program_id, static_cast(path_type), is_outbox); +} + +void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x09, 3, 2); + const u32 ncch_program_id = rp.Pop(); + const u32 size = rp.Pop(); + const u32 option = rp.Pop(); + auto& message_id_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(message_id_buffer); + + LOG_WARNING(Service_CECD, + "(STUBBED) called, ncch_program_id={:#010x}, size={:#010x}, option={:#010x}", + ncch_program_id, size, option); } void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x10, 3, 4); + IPC::RequestParser rp(ctx, 0x0A, 3, 4); const u32 dest_buffer_size = rp.Pop(); - const u32 info_type = rp.Pop(); + const CecSystemInfoType info_type = static_cast(rp.Pop()); const u32 param_buffer_size = rp.Pop(); - const auto& param_buffer = rp.PopMappedBuffer(); + auto& param_buffer = rp.PopMappedBuffer(); auto& dest_buffer = rp.PopMappedBuffer(); + /// TODO: Other CecSystemInfoTypes IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); + std::vector buffer; + switch (info_type) { + case CecSystemInfoType::EulaVersion: /// TODO: Read config Eula version + buffer = {0xFF, 0xFF}; + dest_buffer.Write(buffer.data(), 0, buffer.size()); + break; + case CecSystemInfoType::Eula: + buffer = {0x01}; /// Eula agreed + dest_buffer.Write(buffer.data(), 0, buffer.size()); + break; + case CecSystemInfoType::ParentControl: + buffer = {0x00}; /// No parent control + dest_buffer.Write(buffer.data(), 0, buffer.size()); + break; + default: + LOG_ERROR(Service_CECD, "Unknown system info type {}", static_cast(info_type)); + } + rb.Push(RESULT_SUCCESS); rb.PushMappedBuffer(param_buffer); rb.PushMappedBuffer(dest_buffer); - LOG_WARNING(Service_CECD, - "(STUBBED) called, dest_buffer_size={:#010x}, info_type={:#010x}, " - "param_buffer_size={:#010x}", - dest_buffer_size, info_type, param_buffer_size); + LOG_DEBUG(Service_CECD, + "(STUBBED) called, dest_buffer_size={:#010x}, info_type={:#010x}, " + "param_buffer_size={:#010x}", + dest_buffer_size, static_cast(info_type), param_buffer_size); +} + +void Module::Interface::RunCommand(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0B, 1, 0); + const auto command = static_cast(rp.Pop()); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", static_cast(command)); +} + +void Module::Interface::RunCommandAlt(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0C, 1, 0); + const auto command = static_cast(rp.Pop()); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", static_cast(command)); } void Module::Interface::GetCecStateAbbreviated(Kernel::HLERequestContext& ctx) { @@ -209,36 +366,49 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { const u32 buffer_size = rp.Pop(); const u32 ncch_program_id = rp.Pop(); const auto path_type = static_cast(rp.Pop()); - const u32 file_open_flag = rp.Pop(); + CecOpenMode open_mode; + open_mode.raw = rp.Pop(); rp.PopPID(); auto& read_buffer = rp.PopMappedBuffer(); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - FileSys::Path path(cecd->GetCecDataPathTypeAsString(path_type, ncch_program_id).data()); - FileSys::Mode write_mode = {}; - write_mode.create_flag.Assign(1); - write_mode.write_flag.Assign(1); + FileSys::Mode mode; + mode.write_flag.Assign(1); + mode.create_flag.Assign(1); - auto file_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, - write_mode); - if (file_result.Succeeded()) { - std::vector buffer(buffer_size); - read_buffer.Read(buffer.data(), 0, buffer_size); - const u32 bytes_written = - file_result.Unwrap()->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + switch (path_type) { + case CecDataPathType::CEC_PATH_ROOT_DIR: + case CecDataPathType::CEC_PATH_MBOX_DIR: + case CecDataPathType::CEC_PATH_INBOX_DIR: + case CecDataPathType::CEC_PATH_OUTBOX_DIR: + rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, + ErrorSummary::NotFound, ErrorLevel::Status)); + break; + default: /// If not directory, then it is a file + auto file_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); + if (file_result.Succeeded()) { + auto file = file_result.Unwrap(); + std::vector buffer(buffer_size); - rb.Push(RESULT_SUCCESS); - } else { - rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, - ErrorLevel::Status)); + read_buffer.Read(buffer.data(), 0, buffer_size); + const u32 bytes_written = + file->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); + file->backend->Close(); + + rb.Push(RESULT_SUCCESS); + } else { + LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + } } rb.PushMappedBuffer(read_buffer); - LOG_WARNING(Service_CECD, - "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " - "file_open_flag={:#010x}", - ncch_program_id, static_cast(path_type), file_open_flag); + LOG_DEBUG(Service_CECD, + "called, ncch_program_id={:#010x}, path_type={:#04x}, open_mode={:#010x}, path={}", + ncch_program_id, static_cast(path_type), open_mode.raw, path.AsString()); } void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { @@ -246,42 +416,93 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { const u32 buffer_size = rp.Pop(); const u32 ncch_program_id = rp.Pop(); const auto path_type = static_cast(rp.Pop()); - const u32 file_open_flag = rp.Pop(); + CecOpenMode open_mode; + open_mode.raw = rp.Pop(); rp.PopPID(); auto& write_buffer = rp.PopMappedBuffer(); - IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); - FileSys::Path path(cecd->GetCecDataPathTypeAsString(path_type, ncch_program_id).data()); - FileSys::Mode read_mode = {}; - read_mode.read_flag.Assign(1); + FileSys::Mode mode; + mode.read_flag.Assign(1); + mode.create_flag.Assign(1); + mode.write_flag.Assign(1); - auto file_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, - read_mode); - if (file_result.Succeeded()) { - std::vector buffer(buffer_size); - const u32 bytes_read = - file_result.Unwrap()->backend->Read(0, buffer_size, buffer.data()).Unwrap(); - write_buffer.Write(buffer.data(), 0, buffer_size); - - rb.Push(RESULT_SUCCESS); - rb.Push(bytes_read); - } else { - rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, - ErrorLevel::Status)); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + switch (path_type) { + case CecDataPathType::CEC_PATH_ROOT_DIR: + case CecDataPathType::CEC_PATH_MBOX_DIR: + case CecDataPathType::CEC_PATH_INBOX_DIR: + case CecDataPathType::CEC_PATH_OUTBOX_DIR: + rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, + ErrorSummary::NotFound, ErrorLevel::Status)); rb.Push(0); /// No bytes read + break; + default: /// If not directory, then it is a file + auto file_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); + if (file_result.Succeeded()) { + auto file = file_result.Unwrap(); + std::vector buffer(buffer_size); + + const u32 bytes_read = file->backend->Read(0, buffer_size, buffer.data()).Unwrap(); + write_buffer.Write(buffer.data(), 0, buffer_size); + file->backend->Close(); + + rb.Push(RESULT_SUCCESS); + rb.Push(bytes_read); + } else { + LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); + + if (path_type == CecDataPathType::CEC_PATH_MBOX_INFO) { + const FileSys::Path mbox_path( + cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, + ncch_program_id) + .data()); + Service::FS::CreateDirectoryFromArchive(cecd->cecd_system_save_data_archive, + mbox_path); + } + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + rb.Push(0); /// No bytes read + } } rb.PushMappedBuffer(write_buffer); - LOG_WARNING(Service_CECD, - "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#010x}, " - "file_open_flag={:#010x}", - ncch_program_id, static_cast(path_type), file_open_flag); + LOG_DEBUG(Service_CECD, + "called, ncch_program_id={:#010x}, path_type={:#04x}, open_mode={:#010x}, path={}", + ncch_program_id, static_cast(path_type), open_mode.raw, path.AsString()); +} + +std::string Module::EncodeBase64(const std::vector& in, const std::string& dictionary) const { + std::string out; + out.reserve((in.size() * 4) / 3); + int b; + for (int i = 0; i < in.size(); i += 3) { + b = (in[i] & 0xFC) >> 2; + out += dictionary[b]; + b = (in[i] & 0x03) << 4; + if (i + 1 < in.size()) { + b |= (in[i + 1] & 0xF0) >> 4; + out += dictionary[b]; + b = (in[i + 1] & 0x0F) << 2; + if (i + 2 < in.size()) { + b |= (in[i + 2] & 0xC0) >> 6; + out += dictionary[b]; + b = in[i + 2] & 0x3F; + out += dictionary[b]; + } else { + out += dictionary[b]; + } + } else { + out += dictionary[b]; + } + } + return out; } std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, - const std::vector& msg_id) { - switch(type) { + const std::vector& msg_id) const { + switch (type) { case CecDataPathType::CEC_PATH_MBOX_LIST: return "/CEC/MBoxList____"; case CecDataPathType::CEC_PATH_MBOX_INFO: @@ -293,9 +514,11 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const case CecDataPathType::CEC_PATH_OUTBOX_INDEX: return Common::StringFromFormat("/CEC/%08x/OutBox__/OBIndex_____", program_id); case CecDataPathType::CEC_PATH_INBOX_MSG: - return Common::StringFromFormat("/CEC/%08x/InBox___/_%08x", program_id, msg_id.data()); + return Common::StringFromFormat("/CEC/%08x/InBox___/_%08x", program_id, + EncodeBase64(msg_id, base64_dict).data()); case CecDataPathType::CEC_PATH_OUTBOX_MSG: - return Common::StringFromFormat("/CEC/%08x/OutBox__/_%08x", program_id, msg_id.data()); + return Common::StringFromFormat("/CEC/%08x/OutBox__/_%08x", program_id, + EncodeBase64(msg_id, base64_dict).data()); case CecDataPathType::CEC_PATH_ROOT_DIR: return "/CEC"; case CecDataPathType::CEC_PATH_MBOX_DIR: @@ -313,6 +536,13 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const } } +Module::SessionData::SessionData() {} + +Module::SessionData::~SessionData() { + if (file) + file->backend->Close(); +} + Module::Interface::Interface(std::shared_ptr cecd, const char* name, u32 max_session) : ServiceFramework(name, max_session), cecd(std::move(cecd)) {} @@ -336,16 +566,14 @@ Module::Module() { archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); } - ASSERT_MSG(archive_result.Succeeded(), "Could not open the CECD SystemSaveData archive!"); cecd_system_save_data_archive = *archive_result; } Module::~Module() { - if (cecd_system_save_data_archive) { + if (cecd_system_save_data_archive) Service::FS::CloseArchive(cecd_system_save_data_archive); - } } void InstallInterfaces(SM::ServiceManager& service_manager) { diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index ec7fb0a7e..95c977da6 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -4,9 +4,10 @@ #pragma once +#include "common/bit_field.h" #include "core/hle/kernel/event.h" -#include "core/hle/service/service.h" #include "core/hle/service/fs/archive.h" +#include "core/hle/service/service.h" namespace Service { namespace CECD { @@ -16,14 +17,6 @@ public: Module(); ~Module(); - enum class CecStateAbbreviated : u32 { - CEC_STATE_ABBREV_IDLE = 1, /// Relates to CEC_STATE_IDLE - CEC_STATE_ABBREV_NOT_LOCAL = 2, /// Relates to CEC_STATEs *FINISH*, *POST, and OVER_BOSS - CEC_STATE_ABBREV_SCANNING = 3, /// Relates to CEC_STATE_SCANNING - CEC_STATE_ABBREV_WLREADY = 4, /// Relates to CEC_STATE_WIRELESS_READY when a bool is true - CEC_STATE_ABBREV_OTHER = 5, /// Relates to CEC_STATEs besides *FINISH*, *POST, and - }; /// OVER_BOSS and those listed here - enum class CecCommand : u32 { CEC_COMMAND_NONE = 0, CEC_COMMAND_START = 1, @@ -49,24 +42,158 @@ public: CEC_COMMAND_END = 0x15, }; + /** + * CecDataPathType possible missing values; need to figure out placement + * + * data:/CEC/TMP + * utBox__ + * data:/CEC/test + */ enum class CecDataPathType : u32 { - CEC_PATH_MBOX_LIST = 1, - CEC_PATH_MBOX_INFO = 2, - CEC_PATH_INBOX_INFO = 3, - CEC_PATH_OUTBOX_INFO = 4, - CEC_PATH_OUTBOX_INDEX = 5, - CEC_PATH_INBOX_MSG = 6, - CEC_PATH_OUTBOX_MSG = 7, - CEC_PATH_ROOT_DIR = 10, - CEC_PATH_MBOX_DIR = 11, - CEC_PATH_INBOX_DIR = 12, - CEC_PATH_OUTBOX_DIR = 13, - CEC_MBOX_DATA = 100, - CEC_MBOX_ICON = 101, - CEC_MBOX_TITLE = 110, + CEC_PATH_INVALID = 0, + CEC_PATH_MBOX_LIST = 1, /// data:/CEC/MBoxList____ + CEC_PATH_MBOX_INFO = 2, /// data:/CEC//MBoxInfo____ + CEC_PATH_INBOX_INFO = 3, /// data:/CEC//InBox___/BoxInfo_____ + CEC_PATH_OUTBOX_INFO = 4, /// data:/CEC//OutBox__/BoxInfo_____ + CEC_PATH_OUTBOX_INDEX = 5, /// data:/CEC//OutBox__/OBIndex_____ + CEC_PATH_INBOX_MSG = 6, /// data:/CEC//InBox___/_ + CEC_PATH_OUTBOX_MSG = 7, /// data:/CEC//OutBox__/_ + CEC_PATH_ROOT_DIR = 10, /// data:/CEC + CEC_PATH_MBOX_DIR = 11, /// data:/CEC/ + CEC_PATH_INBOX_DIR = 12, /// data:/CEC//InBox___ + CEC_PATH_OUTBOX_DIR = 13, /// data:/CEC//OutBox__ + CEC_MBOX_DATA = 100, /// data:/CEC//MBoxData.0 + CEC_MBOX_ICON = 101, /// data:/CEC//MBoxData.001 + CEC_MBOX_TITLE = 110, /// data:/CEC//MBoxData.010 + CEC_MBOX_PROGRAM_ID = 150, /// data:/CEC//MBoxData.050 }; - class Interface : public ServiceFramework { + enum class CecState : u32 { + CEC_STATE_NONE = 0, + CEC_STATE_INIT = 1, + CEC_STATE_WIRELESS_PARAM_SETUP = 2, + CEC_STATE_WIRELESS_READY = 3, + CEC_STATE_WIRELESS_START_CONFIG = 4, + CEC_STATE_SCAN = 5, + CEC_STATE_SCANNING = 6, + CEC_STATE_CONNECT = 7, + CEC_STATE_CONNECTING = 8, + CEC_STATE_CONNECTED = 9, + CEC_STATE_CONNECT_TCP = 10, + CEC_STATE_CONNECTING_TCP = 11, + CEC_STATE_CONNECTED_TCP = 12, + CEC_STATE_NEGOTIATION = 13, + CEC_STATE_SEND_RECV_START = 14, + CEC_STATE_SEND_RECV_INIT = 15, + CEC_STATE_SEND_READY = 16, + CEC_STATE_RECEIVE_READY = 17, + CEC_STATE_RECEIVE = 18, + CEC_STATE_CONNECTION_FINISH_TCP = 19, + CEC_STATE_CONNECTION_FINISH = 20, + CEC_STATE_SEND_POST = 21, + CEC_STATE_RECEIVE_POST = 22, + CEC_STATE_FINISHING = 23, + CEC_STATE_FINISH = 24, + CEC_STATE_OVER_BOSS = 25, + CEC_STATE_IDLE = 26 + }; + + /// Need to confirm if CecStateAbbreviated is up-to-date and valid + enum class CecStateAbbreviated : u32 { + CEC_STATE_ABBREV_IDLE = 1, /// Relates to CEC_STATE_IDLE + CEC_STATE_ABBREV_NOT_LOCAL = 2, /// Relates to CEC_STATEs *FINISH*, *POST, and OVER_BOSS + CEC_STATE_ABBREV_SCANNING = 3, /// Relates to CEC_STATE_SCANNING + CEC_STATE_ABBREV_WLREADY = 4, /// Relates to CEC_STATE_WIRELESS_READY when a bool is true + CEC_STATE_ABBREV_OTHER = 5, /// Relates to CEC_STATEs besides *FINISH*, *POST, and + }; /// OVER_BOSS and those listed here + + enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; + + struct CecInOutBoxInfoHeader { + u16_le magic; // bb + u16_le padding; + u32_le box_info_size; + u32_le max_box_size; + u32_le box_size; + u32_le max_message_num; + u32_le message_num; + u32_le max_batch_size; + u32_le max_message_size; + }; + static_assert(sizeof(CecInOutBoxInfoHeader) == 0x20, + "CecInOutBoxInfoHeader struct has incorrect size."); + + struct CecMessageHeader { + u16_le magic; // `` + u16_le padding; + u32_le message_size; + u32_le header_size; + u32_le body_size; + + u32_le title_id; + u32_le title_id_2; + u32_le batch_id; + u32_le unknown_id; + + u8 message_id[8]; + u32_le version; + u8 message_id_2[8]; + u8 flag; + u8 send_method; + u8 is_unopen; + u8 is_new; + u64_le sender_id; + u64_le sender_id2; + struct Time { + u32_le a, b, c; + } send_time, recv_time, create_time; + u8 send_count; + u8 foward_count; + u16_le user_data; + }; + static_assert(sizeof(CecMessageHeader) == 0x70, "CecMessageHeader struct has incorrect size."); + + enum class CecNdmStatus : u32 { + NDM_STATUS_WORKING = 0, + NDM_STATUS_IDLE = 1, + NDM_STATUS_SUSPENDING = 2, + NDM_STATUS_SUSPENDED = 3, + }; + + union CecOpenMode { + u32 raw; + BitField<1, 1, u32> read; + BitField<2, 1, u32> write; + BitField<3, 1, u32> make_dir; + BitField<4, 1, u32> skip_check; /// or is it check/test? + BitField<30, 1, u32> unk_flag; + }; + + enum class CecTest : u32 { + CEC_TEST_000 = 0, + CEC_TEST_001 = 1, + CEC_TEST_002 = 2, + CEC_TEST_003 = 3, + CEC_TEST_004 = 4, + CEC_TEST_005 = 5, + CEC_TEST_006 = 6, + }; + + /// Opening a file and reading/writing can be handled by two different functions + /// So, we need to pass that file data around + struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase { + SessionData(); + ~SessionData(); + + u32 ncch_program_id; + CecDataPathType data_path_type; + CecOpenMode open_mode; + FileSys::Path path; + + std::shared_ptr file; + }; + + class Interface : public ServiceFramework { public: Interface(std::shared_ptr cecd, const char* name, u32 max_session); ~Interface() = default; @@ -107,7 +234,7 @@ public: * Inputs: * 0 : Header Code[0x00030104] * 1 : NCCH Program ID - * 2 : bool is_out_box? + * 2 : bool is_outbox * 3 : Message ID size (unused, always 8) * 4 : Buffer size (unused) * 5 : Descriptor for mapping a read-only buffer in the target process @@ -129,7 +256,7 @@ public: * Inputs: * 0 : Header Code[0x00040106] * 1 : NCCH Program ID - * 2 : bool is_out_box? + * 2 : bool is_outbox * 3 : Message ID size(unused, always 8) * 4 : Buffer size(unused) * 5 : Descriptor for mapping a read-only buffer in the target process @@ -169,7 +296,7 @@ public: * Inputs: * 0 : Header Code[0x00060104] * 1 : NCCH Program ID - * 2 : bool is_out_box? + * 2 : bool is_outbox * 3 : Message ID size(unused, always 8) * 4 : Buffer size(unused) * 5 : Descriptor for mapping a read-only buffer in the target process @@ -190,7 +317,7 @@ public: * Inputs: * 0 : Header Code[0x00070106] * 1 : NCCH Program ID - * 2 : bool is_out_box? + * 2 : bool is_outbox * 3 : Message ID size(unused, always 8) * 4 : Buffer size(unused) * 5 : Descriptor for mapping a read-only buffer in the target process @@ -216,7 +343,7 @@ public: * 0 : Header Code[0x00080102] * 1 : NCCH Program ID * 2 : Path type - * 3 : bool is_out_box? + * 3 : bool is_outbox * 4 : Message ID size (unused) * 5 : Descriptor for mapping a read-only buffer in the target process * 6 : Message ID address @@ -227,6 +354,22 @@ public: */ void Delete(Kernel::HLERequestContext& ctx); + /** + * CECD::Cecd_0x000900C2 service function + * Inputs: + * 0 : Header Code[0x000900C2] + * 1 : NCCH Program ID + * 2 : Path type + * 3 : bool is_outbox + * 4 : Descriptor for mapping a read-only buffer in the target process + * 5 : Message ID address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Descriptor for mapping a read-only buffer in the target process + * 3 : Message ID address + */ + void Cecd_0x000900C2(Kernel::HLERequestContext& ctx); + /** * CECD::GetSystemInfo service function * Inputs: @@ -318,7 +461,7 @@ public: * 1 : Buffer size (unused) * 2 : NCCH Program ID * 3 : Path type - * 4 : File open flag? + * 4 : File open flag * 5 : Descriptor for process ID * 6 : Placeholder for process ID * 7 : Descriptor for mapping a read-only buffer in the target process @@ -337,7 +480,7 @@ public: * 1 : Buffer size (unused) * 2 : NCCH Program ID * 3 : Path type - * 4 : File open flag? + * 4 : File open flag * 5 : Descriptor for process ID * 6 : Placeholder for process ID * 7 : Descriptor for mapping a write-only buffer in the target process @@ -379,12 +522,18 @@ public: }; private: - std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, - const std::vector& message_id = std::vector()); + const std::vector cecd_system_savedata_id = {0x00, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x01, 0x00}; - const std::vector cecd_system_savedata_id = { - 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x01, 0x00 - }; + /// String used by cecd for base64 encoding found in the sysmodule disassembly + const std::string base64_dict = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; + + /// Encoding function used for the message id + std::string EncodeBase64(const std::vector& in, const std::string& dictionary) const; + + std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, + const std::vector& msg_id = std::vector()) const; Service::FS::ArchiveHandle cecd_system_save_data_archive; diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp index e8d6546c6..b736c689b 100644 --- a/src/core/hle/service/cecd/cecd_s.cpp +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -20,9 +20,11 @@ CECD_S::CECD_S(std::shared_ptr cecd) {0x00060104, &CECD_S::WriteMessage, "WriteMessage"}, {0x00070106, &CECD_S::WriteMessageWithHMAC, "WriteMessageWithHMAC"}, {0x00080102, &CECD_S::Delete, "Delete"}, + {0x000900C2, &CECD_S::Cecd_0x000900C2, "Cecd_0x000900C2"}, {0x000A00C4, &CECD_S::GetSystemInfo, "GetSystemInfo"}, - {0x000B0040, nullptr, "RunCommand"}, - {0x000C0040, nullptr, "RunCommandAlt"}, + {0x000B0040, &CECD_S::RunCommand, "RunCommand"}, + {0x000C0040, &CECD_S::RunCommandAlt, "RunCommandAlt"}, + {0x000D0082, nullptr, "GetCecInfoBuffer"}, {0x000E0000, &CECD_S::GetCecStateAbbreviated, "GetCecStateAbbreviated"}, {0x000F0000, &CECD_S::GetCecInfoEventHandle, "GetCecInfoEventHandle"}, {0x00100000, &CECD_S::GetChangeStateEventHandle, "GetChangeStateEventHandle"}, diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp index f89563116..e12b3dde0 100644 --- a/src/core/hle/service/cecd/cecd_u.cpp +++ b/src/core/hle/service/cecd/cecd_u.cpp @@ -20,9 +20,11 @@ CECD_U::CECD_U(std::shared_ptr cecd) {0x00060104, &CECD_U::WriteMessage, "WriteMessage"}, {0x00070106, &CECD_U::WriteMessageWithHMAC, "WriteMessageWithHMAC"}, {0x00080102, &CECD_U::Delete, "Delete"}, + {0x000900C2, &CECD_U::Cecd_0x000900C2, "Cecd_0x000900C2"}, {0x000A00C4, &CECD_U::GetSystemInfo, "GetSystemInfo"}, - {0x000B0040, nullptr, "RunCommand"}, - {0x000C0040, nullptr, "RunCommandAlt"}, + {0x000B0040, &CECD_U::RunCommand, "RunCommand"}, + {0x000C0040, &CECD_U::RunCommandAlt, "RunCommandAlt"}, + {0x000D0082, nullptr, "GetCecInfoBuffer"}, {0x000E0000, &CECD_U::GetCecStateAbbreviated, "GetCecStateAbbreviated"}, {0x000F0000, &CECD_U::GetCecInfoEventHandle, "GetCecInfoEventHandle"}, {0x00100000, &CECD_U::GetChangeStateEventHandle, "GetChangeStateEventHandle"}, From e27c1bd1f5afd34418c09321700055e9af3a7770 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Tue, 7 Aug 2018 13:45:11 -0400 Subject: [PATCH 04/21] service/cecd: Addressed comment about PopEnum --- src/core/hle/service/cecd/cecd.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index c003e547a..eb4aaca66 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -27,7 +27,7 @@ using CecSystemInfoType = Module::CecSystemInfoType; void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x01, 3, 2); const u32 ncch_program_id = rp.Pop(); - const auto path_type = static_cast(rp.Pop()); + const CecDataPathType path_type = rp.PopEnum(); CecOpenMode open_mode; open_mode.raw = rp.Pop(); rp.PopPID(); @@ -243,7 +243,7 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x08, 4, 2); const u32 ncch_program_id = rp.Pop(); - const auto path_type = static_cast(rp.Pop()); + const CecDataPathType path_type = rp.PopEnum(); const bool is_outbox = rp.Pop(); const u32 message_id_size = rp.Pop(); auto& message_id_buffer = rp.PopMappedBuffer(); @@ -276,7 +276,7 @@ void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0A, 3, 4); const u32 dest_buffer_size = rp.Pop(); - const CecSystemInfoType info_type = static_cast(rp.Pop()); + const CecSystemInfoType info_type = rp.PopEnum(); const u32 param_buffer_size = rp.Pop(); auto& param_buffer = rp.PopMappedBuffer(); auto& dest_buffer = rp.PopMappedBuffer(); @@ -313,7 +313,7 @@ void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { void Module::Interface::RunCommand(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0B, 1, 0); - const auto command = static_cast(rp.Pop()); + const CecCommand command = rp.PopEnum(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); @@ -323,7 +323,7 @@ void Module::Interface::RunCommand(Kernel::HLERequestContext& ctx) { void Module::Interface::RunCommandAlt(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0C, 1, 0); - const auto command = static_cast(rp.Pop()); + const CecCommand command = rp.PopEnum(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); @@ -365,7 +365,7 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x11, 4, 4); const u32 buffer_size = rp.Pop(); const u32 ncch_program_id = rp.Pop(); - const auto path_type = static_cast(rp.Pop()); + const CecDataPathType path_type = rp.PopEnum(); CecOpenMode open_mode; open_mode.raw = rp.Pop(); rp.PopPID(); @@ -415,7 +415,7 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x12, 4, 4); const u32 buffer_size = rp.Pop(); const u32 ncch_program_id = rp.Pop(); - const auto path_type = static_cast(rp.Pop()); + const CecDataPathType path_type = rp.PopEnum(); CecOpenMode open_mode; open_mode.raw = rp.Pop(); rp.PopPID(); From 30bbea3f4e13fa6d4c38e67f6d9d6c626cad149b Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Sun, 12 Aug 2018 03:26:45 -0400 Subject: [PATCH 05/21] service/cecd: Add initial files to archive after it is formatted --- src/core/hle/service/cecd/cecd.cpp | 65 +++++++++++++++++++++++++++++- src/core/hle/service/cecd/cecd.h | 1 - 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index eb4aaca66..5d4dd8f8b 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -298,7 +298,7 @@ void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { dest_buffer.Write(buffer.data(), 0, buffer.size()); break; default: - LOG_ERROR(Service_CECD, "Unknown system info type {}", static_cast(info_type)); + LOG_ERROR(Service_CECD, "Unknown system info type={}", static_cast(info_type)); } rb.Push(RESULT_SUCCESS); @@ -454,10 +454,18 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); if (path_type == CecDataPathType::CEC_PATH_MBOX_INFO) { + const FileSys::Path root_dir_path( + cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, + ncch_program_id) + .data()); const FileSys::Path mbox_path( cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, ncch_program_id) .data()); + + /// Just in case the root dir /CEC doesn't exist, we try to create it first + Service::FS::CreateDirectoryFromArchive(cecd->cecd_system_save_data_archive, + root_dir_path); Service::FS::CreateDirectoryFromArchive(cecd->cecd_system_save_data_archive, mbox_path); } @@ -565,6 +573,61 @@ Module::Module() { // Open it again to get a valid archive now that the folder exists archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); + + /// Now that the archive is formatted, we need to create the root CEC directory, + /// eventlog.dat, and CEC/MBoxList____ + const FileSys::Path root_dir_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, 0).data()); + Service::FS::CreateDirectoryFromArchive(*archive_result, root_dir_path); + + FileSys::Mode mode; + mode.write_flag.Assign(1); + mode.create_flag.Assign(1); + + /// eventlog.dat resides in the root of the archive beside the CEC directory + /// Initially created, at offset 0x0, are bytes 0x01 0x41 0x12, followed by + /// zeroes until offset 0x1000, where it changes to 0xDD until the end of file + /// at offset 0x30d53 + FileSys::Path eventlog_path("/eventlog.dat"); + + auto eventlog_result = + Service::FS::OpenFileFromArchive(*archive_result, eventlog_path, mode); + + constexpr u32 eventlog_size = 0x30d54; + auto eventlog = eventlog_result.Unwrap(); + std::vector eventlog_buffer(eventlog_size); + + std::memset(&eventlog_buffer[0], 0, 0x1000); + eventlog_buffer[0] = 0x01; + eventlog_buffer[1] = 0x41; + eventlog_buffer[2] = 0x12; + std::memset(&eventlog_buffer[0x1000], 0xDD, eventlog_size - 0x1000); + + eventlog->backend->Write(0, eventlog_size, true, eventlog_buffer.data()).Unwrap(); + eventlog->backend->Close(); + + /// MBoxList____ resides within the root CEC/ directory. + /// Initially created, at offset 0x0, are bytes 0x68 0x68 0x00 0x00 0x01, with 0x6868 'hh', + /// being the magic number. The rest of the file is filled with zeroes, until the end of + /// file at offset 0x18b + FileSys::Path mboxlist_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_LIST, 0).data()); + + auto mboxlist_result = + Service::FS::OpenFileFromArchive(*archive_result, mboxlist_path, mode); + + constexpr u32 mboxlist_size = 0x18c; + auto mboxlist = mboxlist_result.Unwrap(); + std::vector mboxlist_buffer(mboxlist_size); + + std::memset(&mboxlist_buffer[0], 0, mboxlist_size); + mboxlist_buffer[0] = 0x68; + mboxlist_buffer[1] = 0x68; + /// mboxlist_buffer[2-3] are already zeroed + mboxlist_buffer[4] = 0x01; + + mboxlist->backend->Write(0, mboxlist_size, true, mboxlist_buffer.data()).Unwrap(); + mboxlist->backend->Close(); } ASSERT_MSG(archive_result.Succeeded(), "Could not open the CECD SystemSaveData archive!"); diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 95c977da6..37e6df0d1 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -46,7 +46,6 @@ public: * CecDataPathType possible missing values; need to figure out placement * * data:/CEC/TMP - * utBox__ * data:/CEC/test */ enum class CecDataPathType : u32 { From d99585aa5374dc9e60be075a3db4241c8bddeba6 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Tue, 14 Aug 2018 03:41:14 -0400 Subject: [PATCH 06/21] service/cecd: Add MBox directory check to OpenAndRead and OpenAndWrite and added a CreateAndPopulateMBoxDirectory function --- src/core/hle/service/cecd/cecd.cpp | 184 ++++++++++++++++++++++++++--- src/core/hle/service/cecd/cecd.h | 2 + 2 files changed, 171 insertions(+), 15 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 5d4dd8f8b..cf19b6a51 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -400,6 +400,18 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } else { LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); + + /// We need to check if the MBox /CEC/ directory even exists... + /// If it doesn't, we create and populate it. + const FileSys::Path mbox_path( + cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, + ncch_program_id) + .data()); + auto mbox_result = Service::FS::OpenDirectoryFromArchive( + cecd->cecd_system_save_data_archive, mbox_path); + if (mbox_result.Failed()) + cecd->CreateAndPopulateMBoxDirectory(ncch_program_id); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); } @@ -453,22 +465,19 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { } else { LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); - if (path_type == CecDataPathType::CEC_PATH_MBOX_INFO) { - const FileSys::Path root_dir_path( - cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, - ncch_program_id) - .data()); - const FileSys::Path mbox_path( - cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, - ncch_program_id) - .data()); + /// We need to check if the MBox /CEC/ directory even exists... + /// If it doesn't, we create and populate it. + const FileSys::Path mbox_path( + cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, + ncch_program_id) + .data()); + auto mbox_result = Service::FS::OpenDirectoryFromArchive( + cecd->cecd_system_save_data_archive, mbox_path); + if (mbox_result.Failed()) + cecd->CreateAndPopulateMBoxDirectory(ncch_program_id); - /// Just in case the root dir /CEC doesn't exist, we try to create it first - Service::FS::CreateDirectoryFromArchive(cecd->cecd_system_save_data_archive, - root_dir_path); - Service::FS::CreateDirectoryFromArchive(cecd->cecd_system_save_data_archive, - mbox_path); - } + /// Since the directories/files didn't exist before, we still push a failure + /// A second attempt will then be called, and now everything exists. rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); rb.Push(0); /// No bytes read @@ -544,6 +553,151 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const } } +void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { + const FileSys::Path root_dir_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, ncch_program_id).data()); + const FileSys::Path mbox_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, ncch_program_id).data()); + const FileSys::Path inbox_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_DIR, ncch_program_id).data()); + const FileSys::Path outbox_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_DIR, ncch_program_id).data()); + + /// Just in case the root dir /CEC doesn't exist, we try to create it first + Service::FS::CreateDirectoryFromArchive(cecd_system_save_data_archive, root_dir_path); + Service::FS::CreateDirectoryFromArchive(cecd_system_save_data_archive, mbox_path); + Service::FS::CreateDirectoryFromArchive(cecd_system_save_data_archive, inbox_path); + Service::FS::CreateDirectoryFromArchive(cecd_system_save_data_archive, outbox_path); + + /// Now that the directories have been created, we can create the required files + FileSys::Mode mode; + mode.write_flag.Assign(1); + mode.create_flag.Assign(1); + + /// MBoxInfo____ resides in the MBox /CEC/ directory, + /// The Magic number is 0x6363 'cc', and has size 0x60 + FileSys::Path mbox_info_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_INFO, ncch_program_id).data()); + + auto mbox_info_result = + Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_info_path, mode); + + constexpr u32 mbox_info_size = 0x60; + auto mbox_info = mbox_info_result.Unwrap(); + std::vector mbox_info_buffer(mbox_info_size); + + std::memset(&mbox_info_buffer[0], 0, mbox_info_size); + mbox_info_buffer[0] = 0x63; + mbox_info_buffer[1] = 0x63; + + mbox_info->backend->Write(0, mbox_info_size, true, mbox_info_buffer.data()); + mbox_info->backend->Close(); + + /// BoxInfo_____ resides in both the InBox and OutBox directories, + /// The Magic number is 0x6262 'bb', and has size 0x20 + FileSys::Path inbox_info_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_INFO, ncch_program_id).data()); + + auto inbox_info_result = + Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, inbox_info_path, mode); + + constexpr u32 inbox_info_size = 0x20; + auto inbox_info = inbox_info_result.Unwrap(); + std::vector inbox_info_buffer(inbox_info_size); + + std::memset(&inbox_info_buffer[0], 0, inbox_info_size); + inbox_info_buffer[0] = 0x62; + inbox_info_buffer[1] = 0x62; + + inbox_info->backend->Write(0, inbox_info_size, true, inbox_info_buffer.data()); + inbox_info->backend->Close(); + + /// BoxInfo_____ resides in both the InBox and OutBox directories, + /// The Magic number is 0x6262 'bb', and has size 0x20-byte header, and an array of 0x70-byte + /// entries. Each entry is a copy of the message header. + FileSys::Path outbox_info_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_INFO, ncch_program_id).data()); + + auto outbox_info_result = + Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, outbox_info_path, mode); + + constexpr u32 outbox_info_size = 0x20; + auto outbox_info = outbox_info_result.Unwrap(); + std::vector outbox_info_buffer(outbox_info_size); + + std::memset(&outbox_info_buffer[0], 0, outbox_info_size); + outbox_info_buffer[0] = 0x62; + outbox_info_buffer[1] = 0x62; + + outbox_info->backend->Write(0, outbox_info_size, true, outbox_info_buffer.data()); + outbox_info->backend->Close(); + + /// OBIndex_____ resides in the OutBox directory, + /// Unknown... + FileSys::Path outbox_index_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_INDEX, ncch_program_id).data()); + + auto outbox_index_result = + Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, outbox_index_path, mode); + + constexpr u32 outbox_index_size = 0x32; + auto outbox_index = outbox_index_result.Unwrap(); + std::vector outbox_index_buffer(outbox_index_size); + + std::memset(&outbox_index_buffer[0], 0, outbox_index_size); + + outbox_index->backend->Write(0, outbox_index_size, true, outbox_index_buffer.data()); + outbox_index->backend->Close(); + + /// MBoxData.001 resides in the MBox /CEC/ directory and contains the icon of the app + FileSys::Path mbox_icon_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_MBOX_ICON, ncch_program_id).data()); + + auto mbox_icon_result = + Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_icon_path, mode); + + constexpr u32 mbox_icon_size = 0x1200; + auto mbox_icon = mbox_icon_result.Unwrap(); + std::vector mbox_icon_buffer(mbox_icon_size); + + std::memset(&mbox_icon_buffer[0], 0, mbox_icon_size); + + mbox_icon->backend->Write(0, mbox_icon_size, true, mbox_icon_buffer.data()); + mbox_icon->backend->Close(); + + /// MBoxData.010 resides in the MBox /CEC/ directory and contains the title of the app + /// in null-terminated UTF-16 string. + FileSys::Path mbox_title_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_MBOX_TITLE, ncch_program_id).data()); + + auto mbox_title_result = + Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_title_path, mode); + + constexpr u32 mbox_title_size = 0x32; + auto mbox_title = mbox_title_result.Unwrap(); + std::vector mbox_title_buffer(mbox_title_size); + + std::memset(&mbox_title_buffer[0], 0, mbox_title_size); + + mbox_title->backend->Write(0, mbox_title_size, true, mbox_title_buffer.data()); + mbox_title->backend->Close(); + + /// MBoxData.050 resides in the MBox /CEC/ directory and contains the program id of the app + FileSys::Path mbox_program_id_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_MBOX_PROGRAM_ID, ncch_program_id).data()); + + auto mbox_program_id_result = + Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_program_id_path, mode); + auto mbox_program_id = mbox_program_id_result.Unwrap(); + + std::vector program_id_buffer(8); + u64_le le_program_id = Kernel::g_current_process->codeset->program_id; + std::memcpy(program_id_buffer.data(), &le_program_id, sizeof(u64)); + + mbox_program_id->backend->Write(0, sizeof(u64), true, program_id_buffer.data()); + mbox_program_id->backend->Close(); +} + Module::SessionData::SessionData() {} Module::SessionData::~SessionData() { diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 37e6df0d1..e3573b24d 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -534,6 +534,8 @@ private: std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, const std::vector& msg_id = std::vector()) const; + void CreateAndPopulateMBoxDirectory(const u32 ncch_program_id); + Service::FS::ArchiveHandle cecd_system_save_data_archive; Kernel::SharedPtr cecinfo_event; From 010fbd8614dd97ed8e4a2a9fa3d07ab3706f69f4 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Tue, 14 Aug 2018 17:57:13 -0400 Subject: [PATCH 07/21] service/cecd: Update default values for in/out box info header --- src/core/hle/service/cecd/cecd.cpp | 41 ++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index cf19b6a51..8b2ce0f72 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -594,7 +594,8 @@ void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { mbox_info->backend->Close(); /// BoxInfo_____ resides in both the InBox and OutBox directories, - /// The Magic number is 0x6262 'bb', and has size 0x20 + /// The Magic number is 0x6262 'bb', and has size 0x20-byte header, and an array of 0x70-byte + /// entries. Each entry is a copy of the message header. FileSys::Path inbox_info_path( GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_INFO, ncch_program_id).data()); @@ -605,11 +606,19 @@ void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { auto inbox_info = inbox_info_result.Unwrap(); std::vector inbox_info_buffer(inbox_info_size); - std::memset(&inbox_info_buffer[0], 0, inbox_info_size); - inbox_info_buffer[0] = 0x62; - inbox_info_buffer[1] = 0x62; + CecInOutBoxInfoHeader inbox_info_header = {}; + std::memset(&inbox_info_header, 0, sizeof(CecInOutBoxInfoHeader)); - inbox_info->backend->Write(0, inbox_info_size, true, inbox_info_buffer.data()); + inbox_info_header.magic = 0x6262; + inbox_info_header.box_info_size = 0x20; + inbox_info_header.max_box_size = 0xC3000; + inbox_info_header.box_size = 0x00; + inbox_info_header.max_message_num = 0x0A; + inbox_info_header.message_num = 0x00; + inbox_info_header.max_batch_size = 0x0A; + inbox_info_header.max_message_size = 0x019000; + + inbox_info->backend->Write(0, inbox_info_size, true, (u8*)&inbox_info_header); inbox_info->backend->Close(); /// BoxInfo_____ resides in both the InBox and OutBox directories, @@ -625,26 +634,36 @@ void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { auto outbox_info = outbox_info_result.Unwrap(); std::vector outbox_info_buffer(outbox_info_size); - std::memset(&outbox_info_buffer[0], 0, outbox_info_size); - outbox_info_buffer[0] = 0x62; - outbox_info_buffer[1] = 0x62; + CecInOutBoxInfoHeader outbox_info_header = {}; + std::memset(&outbox_info_header, 0, sizeof(CecInOutBoxInfoHeader)); - outbox_info->backend->Write(0, outbox_info_size, true, outbox_info_buffer.data()); + outbox_info_header.magic = 0x6262; + outbox_info_header.box_info_size = 0x20; + outbox_info_header.max_box_size = 0xC000; + outbox_info_header.box_size = 0x00; + outbox_info_header.max_message_num = 0x01; + outbox_info_header.message_num = 0x00; + outbox_info_header.max_batch_size = 0x01; + outbox_info_header.max_message_size = 0x019000; + + outbox_info->backend->Write(0, outbox_info_size, true, (u8*)&outbox_info_header); outbox_info->backend->Close(); /// OBIndex_____ resides in the OutBox directory, - /// Unknown... + /// The magic number is 0x6767 'gg', and the total size is 0x10 FileSys::Path outbox_index_path( GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_INDEX, ncch_program_id).data()); auto outbox_index_result = Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, outbox_index_path, mode); - constexpr u32 outbox_index_size = 0x32; + constexpr u32 outbox_index_size = 0x10; auto outbox_index = outbox_index_result.Unwrap(); std::vector outbox_index_buffer(outbox_index_size); std::memset(&outbox_index_buffer[0], 0, outbox_index_size); + outbox_index_buffer[0] = 0x67; + outbox_index_buffer[1] = 0x67; outbox_index->backend->Write(0, outbox_index_size, true, outbox_index_buffer.data()); outbox_index->backend->Close(); From d88ad61da4489415b55ab66f33ee281d631dc7ba Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Wed, 15 Aug 2018 01:47:33 -0400 Subject: [PATCH 08/21] service/cecd: Output icon to MBoxData.001 and title to MBoxData.010 --- src/core/hle/service/cecd/cecd.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 8b2ce0f72..4d04267d2 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -5,6 +5,7 @@ #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" +#include "core/core.h" #include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" #include "core/file_sys/errors.h" @@ -16,6 +17,7 @@ #include "core/hle/service/cecd/cecd_ndm.h" #include "core/hle/service/cecd/cecd_s.h" #include "core/hle/service/cecd/cecd_u.h" +#include "core/loader/smdh.h" namespace Service { namespace CECD { @@ -675,13 +677,13 @@ void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { auto mbox_icon_result = Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_icon_path, mode); - constexpr u32 mbox_icon_size = 0x1200; + std::vector mbox_icon_buffer; + Core::System::GetInstance().GetAppLoader().ReadIcon(mbox_icon_buffer); + + const u32 mbox_icon_size = mbox_icon_buffer.size() - 0x24C0; // offset where icon starts auto mbox_icon = mbox_icon_result.Unwrap(); - std::vector mbox_icon_buffer(mbox_icon_size); - std::memset(&mbox_icon_buffer[0], 0, mbox_icon_size); - - mbox_icon->backend->Write(0, mbox_icon_size, true, mbox_icon_buffer.data()); + mbox_icon->backend->Write(0, mbox_icon_size, true, &mbox_icon_buffer[0x24C0]); mbox_icon->backend->Close(); /// MBoxData.010 resides in the MBox /CEC/ directory and contains the title of the app @@ -692,11 +694,16 @@ void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { auto mbox_title_result = Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_title_path, mode); - constexpr u32 mbox_title_size = 0x32; + std::string title_name; + Core::System::GetInstance().GetAppLoader().ReadTitle(title_name); + + std::u16string program_name = Common::UTF8ToUTF16(title_name + '\0'); + + const u32 mbox_title_size = program_name.size(); auto mbox_title = mbox_title_result.Unwrap(); std::vector mbox_title_buffer(mbox_title_size); - std::memset(&mbox_title_buffer[0], 0, mbox_title_size); + std::memcpy(mbox_title_buffer.data(), program_name.data(), mbox_title_size); mbox_title->backend->Write(0, mbox_title_size, true, mbox_title_buffer.data()); mbox_title->backend->Close(); From 71204e525ff47dc446fb989046b7177f1327b36e Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Fri, 17 Aug 2018 02:32:48 -0400 Subject: [PATCH 09/21] service/cecd: Corrected behaviour, started checking and updating file headers --- src/core/hle/service/cecd/cecd.cpp | 506 +++++++++++++++++---------- src/core/hle/service/cecd/cecd.h | 52 ++- src/core/hle/service/cecd/cecd_s.cpp | 6 +- src/core/hle/service/cecd/cecd_u.cpp | 6 +- 4 files changed, 375 insertions(+), 195 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 4d04267d2..e96444d8f 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include +#include #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -26,7 +28,7 @@ using CecDataPathType = Module::CecDataPathType; using CecOpenMode = Module::CecOpenMode; using CecSystemInfoType = Module::CecSystemInfoType; -void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { +void Module::Interface::Open(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x01, 3, 2); const u32 ncch_program_id = rp.Pop(); const CecDataPathType path_type = rp.PopEnum(); @@ -55,11 +57,11 @@ void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { auto dir_result = Service::FS::OpenDirectoryFromArchive(cecd->cecd_system_save_data_archive, path); if (dir_result.Failed()) { - if (open_mode.make_dir) { + if (open_mode.create) { Service::FS::CreateDirectoryFromArchive(cecd->cecd_system_save_data_archive, path); rb.Push(RESULT_SUCCESS); } else { - LOG_ERROR(Service_CECD, "Failed to open directory: {}", path.AsString()); + LOG_DEBUG(Service_CECD, "Failed to open directory: {}", path.AsString()); rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); } @@ -75,7 +77,7 @@ void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { auto file_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); if (file_result.Failed()) { - LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); + LOG_DEBUG(Service_CECD, "Failed to open file: {}", path.AsString()); rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); rb.Push(0); /// No file size @@ -99,7 +101,7 @@ void Module::Interface::OpenRawFile(Kernel::HLERequestContext& ctx) { ncch_program_id, static_cast(path_type), open_mode.raw, path.AsString()); } -void Module::Interface::ReadRawFile(Kernel::HLERequestContext& ctx) { +void Module::Interface::ReadFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x02, 1, 2); const u32 write_buffer_size = rp.Pop(); auto& write_buffer = rp.PopMappedBuffer(); @@ -142,9 +144,42 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { auto& message_id_buffer = rp.PopMappedBuffer(); auto& write_buffer = rp.PopMappedBuffer(); + FileSys::Mode mode; + mode.read_flag.Assign(1); + + std::vector id_buffer(message_id_size); + message_id_buffer.Read(id_buffer.data(), 0, message_id_size); + + FileSys::Path message_path; + if (is_outbox) { + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } else { /// otherwise inbox + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } + + auto message_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, message_path, mode); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 4); - rb.Push(RESULT_SUCCESS); - rb.Push(0); /// Read size + if (message_result.Succeeded()) { + auto message = message_result.Unwrap(); + std::vector buffer(buffer_size); + + const u32 bytes_read = message->backend->Read(0, buffer_size, buffer.data()).Unwrap(); + write_buffer.Write(buffer.data(), 0, buffer_size); + message->backend->Close(); + + rb.Push(RESULT_SUCCESS); + rb.Push(bytes_read); + } else { + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + rb.Push(0); /// zero bytes read + } rb.PushMappedBuffer(message_id_buffer); rb.PushMappedBuffer(write_buffer); @@ -162,9 +197,43 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { auto& hmac_key_buffer = rp.PopMappedBuffer(); auto& write_buffer = rp.PopMappedBuffer(); + FileSys::Mode mode; + mode.read_flag.Assign(1); + + std::vector id_buffer(message_id_size); + message_id_buffer.Read(id_buffer.data(), 0, message_id_size); + + FileSys::Path message_path; + if (is_outbox) { + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } else { /// otherwise inbox + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } + + auto message_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, message_path, mode); + IPC::RequestBuilder rb = rp.MakeBuilder(2, 6); - rb.Push(RESULT_SUCCESS); - rb.Push(0); /// Read size + if (message_result.Succeeded()) { + auto message = message_result.Unwrap(); + std::vector buffer(buffer_size); + + const u32 bytes_read = message->backend->Read(0, buffer_size, buffer.data()).Unwrap(); + write_buffer.Write(buffer.data(), 0, buffer_size); + message->backend->Close(); + + rb.Push(RESULT_SUCCESS); + rb.Push(bytes_read); + } else { + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + rb.Push(0); /// zero bytes read + } + rb.PushMappedBuffer(message_id_buffer); rb.PushMappedBuffer(hmac_key_buffer); rb.PushMappedBuffer(write_buffer); @@ -173,7 +242,7 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { ncch_program_id, is_outbox); } -void Module::Interface::WriteRawFile(Kernel::HLERequestContext& ctx) { +void Module::Interface::WriteFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x05, 1, 2); const u32 read_buffer_size = rp.Pop(); auto& read_buffer = rp.PopMappedBuffer(); @@ -193,6 +262,11 @@ void Module::Interface::WriteRawFile(Kernel::HLERequestContext& ctx) { std::vector buffer(read_buffer_size); read_buffer.Read(buffer.data(), 0, read_buffer_size); + if (session_data->open_mode.check) { + cecd->CheckAndUpdateFile(session_data->data_path_type, session_data->ncch_program_id, + buffer); + } + const u32 bytes_written = session_data->file->backend->Write(0, read_buffer_size, true, buffer.data()).Unwrap(); session_data->file->backend->Close(); @@ -213,8 +287,43 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { auto& read_buffer = rp.PopMappedBuffer(); auto& message_id_buffer = rp.PopMappedBuffer(); + FileSys::Mode mode; + mode.write_flag.Assign(1); + mode.create_flag.Assign(1); + + std::vector id_buffer(message_id_size); + message_id_buffer.Read(id_buffer.data(), 0, message_id_size); + + FileSys::Path message_path; + if (is_outbox) { + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } else { /// otherwise inbox + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } + + auto message_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, message_path, mode); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); - rb.Push(RESULT_SUCCESS); + if (message_result.Succeeded()) { + auto message = message_result.Unwrap(); + std::vector buffer(buffer_size); + + read_buffer.Read(buffer.data(), 0, buffer_size); + const u32 bytes_written = + message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); + message->backend->Close(); + + rb.Push(RESULT_SUCCESS); + } else { + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + } + rb.PushMappedBuffer(read_buffer); rb.PushMappedBuffer(message_id_buffer); @@ -232,8 +341,43 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { auto& hmac_key_buffer = rp.PopMappedBuffer(); auto& message_id_buffer = rp.PopMappedBuffer(); + FileSys::Mode mode; + mode.write_flag.Assign(1); + mode.create_flag.Assign(1); + + std::vector id_buffer(message_id_size); + message_id_buffer.Read(id_buffer.data(), 0, message_id_size); + + FileSys::Path message_path; + if (is_outbox) { + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } else { /// otherwise inbox + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } + + auto message_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, message_path, mode); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 6); - rb.Push(RESULT_SUCCESS); + if (message_result.Succeeded()) { + auto message = message_result.Unwrap(); + std::vector buffer(buffer_size); + + read_buffer.Read(buffer.data(), 0, buffer_size); + const u32 bytes_written = + message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); + message->backend->Close(); + + rb.Push(RESULT_SUCCESS); + } else { + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, + ErrorLevel::Status)); + } + rb.PushMappedBuffer(read_buffer); rb.PushMappedBuffer(hmac_key_buffer); rb.PushMappedBuffer(message_id_buffer); @@ -250,6 +394,11 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { const u32 message_id_size = rp.Pop(); auto& message_id_buffer = rp.PopMappedBuffer(); + if (is_outbox) { + + } else { /// otherwise inbox + } + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushMappedBuffer(message_id_buffer); @@ -259,7 +408,7 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { ncch_program_id, static_cast(path_type), is_outbox); } -void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { +void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// DeleteFile? IPC::RequestParser rp(ctx, 0x09, 3, 2); const u32 ncch_program_id = rp.Pop(); const u32 size = rp.Pop(); @@ -308,7 +457,7 @@ void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(dest_buffer); LOG_DEBUG(Service_CECD, - "(STUBBED) called, dest_buffer_size={:#010x}, info_type={:#010x}, " + "called, dest_buffer_size={:#010x}, info_type={:#010x}, " "param_buffer_size={:#010x}", dest_buffer_size, static_cast(info_type), param_buffer_size); } @@ -393,26 +542,19 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { if (file_result.Succeeded()) { auto file = file_result.Unwrap(); std::vector buffer(buffer_size); - read_buffer.Read(buffer.data(), 0, buffer_size); + + if (open_mode.check) { + cecd->CheckAndUpdateFile(path_type, ncch_program_id, buffer); + } + const u32 bytes_written = file->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); file->backend->Close(); rb.Push(RESULT_SUCCESS); } else { - LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); - - /// We need to check if the MBox /CEC/ directory even exists... - /// If it doesn't, we create and populate it. - const FileSys::Path mbox_path( - cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, - ncch_program_id) - .data()); - auto mbox_result = Service::FS::OpenDirectoryFromArchive( - cecd->cecd_system_save_data_archive, mbox_path); - if (mbox_result.Failed()) - cecd->CreateAndPopulateMBoxDirectory(ncch_program_id); + LOG_DEBUG(Service_CECD, "Failed to open file: {}", path.AsString()); rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); @@ -438,8 +580,6 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { FileSys::Path path(cecd->GetCecDataPathTypeAsString(path_type, ncch_program_id).data()); FileSys::Mode mode; mode.read_flag.Assign(1); - mode.create_flag.Assign(1); - mode.write_flag.Assign(1); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); switch (path_type) { @@ -449,7 +589,7 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { case CecDataPathType::CEC_PATH_OUTBOX_DIR: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); - rb.Push(0); /// No bytes read + rb.Push(0); /// No entries read break; default: /// If not directory, then it is a file auto file_result = @@ -465,21 +605,8 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push(bytes_read); } else { - LOG_ERROR(Service_CECD, "Failed to open file: {}", path.AsString()); + LOG_DEBUG(Service_CECD, "Failed to open file: {}", path.AsString()); - /// We need to check if the MBox /CEC/ directory even exists... - /// If it doesn't, we create and populate it. - const FileSys::Path mbox_path( - cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, - ncch_program_id) - .data()); - auto mbox_result = Service::FS::OpenDirectoryFromArchive( - cecd->cecd_system_save_data_archive, mbox_path); - if (mbox_result.Failed()) - cecd->CreateAndPopulateMBoxDirectory(ncch_program_id); - - /// Since the directories/files didn't exist before, we still push a failure - /// A second attempt will then be called, and now everything exists. rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); rb.Push(0); /// No bytes read @@ -555,128 +682,161 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const } } -void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { - const FileSys::Path root_dir_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, ncch_program_id).data()); - const FileSys::Path mbox_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_DIR, ncch_program_id).data()); - const FileSys::Path inbox_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_DIR, ncch_program_id).data()); - const FileSys::Path outbox_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_DIR, ncch_program_id).data()); +void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, + std::vector& file_buffer) { + switch (path_type) { + case CecDataPathType::CEC_PATH_MBOX_LIST: + break; + case CecDataPathType::CEC_PATH_MBOX_INFO: { + CecMBoxInfoHeader mbox_info_header = {}; + std::memcpy(&mbox_info_header, file_buffer.data(), sizeof(CecMBoxInfoHeader)); - /// Just in case the root dir /CEC doesn't exist, we try to create it first - Service::FS::CreateDirectoryFromArchive(cecd_system_save_data_archive, root_dir_path); - Service::FS::CreateDirectoryFromArchive(cecd_system_save_data_archive, mbox_path); - Service::FS::CreateDirectoryFromArchive(cecd_system_save_data_archive, inbox_path); - Service::FS::CreateDirectoryFromArchive(cecd_system_save_data_archive, outbox_path); + if (file_buffer.size() != sizeof(CecMBoxInfoHeader)) { /// 0x60 + LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader size is incorrect"); + } - /// Now that the directories have been created, we can create the required files - FileSys::Mode mode; - mode.write_flag.Assign(1); - mode.create_flag.Assign(1); + if (mbox_info_header.magic != 0x6363) { /// 'cc' + LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader magic number is incorrect"); + } + if (mbox_info_header.program_id != static_cast(ncch_program_id)) { + LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader program id does not match current id"); + } + + break; + } + case CecDataPathType::CEC_PATH_INBOX_INFO: { + CecInOutBoxInfoHeader inbox_info_header = {}; + std::memcpy(&inbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); + + if (inbox_info_header.magic != 0x6262) { /// 'bb' + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader magic number is incorrect"); + inbox_info_header.magic = 0x6262; + } + + if (inbox_info_header.box_info_size != file_buffer.size()) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader box info size is incorrect"); + inbox_info_header.box_info_size = sizeof(CecInOutBoxInfoHeader); + } + + if (inbox_info_header.max_box_size > 0x100000) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max box size is incorrect"); + } + + if (inbox_info_header.max_message_num > 99) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max box size is incorrect"); + } + + if (inbox_info_header.max_message_size >= 0x019000) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max message size is incorrect"); + } + + if (inbox_info_header.max_batch_size == 0) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max batch size is not set"); + inbox_info_header.max_batch_size = inbox_info_header.max_message_num; + } + + std::memcpy(file_buffer.data(), &inbox_info_header, sizeof(CecInOutBoxInfoHeader)); + break; + } + case CecDataPathType::CEC_PATH_OUTBOX_INFO: { + CecInOutBoxInfoHeader outbox_info_header = {}; + std::memcpy(&outbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); + + if (outbox_info_header.magic != 0x6262) { /// 'bb' + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader magic number is incorrect"); + outbox_info_header.magic = 0x6262; + } + + if (outbox_info_header.box_info_size != file_buffer.size()) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is incorrect"); + outbox_info_header.box_info_size = sizeof(CecInOutBoxInfoHeader); + } + + if (outbox_info_header.max_box_size > 0x100000) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max box size is incorrect"); + } + + if (outbox_info_header.max_message_num > 99) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max box size is incorrect"); + } + + if (outbox_info_header.max_message_size >= 0x019000) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max message size is incorrect"); + } + + if (outbox_info_header.max_batch_size == 0) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max batch size is not set"); + outbox_info_header.max_batch_size = outbox_info_header.max_message_num; + } + + std::memcpy(file_buffer.data(), &outbox_info_header, sizeof(CecInOutBoxInfoHeader)); + break; + } + case CecDataPathType::CEC_PATH_OUTBOX_INDEX: + break; + case CecDataPathType::CEC_PATH_INBOX_MSG: + break; + case CecDataPathType::CEC_PATH_OUTBOX_MSG: + break; + case CecDataPathType::CEC_PATH_ROOT_DIR: + case CecDataPathType::CEC_PATH_MBOX_DIR: + case CecDataPathType::CEC_PATH_INBOX_DIR: + case CecDataPathType::CEC_PATH_OUTBOX_DIR: + break; + case CecDataPathType::CEC_MBOX_DATA: + case CecDataPathType::CEC_MBOX_ICON: + case CecDataPathType::CEC_MBOX_TITLE: + default: {} + } +} +/* /// MBoxInfo____ resides in the MBox /CEC/ directory, /// The Magic number is 0x6363 'cc', and has size 0x60 - FileSys::Path mbox_info_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_INFO, ncch_program_id).data()); - - auto mbox_info_result = - Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_info_path, mode); - constexpr u32 mbox_info_size = 0x60; auto mbox_info = mbox_info_result.Unwrap(); std::vector mbox_info_buffer(mbox_info_size); + u32_le le_ncch_program_id = ncch_program_id; - std::memset(&mbox_info_buffer[0], 0, mbox_info_size); - mbox_info_buffer[0] = 0x63; - mbox_info_buffer[1] = 0x63; + CecMBoxInfoHeader mbox_info_header = {}; + std::memset(&mbox_info_header, 0, sizeof(CecMBoxInfoHeader)); - mbox_info->backend->Write(0, mbox_info_size, true, mbox_info_buffer.data()); - mbox_info->backend->Close(); + auto now = std::chrono::system_clock::now(); + std::time_t now_time_t = std::chrono::system_clock::to_time_t(now); + std::tm* now_tm = std::localtime(&now_time_t); + + mbox_info_header.magic = 0x6363; + /// mbox_info_header.padding already zeroed + mbox_info_header.title_id = ncch_program_id; + /// mbox_info_header.private_id = unknown... + mbox_info_header.flag = 0x00; /// unknown + mbox_info_header.flag2 = 0x01; /// unknown + /// mbox_info_header.padding2 already zeroed + /// mbox_info_header.hmac_key = unknown... + /// mbox_info_header.padding3 already zeroed + mbox_info_header.last_accessed.year = static_cast(1900 + now_tm->tm_year); + mbox_info_header.last_accessed.month = static_cast(1 + now_tm->tm_mon); + mbox_info_header.last_accessed.day = static_cast(now_tm->tm_mday); + mbox_info_header.last_accessed.hour = static_cast(now_tm->tm_hour); + mbox_info_header.last_accessed.minute = static_cast(now_tm->tm_min); + mbox_info_header.last_accessed.second = static_cast(now_tm->tm_sec); + /// mbox_info_header.padding4 already zeroed + /// mbox_info_header.last_received = zeroed until receive? + /// mbox_info_header.padding5 already zeroed + /// mbox_info_header.unknown_time, might be sent-time, might be padding? /// BoxInfo_____ resides in both the InBox and OutBox directories, /// The Magic number is 0x6262 'bb', and has size 0x20-byte header, and an array of 0x70-byte /// entries. Each entry is a copy of the message header. - FileSys::Path inbox_info_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_INFO, ncch_program_id).data()); - - auto inbox_info_result = - Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, inbox_info_path, mode); - - constexpr u32 inbox_info_size = 0x20; - auto inbox_info = inbox_info_result.Unwrap(); - std::vector inbox_info_buffer(inbox_info_size); - - CecInOutBoxInfoHeader inbox_info_header = {}; - std::memset(&inbox_info_header, 0, sizeof(CecInOutBoxInfoHeader)); - - inbox_info_header.magic = 0x6262; - inbox_info_header.box_info_size = 0x20; - inbox_info_header.max_box_size = 0xC3000; - inbox_info_header.box_size = 0x00; - inbox_info_header.max_message_num = 0x0A; - inbox_info_header.message_num = 0x00; - inbox_info_header.max_batch_size = 0x0A; - inbox_info_header.max_message_size = 0x019000; - - inbox_info->backend->Write(0, inbox_info_size, true, (u8*)&inbox_info_header); - inbox_info->backend->Close(); /// BoxInfo_____ resides in both the InBox and OutBox directories, /// The Magic number is 0x6262 'bb', and has size 0x20-byte header, and an array of 0x70-byte /// entries. Each entry is a copy of the message header. - FileSys::Path outbox_info_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_INFO, ncch_program_id).data()); - - auto outbox_info_result = - Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, outbox_info_path, mode); - - constexpr u32 outbox_info_size = 0x20; - auto outbox_info = outbox_info_result.Unwrap(); - std::vector outbox_info_buffer(outbox_info_size); - - CecInOutBoxInfoHeader outbox_info_header = {}; - std::memset(&outbox_info_header, 0, sizeof(CecInOutBoxInfoHeader)); - - outbox_info_header.magic = 0x6262; - outbox_info_header.box_info_size = 0x20; - outbox_info_header.max_box_size = 0xC000; - outbox_info_header.box_size = 0x00; - outbox_info_header.max_message_num = 0x01; - outbox_info_header.message_num = 0x00; - outbox_info_header.max_batch_size = 0x01; - outbox_info_header.max_message_size = 0x019000; - - outbox_info->backend->Write(0, outbox_info_size, true, (u8*)&outbox_info_header); - outbox_info->backend->Close(); /// OBIndex_____ resides in the OutBox directory, /// The magic number is 0x6767 'gg', and the total size is 0x10 - FileSys::Path outbox_index_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_INDEX, ncch_program_id).data()); - - auto outbox_index_result = - Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, outbox_index_path, mode); - - constexpr u32 outbox_index_size = 0x10; - auto outbox_index = outbox_index_result.Unwrap(); - std::vector outbox_index_buffer(outbox_index_size); - - std::memset(&outbox_index_buffer[0], 0, outbox_index_size); - outbox_index_buffer[0] = 0x67; - outbox_index_buffer[1] = 0x67; - - outbox_index->backend->Write(0, outbox_index_size, true, outbox_index_buffer.data()); - outbox_index->backend->Close(); /// MBoxData.001 resides in the MBox /CEC/ directory and contains the icon of the app - FileSys::Path mbox_icon_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_MBOX_ICON, ncch_program_id).data()); - - auto mbox_icon_result = - Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_icon_path, mode); - std::vector mbox_icon_buffer; Core::System::GetInstance().GetAppLoader().ReadIcon(mbox_icon_buffer); @@ -688,12 +848,6 @@ void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { /// MBoxData.010 resides in the MBox /CEC/ directory and contains the title of the app /// in null-terminated UTF-16 string. - FileSys::Path mbox_title_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_MBOX_TITLE, ncch_program_id).data()); - - auto mbox_title_result = - Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_title_path, mode); - std::string title_name; Core::System::GetInstance().GetAppLoader().ReadTitle(title_name); @@ -702,20 +856,9 @@ void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { const u32 mbox_title_size = program_name.size(); auto mbox_title = mbox_title_result.Unwrap(); std::vector mbox_title_buffer(mbox_title_size); - std::memcpy(mbox_title_buffer.data(), program_name.data(), mbox_title_size); - mbox_title->backend->Write(0, mbox_title_size, true, mbox_title_buffer.data()); - mbox_title->backend->Close(); - /// MBoxData.050 resides in the MBox /CEC/ directory and contains the program id of the app - FileSys::Path mbox_program_id_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_MBOX_PROGRAM_ID, ncch_program_id).data()); - - auto mbox_program_id_result = - Service::FS::OpenFileFromArchive(cecd_system_save_data_archive, mbox_program_id_path, mode); - auto mbox_program_id = mbox_program_id_result.Unwrap(); - std::vector program_id_buffer(8); u64_le le_program_id = Kernel::g_current_process->codeset->program_id; std::memcpy(program_id_buffer.data(), &le_program_id, sizeof(u64)); @@ -723,6 +866,7 @@ void Module::CreateAndPopulateMBoxDirectory(const u32 ncch_program_id) { mbox_program_id->backend->Write(0, sizeof(u64), true, program_id_buffer.data()); mbox_program_id->backend->Close(); } +*/ Module::SessionData::SessionData() {} @@ -783,31 +927,35 @@ Module::Module() { eventlog_buffer[2] = 0x12; std::memset(&eventlog_buffer[0x1000], 0xDD, eventlog_size - 0x1000); - eventlog->backend->Write(0, eventlog_size, true, eventlog_buffer.data()).Unwrap(); + eventlog->backend->Write(0, eventlog_size, true, eventlog_buffer.data()); eventlog->backend->Close(); - /// MBoxList____ resides within the root CEC/ directory. - /// Initially created, at offset 0x0, are bytes 0x68 0x68 0x00 0x00 0x01, with 0x6868 'hh', - /// being the magic number. The rest of the file is filled with zeroes, until the end of - /// file at offset 0x18b - FileSys::Path mboxlist_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_LIST, 0).data()); + /* + /// MBoxList____ resides within the root CEC/ directory. + /// Initially created, at offset 0x0, are bytes 0x68 0x68 0x00 0x00 0x01, with + 0x6868 'hh', + /// being the magic number. The rest of the file is filled with zeroes, until the + end of + /// file at offset 0x18b + FileSys::Path mboxlist_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_LIST, 0).data()); - auto mboxlist_result = - Service::FS::OpenFileFromArchive(*archive_result, mboxlist_path, mode); + auto mboxlist_result = + Service::FS::OpenFileFromArchive(*archive_result, mboxlist_path, mode); - constexpr u32 mboxlist_size = 0x18c; - auto mboxlist = mboxlist_result.Unwrap(); - std::vector mboxlist_buffer(mboxlist_size); + constexpr u32 mboxlist_size = 0x18c; + auto mboxlist = mboxlist_result.Unwrap(); + std::vector mboxlist_buffer(mboxlist_size); - std::memset(&mboxlist_buffer[0], 0, mboxlist_size); - mboxlist_buffer[0] = 0x68; - mboxlist_buffer[1] = 0x68; - /// mboxlist_buffer[2-3] are already zeroed - mboxlist_buffer[4] = 0x01; + std::memset(&mboxlist_buffer[0], 0, mboxlist_size); + mboxlist_buffer[0] = 0x68; + mboxlist_buffer[1] = 0x68; + /// mboxlist_buffer[2-3] are already zeroed + mboxlist_buffer[4] = 0x01; - mboxlist->backend->Write(0, mboxlist_size, true, mboxlist_buffer.data()).Unwrap(); - mboxlist->backend->Close(); + mboxlist->backend->Write(0, mboxlist_size, true, mboxlist_buffer.data()); + mboxlist->backend->Close(); + */ } ASSERT_MSG(archive_result.Succeeded(), "Could not open the CECD SystemSaveData archive!"); diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index e3573b24d..6a706f6fb 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -109,7 +109,7 @@ public: enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; struct CecInOutBoxInfoHeader { - u16_le magic; // bb + u16_le magic; // 0x6262 'bb' u16_le padding; u32_le box_info_size; u32_le max_box_size; @@ -122,6 +122,36 @@ public: static_assert(sizeof(CecInOutBoxInfoHeader) == 0x20, "CecInOutBoxInfoHeader struct has incorrect size."); + struct CecMBoxInfoHeader { + u16_le magic; // 0x6363 'cc' + u16_le padding; + u32_le program_id; + u32_le private_id; + u8 flag; + u8 flag2; + u16_le padding2; + u8 hmac_key[32]; + u32_le padding3; + /// year, 4 bytes, month 1 byte, day 1 byte, hour 1 byte, minute 1 byte + struct Time { + u32_le year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 millisecond; + u8 microsecond; + u8 padding; + } last_accessed; + u32_le padding4; + Time last_received; + u32_le padding5; + Time unknown_time; + }; + static_assert(sizeof(CecMBoxInfoHeader) == 0x60, + "CecMBoxInfoHeader struct has incorrect size."); + struct CecMessageHeader { u16_le magic; // `` u16_le padding; @@ -163,8 +193,8 @@ public: u32 raw; BitField<1, 1, u32> read; BitField<2, 1, u32> write; - BitField<3, 1, u32> make_dir; - BitField<4, 1, u32> skip_check; /// or is it check/test? + BitField<3, 1, u32> create; + BitField<4, 1, u32> check; /// or is it check/test? BitField<30, 1, u32> unk_flag; }; @@ -199,7 +229,7 @@ public: protected: /** - * CECD::OpenRawFile service function + * CECD::Open service function * Inputs: * 0 : Header Code[0x000100C2] * 1 : NCCH Program ID @@ -211,10 +241,10 @@ public: * 1 : Result of function, 0 on success, otherwise error code * 2 : File size? */ - void OpenRawFile(Kernel::HLERequestContext& ctx); + void Open(Kernel::HLERequestContext& ctx); /** - * CECD::ReadRawFile service function + * CECD::ReadFile service function * Inputs: * 0 : Header Code[0x00020042] * 1 : Buffer size (unused) @@ -226,7 +256,7 @@ public: * 3 : Descriptor for mapping a write-only buffer in the target process * 4 : Buffer address */ - void ReadRawFile(Kernel::HLERequestContext& ctx); + void ReadFile(Kernel::HLERequestContext& ctx); /** * CECD::ReadMessage service function @@ -277,7 +307,7 @@ public: void ReadMessageWithHMAC(Kernel::HLERequestContext& ctx); /** - * CECD::WriteRawFile service function + * CECD::WriteFile service function * Inputs: * 0 : Header Code[0x00050042] * 1 : Buffer size(unused) @@ -288,7 +318,7 @@ public: * 2 : Descriptor for mapping a read-only buffer in the target process * 3 : Buffer address */ - void WriteRawFile(Kernel::HLERequestContext& ctx); + void WriteFile(Kernel::HLERequestContext& ctx); /** * CECD::WriteMessage service function @@ -534,7 +564,9 @@ private: std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, const std::vector& msg_id = std::vector()) const; - void CreateAndPopulateMBoxDirectory(const u32 ncch_program_id); + // void CreateAndPopulateMBoxDirectory(const u32 ncch_program_id); + void CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, + std::vector& file_buffer); Service::FS::ArchiveHandle cecd_system_save_data_archive; diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp index b736c689b..a83f9c357 100644 --- a/src/core/hle/service/cecd/cecd_s.cpp +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -12,11 +12,11 @@ CECD_S::CECD_S(std::shared_ptr cecd) static const FunctionInfo functions[] = { // cecd:u shared commands // clang-format off - {0x000100C2, &CECD_S::OpenRawFile, "OpenRawFile"}, - {0x00020042, &CECD_S::ReadRawFile, "ReadRawFile"}, + {0x000100C2, &CECD_S::Open, "Open"}, + {0x00020042, &CECD_S::ReadFile, "ReadFile"}, {0x00030104, &CECD_S::ReadMessage, "ReadMessage"}, {0x00040106, &CECD_S::ReadMessageWithHMAC, "ReadMessageWithHMAC"}, - {0x00050042, &CECD_S::WriteRawFile, "WriteRawFile"}, + {0x00050042, &CECD_S::WriteFile, "WriteFile"}, {0x00060104, &CECD_S::WriteMessage, "WriteMessage"}, {0x00070106, &CECD_S::WriteMessageWithHMAC, "WriteMessageWithHMAC"}, {0x00080102, &CECD_S::Delete, "Delete"}, diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp index e12b3dde0..a580872f0 100644 --- a/src/core/hle/service/cecd/cecd_u.cpp +++ b/src/core/hle/service/cecd/cecd_u.cpp @@ -12,11 +12,11 @@ CECD_U::CECD_U(std::shared_ptr cecd) static const FunctionInfo functions[] = { // cecd:u shared commands // clang-format off - {0x000100C2, &CECD_U::OpenRawFile, "OpenRawFile"}, - {0x00020042, &CECD_U::ReadRawFile, "ReadRawFile"}, + {0x000100C2, &CECD_U::Open, "Open"}, + {0x00020042, &CECD_U::ReadFile, "ReadFile"}, {0x00030104, &CECD_U::ReadMessage, "ReadMessage"}, {0x00040106, &CECD_U::ReadMessageWithHMAC, "ReadMessageWithHMAC"}, - {0x00050042, &CECD_U::WriteRawFile, "WriteRawFile"}, + {0x00050042, &CECD_U::WriteFile, "WriteFile"}, {0x00060104, &CECD_U::WriteMessage, "WriteMessage"}, {0x00070106, &CECD_U::WriteMessageWithHMAC, "WriteMessageWithHMAC"}, {0x00080102, &CECD_U::Delete, "Delete"}, From 0e8398b51c78957a9d06714878be67abe04fc0ab Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Sun, 19 Aug 2018 03:05:41 -0400 Subject: [PATCH 10/21] service/cecd: Update header checks and increased debug logging --- src/core/hle/service/cecd/cecd.cpp | 458 +++++++++++++++++++---------- src/core/hle/service/cecd/cecd.h | 38 ++- 2 files changed, 334 insertions(+), 162 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index e96444d8f..8a7b38a75 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -70,6 +70,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { auto directory = dir_result.Unwrap(); rb.Push(RESULT_SUCCESS); rb.Push(directory->backend->Read(0, nullptr)); /// Entry count + directory->backend->Close(); } break; } @@ -92,13 +93,17 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { u64_le le_program_id = Kernel::g_current_process->codeset->program_id; std::memcpy(program_id.data(), &le_program_id, sizeof(u64)); session_data->file->backend->Write(0, sizeof(u64), true, program_id.data()); + session_data->file->backend->Close(); } } } LOG_DEBUG(Service_CECD, - "called, ncch_program_id={:#010x}, path_type={:#04x}, open_mode={:#010x}, path={}", - ncch_program_id, static_cast(path_type), open_mode.raw, path.AsString()); + "called, ncch_program_id={:#010x}, path_type={:#04x}, path={}, " + "open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", + ncch_program_id, static_cast(path_type), path.AsString(), open_mode.raw, + open_mode.unknown, open_mode.read, open_mode.write, open_mode.create, + open_mode.check); } void Module::Interface::ReadFile(Kernel::HLERequestContext& ctx) { @@ -107,6 +112,14 @@ void Module::Interface::ReadFile(Kernel::HLERequestContext& ctx) { auto& write_buffer = rp.PopMappedBuffer(); SessionData* session_data = GetSessionData(ctx.Session()); + LOG_DEBUG(Service_CECD, + "SessionData: ncch_program_id={:#010x}, data_path_type={:#04x}, " + "path={}, open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", + session_data->ncch_program_id, static_cast(session_data->data_path_type), + session_data->path.AsString(), session_data->open_mode.raw, + session_data->open_mode.unknown, session_data->open_mode.read, + session_data->open_mode.write, session_data->open_mode.create, + session_data->open_mode.check); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); switch (session_data->data_path_type) { @@ -131,7 +144,7 @@ void Module::Interface::ReadFile(Kernel::HLERequestContext& ctx) { } rb.PushMappedBuffer(write_buffer); - LOG_DEBUG(Service_CECD, "called, write_buffer_size={:#010x}, path={}", write_buffer_size, + LOG_DEBUG(Service_CECD, "called, write_buffer_size={:#x}, path={}", write_buffer_size, session_data->path.AsString()); } @@ -183,8 +196,10 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(message_id_buffer); rb.PushMappedBuffer(write_buffer); - LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_outbox={}", - ncch_program_id, is_outbox); + LOG_DEBUG( + Service_CECD, + "called, ncch_program_id={:#010x}, is_outbox={}, message_id_size={:#x}, buffer_size={:#x}", + ncch_program_id, is_outbox, message_id_size, buffer_size); } void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { @@ -238,8 +253,10 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(hmac_key_buffer); rb.PushMappedBuffer(write_buffer); - LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_outbox={}", - ncch_program_id, is_outbox); + LOG_DEBUG( + Service_CECD, + "called, ncch_program_id={:#010x}, is_outbox={}, message_id_size={:#x}, buffer_size={:#x}", + ncch_program_id, is_outbox, message_id_size, buffer_size); } void Module::Interface::WriteFile(Kernel::HLERequestContext& ctx) { @@ -248,6 +265,14 @@ void Module::Interface::WriteFile(Kernel::HLERequestContext& ctx) { auto& read_buffer = rp.PopMappedBuffer(); SessionData* session_data = GetSessionData(ctx.Session()); + LOG_DEBUG(Service_CECD, + "SessionData: ncch_program_id={:#010x}, data_path_type={:#04x}, " + "path={}, open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", + session_data->ncch_program_id, static_cast(session_data->data_path_type), + session_data->path.AsString(), session_data->open_mode.raw, + session_data->open_mode.unknown, session_data->open_mode.read, + session_data->open_mode.write, session_data->open_mode.create, + session_data->open_mode.check); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); switch (session_data->data_path_type) { @@ -275,7 +300,7 @@ void Module::Interface::WriteFile(Kernel::HLERequestContext& ctx) { } rb.PushMappedBuffer(read_buffer); - LOG_DEBUG(Service_CECD, "called, read_buffer_size={:#010x}", read_buffer_size); + LOG_DEBUG(Service_CECD, "called, read_buffer_size={:#x}", read_buffer_size); } void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { @@ -327,8 +352,10 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(read_buffer); rb.PushMappedBuffer(message_id_buffer); - LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_outbox={}", - ncch_program_id, is_outbox); + LOG_DEBUG( + Service_CECD, + "called, ncch_program_id={:#010x}, is_outbox={}, message_id_size={:#x}, buffer_size={:#x}", + ncch_program_id, is_outbox, message_id_size, buffer_size); } void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { @@ -382,11 +409,13 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(hmac_key_buffer); rb.PushMappedBuffer(message_id_buffer); - LOG_WARNING(Service_CECD, "(STUBBED) called, ncch_program_id={:#010x}, is_outbox={}", - ncch_program_id, is_outbox); + LOG_DEBUG( + Service_CECD, + "called, ncch_program_id={:#010x}, is_outbox={}, message_id_size={:#x}, buffer_size={:#x}", + ncch_program_id, is_outbox, message_id_size, buffer_size); } -void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { +void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { /// DeleteMessage? IPC::RequestParser rp(ctx, 0x08, 4, 2); const u32 ncch_program_id = rp.Pop(); const CecDataPathType path_type = rp.PopEnum(); @@ -403,25 +432,58 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.PushMappedBuffer(message_id_buffer); - LOG_WARNING(Service_CECD, - "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#04x}, is_outbox={}", - ncch_program_id, static_cast(path_type), is_outbox); + LOG_DEBUG(Service_CECD, + "called, ncch_program_id={:#010x}, path_type={:#04x}, " + "is_outbox={}, message_id_size={:#x}", + ncch_program_id, static_cast(path_type), is_outbox, message_id_size); } -void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// DeleteFile? +void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// Update Index/List? IPC::RequestParser rp(ctx, 0x09, 3, 2); const u32 ncch_program_id = rp.Pop(); - const u32 size = rp.Pop(); + const u32 buffer_size = rp.Pop(); const u32 option = rp.Pop(); auto& message_id_buffer = rp.PopMappedBuffer(); + if (buffer_size > 0) { + FileSys::Path path("/Cecd_0x000900C2.out"); + FileSys::Mode mode; + mode.write_flag.Assign(1); + mode.create_flag.Assign(1); + + auto file_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); + if (file_result.Succeeded()) { + auto file = file_result.Unwrap(); + std::vector buffer(buffer_size); + message_id_buffer.Read(buffer.data(), 0, buffer_size); + + file->backend->Write(0, buffer_size, true, buffer.data()); + file->backend->Close(); + } + } + + SessionData* session_data = GetSessionData(ctx.Session()); + if (session_data->file) + LOG_DEBUG( + Service_CECD, + "SessionData: ncch_program_id={:#010x}, data_path_type={:#04x}, " + "path={}, open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", + session_data->ncch_program_id, static_cast(session_data->data_path_type), + session_data->path.AsString(), session_data->open_mode.raw, + session_data->open_mode.unknown, session_data->open_mode.read, + session_data->open_mode.write, session_data->open_mode.create, + session_data->open_mode.check); + + if (session_data->file) + session_data->file->backend->Close(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushMappedBuffer(message_id_buffer); - LOG_WARNING(Service_CECD, - "(STUBBED) called, ncch_program_id={:#010x}, size={:#010x}, option={:#010x}", - ncch_program_id, size, option); + LOG_DEBUG(Service_CECD, "called, ncch_program_id={:#010x}, buffer_size={:#x}, option={:#x}", + ncch_program_id, buffer_size, option); } void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { @@ -449,7 +511,7 @@ void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { dest_buffer.Write(buffer.data(), 0, buffer.size()); break; default: - LOG_ERROR(Service_CECD, "Unknown system info type={}", static_cast(info_type)); + LOG_ERROR(Service_CECD, "Unknown system info type={:#x}", static_cast(info_type)); } rb.Push(RESULT_SUCCESS); @@ -457,8 +519,7 @@ void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(dest_buffer); LOG_DEBUG(Service_CECD, - "called, dest_buffer_size={:#010x}, info_type={:#010x}, " - "param_buffer_size={:#010x}", + "called, dest_buffer_size={:#x}, info_type={:#x}, param_buffer_size={:#x}", dest_buffer_size, static_cast(info_type), param_buffer_size); } @@ -469,7 +530,7 @@ void Module::Interface::RunCommand(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", static_cast(command)); + LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", cecd->GetCecCommandAsString(command)); } void Module::Interface::RunCommandAlt(Kernel::HLERequestContext& ctx) { @@ -479,7 +540,7 @@ void Module::Interface::RunCommandAlt(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", static_cast(command)); + LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", cecd->GetCecCommandAsString(command)); } void Module::Interface::GetCecStateAbbreviated(Kernel::HLERequestContext& ctx) { @@ -554,8 +615,6 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } else { - LOG_DEBUG(Service_CECD, "Failed to open file: {}", path.AsString()); - rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); } @@ -563,8 +622,11 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(read_buffer); LOG_DEBUG(Service_CECD, - "called, ncch_program_id={:#010x}, path_type={:#04x}, open_mode={:#010x}, path={}", - ncch_program_id, static_cast(path_type), open_mode.raw, path.AsString()); + "called, ncch_program_id={:#010x}, path_type={:#04x}, path={}, buffer_size={:#x} " + "open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", + ncch_program_id, static_cast(path_type), path.AsString(), buffer_size, + open_mode.raw, open_mode.unknown, open_mode.read, open_mode.write, open_mode.create, + open_mode.check); } void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { @@ -605,8 +667,6 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push(bytes_read); } else { - LOG_DEBUG(Service_CECD, "Failed to open file: {}", path.AsString()); - rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); rb.Push(0); /// No bytes read @@ -615,8 +675,11 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(write_buffer); LOG_DEBUG(Service_CECD, - "called, ncch_program_id={:#010x}, path_type={:#04x}, open_mode={:#010x}, path={}", - ncch_program_id, static_cast(path_type), open_mode.raw, path.AsString()); + "called, ncch_program_id={:#010x}, path_type={:#04x}, path={}, buffer_size={:#x} " + "open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", + ncch_program_id, static_cast(path_type), path.AsString(), buffer_size, + open_mode.raw, open_mode.unknown, open_mode.read, open_mode.write, open_mode.create, + open_mode.check); } std::string Module::EncodeBase64(const std::vector& in, const std::string& dictionary) const { @@ -682,27 +745,125 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const } } +std::string Module::GetCecCommandAsString(const CecCommand command) const { + switch (command) { + case CecCommand::CEC_COMMAND_NONE: + return "NONE"; + case CecCommand::CEC_COMMAND_START: + return "START"; + case CecCommand::CEC_COMMAND_RESET_START: + return "RESET_START"; + case CecCommand::CEC_COMMAND_READYSCAN: + return "READYSCAN"; + case CecCommand::CEC_COMMAND_READYSCANWAIT: + return "READYSCANWAIT"; + case CecCommand::CEC_COMMAND_STARTSCAN: + return "STARTSCAN"; + case CecCommand::CEC_COMMAND_RESCAN: + return "RESCAN"; + case CecCommand::CEC_COMMAND_NDM_RESUME: + return "RESUME"; + case CecCommand::CEC_COMMAND_NDM_SUSPEND: + return "NDM_SUSPEND"; + case CecCommand::CEC_COMMAND_NDM_SUSPEND_IMMEDIATE: + return "NDM_SUSPEND_IMMEDIATE"; + case CecCommand::CEC_COMMAND_STOPWAIT: + return "STOPWAIT"; + case CecCommand::CEC_COMMAND_STOP: + return "STOP"; + case CecCommand::CEC_COMMAND_STOP_FORCE: + return "STOP_FORCE"; + case CecCommand::CEC_COMMAND_STOP_FORCE_WAIT: + return "STOP_FORCE_WAIT"; + case CecCommand::CEC_COMMAND_RESET_FILTER: + return "RESET_FILTER"; + case CecCommand::CEC_COMMAND_DAEMON_STOP: + return "DAEMON_STOP"; + case CecCommand::CEC_COMMAND_DAEMON_START: + return "DAEMON_START"; + case CecCommand::CEC_COMMAND_EXIT: + return "EXIT"; + case CecCommand::CEC_COMMAND_OVER_BOSS: + return "OVER_BOSS"; + case CecCommand::CEC_COMMAND_OVER_BOSS_FORCE: + return "OVER_BOSS_FORCE"; + case CecCommand::CEC_COMMAND_OVER_BOSS_FORCE_WAIT: + return "OVER_BOSS_FORCE_WAIT"; + case CecCommand::CEC_COMMAND_END: + return "END"; + default: + return "Unknown"; + } +} + void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, std::vector& file_buffer) { + const u32 file_size = file_buffer.size(); + switch (path_type) { - case CecDataPathType::CEC_PATH_MBOX_LIST: + case CecDataPathType::CEC_PATH_MBOX_LIST: { + CecMBoxListHeader mbox_list_header = {}; + CecMBoxListBoxes mbox_list_boxes = {}; + std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); + std::memcpy(&mbox_list_boxes, &file_buffer[0xC], sizeof(CecMBoxListBoxes)); + + if (file_size != 0x18C) { /// 0x18C CecMBoxListHeader + CecMBoxListBoxes + LOG_DEBUG(Service_CECD, "CecMBoxListHeader size is incorrect: {}", file_size); + } + + if (mbox_list_header.magic != 0x6868) { /// 'hh' + if (mbox_list_header.magic == 0) + LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is not set"); + else + LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is incorrect: {}", + mbox_list_header.magic); + mbox_list_header.magic = 0x6868; + } + + if (mbox_list_header.version != 0x01) { /// Not quite sure if it is a version + if (mbox_list_header.version == 0) + LOG_DEBUG(Service_CECD, "CecMBoxListHeader version is not set"); + else + LOG_DEBUG(Service_CECD, "CecMBoxListHeader version is incorrect: {}", + mbox_list_header.version); + mbox_list_header.version = 0x01; + } + + if (mbox_list_header.num_boxes > 24) { + LOG_DEBUG(Service_CECD, "CecMBoxListHeader number of boxes is too large: {}", + mbox_list_header.num_boxes); + } + + std::memcpy(file_buffer.data(), &mbox_list_header, sizeof(CecMBoxListHeader)); + std::memcpy(&file_buffer[0xC], &mbox_list_boxes, sizeof(CecMBoxListBoxes)); break; + } case CecDataPathType::CEC_PATH_MBOX_INFO: { CecMBoxInfoHeader mbox_info_header = {}; std::memcpy(&mbox_info_header, file_buffer.data(), sizeof(CecMBoxInfoHeader)); - if (file_buffer.size() != sizeof(CecMBoxInfoHeader)) { /// 0x60 - LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader size is incorrect"); + if (file_size != sizeof(CecMBoxInfoHeader)) { /// 0x60 + LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader size is incorrect: {}", file_size); } if (mbox_info_header.magic != 0x6363) { /// 'cc' - LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader magic number is incorrect"); + if (mbox_info_header.magic == 0) + LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader magic number is not set"); + else + LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader magic number is incorrect: {}", + mbox_info_header.magic); + mbox_info_header.magic = 0x6363; } - if (mbox_info_header.program_id != static_cast(ncch_program_id)) { - LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader program id does not match current id"); + if (mbox_info_header.program_id != ncch_program_id) { + if (mbox_info_header.program_id == 0) + LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader program id is not set"); + else + LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader program id doesn't match current id: {}", + mbox_info_header.program_id); } + std::memcpy(file_buffer.data(), &mbox_info_header, sizeof(CecMBoxInfoHeader)); break; } case CecDataPathType::CEC_PATH_INBOX_INFO: { @@ -710,30 +871,48 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(&inbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); if (inbox_info_header.magic != 0x6262) { /// 'bb' - LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader magic number is incorrect"); + if (inbox_info_header.magic == 0) + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader magic number is not set"); + else + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader magic number is incorrect: {}", + inbox_info_header.magic); inbox_info_header.magic = 0x6262; } - if (inbox_info_header.box_info_size != file_buffer.size()) { - LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader box info size is incorrect"); + if (inbox_info_header.box_info_size != file_size) { + if (inbox_info_header.box_info_size == 0) + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader box info size is not set"); + else + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader box info size is incorrect:", + inbox_info_header.box_info_size); inbox_info_header.box_info_size = sizeof(CecInOutBoxInfoHeader); } - if (inbox_info_header.max_box_size > 0x100000) { - LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max box size is incorrect"); + if (inbox_info_header.max_box_size == 0) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max box size is not set"); + } else if (inbox_info_header.max_box_size > 0x100000) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max box size is too large: {}", + inbox_info_header.max_box_size); } - if (inbox_info_header.max_message_num > 99) { - LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max box size is incorrect"); + if (inbox_info_header.max_message_num == 0) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max message number is not set"); + } else if (inbox_info_header.max_message_num > 99) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max message number is too large: {}", + inbox_info_header.max_message_num); } - if (inbox_info_header.max_message_size >= 0x019000) { - LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max message size is incorrect"); + if (inbox_info_header.max_message_size == 0) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max message size is not set"); + } else if (inbox_info_header.max_message_size > 0x019000) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max message size is too large"); } if (inbox_info_header.max_batch_size == 0) { LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max batch size is not set"); inbox_info_header.max_batch_size = inbox_info_header.max_message_num; + } else if (inbox_info_header.max_batch_size != inbox_info_header.max_message_num) { + LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max batch size != max message number"); } std::memcpy(file_buffer.data(), &inbox_info_header, sizeof(CecInOutBoxInfoHeader)); @@ -744,37 +923,81 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(&outbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); if (outbox_info_header.magic != 0x6262) { /// 'bb' - LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader magic number is incorrect"); + if (outbox_info_header.magic == 0) + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader magic number is not set"); + else + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader magic number is incorrect: {}", + outbox_info_header.magic); outbox_info_header.magic = 0x6262; } - if (outbox_info_header.box_info_size != file_buffer.size()) { - LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is incorrect"); + if (outbox_info_header.box_info_size != file_size) { + if (outbox_info_header.box_info_size == 0) + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is not set"); + else + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is incorrect:", + outbox_info_header.box_info_size); outbox_info_header.box_info_size = sizeof(CecInOutBoxInfoHeader); } - if (outbox_info_header.max_box_size > 0x100000) { - LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max box size is incorrect"); + if (outbox_info_header.max_box_size == 0) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max box size is not set"); + } else if (outbox_info_header.max_box_size > 0x100000) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max box size is too large"); } - if (outbox_info_header.max_message_num > 99) { - LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max box size is incorrect"); + if (outbox_info_header.max_message_num == 0) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max message number is not set"); + } else if (outbox_info_header.max_message_num > 99) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max message number is too large"); } - if (outbox_info_header.max_message_size >= 0x019000) { - LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max message size is incorrect"); + if (outbox_info_header.max_message_size == 0) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max message size is not set"); + } else if (outbox_info_header.max_message_size > 0x019000) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max message size is too large"); } if (outbox_info_header.max_batch_size == 0) { LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max batch size is not set"); outbox_info_header.max_batch_size = outbox_info_header.max_message_num; + } else if (outbox_info_header.max_batch_size != outbox_info_header.max_message_num) { + LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max batch size != max message number"); } std::memcpy(file_buffer.data(), &outbox_info_header, sizeof(CecInOutBoxInfoHeader)); break; } - case CecDataPathType::CEC_PATH_OUTBOX_INDEX: + case CecDataPathType::CEC_PATH_OUTBOX_INDEX: { + CecOBIndexHeader obindex_header = {}; + std::memcpy(&obindex_header, file_buffer.data(), sizeof(CecOBIndexHeader)); + + if (file_size < sizeof(CecOBIndexHeader)) { /// 0x08, minimum size + LOG_DEBUG(Service_CECD, "CecOBIndexHeader size is too small: {}", file_size); + } + + if (obindex_header.magic != 0x6767) { /// 'gg' + if (obindex_header.magic == 0) + LOG_DEBUG(Service_CECD, "CecOBIndexHeader magic number is not set"); + else + LOG_DEBUG(Service_CECD, "CecOBIndexHeader magic number is incorrect: {}", + obindex_header.magic); + obindex_header.magic = 0x6767; + } + + if (obindex_header.message_num == 0) { + if (file_size > sizeof(CecOBIndexHeader)) { + LOG_DEBUG(Service_CECD, "CecOBIndexHeader message number is not set"); + obindex_header.message_num = (file_size % 8) - 1; /// 8 byte message id - 1 header + } + } else if (obindex_header.message_num != (file_size % 8) - 1) { + LOG_DEBUG(Service_CECD, "CecOBIndexHeader message number is incorrect: {}", + obindex_header.message_num); + } + + std::memcpy(file_buffer.data(), &obindex_header, sizeof(CecOBIndexHeader)); break; + } case CecDataPathType::CEC_PATH_INBOX_MSG: break; case CecDataPathType::CEC_PATH_OUTBOX_MSG: @@ -790,83 +1013,6 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ default: {} } } -/* - /// MBoxInfo____ resides in the MBox /CEC/ directory, - /// The Magic number is 0x6363 'cc', and has size 0x60 - constexpr u32 mbox_info_size = 0x60; - auto mbox_info = mbox_info_result.Unwrap(); - std::vector mbox_info_buffer(mbox_info_size); - u32_le le_ncch_program_id = ncch_program_id; - - CecMBoxInfoHeader mbox_info_header = {}; - std::memset(&mbox_info_header, 0, sizeof(CecMBoxInfoHeader)); - - auto now = std::chrono::system_clock::now(); - std::time_t now_time_t = std::chrono::system_clock::to_time_t(now); - std::tm* now_tm = std::localtime(&now_time_t); - - mbox_info_header.magic = 0x6363; - /// mbox_info_header.padding already zeroed - mbox_info_header.title_id = ncch_program_id; - /// mbox_info_header.private_id = unknown... - mbox_info_header.flag = 0x00; /// unknown - mbox_info_header.flag2 = 0x01; /// unknown - /// mbox_info_header.padding2 already zeroed - /// mbox_info_header.hmac_key = unknown... - /// mbox_info_header.padding3 already zeroed - mbox_info_header.last_accessed.year = static_cast(1900 + now_tm->tm_year); - mbox_info_header.last_accessed.month = static_cast(1 + now_tm->tm_mon); - mbox_info_header.last_accessed.day = static_cast(now_tm->tm_mday); - mbox_info_header.last_accessed.hour = static_cast(now_tm->tm_hour); - mbox_info_header.last_accessed.minute = static_cast(now_tm->tm_min); - mbox_info_header.last_accessed.second = static_cast(now_tm->tm_sec); - /// mbox_info_header.padding4 already zeroed - /// mbox_info_header.last_received = zeroed until receive? - /// mbox_info_header.padding5 already zeroed - /// mbox_info_header.unknown_time, might be sent-time, might be padding? - - /// BoxInfo_____ resides in both the InBox and OutBox directories, - /// The Magic number is 0x6262 'bb', and has size 0x20-byte header, and an array of 0x70-byte - /// entries. Each entry is a copy of the message header. - - /// BoxInfo_____ resides in both the InBox and OutBox directories, - /// The Magic number is 0x6262 'bb', and has size 0x20-byte header, and an array of 0x70-byte - /// entries. Each entry is a copy of the message header. - - /// OBIndex_____ resides in the OutBox directory, - /// The magic number is 0x6767 'gg', and the total size is 0x10 - - /// MBoxData.001 resides in the MBox /CEC/ directory and contains the icon of the app - std::vector mbox_icon_buffer; - Core::System::GetInstance().GetAppLoader().ReadIcon(mbox_icon_buffer); - - const u32 mbox_icon_size = mbox_icon_buffer.size() - 0x24C0; // offset where icon starts - auto mbox_icon = mbox_icon_result.Unwrap(); - - mbox_icon->backend->Write(0, mbox_icon_size, true, &mbox_icon_buffer[0x24C0]); - mbox_icon->backend->Close(); - - /// MBoxData.010 resides in the MBox /CEC/ directory and contains the title of the app - /// in null-terminated UTF-16 string. - std::string title_name; - Core::System::GetInstance().GetAppLoader().ReadTitle(title_name); - - std::u16string program_name = Common::UTF8ToUTF16(title_name + '\0'); - - const u32 mbox_title_size = program_name.size(); - auto mbox_title = mbox_title_result.Unwrap(); - std::vector mbox_title_buffer(mbox_title_size); - std::memcpy(mbox_title_buffer.data(), program_name.data(), mbox_title_size); - - /// MBoxData.050 resides in the MBox /CEC/ directory and contains the program id of the app - std::vector program_id_buffer(8); - u64_le le_program_id = Kernel::g_current_process->codeset->program_id; - std::memcpy(program_id_buffer.data(), &le_program_id, sizeof(u64)); - - mbox_program_id->backend->Write(0, sizeof(u64), true, program_id_buffer.data()); - mbox_program_id->backend->Close(); -} -*/ Module::SessionData::SessionData() {} @@ -930,32 +1076,28 @@ Module::Module() { eventlog->backend->Write(0, eventlog_size, true, eventlog_buffer.data()); eventlog->backend->Close(); - /* - /// MBoxList____ resides within the root CEC/ directory. - /// Initially created, at offset 0x0, are bytes 0x68 0x68 0x00 0x00 0x01, with - 0x6868 'hh', - /// being the magic number. The rest of the file is filled with zeroes, until the - end of - /// file at offset 0x18b - FileSys::Path mboxlist_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_LIST, 0).data()); + /// MBoxList____ resides within the root CEC/ directory. + /// Initially created, at offset 0x0, are bytes 0x68 0x68 0x00 0x00 0x01, with 0x6868 'hh', + /// being the magic number. The rest of the file is filled with zeroes, until the end of + /// file at offset 0x18b + FileSys::Path mboxlist_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_LIST, 0).data()); - auto mboxlist_result = - Service::FS::OpenFileFromArchive(*archive_result, mboxlist_path, mode); + auto mboxlist_result = + Service::FS::OpenFileFromArchive(*archive_result, mboxlist_path, mode); - constexpr u32 mboxlist_size = 0x18c; - auto mboxlist = mboxlist_result.Unwrap(); - std::vector mboxlist_buffer(mboxlist_size); + constexpr u32 mboxlist_size = 0x18c; + auto mboxlist = mboxlist_result.Unwrap(); + std::vector mboxlist_buffer(mboxlist_size); - std::memset(&mboxlist_buffer[0], 0, mboxlist_size); - mboxlist_buffer[0] = 0x68; - mboxlist_buffer[1] = 0x68; - /// mboxlist_buffer[2-3] are already zeroed - mboxlist_buffer[4] = 0x01; + std::memset(&mboxlist_buffer[0], 0, mboxlist_size); + mboxlist_buffer[0] = 0x68; + mboxlist_buffer[1] = 0x68; + /// mboxlist_buffer[2-3] are already zeroed + mboxlist_buffer[4] = 0x01; - mboxlist->backend->Write(0, mboxlist_size, true, mboxlist_buffer.data()); - mboxlist->backend->Close(); - */ + mboxlist->backend->Write(0, mboxlist_size, true, mboxlist_buffer.data()); + mboxlist->backend->Close(); } ASSERT_MSG(archive_result.Succeeded(), "Could not open the CECD SystemSaveData archive!"); diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 6a706f6fb..593f264d3 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -152,6 +152,25 @@ public: static_assert(sizeof(CecMBoxInfoHeader) == 0x60, "CecMBoxInfoHeader struct has incorrect size."); + struct CecMBoxListBoxes { + struct Box { + u32_le ncch_program_id; + u32_le padding; + u64_le padding2; + } box[24]; + }; + static_assert(sizeof(CecMBoxListBoxes) == 0x180, "CecMBoxListBoxes struct has incorrect size."); + + struct CecMBoxListHeader { + u16_le magic; // 0x6868 'hh' + u16_le padding; + u16_le version; /// 0x01 00, maybe activated flag? + u16_le padding2; + u16_le num_boxes; /// 24 max? + u16_le padding3; + }; + static_assert(sizeof(CecMBoxListHeader) == 0xC, "CecMBoxListHeader struct has incorrect size."); + struct CecMessageHeader { u16_le magic; // `` u16_le padding; @@ -182,6 +201,14 @@ public: }; static_assert(sizeof(CecMessageHeader) == 0x70, "CecMessageHeader struct has incorrect size."); + struct CecOBIndexHeader { + u16_le magic; /// 0x6767 'gg' + u16_le padding; + u32_le message_num; + /// Array? of messageid's 8 bytes each, same as CecMessageHeader.message_id[8] + }; + static_assert(sizeof(CecOBIndexHeader) == 0x08, "CecOBIndexHeader struct has incorrect size."); + enum class CecNdmStatus : u32 { NDM_STATUS_WORKING = 0, NDM_STATUS_IDLE = 1, @@ -191,10 +218,11 @@ public: union CecOpenMode { u32 raw; - BitField<1, 1, u32> read; - BitField<2, 1, u32> write; - BitField<3, 1, u32> create; - BitField<4, 1, u32> check; /// or is it check/test? + BitField<0, 1, u32> unknown; /// 1 delete? + BitField<1, 1, u32> read; /// 2 + BitField<2, 1, u32> write; /// 4 + BitField<3, 1, u32> create; /// 8 + BitField<4, 1, u32> check; /// 16 BitField<30, 1, u32> unk_flag; }; @@ -564,6 +592,8 @@ private: std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, const std::vector& msg_id = std::vector()) const; + std::string GetCecCommandAsString(const CecCommand command) const; + // void CreateAndPopulateMBoxDirectory(const u32 ncch_program_id); void CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, std::vector& file_buffer); From 7a8477d10610f1229552f29004a534c8ad8b00c4 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Thu, 23 Aug 2018 03:13:10 -0400 Subject: [PATCH 11/21] service/cecd: Implement mboxlist handling --- src/core/hle/service/cecd/cecd.cpp | 130 +++++++++++++++++++++++++---- src/core/hle/service/cecd/cecd.h | 24 ++---- 2 files changed, 123 insertions(+), 31 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 8a7b38a75..ede743bea 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -67,9 +67,17 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { } rb.Push(0); /// Zero entries } else { + constexpr u32 max_entries = 32; /// reasonable value, just over max boxes 24 auto directory = dir_result.Unwrap(); + + /// Actual reading into vector seems to be required for entry count + std::vector entries(max_entries); + const u32 entry_count = directory->backend->Read(max_entries, entries.data()); + + LOG_DEBUG(Service_CECD, "Number of entries found in = {}", entry_count); + rb.Push(RESULT_SUCCESS); - rb.Push(directory->backend->Read(0, nullptr)); /// Entry count + rb.Push(entry_count); /// Entry count directory->backend->Close(); } break; @@ -423,19 +431,49 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { /// DeleteMessa const u32 message_id_size = rp.Pop(); auto& message_id_buffer = rp.PopMappedBuffer(); - if (is_outbox) { - - } else { /// otherwise inbox - } + FileSys::Path path(cecd->GetCecDataPathTypeAsString(path_type, ncch_program_id).data()); + FileSys::Mode mode; + mode.write_flag.Assign(1); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(RESULT_SUCCESS); + switch (path_type) { + case CecDataPathType::CEC_PATH_ROOT_DIR: + case CecDataPathType::CEC_PATH_MBOX_DIR: + case CecDataPathType::CEC_PATH_INBOX_DIR: + case CecDataPathType::CEC_PATH_OUTBOX_DIR: + rb.Push(Service::FS::DeleteDirectoryRecursivelyFromArchive( + cecd->cecd_system_save_data_archive, path)); + break; + default: /// If not directory, then it is a file + if (message_id_size == 0) { + rb.Push(Service::FS::DeleteFileFromArchive(cecd->cecd_system_save_data_archive, path)); + } else { + std::vector id_buffer(message_id_size); + message_id_buffer.Read(id_buffer.data(), 0, message_id_size); + + FileSys::Path message_path; + if (is_outbox) { + message_path = + cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } else { /// otherwise inbox + message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, + ncch_program_id, id_buffer) + .data(); + } + rb.Push(Service::FS::DeleteFileFromArchive(cecd->cecd_system_save_data_archive, + message_path)); + } + } + rb.PushMappedBuffer(message_id_buffer); LOG_DEBUG(Service_CECD, - "called, ncch_program_id={:#010x}, path_type={:#04x}, " + "called, ncch_program_id={:#010x}, path_type={:#04x}, path={}, " "is_outbox={}, message_id_size={:#x}", - ncch_program_id, static_cast(path_type), is_outbox, message_id_size); + ncch_program_id, static_cast(path_type), path.AsString(), is_outbox, + message_id_size); } void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// Update Index/List? @@ -798,25 +836,28 @@ std::string Module::GetCecCommandAsString(const CecCommand command) const { void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, std::vector& file_buffer) { + constexpr u32 max_num_boxes = 24; + constexpr u32 name_size = 16; /// fixed size 16 characters long + constexpr u32 valid_name_size = 8; /// 8 characters are valid, the rest are null const u32 file_size = file_buffer.size(); switch (path_type) { case CecDataPathType::CEC_PATH_MBOX_LIST: { CecMBoxListHeader mbox_list_header = {}; - CecMBoxListBoxes mbox_list_boxes = {}; std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); - std::memcpy(&mbox_list_boxes, &file_buffer[0xC], sizeof(CecMBoxListBoxes)); - if (file_size != 0x18C) { /// 0x18C CecMBoxListHeader + CecMBoxListBoxes + if (file_size != sizeof(CecMBoxListHeader)) { /// 0x18C LOG_DEBUG(Service_CECD, "CecMBoxListHeader size is incorrect: {}", file_size); } if (mbox_list_header.magic != 0x6868) { /// 'hh' - if (mbox_list_header.magic == 0) + if (mbox_list_header.magic == 0 || mbox_list_header.magic == 0xFFFF) { LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is not set"); - else + } else { LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is incorrect: {}", mbox_list_header.magic); + } + std::memset(&mbox_list_header, 0, sizeof(CecMBoxListHeader)); mbox_list_header.magic = 0x6868; } @@ -832,10 +873,69 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ if (mbox_list_header.num_boxes > 24) { LOG_DEBUG(Service_CECD, "CecMBoxListHeader number of boxes is too large: {}", mbox_list_header.num_boxes); - } + } else { + std::vector name_buffer(name_size); + std::memset(name_buffer.data(), 0, name_size); + if (ncch_program_id != 0) { + std::string name = Common::StringFromFormat("%08x", ncch_program_id); + std::memcpy(name_buffer.data(), name.data(), name.size()); + + bool already_activated = false; + for (auto i = 0; i < mbox_list_header.num_boxes; i++) { + LOG_DEBUG(Service_CECD, "{}", i); + /// Box names start at offset 0xC, are 16 char long, first 8 id, last 8 null + if (std::memcmp(name_buffer.data(), &mbox_list_header.box_names[i * name_size], + valid_name_size) == 0) { + LOG_DEBUG(Service_CECD, "Title already activated"); + already_activated = true; + } + }; + + if (!already_activated) { + if (mbox_list_header.num_boxes < max_num_boxes) { /// max boxes + LOG_DEBUG(Service_CECD, "Adding title to mboxlist____: {}", name); + std::memcpy( + &mbox_list_header.box_names[mbox_list_header.num_boxes * name_size], + name_buffer.data(), name_size); + mbox_list_header.num_boxes++; + } + } + } else { /// ncch_program_id == 0, remove/update activated boxes + /// We need to read the /CEC directory to find out which titles, if any, + /// are activated. The num_of_titles = (total_read_count) - 1, to adjust for + /// the MBoxList____ file that is present in the directory as well. + FileSys::Path root_path( + GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, 0).data()); + + auto dir_result = + Service::FS::OpenDirectoryFromArchive(cecd_system_save_data_archive, root_path); + + auto root_dir = dir_result.Unwrap(); + std::vector entries(max_num_boxes + 1); // + 1 mboxlist + const u32 entry_count = root_dir->backend->Read(max_num_boxes + 1, entries.data()); + root_dir->backend->Close(); + + LOG_DEBUG(Service_CECD, "Number of entries found in /CEC = {}", entry_count); + + std::string mbox_list_name("MBoxList____"); + std::string file_name; + std::u16string u16_filename; + + /// Loop through entries but don't add mboxlist____ to itself. + for (auto i = 0; i < entry_count; i++) { + u16_filename = std::u16string(entries[i].filename); + file_name = Common::UTF16ToUTF8(u16_filename); + + if (mbox_list_name.compare(file_name) != 0) { + LOG_DEBUG(Service_CECD, "Adding title to mboxlist____: {}", file_name); + std::memcpy(&mbox_list_header.box_names[16 * mbox_list_header.num_boxes++], + file_name.data(), valid_name_size); + } + } + } + } std::memcpy(file_buffer.data(), &mbox_list_header, sizeof(CecMBoxListHeader)); - std::memcpy(&file_buffer[0xC], &mbox_list_boxes, sizeof(CecMBoxListBoxes)); break; } case CecDataPathType::CEC_PATH_MBOX_INFO: { diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 593f264d3..0fbda5da2 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -152,24 +152,17 @@ public: static_assert(sizeof(CecMBoxInfoHeader) == 0x60, "CecMBoxInfoHeader struct has incorrect size."); - struct CecMBoxListBoxes { - struct Box { - u32_le ncch_program_id; - u32_le padding; - u64_le padding2; - } box[24]; - }; - static_assert(sizeof(CecMBoxListBoxes) == 0x180, "CecMBoxListBoxes struct has incorrect size."); - struct CecMBoxListHeader { u16_le magic; // 0x6868 'hh' u16_le padding; u16_le version; /// 0x01 00, maybe activated flag? u16_le padding2; - u16_le num_boxes; /// 24 max? + u16_le num_boxes; /// 24 max u16_le padding3; + u8 box_names[16 * 24]; /// 16 char names, 24 boxes }; - static_assert(sizeof(CecMBoxListHeader) == 0xC, "CecMBoxListHeader struct has incorrect size."); + static_assert(sizeof(CecMBoxListHeader) == 0x18C, + "CecMBoxListHeader struct has incorrect size."); struct CecMessageHeader { u16_le magic; // `` @@ -222,7 +215,7 @@ public: BitField<1, 1, u32> read; /// 2 BitField<2, 1, u32> write; /// 4 BitField<3, 1, u32> create; /// 8 - BitField<4, 1, u32> check; /// 16 + BitField<4, 1, u32> check; /// 16 maybe validate sig? BitField<30, 1, u32> unk_flag; }; @@ -579,13 +572,13 @@ public: }; private: - const std::vector cecd_system_savedata_id = {0x00, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x01, 0x00}; - /// String used by cecd for base64 encoding found in the sysmodule disassembly const std::string base64_dict = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; + const std::vector cecd_system_savedata_id = {0x00, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x01, 0x00}; + /// Encoding function used for the message id std::string EncodeBase64(const std::vector& in, const std::string& dictionary) const; @@ -594,7 +587,6 @@ private: std::string GetCecCommandAsString(const CecCommand command) const; - // void CreateAndPopulateMBoxDirectory(const u32 ncch_program_id); void CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, std::vector& file_buffer); From 25e7209d5cf33473dec828aef8f1e3da70bc65a3 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Sat, 25 Aug 2018 02:31:01 -0400 Subject: [PATCH 12/21] service/cecd: Updated function names --- src/core/hle/service/cecd/cecd.cpp | 38 ++++++++++++------ src/core/hle/service/cecd/cecd.h | 59 ++++++++++++++-------------- src/core/hle/service/cecd/cecd_s.cpp | 17 ++++---- src/core/hle/service/cecd/cecd_u.cpp | 16 ++++---- 4 files changed, 73 insertions(+), 57 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index ede743bea..6a88e16dd 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -74,7 +74,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { std::vector entries(max_entries); const u32 entry_count = directory->backend->Read(max_entries, entries.data()); - LOG_DEBUG(Service_CECD, "Number of entries found in = {}", entry_count); + LOG_DEBUG(Service_CECD, "Number of entries found: {}", entry_count); rb.Push(RESULT_SUCCESS); rb.Push(entry_count); /// Entry count @@ -114,7 +114,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { open_mode.check); } -void Module::Interface::ReadFile(Kernel::HLERequestContext& ctx) { +void Module::Interface::Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x02, 1, 2); const u32 write_buffer_size = rp.Pop(); auto& write_buffer = rp.PopMappedBuffer(); @@ -267,7 +267,7 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { ncch_program_id, is_outbox, message_id_size, buffer_size); } -void Module::Interface::WriteFile(Kernel::HLERequestContext& ctx) { +void Module::Interface::Write(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x05, 1, 2); const u32 read_buffer_size = rp.Pop(); auto& read_buffer = rp.PopMappedBuffer(); @@ -476,7 +476,7 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { /// DeleteMessa message_id_size); } -void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// Update Index/List? +void Module::Interface::SetData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x09, 3, 2); const u32 ncch_program_id = rp.Pop(); const u32 buffer_size = rp.Pop(); @@ -484,7 +484,7 @@ void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// Up auto& message_id_buffer = rp.PopMappedBuffer(); if (buffer_size > 0) { - FileSys::Path path("/Cecd_0x000900C2.out"); + FileSys::Path path("/SetData.out"); FileSys::Mode mode; mode.write_flag.Assign(1); mode.create_flag.Assign(1); @@ -503,7 +503,7 @@ void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// Up SessionData* session_data = GetSessionData(ctx.Session()); if (session_data->file) - LOG_DEBUG( + LOG_TRACE( Service_CECD, "SessionData: ncch_program_id={:#010x}, data_path_type={:#04x}, " "path={}, open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", @@ -524,7 +524,7 @@ void Module::Interface::Cecd_0x000900C2(Kernel::HLERequestContext& ctx) { /// Up ncch_program_id, buffer_size, option); } -void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { +void Module::Interface::ReadData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0A, 3, 4); const u32 dest_buffer_size = rp.Pop(); const CecSystemInfoType info_type = rp.PopEnum(); @@ -561,7 +561,7 @@ void Module::Interface::GetSystemInfo(Kernel::HLERequestContext& ctx) { dest_buffer_size, static_cast(info_type), param_buffer_size); } -void Module::Interface::RunCommand(Kernel::HLERequestContext& ctx) { +void Module::Interface::Start(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0B, 1, 0); const CecCommand command = rp.PopEnum(); @@ -571,7 +571,7 @@ void Module::Interface::RunCommand(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", cecd->GetCecCommandAsString(command)); } -void Module::Interface::RunCommandAlt(Kernel::HLERequestContext& ctx) { +void Module::Interface::Stop(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0C, 1, 0); const CecCommand command = rp.PopEnum(); @@ -581,12 +581,26 @@ void Module::Interface::RunCommandAlt(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", cecd->GetCecCommandAsString(command)); } -void Module::Interface::GetCecStateAbbreviated(Kernel::HLERequestContext& ctx) { +void Module::Interface::GetCecInfoBuffer(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0D, 2, 2); + const u32 buffer_size = rp.Pop(); + const u32 possible_info_type = rp.Pop(); + auto& buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(buffer); + + LOG_DEBUG(Service_CECD, "called, buffer_size={}, possible_info_type={}", buffer_size, + possible_info_type); +} + +void Module::Interface::GetCecdState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0E, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); - rb.PushEnum(CecStateAbbreviated::CEC_STATE_ABBREV_IDLE); + rb.PushEnum(CecdState::NDM_STATUS_IDLE); LOG_WARNING(Service_CECD, "(STUBBED) called"); } @@ -916,7 +930,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ const u32 entry_count = root_dir->backend->Read(max_num_boxes + 1, entries.data()); root_dir->backend->Close(); - LOG_DEBUG(Service_CECD, "Number of entries found in /CEC = {}", entry_count); + LOG_DEBUG(Service_CECD, "Number of entries found in /CEC: {}", entry_count); std::string mbox_list_name("MBoxList____"); std::string file_name; diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 0fbda5da2..6e9dbe05d 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -97,15 +97,6 @@ public: CEC_STATE_IDLE = 26 }; - /// Need to confirm if CecStateAbbreviated is up-to-date and valid - enum class CecStateAbbreviated : u32 { - CEC_STATE_ABBREV_IDLE = 1, /// Relates to CEC_STATE_IDLE - CEC_STATE_ABBREV_NOT_LOCAL = 2, /// Relates to CEC_STATEs *FINISH*, *POST, and OVER_BOSS - CEC_STATE_ABBREV_SCANNING = 3, /// Relates to CEC_STATE_SCANNING - CEC_STATE_ABBREV_WLREADY = 4, /// Relates to CEC_STATE_WIRELESS_READY when a bool is true - CEC_STATE_ABBREV_OTHER = 5, /// Relates to CEC_STATEs besides *FINISH*, *POST, and - }; /// OVER_BOSS and those listed here - enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; struct CecInOutBoxInfoHeader { @@ -202,7 +193,7 @@ public: }; static_assert(sizeof(CecOBIndexHeader) == 0x08, "CecOBIndexHeader struct has incorrect size."); - enum class CecNdmStatus : u32 { + enum class CecdState : u32 { NDM_STATUS_WORKING = 0, NDM_STATUS_IDLE = 1, NDM_STATUS_SUSPENDING = 2, @@ -265,7 +256,7 @@ public: void Open(Kernel::HLERequestContext& ctx); /** - * CECD::ReadFile service function + * CECD::Read service function * Inputs: * 0 : Header Code[0x00020042] * 1 : Buffer size (unused) @@ -277,7 +268,7 @@ public: * 3 : Descriptor for mapping a write-only buffer in the target process * 4 : Buffer address */ - void ReadFile(Kernel::HLERequestContext& ctx); + void Read(Kernel::HLERequestContext& ctx); /** * CECD::ReadMessage service function @@ -328,7 +319,7 @@ public: void ReadMessageWithHMAC(Kernel::HLERequestContext& ctx); /** - * CECD::WriteFile service function + * CECD::Write service function * Inputs: * 0 : Header Code[0x00050042] * 1 : Buffer size(unused) @@ -339,7 +330,7 @@ public: * 2 : Descriptor for mapping a read-only buffer in the target process * 3 : Buffer address */ - void WriteFile(Kernel::HLERequestContext& ctx); + void Write(Kernel::HLERequestContext& ctx); /** * CECD::WriteMessage service function @@ -405,7 +396,7 @@ public: void Delete(Kernel::HLERequestContext& ctx); /** - * CECD::Cecd_0x000900C2 service function + * CECD::SetData service function * Inputs: * 0 : Header Code[0x000900C2] * 1 : NCCH Program ID @@ -418,10 +409,10 @@ public: * 2 : Descriptor for mapping a read-only buffer in the target process * 3 : Message ID address */ - void Cecd_0x000900C2(Kernel::HLERequestContext& ctx); + void SetData(Kernel::HLERequestContext& ctx); /** - * CECD::GetSystemInfo service function + * CECD::ReadData service function * Inputs: * 0 : Header Code[0x000A00C4] * 1 : Destination buffer size (unused) @@ -438,51 +429,51 @@ public: * 4 : Descriptor for mapping a write-only buffer in the target process * 5 : Destination buffer address */ - void GetSystemInfo(Kernel::HLERequestContext& ctx); + void ReadData(Kernel::HLERequestContext& ctx); /** - * CECD::RunCommand service function + * CECD::Start service function * Inputs: * 0 : Header Code[0x000B0040] * 1 : Command * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ - void RunCommand(Kernel::HLERequestContext& ctx); + void Start(Kernel::HLERequestContext& ctx); /** - * CECD::RunCommandAlt service function + * CECD::Stop service function * Inputs: * 0 : Header Code[0x000C0040] * 1 : Command * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ - void RunCommandAlt(Kernel::HLERequestContext& ctx); + void Stop(Kernel::HLERequestContext& ctx); /** * CECD::GetCecInfoBuffer service function * Inputs: * 0 : Header Code[0x000D0082] * 1 : unknown - * 2 : unknown - * 3 : buffer descriptor - * 4 : buffer address + * 2 : unknown, buffer size? + * 3 : Descriptor for mapping a write-only buffer in the target process + * 4 : Destination buffer address * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * 2 : + * 2-3 : MappedBuffer */ void GetCecInfoBuffer(Kernel::HLERequestContext& ctx); /** - * GetCecStateAbbreviated service function + * GetCecdState service function * Inputs: * 0: Header Code[0x000E0000] * Outputs: * 1: ResultCode - * 2: CecStateAbbreviated + * 2: CecdState */ - void GetCecStateAbbreviated(Kernel::HLERequestContext& ctx); + void GetCecdState(Kernel::HLERequestContext& ctx); /** * GetCecInfoEventHandle service function @@ -567,6 +558,16 @@ public: */ void GetEventLogStart(Kernel::HLERequestContext& ctx); + /** + * GetCecInfoEventHandleSys service function + * Inputs: + * 0: Header Code[0x40020002] + * Outputs: + * 1: ResultCode + * 3: Event Handle + */ + void GetCecInfoEventHandleSys(Kernel::HLERequestContext& ctx); + private: std::shared_ptr cecd; }; diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp index a83f9c357..f84d90450 100644 --- a/src/core/hle/service/cecd/cecd_s.cpp +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -13,25 +13,26 @@ CECD_S::CECD_S(std::shared_ptr cecd) // cecd:u shared commands // clang-format off {0x000100C2, &CECD_S::Open, "Open"}, - {0x00020042, &CECD_S::ReadFile, "ReadFile"}, + {0x00020042, &CECD_S::Read, "Read"}, {0x00030104, &CECD_S::ReadMessage, "ReadMessage"}, {0x00040106, &CECD_S::ReadMessageWithHMAC, "ReadMessageWithHMAC"}, - {0x00050042, &CECD_S::WriteFile, "WriteFile"}, + {0x00050042, &CECD_S::Write, "Write"}, {0x00060104, &CECD_S::WriteMessage, "WriteMessage"}, {0x00070106, &CECD_S::WriteMessageWithHMAC, "WriteMessageWithHMAC"}, {0x00080102, &CECD_S::Delete, "Delete"}, - {0x000900C2, &CECD_S::Cecd_0x000900C2, "Cecd_0x000900C2"}, - {0x000A00C4, &CECD_S::GetSystemInfo, "GetSystemInfo"}, - {0x000B0040, &CECD_S::RunCommand, "RunCommand"}, - {0x000C0040, &CECD_S::RunCommandAlt, "RunCommandAlt"}, - {0x000D0082, nullptr, "GetCecInfoBuffer"}, - {0x000E0000, &CECD_S::GetCecStateAbbreviated, "GetCecStateAbbreviated"}, + {0x000900C2, &CECD_S::SetData, "SetData"}, + {0x000A00C4, &CECD_S::ReadData, "ReadData"}, + {0x000B0040, &CECD_S::Start, "Start"}, + {0x000C0040, &CECD_S::Stop, "Stop"}, + {0x000D0082, &CECD_S::GetCecInfoBuffer, "GetCecInfoBuffer"}, + {0x000E0000, &CECD_S::GetCecdState, "GetCecdState"}, {0x000F0000, &CECD_S::GetCecInfoEventHandle, "GetCecInfoEventHandle"}, {0x00100000, &CECD_S::GetChangeStateEventHandle, "GetChangeStateEventHandle"}, {0x00110104, &CECD_S::OpenAndWrite, "OpenAndWrite"}, {0x00120104, &CECD_S::OpenAndRead, "OpenAndRead"}, {0x001E0082, nullptr, "GetEventLog"}, {0x001F0000, nullptr, "GetEventLogStart"}, + {0x40020002, nullptr, "GetCecInfoEventHandleSys"}, // clang-format on }; diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp index a580872f0..0f721796a 100644 --- a/src/core/hle/service/cecd/cecd_u.cpp +++ b/src/core/hle/service/cecd/cecd_u.cpp @@ -13,19 +13,19 @@ CECD_U::CECD_U(std::shared_ptr cecd) // cecd:u shared commands // clang-format off {0x000100C2, &CECD_U::Open, "Open"}, - {0x00020042, &CECD_U::ReadFile, "ReadFile"}, + {0x00020042, &CECD_U::Read, "Read"}, {0x00030104, &CECD_U::ReadMessage, "ReadMessage"}, {0x00040106, &CECD_U::ReadMessageWithHMAC, "ReadMessageWithHMAC"}, - {0x00050042, &CECD_U::WriteFile, "WriteFile"}, + {0x00050042, &CECD_U::Write, "Write"}, {0x00060104, &CECD_U::WriteMessage, "WriteMessage"}, {0x00070106, &CECD_U::WriteMessageWithHMAC, "WriteMessageWithHMAC"}, {0x00080102, &CECD_U::Delete, "Delete"}, - {0x000900C2, &CECD_U::Cecd_0x000900C2, "Cecd_0x000900C2"}, - {0x000A00C4, &CECD_U::GetSystemInfo, "GetSystemInfo"}, - {0x000B0040, &CECD_U::RunCommand, "RunCommand"}, - {0x000C0040, &CECD_U::RunCommandAlt, "RunCommandAlt"}, - {0x000D0082, nullptr, "GetCecInfoBuffer"}, - {0x000E0000, &CECD_U::GetCecStateAbbreviated, "GetCecStateAbbreviated"}, + {0x000900C2, &CECD_U::SetData, "SetData"}, + {0x000A00C4, &CECD_U::ReadData, "ReadData"}, + {0x000B0040, &CECD_U::Start, "Start"}, + {0x000C0040, &CECD_U::Stop, "Stop"}, + {0x000D0082, &CECD_U::GetCecInfoBuffer, "GetCecInfoBuffer"}, + {0x000E0000, &CECD_U::GetCecdState, "GetCecdState"}, {0x000F0000, &CECD_U::GetCecInfoEventHandle, "GetCecInfoEventHandle"}, {0x00100000, &CECD_U::GetChangeStateEventHandle, "GetChangeStateEventHandle"}, {0x00110104, &CECD_U::OpenAndWrite, "OpenAndWrite"}, From dd7234a6d08ebab503b9417d9b7341cb38f70ce1 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Thu, 30 Aug 2018 02:39:53 -0400 Subject: [PATCH 13/21] service/cecd: Migrate Common::StringFromFormat(...) to fmt::format(...) --- src/core/hle/service/cecd/cecd.cpp | 34 +++++++++++++----------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 6a88e16dd..e1ce05c2e 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -2,12 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include -#include #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" -#include "core/core.h" +#include "fmt/format.h" #include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" #include "core/file_sys/errors.h" @@ -19,7 +17,6 @@ #include "core/hle/service/cecd/cecd_ndm.h" #include "core/hle/service/cecd/cecd_s.h" #include "core/hle/service/cecd/cecd_u.h" -#include "core/loader/smdh.h" namespace Service { namespace CECD { @@ -767,33 +764,32 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const case CecDataPathType::CEC_PATH_MBOX_LIST: return "/CEC/MBoxList____"; case CecDataPathType::CEC_PATH_MBOX_INFO: - return Common::StringFromFormat("/CEC/%08x/MBoxInfo____", program_id); + return fmt::format("/CEC/{:08x}/MBoxInfo____", program_id); case CecDataPathType::CEC_PATH_INBOX_INFO: - return Common::StringFromFormat("/CEC/%08x/InBox___/BoxInfo_____", program_id); + return fmt::format("/CEC/{:08x}/InBox___/BoxInfo_____", program_id); case CecDataPathType::CEC_PATH_OUTBOX_INFO: - return Common::StringFromFormat("/CEC/%08x/OutBox__/BoxInfo_____", program_id); + return fmt::format("/CEC/{:08x}/OutBox__/BoxInfo_____", program_id); case CecDataPathType::CEC_PATH_OUTBOX_INDEX: - return Common::StringFromFormat("/CEC/%08x/OutBox__/OBIndex_____", program_id); + return fmt::format("/CEC/{:08x}/OutBox__/OBIndex_____", program_id); case CecDataPathType::CEC_PATH_INBOX_MSG: - return Common::StringFromFormat("/CEC/%08x/InBox___/_%08x", program_id, - EncodeBase64(msg_id, base64_dict).data()); + return fmt::format("/CEC/{:08x}/InBox___/_{}", program_id, + EncodeBase64(msg_id, base64_dict)); case CecDataPathType::CEC_PATH_OUTBOX_MSG: - return Common::StringFromFormat("/CEC/%08x/OutBox__/_%08x", program_id, - EncodeBase64(msg_id, base64_dict).data()); + return fmt::format("/CEC/{:08x}/OutBox__/_{}", program_id, + EncodeBase64(msg_id, base64_dict)); case CecDataPathType::CEC_PATH_ROOT_DIR: return "/CEC"; case CecDataPathType::CEC_PATH_MBOX_DIR: - return Common::StringFromFormat("/CEC/%08x", program_id); + return fmt::format("/CEC/{:08x}", program_id); case CecDataPathType::CEC_PATH_INBOX_DIR: - return Common::StringFromFormat("/CEC/%08x/InBox___", program_id); + return fmt::format("/CEC/{:08x}/InBox___", program_id); case CecDataPathType::CEC_PATH_OUTBOX_DIR: - return Common::StringFromFormat("/CEC/%08x/OutBox__", program_id); + return fmt::format("/CEC/{:08x}/OutBox__", program_id); case CecDataPathType::CEC_MBOX_DATA: case CecDataPathType::CEC_MBOX_ICON: case CecDataPathType::CEC_MBOX_TITLE: default: - return Common::StringFromFormat("/CEC/%08x/MBoxData.%03d", program_id, - static_cast(type) - 100); + return fmt::format("/CEC/{:08x}/MBoxData.{:03}", program_id, static_cast(type) - 100); } } @@ -892,7 +888,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memset(name_buffer.data(), 0, name_size); if (ncch_program_id != 0) { - std::string name = Common::StringFromFormat("%08x", ncch_program_id); + std::string name = fmt::format("{:08x}", ncch_program_id); std::memcpy(name_buffer.data(), name.data(), name.size()); bool already_activated = false; @@ -1171,7 +1167,7 @@ Module::Module() { /// eventlog.dat resides in the root of the archive beside the CEC directory /// Initially created, at offset 0x0, are bytes 0x01 0x41 0x12, followed by /// zeroes until offset 0x1000, where it changes to 0xDD until the end of file - /// at offset 0x30d53 + /// at offset 0x30d53. Not sure why the 0xDD... FileSys::Path eventlog_path("/eventlog.dat"); auto eventlog_result = From c185c35bc23f1a91a42e74822297fb9d9f4ca781 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Thu, 30 Aug 2018 13:48:46 -0400 Subject: [PATCH 14/21] service/cecd: Clang format fixup --- src/core/hle/service/cecd/cecd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index e1ce05c2e..ef5fbe1c5 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -5,7 +5,6 @@ #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" -#include "fmt/format.h" #include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" #include "core/file_sys/errors.h" @@ -17,6 +16,7 @@ #include "core/hle/service/cecd/cecd_ndm.h" #include "core/hle/service/cecd/cecd_s.h" #include "core/hle/service/cecd/cecd_u.h" +#include "fmt/format.h" namespace Service { namespace CECD { From c89759f597c3bad7a76e4e35340a498324e4ede6 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Thu, 30 Aug 2018 20:27:46 -0400 Subject: [PATCH 15/21] service/cecd: Corrected eventlog.dat creation --- src/core/hle/service/cecd/cecd.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index ef5fbe1c5..b5ad6f061 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -420,7 +420,7 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { ncch_program_id, is_outbox, message_id_size, buffer_size); } -void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { /// DeleteMessage? +void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x08, 4, 2); const u32 ncch_program_id = rp.Pop(); const CecDataPathType path_type = rp.PopEnum(); @@ -1167,7 +1167,8 @@ Module::Module() { /// eventlog.dat resides in the root of the archive beside the CEC directory /// Initially created, at offset 0x0, are bytes 0x01 0x41 0x12, followed by /// zeroes until offset 0x1000, where it changes to 0xDD until the end of file - /// at offset 0x30d53. Not sure why the 0xDD... + /// at offset 0x30d53. 0xDD means that the cec module hasn't written data to that + /// region yet. FileSys::Path eventlog_path("/eventlog.dat"); auto eventlog_result = @@ -1181,7 +1182,6 @@ Module::Module() { eventlog_buffer[0] = 0x01; eventlog_buffer[1] = 0x41; eventlog_buffer[2] = 0x12; - std::memset(&eventlog_buffer[0x1000], 0xDD, eventlog_size - 0x1000); eventlog->backend->Write(0, eventlog_size, true, eventlog_buffer.data()); eventlog->backend->Close(); From 69b3217394f8af591ea4da0b8d41fe54ca11aa2f Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Thu, 6 Sep 2018 15:48:00 -0400 Subject: [PATCH 16/21] service/cecd: Addressed comments, code cleanup --- src/core/hle/service/cecd/cecd.cpp | 339 +++++++++++++---------------- src/core/hle/service/cecd/cecd.h | 192 ++++++++-------- 2 files changed, 249 insertions(+), 282 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index b5ad6f061..bc87e63b6 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -47,10 +47,10 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); switch (path_type) { - case CecDataPathType::CEC_PATH_ROOT_DIR: - case CecDataPathType::CEC_PATH_MBOX_DIR: - case CecDataPathType::CEC_PATH_INBOX_DIR: - case CecDataPathType::CEC_PATH_OUTBOX_DIR: { + case CecDataPathType::ROOT_DIR: + case CecDataPathType::MBOX_DIR: + case CecDataPathType::INBOX_DIR: + case CecDataPathType::OUTBOX_DIR: { auto dir_result = Service::FS::OpenDirectoryFromArchive(cecd->cecd_system_save_data_archive, path); if (dir_result.Failed()) { @@ -62,38 +62,38 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); } - rb.Push(0); /// Zero entries + rb.Push(0); // Zero entries } else { - constexpr u32 max_entries = 32; /// reasonable value, just over max boxes 24 + constexpr u32 max_entries = 32; // reasonable value, just over max boxes 24 auto directory = dir_result.Unwrap(); - /// Actual reading into vector seems to be required for entry count + // Actual reading into vector seems to be required for entry count std::vector entries(max_entries); const u32 entry_count = directory->backend->Read(max_entries, entries.data()); LOG_DEBUG(Service_CECD, "Number of entries found: {}", entry_count); rb.Push(RESULT_SUCCESS); - rb.Push(entry_count); /// Entry count + rb.Push(entry_count); // Entry count directory->backend->Close(); } break; } - default: { /// If not directory, then it is a file + default: { // If not directory, then it is a file auto file_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); if (file_result.Failed()) { LOG_DEBUG(Service_CECD, "Failed to open file: {}", path.AsString()); rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); - rb.Push(0); /// No file size + rb.Push(0); // No file size } else { session_data->file = std::move(file_result.Unwrap()); rb.Push(RESULT_SUCCESS); - rb.Push(session_data->file->backend->GetSize()); /// Return file size + rb.Push(session_data->file->backend->GetSize()); // Return file size } - if (path_type == CecDataPathType::CEC_MBOX_PROGRAM_ID) { + if (path_type == CecDataPathType::MBOX_PROGRAM_ID) { std::vector program_id(8); u64_le le_program_id = Kernel::g_current_process->codeset->program_id; std::memcpy(program_id.data(), &le_program_id, sizeof(u64)); @@ -128,15 +128,15 @@ void Module::Interface::Read(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); switch (session_data->data_path_type) { - case CecDataPathType::CEC_PATH_ROOT_DIR: - case CecDataPathType::CEC_PATH_MBOX_DIR: - case CecDataPathType::CEC_PATH_INBOX_DIR: - case CecDataPathType::CEC_PATH_OUTBOX_DIR: + case CecDataPathType::ROOT_DIR: + case CecDataPathType::MBOX_DIR: + case CecDataPathType::INBOX_DIR: + case CecDataPathType::OUTBOX_DIR: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); - rb.Push(0); /// No bytes read + rb.Push(0); // No bytes read break; - default: /// If not directory, then it is a file + default: // If not directory, then it is a file std::vector buffer(write_buffer_size); const u32 bytes_read = session_data->file->backend->Read(0, write_buffer_size, buffer.data()).Unwrap(); @@ -168,16 +168,11 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { std::vector id_buffer(message_id_size); message_id_buffer.Read(id_buffer.data(), 0, message_id_size); - FileSys::Path message_path; - if (is_outbox) { - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } else { /// otherwise inbox - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } + FileSys::Path message_path = + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG + : CecDataPathType::INBOX_MSG, + ncch_program_id, id_buffer) + .data(); auto message_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, message_path, mode); @@ -196,7 +191,7 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { } else { rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); - rb.Push(0); /// zero bytes read + rb.Push(0); // zero bytes read } rb.PushMappedBuffer(message_id_buffer); rb.PushMappedBuffer(write_buffer); @@ -217,22 +212,19 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { auto& hmac_key_buffer = rp.PopMappedBuffer(); auto& write_buffer = rp.PopMappedBuffer(); + // TODO verify message HMAC with the given key + FileSys::Mode mode; mode.read_flag.Assign(1); std::vector id_buffer(message_id_size); message_id_buffer.Read(id_buffer.data(), 0, message_id_size); - FileSys::Path message_path; - if (is_outbox) { - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } else { /// otherwise inbox - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } + FileSys::Path message_path = + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG + : CecDataPathType::INBOX_MSG, + ncch_program_id, id_buffer) + .data(); auto message_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, message_path, mode); @@ -251,7 +243,7 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { } else { rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); - rb.Push(0); /// zero bytes read + rb.Push(0); // zero bytes read } rb.PushMappedBuffer(message_id_buffer); @@ -281,14 +273,14 @@ void Module::Interface::Write(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); switch (session_data->data_path_type) { - case CecDataPathType::CEC_PATH_ROOT_DIR: - case CecDataPathType::CEC_PATH_MBOX_DIR: - case CecDataPathType::CEC_PATH_INBOX_DIR: - case CecDataPathType::CEC_PATH_OUTBOX_DIR: + case CecDataPathType::ROOT_DIR: + case CecDataPathType::MBOX_DIR: + case CecDataPathType::INBOX_DIR: + case CecDataPathType::OUTBOX_DIR: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); break; - default: /// If not directory, then it is a file + default: // If not directory, then it is a file std::vector buffer(read_buffer_size); read_buffer.Read(buffer.data(), 0, read_buffer_size); @@ -324,16 +316,11 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { std::vector id_buffer(message_id_size); message_id_buffer.Read(id_buffer.data(), 0, message_id_size); - FileSys::Path message_path; - if (is_outbox) { - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } else { /// otherwise inbox - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } + FileSys::Path message_path = + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG + : CecDataPathType::INBOX_MSG, + ncch_program_id, id_buffer) + .data(); auto message_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, message_path, mode); @@ -373,6 +360,8 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { auto& hmac_key_buffer = rp.PopMappedBuffer(); auto& message_id_buffer = rp.PopMappedBuffer(); + // TODO verify message HMAC with the given key + FileSys::Mode mode; mode.write_flag.Assign(1); mode.create_flag.Assign(1); @@ -380,16 +369,11 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { std::vector id_buffer(message_id_size); message_id_buffer.Read(id_buffer.data(), 0, message_id_size); - FileSys::Path message_path; - if (is_outbox) { - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } else { /// otherwise inbox - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } + FileSys::Path message_path = + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG + : CecDataPathType::INBOX_MSG, + ncch_program_id, id_buffer) + .data(); auto message_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, message_path, mode); @@ -434,31 +418,25 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); switch (path_type) { - case CecDataPathType::CEC_PATH_ROOT_DIR: - case CecDataPathType::CEC_PATH_MBOX_DIR: - case CecDataPathType::CEC_PATH_INBOX_DIR: - case CecDataPathType::CEC_PATH_OUTBOX_DIR: + case CecDataPathType::ROOT_DIR: + case CecDataPathType::MBOX_DIR: + case CecDataPathType::INBOX_DIR: + case CecDataPathType::OUTBOX_DIR: rb.Push(Service::FS::DeleteDirectoryRecursivelyFromArchive( cecd->cecd_system_save_data_archive, path)); break; - default: /// If not directory, then it is a file + default: // If not directory, then it is a file if (message_id_size == 0) { rb.Push(Service::FS::DeleteFileFromArchive(cecd->cecd_system_save_data_archive, path)); } else { std::vector id_buffer(message_id_size); message_id_buffer.Read(id_buffer.data(), 0, message_id_size); - FileSys::Path message_path; - if (is_outbox) { - message_path = - cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_OUTBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } else { /// otherwise inbox - message_path = cecd->GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_INBOX_MSG, - ncch_program_id, id_buffer) - .data(); - } + FileSys::Path message_path = + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG + : CecDataPathType::INBOX_MSG, + ncch_program_id, id_buffer) + .data(); rb.Push(Service::FS::DeleteFileFromArchive(cecd->cecd_system_save_data_archive, message_path)); } @@ -480,24 +458,6 @@ void Module::Interface::SetData(Kernel::HLERequestContext& ctx) { const u32 option = rp.Pop(); auto& message_id_buffer = rp.PopMappedBuffer(); - if (buffer_size > 0) { - FileSys::Path path("/SetData.out"); - FileSys::Mode mode; - mode.write_flag.Assign(1); - mode.create_flag.Assign(1); - - auto file_result = - Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); - if (file_result.Succeeded()) { - auto file = file_result.Unwrap(); - std::vector buffer(buffer_size); - message_id_buffer.Read(buffer.data(), 0, buffer_size); - - file->backend->Write(0, buffer_size, true, buffer.data()); - file->backend->Close(); - } - } - SessionData* session_data = GetSessionData(ctx.Session()); if (session_data->file) LOG_TRACE( @@ -529,20 +489,20 @@ void Module::Interface::ReadData(Kernel::HLERequestContext& ctx) { auto& param_buffer = rp.PopMappedBuffer(); auto& dest_buffer = rp.PopMappedBuffer(); - /// TODO: Other CecSystemInfoTypes + // TODO: Other CecSystemInfoTypes IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); std::vector buffer; switch (info_type) { - case CecSystemInfoType::EulaVersion: /// TODO: Read config Eula version + case CecSystemInfoType::EulaVersion: // TODO: Read config Eula version buffer = {0xFF, 0xFF}; dest_buffer.Write(buffer.data(), 0, buffer.size()); break; case CecSystemInfoType::Eula: - buffer = {0x01}; /// Eula agreed + buffer = {0x01}; // Eula agreed dest_buffer.Write(buffer.data(), 0, buffer.size()); break; case CecSystemInfoType::ParentControl: - buffer = {0x00}; /// No parent control + buffer = {0x00}; // No parent control dest_buffer.Write(buffer.data(), 0, buffer.size()); break; default: @@ -639,14 +599,14 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); switch (path_type) { - case CecDataPathType::CEC_PATH_ROOT_DIR: - case CecDataPathType::CEC_PATH_MBOX_DIR: - case CecDataPathType::CEC_PATH_INBOX_DIR: - case CecDataPathType::CEC_PATH_OUTBOX_DIR: + case CecDataPathType::ROOT_DIR: + case CecDataPathType::MBOX_DIR: + case CecDataPathType::INBOX_DIR: + case CecDataPathType::OUTBOX_DIR: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); break; - default: /// If not directory, then it is a file + default: // If not directory, then it is a file auto file_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); if (file_result.Succeeded()) { @@ -694,15 +654,15 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); switch (path_type) { - case CecDataPathType::CEC_PATH_ROOT_DIR: - case CecDataPathType::CEC_PATH_MBOX_DIR: - case CecDataPathType::CEC_PATH_INBOX_DIR: - case CecDataPathType::CEC_PATH_OUTBOX_DIR: + case CecDataPathType::ROOT_DIR: + case CecDataPathType::MBOX_DIR: + case CecDataPathType::INBOX_DIR: + case CecDataPathType::OUTBOX_DIR: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); - rb.Push(0); /// No entries read + rb.Push(0); // No entries read break; - default: /// If not directory, then it is a file + default: // If not directory, then it is a file auto file_result = Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); if (file_result.Succeeded()) { @@ -718,7 +678,7 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { } else { rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); - rb.Push(0); /// No bytes read + rb.Push(0); // No bytes read } } rb.PushMappedBuffer(write_buffer); @@ -761,33 +721,33 @@ std::string Module::EncodeBase64(const std::vector& in, const std::string& d std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, const std::vector& msg_id) const { switch (type) { - case CecDataPathType::CEC_PATH_MBOX_LIST: + case CecDataPathType::MBOX_LIST: return "/CEC/MBoxList____"; - case CecDataPathType::CEC_PATH_MBOX_INFO: + case CecDataPathType::MBOX_INFO: return fmt::format("/CEC/{:08x}/MBoxInfo____", program_id); - case CecDataPathType::CEC_PATH_INBOX_INFO: + case CecDataPathType::INBOX_INFO: return fmt::format("/CEC/{:08x}/InBox___/BoxInfo_____", program_id); - case CecDataPathType::CEC_PATH_OUTBOX_INFO: + case CecDataPathType::OUTBOX_INFO: return fmt::format("/CEC/{:08x}/OutBox__/BoxInfo_____", program_id); - case CecDataPathType::CEC_PATH_OUTBOX_INDEX: + case CecDataPathType::OUTBOX_INDEX: return fmt::format("/CEC/{:08x}/OutBox__/OBIndex_____", program_id); - case CecDataPathType::CEC_PATH_INBOX_MSG: + case CecDataPathType::INBOX_MSG: return fmt::format("/CEC/{:08x}/InBox___/_{}", program_id, EncodeBase64(msg_id, base64_dict)); - case CecDataPathType::CEC_PATH_OUTBOX_MSG: + case CecDataPathType::OUTBOX_MSG: return fmt::format("/CEC/{:08x}/OutBox__/_{}", program_id, EncodeBase64(msg_id, base64_dict)); - case CecDataPathType::CEC_PATH_ROOT_DIR: + case CecDataPathType::ROOT_DIR: return "/CEC"; - case CecDataPathType::CEC_PATH_MBOX_DIR: + case CecDataPathType::MBOX_DIR: return fmt::format("/CEC/{:08x}", program_id); - case CecDataPathType::CEC_PATH_INBOX_DIR: + case CecDataPathType::INBOX_DIR: return fmt::format("/CEC/{:08x}/InBox___", program_id); - case CecDataPathType::CEC_PATH_OUTBOX_DIR: + case CecDataPathType::OUTBOX_DIR: return fmt::format("/CEC/{:08x}/OutBox__", program_id); - case CecDataPathType::CEC_MBOX_DATA: - case CecDataPathType::CEC_MBOX_ICON: - case CecDataPathType::CEC_MBOX_TITLE: + case CecDataPathType::MBOX_DATA: + case CecDataPathType::MBOX_ICON: + case CecDataPathType::MBOX_TITLE: default: return fmt::format("/CEC/{:08x}/MBoxData.{:03}", program_id, static_cast(type) - 100); } @@ -795,49 +755,49 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const std::string Module::GetCecCommandAsString(const CecCommand command) const { switch (command) { - case CecCommand::CEC_COMMAND_NONE: + case CecCommand::NONE: return "NONE"; - case CecCommand::CEC_COMMAND_START: + case CecCommand::START: return "START"; - case CecCommand::CEC_COMMAND_RESET_START: + case CecCommand::RESET_START: return "RESET_START"; - case CecCommand::CEC_COMMAND_READYSCAN: + case CecCommand::READYSCAN: return "READYSCAN"; - case CecCommand::CEC_COMMAND_READYSCANWAIT: + case CecCommand::READYSCANWAIT: return "READYSCANWAIT"; - case CecCommand::CEC_COMMAND_STARTSCAN: + case CecCommand::STARTSCAN: return "STARTSCAN"; - case CecCommand::CEC_COMMAND_RESCAN: + case CecCommand::RESCAN: return "RESCAN"; - case CecCommand::CEC_COMMAND_NDM_RESUME: + case CecCommand::NDM_RESUME: return "RESUME"; - case CecCommand::CEC_COMMAND_NDM_SUSPEND: + case CecCommand::NDM_SUSPEND: return "NDM_SUSPEND"; - case CecCommand::CEC_COMMAND_NDM_SUSPEND_IMMEDIATE: + case CecCommand::NDM_SUSPEND_IMMEDIATE: return "NDM_SUSPEND_IMMEDIATE"; - case CecCommand::CEC_COMMAND_STOPWAIT: + case CecCommand::STOPWAIT: return "STOPWAIT"; - case CecCommand::CEC_COMMAND_STOP: + case CecCommand::STOP: return "STOP"; - case CecCommand::CEC_COMMAND_STOP_FORCE: + case CecCommand::STOP_FORCE: return "STOP_FORCE"; - case CecCommand::CEC_COMMAND_STOP_FORCE_WAIT: + case CecCommand::STOP_FORCE_WAIT: return "STOP_FORCE_WAIT"; - case CecCommand::CEC_COMMAND_RESET_FILTER: + case CecCommand::RESET_FILTER: return "RESET_FILTER"; - case CecCommand::CEC_COMMAND_DAEMON_STOP: + case CecCommand::DAEMON_STOP: return "DAEMON_STOP"; - case CecCommand::CEC_COMMAND_DAEMON_START: + case CecCommand::DAEMON_START: return "DAEMON_START"; - case CecCommand::CEC_COMMAND_EXIT: + case CecCommand::EXIT: return "EXIT"; - case CecCommand::CEC_COMMAND_OVER_BOSS: + case CecCommand::OVER_BOSS: return "OVER_BOSS"; - case CecCommand::CEC_COMMAND_OVER_BOSS_FORCE: + case CecCommand::OVER_BOSS_FORCE: return "OVER_BOSS_FORCE"; - case CecCommand::CEC_COMMAND_OVER_BOSS_FORCE_WAIT: + case CecCommand::OVER_BOSS_FORCE_WAIT: return "OVER_BOSS_FORCE_WAIT"; - case CecCommand::CEC_COMMAND_END: + case CecCommand::END: return "END"; default: return "Unknown"; @@ -847,20 +807,20 @@ std::string Module::GetCecCommandAsString(const CecCommand command) const { void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, std::vector& file_buffer) { constexpr u32 max_num_boxes = 24; - constexpr u32 name_size = 16; /// fixed size 16 characters long - constexpr u32 valid_name_size = 8; /// 8 characters are valid, the rest are null + constexpr u32 name_size = 16; // fixed size 16 characters long + constexpr u32 valid_name_size = 8; // 8 characters are valid, the rest are null const u32 file_size = file_buffer.size(); switch (path_type) { - case CecDataPathType::CEC_PATH_MBOX_LIST: { + case CecDataPathType::MBOX_LIST: { CecMBoxListHeader mbox_list_header = {}; std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); - if (file_size != sizeof(CecMBoxListHeader)) { /// 0x18C + if (file_size != sizeof(CecMBoxListHeader)) { // 0x18C LOG_DEBUG(Service_CECD, "CecMBoxListHeader size is incorrect: {}", file_size); } - if (mbox_list_header.magic != 0x6868) { /// 'hh' + if (mbox_list_header.magic != 0x6868) { // 'hh' if (mbox_list_header.magic == 0 || mbox_list_header.magic == 0xFFFF) { LOG_DEBUG(Service_CECD, "CecMBoxListHeader magic number is not set"); } else { @@ -871,7 +831,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ mbox_list_header.magic = 0x6868; } - if (mbox_list_header.version != 0x01) { /// Not quite sure if it is a version + if (mbox_list_header.version != 0x01) { // Not quite sure if it is a version if (mbox_list_header.version == 0) LOG_DEBUG(Service_CECD, "CecMBoxListHeader version is not set"); else @@ -894,8 +854,8 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ bool already_activated = false; for (auto i = 0; i < mbox_list_header.num_boxes; i++) { LOG_DEBUG(Service_CECD, "{}", i); - /// Box names start at offset 0xC, are 16 char long, first 8 id, last 8 null - if (std::memcmp(name_buffer.data(), &mbox_list_header.box_names[i * name_size], + // Box names start at offset 0xC, are 16 char long, first 8 id, last 8 null + if (std::memcmp(name_buffer.data(), &mbox_list_header.box_names[i], valid_name_size) == 0) { LOG_DEBUG(Service_CECD, "Title already activated"); already_activated = true; @@ -903,20 +863,19 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ }; if (!already_activated) { - if (mbox_list_header.num_boxes < max_num_boxes) { /// max boxes + if (mbox_list_header.num_boxes < max_num_boxes) { // max boxes LOG_DEBUG(Service_CECD, "Adding title to mboxlist____: {}", name); - std::memcpy( - &mbox_list_header.box_names[mbox_list_header.num_boxes * name_size], - name_buffer.data(), name_size); + std::memcpy(&mbox_list_header.box_names[mbox_list_header.num_boxes], + name_buffer.data(), name_size); mbox_list_header.num_boxes++; } } - } else { /// ncch_program_id == 0, remove/update activated boxes + } else { // ncch_program_id == 0, remove/update activated boxes /// We need to read the /CEC directory to find out which titles, if any, /// are activated. The num_of_titles = (total_read_count) - 1, to adjust for /// the MBoxList____ file that is present in the directory as well. FileSys::Path root_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, 0).data()); + GetCecDataPathTypeAsString(CecDataPathType::ROOT_DIR, 0).data()); auto dir_result = Service::FS::OpenDirectoryFromArchive(cecd_system_save_data_archive, root_path); @@ -932,14 +891,14 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::string file_name; std::u16string u16_filename; - /// Loop through entries but don't add mboxlist____ to itself. + // Loop through entries but don't add mboxlist____ to itself. for (auto i = 0; i < entry_count; i++) { u16_filename = std::u16string(entries[i].filename); file_name = Common::UTF16ToUTF8(u16_filename); if (mbox_list_name.compare(file_name) != 0) { LOG_DEBUG(Service_CECD, "Adding title to mboxlist____: {}", file_name); - std::memcpy(&mbox_list_header.box_names[16 * mbox_list_header.num_boxes++], + std::memcpy(&mbox_list_header.box_names[mbox_list_header.num_boxes++], file_name.data(), valid_name_size); } } @@ -948,15 +907,15 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &mbox_list_header, sizeof(CecMBoxListHeader)); break; } - case CecDataPathType::CEC_PATH_MBOX_INFO: { + case CecDataPathType::MBOX_INFO: { CecMBoxInfoHeader mbox_info_header = {}; std::memcpy(&mbox_info_header, file_buffer.data(), sizeof(CecMBoxInfoHeader)); - if (file_size != sizeof(CecMBoxInfoHeader)) { /// 0x60 + if (file_size != sizeof(CecMBoxInfoHeader)) { // 0x60 LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader size is incorrect: {}", file_size); } - if (mbox_info_header.magic != 0x6363) { /// 'cc' + if (mbox_info_header.magic != 0x6363) { // 'cc' if (mbox_info_header.magic == 0) LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader magic number is not set"); else @@ -976,11 +935,11 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &mbox_info_header, sizeof(CecMBoxInfoHeader)); break; } - case CecDataPathType::CEC_PATH_INBOX_INFO: { + case CecDataPathType::INBOX_INFO: { CecInOutBoxInfoHeader inbox_info_header = {}; std::memcpy(&inbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); - if (inbox_info_header.magic != 0x6262) { /// 'bb' + if (inbox_info_header.magic != 0x6262) { // 'bb' if (inbox_info_header.magic == 0) LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader magic number is not set"); else @@ -1028,11 +987,11 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &inbox_info_header, sizeof(CecInOutBoxInfoHeader)); break; } - case CecDataPathType::CEC_PATH_OUTBOX_INFO: { + case CecDataPathType::OUTBOX_INFO: { CecInOutBoxInfoHeader outbox_info_header = {}; std::memcpy(&outbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); - if (outbox_info_header.magic != 0x6262) { /// 'bb' + if (outbox_info_header.magic != 0x6262) { // 'bb' if (outbox_info_header.magic == 0) LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader magic number is not set"); else @@ -1078,15 +1037,15 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &outbox_info_header, sizeof(CecInOutBoxInfoHeader)); break; } - case CecDataPathType::CEC_PATH_OUTBOX_INDEX: { + case CecDataPathType::OUTBOX_INDEX: { CecOBIndexHeader obindex_header = {}; std::memcpy(&obindex_header, file_buffer.data(), sizeof(CecOBIndexHeader)); - if (file_size < sizeof(CecOBIndexHeader)) { /// 0x08, minimum size + if (file_size < sizeof(CecOBIndexHeader)) { // 0x08, minimum size LOG_DEBUG(Service_CECD, "CecOBIndexHeader size is too small: {}", file_size); } - if (obindex_header.magic != 0x6767) { /// 'gg' + if (obindex_header.magic != 0x6767) { // 'gg' if (obindex_header.magic == 0) LOG_DEBUG(Service_CECD, "CecOBIndexHeader magic number is not set"); else @@ -1098,7 +1057,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ if (obindex_header.message_num == 0) { if (file_size > sizeof(CecOBIndexHeader)) { LOG_DEBUG(Service_CECD, "CecOBIndexHeader message number is not set"); - obindex_header.message_num = (file_size % 8) - 1; /// 8 byte message id - 1 header + obindex_header.message_num = (file_size % 8) - 1; // 8 byte message id - 1 header } } else if (obindex_header.message_num != (file_size % 8) - 1) { LOG_DEBUG(Service_CECD, "CecOBIndexHeader message number is incorrect: {}", @@ -1108,18 +1067,18 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &obindex_header, sizeof(CecOBIndexHeader)); break; } - case CecDataPathType::CEC_PATH_INBOX_MSG: + case CecDataPathType::INBOX_MSG: break; - case CecDataPathType::CEC_PATH_OUTBOX_MSG: + case CecDataPathType::OUTBOX_MSG: break; - case CecDataPathType::CEC_PATH_ROOT_DIR: - case CecDataPathType::CEC_PATH_MBOX_DIR: - case CecDataPathType::CEC_PATH_INBOX_DIR: - case CecDataPathType::CEC_PATH_OUTBOX_DIR: + case CecDataPathType::ROOT_DIR: + case CecDataPathType::MBOX_DIR: + case CecDataPathType::INBOX_DIR: + case CecDataPathType::OUTBOX_DIR: break; - case CecDataPathType::CEC_MBOX_DATA: - case CecDataPathType::CEC_MBOX_ICON: - case CecDataPathType::CEC_MBOX_TITLE: + case CecDataPathType::MBOX_DATA: + case CecDataPathType::MBOX_ICON: + case CecDataPathType::MBOX_TITLE: default: {} } } @@ -1157,7 +1116,7 @@ Module::Module() { /// Now that the archive is formatted, we need to create the root CEC directory, /// eventlog.dat, and CEC/MBoxList____ const FileSys::Path root_dir_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_ROOT_DIR, 0).data()); + GetCecDataPathTypeAsString(CecDataPathType::ROOT_DIR, 0).data()); Service::FS::CreateDirectoryFromArchive(*archive_result, root_dir_path); FileSys::Mode mode; @@ -1191,7 +1150,7 @@ Module::Module() { /// being the magic number. The rest of the file is filled with zeroes, until the end of /// file at offset 0x18b FileSys::Path mboxlist_path( - GetCecDataPathTypeAsString(CecDataPathType::CEC_PATH_MBOX_LIST, 0).data()); + GetCecDataPathTypeAsString(CecDataPathType::MBOX_LIST, 0).data()); auto mboxlist_result = Service::FS::OpenFileFromArchive(*archive_result, mboxlist_path, mode); @@ -1203,7 +1162,7 @@ Module::Module() { std::memset(&mboxlist_buffer[0], 0, mboxlist_size); mboxlist_buffer[0] = 0x68; mboxlist_buffer[1] = 0x68; - /// mboxlist_buffer[2-3] are already zeroed + // mboxlist_buffer[2-3] are already zeroed mboxlist_buffer[4] = 0x01; mboxlist->backend->Write(0, mboxlist_size, true, mboxlist_buffer.data()); diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 6e9dbe05d..11f50c741 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -5,6 +5,7 @@ #pragma once #include "common/bit_field.h" +#include "common/common_funcs.h" #include "core/hle/kernel/event.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/service.h" @@ -18,28 +19,28 @@ public: ~Module(); enum class CecCommand : u32 { - CEC_COMMAND_NONE = 0, - CEC_COMMAND_START = 1, - CEC_COMMAND_RESET_START = 2, - CEC_COMMAND_READYSCAN = 3, - CEC_COMMAND_READYSCANWAIT = 4, - CEC_COMMAND_STARTSCAN = 5, - CEC_COMMAND_RESCAN = 6, - CEC_COMMAND_NDM_RESUME = 7, - CEC_COMMAND_NDM_SUSPEND = 8, - CEC_COMMAND_NDM_SUSPEND_IMMEDIATE = 9, - CEC_COMMAND_STOPWAIT = 0x0A, - CEC_COMMAND_STOP = 0x0B, - CEC_COMMAND_STOP_FORCE = 0x0C, - CEC_COMMAND_STOP_FORCE_WAIT = 0x0D, - CEC_COMMAND_RESET_FILTER = 0x0E, - CEC_COMMAND_DAEMON_STOP = 0x0F, - CEC_COMMAND_DAEMON_START = 0x10, - CEC_COMMAND_EXIT = 0x11, - CEC_COMMAND_OVER_BOSS = 0x12, - CEC_COMMAND_OVER_BOSS_FORCE = 0x13, - CEC_COMMAND_OVER_BOSS_FORCE_WAIT = 0x14, - CEC_COMMAND_END = 0x15, + NONE = 0, + START = 1, + RESET_START = 2, + READYSCAN = 3, + READYSCANWAIT = 4, + STARTSCAN = 5, + RESCAN = 6, + NDM_RESUME = 7, + NDM_SUSPEND = 8, + NDM_SUSPEND_IMMEDIATE = 9, + STOPWAIT = 0x0A, + STOP = 0x0B, + STOP_FORCE = 0x0C, + STOP_FORCE_WAIT = 0x0D, + RESET_FILTER = 0x0E, + DAEMON_STOP = 0x0F, + DAEMON_START = 0x10, + EXIT = 0x11, + OVER_BOSS = 0x12, + OVER_BOSS_FORCE = 0x13, + OVER_BOSS_FORCE_WAIT = 0x14, + END = 0x15, }; /** @@ -49,59 +50,59 @@ public: * data:/CEC/test */ enum class CecDataPathType : u32 { - CEC_PATH_INVALID = 0, - CEC_PATH_MBOX_LIST = 1, /// data:/CEC/MBoxList____ - CEC_PATH_MBOX_INFO = 2, /// data:/CEC//MBoxInfo____ - CEC_PATH_INBOX_INFO = 3, /// data:/CEC//InBox___/BoxInfo_____ - CEC_PATH_OUTBOX_INFO = 4, /// data:/CEC//OutBox__/BoxInfo_____ - CEC_PATH_OUTBOX_INDEX = 5, /// data:/CEC//OutBox__/OBIndex_____ - CEC_PATH_INBOX_MSG = 6, /// data:/CEC//InBox___/_ - CEC_PATH_OUTBOX_MSG = 7, /// data:/CEC//OutBox__/_ - CEC_PATH_ROOT_DIR = 10, /// data:/CEC - CEC_PATH_MBOX_DIR = 11, /// data:/CEC/ - CEC_PATH_INBOX_DIR = 12, /// data:/CEC//InBox___ - CEC_PATH_OUTBOX_DIR = 13, /// data:/CEC//OutBox__ - CEC_MBOX_DATA = 100, /// data:/CEC//MBoxData.0 - CEC_MBOX_ICON = 101, /// data:/CEC//MBoxData.001 - CEC_MBOX_TITLE = 110, /// data:/CEC//MBoxData.010 - CEC_MBOX_PROGRAM_ID = 150, /// data:/CEC//MBoxData.050 + INVALID = 0, + MBOX_LIST = 1, /// data:/CEC/MBoxList____ + MBOX_INFO = 2, /// data:/CEC//MBoxInfo____ + INBOX_INFO = 3, /// data:/CEC//InBox___/BoxInfo_____ + OUTBOX_INFO = 4, /// data:/CEC//OutBox__/BoxInfo_____ + OUTBOX_INDEX = 5, /// data:/CEC//OutBox__/OBIndex_____ + INBOX_MSG = 6, /// data:/CEC//InBox___/_ + OUTBOX_MSG = 7, /// data:/CEC//OutBox__/_ + ROOT_DIR = 10, /// data:/CEC + MBOX_DIR = 11, /// data:/CEC/ + INBOX_DIR = 12, /// data:/CEC//InBox___ + OUTBOX_DIR = 13, /// data:/CEC//OutBox__ + MBOX_DATA = 100, /// data:/CEC//MBoxData.0 + MBOX_ICON = 101, /// data:/CEC//MBoxData.001 + MBOX_TITLE = 110, /// data:/CEC//MBoxData.010 + MBOX_PROGRAM_ID = 150, /// data:/CEC//MBoxData.050 }; enum class CecState : u32 { - CEC_STATE_NONE = 0, - CEC_STATE_INIT = 1, - CEC_STATE_WIRELESS_PARAM_SETUP = 2, - CEC_STATE_WIRELESS_READY = 3, - CEC_STATE_WIRELESS_START_CONFIG = 4, - CEC_STATE_SCAN = 5, - CEC_STATE_SCANNING = 6, - CEC_STATE_CONNECT = 7, - CEC_STATE_CONNECTING = 8, - CEC_STATE_CONNECTED = 9, - CEC_STATE_CONNECT_TCP = 10, - CEC_STATE_CONNECTING_TCP = 11, - CEC_STATE_CONNECTED_TCP = 12, - CEC_STATE_NEGOTIATION = 13, - CEC_STATE_SEND_RECV_START = 14, - CEC_STATE_SEND_RECV_INIT = 15, - CEC_STATE_SEND_READY = 16, - CEC_STATE_RECEIVE_READY = 17, - CEC_STATE_RECEIVE = 18, - CEC_STATE_CONNECTION_FINISH_TCP = 19, - CEC_STATE_CONNECTION_FINISH = 20, - CEC_STATE_SEND_POST = 21, - CEC_STATE_RECEIVE_POST = 22, - CEC_STATE_FINISHING = 23, - CEC_STATE_FINISH = 24, - CEC_STATE_OVER_BOSS = 25, - CEC_STATE_IDLE = 26 + NONE = 0, + INIT = 1, + WIRELESS_PARAM_SETUP = 2, + WIRELESS_READY = 3, + WIRELESS_START_CONFIG = 4, + SCAN = 5, + SCANNING = 6, + CONNECT = 7, + CONNECTING = 8, + CONNECTED = 9, + CONNECT_TCP = 10, + CONNECTING_TCP = 11, + CONNECTED_TCP = 12, + NEGOTIATION = 13, + SEND_RECV_START = 14, + SEND_RECV_INIT = 15, + SEND_READY = 16, + RECEIVE_READY = 17, + RECEIVE = 18, + CONNECTION_FINISH_TCP = 19, + CONNECTION_FINISH = 20, + SEND_POST = 21, + RECEIVE_POST = 22, + FINISHING = 23, + FINISH = 24, + OVER_BOSS = 25, + IDLE = 26 }; enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; struct CecInOutBoxInfoHeader { u16_le magic; // 0x6262 'bb' - u16_le padding; + INSERT_PADDING_BYTES(2); u32_le box_info_size; u32_le max_box_size; u32_le box_size; @@ -115,15 +116,14 @@ public: struct CecMBoxInfoHeader { u16_le magic; // 0x6363 'cc' - u16_le padding; + INSERT_PADDING_BYTES(2); u32_le program_id; u32_le private_id; u8 flag; u8 flag2; - u16_le padding2; - u8 hmac_key[32]; - u32_le padding3; - /// year, 4 bytes, month 1 byte, day 1 byte, hour 1 byte, minute 1 byte + INSERT_PADDING_BYTES(2); + std::array hmac_key; + INSERT_PADDING_BYTES(4); struct Time { u32_le year; u8 month; @@ -135,9 +135,9 @@ public: u8 microsecond; u8 padding; } last_accessed; - u32_le padding4; + INSERT_PADDING_BYTES(4); Time last_received; - u32_le padding5; + INSERT_PADDING_BYTES(4); Time unknown_time; }; static_assert(sizeof(CecMBoxInfoHeader) == 0x60, @@ -145,19 +145,19 @@ public: struct CecMBoxListHeader { u16_le magic; // 0x6868 'hh' - u16_le padding; - u16_le version; /// 0x01 00, maybe activated flag? - u16_le padding2; - u16_le num_boxes; /// 24 max - u16_le padding3; - u8 box_names[16 * 24]; /// 16 char names, 24 boxes + INSERT_PADDING_BYTES(2); + u16_le version; // 0x01 00, maybe activated flag? + INSERT_PADDING_BYTES(2); + u16_le num_boxes; // 24 max + INSERT_PADDING_BYTES(2); + std::array, 24> box_names; // 16 char names, 24 boxes }; static_assert(sizeof(CecMBoxListHeader) == 0x18C, "CecMBoxListHeader struct has incorrect size."); struct CecMessageHeader { - u16_le magic; // `` - u16_le padding; + u16_le magic; // 0x6060 `` + INSERT_PADDING_BYTES(2); u32_le message_size; u32_le header_size; u32_le body_size; @@ -167,9 +167,9 @@ public: u32_le batch_id; u32_le unknown_id; - u8 message_id[8]; + std::array message_id; u32_le version; - u8 message_id_2[8]; + std::array message_id_2; u8 flag; u8 send_method; u8 is_unopen; @@ -177,7 +177,15 @@ public: u64_le sender_id; u64_le sender_id2; struct Time { - u32_le a, b, c; + u32_le year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 millisecond; + u8 microsecond; + u8 padding; } send_time, recv_time, create_time; u8 send_count; u8 foward_count; @@ -186,10 +194,10 @@ public: static_assert(sizeof(CecMessageHeader) == 0x70, "CecMessageHeader struct has incorrect size."); struct CecOBIndexHeader { - u16_le magic; /// 0x6767 'gg' - u16_le padding; + u16_le magic; // 0x6767 'gg' + INSERT_PADDING_BYTES(2); u32_le message_num; - /// Array? of messageid's 8 bytes each, same as CecMessageHeader.message_id[8] + // Array of messageid's 8 bytes each, same as CecMessageHeader.message_id[8] }; static_assert(sizeof(CecOBIndexHeader) == 0x08, "CecOBIndexHeader struct has incorrect size."); @@ -202,11 +210,11 @@ public: union CecOpenMode { u32 raw; - BitField<0, 1, u32> unknown; /// 1 delete? - BitField<1, 1, u32> read; /// 2 - BitField<2, 1, u32> write; /// 4 - BitField<3, 1, u32> create; /// 8 - BitField<4, 1, u32> check; /// 16 maybe validate sig? + BitField<0, 1, u32> unknown; // 1 delete? + BitField<1, 1, u32> read; // 2 + BitField<2, 1, u32> write; // 4 + BitField<3, 1, u32> create; // 8 + BitField<4, 1, u32> check; // 16 maybe validate sig? BitField<30, 1, u32> unk_flag; }; From ff1beca74ab19b5bcc0922a29e0b72177146dce2 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Fri, 7 Sep 2018 19:36:33 -0400 Subject: [PATCH 17/21] service/cecd: Fixed enum item naming style --- src/core/hle/service/cecd/cecd.cpp | 222 ++++++++++++++--------------- src/core/hle/service/cecd/cecd.h | 138 +++++++++--------- 2 files changed, 180 insertions(+), 180 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index bc87e63b6..9e649a5c1 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -47,10 +47,10 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); switch (path_type) { - case CecDataPathType::ROOT_DIR: - case CecDataPathType::MBOX_DIR: - case CecDataPathType::INBOX_DIR: - case CecDataPathType::OUTBOX_DIR: { + case CecDataPathType::RootDir: + case CecDataPathType::MboxDir: + case CecDataPathType::InboxDir: + case CecDataPathType::OutboxDir: { auto dir_result = Service::FS::OpenDirectoryFromArchive(cecd->cecd_system_save_data_archive, path); if (dir_result.Failed()) { @@ -93,7 +93,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { rb.Push(session_data->file->backend->GetSize()); // Return file size } - if (path_type == CecDataPathType::MBOX_PROGRAM_ID) { + if (path_type == CecDataPathType::MboxProgramId) { std::vector program_id(8); u64_le le_program_id = Kernel::g_current_process->codeset->program_id; std::memcpy(program_id.data(), &le_program_id, sizeof(u64)); @@ -128,10 +128,10 @@ void Module::Interface::Read(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); switch (session_data->data_path_type) { - case CecDataPathType::ROOT_DIR: - case CecDataPathType::MBOX_DIR: - case CecDataPathType::INBOX_DIR: - case CecDataPathType::OUTBOX_DIR: + case CecDataPathType::RootDir: + case CecDataPathType::MboxDir: + case CecDataPathType::InboxDir: + case CecDataPathType::OutboxDir: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); rb.Push(0); // No bytes read @@ -169,8 +169,8 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { message_id_buffer.Read(id_buffer.data(), 0, message_id_size); FileSys::Path message_path = - cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG - : CecDataPathType::INBOX_MSG, + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OutboxMsg + : CecDataPathType::InboxMsg, ncch_program_id, id_buffer) .data(); @@ -221,8 +221,8 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { message_id_buffer.Read(id_buffer.data(), 0, message_id_size); FileSys::Path message_path = - cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG - : CecDataPathType::INBOX_MSG, + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OutboxMsg + : CecDataPathType::InboxMsg, ncch_program_id, id_buffer) .data(); @@ -273,10 +273,10 @@ void Module::Interface::Write(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); switch (session_data->data_path_type) { - case CecDataPathType::ROOT_DIR: - case CecDataPathType::MBOX_DIR: - case CecDataPathType::INBOX_DIR: - case CecDataPathType::OUTBOX_DIR: + case CecDataPathType::RootDir: + case CecDataPathType::MboxDir: + case CecDataPathType::InboxDir: + case CecDataPathType::OutboxDir: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); break; @@ -317,8 +317,8 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { message_id_buffer.Read(id_buffer.data(), 0, message_id_size); FileSys::Path message_path = - cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG - : CecDataPathType::INBOX_MSG, + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OutboxMsg + : CecDataPathType::InboxMsg, ncch_program_id, id_buffer) .data(); @@ -370,8 +370,8 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { message_id_buffer.Read(id_buffer.data(), 0, message_id_size); FileSys::Path message_path = - cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG - : CecDataPathType::INBOX_MSG, + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OutboxMsg + : CecDataPathType::InboxMsg, ncch_program_id, id_buffer) .data(); @@ -418,10 +418,10 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); switch (path_type) { - case CecDataPathType::ROOT_DIR: - case CecDataPathType::MBOX_DIR: - case CecDataPathType::INBOX_DIR: - case CecDataPathType::OUTBOX_DIR: + case CecDataPathType::RootDir: + case CecDataPathType::MboxDir: + case CecDataPathType::InboxDir: + case CecDataPathType::OutboxDir: rb.Push(Service::FS::DeleteDirectoryRecursivelyFromArchive( cecd->cecd_system_save_data_archive, path)); break; @@ -433,8 +433,8 @@ void Module::Interface::Delete(Kernel::HLERequestContext& ctx) { message_id_buffer.Read(id_buffer.data(), 0, message_id_size); FileSys::Path message_path = - cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OUTBOX_MSG - : CecDataPathType::INBOX_MSG, + cecd->GetCecDataPathTypeAsString(is_outbox ? CecDataPathType::OutboxMsg + : CecDataPathType::InboxMsg, ncch_program_id, id_buffer) .data(); rb.Push(Service::FS::DeleteFileFromArchive(cecd->cecd_system_save_data_archive, @@ -557,7 +557,7 @@ void Module::Interface::GetCecdState(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); - rb.PushEnum(CecdState::NDM_STATUS_IDLE); + rb.PushEnum(CecdState::NdmStatusIdle); LOG_WARNING(Service_CECD, "(STUBBED) called"); } @@ -599,10 +599,10 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); switch (path_type) { - case CecDataPathType::ROOT_DIR: - case CecDataPathType::MBOX_DIR: - case CecDataPathType::INBOX_DIR: - case CecDataPathType::OUTBOX_DIR: + case CecDataPathType::RootDir: + case CecDataPathType::MboxDir: + case CecDataPathType::InboxDir: + case CecDataPathType::OutboxDir: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); break; @@ -654,10 +654,10 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); switch (path_type) { - case CecDataPathType::ROOT_DIR: - case CecDataPathType::MBOX_DIR: - case CecDataPathType::INBOX_DIR: - case CecDataPathType::OUTBOX_DIR: + case CecDataPathType::RootDir: + case CecDataPathType::MboxDir: + case CecDataPathType::InboxDir: + case CecDataPathType::OutboxDir: rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::CEC, ErrorSummary::NotFound, ErrorLevel::Status)); rb.Push(0); // No entries read @@ -721,33 +721,33 @@ std::string Module::EncodeBase64(const std::vector& in, const std::string& d std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, const std::vector& msg_id) const { switch (type) { - case CecDataPathType::MBOX_LIST: + case CecDataPathType::MboxList: return "/CEC/MBoxList____"; - case CecDataPathType::MBOX_INFO: + case CecDataPathType::MboxInfo: return fmt::format("/CEC/{:08x}/MBoxInfo____", program_id); - case CecDataPathType::INBOX_INFO: + case CecDataPathType::InboxInfo: return fmt::format("/CEC/{:08x}/InBox___/BoxInfo_____", program_id); - case CecDataPathType::OUTBOX_INFO: + case CecDataPathType::OutboxInfo: return fmt::format("/CEC/{:08x}/OutBox__/BoxInfo_____", program_id); - case CecDataPathType::OUTBOX_INDEX: + case CecDataPathType::OutboxIndex: return fmt::format("/CEC/{:08x}/OutBox__/OBIndex_____", program_id); - case CecDataPathType::INBOX_MSG: + case CecDataPathType::InboxMsg: return fmt::format("/CEC/{:08x}/InBox___/_{}", program_id, EncodeBase64(msg_id, base64_dict)); - case CecDataPathType::OUTBOX_MSG: + case CecDataPathType::OutboxMsg: return fmt::format("/CEC/{:08x}/OutBox__/_{}", program_id, EncodeBase64(msg_id, base64_dict)); - case CecDataPathType::ROOT_DIR: + case CecDataPathType::RootDir: return "/CEC"; - case CecDataPathType::MBOX_DIR: + case CecDataPathType::MboxDir: return fmt::format("/CEC/{:08x}", program_id); - case CecDataPathType::INBOX_DIR: + case CecDataPathType::InboxDir: return fmt::format("/CEC/{:08x}/InBox___", program_id); - case CecDataPathType::OUTBOX_DIR: + case CecDataPathType::OutboxDir: return fmt::format("/CEC/{:08x}/OutBox__", program_id); - case CecDataPathType::MBOX_DATA: - case CecDataPathType::MBOX_ICON: - case CecDataPathType::MBOX_TITLE: + case CecDataPathType::MboxData: + case CecDataPathType::MboxIcon: + case CecDataPathType::MboxTitle: default: return fmt::format("/CEC/{:08x}/MBoxData.{:03}", program_id, static_cast(type) - 100); } @@ -755,50 +755,50 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const std::string Module::GetCecCommandAsString(const CecCommand command) const { switch (command) { - case CecCommand::NONE: - return "NONE"; - case CecCommand::START: - return "START"; - case CecCommand::RESET_START: - return "RESET_START"; - case CecCommand::READYSCAN: - return "READYSCAN"; - case CecCommand::READYSCANWAIT: - return "READYSCANWAIT"; - case CecCommand::STARTSCAN: - return "STARTSCAN"; - case CecCommand::RESCAN: - return "RESCAN"; - case CecCommand::NDM_RESUME: - return "RESUME"; - case CecCommand::NDM_SUSPEND: - return "NDM_SUSPEND"; - case CecCommand::NDM_SUSPEND_IMMEDIATE: - return "NDM_SUSPEND_IMMEDIATE"; - case CecCommand::STOPWAIT: - return "STOPWAIT"; - case CecCommand::STOP: - return "STOP"; - case CecCommand::STOP_FORCE: - return "STOP_FORCE"; - case CecCommand::STOP_FORCE_WAIT: - return "STOP_FORCE_WAIT"; - case CecCommand::RESET_FILTER: - return "RESET_FILTER"; - case CecCommand::DAEMON_STOP: - return "DAEMON_STOP"; - case CecCommand::DAEMON_START: - return "DAEMON_START"; - case CecCommand::EXIT: - return "EXIT"; - case CecCommand::OVER_BOSS: - return "OVER_BOSS"; - case CecCommand::OVER_BOSS_FORCE: - return "OVER_BOSS_FORCE"; - case CecCommand::OVER_BOSS_FORCE_WAIT: - return "OVER_BOSS_FORCE_WAIT"; - case CecCommand::END: - return "END"; + case CecCommand::None: + return "None"; + case CecCommand::Start: + return "Start"; + case CecCommand::ResetStart: + return "ResetStart"; + case CecCommand::ReadyScan: + return "ReadyScan"; + case CecCommand::ReadyScanWait: + return "ReadyScanWait"; + case CecCommand::StartScan: + return "StartScan"; + case CecCommand::Rescan: + return "Rescan"; + case CecCommand::NdmResume: + return "NdmResume"; + case CecCommand::NdmSuspend: + return "NdmSuspend"; + case CecCommand::NdmSuspendImmediate: + return "NdmSuspendImmediate"; + case CecCommand::StopWait: + return "StopWait"; + case CecCommand::Stop: + return "Stop"; + case CecCommand::StopForce: + return "StopForce"; + case CecCommand::StopForceWait: + return "StopForceWait"; + case CecCommand::ResetFilter: + return "ResetFilter"; + case CecCommand::DaemonStop: + return "DaemonStop"; + case CecCommand::DaemonStart: + return "DaemonStart"; + case CecCommand::Exit: + return "Exit"; + case CecCommand::OverBoss: + return "OverBoss"; + case CecCommand::OverBossForce: + return "OverBossForce"; + case CecCommand::OverBossForceWait: + return "OverBossForceWait"; + case CecCommand::End: + return "End"; default: return "Unknown"; } @@ -812,7 +812,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ const u32 file_size = file_buffer.size(); switch (path_type) { - case CecDataPathType::MBOX_LIST: { + case CecDataPathType::MboxList: { CecMBoxListHeader mbox_list_header = {}; std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); @@ -875,7 +875,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ /// are activated. The num_of_titles = (total_read_count) - 1, to adjust for /// the MBoxList____ file that is present in the directory as well. FileSys::Path root_path( - GetCecDataPathTypeAsString(CecDataPathType::ROOT_DIR, 0).data()); + GetCecDataPathTypeAsString(CecDataPathType::RootDir, 0).data()); auto dir_result = Service::FS::OpenDirectoryFromArchive(cecd_system_save_data_archive, root_path); @@ -907,7 +907,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &mbox_list_header, sizeof(CecMBoxListHeader)); break; } - case CecDataPathType::MBOX_INFO: { + case CecDataPathType::MboxInfo: { CecMBoxInfoHeader mbox_info_header = {}; std::memcpy(&mbox_info_header, file_buffer.data(), sizeof(CecMBoxInfoHeader)); @@ -935,7 +935,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &mbox_info_header, sizeof(CecMBoxInfoHeader)); break; } - case CecDataPathType::INBOX_INFO: { + case CecDataPathType::InboxInfo: { CecInOutBoxInfoHeader inbox_info_header = {}; std::memcpy(&inbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); @@ -987,7 +987,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &inbox_info_header, sizeof(CecInOutBoxInfoHeader)); break; } - case CecDataPathType::OUTBOX_INFO: { + case CecDataPathType::OutboxInfo: { CecInOutBoxInfoHeader outbox_info_header = {}; std::memcpy(&outbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); @@ -1037,7 +1037,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &outbox_info_header, sizeof(CecInOutBoxInfoHeader)); break; } - case CecDataPathType::OUTBOX_INDEX: { + case CecDataPathType::OutboxIndex: { CecOBIndexHeader obindex_header = {}; std::memcpy(&obindex_header, file_buffer.data(), sizeof(CecOBIndexHeader)); @@ -1067,18 +1067,18 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ std::memcpy(file_buffer.data(), &obindex_header, sizeof(CecOBIndexHeader)); break; } - case CecDataPathType::INBOX_MSG: + case CecDataPathType::InboxMsg: break; - case CecDataPathType::OUTBOX_MSG: + case CecDataPathType::OutboxMsg: break; - case CecDataPathType::ROOT_DIR: - case CecDataPathType::MBOX_DIR: - case CecDataPathType::INBOX_DIR: - case CecDataPathType::OUTBOX_DIR: + case CecDataPathType::RootDir: + case CecDataPathType::MboxDir: + case CecDataPathType::InboxDir: + case CecDataPathType::OutboxDir: break; - case CecDataPathType::MBOX_DATA: - case CecDataPathType::MBOX_ICON: - case CecDataPathType::MBOX_TITLE: + case CecDataPathType::MboxData: + case CecDataPathType::MboxIcon: + case CecDataPathType::MboxTitle: default: {} } } @@ -1116,7 +1116,7 @@ Module::Module() { /// Now that the archive is formatted, we need to create the root CEC directory, /// eventlog.dat, and CEC/MBoxList____ const FileSys::Path root_dir_path( - GetCecDataPathTypeAsString(CecDataPathType::ROOT_DIR, 0).data()); + GetCecDataPathTypeAsString(CecDataPathType::RootDir, 0).data()); Service::FS::CreateDirectoryFromArchive(*archive_result, root_dir_path); FileSys::Mode mode; @@ -1150,7 +1150,7 @@ Module::Module() { /// being the magic number. The rest of the file is filled with zeroes, until the end of /// file at offset 0x18b FileSys::Path mboxlist_path( - GetCecDataPathTypeAsString(CecDataPathType::MBOX_LIST, 0).data()); + GetCecDataPathTypeAsString(CecDataPathType::MboxList, 0).data()); auto mboxlist_result = Service::FS::OpenFileFromArchive(*archive_result, mboxlist_path, mode); diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 11f50c741..777f825ce 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -19,28 +19,28 @@ public: ~Module(); enum class CecCommand : u32 { - NONE = 0, - START = 1, - RESET_START = 2, - READYSCAN = 3, - READYSCANWAIT = 4, - STARTSCAN = 5, - RESCAN = 6, - NDM_RESUME = 7, - NDM_SUSPEND = 8, - NDM_SUSPEND_IMMEDIATE = 9, - STOPWAIT = 0x0A, - STOP = 0x0B, - STOP_FORCE = 0x0C, - STOP_FORCE_WAIT = 0x0D, - RESET_FILTER = 0x0E, - DAEMON_STOP = 0x0F, - DAEMON_START = 0x10, - EXIT = 0x11, - OVER_BOSS = 0x12, - OVER_BOSS_FORCE = 0x13, - OVER_BOSS_FORCE_WAIT = 0x14, - END = 0x15, + None = 0, + Start = 1, + ResetStart = 2, + ReadyScan = 3, + ReadyScanWait = 4, + StartScan = 5, + Rescan = 6, + NdmResume = 7, + NdmSuspend = 8, + NdmSuspendImmediate = 9, + StopWait = 0x0A, + Stop = 0x0B, + StopForce = 0x0C, + StopForceWait = 0x0D, + ResetFilter = 0x0E, + DaemonStop = 0x0F, + DaemonStart = 0x10, + Exit = 0x11, + OverBoss = 0x12, + OverBossForce = 0x13, + OverBossForceWait = 0x14, + End = 0x15, }; /** @@ -50,52 +50,52 @@ public: * data:/CEC/test */ enum class CecDataPathType : u32 { - INVALID = 0, - MBOX_LIST = 1, /// data:/CEC/MBoxList____ - MBOX_INFO = 2, /// data:/CEC//MBoxInfo____ - INBOX_INFO = 3, /// data:/CEC//InBox___/BoxInfo_____ - OUTBOX_INFO = 4, /// data:/CEC//OutBox__/BoxInfo_____ - OUTBOX_INDEX = 5, /// data:/CEC//OutBox__/OBIndex_____ - INBOX_MSG = 6, /// data:/CEC//InBox___/_ - OUTBOX_MSG = 7, /// data:/CEC//OutBox__/_ - ROOT_DIR = 10, /// data:/CEC - MBOX_DIR = 11, /// data:/CEC/ - INBOX_DIR = 12, /// data:/CEC//InBox___ - OUTBOX_DIR = 13, /// data:/CEC//OutBox__ - MBOX_DATA = 100, /// data:/CEC//MBoxData.0 - MBOX_ICON = 101, /// data:/CEC//MBoxData.001 - MBOX_TITLE = 110, /// data:/CEC//MBoxData.010 - MBOX_PROGRAM_ID = 150, /// data:/CEC//MBoxData.050 + Invalid = 0, + MboxList = 1, /// data:/CEC/MBoxList____ + MboxInfo = 2, /// data:/CEC//MBoxInfo____ + InboxInfo = 3, /// data:/CEC//InBox___/BoxInfo_____ + OutboxInfo = 4, /// data:/CEC//OutBox__/BoxInfo_____ + OutboxIndex = 5, /// data:/CEC//OutBox__/OBIndex_____ + InboxMsg = 6, /// data:/CEC//InBox___/_ + OutboxMsg = 7, /// data:/CEC//OutBox__/_ + RootDir = 10, /// data:/CEC + MboxDir = 11, /// data:/CEC/ + InboxDir = 12, /// data:/CEC//InBox___ + OutboxDir = 13, /// data:/CEC//OutBox__ + MboxData = 100, /// data:/CEC//MBoxData.0 + MboxIcon = 101, /// data:/CEC//MBoxData.001 + MboxTitle = 110, /// data:/CEC//MBoxData.010 + MboxProgramId = 150, /// data:/CEC//MBoxData.050 }; enum class CecState : u32 { - NONE = 0, - INIT = 1, - WIRELESS_PARAM_SETUP = 2, - WIRELESS_READY = 3, - WIRELESS_START_CONFIG = 4, - SCAN = 5, - SCANNING = 6, - CONNECT = 7, - CONNECTING = 8, - CONNECTED = 9, - CONNECT_TCP = 10, - CONNECTING_TCP = 11, - CONNECTED_TCP = 12, - NEGOTIATION = 13, - SEND_RECV_START = 14, - SEND_RECV_INIT = 15, - SEND_READY = 16, - RECEIVE_READY = 17, - RECEIVE = 18, - CONNECTION_FINISH_TCP = 19, - CONNECTION_FINISH = 20, - SEND_POST = 21, - RECEIVE_POST = 22, - FINISHING = 23, - FINISH = 24, - OVER_BOSS = 25, - IDLE = 26 + None = 0, + Init = 1, + WirelessParamSetup = 2, + WirelessReady = 3, + WirelessStartConfig = 4, + Scan = 5, + Scanning = 6, + Connect = 7, + Connecting = 8, + Connected = 9, + ConnectTcp = 10, + ConnectingTcp = 11, + ConnectedTcp = 12, + Negotiation = 13, + SendRecvStart = 14, + SendRecvInit = 15, + SendReady = 16, + ReceiveReady = 17, + Receive = 18, + ConnectionFinishTcp = 19, + ConnectionFinish = 20, + SendPost = 21, + ReceivePost = 22, + Finishing = 23, + Finish = 24, + OverBoss = 25, + Idle = 26 }; enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; @@ -202,10 +202,10 @@ public: static_assert(sizeof(CecOBIndexHeader) == 0x08, "CecOBIndexHeader struct has incorrect size."); enum class CecdState : u32 { - NDM_STATUS_WORKING = 0, - NDM_STATUS_IDLE = 1, - NDM_STATUS_SUSPENDING = 2, - NDM_STATUS_SUSPENDED = 3, + NdmStatusWorking = 0, + NdmStatusIdle = 1, + NdmStatusSuspending = 2, + NdmStatusSuspended = 3, }; union CecOpenMode { From 648cecf1aa943845559c08ca96503c0a6d8907f9 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Fri, 7 Sep 2018 23:09:14 -0400 Subject: [PATCH 18/21] service/cecd: Utilize CryptoPP::Base64Encoder for message id --- externals/cryptopp/CMakeLists.txt | 1 + src/core/hle/service/cecd/cecd.cpp | 46 ++++++++++++------------------ src/core/hle/service/cecd/cecd.h | 2 +- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/externals/cryptopp/CMakeLists.txt b/externals/cryptopp/CMakeLists.txt index fb2ba3588..db40f06cb 100644 --- a/externals/cryptopp/CMakeLists.txt +++ b/externals/cryptopp/CMakeLists.txt @@ -131,6 +131,7 @@ set(cryptopp_SOURCES cryptopp/algparam.cpp cryptopp/asn.cpp cryptopp/authenc.cpp + cryptopp/base64.cpp cryptopp/basecode.cpp cryptopp/ccm.cpp cryptopp/crc-simd.cpp diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 9e649a5c1..87eabac78 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -691,30 +692,23 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) { open_mode.check); } -std::string Module::EncodeBase64(const std::vector& in, const std::string& dictionary) const { +std::string Module::EncodeBase64(const std::vector& in) const { + using namespace CryptoPP; + using Name::EncodingLookupArray; + using Name::InsertLineBreaks; + using Name::Pad; + std::string out; - out.reserve((in.size() * 4) / 3); - int b; - for (int i = 0; i < in.size(); i += 3) { - b = (in[i] & 0xFC) >> 2; - out += dictionary[b]; - b = (in[i] & 0x03) << 4; - if (i + 1 < in.size()) { - b |= (in[i + 1] & 0xF0) >> 4; - out += dictionary[b]; - b = (in[i + 1] & 0x0F) << 2; - if (i + 2 < in.size()) { - b |= (in[i + 2] & 0xC0) >> 6; - out += dictionary[b]; - b = in[i + 2] & 0x3F; - out += dictionary[b]; - } else { - out += dictionary[b]; - } - } else { - out += dictionary[b]; - } - } + Base64Encoder encoder; + AlgorithmParameters params = + MakeParameters(EncodingLookupArray(), (const byte*)base64_dict.data())(InsertLineBreaks(), + false)(Pad(), false); + + encoder.IsolatedInitialize(params); + encoder.Attach(new StringSink(out)); + encoder.Put(in.data(), in.size()); + encoder.MessageEnd(); + return out; } @@ -732,11 +726,9 @@ std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const case CecDataPathType::OutboxIndex: return fmt::format("/CEC/{:08x}/OutBox__/OBIndex_____", program_id); case CecDataPathType::InboxMsg: - return fmt::format("/CEC/{:08x}/InBox___/_{}", program_id, - EncodeBase64(msg_id, base64_dict)); + return fmt::format("/CEC/{:08x}/InBox___/_{}", program_id, EncodeBase64(msg_id)); case CecDataPathType::OutboxMsg: - return fmt::format("/CEC/{:08x}/OutBox__/_{}", program_id, - EncodeBase64(msg_id, base64_dict)); + return fmt::format("/CEC/{:08x}/OutBox__/_{}", program_id, EncodeBase64(msg_id)); case CecDataPathType::RootDir: return "/CEC"; case CecDataPathType::MboxDir: diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 777f825ce..4b0eff1f0 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -589,7 +589,7 @@ private: 0x26, 0x00, 0x01, 0x00}; /// Encoding function used for the message id - std::string EncodeBase64(const std::vector& in, const std::string& dictionary) const; + std::string EncodeBase64(const std::vector& in) const; std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, const std::vector& msg_id = std::vector()) const; From 192a0f3b92deb09659b22335c0b2719ece680772 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Mon, 10 Sep 2018 04:21:24 -0400 Subject: [PATCH 19/21] service/cecd: Update handling of /outbox/boxinfo and /outbox/obindex --- src/core/hle/service/cecd/cecd.cpp | 299 ++++++++++++++++++++++++++--- src/core/hle/service/cecd/cecd.h | 11 +- 2 files changed, 277 insertions(+), 33 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 87eabac78..17b1f3178 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -187,6 +188,26 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { write_buffer.Write(buffer.data(), 0, buffer_size); message->backend->Close(); + CecMessageHeader msg_header; + + std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); + LOG_DEBUG(Service_CECD, + "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " + "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " + "batch_id={:#010x}", + msg_header.magic, msg_header.message_size, msg_header.header_size, + msg_header.body_size, msg_header.title_id, msg_header.title_id2, + msg_header.batch_id); + LOG_DEBUG(Service_CECD, + "unknown_id={:#010x}, version={:#010x}, flag={:#04x}, " + "send_method={:#04x}, is_unopen={:#04x}, is_new={:#04x}, " + "sender_id={:#018x}, sender_id2={:#018x}, send_count={:#04x}, " + "forward_count={:#04x}, user_data={:#06x}, ", + msg_header.unknown_id, msg_header.version, msg_header.flag, + msg_header.send_method, msg_header.is_unopen, msg_header.is_new, + msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, + msg_header.forward_count, msg_header.user_data); + rb.Push(RESULT_SUCCESS); rb.Push(bytes_read); } else { @@ -239,6 +260,26 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { write_buffer.Write(buffer.data(), 0, buffer_size); message->backend->Close(); + CecMessageHeader msg_header; + + std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); + LOG_DEBUG(Service_CECD, + "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " + "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " + "batch_id={:#010x}", + msg_header.magic, msg_header.message_size, msg_header.header_size, + msg_header.body_size, msg_header.title_id, msg_header.title_id2, + msg_header.batch_id); + LOG_DEBUG(Service_CECD, + "unknown_id={:#010x}, version={:#010x}, flag={:#04x}, " + "send_method={:#04x}, is_unopen={:#04x}, is_new={:#04x}, " + "sender_id={:#018x}, sender_id2={:#018x}, send_count={:#04x}, " + "forward_count={:#04x}, user_data={:#06x}, ", + msg_header.unknown_id, msg_header.version, msg_header.flag, + msg_header.send_method, msg_header.is_unopen, msg_header.is_new, + msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, + msg_header.forward_count, msg_header.user_data); + rb.Push(RESULT_SUCCESS); rb.Push(bytes_read); } else { @@ -285,13 +326,17 @@ void Module::Interface::Write(Kernel::HLERequestContext& ctx) { std::vector buffer(read_buffer_size); read_buffer.Read(buffer.data(), 0, read_buffer_size); + if (session_data->file->backend->GetSize() != read_buffer_size) { + session_data->file->backend->SetSize(read_buffer_size); + } + if (session_data->open_mode.check) { cecd->CheckAndUpdateFile(session_data->data_path_type, session_data->ncch_program_id, buffer); } const u32 bytes_written = - session_data->file->backend->Write(0, read_buffer_size, true, buffer.data()).Unwrap(); + session_data->file->backend->Write(0, buffer.size(), true, buffer.data()).Unwrap(); session_data->file->backend->Close(); rb.Push(RESULT_SUCCESS); @@ -330,8 +375,27 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { if (message_result.Succeeded()) { auto message = message_result.Unwrap(); std::vector buffer(buffer_size); + CecMessageHeader msg_header; read_buffer.Read(buffer.data(), 0, buffer_size); + std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); + LOG_DEBUG(Service_CECD, + "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " + "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " + "batch_id={:#010x}", + msg_header.magic, msg_header.message_size, msg_header.header_size, + msg_header.body_size, msg_header.title_id, msg_header.title_id2, + msg_header.batch_id); + LOG_DEBUG(Service_CECD, + "unknown_id={:#010x}, version={:#010x}, flag={:#04x}, " + "send_method={:#04x}, is_unopen={:#04x}, is_new={:#04x}, " + "sender_id={:#018x}, sender_id2={:#018x}, send_count={:#04x}, " + "forward_count={:#04x}, user_data={:#06x}, ", + msg_header.unknown_id, msg_header.version, msg_header.flag, + msg_header.send_method, msg_header.is_unopen, msg_header.is_new, + msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, + msg_header.forward_count, msg_header.user_data); + const u32 bytes_written = message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); message->backend->Close(); @@ -383,8 +447,27 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { if (message_result.Succeeded()) { auto message = message_result.Unwrap(); std::vector buffer(buffer_size); + CecMessageHeader msg_header; read_buffer.Read(buffer.data(), 0, buffer_size); + std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); + LOG_DEBUG(Service_CECD, + "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " + "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " + "batch_id={:#010x}", + msg_header.magic, msg_header.message_size, msg_header.header_size, + msg_header.body_size, msg_header.title_id, msg_header.title_id2, + msg_header.batch_id); + LOG_DEBUG(Service_CECD, + "unknown_id={:#010x}, version={:#010x}, flag={:#04x}, " + "send_method={:#04x}, is_unopen={:#04x}, is_new={:#04x}, " + "sender_id={:#018x}, sender_id2={:#018x}, send_count={:#04x}, " + "forward_count={:#04x}, user_data={:#06x}, ", + msg_header.unknown_id, msg_header.version, msg_header.flag, + msg_header.send_method, msg_header.is_unopen, msg_header.is_new, + msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, + msg_header.forward_count, msg_header.user_data); + const u32 bytes_written = message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); message->backend->Close(); @@ -457,26 +540,32 @@ void Module::Interface::SetData(Kernel::HLERequestContext& ctx) { const u32 ncch_program_id = rp.Pop(); const u32 buffer_size = rp.Pop(); const u32 option = rp.Pop(); - auto& message_id_buffer = rp.PopMappedBuffer(); + auto& read_buffer = rp.PopMappedBuffer(); - SessionData* session_data = GetSessionData(ctx.Session()); - if (session_data->file) - LOG_TRACE( - Service_CECD, - "SessionData: ncch_program_id={:#010x}, data_path_type={:#04x}, " - "path={}, open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", - session_data->ncch_program_id, static_cast(session_data->data_path_type), - session_data->path.AsString(), session_data->open_mode.raw, - session_data->open_mode.unknown, session_data->open_mode.read, - session_data->open_mode.write, session_data->open_mode.create, - session_data->open_mode.check); + if (option == 2 && buffer_size > 0) { // update obindex? + FileSys::Path path( + cecd->GetCecDataPathTypeAsString(CecDataPathType::OutboxIndex, ncch_program_id).data()); + FileSys::Mode mode; + mode.write_flag.Assign(1); + mode.create_flag.Assign(1); - if (session_data->file) - session_data->file->backend->Close(); + auto file_result = + Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); + if (file_result.Succeeded()) { + auto file = file_result.Unwrap(); + std::vector buffer(buffer_size); + read_buffer.Read(buffer.data(), 0, buffer_size); + + cecd->CheckAndUpdateFile(CecDataPathType::OutboxIndex, ncch_program_id, buffer); + + file->backend->Write(0, buffer.size(), true, buffer.data()); + file->backend->Close(); + } + } IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); - rb.PushMappedBuffer(message_id_buffer); + rb.PushMappedBuffer(read_buffer); LOG_DEBUG(Service_CECD, "called, ncch_program_id={:#010x}, buffer_size={:#x}, option={:#x}", ncch_program_id, buffer_size, option); @@ -612,15 +701,20 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); if (file_result.Succeeded()) { auto file = file_result.Unwrap(); + std::vector buffer(buffer_size); read_buffer.Read(buffer.data(), 0, buffer_size); + if (file->backend->GetSize() != buffer_size) { + file->backend->SetSize(buffer_size); + } + if (open_mode.check) { cecd->CheckAndUpdateFile(path_type, ncch_program_id, buffer); } const u32 bytes_written = - file->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); + file->backend->Write(0, buffer.size(), true, buffer.data()).Unwrap(); file->backend->Close(); rb.Push(RESULT_SUCCESS); @@ -808,6 +902,9 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ CecMBoxListHeader mbox_list_header = {}; std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); + LOG_DEBUG(Service_CECD, "CecMBoxList: magic={:#06x}, version={:#06x}, num_boxes={:#06x}", + mbox_list_header.magic, mbox_list_header.version, mbox_list_header.num_boxes); + if (file_size != sizeof(CecMBoxListHeader)) { // 0x18C LOG_DEBUG(Service_CECD, "CecMBoxListHeader size is incorrect: {}", file_size); } @@ -845,7 +942,6 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ bool already_activated = false; for (auto i = 0; i < mbox_list_header.num_boxes; i++) { - LOG_DEBUG(Service_CECD, "{}", i); // Box names start at offset 0xC, are 16 char long, first 8 id, last 8 null if (std::memcmp(name_buffer.data(), &mbox_list_header.box_names[i], valid_name_size) == 0) { @@ -903,6 +999,12 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ CecMBoxInfoHeader mbox_info_header = {}; std::memcpy(&mbox_info_header, file_buffer.data(), sizeof(CecMBoxInfoHeader)); + LOG_DEBUG(Service_CECD, + "CecMBoxInfoHeader: magic={:#06x}, program_id={:#010x}, " + "private_id={:#010x}, flag={:#04x}, flag2={:#04x}", + mbox_info_header.magic, mbox_info_header.program_id, mbox_info_header.private_id, + mbox_info_header.flag, mbox_info_header.flag2); + if (file_size != sizeof(CecMBoxInfoHeader)) { // 0x60 LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader size is incorrect: {}", file_size); } @@ -928,8 +1030,18 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ break; } case CecDataPathType::InboxInfo: { - CecInOutBoxInfoHeader inbox_info_header = {}; - std::memcpy(&inbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); + CecBoxInfoHeader inbox_info_header = {}; + std::memcpy(&inbox_info_header, file_buffer.data(), sizeof(CecBoxInfoHeader)); + + LOG_DEBUG(Service_CECD, + "CecBoxInfoHeader: magic={:#06x}, box_info_size={:#010x}, " + "max_box_size={:#010x}, box_size={:#010x}, " + "max_message_num={:#010x}, message_num={:#010x}, " + "max_batch_size={:#010x}, max_message_size={:#010x}", + inbox_info_header.magic, inbox_info_header.box_info_size, + inbox_info_header.max_box_size, inbox_info_header.box_size, + inbox_info_header.max_message_num, inbox_info_header.message_num, + inbox_info_header.max_batch_size, inbox_info_header.max_message_size); if (inbox_info_header.magic != 0x6262) { // 'bb' if (inbox_info_header.magic == 0) @@ -946,7 +1058,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ else LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader box info size is incorrect:", inbox_info_header.box_info_size); - inbox_info_header.box_info_size = sizeof(CecInOutBoxInfoHeader); + inbox_info_header.box_info_size = sizeof(CecBoxInfoHeader); } if (inbox_info_header.max_box_size == 0) { @@ -976,12 +1088,22 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max batch size != max message number"); } - std::memcpy(file_buffer.data(), &inbox_info_header, sizeof(CecInOutBoxInfoHeader)); + std::memcpy(file_buffer.data(), &inbox_info_header, sizeof(CecBoxInfoHeader)); break; } case CecDataPathType::OutboxInfo: { - CecInOutBoxInfoHeader outbox_info_header = {}; - std::memcpy(&outbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); + CecBoxInfoHeader outbox_info_header = {}; + std::memcpy(&outbox_info_header, file_buffer.data(), sizeof(CecBoxInfoHeader)); + + LOG_DEBUG(Service_CECD, + "CecBoxInfoHeader: magic={:#06x}, box_info_size={:#010x}, " + "max_box_size={:#010x}, box_size={:#010x}, " + "max_message_num={:#010x}, message_num={:#010x}, " + "max_batch_size={:#010x}, max_message_size={:#010x}", + outbox_info_header.magic, outbox_info_header.box_info_size, + outbox_info_header.max_box_size, outbox_info_header.box_size, + outbox_info_header.max_message_num, outbox_info_header.message_num, + outbox_info_header.max_batch_size, outbox_info_header.max_message_size); if (outbox_info_header.magic != 0x6262) { // 'bb' if (outbox_info_header.magic == 0) @@ -992,13 +1114,14 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ outbox_info_header.magic = 0x6262; } - if (outbox_info_header.box_info_size != file_size) { + if (outbox_info_header.box_info_size != file_buffer.size()) { if (outbox_info_header.box_info_size == 0) LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is not set"); else LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is incorrect:", outbox_info_header.box_info_size); - outbox_info_header.box_info_size = sizeof(CecInOutBoxInfoHeader); + outbox_info_header.box_info_size = sizeof(CecBoxInfoHeader); + outbox_info_header.message_num = 0; } if (outbox_info_header.max_box_size == 0) { @@ -1026,7 +1149,71 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max batch size != max message number"); } - std::memcpy(file_buffer.data(), &outbox_info_header, sizeof(CecInOutBoxInfoHeader)); + /// We need to read the /CEC//OutBox directory to find out which messages, if any, + /// are present. The num_of_messages = (total_read_count) - 2, to adjust for + /// the BoxInfo____ and OBIndex_____files that are present in the directory as well. + FileSys::Path outbox_path( + GetCecDataPathTypeAsString(CecDataPathType::OutboxDir, ncch_program_id).data()); + + auto dir_result = + Service::FS::OpenDirectoryFromArchive(cecd_system_save_data_archive, outbox_path); + + auto outbox_dir = dir_result.Unwrap(); + std::vector entries(outbox_info_header.max_message_num + 2); + const u32 entry_count = + outbox_dir->backend->Read(outbox_info_header.max_message_num + 2, entries.data()); + outbox_dir->backend->Close(); + + LOG_DEBUG(Service_CECD, "Number of entries found in /OutBox: {}", entry_count); + std::array message_headers; + + std::string boxinfo_name("BoxInfo_____"); + std::string obindex_name("OBIndex_____"); + std::string file_name; + std::u16string u16_filename; + + for (auto i = 0; i < entry_count; i++) { + u16_filename = std::u16string(entries[i].filename); + file_name = Common::UTF16ToUTF8(u16_filename); + + if (boxinfo_name.compare(file_name) != 0 && obindex_name.compare(file_name) != 0) { + LOG_DEBUG(Service_CECD, "Adding message to BoxInfo_____: {}", file_name); + + FileSys::Path message_path( + (GetCecDataPathTypeAsString(CecDataPathType::OutboxDir, ncch_program_id) + "/" + + file_name) + .data()); + + FileSys::Mode mode; + mode.read_flag.Assign(1); + + auto message_result = Service::FS::OpenFileFromArchive( + cecd_system_save_data_archive, message_path, mode); + + auto message = message_result.Unwrap(); + const u32 message_size = message->backend->GetSize(); + std::vector buffer(message_size); + + message->backend->Read(0, message_size, buffer.data()).Unwrap(); + message->backend->Close(); + + std::memcpy(&message_headers[outbox_info_header.message_num++], buffer.data(), + sizeof(CecMessageHeader)); + } + } + + if (outbox_info_header.message_num > 0) { + const u32 message_headers_size = + outbox_info_header.message_num * sizeof(CecMessageHeader); + + file_buffer.resize(sizeof(CecBoxInfoHeader) + message_headers_size, 0); + outbox_info_header.box_info_size += message_headers_size; + + std::memcpy(file_buffer.data() + sizeof(CecBoxInfoHeader), &message_headers, + message_headers_size); + } + + std::memcpy(file_buffer.data(), &outbox_info_header, sizeof(CecBoxInfoHeader)); break; } case CecDataPathType::OutboxIndex: { @@ -1054,6 +1241,64 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ } else if (obindex_header.message_num != (file_size % 8) - 1) { LOG_DEBUG(Service_CECD, "CecOBIndexHeader message number is incorrect: {}", obindex_header.message_num); + obindex_header.message_num = 0; + } + + /// We need to read the /CEC//OutBox directory to find out which messages, if any, + /// are present. The num_of_messages = (total_read_count) - 2, to adjust for + /// the BoxInfo____ and OBIndex_____files that are present in the directory as well. + FileSys::Path outbox_path( + GetCecDataPathTypeAsString(CecDataPathType::OutboxDir, ncch_program_id).data()); + + auto dir_result = + Service::FS::OpenDirectoryFromArchive(cecd_system_save_data_archive, outbox_path); + + auto outbox_dir = dir_result.Unwrap(); + std::vector entries(8); + const u32 entry_count = outbox_dir->backend->Read(8, entries.data()); + outbox_dir->backend->Close(); + + LOG_DEBUG(Service_CECD, "Number of entries found in /OutBox: {}", entry_count); + std::array, 8> message_ids; + + std::string boxinfo_name("BoxInfo_____"); + std::string obindex_name("OBIndex_____"); + std::string file_name; + std::u16string u16_filename; + + for (auto i = 0; i < entry_count; i++) { + u16_filename = std::u16string(entries[i].filename); + file_name = Common::UTF16ToUTF8(u16_filename); + + if (boxinfo_name.compare(file_name) != 0 && obindex_name.compare(file_name) != 0) { + FileSys::Path message_path( + (GetCecDataPathTypeAsString(CecDataPathType::OutboxDir, ncch_program_id) + "/" + + file_name) + .data()); + + FileSys::Mode mode; + mode.read_flag.Assign(1); + + auto message_result = Service::FS::OpenFileFromArchive( + cecd_system_save_data_archive, message_path, mode); + + auto message = message_result.Unwrap(); + const u32 message_size = message->backend->GetSize(); + std::vector buffer(message_size); + + message->backend->Read(0, message_size, buffer.data()).Unwrap(); + message->backend->Close(); + + // Message id is at offset 0x20, and is 8 bytes + std::memcpy(&message_ids[obindex_header.message_num++], buffer.data() + 0x20, 8); + } + } + + if (obindex_header.message_num > 0) { + const u32 message_ids_size = obindex_header.message_num * 8; + file_buffer.resize(sizeof(CecOBIndexHeader) + message_ids_size); + std::memcpy(file_buffer.data() + sizeof(CecOBIndexHeader), &message_ids, + message_ids_size); } std::memcpy(file_buffer.data(), &obindex_header, sizeof(CecOBIndexHeader)); diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 4b0eff1f0..074c94f5c 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -100,7 +100,7 @@ public: enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; - struct CecInOutBoxInfoHeader { + struct CecBoxInfoHeader { u16_le magic; // 0x6262 'bb' INSERT_PADDING_BYTES(2); u32_le box_info_size; @@ -111,8 +111,7 @@ public: u32_le max_batch_size; u32_le max_message_size; }; - static_assert(sizeof(CecInOutBoxInfoHeader) == 0x20, - "CecInOutBoxInfoHeader struct has incorrect size."); + static_assert(sizeof(CecBoxInfoHeader) == 0x20, "CecBoxInfoHeader struct has incorrect size."); struct CecMBoxInfoHeader { u16_le magic; // 0x6363 'cc' @@ -163,13 +162,13 @@ public: u32_le body_size; u32_le title_id; - u32_le title_id_2; + u32_le title_id2; u32_le batch_id; u32_le unknown_id; std::array message_id; u32_le version; - std::array message_id_2; + std::array message_id2; u8 flag; u8 send_method; u8 is_unopen; @@ -188,7 +187,7 @@ public: u8 padding; } send_time, recv_time, create_time; u8 send_count; - u8 foward_count; + u8 forward_count; u16_le user_data; }; static_assert(sizeof(CecMessageHeader) == 0x70, "CecMessageHeader struct has incorrect size."); From 105bcc95c0e4fbc18b8ecc65181c8695c89de843 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Mon, 10 Sep 2018 19:53:23 -0400 Subject: [PATCH 20/21] service/cecd: Add hmac handling --- src/core/hle/service/cecd/cecd.cpp | 59 +++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 17b1f3178..574746875 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -189,8 +190,8 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { message->backend->Close(); CecMessageHeader msg_header; - std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); + LOG_DEBUG(Service_CECD, "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " @@ -234,8 +235,6 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { auto& hmac_key_buffer = rp.PopMappedBuffer(); auto& write_buffer = rp.PopMappedBuffer(); - // TODO verify message HMAC with the given key - FileSys::Mode mode; mode.read_flag.Assign(1); @@ -261,8 +260,8 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { message->backend->Close(); CecMessageHeader msg_header; - std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); + LOG_DEBUG(Service_CECD, "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " @@ -280,6 +279,28 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, msg_header.forward_count, msg_header.user_data); + std::vector hmac_digest(0x20); + std::memcpy(hmac_digest.data(), + buffer.data() + msg_header.header_size + msg_header.body_size, 0x20); + + std::vector message_body(msg_header.body_size); + std::memcpy(message_body.data(), buffer.data() + msg_header.header_size, + msg_header.body_size); + + using namespace CryptoPP; + SecByteBlock key(0x20); + hmac_key_buffer.Read(key.data(), 0, key.size()); + + HMAC hmac(key, key.size()); + + const bool verify_hmac = + hmac.VerifyDigest(hmac_digest.data(), message_body.data(), message_body.size()); + + if (verify_hmac) + LOG_DEBUG(Service_CECD, "Verification succeeded"); + else + LOG_DEBUG(Service_CECD, "Verification failed"); + rb.Push(RESULT_SUCCESS); rb.Push(bytes_read); } else { @@ -374,11 +395,13 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); if (message_result.Succeeded()) { auto message = message_result.Unwrap(); - std::vector buffer(buffer_size); - CecMessageHeader msg_header; + std::vector buffer(buffer_size); read_buffer.Read(buffer.data(), 0, buffer_size); + + CecMessageHeader msg_header; std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); + LOG_DEBUG(Service_CECD, "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " @@ -425,8 +448,6 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { auto& hmac_key_buffer = rp.PopMappedBuffer(); auto& message_id_buffer = rp.PopMappedBuffer(); - // TODO verify message HMAC with the given key - FileSys::Mode mode; mode.write_flag.Assign(1); mode.create_flag.Assign(1); @@ -446,11 +467,13 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 6); if (message_result.Succeeded()) { auto message = message_result.Unwrap(); - std::vector buffer(buffer_size); - CecMessageHeader msg_header; + std::vector buffer(buffer_size); read_buffer.Read(buffer.data(), 0, buffer_size); + + CecMessageHeader msg_header; std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); + LOG_DEBUG(Service_CECD, "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " @@ -468,6 +491,22 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, msg_header.forward_count, msg_header.user_data); + const u32 hmac_offset = msg_header.header_size + msg_header.body_size; + const u32 hmac_size = 0x20; + + std::vector hmac_digest(hmac_size); + std::vector message_body(msg_header.body_size); + std::memcpy(message_body.data(), buffer.data() + msg_header.header_size, + msg_header.body_size); + + using namespace CryptoPP; + SecByteBlock key(hmac_size); + hmac_key_buffer.Read(key.data(), 0, hmac_size); + + HMAC hmac(key, hmac_size); + hmac.CalculateDigest(hmac_digest.data(), message_body.data(), msg_header.body_size); + std::memcpy(buffer.data() + hmac_offset, hmac_digest.data(), hmac_size); + const u32 bytes_written = message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); message->backend->Close(); From 0d15b99bfc460156a358f2c31225550857ab503d Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Tue, 11 Sep 2018 14:39:48 -0400 Subject: [PATCH 21/21] service/cecd: Corrected cecd:s function table --- src/core/hle/service/cecd/cecd_s.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp index f84d90450..66c7455e4 100644 --- a/src/core/hle/service/cecd/cecd_s.cpp +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -32,7 +32,8 @@ CECD_S::CECD_S(std::shared_ptr cecd) {0x00120104, &CECD_S::OpenAndRead, "OpenAndRead"}, {0x001E0082, nullptr, "GetEventLog"}, {0x001F0000, nullptr, "GetEventLogStart"}, - {0x40020002, nullptr, "GetCecInfoEventHandleSys"}, + // cecd:s commands + {0x04020002, nullptr, "GetCecInfoEventHandleSys"}, // clang-format on };