1 // Copyright 2015 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <memory> 8 #include "common/bit_field.h" 9 #include "common/common_funcs.h" 10 #include "core/hle/kernel/event.h" 11 #include "core/hle/service/fs/archive.h" 12 #include "core/hle/service/service.h" 13 14 namespace FileSys { 15 class ArchiveBackend; 16 class FileBackend; 17 } // namespace FileSys 18 19 namespace Core { 20 class System; 21 } 22 23 namespace Service::CECD { 24 25 class Module final { 26 public: 27 explicit Module(Core::System& system); 28 ~Module(); 29 30 enum class CecCommand : u32 { 31 None = 0, 32 Start = 1, 33 ResetStart = 2, 34 ReadyScan = 3, 35 ReadyScanWait = 4, 36 StartScan = 5, 37 Rescan = 6, 38 NdmResume = 7, 39 NdmSuspend = 8, 40 NdmSuspendImmediate = 9, 41 StopWait = 0x0A, 42 Stop = 0x0B, 43 StopForce = 0x0C, 44 StopForceWait = 0x0D, 45 ResetFilter = 0x0E, 46 DaemonStop = 0x0F, 47 DaemonStart = 0x10, 48 Exit = 0x11, 49 OverBoss = 0x12, 50 OverBossForce = 0x13, 51 OverBossForceWait = 0x14, 52 End = 0x15, 53 }; 54 55 /** 56 * CecDataPathType possible missing values; need to figure out placement 57 * 58 * data:/CEC/TMP 59 * data:/CEC/test 60 */ 61 enum class CecDataPathType : u32 { 62 Invalid = 0, 63 MboxList = 1, /// data:/CEC/MBoxList____ 64 MboxInfo = 2, /// data:/CEC/<id>/MBoxInfo____ 65 InboxInfo = 3, /// data:/CEC/<id>/InBox___/BoxInfo_____ 66 OutboxInfo = 4, /// data:/CEC/<id>/OutBox__/BoxInfo_____ 67 OutboxIndex = 5, /// data:/CEC/<id>/OutBox__/OBIndex_____ 68 InboxMsg = 6, /// data:/CEC/<id>/InBox___/_<message_id> 69 OutboxMsg = 7, /// data:/CEC/<id>/OutBox__/_<message_id> 70 RootDir = 10, /// data:/CEC 71 MboxDir = 11, /// data:/CEC/<id> 72 InboxDir = 12, /// data:/CEC/<id>/InBox___ 73 OutboxDir = 13, /// data:/CEC/<id>/OutBox__ 74 MboxData = 100, /// data:/CEC/<id>/MBoxData.0<i-100> 75 MboxIcon = 101, /// data:/CEC/<id>/MBoxData.001 76 MboxTitle = 110, /// data:/CEC/<id>/MBoxData.010 77 MboxProgramId = 150, /// data:/CEC/<id>/MBoxData.050 78 }; 79 80 enum class CecState : u32 { 81 None = 0, 82 Init = 1, 83 WirelessParamSetup = 2, 84 WirelessReady = 3, 85 WirelessStartConfig = 4, 86 Scan = 5, 87 Scanning = 6, 88 Connect = 7, 89 Connecting = 8, 90 Connected = 9, 91 ConnectTcp = 10, 92 ConnectingTcp = 11, 93 ConnectedTcp = 12, 94 Negotiation = 13, 95 SendRecvStart = 14, 96 SendRecvInit = 15, 97 SendReady = 16, 98 ReceiveReady = 17, 99 Receive = 18, 100 ConnectionFinishTcp = 19, 101 ConnectionFinish = 20, 102 SendPost = 21, 103 ReceivePost = 22, 104 Finishing = 23, 105 Finish = 24, 106 OverBoss = 25, 107 Idle = 26 108 }; 109 110 enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; 111 112 struct CecBoxInfoHeader { 113 u16_le magic; // 0x6262 'bb' 114 INSERT_PADDING_BYTES(2); 115 u32_le box_info_size; 116 u32_le max_box_size; 117 u32_le box_size; 118 u32_le max_message_num; 119 u32_le message_num; 120 u32_le max_batch_size; 121 u32_le max_message_size; 122 }; 123 static_assert(sizeof(CecBoxInfoHeader) == 0x20, "CecBoxInfoHeader struct has incorrect size."); 124 125 struct CecMBoxInfoHeader { 126 u16_le magic; // 0x6363 'cc' 127 INSERT_PADDING_BYTES(2); 128 u32_le program_id; 129 u32_le private_id; 130 u8 flag; 131 u8 flag2; 132 INSERT_PADDING_BYTES(2); 133 std::array<u8, 32> hmac_key; 134 INSERT_PADDING_BYTES(4); 135 struct Time { 136 u32_le year; 137 u8 month; 138 u8 day; 139 u8 hour; 140 u8 minute; 141 u8 second; 142 u8 millisecond; 143 u8 microsecond; 144 u8 padding; 145 } last_accessed; 146 INSERT_PADDING_BYTES(4); 147 Time last_received; 148 INSERT_PADDING_BYTES(4); 149 Time unknown_time; 150 }; 151 static_assert(sizeof(CecMBoxInfoHeader) == 0x60, 152 "CecMBoxInfoHeader struct has incorrect size."); 153 154 struct CecMBoxListHeader { 155 u16_le magic; // 0x6868 'hh' 156 INSERT_PADDING_BYTES(2); 157 u16_le version; // 0x01 00, maybe activated flag? 158 INSERT_PADDING_BYTES(2); 159 u16_le num_boxes; // 24 max 160 INSERT_PADDING_BYTES(2); 161 std::array<std::array<u8, 16>, 24> box_names; // 16 char names, 24 boxes 162 }; 163 static_assert(sizeof(CecMBoxListHeader) == 0x18C, 164 "CecMBoxListHeader struct has incorrect size."); 165 166 struct CecMessageHeader { 167 u16_le magic; // 0x6060 `` 168 INSERT_PADDING_BYTES(2); 169 u32_le message_size; 170 u32_le header_size; 171 u32_le body_size; 172 173 u32_le title_id; 174 u32_le title_id2; 175 u32_le batch_id; 176 u32_le unknown_id; 177 178 std::array<u8, 8> message_id; 179 u32_le version; 180 std::array<u8, 8> message_id2; 181 u8 flag; 182 u8 send_method; 183 u8 is_unopen; 184 u8 is_new; 185 u64_le sender_id; 186 u64_le sender_id2; 187 struct Time { 188 u32_le year; 189 u8 month; 190 u8 day; 191 u8 hour; 192 u8 minute; 193 u8 second; 194 u8 millisecond; 195 u8 microsecond; 196 u8 padding; 197 } send_time, recv_time, create_time; 198 u8 send_count; 199 u8 forward_count; 200 u16_le user_data; 201 }; 202 static_assert(sizeof(CecMessageHeader) == 0x70, "CecMessageHeader struct has incorrect size."); 203 204 struct CecOBIndexHeader { 205 u16_le magic; // 0x6767 'gg' 206 INSERT_PADDING_BYTES(2); 207 u32_le message_num; 208 // Array of messageid's 8 bytes each, same as CecMessageHeader.message_id[8] 209 }; 210 static_assert(sizeof(CecOBIndexHeader) == 0x08, "CecOBIndexHeader struct has incorrect size."); 211 212 enum class CecdState : u32 { 213 NdmStatusWorking = 0, 214 NdmStatusIdle = 1, 215 NdmStatusSuspending = 2, 216 NdmStatusSuspended = 3, 217 }; 218 219 union CecOpenMode { 220 u32 raw; 221 BitField<0, 1, u32> unknown; // 1 delete? 222 BitField<1, 1, u32> read; // 2 223 BitField<2, 1, u32> write; // 4 224 BitField<3, 1, u32> create; // 8 225 BitField<4, 1, u32> check; // 16 maybe validate sig? 226 BitField<30, 1, u32> unk_flag; 227 }; 228 229 enum class CecTest : u32 { 230 CEC_TEST_000 = 0, 231 CEC_TEST_001 = 1, 232 CEC_TEST_002 = 2, 233 CEC_TEST_003 = 3, 234 CEC_TEST_004 = 4, 235 CEC_TEST_005 = 5, 236 CEC_TEST_006 = 6, 237 }; 238 239 /// Opening a file and reading/writing can be handled by two different functions 240 /// So, we need to pass that file data around 241 struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase { 242 SessionData(); 243 ~SessionData(); 244 245 u32 ncch_program_id; 246 CecDataPathType data_path_type; 247 CecOpenMode open_mode; 248 FileSys::Path path; 249 250 std::unique_ptr<FileSys::FileBackend> file; 251 252 private: 253 template <class Archive> serializeSessionData254 void serialize(Archive& ar, const unsigned int) { 255 ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>( 256 *this); 257 ar& ncch_program_id; 258 ar& data_path_type; 259 ar& open_mode.raw; 260 ar& path; 261 ar& file; 262 } 263 friend class boost::serialization::access; 264 }; 265 266 class Interface : public ServiceFramework<Interface, SessionData> { 267 public: 268 Interface(std::shared_ptr<Module> cecd, const char* name, u32 max_session); 269 ~Interface() = default; 270 271 protected: 272 /** 273 * CECD::Open service function 274 * Inputs: 275 * 0 : Header Code[0x000100C2] 276 * 1 : NCCH Program ID 277 * 2 : Path type 278 * 3 : File open flag 279 * 4 : Descriptor for process ID 280 * 5 : Placeholder for process ID 281 * Outputs: 282 * 1 : Result of function, 0 on success, otherwise error code 283 * 2 : File size? 284 */ 285 void Open(Kernel::HLERequestContext& ctx); 286 287 /** 288 * CECD::Read service function 289 * Inputs: 290 * 0 : Header Code[0x00020042] 291 * 1 : Buffer size (unused) 292 * 2 : Descriptor for mapping a write-only buffer in the target process 293 * 3 : Buffer address 294 * Outputs: 295 * 1 : Result of function, 0 on success, otherwise error code 296 * 2 : Read size 297 * 3 : Descriptor for mapping a write-only buffer in the target process 298 * 4 : Buffer address 299 */ 300 void Read(Kernel::HLERequestContext& ctx); 301 302 /** 303 * CECD::ReadMessage service function 304 * Inputs: 305 * 0 : Header Code[0x00030104] 306 * 1 : NCCH Program ID 307 * 2 : bool is_outbox 308 * 3 : Message ID size (unused, always 8) 309 * 4 : Buffer size (unused) 310 * 5 : Descriptor for mapping a read-only buffer in the target process 311 * 6 : Message ID address 312 * 7 : Descriptor for mapping a write-only buffer in the target process 313 * 8 : Buffer address 314 * Outputs: 315 * 1 : Result of function, 0 on success, otherwise error code 316 * 2 : Read size 317 * 3 : Descriptor for mapping a read-only buffer in the target process 318 * 4 : Message ID address 319 * 5 : Descriptor for mapping a write-only buffer in the target process 320 * 6 : Buffer address 321 */ 322 void ReadMessage(Kernel::HLERequestContext& ctx); 323 324 /** 325 * CECD::ReadMessageWithHMAC service function 326 * Inputs: 327 * 0 : Header Code[0x00040106] 328 * 1 : NCCH Program ID 329 * 2 : bool is_outbox 330 * 3 : Message ID size(unused, always 8) 331 * 4 : Buffer size(unused) 332 * 5 : Descriptor for mapping a read-only buffer in the target process 333 * 6 : Message ID address 334 * 7 : Descriptor for mapping a read-only buffer in the target process 335 * 8 : HMAC key address 336 * 9 : Descriptor for mapping a write-only buffer in the target process 337 * 10 : Buffer address 338 * Outputs: 339 * 1 : Result of function, 0 on success, otherwise error code 340 * 2 : Read size 341 * 3 : Descriptor for mapping a read-only buffer in the target process 342 * 4 : Message ID address 343 * 5 : Descriptor for mapping a read-only buffer in the target process 344 * 6 : HMAC key address 345 * 7 : Descriptor for mapping a write-only buffer in the target process 346 * 8 : Buffer address 347 */ 348 void ReadMessageWithHMAC(Kernel::HLERequestContext& ctx); 349 350 /** 351 * CECD::Write service function 352 * Inputs: 353 * 0 : Header Code[0x00050042] 354 * 1 : Buffer size(unused) 355 * 2 : Descriptor for mapping a read-only buffer in the target process 356 * 3 : Buffer address 357 * Outputs: 358 * 1 : Result of function, 0 on success, otherwise error code 359 * 2 : Descriptor for mapping a read-only buffer in the target process 360 * 3 : Buffer address 361 */ 362 void Write(Kernel::HLERequestContext& ctx); 363 364 /** 365 * CECD::WriteMessage service function 366 * Inputs: 367 * 0 : Header Code[0x00060104] 368 * 1 : NCCH Program ID 369 * 2 : bool is_outbox 370 * 3 : Message ID size(unused, always 8) 371 * 4 : Buffer size(unused) 372 * 5 : Descriptor for mapping a read-only buffer in the target process 373 * 6 : Buffer address 374 * 7 : Descriptor for mapping a read/write buffer in the target process 375 * 8 : Message ID address 376 * Outputs: 377 * 1 : Result of function, 0 on success, otherwise error code 378 * 2 : Descriptor for mapping a read-only buffer in the target process 379 * 3 : Buffer address 380 * 4 : Descriptor for mapping a read/write buffer in the target process 381 * 5 : Message ID address 382 */ 383 void WriteMessage(Kernel::HLERequestContext& ctx); 384 385 /** 386 * CECD::WriteMessageWithHMAC service function 387 * Inputs: 388 * 0 : Header Code[0x00070106] 389 * 1 : NCCH Program ID 390 * 2 : bool is_outbox 391 * 3 : Message ID size(unused, always 8) 392 * 4 : Buffer size(unused) 393 * 5 : Descriptor for mapping a read-only buffer in the target process 394 * 6 : Buffer address 395 * 7 : Descriptor for mapping a read-only buffer in the target process 396 * 8 : HMAC key address 397 * 9 : Descriptor for mapping a read/write buffer in the target process 398 * 10 : Message ID address 399 * Outputs: 400 * 1 : Result of function, 0 on success, otherwise error code 401 * 2 : Descriptor for mapping a read-only buffer in the target process 402 * 3 : Buffer address 403 * 4 : Descriptor for mapping a read-only buffer in the target process 404 * 5 : HMAC key address 405 * 6 : Descriptor for mapping a read/write buffer in the target process 406 * 7 : Message ID address 407 */ 408 void WriteMessageWithHMAC(Kernel::HLERequestContext& ctx); 409 410 /** 411 * CECD::Delete service function 412 * Inputs: 413 * 0 : Header Code[0x00080102] 414 * 1 : NCCH Program ID 415 * 2 : Path type 416 * 3 : bool is_outbox 417 * 4 : Message ID size (unused) 418 * 5 : Descriptor for mapping a read-only buffer in the target process 419 * 6 : Message ID address 420 * Outputs: 421 * 1 : Result of function, 0 on success, otherwise error code 422 * 2 : Descriptor for mapping a read-only buffer in the target process 423 * 3 : Message ID address 424 */ 425 void Delete(Kernel::HLERequestContext& ctx); 426 427 /** 428 * CECD::SetData service function 429 * Inputs: 430 * 0 : Header Code[0x000900C2] 431 * 1 : NCCH Program ID 432 * 2 : Path type 433 * 3 : bool is_outbox 434 * 4 : Descriptor for mapping a read-only buffer in the target process 435 * 5 : Message ID address 436 * Outputs: 437 * 1 : Result of function, 0 on success, otherwise error code 438 * 2 : Descriptor for mapping a read-only buffer in the target process 439 * 3 : Message ID address 440 */ 441 void SetData(Kernel::HLERequestContext& ctx); 442 443 /** 444 * CECD::ReadData service function 445 * Inputs: 446 * 0 : Header Code[0x000A00C4] 447 * 1 : Destination buffer size (unused) 448 * 2 : Info type 449 * 3 : Param buffer size (unused) 450 * 4 : Descriptor for mapping a read-only buffer in the target process 451 * 5 : Param buffer address 452 * 6 : Descriptor for mapping a write-only buffer in the target process 453 * 7 : Destination buffer address 454 * Outputs: 455 * 1 : Result of function, 0 on success, otherwise error code 456 * 2 : Descriptor for mapping a read-only buffer in the target process 457 * 3 : Param buffer address 458 * 4 : Descriptor for mapping a write-only buffer in the target process 459 * 5 : Destination buffer address 460 */ 461 void ReadData(Kernel::HLERequestContext& ctx); 462 463 /** 464 * CECD::Start service function 465 * Inputs: 466 * 0 : Header Code[0x000B0040] 467 * 1 : Command 468 * Outputs: 469 * 1 : Result of function, 0 on success, otherwise error code 470 */ 471 void Start(Kernel::HLERequestContext& ctx); 472 473 /** 474 * CECD::Stop service function 475 * Inputs: 476 * 0 : Header Code[0x000C0040] 477 * 1 : Command 478 * Outputs: 479 * 1 : Result of function, 0 on success, otherwise error code 480 */ 481 void Stop(Kernel::HLERequestContext& ctx); 482 483 /** 484 * CECD::GetCecInfoBuffer service function 485 * Inputs: 486 * 0 : Header Code[0x000D0082] 487 * 1 : unknown 488 * 2 : unknown, buffer size? 489 * 3 : Descriptor for mapping a write-only buffer in the target process 490 * 4 : Destination buffer address 491 * Outputs: 492 * 1 : Result of function, 0 on success, otherwise error code 493 * 2-3 : MappedBuffer 494 */ 495 void GetCecInfoBuffer(Kernel::HLERequestContext& ctx); 496 497 /** 498 * GetCecdState service function 499 * Inputs: 500 * 0: Header Code[0x000E0000] 501 * Outputs: 502 * 1: ResultCode 503 * 2: CecdState 504 */ 505 void GetCecdState(Kernel::HLERequestContext& ctx); 506 507 /** 508 * GetCecInfoEventHandle service function 509 * Inputs: 510 * 0: Header Code[0x000F0000] 511 * Outputs: 512 * 1: ResultCode 513 * 3: Event Handle 514 */ 515 void GetCecInfoEventHandle(Kernel::HLERequestContext& ctx); 516 517 /** 518 * GetChangeStateEventHandle service function 519 * Inputs: 520 * 0: Header Code[0x00100000] 521 * Outputs: 522 * 1: ResultCode 523 * 3: Event Handle 524 */ 525 void GetChangeStateEventHandle(Kernel::HLERequestContext& ctx); 526 527 /** 528 * CECD::OpenAndWrite service function 529 * Inputs: 530 * 0 : Header Code[0x00110104] 531 * 1 : Buffer size (unused) 532 * 2 : NCCH Program ID 533 * 3 : Path type 534 * 4 : File open flag 535 * 5 : Descriptor for process ID 536 * 6 : Placeholder for process ID 537 * 7 : Descriptor for mapping a read-only buffer in the target process 538 * 8 : Buffer address 539 * Outputs: 540 * 1 : Result of function, 0 on success, otherwise error code 541 * 2 : Descriptor for mapping a read-only buffer in the target process 542 * 3 : Buffer address 543 */ 544 void OpenAndWrite(Kernel::HLERequestContext& ctx); 545 546 /** 547 * CECD::OpenAndRead service function 548 * Inputs: 549 * 0 : Header Code[0x00120104] 550 * 1 : Buffer size (unused) 551 * 2 : NCCH Program ID 552 * 3 : Path type 553 * 4 : File open flag 554 * 5 : Descriptor for process ID 555 * 6 : Placeholder for process ID 556 * 7 : Descriptor for mapping a write-only buffer in the target process 557 * 8 : Buffer address 558 * Outputs: 559 * 1 : Result of function, 0 on success, otherwise error code 560 * 2 : Toal bytes read 561 * 3 : Descriptor for mapping a write-only buffer in the target process 562 * 4 : Buffer address 563 */ 564 void OpenAndRead(Kernel::HLERequestContext& ctx); 565 566 /** 567 * CECD::GetEventLog service function 568 * Inputs: 569 * 0 : Header Code[0x001E0082] 570 * 1 : unknown 571 * 2 : unknown 572 * 3 : buffer descriptor 573 * 4 : buffer address 574 * Outputs: 575 * 1 : Result of function, 0 on success, otherwise error code 576 * 2 : unknown 577 */ 578 void GetEventLog(Kernel::HLERequestContext& ctx); 579 580 /** 581 * CECD::GetEventLogStart service function 582 * Inputs: 583 * 0 : Header Code[0x001F0000] 584 * Outputs: 585 * 1 : Result of function, 0 on success, otherwise error code 586 * 2 : unknown 587 */ 588 void GetEventLogStart(Kernel::HLERequestContext& ctx); 589 590 /** 591 * GetCecInfoEventHandleSys service function 592 * Inputs: 593 * 0: Header Code[0x40020002] 594 * Outputs: 595 * 1: ResultCode 596 * 3: Event Handle 597 */ 598 void GetCecInfoEventHandleSys(Kernel::HLERequestContext& ctx); 599 600 protected: 601 std::shared_ptr<Module> cecd; 602 }; 603 604 private: 605 /// String used by cecd for base64 encoding found in the sysmodule disassembly 606 const std::string base64_dict = 607 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; 608 609 const std::vector<u8> cecd_system_savedata_id = {0x00, 0x00, 0x00, 0x00, 610 0x26, 0x00, 0x01, 0x00}; 611 612 /// Encoding function used for the message id 613 std::string EncodeBase64(const std::vector<u8>& in) const; 614 615 std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id, 616 const std::vector<u8>& msg_id = std::vector<u8>()) const; 617 618 std::string GetCecCommandAsString(const CecCommand command) const; 619 620 void CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_program_id, 621 std::vector<u8>& file_buffer); 622 623 std::unique_ptr<FileSys::ArchiveBackend> cecd_system_save_data_archive; 624 625 std::shared_ptr<Kernel::Event> cecinfo_event; 626 std::shared_ptr<Kernel::Event> change_state_event; 627 628 Core::System& system; 629 630 template <class Archive> 631 void serialize(Archive& ar, const unsigned int); 632 friend class boost::serialization::access; 633 }; 634 635 /// Initialize CECD service(s) 636 void InstallInterfaces(Core::System& system); 637 638 } // namespace Service::CECD 639 640 SERVICE_CONSTRUCT(Service::CECD::Module) 641 BOOST_CLASS_EXPORT_KEY(Service::CECD::Module) 642 BOOST_CLASS_EXPORT_KEY(Service::CECD::Module::SessionData) 643