uboot/drivers/xen/xenbus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * (C) 2006 - Cambridge University
   4 * (C) 2020 - EPAM Systems Inc.
   5 *
   6 * File: xenbus.c [1]
   7 * Author: Steven Smith (sos22@cam.ac.uk)
   8 * Changes: Grzegorz Milos (gm281@cam.ac.uk)
   9 * Changes: John D. Ramsdell
  10 *
  11 * Date: Jun 2006, changes Aug 2006
  12 *
  13 * Description: Minimal implementation of xenbus
  14 *
  15 * [1] - http://xenbits.xen.org/gitweb/?p=mini-os.git;a=summary
  16 */
  17
  18#include <common.h>
  19#include <log.h>
  20
  21#include <asm/armv8/mmu.h>
  22#include <asm/io.h>
  23#include <asm/xen/system.h>
  24
  25#include <linux/bug.h>
  26#include <linux/compat.h>
  27
  28#include <xen/events.h>
  29#include <xen/hvm.h>
  30#include <xen/xenbus.h>
  31
  32#include <xen/interface/io/xs_wire.h>
  33
  34#define map_frame_virt(v)       (v << PAGE_SHIFT)
  35
  36#define SCNd16                  "d"
  37
  38/* Wait for reply time out, ms */
  39#define WAIT_XENBUS_TO_MS       5000
  40/* Polling time out, ms */
  41#define WAIT_XENBUS_POLL_TO_MS  1
  42
  43static struct xenstore_domain_interface *xenstore_buf;
  44
  45static char *errmsg(struct xsd_sockmsg *rep);
  46
  47u32 xenbus_evtchn;
  48
  49struct write_req {
  50        const void *data;
  51        unsigned int len;
  52};
  53
  54static void memcpy_from_ring(const void *r, void *d, int off, int len)
  55{
  56        int c1, c2;
  57        const char *ring = r;
  58        char *dest = d;
  59
  60        c1 = min(len, XENSTORE_RING_SIZE - off);
  61        c2 = len - c1;
  62        memcpy(dest, ring + off, c1);
  63        memcpy(dest + c1, ring, c2);
  64}
  65
  66/**
  67 * xenbus_get_reply() - Receive reply from xenbus
  68 * @req_reply: reply message structure
  69 *
  70 * Wait for reply message event from the ring and copy received message
  71 * to input xsd_sockmsg structure. Repeat until full reply is
  72 * proceeded.
  73 *
  74 * Return: false - timeout
  75 *         true - reply is received
  76 */
  77static bool xenbus_get_reply(struct xsd_sockmsg **req_reply)
  78{
  79        struct xsd_sockmsg msg;
  80        unsigned int prod = xenstore_buf->rsp_prod;
  81
  82again:
  83        if (!wait_event_timeout(NULL, prod != xenstore_buf->rsp_prod,
  84                                WAIT_XENBUS_TO_MS)) {
  85                printk("%s: wait_event timeout\n", __func__);
  86                return false;
  87        }
  88
  89        prod = xenstore_buf->rsp_prod;
  90        if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg))
  91                goto again;
  92
  93        rmb();
  94        memcpy_from_ring(xenstore_buf->rsp, &msg,
  95                         MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
  96                         sizeof(msg));
  97
  98        if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg) + msg.len)
  99                goto again;
 100
 101        /* We do not support and expect any Xen bus wathes. */
 102        BUG_ON(msg.type == XS_WATCH_EVENT);
 103
 104        *req_reply = malloc(sizeof(msg) + msg.len);
 105        memcpy_from_ring(xenstore_buf->rsp, *req_reply,
 106                         MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
 107                         msg.len + sizeof(msg));
 108        mb();
 109        xenstore_buf->rsp_cons += msg.len + sizeof(msg);
 110
 111        wmb();
 112        notify_remote_via_evtchn(xenbus_evtchn);
 113        return true;
 114}
 115
 116char *xenbus_switch_state(xenbus_transaction_t xbt, const char *path,
 117                          XenbusState state)
 118{
 119        char *current_state;
 120        char *msg = NULL;
 121        char *msg2 = NULL;
 122        char value[2];
 123        XenbusState rs;
 124        int xbt_flag = 0;
 125        int retry = 0;
 126
 127        do {
 128                if (xbt == XBT_NIL) {
 129                        msg = xenbus_transaction_start(&xbt);
 130                        if (msg)
 131                                goto exit;
 132                        xbt_flag = 1;
 133                }
 134
 135                msg = xenbus_read(xbt, path, &current_state);
 136                if (msg)
 137                        goto exit;
 138
 139                rs = (XenbusState)(current_state[0] - '0');
 140                free(current_state);
 141                if (rs == state) {
 142                        msg = NULL;
 143                        goto exit;
 144                }
 145
 146                snprintf(value, 2, "%d", state);
 147                msg = xenbus_write(xbt, path, value);
 148
 149exit:
 150                if (xbt_flag) {
 151                        msg2 = xenbus_transaction_end(xbt, 0, &retry);
 152                        xbt = XBT_NIL;
 153                }
 154                if (msg == NULL && msg2 != NULL)
 155                        msg = msg2;
 156                else
 157                        free(msg2);
 158        } while (retry);
 159
 160        return msg;
 161}
 162
 163char *xenbus_wait_for_state_change(const char *path, XenbusState *state)
 164{
 165        for (;;) {
 166                char *res, *msg;
 167                XenbusState rs;
 168
 169                msg = xenbus_read(XBT_NIL, path, &res);
 170                if (msg)
 171                        return msg;
 172
 173                rs = (XenbusState)(res[0] - 48);
 174                free(res);
 175
 176                if (rs == *state) {
 177                        wait_event_timeout(NULL, false, WAIT_XENBUS_POLL_TO_MS);
 178                } else {
 179                        *state = rs;
 180                        break;
 181                }
 182        }
 183        return NULL;
 184}
 185
 186/* Send data to xenbus.  This can block.  All of the requests are seen
 187 * by xenbus as if sent atomically.  The header is added
 188 * automatically, using type %type, req_id %req_id, and trans_id
 189 * %trans_id.
 190 */
 191static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
 192                     const struct write_req *req, int nr_reqs)
 193{
 194        XENSTORE_RING_IDX prod;
 195        int r;
 196        int len = 0;
 197        const struct write_req *cur_req;
 198        int req_off;
 199        int total_off;
 200        int this_chunk;
 201        struct xsd_sockmsg m = {
 202                .type = type,
 203                .req_id = req_id,
 204                .tx_id = trans_id
 205        };
 206        struct write_req header_req = {
 207                &m,
 208                sizeof(m)
 209        };
 210
 211        for (r = 0; r < nr_reqs; r++)
 212                len += req[r].len;
 213        m.len = len;
 214        len += sizeof(m);
 215
 216        cur_req = &header_req;
 217
 218        BUG_ON(len > XENSTORE_RING_SIZE);
 219        prod = xenstore_buf->req_prod;
 220        /* We are running synchronously, so it is a bug if we do not
 221         * have enough room to send a message: please note that a message
 222         * can occupy multiple slots in the ring buffer.
 223         */
 224        BUG_ON(prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE);
 225
 226        total_off = 0;
 227        req_off = 0;
 228        while (total_off < len) {
 229                this_chunk = min(cur_req->len - req_off,
 230                                 XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
 231                memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod),
 232                       (char *)cur_req->data + req_off, this_chunk);
 233                prod += this_chunk;
 234                req_off += this_chunk;
 235                total_off += this_chunk;
 236                if (req_off == cur_req->len) {
 237                        req_off = 0;
 238                        if (cur_req == &header_req)
 239                                cur_req = req;
 240                        else
 241                                cur_req++;
 242                }
 243        }
 244
 245        BUG_ON(req_off != 0);
 246        BUG_ON(total_off != len);
 247        BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE);
 248
 249        /* Remote must see entire message before updating indexes */
 250        wmb();
 251
 252        xenstore_buf->req_prod += len;
 253
 254        /* Send evtchn to notify remote */
 255        notify_remote_via_evtchn(xenbus_evtchn);
 256}
 257
 258/* Send a message to xenbus, in the same fashion as xb_write, and
 259 * block waiting for a reply.  The reply is malloced and should be
 260 * freed by the caller.
 261 */
 262struct xsd_sockmsg *xenbus_msg_reply(int type,
 263                                     xenbus_transaction_t trans,
 264                                     struct write_req *io,
 265                                     int nr_reqs)
 266{
 267        struct xsd_sockmsg *rep;
 268
 269        /* We do not use request identifier which is echoed in daemon's response. */
 270        xb_write(type, 0, trans, io, nr_reqs);
 271        /* Now wait for the message to arrive. */
 272        if (!xenbus_get_reply(&rep))
 273                return NULL;
 274        return rep;
 275}
 276
 277static char *errmsg(struct xsd_sockmsg *rep)
 278{
 279        char *res;
 280
 281        if (!rep) {
 282                char msg[] = "No reply";
 283                size_t len = strlen(msg) + 1;
 284
 285                return memcpy(malloc(len), msg, len);
 286        }
 287        if (rep->type != XS_ERROR)
 288                return NULL;
 289        res = malloc(rep->len + 1);
 290        memcpy(res, rep + 1, rep->len);
 291        res[rep->len] = 0;
 292        free(rep);
 293        return res;
 294}
 295
 296/* List the contents of a directory.  Returns a malloc()ed array of
 297 * pointers to malloc()ed strings.  The array is NULL terminated.  May
 298 * block.
 299 */
 300char *xenbus_ls(xenbus_transaction_t xbt, const char *pre, char ***contents)
 301{
 302        struct xsd_sockmsg *reply, *repmsg;
 303        struct write_req req[] = { { pre, strlen(pre) + 1 } };
 304        int nr_elems, x, i;
 305        char **res, *msg;
 306
 307        repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
 308        msg = errmsg(repmsg);
 309        if (msg) {
 310                *contents = NULL;
 311                return msg;
 312        }
 313        reply = repmsg + 1;
 314        for (x = nr_elems = 0; x < repmsg->len; x++)
 315                nr_elems += (((char *)reply)[x] == 0);
 316        res = malloc(sizeof(res[0]) * (nr_elems + 1));
 317        for (x = i = 0; i < nr_elems; i++) {
 318                int l = strlen((char *)reply + x);
 319
 320                res[i] = malloc(l + 1);
 321                memcpy(res[i], (char *)reply + x, l + 1);
 322                x += l + 1;
 323        }
 324        res[i] = NULL;
 325        free(repmsg);
 326        *contents = res;
 327        return NULL;
 328}
 329
 330char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value)
 331{
 332        struct write_req req[] = { {path, strlen(path) + 1} };
 333        struct xsd_sockmsg *rep;
 334        char *res, *msg;
 335
 336        rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req));
 337        msg = errmsg(rep);
 338        if (msg) {
 339                *value = NULL;
 340                return msg;
 341        }
 342        res = malloc(rep->len + 1);
 343        memcpy(res, rep + 1, rep->len);
 344        res[rep->len] = 0;
 345        free(rep);
 346        *value = res;
 347        return NULL;
 348}
 349
 350char *xenbus_write(xenbus_transaction_t xbt, const char *path,
 351                                   const char *value)
 352{
 353        struct write_req req[] = {
 354                {path, strlen(path) + 1},
 355                {value, strlen(value)},
 356        };
 357        struct xsd_sockmsg *rep;
 358        char *msg;
 359
 360        rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req));
 361        msg = errmsg(rep);
 362        if (msg)
 363                return msg;
 364        free(rep);
 365        return NULL;
 366}
 367
 368char *xenbus_rm(xenbus_transaction_t xbt, const char *path)
 369{
 370        struct write_req req[] = { {path, strlen(path) + 1} };
 371        struct xsd_sockmsg *rep;
 372        char *msg;
 373
 374        rep = xenbus_msg_reply(XS_RM, xbt, req, ARRAY_SIZE(req));
 375        msg = errmsg(rep);
 376        if (msg)
 377                return msg;
 378        free(rep);
 379        return NULL;
 380}
 381
 382char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char **value)
 383{
 384        struct write_req req[] = { {path, strlen(path) + 1} };
 385        struct xsd_sockmsg *rep;
 386        char *res, *msg;
 387
 388        rep = xenbus_msg_reply(XS_GET_PERMS, xbt, req, ARRAY_SIZE(req));
 389        msg = errmsg(rep);
 390        if (msg) {
 391                *value = NULL;
 392                return msg;
 393        }
 394        res = malloc(rep->len + 1);
 395        memcpy(res, rep + 1, rep->len);
 396        res[rep->len] = 0;
 397        free(rep);
 398        *value = res;
 399        return NULL;
 400}
 401
 402#define PERM_MAX_SIZE 32
 403char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path,
 404                       domid_t dom, char perm)
 405{
 406        char value[PERM_MAX_SIZE];
 407        struct write_req req[] = {
 408                {path, strlen(path) + 1},
 409                {value, 0},
 410        };
 411        struct xsd_sockmsg *rep;
 412        char *msg;
 413
 414        snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
 415        req[1].len = strlen(value) + 1;
 416        rep = xenbus_msg_reply(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
 417        msg = errmsg(rep);
 418        if (msg)
 419                return msg;
 420        free(rep);
 421        return NULL;
 422}
 423
 424char *xenbus_transaction_start(xenbus_transaction_t *xbt)
 425{
 426        /* Xenstored becomes angry if you send a length 0 message, so just
 427         * shove a nul terminator on the end
 428         */
 429        struct write_req req = { "", 1};
 430        struct xsd_sockmsg *rep;
 431        char *err;
 432
 433        rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
 434        err = errmsg(rep);
 435        if (err)
 436                return err;
 437        sscanf((char *)(rep + 1), "%lu", xbt);
 438        free(rep);
 439        return NULL;
 440}
 441
 442char *xenbus_transaction_end(xenbus_transaction_t t, int abort, int *retry)
 443{
 444        struct xsd_sockmsg *rep;
 445        struct write_req req;
 446        char *err;
 447
 448        *retry = 0;
 449
 450        req.data = abort ? "F" : "T";
 451        req.len = 2;
 452        rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1);
 453        err = errmsg(rep);
 454        if (err) {
 455                if (!strcmp(err, "EAGAIN")) {
 456                        *retry = 1;
 457                        free(err);
 458                        return NULL;
 459                } else {
 460                        return err;
 461                }
 462        }
 463        free(rep);
 464        return NULL;
 465}
 466
 467int xenbus_read_integer(const char *path)
 468{
 469        char *res, *buf;
 470        int t;
 471
 472        res = xenbus_read(XBT_NIL, path, &buf);
 473        if (res) {
 474                printk("Failed to read %s.\n", path);
 475                free(res);
 476                return -1;
 477        }
 478        sscanf(buf, "%d", &t);
 479        free(buf);
 480        return t;
 481}
 482
 483int xenbus_read_uuid(const char *path, unsigned char uuid[16])
 484{
 485        char *res, *buf;
 486
 487        res = xenbus_read(XBT_NIL, path, &buf);
 488        if (res) {
 489                printk("Failed to read %s.\n", path);
 490                free(res);
 491                return 0;
 492        }
 493        if (strlen(buf) != ((2 * 16) + 4) /* 16 hex bytes and 4 hyphens */
 494            || sscanf(buf,
 495                      "%2hhx%2hhx%2hhx%2hhx-"
 496                      "%2hhx%2hhx-"
 497                      "%2hhx%2hhx-"
 498                      "%2hhx%2hhx-"
 499                      "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
 500                      uuid, uuid + 1, uuid + 2, uuid + 3,
 501                      uuid + 4, uuid + 5, uuid + 6, uuid + 7,
 502                      uuid + 8, uuid + 9, uuid + 10, uuid + 11,
 503                      uuid + 12, uuid + 13, uuid + 14, uuid + 15) != 16) {
 504                printk("Xenbus path %s value %s is not a uuid!\n", path, buf);
 505                free(buf);
 506                return 0;
 507        }
 508        free(buf);
 509        return 1;
 510}
 511
 512char *xenbus_printf(xenbus_transaction_t xbt,
 513                    const char *node, const char *path,
 514                    const char *fmt, ...)
 515{
 516#define BUFFER_SIZE 256
 517        char fullpath[BUFFER_SIZE];
 518        char val[BUFFER_SIZE];
 519        va_list args;
 520
 521        BUG_ON(strlen(node) + strlen(path) + 1 >= BUFFER_SIZE);
 522        sprintf(fullpath, "%s/%s", node, path);
 523        va_start(args, fmt);
 524        vsprintf(val, fmt, args);
 525        va_end(args);
 526        return xenbus_write(xbt, fullpath, val);
 527}
 528
 529domid_t xenbus_get_self_id(void)
 530{
 531        char *dom_id;
 532        domid_t ret;
 533
 534        BUG_ON(xenbus_read(XBT_NIL, "domid", &dom_id));
 535        sscanf(dom_id, "%"SCNd16, &ret);
 536
 537        return ret;
 538}
 539
 540void init_xenbus(void)
 541{
 542        u64 v;
 543
 544        debug("%s\n", __func__);
 545        if (hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v))
 546                BUG();
 547        xenbus_evtchn = v;
 548
 549        if (hvm_get_parameter(HVM_PARAM_STORE_PFN, &v))
 550                BUG();
 551        xenstore_buf = (struct xenstore_domain_interface *)map_frame_virt(v);
 552}
 553
 554void fini_xenbus(void)
 555{
 556        debug("%s\n", __func__);
 557}
 558