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