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