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#ifndef _DEFAULT_SOURCE
27# define _DEFAULT_SOURCE
28#endif
29#include <stdint.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <stddef.h>
33#include <assert.h>
34#include "hw/remote-port-proto.h"
35
36#undef MIN
37#define MIN(x, y) (x < y ? x : y)
38
39#if defined(__linux__)
40# include <endian.h>
41#elif defined(__FreeBSD__) || defined(__NetBSD__)
42# include <sys/endian.h>
43#elif defined(__OpenBSD__)
44# include <sys/types.h>
45# define be16toh(x) betoh16(x)
46# define be32toh(x) betoh32(x)
47# define be64toh(x) betoh64(x)
48#elif defined(__WIN32)
49
50# define htobe64(x) _byteswap_uint64(x)
51# define htobe32(x) _byteswap_ulong(x)
52# define htobe16(x) _byteswap_ushort(x)
53
54# define be64toh(x) _byteswap_uint64(x)
55# define be32toh(x) _byteswap_ulong(x)
56# define be16toh(x) _byteswap_ushort(x)
57#elif defined(__APPLE__)
58# include <libkern/OSByteOrder.h>
59
60
61# define htobe64(x) OSSwapHostToBigInt64(x)
62# define htobe32(x) OSSwapHostToBigInt32(x)
63# define htobe16(x) OSSwapHostToBigInt16(x)
64
65# define be64toh(x) OSSwapBigToHostInt64(x)
66# define be32toh(x) OSSwapBigToHostInt32(x)
67# define be16toh(x) OSSwapBigToHostInt16(x)
68#endif
69
70
71#ifndef htobe64
72# include <byteswap.h>
73
74# if __BYTE_ORDER == __LITTLE_ENDIAN
75# define htobe64(x) bswap_64(x)
76# define htobe32(x) bswap_32(x)
77# define htobe16(x) bswap_16(x)
78
79# define be64toh(x) bswap_64(x)
80# define be32toh(x) bswap_32(x)
81# define be16toh(x) bswap_16(x)
82# else
83# define htobe64(x) x
84# define htobe32(x) x
85# define htobe16(x) x
86
87# define be64toh(x) x
88# define be32toh(x) x
89# define be16toh(x) x
90# endif
91#endif
92
93static const char *rp_cmd_names[RP_CMD_max + 1] = {
94 [RP_CMD_nop] = "nop",
95 [RP_CMD_hello] = "hello",
96 [RP_CMD_cfg] = "cfg",
97 [RP_CMD_read] = "read",
98 [RP_CMD_write] = "write",
99 [RP_CMD_interrupt] = "interrupt",
100 [RP_CMD_sync] = "sync",
101};
102
103const char *rp_cmd_to_string(enum rp_cmd cmd)
104{
105 assert(cmd <= RP_CMD_max);
106 return rp_cmd_names[cmd];
107}
108
109int rp_decode_hdr(struct rp_pkt *pkt)
110{
111 int used = 0;
112
113 pkt->hdr.cmd = be32toh(pkt->hdr.cmd);
114 pkt->hdr.len = be32toh(pkt->hdr.len);
115 pkt->hdr.id = be32toh(pkt->hdr.id);
116 pkt->hdr.flags = be32toh(pkt->hdr.flags);
117 pkt->hdr.dev = be32toh(pkt->hdr.dev);
118 used += sizeof pkt->hdr;
119 return used;
120}
121
122int rp_decode_payload(struct rp_pkt *pkt)
123{
124 int used = 0;
125
126 uint64_t master_id;
127
128 switch (pkt->hdr.cmd) {
129 case RP_CMD_hello:
130 assert(pkt->hdr.len >= sizeof pkt->hello.version);
131 pkt->hello.version.major = be16toh(pkt->hello.version.major);
132 pkt->hello.version.minor = be16toh(pkt->hello.version.minor);
133 used += sizeof pkt->hello.version;
134
135 if ((pkt->hdr.len - used) >= sizeof pkt->hello.caps) {
136 void *offset;
137 int i;
138
139 pkt->hello.caps.offset = be32toh(pkt->hello.caps.offset);
140 pkt->hello.caps.len = be16toh(pkt->hello.caps.len);
141
142 offset = (char *)pkt + pkt->hello.caps.offset;
143 for (i = 0; i < pkt->hello.caps.len; i++) {
144 uint32_t cap;
145
146
147
148 memcpy(&cap, offset + i * sizeof cap, sizeof cap);
149 cap = be32toh(cap);
150 memcpy(offset + i * sizeof cap, &cap, sizeof cap);
151 }
152 used += sizeof pkt->hello.caps;
153 } else {
154 pkt->hello.caps.offset = 0;
155 pkt->hello.caps.len = 0;
156 }
157
158
159
160 used = pkt->hdr.len;
161 break;
162 case RP_CMD_write:
163 case RP_CMD_read:
164 assert(pkt->hdr.len >= sizeof pkt->busaccess - sizeof pkt->hdr);
165 pkt->busaccess.timestamp = be64toh(pkt->busaccess.timestamp);
166 pkt->busaccess.addr = be64toh(pkt->busaccess.addr);
167 pkt->busaccess.master_id = be16toh(pkt->busaccess.master_id);
168 pkt->busaccess.attributes = be64toh(pkt->busaccess.attributes);
169 pkt->busaccess.len = be32toh(pkt->busaccess.len);
170 pkt->busaccess.width = be32toh(pkt->busaccess.width);
171 pkt->busaccess.stream_width = be32toh(pkt->busaccess.stream_width);
172 master_id = be16toh(pkt->busaccess.master_id);
173
174 used += sizeof pkt->busaccess - sizeof pkt->hdr;
175
176 if (pkt->busaccess.attributes & RP_BUS_ATTR_EXT_BASE) {
177 struct rp_pkt_busaccess_ext_base *pext = &pkt->busaccess_ext_base;
178
179 assert(pkt->hdr.len >= sizeof *pext - sizeof pkt->hdr);
180 master_id |= (uint64_t)be16toh(pext->master_id_31_16) << 16;
181 master_id |= (uint64_t)be32toh(pext->master_id_63_32) << 32;
182 pext->data_offset = be32toh(pext->data_offset);
183 pext->next_offset = be32toh(pext->next_offset);
184 pext->byte_enable_offset = be32toh(pext->byte_enable_offset);
185 pext->byte_enable_len = be32toh(pext->byte_enable_len);
186
187 used += sizeof *pext - sizeof pkt->busaccess;
188 }
189 pkt->busaccess.master_id = master_id;
190 break;
191 case RP_CMD_interrupt:
192 pkt->interrupt.timestamp = be64toh(pkt->interrupt.timestamp);
193 pkt->interrupt.vector = be64toh(pkt->interrupt.vector);
194 pkt->interrupt.line = be32toh(pkt->interrupt.line);
195 pkt->interrupt.val = pkt->interrupt.val;
196 used += pkt->hdr.len;
197 break;
198 case RP_CMD_sync:
199 pkt->sync.timestamp = be64toh(pkt->interrupt.timestamp);
200 used += pkt->hdr.len;
201 break;
202 default:
203 break;
204 }
205 return used;
206}
207
208void rp_encode_hdr(struct rp_pkt_hdr *hdr, uint32_t cmd, uint32_t id,
209 uint32_t dev, uint32_t len, uint32_t flags)
210{
211 hdr->cmd = htobe32(cmd);
212 hdr->len = htobe32(len);
213 hdr->id = htobe32(id);
214 hdr->dev = htobe32(dev);
215 hdr->flags = htobe32(flags);
216}
217
218size_t rp_encode_hello_caps(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
219 uint16_t version_major, uint16_t version_minor,
220 uint32_t *caps, uint32_t *caps_out,
221 uint32_t caps_len)
222{
223 size_t psize = sizeof *pkt + sizeof caps[0] * caps_len;
224 unsigned int i;
225
226 rp_encode_hdr(&pkt->hdr, RP_CMD_hello, id, dev,
227 psize - sizeof pkt->hdr, 0);
228 pkt->version.major = htobe16(version_major);
229 pkt->version.minor = htobe16(version_minor);
230
231
232 pkt->caps.offset = htobe32(sizeof *pkt);
233 pkt->caps.len = htobe16(caps_len);
234
235 for (i = 0; i < caps_len; i++) {
236 uint32_t cap;
237
238 cap = caps[i];
239 caps_out[i] = htobe32(cap);
240 }
241 return sizeof *pkt;
242}
243
244static void rp_encode_busaccess_common(struct rp_pkt_busaccess *pkt,
245 int64_t clk, uint16_t master_id,
246 uint64_t addr, uint64_t attr, uint32_t size,
247 uint32_t width, uint32_t stream_width)
248{
249 pkt->timestamp = htobe64(clk);
250 pkt->master_id = htobe16(master_id);
251 pkt->addr = htobe64(addr);
252 pkt->attributes = htobe64(attr);
253 pkt->len = htobe32(size);
254 pkt->width = htobe32(width);
255 pkt->stream_width = htobe32(stream_width);
256}
257
258size_t rp_encode_read(uint32_t id, uint32_t dev,
259 struct rp_pkt_busaccess *pkt,
260 int64_t clk, uint16_t master_id,
261 uint64_t addr, uint64_t attr, uint32_t size,
262 uint32_t width, uint32_t stream_width)
263{
264 rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
265 sizeof *pkt - sizeof pkt->hdr, 0);
266 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
267 size, width, stream_width);
268 return sizeof *pkt;
269}
270
271size_t rp_encode_read_resp(uint32_t id, uint32_t dev,
272 struct rp_pkt_busaccess *pkt,
273 int64_t clk, uint16_t master_id,
274 uint64_t addr, uint64_t attr, uint32_t size,
275 uint32_t width, uint32_t stream_width)
276{
277 rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
278 sizeof *pkt - sizeof pkt->hdr + size, RP_PKT_FLAGS_response);
279 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
280 size, width, stream_width);
281 return sizeof *pkt + size;
282}
283
284size_t rp_encode_write(uint32_t id, uint32_t dev,
285 struct rp_pkt_busaccess *pkt,
286 int64_t clk, uint16_t master_id,
287 uint64_t addr, uint64_t attr, uint32_t size,
288 uint32_t width, uint32_t stream_width)
289{
290 rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
291 sizeof *pkt - sizeof pkt->hdr + size, 0);
292 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
293 size, width, stream_width);
294 return sizeof *pkt;
295}
296
297size_t rp_encode_write_resp(uint32_t id, uint32_t dev,
298 struct rp_pkt_busaccess *pkt,
299 int64_t clk, uint16_t master_id,
300 uint64_t addr, uint64_t attr, uint32_t size,
301 uint32_t width, uint32_t stream_width)
302{
303 rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
304 sizeof *pkt - sizeof pkt->hdr, RP_PKT_FLAGS_response);
305 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
306 size, width, stream_width);
307 return sizeof *pkt;
308}
309
310
311size_t rp_encode_busaccess(struct rp_peer_state *peer,
312 struct rp_pkt_busaccess_ext_base *pkt,
313 struct rp_encode_busaccess_in *in) {
314 struct rp_pkt_busaccess *pkt_v4_0 = (void *) pkt;
315 uint32_t hsize = 0;
316 uint32_t ret_size = 0;
317
318
319 if (in->cmd == RP_CMD_write && !(in->flags & RP_PKT_FLAGS_response)) {
320 hsize = in->size;
321 }
322 if (in->cmd == RP_CMD_read && (in->flags & RP_PKT_FLAGS_response)) {
323 hsize = in->size;
324 ret_size = in->size;
325 }
326
327
328
329
330
331 if (!peer->caps.busaccess_ext_base && !(in->attr & RP_BUS_ATTR_EXT_BASE)) {
332
333 assert(in->master_id < UINT16_MAX);
334
335 rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
336 sizeof *pkt_v4_0 - sizeof pkt->hdr + hsize, in->flags);
337 rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id,
338 in->addr, in->attr,
339 in->size, in->width, in->stream_width);
340 return sizeof *pkt_v4_0 + ret_size;
341 }
342
343
344 pkt->master_id_31_16 = htobe16(in->master_id >> 16);
345 pkt->master_id_63_32 = htobe32(in->master_id >> 32);
346
347
348 pkt->data_offset = htobe32(sizeof *pkt);
349 pkt->next_offset = 0;
350
351 pkt->byte_enable_offset = htobe32(sizeof *pkt + hsize);
352 pkt->byte_enable_len = htobe32(in->byte_enable_len);
353 hsize += in->byte_enable_len;
354
355 rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
356 sizeof *pkt - sizeof pkt->hdr + hsize, in->flags);
357 rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id, in->addr,
358 in->attr | RP_BUS_ATTR_EXT_BASE,
359 in->size, in->width, in->stream_width);
360
361 return sizeof *pkt + ret_size;
362}
363
364size_t rp_encode_interrupt_f(uint32_t id, uint32_t dev,
365 struct rp_pkt_interrupt *pkt,
366 int64_t clk,
367 uint32_t line, uint64_t vector, uint8_t val,
368 uint32_t flags)
369{
370 rp_encode_hdr(&pkt->hdr, RP_CMD_interrupt, id, dev,
371 sizeof *pkt - sizeof pkt->hdr, flags);
372 pkt->timestamp = htobe64(clk);
373 pkt->vector = htobe64(vector);
374 pkt->line = htobe32(line);
375 pkt->val = val;
376 return sizeof *pkt;
377}
378
379size_t rp_encode_interrupt(uint32_t id, uint32_t dev,
380 struct rp_pkt_interrupt *pkt,
381 int64_t clk,
382 uint32_t line, uint64_t vector, uint8_t val)
383{
384 return rp_encode_interrupt_f(id, dev, pkt, clk, line, vector, val, 0);
385}
386
387static size_t rp_encode_sync_common(uint32_t id, uint32_t dev,
388 struct rp_pkt_sync *pkt,
389 int64_t clk, uint32_t flags)
390{
391 rp_encode_hdr(&pkt->hdr, RP_CMD_sync, id, dev,
392 sizeof *pkt - sizeof pkt->hdr, flags);
393 pkt->timestamp = htobe64(clk);
394 return sizeof *pkt;
395}
396
397size_t rp_encode_sync(uint32_t id, uint32_t dev,
398 struct rp_pkt_sync *pkt,
399 int64_t clk)
400{
401 return rp_encode_sync_common(id, dev, pkt, clk, 0);
402}
403
404size_t rp_encode_sync_resp(uint32_t id, uint32_t dev,
405 struct rp_pkt_sync *pkt,
406 int64_t clk)
407{
408 return rp_encode_sync_common(id, dev, pkt, clk, RP_PKT_FLAGS_response);
409}
410
411void rp_process_caps(struct rp_peer_state *peer,
412 void *caps, size_t caps_len)
413{
414 int i;
415
416 assert(peer->caps.busaccess_ext_base == false);
417
418 for (i = 0; i < caps_len; i++) {
419 uint32_t cap;
420
421 memcpy(&cap, caps + i * sizeof cap, sizeof cap);
422
423 switch (cap) {
424 case CAP_BUSACCESS_EXT_BASE:
425 peer->caps.busaccess_ext_base = true;
426 break;
427 case CAP_BUSACCESS_EXT_BYTE_EN:
428 peer->caps.busaccess_ext_byte_en = true;
429 break;
430 case CAP_WIRE_POSTED_UPDATES:
431 peer->caps.wire_posted_updates = true;
432 break;
433 }
434 }
435}
436
437
438void rp_dpkt_alloc(RemotePortDynPkt *dpkt, size_t size)
439{
440 if (dpkt->size < size) {
441 char *u8;
442 dpkt->pkt = realloc(dpkt->pkt, size);
443 u8 = (void *) dpkt->pkt;
444 memset(u8 + dpkt->size, 0, size - dpkt->size);
445 dpkt->size = size;
446 }
447}
448
449void rp_dpkt_swap(RemotePortDynPkt *a, RemotePortDynPkt *b)
450{
451 struct rp_pkt *tmp_pkt;
452 size_t tmp_size;
453
454 tmp_pkt = a->pkt;
455 tmp_size = a->size;
456 a->pkt = b->pkt;
457 a->size = b->size;
458 b->pkt = tmp_pkt;
459 b->size = tmp_size;
460}
461
462bool rp_dpkt_is_valid(RemotePortDynPkt *dpkt)
463{
464 return dpkt->size > 0 && dpkt->pkt->hdr.len;
465}
466
467void rp_dpkt_invalidate(RemotePortDynPkt *dpkt)
468{
469 assert(rp_dpkt_is_valid(dpkt));
470 dpkt->pkt->hdr.len = 0;
471}
472
473inline void rp_dpkt_free(RemotePortDynPkt *dpkt)
474{
475 dpkt->size = 0;
476 free(dpkt->pkt);
477}
478