On 7/1/20 6:29 PM, Anastasiia Lukianenko wrote: > From: Oleksandr Andrushchenko <oleksandr_andrushche...@epam.com> > > Make required updates to run on u-boot and strip test code. > > Signed-off-by: Anastasiia Lukianenko <anastasiia_lukiane...@epam.com> > Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushche...@epam.com> > --- > arch/arm/Kconfig | 1 + > board/xen/xenguest_arm64/xenguest_arm64.c | 16 +- > drivers/xen/Makefile | 1 + > drivers/xen/hypervisor.c | 2 + > drivers/xen/xenbus.c | 547 ++++++++++++++++++++++ > include/xen/xenbus.h | 86 ++++ > 6 files changed, 652 insertions(+), 1 deletion(-) > create mode 100644 drivers/xen/xenbus.c > create mode 100644 include/xen/xenbus.h > > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig > index d4de1139aa..bcd9ab5c9d 100644 > --- a/arch/arm/Kconfig > +++ b/arch/arm/Kconfig > @@ -1724,6 +1724,7 @@ config TARGET_XENGUEST_ARM64 > select OF_CONTROL > select LINUX_KERNEL_IMAGE_HEADER > select XEN_SERIAL > + select SSCANF > endchoice > > config ARCH_SUPPORT_TFABOOT > diff --git a/board/xen/xenguest_arm64/xenguest_arm64.c > b/board/xen/xenguest_arm64/xenguest_arm64.c > index fd10a002e9..e8621f7174 100644 > --- a/board/xen/xenguest_arm64/xenguest_arm64.c > +++ b/board/xen/xenguest_arm64/xenguest_arm64.c > @@ -67,7 +67,7 @@ static int setup_mem_map(void) > > /* > * Add "magic" region which is used by Xen to provide some essentials > - * for the guest: we need console. > + * for the guest: we need console and xenstore. > */ > ret = hvm_get_parameter_maintain_dcache(HVM_PARAM_CONSOLE_PFN, &gfn); > if (ret < 0) { > @@ -83,6 +83,20 @@ static int setup_mem_map(void) > PTE_BLOCK_INNER_SHARE); > i++; > > + ret = hvm_get_parameter_maintain_dcache(HVM_PARAM_STORE_PFN, &gfn); > + if (ret < 0) { > + printf("%s: Can't get HVM_PARAM_STORE_PFN, ret %d\n", > + __func__, ret); > + return -EINVAL; > + } > + > + xen_mem_map[i].virt = PFN_PHYS(gfn); > + xen_mem_map[i].phys = PFN_PHYS(gfn); > + xen_mem_map[i].size = PAGE_SIZE; > + xen_mem_map[i].attrs = (PTE_BLOCK_MEMTYPE(MT_NORMAL) | > + PTE_BLOCK_INNER_SHARE); > + i++; > + > mem = get_next_memory_node(blob, -1); > if (mem < 0) { > printf("%s: Missing /memory node\n", __func__); > diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile > index 0ad35edefb..9d0f604aaa 100644 > --- a/drivers/xen/Makefile > +++ b/drivers/xen/Makefile > @@ -4,3 +4,4 @@ > > obj-y += hypervisor.o > obj-y += events.o > +obj-y += xenbus.o > diff --git a/drivers/xen/hypervisor.c b/drivers/xen/hypervisor.c > index 975e552242..d7fbacb08e 100644 > --- a/drivers/xen/hypervisor.c > +++ b/drivers/xen/hypervisor.c > @@ -38,6 +38,7 @@ > > #include <xen/hvm.h> > #include <xen/events.h> > +#include <xen/xenbus.h> > #include <xen/interface/memory.h> > > #define active_evtchns(cpu, sh, idx) \ > @@ -273,5 +274,6 @@ void xen_init(void) > > map_shared_info(NULL); > init_events(); > + init_xenbus(); > } > > diff --git a/drivers/xen/xenbus.c b/drivers/xen/xenbus.c > new file mode 100644 > index 0000000000..64eb28e843 > --- /dev/null > +++ b/drivers/xen/xenbus.c > @@ -0,0 +1,547 @@ > +/*
Add an SPDX header, please. > + **************************************************************************** > + * (C) 2006 - Cambridge University > + * (C) 2020 - EPAM Systems Inc. > + **************************************************************************** > + * > + * File: xenbus.c > + * Author: Steven Smith (so...@cam.ac.uk) > + * Changes: Grzegorz Milos (gm...@cam.ac.uk) > + * Changes: John D. Ramsdell > + * > + * Date: Jun 2006, chages Aug 2005 %s/chages/changes/ ? Does time run in reverse in Cambridge? > + * > + * Environment: Xen Minimal OS This is U-Boot. Better provide a link to the original source. > + * Description: Minimal implementation of xenbus > + * > + **************************************************************************** Can we get rid of this not U-Boot style formatting? > + **/ > + > +#include <common.h> > +#include <log.h> > + > +#include <asm/armv8/mmu.h> > +#include <asm/io.h> > +#include <asm/xen/system.h> > + > +#include <linux/bug.h> > +#include <linux/compat.h> > + > +#include <xen/events.h> > +#include <xen/hvm.h> > +#include <xen/xenbus.h> > + > +#include <xen/interface/io/xs_wire.h> > + > +#define map_frame_virt(v) (v << PAGE_SHIFT) > + > +#define SCNd16 "d" > + > +/* Wait for reply time out, ms */ > +#define WAIT_XENBUS_TO_MS 5000 > +/* Polling time out, ms */ > +#define WAIT_XENBUS_POLL_TO_MS 1 > + > +static struct xenstore_domain_interface *xenstore_buf; > + > +static char *errmsg(struct xsd_sockmsg *rep); > + > +u32 xenbus_evtchn; > + > +struct write_req { > + const void *data; > + unsigned int len; > +}; > + > +static void memcpy_from_ring(const void *r, void *d, int off, int len) > +{ > + int c1, c2; > + const char *ring = r; > + char *dest = d; > + > + c1 = min(len, XENSTORE_RING_SIZE - off); > + c2 = len - c1; > + memcpy(dest, ring + off, c1); > + memcpy(dest + c1, ring, c2); > +} > + > +static bool xenbus_get_reply(struct xsd_sockmsg **req_reply) > +{ > + struct xsd_sockmsg msg; > + unsigned int prod = xenstore_buf->rsp_prod; > + > +again: > + if (!wait_event_timeout(NULL, prod != xenstore_buf->rsp_prod, > + WAIT_XENBUS_TO_MS)) { > + printk("%s: wait_event timeout\n", __func__); > + return false; > + } > + > + prod = xenstore_buf->rsp_prod; > + if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg)) > + goto again; > + > + rmb(); > + memcpy_from_ring(xenstore_buf->rsp, &msg, > + MASK_XENSTORE_IDX(xenstore_buf->rsp_cons), > + sizeof(msg)); > + > + if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg) + > msg.len) > + goto again; > + > + /* We do not support and expect any Xen bus wathes. */ > + BUG_ON(msg.type == XS_WATCH_EVENT); > + > + *req_reply = malloc(sizeof(msg) + msg.len); > + memcpy_from_ring(xenstore_buf->rsp, *req_reply, > + MASK_XENSTORE_IDX(xenstore_buf->rsp_cons), > + msg.len + sizeof(msg)); > + mb(); > + xenstore_buf->rsp_cons += msg.len + sizeof(msg); > + > + wmb(); > + notify_remote_via_evtchn(xenbus_evtchn); > + return true; > +} > + Document functions, please. https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html#function-documentation Best regards Heinrich > +char *xenbus_switch_state(xenbus_transaction_t xbt, const char *path, > + XenbusState state) > +{ > + char *current_state; > + char *msg = NULL; > + char *msg2 = NULL; > + char value[2]; > + XenbusState rs; > + int xbt_flag = 0; > + int retry = 0; > + > + do { > + if (xbt == XBT_NIL) { > + msg = xenbus_transaction_start(&xbt); > + if (msg) > + goto exit; > + xbt_flag = 1; > + } > + > + msg = xenbus_read(xbt, path, ¤t_state); > + if (msg) > + goto exit; > + > + rs = (XenbusState)(current_state[0] - '0'); > + free(current_state); > + if (rs == state) { > + msg = NULL; > + goto exit; > + } > + > + snprintf(value, 2, "%d", state); > + msg = xenbus_write(xbt, path, value); > + > +exit: > + if (xbt_flag) { > + msg2 = xenbus_transaction_end(xbt, 0, &retry); > + xbt = XBT_NIL; > + } > + if (msg == NULL && msg2 != NULL) > + msg = msg2; > + else > + free(msg2); > + } while (retry); > + > + return msg; > +} > + > +char *xenbus_wait_for_state_change(const char *path, XenbusState *state) > +{ > + for (;;) { > + char *res, *msg; > + XenbusState rs; > + > + msg = xenbus_read(XBT_NIL, path, &res); > + if (msg) > + return msg; > + > + rs = (XenbusState)(res[0] - 48); > + free(res); > + > + if (rs == *state) { > + wait_event_timeout(NULL, false, WAIT_XENBUS_POLL_TO_MS); > + } else { > + *state = rs; > + break; > + } > + } > + return NULL; > +} > + > +/* Send data to xenbus. This can block. All of the requests are seen > + * by xenbus as if sent atomically. The header is added > + * automatically, using type %type, req_id %req_id, and trans_id > + * %trans_id. > + */ > +static void xb_write(int type, int req_id, xenbus_transaction_t trans_id, > + const struct write_req *req, int nr_reqs) > +{ > + XENSTORE_RING_IDX prod; > + int r; > + int len = 0; > + const struct write_req *cur_req; > + int req_off; > + int total_off; > + int this_chunk; > + struct xsd_sockmsg m = { > + .type = type, > + .req_id = req_id, > + .tx_id = trans_id > + }; > + struct write_req header_req = { > + &m, > + sizeof(m) > + }; > + > + for (r = 0; r < nr_reqs; r++) > + len += req[r].len; > + m.len = len; > + len += sizeof(m); > + > + cur_req = &header_req; > + > + BUG_ON(len > XENSTORE_RING_SIZE); > + prod = xenstore_buf->req_prod; > + /* We are running synchronously, so it is a bug if we do not > + * have enough room to send a message: please note that a message > + * can occupy multiple slots in the ring buffer. > + */ > + BUG_ON(prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE); > + > + total_off = 0; > + req_off = 0; > + while (total_off < len) { > + this_chunk = min(cur_req->len - req_off, > + XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod)); > + memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod), > + (char *)cur_req->data + req_off, this_chunk); > + prod += this_chunk; > + req_off += this_chunk; > + total_off += this_chunk; > + if (req_off == cur_req->len) { > + req_off = 0; > + if (cur_req == &header_req) > + cur_req = req; > + else > + cur_req++; > + } > + } > + > + BUG_ON(req_off != 0); > + BUG_ON(total_off != len); > + BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE); > + > + /* Remote must see entire message before updating indexes */ > + wmb(); > + > + xenstore_buf->req_prod += len; > + > + /* Send evtchn to notify remote */ > + notify_remote_via_evtchn(xenbus_evtchn); > +} > + > +/* Send a message to xenbus, in the same fashion as xb_write, and > + * block waiting for a reply. The reply is malloced and should be > + * freed by the caller. > + */ > +struct xsd_sockmsg *xenbus_msg_reply(int type, > + xenbus_transaction_t trans, > + struct write_req *io, > + int nr_reqs) > +{ > + struct xsd_sockmsg *rep; > + > + /* We do not use request identifier which is echoed in daemon's > response. */ > + xb_write(type, 0, trans, io, nr_reqs); > + /* Now wait for the message to arrive. */ > + if (!xenbus_get_reply(&rep)) > + return NULL; > + return rep; > +} > + > +static char *errmsg(struct xsd_sockmsg *rep) > +{ > + char *res; > + > + if (!rep) { > + char msg[] = "No reply"; > + size_t len = strlen(msg) + 1; > + > + return memcpy(malloc(len), msg, len); > + } > + if (rep->type != XS_ERROR) > + return NULL; > + res = malloc(rep->len + 1); > + memcpy(res, rep + 1, rep->len); > + res[rep->len] = 0; > + free(rep); > + return res; > +} > + > +/* List the contents of a directory. Returns a malloc()ed array of > + * pointers to malloc()ed strings. The array is NULL terminated. May > + * block. > + */ > +char *xenbus_ls(xenbus_transaction_t xbt, const char *pre, char ***contents) > +{ > + struct xsd_sockmsg *reply, *repmsg; > + struct write_req req[] = { { pre, strlen(pre) + 1 } }; > + int nr_elems, x, i; > + char **res, *msg; > + > + repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req)); > + msg = errmsg(repmsg); > + if (msg) { > + *contents = NULL; > + return msg; > + } > + reply = repmsg + 1; > + for (x = nr_elems = 0; x < repmsg->len; x++) > + nr_elems += (((char *)reply)[x] == 0); > + res = malloc(sizeof(res[0]) * (nr_elems + 1)); > + for (x = i = 0; i < nr_elems; i++) { > + int l = strlen((char *)reply + x); > + > + res[i] = malloc(l + 1); > + memcpy(res[i], (char *)reply + x, l + 1); > + x += l + 1; > + } > + res[i] = NULL; > + free(repmsg); > + *contents = res; > + return NULL; > +} > + > +char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value) > +{ > + struct write_req req[] = { {path, strlen(path) + 1} }; > + struct xsd_sockmsg *rep; > + char *res, *msg; > + > + rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req)); > + msg = errmsg(rep); > + if (msg) { > + *value = NULL; > + return msg; > + } > + res = malloc(rep->len + 1); > + memcpy(res, rep + 1, rep->len); > + res[rep->len] = 0; > + free(rep); > + *value = res; > + return NULL; > +} > + > +char *xenbus_write(xenbus_transaction_t xbt, const char *path, > + const char *value) > +{ > + struct write_req req[] = { > + {path, strlen(path) + 1}, > + {value, strlen(value)}, > + }; > + struct xsd_sockmsg *rep; > + char *msg; > + > + rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req)); > + msg = errmsg(rep); > + if (msg) > + return msg; > + free(rep); > + return NULL; > +} > + > +char *xenbus_rm(xenbus_transaction_t xbt, const char *path) > +{ > + struct write_req req[] = { {path, strlen(path) + 1} }; > + struct xsd_sockmsg *rep; > + char *msg; > + > + rep = xenbus_msg_reply(XS_RM, xbt, req, ARRAY_SIZE(req)); > + msg = errmsg(rep); > + if (msg) > + return msg; > + free(rep); > + return NULL; > +} > + > +char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char > **value) > +{ > + struct write_req req[] = { {path, strlen(path) + 1} }; > + struct xsd_sockmsg *rep; > + char *res, *msg; > + > + rep = xenbus_msg_reply(XS_GET_PERMS, xbt, req, ARRAY_SIZE(req)); > + msg = errmsg(rep); > + if (msg) { > + *value = NULL; > + return msg; > + } > + res = malloc(rep->len + 1); > + memcpy(res, rep + 1, rep->len); > + res[rep->len] = 0; > + free(rep); > + *value = res; > + return NULL; > +} > + > +#define PERM_MAX_SIZE 32 > +char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, > + domid_t dom, char perm) > +{ > + char value[PERM_MAX_SIZE]; > + struct write_req req[] = { > + {path, strlen(path) + 1}, > + {value, 0}, > + }; > + struct xsd_sockmsg *rep; > + char *msg; > + > + snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom); > + req[1].len = strlen(value) + 1; > + rep = xenbus_msg_reply(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req)); > + msg = errmsg(rep); > + if (msg) > + return msg; > + free(rep); > + return NULL; > +} > + > +char *xenbus_transaction_start(xenbus_transaction_t *xbt) > +{ > + /* Xenstored becomes angry if you send a length 0 message, so just > + * shove a nul terminator on the end > + */ > + struct write_req req = { "", 1}; > + struct xsd_sockmsg *rep; > + char *err; > + > + rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1); > + err = errmsg(rep); > + if (err) > + return err; > + sscanf((char *)(rep + 1), "%lu", xbt); > + free(rep); > + return NULL; > +} > + > +char *xenbus_transaction_end(xenbus_transaction_t t, int abort, int *retry) > +{ > + struct xsd_sockmsg *rep; > + struct write_req req; > + char *err; > + > + *retry = 0; > + > + req.data = abort ? "F" : "T"; > + req.len = 2; > + rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1); > + err = errmsg(rep); > + if (err) { > + if (!strcmp(err, "EAGAIN")) { > + *retry = 1; > + free(err); > + return NULL; > + } else { > + return err; > + } > + } > + free(rep); > + return NULL; > +} > + > +int xenbus_read_integer(const char *path) > +{ > + char *res, *buf; > + int t; > + > + res = xenbus_read(XBT_NIL, path, &buf); > + if (res) { > + printk("Failed to read %s.\n", path); > + free(res); > + return -1; > + } > + sscanf(buf, "%d", &t); > + free(buf); > + return t; > +} > + > +int xenbus_read_uuid(const char *path, unsigned char uuid[16]) { > + char *res, *buf; > + > + res = xenbus_read(XBT_NIL, path, &buf); > + if (res) { > + printk("Failed to read %s.\n", path); > + free(res); > + return 0; > + } > + if (strlen(buf) != ((2 * 16) + 4) /* 16 hex bytes and 4 hyphens */ > + || sscanf(buf, > + "%2hhx%2hhx%2hhx%2hhx-" > + "%2hhx%2hhx-" > + "%2hhx%2hhx-" > + "%2hhx%2hhx-" > + "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", > + uuid, uuid + 1, uuid + 2, uuid + 3, > + uuid + 4, uuid + 5, uuid + 6, uuid + 7, > + uuid + 8, uuid + 9, uuid + 10, uuid + 11, > + uuid + 12, uuid + 13, uuid + 14, uuid + 15) != 16) { > + printk("Xenbus path %s value %s is not a uuid!\n", path, buf); > + free(buf); > + return 0; > + } > + free(buf); > + return 1; > +} > + > +char *xenbus_printf(xenbus_transaction_t xbt, > + const char *node, const char *path, > + const char *fmt, ...) > +{ > +#define BUFFER_SIZE 256 > + char fullpath[BUFFER_SIZE]; > + char val[BUFFER_SIZE]; > + va_list args; > + > + BUG_ON(strlen(node) + strlen(path) + 1 >= BUFFER_SIZE); > + sprintf(fullpath, "%s/%s", node, path); > + va_start(args, fmt); > + vsprintf(val, fmt, args); > + va_end(args); > + return xenbus_write(xbt, fullpath, val); > +} > + > +domid_t xenbus_get_self_id(void) > +{ > + char *dom_id; > + domid_t ret; > + > + BUG_ON(xenbus_read(XBT_NIL, "domid", &dom_id)); > + sscanf(dom_id, "%"SCNd16, &ret); > + > + return ret; > +} > + > +void init_xenbus(void) > +{ > + u64 v; > + > + debug("%s\n", __func__); > + if (hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v)) > + BUG(); > + xenbus_evtchn = v; > + > + if (hvm_get_parameter(HVM_PARAM_STORE_PFN, &v)) > + BUG(); > + xenstore_buf = (struct xenstore_domain_interface *)map_frame_virt(v); > +} > + > +void fini_xenbus(void) > +{ > + debug("%s\n", __func__); > +} > diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h > new file mode 100644 > index 0000000000..e2e3ef9292 > --- /dev/null > +++ b/include/xen/xenbus.h > @@ -0,0 +1,86 @@ > +#ifndef XENBUS_H__ > +#define XENBUS_H__ > + > +#include <xen/interface/xen.h> > +#include <xen/interface/io/xenbus.h> > + > +typedef unsigned long xenbus_transaction_t; > +#define XBT_NIL ((xenbus_transaction_t)0) > + > +extern u32 xenbus_evtchn; > + > +/* Initialize the XenBus system. */ > +void init_xenbus(void); > +/* Finalize the XenBus system. */ > +void fini_xenbus(void); > + > +/* Read the value associated with a path. Returns a malloc'd error > + * string on failure and sets *value to NULL. On success, *value is > + * set to a malloc'd copy of the value. > + */ > +char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value); > + > +char *xenbus_wait_for_state_change(const char *path, XenbusState *state); > +char *xenbus_switch_state(xenbus_transaction_t xbt, const char *path, > + XenbusState state); > + > +/* Associates a value with a path. Returns a malloc'd error string on > + * failure. > + */ > +char *xenbus_write(xenbus_transaction_t xbt, const char *path, > + const char *value); > + > +/* Removes the value associated with a path. Returns a malloc'd error > + * string on failure. > + */ > +char *xenbus_rm(xenbus_transaction_t xbt, const char *path); > + > +/* List the contents of a directory. Returns a malloc'd error string > + * on failure and sets *contents to NULL. On success, *contents is > + * set to a malloc'd array of pointers to malloc'd strings. The array > + * is NULL terminated. May block. > + */ > +char *xenbus_ls(xenbus_transaction_t xbt, const char *prefix, char > ***contents); > + > +/* Reads permissions associated with a path. Returns a malloc'd error > + * string on failure and sets *value to NULL. On success, *value is > + * set to a malloc'd copy of the value. > + */ > +char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char > **value); > + > +/* Sets the permissions associated with a path. Returns a malloc'd > + * error string on failure. > + */ > +char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, domid_t > dom, > + char perm); > + > +/* Start a xenbus transaction. Returns the transaction in xbt on > + * success or a malloc'd error string otherwise. > + */ > +char *xenbus_transaction_start(xenbus_transaction_t *xbt); > + > +/* End a xenbus transaction. Returns a malloc'd error string if it > + * fails. abort says whether the transaction should be aborted. > + * Returns 1 in *retry iff the transaction should be retried. > + */ > +char *xenbus_transaction_end(xenbus_transaction_t, int abort, > + int *retry); > + > +/* Read path and parse it as an integer. Returns -1 on error. */ > +int xenbus_read_integer(const char *path); > + > +/* Read path and parse it as 16 byte uuid. Returns 1 if > + * read and parsing were successful, 0 if not > + */ > +int xenbus_read_uuid(const char *path, unsigned char uuid[16]); > + > +/* Contraction of snprintf and xenbus_write(path/node). */ > +char *xenbus_printf(xenbus_transaction_t xbt, > + const char *node, const char *path, > + const char *fmt, ...) > + __attribute__((__format__(printf, 4, 5))); > + > +/* Utility function to figure out our domain id */ > +domid_t xenbus_get_self_id(void); > + > +#endif /* XENBUS_H__ */ >