-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdraft.dtd
431 lines (428 loc) · 20.3 KB
/
draft.dtd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
<?xml version="1.0"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
<rfc category="std" ipr="none">
<front>
<title abbrev="PINE">
Protocol for Instrumentation of Emulators
</title>
<author initials="Gauvain T. H. G. I." surname="Roussel-Tarbouriech"
fullname="Gauvain Roussel-Tarbouriech">
<organization abbrev="PCSX2">
PCSX2 Emulator Project
</organization>
<address>
<email>[email protected]</email>
<uri>https://govanify.com/</uri>
</address>
</author>
<date month="May" year="2021" day="30"/>
<abstract>
<t>This standard presents PINE (Protocol for
Instrumentation of Emulators), an
Inter-Process Communication protocol targeted
at video-game emulators.</t>
</abstract>
</front>
<middle>
<section anchor="intro" title="Introduction">
<t>This standard describes the PINE Protocol
(Protocol for Instrumentation of Emulators).</t>
<t>This protocol was developped for video-game
emulators to provide a consistent interface
between all of them with four main design
goals:
<list>
<t>Speed</t>
<t>Simplicity</t>
<t>Robustness</t>
<t>Retro-compatibility</t>
</list>
</t>
</section>
<section title="Communication mechanisms">
<t>PINE, as a protocol, needs a way to communicate
with the emulator it targets. This implementation
is system-specific and is only standardized for
Linux (<xref target="lnx_com"/>),
MacOS (<xref target="mac_com"/>) and
Windows (<xref target="win_com"/>). Systems that are not
standardized can still implement the PINE protocol;
The base requirements for them is to have a working
IPC process that can open simultaneous connections.
While a minimum is not enforced a system that
can implement 10 simultaneous communications would
be perfect for this usage.</t>
<t>Each PINE target must have a defined
slot (<xref target="slot"/>) and
target name (<xref target="target_name"/>).</t>
<section anchor="slot" title="Slots">
<t>PINE implements a concept of slots to allow
for simultaneous connections. They can be roughly
thought of as TCP ports <xref target="tsockets"/>. They can be set
to any number between 0 and 65536 included. PINE
targets have a default slot to allow for PnP
(plug-n-play) which must be in the range
28000-30000. Those numbers must be overrideable
manually to allow for multiple instances of the
same software to be able to work concurrently.</t>
</section>
<section anchor="target_name" title="Target name">
<t>Every PINE target must have a set target name.
This target name is used to differenciate targets
between each others. An example target name is
"pcsx2".</t>
</section>
<section title="System-specific implementation">
<section anchor="lnx_com" title="Linux">
<t>Linux uses unix sockets <xref target="usockets"/> of domain SOCK_STREAM
to communicate.
Linux follow the XDG Base specification <xref target="xdg"/> and
as such will use the environment variable
XDG_RUNTIME_DIR as a folder to use to store the unix
socket. In case this variable is not set, it will default
to /tmp. In case the default slot is used, the socket will
be named assuming the format:</t>
<t>'Target name + ".sock"'.</t>
<t>If the slot is specified it will use this format instead:</t>
<t>'Target name + ".sock." + slot'.</t>
<t>Examples:
<list>
<t>/run/user/1000/pcsx2.sock: default slot, XDG_RUNTIME_DIR set</t>
<t>/tmp/pcsx2.sock.123: slot 123, XDG_RUNTIME_DIR not set</t>
</list>
</t>
</section>
<section anchor="mac_com" title="MacOS">
<t>MacOS uses unix sockets <xref target="usockets"/> of domain SOCK_STREAM
to communicate.
MacOS will use the environment variable
TMPDIR as a folder to use to store the unix
socket. In case this variable is not set, it will default
to /tmp. In case the default slot is used, the socket will
be named assuming the format:</t>
<t>'Target name + ".sock"'.</t>
<t>If the slot is specified it will use this format instead:</t>
<t>'Target name + ".sock." + slot'.</t>
<t>Examples:
<list>
<t>/hello/pcsx2.sock: default slot, TMPDIR set to hello</t>
<t>/tmp/pcsx2.sock.123: slot 123, TMPDIR not set</t>
</list>
</t>
</section>
<section anchor="win_com" title="Windows">
<t>Windows uses TCP sockets <xref target="tsockets"/> to communicate.
Slots are used as TCP ports, listening only to localhost.</t>
</section>
</section>
</section>
<section title="Protocol specification">
<t>PINE is a stateless binary-serialized messaging protocol.
Every request sent by the client (program) will always have a reply from
the server (emulator). The server can also initiate requests[todo events]
although it will not expect any answer.</t>
<t>There are three types of messages defined:
<list style="number">
<t>Requests (<xref target="ipc_req"/>)</t>
<t>Answers (<xref target="ipc_ans"/>)</t>
<t>Events (<xref target="ipc_evt"/>)</t>
</list>
Separately, Requests and Answers can also be batched together into batch
commands (<xref target="batch"/>) in order to avoid the roundtrip latency,
when possible.
</t>
<t>All IPC messages are preceded by a uint32_t set to the size of the message,
including this field.</t>
<section anchor="ipc_req" title="Request messages">
<t>
<figure>
<preamble>A request message begins by an uint8_t opcode, followed
by arguments defined per operation. Here is an example of a fully
formed request message:</preamble>
<artwork>
+-----------+--+-----------+
|09 00 00 00|00|34 7d 34 00|
+-----------+--+-----------+
| | |
| | argument
| |
| opcode
|
message size
</artwork>
<postamble>In this case this is a message with opcode 0,
(MsgRead8: <xref target="msgread8"/>) using for argument
0x00347D34 (the address it wants to read). Refer to the sections
below for opcode specific information.</postamble>
</figure>
</t>
<t>opcodes (operation codes) are uint8_t defining the operation that
must be executed by the server. Some of them have special meaning:
<list>
<t>FF: unimplemented</t>
<t>F0-FE (included): reserved for multiple opcodes commands</t>
<t>D0-EF (included): reserved for target-specific operations</t>
</list>
</t>
<t>You will find below a list of all standardized request messages,
along with their arguments and their opcodes.</t>
<section anchor="msgread8" title="MsgRead8">
<t>Reads a 8 byte value from memory location mem.</t>
<t>opcode = 0</t>
<t>argument = [ uint32_t mem ];</t>
</section>
<section anchor="msgread16" title="MsgRead16">
<t>Reads a 16 byte value from memory location mem.</t>
<t>opcode = 1</t>
<t>argument = [ uint32_t mem ];</t>
</section>
<section anchor="msgread32" title="MsgRead32">
<t>Reads a 32 byte value from memory location mem.</t>
<t>opcode = 2</t>
<t>argument = [ uint32_t mem ];</t>
</section>
<section anchor="msgread64" title="MsgRead64">
<t>Reads a 64 byte value from memory location mem.</t>
<t>opcode = 3</t>
<t>argument = [ uint32_t mem ];</t>
</section>
<section anchor="msgwrite8" title="MsgWrite8">
<t>Writes a 8 byte value val to memory location mem.</t>
<t>opcode = 4</t>
<t>argument = [ uint32_t mem, uint8_t val ];</t>
</section>
<section anchor="msgwrite16" title="MsgWrite16">
<t>Writes a 16 byte value val to memory location mem.</t>
<t>opcode = 5</t>
<t>argument = [ uint32_t mem, uint16_t val ];</t>
</section>
<section anchor="msgwrite32" title="MsgWrite32">
<t>Writes a 32 byte value val to memory location mem.</t>
<t>opcode = 6</t>
<t>argument = [ uint32_t mem, uint32_t val ];</t>
</section>
<section anchor="msgwrite64" title="MsgWrite64">
<t>Writes a 64 byte value val to memory location mem.</t>
<t>opcode = 7</t>
<t>argument = [ uint32_t mem, uint64_t val ];</t>
</section>
<section anchor="msgversion" title="MsgVersion">
<t>Retrieves the version of the target.</t>
<t>opcode = 8</t>
<t>argument = [ ];</t>
</section>
<section anchor="msgsavestate" title="MsgSaveState">
<t>Request the emulator to save to state sta.</t>
<t>opcode = 9</t>
<t>argument = [ uint8_t sta ];</t>
</section>
<section anchor="msgloadstate" title="MsgLoadState">
<t>Request the emulator to load state sta.</t>
<t>opcode = 10</t>
<t>argument = [ uint8_t sta ];</t>
</section>
<section anchor="msgtitle" title="MsgTitle">
<t>Request the title of the game currently running.</t>
<t>opcode = 10</t>
<t>argument = [ ];</t>
</section>
<section anchor="msgid" title="MsgID">
<t>Request the ID of the game currently running.</t>
<t>opcode = 11</t>
<t>argument = [ ];</t>
</section>
<section anchor="msguuid" title="MsgUUID">
<t>Request the UUID of the game currently running.</t>
<t>opcode = 12</t>
<t>argument = [ ];</t>
</section>
<section anchor="msggameversion" title="MsgGameVersion">
<t>Request the version of the game currently running.</t>
<t>opcode = 13</t>
<t>argument = [ ];</t>
</section>
<section anchor="msgstatus" title="MsgStatus">
<t>Request the status of the emulator.</t>
<t>opcode = 14</t>
<t>argument = [ ];</t>
</section>
</section>
<section anchor="ipc_ans" title="Answer messages">
<t>
<figure>
<preamble>An answer message begins by an uint8_t result code,
which can be either of those two values:
<list style="numbers">
<t>00: OK</t>
<t>FF: FAIL</t>
</list>
whereas FAIL denotes a failure on the server side. It is followed
by arguments defined per operation. Here is an example of a fully
formed request message:</preamble>
<artwork>
+-----------+--+--+
|06 00 00 00|00|00|
+-----------+--+--+
| | |
| | argument
| |
| result code
|
message size
</artwork>
<postamble>In this case this is an answer message of type MsgRead8,
(MsgRead8: <xref target="msgread8"/>) replying with the result
0x00 (the value it read). Refer to the sections
below for documentation on all possible answer messages.</postamble>
</figure>
</t>
<section anchor="ans_msgread8" title="MsgRead8">
<t>argument = [ uint8_t val ];</t>
</section>
<section anchor="ans_msgread16" title="MsgRead16">
<t>argument = [ uint16_t val ];</t>
</section>
<section anchor="ans_msgread32" title="MsgRead32">
<t>argument = [ uint32_t val ];</t>
</section>
<section anchor="ans_msgread64" title="MsgRead64">
<t>argument = [ uint64_t val ];</t>
</section>
<section anchor="ans_msgwrite8" title="MsgWrite8">
<t>argument = [ ];</t>
</section>
<section anchor="ans_msgwrite16" title="MsgWrite16">
<t>argument = [ ];</t>
</section>
<section anchor="ans_msgwrite32" title="MsgWrite32">
<t>argument = [ ];</t>
</section>
<section anchor="ans_msgwrite64" title="MsgWrite64">
<t>argument = [ ];</t>
</section>
<section anchor="ans_msgversion" title="MsgVersion">
<t>argument = [ uint32_t size, char* version ];</t>
</section>
<section anchor="ans_msgsavestate" title="MsgSaveState">
<t>argument = [ ];</t>
</section>
<section anchor="ans_msgloadstate" title="MsgLoadState">
<t>argument = [ ];</t>
</section>
<section anchor="ans_msgtitle" title="MsgTitle">
<t>argument = [ uint32_t size, char* version ];</t>
</section>
<section anchor="ans_msgid" title="MsgID">
<t>argument = [ uint32_t size, char* version ];</t>
</section>
<section anchor="ans_msguuid" title="MsgUUID">
<t>argument = [ uint32_t size, char* version ];</t>
</section>
<section anchor="ans_msggameversion" title="MsgGameVersion">
<t>argument = [ uint32_t size, char* version ];</t>
</section>
<section anchor="ans_msgstatus" title="MsgStatus">
<t>argument = [ uint32_t status ];</t>
<t>Where status can be any of those value:
<list style="numbers">
<t>0: Running</t>
<t>1: Paused</t>
<t>2: Shutdown</t>
</list>
</t>
</section>
</section>
<section anchor="ipc_evt" title="Event messages">
<t>As of right now, event messages are not implemented. This
should change before this draft becomes a standard.</t>
</section>
<section anchor="batch" title="Batch messages">
<t>
<figure>
<preamble>Batch messages works for both request and answer messages.
They are simply a concatenated gist of all messages minus the original
size header preamble. Here is an example with a request message:</preamble>
<artwork>
+-----------+--------------+--------------+
|0e 00 00 00|00 34 7d 34 00|00 34 7d 34 00|
+-----------+--------------+--------------+
| | |
| | message 2
| |
| message 1
|
message size
</artwork>
</figure>
<figure>
<preamble>And with an answer message:</preamble>
<artwork>
+-----------+--+-----+
|07 00 00 00|00|00|00|
+-----------+--+-----+
| | | |
| | | message 2
| | |
| | message 1
| |
| result code
|
message size
</artwork>
<postamble>As answer messages do not have any identifier and may
have arguments of size unknown at request time, as such it is the
duty of the client to relocate all responses according to the size
of the replies <xref target="client_reloc"/></postamble>
</figure>
</t>
</section>
</section>
</middle>
<back>
<references>
<reference anchor="client_reloc" target="https://code.govanify.com/govanify/pine/src/commit/bdb84a810bd6dde0a30d6253ac5895b3439b044b/src/pine.h#L669-L690">
<front>
<title>PINE client relocation of answer arguments</title>
<author initials="Gauvain T. H. G. I." surname="Roussel-Tarbouriech"
fullname="Gauvain Roussel-Tarbouriech">
<organization abbrev="PCSX2">
PCSX2 Emulator Project
</organization>
</author>
</front>
</reference>
<reference anchor="tsockets">
<front>
<title>Transmission Control Protocol</title>
<author fullname="DARPA">
</author>
</front>
<seriesInfo name="RFC" value="793" />
</reference>
<reference anchor="usockets" target="https://en.wikipedia.org/wiki/Unix_domain_socket">
<front>
<title>Unix Domain Sockets</title>
<author initials="UNIX">
</author>
</front>
</reference>
<reference anchor="xdg" target="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html">
<front>
<title>XDG Base Directory Specification</title>
<author initials="W." surname="Bastian"
fullname="Waldo Bastian">
</author>
<author initials="A." surname="Karlitskaya"
fullname="Allison Karlitskaya">
</author>
<author initials="L." surname="Poettering"
fullname="Lennart Poettering">
</author>
<author initials="J." surname="Löthberg"
fullname="Johannes Löthberg">
</author>
</front>
</reference>
</references>
</back>
</rfc>