1 // Copyright 2016 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 "common/common_types.h"
8 #include "core/hle/kernel/errors.h"
9 #include "core/hle/kernel/thread.h"
10 #include "core/memory.h"
11 
12 namespace IPC {
13 
14 /// Size of the command buffer area, in 32-bit words.
15 constexpr std::size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32);
16 
17 // Maximum number of static buffers per thread.
18 constexpr std::size_t MAX_STATIC_BUFFERS = 16;
19 
20 // These errors are commonly returned by invalid IPC translations, so alias them here for
21 // convenience.
22 // TODO(yuriks): These will probably go away once translation is implemented inside the kernel.
23 using Kernel::ERR_INVALID_BUFFER_DESCRIPTOR;
24 constexpr auto ERR_INVALID_HANDLE = Kernel::ERR_INVALID_HANDLE_OS;
25 
26 enum DescriptorType : u32 {
27     // Buffer related descriptors types (mask : 0x0F)
28     StaticBuffer = 0x02,
29     PXIBuffer = 0x04,
30     MappedBuffer = 0x08,
31     // Handle related descriptors types (mask : 0x30, but need to check for buffer related
32     // descriptors first )
33     CopyHandle = 0x00,
34     MoveHandle = 0x10,
35     CallingPid = 0x20,
36 };
37 
38 union Header {
39     u32 raw;
40     BitField<0, 6, u32> translate_params_size;
41     BitField<6, 6, u32> normal_params_size;
42     BitField<16, 16, u32> command_id;
43 };
44 
45 /**
46  * @brief Creates a command header to be used for IPC
47  * @param command_id            ID of the command to create a header for.
48  * @param normal_params_size         Size of the normal parameters in words. Up to 63.
49  * @param translate_params_size Size of the translate parameters in words. Up to 63.
50  * @return The created IPC header.
51  *
52  * Normal parameters are sent directly to the process while the translate parameters might go
53  * through modifications and checks by the kernel.
54  * The translate parameters are described by headers generated with the IPC::*Desc functions.
55  *
56  * @note While @p normal_params_size is equivalent to the number of normal parameters,
57  * @p translate_params_size includes the size occupied by the translate parameters headers.
58  */
MakeHeader(u16 command_id,unsigned int normal_params_size,unsigned int translate_params_size)59 inline u32 MakeHeader(u16 command_id, unsigned int normal_params_size,
60                       unsigned int translate_params_size) {
61     Header header{};
62     header.command_id.Assign(command_id);
63     header.normal_params_size.Assign(normal_params_size);
64     header.translate_params_size.Assign(translate_params_size);
65     return header.raw;
66 }
67 
68 constexpr u32 MoveHandleDesc(u32 num_handles = 1) {
69     return MoveHandle | ((num_handles - 1) << 26);
70 }
71 
72 constexpr u32 CopyHandleDesc(u32 num_handles = 1) {
73     return CopyHandle | ((num_handles - 1) << 26);
74 }
75 
CallingPidDesc()76 constexpr u32 CallingPidDesc() {
77     return CallingPid;
78 }
79 
IsHandleDescriptor(u32 descriptor)80 constexpr bool IsHandleDescriptor(u32 descriptor) {
81     return (descriptor & 0xF) == 0x0;
82 }
83 
HandleNumberFromDesc(u32 handle_descriptor)84 constexpr u32 HandleNumberFromDesc(u32 handle_descriptor) {
85     return (handle_descriptor >> 26) + 1;
86 }
87 
88 union StaticBufferDescInfo {
89     u32 raw;
90     BitField<0, 4, u32> descriptor_type;
91     BitField<10, 4, u32> buffer_id;
92     BitField<14, 18, u32> size;
93 };
94 
StaticBufferDesc(std::size_t size,u8 buffer_id)95 inline u32 StaticBufferDesc(std::size_t size, u8 buffer_id) {
96     StaticBufferDescInfo info{};
97     info.descriptor_type.Assign(StaticBuffer);
98     info.buffer_id.Assign(buffer_id);
99     info.size.Assign(static_cast<u32>(size));
100     return info.raw;
101 }
102 
103 /**
104  * @brief Creates a header describing a buffer to be sent over PXI.
105  * @param size         Size of the buffer. Max 0x00FFFFFF.
106  * @param buffer_id    The Id of the buffer. Max 0xF.
107  * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have
108  * read-write access.
109  * @return The created PXI buffer header.
110  *
111  * The next value is a phys-address of a table located in the BASE memregion.
112  */
PXIBufferDesc(u32 size,unsigned buffer_id,bool is_read_only)113 inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) {
114     u32 type = PXIBuffer;
115     if (is_read_only)
116         type |= 0x2;
117     return type | (size << 8) | ((buffer_id & 0xF) << 4);
118 }
119 
120 enum MappedBufferPermissions : u32 {
121     R = 1,
122     W = 2,
123     RW = R | W,
124 };
125 
126 union MappedBufferDescInfo {
127     u32 raw;
128     BitField<0, 4, u32> flags;
129     BitField<1, 2, MappedBufferPermissions> perms;
130     BitField<4, 28, u32> size;
131 };
132 
MappedBufferDesc(std::size_t size,MappedBufferPermissions perms)133 inline u32 MappedBufferDesc(std::size_t size, MappedBufferPermissions perms) {
134     MappedBufferDescInfo info{};
135     info.flags.Assign(MappedBuffer);
136     info.perms.Assign(perms);
137     info.size.Assign(static_cast<u32>(size));
138     return info.raw;
139 }
140 
GetDescriptorType(u32 descriptor)141 inline DescriptorType GetDescriptorType(u32 descriptor) {
142     // Note: Those checks must be done in this order
143     if (IsHandleDescriptor(descriptor))
144         return (DescriptorType)(descriptor & 0x30);
145 
146     // handle the fact that the following descriptors can have rights
147     if (descriptor & MappedBuffer)
148         return MappedBuffer;
149 
150     if (descriptor & PXIBuffer)
151         return PXIBuffer;
152 
153     return StaticBuffer;
154 }
155 
156 } // namespace IPC
157