mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	service/cecd: Implement basic file handling functions.
This commit is contained in:
		
							parent
							
								
									2ee395d7de
								
							
						
					
					
						commit
						413f1651b7
					
				
					 4 changed files with 520 additions and 139 deletions
				
			
		|  | @ -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<u32>(); | ||||
|     const auto path_type = static_cast<CecDataPathType>(rp.Pop<u32>()); | ||||
|     const u32 file_open_flag = rp.Pop<u32>(); | ||||
|     CecOpenMode open_mode; | ||||
|     open_mode.raw = rp.Pop<u32>(); | ||||
|     rp.PopPID(); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.Push<u32>(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<u32>(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<u32>(0); /// Zero entries
 | ||||
|         } else { | ||||
|             auto directory = dir_result.Unwrap(); | ||||
|             rb.Push(RESULT_SUCCESS); | ||||
|             rb.Push<u32>(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<u32>(0); /// No file size
 | ||||
|         } else { | ||||
|             session_data->file = std::move(file_result.Unwrap()); | ||||
|             rb.Push(RESULT_SUCCESS); | ||||
|             rb.Push<u32>(session_data->file->backend->GetSize()); /// Return file size
 | ||||
|         } | ||||
| 
 | ||||
|         if (path_type == CecDataPathType::CEC_MBOX_PROGRAM_ID) { | ||||
|             std::vector<u8> 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<u32>(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<u32>(); | ||||
|     auto& buffer = rp.PopMappedBuffer(); | ||||
|     const u32 write_buffer_size = rp.Pop<u32>(); | ||||
|     auto& write_buffer = rp.PopMappedBuffer(); | ||||
| 
 | ||||
|     SessionData* session_data = GetSessionData(ctx.Session()); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.Push<u32>(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<u32>(0); /// No bytes read
 | ||||
|         break; | ||||
|     default: /// If not directory, then it is a file
 | ||||
|         std::vector<u8> 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<u32>(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<u32>(); | ||||
|     const bool is_out_box = rp.Pop<bool>(); | ||||
|     const bool is_outbox = rp.Pop<bool>(); | ||||
|     const u32 message_id_size = rp.Pop<u32>(); | ||||
|     const u32 buffer_size = rp.Pop<u32>(); | ||||
|     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<u32>(); | ||||
|     const bool is_out_box = rp.Pop<bool>(); | ||||
|     const bool is_outbox = rp.Pop<bool>(); | ||||
|     const u32 message_id_size = rp.Pop<u32>(); | ||||
|     const u32 buffer_size = rp.Pop<u32>(); | ||||
|     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<u32>(); | ||||
|     const auto& buffer = rp.PopMappedBuffer(); | ||||
|     const u32 read_buffer_size = rp.Pop<u32>(); | ||||
|     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<u8> 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<u32>(); | ||||
|     const bool is_out_box = rp.Pop<bool>(); | ||||
|     const bool is_outbox = rp.Pop<bool>(); | ||||
|     const u32 message_id_size = rp.Pop<u32>(); | ||||
|     const u32 buffer_size = rp.Pop<u32>(); | ||||
|     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<u32>(); | ||||
|     const bool is_out_box = rp.Pop<bool>(); | ||||
|     const bool is_outbox = rp.Pop<bool>(); | ||||
|     const u32 message_id_size = rp.Pop<u32>(); | ||||
|     const u32 buffer_size = rp.Pop<u32>(); | ||||
|     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<u32>(); | ||||
|     const auto path_type = static_cast<CecDataPathType>(rp.Pop<u32>()); | ||||
|     const bool is_out_box = rp.Pop<bool>(); | ||||
|     const bool is_outbox = rp.Pop<bool>(); | ||||
|     const u32 message_id_size = rp.Pop<u32>(); | ||||
|     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<u32>(path_type), is_out_box); | ||||
|                 "(STUBBED) called, ncch_program_id={:#010x}, path_type={:#04x}, is_outbox={}", | ||||
|                 ncch_program_id, static_cast<u32>(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<u32>(); | ||||
|     const u32 size = rp.Pop<u32>(); | ||||
|     const u32 option = rp.Pop<u32>(); | ||||
|     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<u32>(); | ||||
|     const u32 info_type = rp.Pop<u32>(); | ||||
|     const CecSystemInfoType info_type = static_cast<CecSystemInfoType>(rp.Pop<u32>()); | ||||
|     const u32 param_buffer_size = rp.Pop<u32>(); | ||||
|     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<u8> 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<u32>(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<u32>(info_type), param_buffer_size); | ||||
| } | ||||
| 
 | ||||
| void Module::Interface::RunCommand(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx, 0x0B, 1, 0); | ||||
|     const auto command = static_cast<CecCommand>(rp.Pop<u32>()); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
| 
 | ||||
|     LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", static_cast<u32>(command)); | ||||
| } | ||||
| 
 | ||||
| void Module::Interface::RunCommandAlt(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx, 0x0C, 1, 0); | ||||
|     const auto command = static_cast<CecCommand>(rp.Pop<u32>()); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
| 
 | ||||
|     LOG_WARNING(Service_CECD, "(STUBBED) called, command={}", static_cast<u32>(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<u32>(); | ||||
|     const u32 ncch_program_id = rp.Pop<u32>(); | ||||
|     const auto path_type = static_cast<CecDataPathType>(rp.Pop<u32>()); | ||||
|     const u32 file_open_flag = rp.Pop<u32>(); | ||||
|     CecOpenMode open_mode; | ||||
|     open_mode.raw = rp.Pop<u32>(); | ||||
|     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<u8> 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<u8> 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<u32>(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<u32>(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<u32>(); | ||||
|     const u32 ncch_program_id = rp.Pop<u32>(); | ||||
|     const auto path_type = static_cast<CecDataPathType>(rp.Pop<u32>()); | ||||
|     const u32 file_open_flag = rp.Pop<u32>(); | ||||
|     CecOpenMode open_mode; | ||||
|     open_mode.raw = rp.Pop<u32>(); | ||||
|     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<u8> 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<u32>(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<u32>(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<u8> 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<u32>(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<u32>(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<u32>(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<u32>(path_type), open_mode.raw, path.AsString()); | ||||
| } | ||||
| 
 | ||||
| std::string Module::EncodeBase64(const std::vector<u8>& 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<u8>& msg_id) { | ||||
|     switch(type) { | ||||
|                                                const std::vector<u8>& 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<Module> 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) { | ||||
|  |  | |||
|  | @ -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/<id>/MBoxInfo____
 | ||||
|         CEC_PATH_INBOX_INFO = 3,   /// data:/CEC/<id>/InBox___/BoxInfo_____
 | ||||
|         CEC_PATH_OUTBOX_INFO = 4,  /// data:/CEC/<id>/OutBox__/BoxInfo_____
 | ||||
|         CEC_PATH_OUTBOX_INDEX = 5, /// data:/CEC/<id>/OutBox__/OBIndex_____
 | ||||
|         CEC_PATH_INBOX_MSG = 6,    /// data:/CEC/<id>/InBox___/_<message_id>
 | ||||
|         CEC_PATH_OUTBOX_MSG = 7,   /// data:/CEC/<id>/OutBox__/_<message_id>
 | ||||
|         CEC_PATH_ROOT_DIR = 10,    /// data:/CEC
 | ||||
|         CEC_PATH_MBOX_DIR = 11,    /// data:/CEC/<id>
 | ||||
|         CEC_PATH_INBOX_DIR = 12,   /// data:/CEC/<id>/InBox___
 | ||||
|         CEC_PATH_OUTBOX_DIR = 13,  /// data:/CEC/<id>/OutBox__
 | ||||
|         CEC_MBOX_DATA = 100,       /// data:/CEC/<id>/MBoxData.0<i-100>
 | ||||
|         CEC_MBOX_ICON = 101,       /// data:/CEC/<id>/MBoxData.001
 | ||||
|         CEC_MBOX_TITLE = 110,      /// data:/CEC/<id>/MBoxData.010
 | ||||
|         CEC_MBOX_PROGRAM_ID = 150, /// data:/CEC/<id>/MBoxData.050
 | ||||
|     }; | ||||
| 
 | ||||
|     class Interface : public ServiceFramework<Interface> { | ||||
|     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<Service::FS::File> file; | ||||
|     }; | ||||
| 
 | ||||
|     class Interface : public ServiceFramework<Interface, SessionData> { | ||||
|     public: | ||||
|         Interface(std::shared_ptr<Module> 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<u8>& message_id = std::vector<u8>()); | ||||
|     const std::vector<u8> cecd_system_savedata_id = {0x00, 0x00, 0x00, 0x00, | ||||
|                                                      0x26, 0x00, 0x01, 0x00}; | ||||
| 
 | ||||
|     const std::vector<u8> 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<u8>& in, const std::string& dictionary) const; | ||||
| 
 | ||||
|     std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, | ||||
|                                            const std::vector<u8>& msg_id = std::vector<u8>()) const; | ||||
| 
 | ||||
|     Service::FS::ArchiveHandle cecd_system_save_data_archive; | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,9 +20,11 @@ CECD_S::CECD_S(std::shared_ptr<Module> 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"}, | ||||
|  |  | |||
|  | @ -20,9 +20,11 @@ CECD_U::CECD_U(std::shared_ptr<Module> 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"}, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue