qemu/hw/core/remote-port-proto.c
<<
>>
Prefs
   1/*
   2 * Remote-port protocol
   3 *
   4 * Copyright (c) 2013 Xilinx Inc
   5 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  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/* We assume little endian.  */
  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/* We assume little endian. */
  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/* Fallback for ancient Linux systems.  */
  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    /* Master_id has an odd decoding due to historical reasons.  */
 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                /* We don't know if offset is 32bit aligned so use
 147                 * memcpy to do the endian conversion.  */
 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        /* Consume everything ignoring additional headers we do not yet
 159         * know about.  */
 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    /* Feature list is appeneded right after the hello packet.  */
 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/* New API for extended header.  */
 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    /* Allocate packet space.  */
 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    /* If peer does not support the busaccess base extensions, use the
 328     * old layout. For responses, what matters is if we're responding
 329     * to a packet with the extensions.
 330     */
 331    if (!peer->caps.busaccess_ext_base && !(in->attr & RP_BUS_ATTR_EXT_BASE)) {
 332        /* Old layout.  */
 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    /* Encode the extended fields.  */
 344    pkt->master_id_31_16 = htobe16(in->master_id >> 16);
 345    pkt->master_id_63_32 = htobe32(in->master_id >> 32);
 346
 347    /* We always put data right after the header.  */
 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