diff --git a/.gitignore b/.gitignore index c056247fdf..74747cb7e7 100644 --- a/.gitignore +++ b/.gitignore @@ -285,8 +285,7 @@ xen/arch/*/efi/boot.c xen/arch/*/efi/compat.c xen/arch/*/efi/efi.h xen/arch/*/efi/runtime.c -xen/include/headers.chk -xen/include/headers++.chk +xen/include/headers*.chk xen/include/asm xen/include/asm-*/asm-offsets.h xen/include/asm-x86/cpuid-autogen.h diff --git a/docs/misc/tmem-internals.html b/docs/misc/tmem-internals.html index 2d8635d64d..9b7e70e650 100644 --- a/docs/misc/tmem-internals.html +++ b/docs/misc/tmem-internals.html @@ -715,11 +715,9 @@ Ocfs2 has only very limited security; it is assumed that anyone who can access the filesystem bits on the shared disk can mount the filesystem and use it. But in a virtualized data center, higher isolation requirements may apply. -As a result, a Xen boot option -- "tmem_shared_auth" -- was -added. The option defaults to disabled, -but when it is enabled, management tools must explicitly authenticate (or may +As a result, management tools must explicitly authenticate (or may explicitly deny) shared pool access to any client. -On Xen, this is done with the "xm +On Xen, this is done with the "xl tmem-shared-auth" command.

32-bit implementation. diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown index 9eb85d68b5..9690512b6d 100644 --- a/docs/misc/xen-command-line.markdown +++ b/docs/misc/xen-command-line.markdown @@ -1539,9 +1539,6 @@ pages) must also be specified via the tbuf\_size parameter. ### tmem\_compress > `= ` -### tmem\_shared\_auth -> `= ` - ### tsc > `= unstable | skewed | stable:socket` diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index 2d97d36c38..e2b4cc15fd 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -1901,7 +1901,7 @@ int xc_tmem_control_oid(xc_interface *xch, int32_t pool_id, uint32_t subop, int xc_tmem_control(xc_interface *xch, int32_t pool_id, uint32_t subop, uint32_t cli_id, uint32_t len, uint32_t arg, void *buf); -int xc_tmem_auth(xc_interface *xch, int cli_id, char *uuid_str, int arg1); +int xc_tmem_auth(xc_interface *xch, int cli_id, char *uuid_str, int enable); int xc_tmem_save(xc_interface *xch, int dom, int live, int fd, int field_marker); int xc_tmem_save_extra(xc_interface *xch, int dom, int fd, int field_marker); void xc_tmem_save_done(xc_interface *xch, int dom); diff --git a/tools/libxc/xc_tmem.c b/tools/libxc/xc_tmem.c index 51d11efa25..9bf5cc3cf4 100644 --- a/tools/libxc/xc_tmem.c +++ b/tools/libxc/xc_tmem.c @@ -22,30 +22,6 @@ #include #include -static int do_tmem_op(xc_interface *xch, tmem_op_t *op) -{ - int ret; - DECLARE_HYPERCALL_BOUNCE(op, sizeof(*op), XC_HYPERCALL_BUFFER_BOUNCE_BOTH); - - if ( xc_hypercall_bounce_pre(xch, op) ) - { - PERROR("Could not bounce buffer for tmem op hypercall"); - return -EFAULT; - } - - ret = xencall1(xch->xcall, __HYPERVISOR_tmem_op, - HYPERCALL_BUFFER_AS_ARG(op)); - if ( ret < 0 ) - { - if ( errno == EACCES ) - DPRINTF("tmem operation failed -- need to" - " rebuild the user-space tool set?\n"); - } - xc_hypercall_bounce_post(xch, op); - - return ret; -} - int xc_tmem_control(xc_interface *xch, int32_t pool_id, uint32_t cmd, @@ -69,7 +45,8 @@ int xc_tmem_control(xc_interface *xch, sysctl.u.tmem_op.oid.oid[1] = 0; sysctl.u.tmem_op.oid.oid[2] = 0; - if ( cmd == XEN_SYSCTL_TMEM_OP_SET_CLIENT_INFO ) + if ( cmd == XEN_SYSCTL_TMEM_OP_SET_CLIENT_INFO || + cmd == XEN_SYSCTL_TMEM_OP_SET_AUTH ) HYPERCALL_BOUNCE_SET_DIR(buf, XC_HYPERCALL_BUFFER_BOUNCE_IN); if ( len ) { @@ -161,9 +138,9 @@ static int xc_tmem_uuid_parse(char *uuid_str, uint64_t *uuid_lo, uint64_t *uuid_ else if ( *p >= '0' && *p <= '9' ) digit = *p - '0'; else if ( *p >= 'A' && *p <= 'F' ) - digit = *p - 'A'; + digit = *p - 'A' + 10; else if ( *p >= 'a' && *p <= 'f' ) - digit = *p - 'a'; + digit = *p - 'a' + 10; else return -1; *x = (*x << 4) | digit; @@ -176,22 +153,25 @@ static int xc_tmem_uuid_parse(char *uuid_str, uint64_t *uuid_lo, uint64_t *uuid_ int xc_tmem_auth(xc_interface *xch, int cli_id, char *uuid_str, - int arg1) + int enable) { - tmem_op_t op; - - op.cmd = TMEM_AUTH; - op.pool_id = 0; - op.u.creat.arg1 = cli_id; - op.u.creat.flags = arg1; - if ( xc_tmem_uuid_parse(uuid_str, &op.u.creat.uuid[0], - &op.u.creat.uuid[1]) < 0 ) + xen_tmem_pool_info_t pool = { + .flags.u.auth = enable, + .id = 0, + .n_pages = 0, + .uuid[0] = 0, + .uuid[1] = 0, + }; + if ( xc_tmem_uuid_parse(uuid_str, &pool.uuid[0], + &pool.uuid[1]) < 0 ) { PERROR("Can't parse uuid, use xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); return -1; } - - return do_tmem_op(xch, &op); + return xc_tmem_control(xch, 0 /* pool_id */, + XEN_SYSCTL_TMEM_OP_SET_AUTH, + cli_id, sizeof(pool), + 0 /* arg */, &pool); } /* Save/restore/live migrate */ @@ -385,16 +365,18 @@ static int xc_tmem_restore_new_pool( uint64_t uuid_lo, uint64_t uuid_hi) { - tmem_op_t op; + xen_tmem_pool_info_t pool = { + .flags.raw = flags, + .id = pool_id, + .n_pages = 0, + .uuid[0] = uuid_lo, + .uuid[1] = uuid_hi, + }; - op.cmd = TMEM_RESTORE_NEW; - op.pool_id = pool_id; - op.u.creat.arg1 = cli_id; - op.u.creat.flags = flags; - op.u.creat.uuid[0] = uuid_lo; - op.u.creat.uuid[1] = uuid_hi; - - return do_tmem_op(xch, &op); + return xc_tmem_control(xch, pool_id, + XEN_SYSCTL_TMEM_OP_SET_POOLS, + cli_id, sizeof(pool), + 0 /* arg */, &pool); } int xc_tmem_restore(xc_interface *xch, int dom, int io_fd) diff --git a/tools/xl/xl_cmdtable.c b/tools/xl/xl_cmdtable.c index 7d9781113c..30eb93c17f 100644 --- a/tools/xl/xl_cmdtable.c +++ b/tools/xl/xl_cmdtable.c @@ -416,7 +416,7 @@ struct cmd_spec cmd_table[] = { " -a Authenticate for all tmem pools\n" " -u UUID Specify uuid\n" " (abcdef01-2345-6789-1234-567890abcdef)\n" - " -A AUTH 0=auth,1=deauth", + " -A AUTH 0=deauth,1=auth", }, { "tmem-freeable", &main_tmem_freeable, 0, 0, diff --git a/xen/common/tmem.c b/xen/common/tmem.c index 6d5de5b036..306dda60d5 100644 --- a/xen/common/tmem.c +++ b/xen/common/tmem.c @@ -804,7 +804,7 @@ static void pool_flush(struct tmem_pool *pool, domid_t cli_id) /************ CLIENT MANIPULATION OPERATIONS **************************/ -static struct client *client_create(domid_t cli_id) +struct client *client_create(domid_t cli_id) { struct client *client = xzalloc(struct client); int i, shift; @@ -846,7 +846,6 @@ static struct client *client_create(domid_t cli_id) client->info.version = TMEM_SPEC_VERSION; client->info.maxpools = MAX_POOLS_PER_DOMAIN; client->info.flags.u.compress = tmem_compression_enabled(); - client->shared_auth_required = tmem_shared_auth(); for ( i = 0; i < MAX_GLOBAL_SHARED_POOLS; i++) client->shared_auth_uuid[i][0] = client->shared_auth_uuid[i][1] = -1L; @@ -1435,9 +1434,9 @@ static int do_tmem_destroy_pool(uint32_t pool_id) return 1; } -static int do_tmem_new_pool(domid_t this_cli_id, - uint32_t d_poolid, uint32_t flags, - uint64_t uuid_lo, uint64_t uuid_hi) +int do_tmem_new_pool(domid_t this_cli_id, + uint32_t d_poolid, uint32_t flags, + uint64_t uuid_lo, uint64_t uuid_hi) { struct client *client; domid_t cli_id; @@ -1530,7 +1529,7 @@ static int do_tmem_new_pool(domid_t this_cli_id, pool->shared = 0; goto out; } - if ( client->shared_auth_required && !tmem_global.shared_auth ) + if ( !tmem_global.shared_auth ) { for ( i = 0; i < MAX_GLOBAL_SHARED_POOLS; i++) if ( (client->shared_auth_uuid[i][0] == uuid_lo) && @@ -1604,8 +1603,8 @@ fail: /************ TMEM CONTROL OPERATIONS ************************************/ -static int tmemc_shared_pool_auth(domid_t cli_id, uint64_t uuid_lo, - uint64_t uuid_hi, bool_t auth) +int tmemc_shared_pool_auth(domid_t cli_id, uint64_t uuid_lo, + uint64_t uuid_hi, bool auth) { struct client *client; int i, free = -1; @@ -1908,21 +1907,15 @@ long do_tmem_op(tmem_cli_op_t uops) /* Acquire write lock for all commands at first. */ write_lock(&tmem_rwlock); - if ( op.cmd == TMEM_CONTROL ) + switch ( op.cmd ) { + case TMEM_CONTROL: + case TMEM_RESTORE_NEW: + case TMEM_AUTH: rc = -EOPNOTSUPP; - } - else if ( op.cmd == TMEM_AUTH ) - { - rc = tmemc_shared_pool_auth(op.u.creat.arg1,op.u.creat.uuid[0], - op.u.creat.uuid[1],op.u.creat.flags); - } - else if ( op.cmd == TMEM_RESTORE_NEW ) - { - rc = do_tmem_new_pool(op.u.creat.arg1, op.pool_id, op.u.creat.flags, - op.u.creat.uuid[0], op.u.creat.uuid[1]); - } - else { + break; + + default: /* * For other commands, create per-client tmem structure dynamically on * first use by client. @@ -1999,6 +1992,8 @@ long do_tmem_op(tmem_cli_op_t uops) tmem_stats.errored_tmem_ops++; return rc; } + break; + } out: write_unlock(&tmem_rwlock); diff --git a/xen/common/tmem_control.c b/xen/common/tmem_control.c index ddd9cfe16b..2d980e3f73 100644 --- a/xen/common/tmem_control.c +++ b/xen/common/tmem_control.c @@ -402,6 +402,101 @@ static int tmemc_get_pool(int cli_id, return rc ? : idx; } +static int tmemc_set_pools(int cli_id, + XEN_GUEST_HANDLE(xen_tmem_pool_info_t) pools, + uint32_t len) +{ + unsigned int i; + int rc = 0; + unsigned int nr = len / sizeof(xen_tmem_pool_info_t); + struct client *client = tmem_client_from_cli_id(cli_id); + + if ( len % sizeof(xen_tmem_pool_info_t) ) + return -EINVAL; + + if ( nr > MAX_POOLS_PER_DOMAIN ) + return -E2BIG; + + if ( !guest_handle_okay(pools, nr) ) + return -EINVAL; + + if ( !client ) + { + client = client_create(cli_id); + if ( !client ) + return -ENOMEM; + } + for ( i = 0; i < nr; i++ ) + { + xen_tmem_pool_info_t pool; + + if ( __copy_from_guest_offset(&pool, pools, i, 1 ) ) + return -EFAULT; + + if ( pool.n_pages ) + return -EINVAL; + + rc = do_tmem_new_pool(cli_id, pool.id, pool.flags.raw, + pool.uuid[0], pool.uuid[1]); + if ( rc < 0 ) + break; + + pool.id = rc; + if ( __copy_to_guest_offset(pools, i, &pool, 1) ) + return -EFAULT; + } + + /* And how many we have processed. */ + return rc ? : i; +} + +static int tmemc_auth_pools(int cli_id, + XEN_GUEST_HANDLE(xen_tmem_pool_info_t) pools, + uint32_t len) +{ + unsigned int i; + int rc = 0; + unsigned int nr = len / sizeof(xen_tmem_pool_info_t); + struct client *client = tmem_client_from_cli_id(cli_id); + + if ( len % sizeof(xen_tmem_pool_info_t) ) + return -EINVAL; + + if ( nr > MAX_POOLS_PER_DOMAIN ) + return -E2BIG; + + if ( !guest_handle_okay(pools, nr) ) + return -EINVAL; + + if ( !client ) + { + client = client_create(cli_id); + if ( !client ) + return -ENOMEM; + } + + for ( i = 0; i < nr; i++ ) + { + xen_tmem_pool_info_t pool; + + if ( __copy_from_guest_offset(&pool, pools, i, 1 ) ) + return -EFAULT; + + if ( pool.n_pages ) + return -EINVAL; + + rc = tmemc_shared_pool_auth(cli_id, pool.uuid[0], pool.uuid[1], + pool.flags.u.auth); + + if ( rc < 0 ) + break; + + } + + /* And how many we have processed. */ + return rc ? : i; +} + int tmem_control(struct xen_sysctl_tmem_op *op) { int ret; @@ -438,6 +533,12 @@ int tmem_control(struct xen_sysctl_tmem_op *op) case XEN_SYSCTL_TMEM_OP_GET_POOLS: ret = tmemc_get_pool(op->cli_id, op->u.pool, op->len); break; + case XEN_SYSCTL_TMEM_OP_SET_POOLS: /* TMEM_RESTORE_NEW */ + ret = tmemc_set_pools(op->cli_id, op->u.pool, op->len); + break; + case XEN_SYSCTL_TMEM_OP_SET_AUTH: /* TMEM_AUTH */ + ret = tmemc_auth_pools(op->cli_id, op->u.pool, op->len); + break; default: ret = do_tmem_control(op); break; diff --git a/xen/common/tmem_xen.c b/xen/common/tmem_xen.c index 7d60b7129e..06ce3ef129 100644 --- a/xen/common/tmem_xen.c +++ b/xen/common/tmem_xen.c @@ -20,9 +20,6 @@ boolean_param("tmem", opt_tmem); bool_t __read_mostly opt_tmem_compress = 0; boolean_param("tmem_compress", opt_tmem_compress); -bool_t __read_mostly opt_tmem_shared_auth = 0; -boolean_param("tmem_shared_auth", opt_tmem_shared_auth); - atomic_t freeable_page_count = ATOMIC_INIT(0); /* these are a concurrency bottleneck, could be percpu and dynamically diff --git a/xen/include/Makefile b/xen/include/Makefile index aca7f2051d..65a732a707 100644 --- a/xen/include/Makefile +++ b/xen/include/Makefile @@ -90,11 +90,15 @@ compat/xlat.h: $(addprefix compat/.xlat/,$(xlat-y)) Makefile ifeq ($(XEN_TARGET_ARCH),$(XEN_COMPILE_ARCH)) -all: headers.chk headers++.chk +all: headers.chk headers99.chk headers++.chk PUBLIC_HEADERS := $(filter-out public/arch-% public/dom0_ops.h, $(wildcard public/*.h public/*/*.h) $(public-y)) -PUBLIC_ANSI_HEADERS := $(filter-out public/%ctl.h public/xsm/% public/%hvm/save.h, $(PUBLIC_HEADERS)) +PUBLIC_C99_HEADERS := public/io/9pfs.h public/io/pvcalls.h +PUBLIC_ANSI_HEADERS := $(filter-out public/%ctl.h public/xsm/% public/%hvm/save.h $(PUBLIC_C99_HEADERS), $(PUBLIC_HEADERS)) + +public/io/9pfs.h-prereq := string +public/io/pvcalls.h-prereq := string headers.chk: $(PUBLIC_ANSI_HEADERS) Makefile for i in $(filter %.h,$^); do \ @@ -104,16 +108,24 @@ headers.chk: $(PUBLIC_ANSI_HEADERS) Makefile done >$@.new mv $@.new $@ +headers99.chk: $(PUBLIC_C99_HEADERS) Makefile + rm -f $@.new + $(foreach i, $(filter %.h,$^), \ + $(CC) -x c -std=c99 -Wall -Werror \ + -include stdint.h $(foreach j, $($(i)-prereq), -include $(j).h) \ + -S -o /dev/null $(i) \ + || exit $$?; echo $(i) >> $@.new;) + mv $@.new $@ + headers++.chk: $(PUBLIC_HEADERS) Makefile - if $(CXX) -v >/dev/null 2>&1; then \ - for i in $(filter %.h,$^); do \ - echo '#include "'$$i'"' \ - | $(CXX) -x c++ -std=gnu++98 -Wall -Werror -D__XEN_TOOLS__ \ - -include stdint.h -include public/xen.h -S -o /dev/null - \ - || exit 1; \ - echo $$i; \ - done ; \ - fi >$@.new + rm -f $@.new + $(CXX) -v >/dev/null 2>&1 || exit 0; \ + $(foreach i, $(filter %.h,$^), \ + echo "#include "\"$(i)\" \ + | $(CXX) -x c++ -std=gnu++98 -Wall -Werror -D__XEN_TOOLS__ \ + -include stdint.h -include public/xen.h \ + $(foreach j, $($(i)-prereq), -include c$(j)) -S -o /dev/null - \ + || exit $$?; echo $(i) >> $@.new;) mv $@.new $@ endif @@ -128,5 +140,5 @@ all: $(BASEDIR)/include/asm-x86/cpuid-autogen.h endif clean:: - rm -rf compat headers.chk headers++.chk + rm -rf compat headers*.chk rm -f $(BASEDIR)/include/asm-x86/cpuid-autogen.h diff --git a/xen/include/public/io/9pfs.h b/xen/include/public/io/9pfs.h new file mode 100644 index 0000000000..4bfd5d48b1 --- /dev/null +++ b/xen/include/public/io/9pfs.h @@ -0,0 +1,49 @@ +/* + * 9pfs.h -- Xen 9PFS transport + * + * Refer to docs/misc/9pfs.markdown for the specification + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (C) 2017 Stefano Stabellini + */ + +#ifndef __XEN_PUBLIC_IO_9PFS_H__ +#define __XEN_PUBLIC_IO_9PFS_H__ + +#include "../grant_table.h" +#include "ring.h" + +/* + * See docs/misc/9pfs.markdown in xen.git for the full specification: + * https://xenbits.xen.org/docs/unstable/misc/9pfs.html + */ +DEFINE_XEN_FLEX_RING_AND_INTF(xen_9pfs); + +#endif + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/io/displif.h b/xen/include/public/io/displif.h new file mode 100644 index 0000000000..8a94f1f9b9 --- /dev/null +++ b/xen/include/public/io/displif.h @@ -0,0 +1,864 @@ +/****************************************************************************** + * displif.h + * + * Unified display device I/O interface for Xen guest OSes. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (C) 2016-2017 EPAM Systems Inc. + * + * Authors: Oleksandr Andrushchenko + * Oleksandr Grytsov + */ + +#ifndef __XEN_PUBLIC_IO_DISPLIF_H__ +#define __XEN_PUBLIC_IO_DISPLIF_H__ + +#include "ring.h" +#include "../grant_table.h" + +/* + ****************************************************************************** + * Protocol version + ****************************************************************************** + */ +#define XENDISPL_PROTOCOL_VERSION "1" + +/* + ****************************************************************************** + * Main features provided by the protocol + ****************************************************************************** + * This protocol aims to provide a unified protocol which fits more + * sophisticated use-cases than a framebuffer device can handle. At the + * moment basic functionality is supported with the intention to be extended: + * o multiple dynamically allocated/destroyed framebuffers + * o buffers of arbitrary sizes + * o buffer allocation at either back or front end + * o better configuration options including multiple display support + * + * Note: existing fbif can be used together with displif running at the + * same time, e.g. on Linux one provides framebuffer and another DRM/KMS + * + * Note: display resolution (XenStore's "resolution" property) defines + * visible area of the virtual display. At the same time resolution of + * the display and frame buffers may differ: buffers can be smaller, equal + * or bigger than the visible area. This is to enable use-cases, where backend + * may do some post-processing of the display and frame buffers supplied, + * e.g. those buffers can be just a part of the final composition. + * + ****************************************************************************** + * Direction of improvements + ****************************************************************************** + * Future extensions to the existing protocol may include: + * o display/connector cloning + * o allocation of objects other than display buffers + * o plane/overlay support + * o scaling support + * o rotation support + * + ****************************************************************************** + * Feature and Parameter Negotiation + ****************************************************************************** + * + * Front->back notifications: when enqueuing a new request, sending a + * notification can be made conditional on xendispl_req (i.e., the generic + * hold-off mechanism provided by the ring macros). Backends must set + * xendispl_req appropriately (e.g., using RING_FINAL_CHECK_FOR_REQUESTS()). + * + * Back->front notifications: when enqueuing a new response, sending a + * notification can be made conditional on xendispl_resp (i.e., the generic + * hold-off mechanism provided by the ring macros). Frontends must set + * xendispl_resp appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()). + * + * The two halves of a para-virtual display driver utilize nodes within + * XenStore to communicate capabilities and to negotiate operating parameters. + * This section enumerates these nodes which reside in the respective front and + * backend portions of XenStore, following the XenBus convention. + * + * All data in XenStore is stored as strings. Nodes specifying numeric + * values are encoded in decimal. Integer value ranges listed below are + * expressed as fixed sized integer types capable of storing the conversion + * of a properly formated node string, without loss of information. + * + ****************************************************************************** + * Example configuration + ****************************************************************************** + * + * Note: depending on the use-case backend can expose more display connectors + * than the underlying HW physically has by employing SW graphics compositors + * + * This is an example of backend and frontend configuration: + * + *--------------------------------- Backend ----------------------------------- + * + * /local/domain/0/backend/vdispl/1/0/frontend-id = "1" + * /local/domain/0/backend/vdispl/1/0/frontend = "/local/domain/1/device/vdispl/0" + * /local/domain/0/backend/vdispl/1/0/state = "4" + * /local/domain/0/backend/vdispl/1/0/versions = "1,2" + * + *--------------------------------- Frontend ---------------------------------- + * + * /local/domain/1/device/vdispl/0/backend-id = "0" + * /local/domain/1/device/vdispl/0/backend = "/local/domain/0/backend/vdispl/1/0" + * /local/domain/1/device/vdispl/0/state = "4" + * /local/domain/1/device/vdispl/0/version = "1" + * /local/domain/1/device/vdispl/0/be-alloc = "1" + * + *-------------------------- Connector 0 configuration ------------------------ + * + * /local/domain/1/device/vdispl/0/0/resolution = "1920x1080" + * /local/domain/1/device/vdispl/0/0/req-ring-ref = "2832" + * /local/domain/1/device/vdispl/0/0/req-event-channel = "15" + * /local/domain/1/device/vdispl/0/0/evt-ring-ref = "387" + * /local/domain/1/device/vdispl/0/0/evt-event-channel = "16" + * + *-------------------------- Connector 1 configuration ------------------------ + * + * /local/domain/1/device/vdispl/0/1/resolution = "800x600" + * /local/domain/1/device/vdispl/0/1/req-ring-ref = "2833" + * /local/domain/1/device/vdispl/0/1/req-event-channel = "17" + * /local/domain/1/device/vdispl/0/1/evt-ring-ref = "388" + * /local/domain/1/device/vdispl/0/1/evt-event-channel = "18" + * + ****************************************************************************** + * Backend XenBus Nodes + ****************************************************************************** + * + *----------------------------- Protocol version ------------------------------ + * + * versions + * Values: + * + * List of XENDISPL_LIST_SEPARATOR separated protocol versions supported + * by the backend. For example "1,2,3". + * + ****************************************************************************** + * Frontend XenBus Nodes + ****************************************************************************** + * + *-------------------------------- Addressing --------------------------------- + * + * dom-id + * Values: + * + * Domain identifier. + * + * dev-id + * Values: + * + * Device identifier. + * + * conn-idx + * Values: + * + * Zero based contigous index of the connector. + * /local/domain//device/vdispl///... + * + *----------------------------- Protocol version ------------------------------ + * + * version + * Values: + * + * Protocol version, chosen among the ones supported by the backend. + * + *------------------------- Backend buffer allocation ------------------------- + * + * be-alloc + * Values: "0", "1" + * + * If value is set to "1", then backend can be a buffer provider/allocator + * for this domain during XENDISPL_OP_DBUF_CREATE operation (see below + * for negotiation). + * If value is not "1" or omitted frontend must allocate buffers itself. + * + *----------------------------- Connector settings ---------------------------- + * + * resolution + * Values: x + * + * Width and height of the connector in pixels separated by + * XENDISPL_RESOLUTION_SEPARATOR. This defines visible area of the + * display. + * + *------------------ Connector Request Transport Parameters ------------------- + * + * This communication path is used to deliver requests from frontend to backend + * and get the corresponding responses from backend to frontend, + * set up per connector. + * + * req-event-channel + * Values: + * + * The identifier of the Xen connector's control event channel + * used to signal activity in the ring buffer. + * + * req-ring-ref + * Values: + * + * The Xen grant reference granting permission for the backend to map + * a sole page of connector's control ring buffer. + * + *------------------- Connector Event Transport Parameters -------------------- + * + * This communication path is used to deliver asynchronous events from backend + * to frontend, set up per connector. + * + * evt-event-channel + * Values: + * + * The identifier of the Xen connector's event channel + * used to signal activity in the ring buffer. + * + * evt-ring-ref + * Values: + * + * The Xen grant reference granting permission for the backend to map + * a sole page of connector's event ring buffer. + */ + +/* + ****************************************************************************** + * STATE DIAGRAMS + ****************************************************************************** + * + * Tool stack creates front and back state nodes with initial state + * XenbusStateInitialising. + * Tool stack creates and sets up frontend display configuration + * nodes per domain. + * + *-------------------------------- Normal flow -------------------------------- + * + * Front Back + * ================================= ===================================== + * XenbusStateInitialising XenbusStateInitialising + * o Query backend device identification + * data. + * o Open and validate backend device. + * | + * | + * V + * XenbusStateInitWait + * + * o Query frontend configuration + * o Allocate and initialize + * event channels per configured + * connector. + * o Publish transport parameters + * that will be in effect during + * this connection. + * | + * | + * V + * XenbusStateInitialised + * + * o Query frontend transport parameters. + * o Connect to the event channels. + * | + * | + * V + * XenbusStateConnected + * + * o Create and initialize OS + * virtual display connectors + * as per configuration. + * | + * | + * V + * XenbusStateConnected + * + * XenbusStateUnknown + * XenbusStateClosed + * XenbusStateClosing + * o Remove virtual display device + * o Remove event channels + * | + * | + * V + * XenbusStateClosed + * + *------------------------------- Recovery flow ------------------------------- + * + * In case of frontend unrecoverable errors backend handles that as + * if frontend goes into the XenbusStateClosed state. + * + * In case of backend unrecoverable errors frontend tries removing + * the virtualized device. If this is possible at the moment of error, + * then frontend goes into the XenbusStateInitialising state and is ready for + * new connection with backend. If the virtualized device is still in use and + * cannot be removed, then frontend goes into the XenbusStateReconfiguring state + * until either the virtualized device is removed or backend initiates a new + * connection. On the virtualized device removal frontend goes into the + * XenbusStateInitialising state. + * + * Note on XenbusStateReconfiguring state of the frontend: if backend has + * unrecoverable errors then frontend cannot send requests to the backend + * and thus cannot provide functionality of the virtualized device anymore. + * After backend is back to normal the virtualized device may still hold some + * state: configuration in use, allocated buffers, client application state etc. + * In most cases, this will require frontend to implement complex recovery + * reconnect logic. Instead, by going into XenbusStateReconfiguring state, + * frontend will make sure no new clients of the virtualized device are + * accepted, allow existing client(s) to exit gracefully by signaling error + * state etc. + * Once all the clients are gone frontend can reinitialize the virtualized + * device and get into XenbusStateInitialising state again signaling the + * backend that a new connection can be made. + * + * There are multiple conditions possible under which frontend will go from + * XenbusStateReconfiguring into XenbusStateInitialising, some of them are OS + * specific. For example: + * 1. The underlying OS framework may provide callbacks to signal that the last + * client of the virtualized device has gone and the device can be removed + * 2. Frontend can schedule a deferred work (timer/tasklet/workqueue) + * to periodically check if this is the right time to re-try removal of + * the virtualized device. + * 3. By any other means. + * + ****************************************************************************** + * REQUEST CODES + ****************************************************************************** + * Request codes [0; 15] are reserved and must not be used + */ + +#define XENDISPL_OP_DBUF_CREATE 0x10 +#define XENDISPL_OP_DBUF_DESTROY 0x11 +#define XENDISPL_OP_FB_ATTACH 0x12 +#define XENDISPL_OP_FB_DETACH 0x13 +#define XENDISPL_OP_SET_CONFIG 0x14 +#define XENDISPL_OP_PG_FLIP 0x15 + +/* + ****************************************************************************** + * EVENT CODES + ****************************************************************************** + */ +#define XENDISPL_EVT_PG_FLIP 0x00 + +/* + ****************************************************************************** + * XENSTORE FIELD AND PATH NAME STRINGS, HELPERS + ****************************************************************************** + */ +#define XENDISPL_DRIVER_NAME "vdispl" + +#define XENDISPL_LIST_SEPARATOR "," +#define XENDISPL_RESOLUTION_SEPARATOR "x" + +#define XENDISPL_FIELD_BE_VERSIONS "versions" +#define XENDISPL_FIELD_FE_VERSION "version" +#define XENDISPL_FIELD_REQ_RING_REF "req-ring-ref" +#define XENDISPL_FIELD_REQ_CHANNEL "req-event-channel" +#define XENDISPL_FIELD_EVT_RING_REF "evt-ring-ref" +#define XENDISPL_FIELD_EVT_CHANNEL "evt-event-channel" +#define XENDISPL_FIELD_RESOLUTION "resolution" +#define XENDISPL_FIELD_BE_ALLOC "be-alloc" + +/* + ****************************************************************************** + * STATUS RETURN CODES + ****************************************************************************** + * + * Status return code is zero on success and -XEN_EXX on failure. + * + ****************************************************************************** + * Assumptions + ****************************************************************************** + * o usage of grant reference 0 as invalid grant reference: + * grant reference 0 is valid, but never exposed to a PV driver, + * because of the fact it is already in use/reserved by the PV console. + * o all references in this document to page sizes must be treated + * as pages of size XEN_PAGE_SIZE unless otherwise noted. + * + ****************************************************************************** + * Description of the protocol between frontend and backend driver + ****************************************************************************** + * + * The two halves of a Para-virtual display driver communicate with + * each other using shared pages and event channels. + * Shared page contains a ring with request/response packets. + * + * All reserved fields in the structures below must be 0. + * Display buffers's cookie of value 0 is treated as invalid. + * Framebuffer's cookie of value 0 is treated as invalid. + * + * For all request/response/event packets that use cookies: + * dbuf_cookie - uint64_t, unique to guest domain value used by the backend + * to map remote display buffer to its local one + * fb_cookie - uint64_t, unique to guest domain value used by the backend + * to map remote framebuffer to its local one + * + *---------------------------------- Requests --------------------------------- + * + * All requests/responses, which are not connector specific, must be sent over + * control ring of the connector which has the index value of 0: + * /local/domain//device/vdispl//0/req-ring-ref + * + * All request packets have the same length (64 octets) + * All request packets have common header: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | operation | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * id - uint16_t, private guest value, echoed in response + * operation - uint8_t, operation code, XENDISPL_OP_??? + * + * Request dbuf creation - request creation of a display buffer. + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id |_OP_DBUF_CREATE | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | dbuf_cookie low 32-bit | 12 + * +----------------+----------------+----------------+----------------+ + * | dbuf_cookie high 32-bit | 16 + * +----------------+----------------+----------------+----------------+ + * | width | 20 + * +----------------+----------------+----------------+----------------+ + * | height | 24 + * +----------------+----------------+----------------+----------------+ + * | bpp | 28 + * +----------------+----------------+----------------+----------------+ + * | buffer_sz | 32 + * +----------------+----------------+----------------+----------------+ + * | flags | 36 + * +----------------+----------------+----------------+----------------+ + * | gref_directory | 40 + * +----------------+----------------+----------------+----------------+ + * | reserved | 44 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | reserved | 64 + * +----------------+----------------+----------------+----------------+ + * + * Must be sent over control ring of the connector which has the index + * value of 0: + * /local/domain//device/vdispl//0/req-ring-ref + * All unused bits in flags field must be set to 0. + * + * An attempt to create multiple display buffers with the same dbuf_cookie is + * an error. dbuf_cookie can be re-used after destroying the corresponding + * display buffer. + * + * Width and height of the display buffers can be smaller, equal or bigger + * than the connector's resolution. Depth/pixel format of the individual + * buffers can differ as well. + * + * width - uint32_t, width in pixels + * height - uint32_t, height in pixels + * bpp - uint32_t, bits per pixel + * buffer_sz - uint32_t, buffer size to be allocated, octets + * flags - uint32_t, flags of the operation + * o XENDISPL_DBUF_FLG_REQ_ALLOC - if set, then backend is requested + * to allocate the buffer with the parameters provided in this request. + * Page directory is handled as follows: + * Frontend on request: + * o allocates pages for the directory (gref_directory, + * gref_dir_next_page(s) + * o grants permissions for the pages of the directory to the backend + * o sets gref_dir_next_page fields + * Backend on response: + * o grants permissions for the pages of the buffer allocated to + * the frontend + * o fills in page directory with grant references + * (gref[] in struct xendispl_page_directory) + * gref_directory - grant_ref_t, a reference to the first shared page + * describing shared buffer references. At least one page exists. If shared + * buffer size (buffer_sz) exceeds what can be addressed by this single page, + * then reference to the next page must be supplied (see gref_dir_next_page + * below) + */ + +#define XENDISPL_DBUF_FLG_REQ_ALLOC (1 << 0) + +struct xendispl_dbuf_create_req { + uint64_t dbuf_cookie; + uint32_t width; + uint32_t height; + uint32_t bpp; + uint32_t buffer_sz; + uint32_t flags; + grant_ref_t gref_directory; +}; + +/* + * Shared page for XENDISPL_OP_DBUF_CREATE buffer descriptor (gref_directory in + * the request) employs a list of pages, describing all pages of the shared + * data buffer: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | gref_dir_next_page | 4 + * +----------------+----------------+----------------+----------------+ + * | gref[0] | 8 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | gref[i] | i*4+8 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | gref[N - 1] | N*4+8 + * +----------------+----------------+----------------+----------------+ + * + * gref_dir_next_page - grant_ref_t, reference to the next page describing + * page directory. Must be 0 if there are no more pages in the list. + * gref[i] - grant_ref_t, reference to a shared page of the buffer + * allocated at XENDISPL_OP_DBUF_CREATE + * + * Number of grant_ref_t entries in the whole page directory is not + * passed, but instead can be calculated as: + * num_grefs_total = (XENDISPL_OP_DBUF_CREATE.buffer_sz + XEN_PAGE_SIZE - 1) / + * XEN_PAGE_SIZE + */ + +struct xendispl_page_directory { + grant_ref_t gref_dir_next_page; + grant_ref_t gref[1]; /* Variable length */ +}; + +/* + * Request dbuf destruction - destroy a previously allocated display buffer: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id |_OP_DBUF_DESTROY| reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | dbuf_cookie low 32-bit | 12 + * +----------------+----------------+----------------+----------------+ + * | dbuf_cookie high 32-bit | 16 + * +----------------+----------------+----------------+----------------+ + * | reserved | 20 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | reserved | 64 + * +----------------+----------------+----------------+----------------+ + * + * Must be sent over control ring of the connector which has the index + * value of 0: + * /local/domain//device/vdispl//0/req-ring-ref + */ + +struct xendispl_dbuf_destroy_req { + uint64_t dbuf_cookie; +}; + +/* + * Request framebuffer attachment - request attachment of a framebuffer to + * previously created display buffer. + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | _OP_FB_ATTACH | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | dbuf_cookie low 32-bit | 12 + * +----------------+----------------+----------------+----------------+ + * | dbuf_cookie high 32-bit | 16 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie low 32-bit | 20 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie high 32-bit | 24 + * +----------------+----------------+----------------+----------------+ + * | width | 28 + * +----------------+----------------+----------------+----------------+ + * | height | 32 + * +----------------+----------------+----------------+----------------+ + * | pixel_format | 36 + * +----------------+----------------+----------------+----------------+ + * | reserved | 40 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | reserved | 64 + * +----------------+----------------+----------------+----------------+ + * + * Must be sent over control ring of the connector which has the index + * value of 0: + * /local/domain//device/vdispl//0/req-ring-ref + * Width and height can be smaller, equal or bigger than the connector's + * resolution. + * + * An attempt to create multiple frame buffers with the same fb_cookie is + * an error. fb_cookie can be re-used after destroying the corresponding + * frame buffer. + * + * width - uint32_t, width in pixels + * height - uint32_t, height in pixels + * pixel_format - uint32_t, pixel format of the framebuffer, FOURCC code + */ + +struct xendispl_fb_attach_req { + uint64_t dbuf_cookie; + uint64_t fb_cookie; + uint32_t width; + uint32_t height; + uint32_t pixel_format; +}; + +/* + * Request framebuffer detach - detach a previously + * attached framebuffer from the display buffer in request: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | _OP_FB_DETACH | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie low 32-bit | 12 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie high 32-bit | 16 + * +----------------+----------------+----------------+----------------+ + * | reserved | 20 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | reserved | 64 + * +----------------+----------------+----------------+----------------+ + * + * Must be sent over control ring of the connector which has the index + * value of 0: + * /local/domain//device/vdispl//0/req-ring-ref + */ + +struct xendispl_fb_detach_req { + uint64_t fb_cookie; +}; + +/* + * Request configuration set/reset - request to set or reset + * the configuration/mode of the display: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | _OP_SET_CONFIG | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie low 32-bit | 12 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie high 32-bit | 16 + * +----------------+----------------+----------------+----------------+ + * | x | 20 + * +----------------+----------------+----------------+----------------+ + * | y | 24 + * +----------------+----------------+----------------+----------------+ + * | width | 28 + * +----------------+----------------+----------------+----------------+ + * | height | 32 + * +----------------+----------------+----------------+----------------+ + * | bpp | 40 + * +----------------+----------------+----------------+----------------+ + * | reserved | 44 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | reserved | 64 + * +----------------+----------------+----------------+----------------+ + * + * Pass all zeros to reset, otherwise command is treated as + * configuration set. + * Framebuffer's cookie defines which framebuffer/dbuf must be + * displayed while enabling display (applying configuration). + * x, y, width and height are bound by the connector's resolution and must not + * exceed it. + * + * x - uint32_t, starting position in pixels by X axis + * y - uint32_t, starting position in pixels by Y axis + * width - uint32_t, width in pixels + * height - uint32_t, height in pixels + * bpp - uint32_t, bits per pixel + */ + +struct xendispl_set_config_req { + uint64_t fb_cookie; + uint32_t x; + uint32_t y; + uint32_t width; + uint32_t height; + uint32_t bpp; +}; + +/* + * Request page flip - request to flip a page identified by the framebuffer + * cookie: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | _OP_PG_FLIP | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie low 32-bit | 12 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie high 32-bit | 16 + * +----------------+----------------+----------------+----------------+ + * | reserved | 20 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | reserved | 64 + * +----------------+----------------+----------------+----------------+ + */ + +struct xendispl_page_flip_req { + uint64_t fb_cookie; +}; + +/* + *---------------------------------- Responses -------------------------------- + * + * All response packets have the same length (64 octets) + * + * All response packets have common header: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | status | 8 + * +----------------+----------------+----------------+----------------+ + * | reserved | 12 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | reserved | 64 + * +----------------+----------------+----------------+----------------+ + * + * id - uint16_t, private guest value, echoed from request + * status - int32_t, response status, zero on success and -XEN_EXX on failure + * + *----------------------------------- Events ---------------------------------- + * + * Events are sent via a shared page allocated by the front and propagated by + * evt-event-channel/evt-ring-ref XenStore entries + * All event packets have the same length (64 octets) + * All event packets have common header: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | type | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * + * id - uint16_t, event id, may be used by front + * type - uint8_t, type of the event + * + * + * Page flip complete event - event from back to front on page flip completed: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | _EVT_PG_FLIP | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie low 32-bit | 12 + * +----------------+----------------+----------------+----------------+ + * | fb_cookie high 32-bit | 16 + * +----------------+----------------+----------------+----------------+ + * | reserved | 20 + * +----------------+----------------+----------------+----------------+ + * |/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/| + * +----------------+----------------+----------------+----------------+ + * | reserved | 64 + * +----------------+----------------+----------------+----------------+ + */ + +struct xendispl_pg_flip_evt { + uint64_t fb_cookie; +}; + +struct xendispl_req { + uint16_t id; + uint8_t operation; + uint8_t reserved[5]; + union { + struct xendispl_dbuf_create_req dbuf_create; + struct xendispl_dbuf_destroy_req dbuf_destroy; + struct xendispl_fb_attach_req fb_attach; + struct xendispl_fb_detach_req fb_detach; + struct xendispl_set_config_req set_config; + struct xendispl_page_flip_req pg_flip; + uint8_t reserved[56]; + } op; +}; + +struct xendispl_resp { + uint16_t id; + uint8_t operation; + uint8_t reserved; + int32_t status; + uint8_t reserved1[56]; +}; + +struct xendispl_evt { + uint16_t id; + uint8_t type; + uint8_t reserved[5]; + union { + struct xendispl_pg_flip_evt pg_flip; + uint8_t reserved[56]; + } op; +}; + +DEFINE_RING_TYPES(xen_displif, struct xendispl_req, struct xendispl_resp); + +/* + ****************************************************************************** + * Back to front events delivery + ****************************************************************************** + * In order to deliver asynchronous events from back to front a shared page is + * allocated by front and its granted reference propagated to back via + * XenStore entries (evt-ring-ref/evt-event-channel). + * This page has a common header used by both front and back to synchronize + * access and control event's ring buffer, while back being a producer of the + * events and front being a consumer. The rest of the page after the header + * is used for event packets. + * + * Upon reception of an event(s) front may confirm its reception + * for either each event, group of events or none. + */ + +struct xendispl_event_page { + uint32_t in_cons; + uint32_t in_prod; + uint8_t reserved[56]; +}; + +#define XENDISPL_EVENT_PAGE_SIZE 4096 +#define XENDISPL_IN_RING_OFFS (sizeof(struct xendispl_event_page)) +#define XENDISPL_IN_RING_SIZE (XENDISPL_EVENT_PAGE_SIZE - XENDISPL_IN_RING_OFFS) +#define XENDISPL_IN_RING_LEN (XENDISPL_IN_RING_SIZE / sizeof(struct xendispl_evt)) +#define XENDISPL_IN_RING(page) \ + ((struct xendispl_evt *)((char *)(page) + XENDISPL_IN_RING_OFFS)) +#define XENDISPL_IN_RING_REF(page, idx) \ + (XENDISPL_IN_RING((page))[(idx) % XENDISPL_IN_RING_LEN]) + +#endif /* __XEN_PUBLIC_IO_DISPLIF_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/io/pvcalls.h b/xen/include/public/io/pvcalls.h new file mode 100644 index 0000000000..cb8171275c --- /dev/null +++ b/xen/include/public/io/pvcalls.h @@ -0,0 +1,153 @@ +/* + * pvcalls.h -- Xen PV Calls Protocol + * + * Refer to docs/misc/pvcalls.markdown for the specification + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (C) 2017 Stefano Stabellini + */ + +#ifndef __XEN_PUBLIC_IO_PVCALLS_H__ +#define __XEN_PUBLIC_IO_PVCALLS_H__ + +#include "../grant_table.h" +#include "ring.h" + +/* + * See docs/misc/pvcalls.markdown in xen.git for the full specification: + * https://xenbits.xen.org/docs/unstable/misc/pvcalls.html + */ +struct pvcalls_data_intf { + RING_IDX in_cons, in_prod, in_error; + + uint8_t pad1[52]; + + RING_IDX out_cons, out_prod, out_error; + + uint8_t pad2[52]; + + RING_IDX ring_order; + grant_ref_t ref[]; +}; +DEFINE_XEN_FLEX_RING(pvcalls); + +#define PVCALLS_SOCKET 0 +#define PVCALLS_CONNECT 1 +#define PVCALLS_RELEASE 2 +#define PVCALLS_BIND 3 +#define PVCALLS_LISTEN 4 +#define PVCALLS_ACCEPT 5 +#define PVCALLS_POLL 6 + +struct xen_pvcalls_request { + uint32_t req_id; /* private to guest, echoed in response */ + uint32_t cmd; /* command to execute */ + union { + struct xen_pvcalls_socket { + uint64_t id; + uint32_t domain; + uint32_t type; + uint32_t protocol; + } socket; + struct xen_pvcalls_connect { + uint64_t id; + uint8_t addr[28]; + uint32_t len; + uint32_t flags; + grant_ref_t ref; + uint32_t evtchn; + } connect; + struct xen_pvcalls_release { + uint64_t id; + uint8_t reuse; + } release; + struct xen_pvcalls_bind { + uint64_t id; + uint8_t addr[28]; + uint32_t len; + } bind; + struct xen_pvcalls_listen { + uint64_t id; + uint32_t backlog; + } listen; + struct xen_pvcalls_accept { + uint64_t id; + uint64_t id_new; + grant_ref_t ref; + uint32_t evtchn; + } accept; + struct xen_pvcalls_poll { + uint64_t id; + } poll; + /* dummy member to force sizeof(struct xen_pvcalls_request) + * to match across archs */ + struct xen_pvcalls_dummy { + uint8_t dummy[56]; + } dummy; + } u; +}; + +struct xen_pvcalls_response { + uint32_t req_id; + uint32_t cmd; + int32_t ret; + uint32_t pad; + union { + struct _xen_pvcalls_socket { + uint64_t id; + } socket; + struct _xen_pvcalls_connect { + uint64_t id; + } connect; + struct _xen_pvcalls_release { + uint64_t id; + } release; + struct _xen_pvcalls_bind { + uint64_t id; + } bind; + struct _xen_pvcalls_listen { + uint64_t id; + } listen; + struct _xen_pvcalls_accept { + uint64_t id; + } accept; + struct _xen_pvcalls_poll { + uint64_t id; + } poll; + struct _xen_pvcalls_dummy { + uint8_t dummy[8]; + } dummy; + } u; +}; + +DEFINE_RING_TYPES(xen_pvcalls, struct xen_pvcalls_request, + struct xen_pvcalls_response); + +#endif + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h index 801c0da1dc..30342fc8c0 100644 --- a/xen/include/public/io/ring.h +++ b/xen/include/public/io/ring.h @@ -27,6 +27,21 @@ #ifndef __XEN_PUBLIC_IO_RING_H__ #define __XEN_PUBLIC_IO_RING_H__ +/* + * When #include'ing this header, you need to provide the following + * declaration upfront: + * - standard integers types (uint8_t, uint16_t, etc) + * They are provided by stdint.h of the standard headers. + * + * In addition, if you intend to use the FLEX macros, you also need to + * provide the following, before invoking the FLEX macros: + * - size_t + * - memcpy + * - grant_ref_t + * These declarations are provided by string.h of the standard headers, + * and grant_table.h from the Xen public headers. + */ + #include "../xen-compat.h" #if __XEN_INTERFACE_VERSION__ < 0x00030208 @@ -313,6 +328,149 @@ typedef struct __name##_back_ring __name##_back_ring_t (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ } while (0) + +/* + * DEFINE_XEN_FLEX_RING_AND_INTF defines two monodirectional rings and + * functions to check if there is data on the ring, and to read and + * write to them. + * + * DEFINE_XEN_FLEX_RING is similar to DEFINE_XEN_FLEX_RING_AND_INTF, but + * does not define the indexes page. As different protocols can have + * extensions to the basic format, this macro allow them to define their + * own struct. + * + * XEN_FLEX_RING_SIZE + * Convenience macro to calculate the size of one of the two rings + * from the overall order. + * + * $NAME_mask + * Function to apply the size mask to an index, to reduce the index + * within the range [0-size]. + * + * $NAME_read_packet + * Function to read data from the ring. The amount of data to read is + * specified by the "size" argument. + * + * $NAME_write_packet + * Function to write data to the ring. The amount of data to write is + * specified by the "size" argument. + * + * $NAME_get_ring_ptr + * Convenience function that returns a pointer to read/write to the + * ring at the right location. + * + * $NAME_data_intf + * Indexes page, shared between frontend and backend. It also + * contains the array of grant refs. + * + * $NAME_queued + * Function to calculate how many bytes are currently on the ring, + * ready to be read. It can also be used to calculate how much free + * space is currently on the ring (XEN_FLEX_RING_SIZE() - + * $NAME_queued()). + */ + +#ifndef XEN_PAGE_SHIFT +/* The PAGE_SIZE for ring protocols and hypercall interfaces is always + * 4K, regardless of the architecture, and page granularity chosen by + * operating systems. + */ +#define XEN_PAGE_SHIFT 12 +#endif +#define XEN_FLEX_RING_SIZE(order) \ + (1UL << ((order) + XEN_PAGE_SHIFT - 1)) + +#define DEFINE_XEN_FLEX_RING(name) \ +static inline RING_IDX name##_mask(RING_IDX idx, RING_IDX ring_size) \ +{ \ + return idx & (ring_size - 1); \ +} \ + \ +static inline unsigned char *name##_get_ring_ptr(unsigned char *buf, \ + RING_IDX idx, \ + RING_IDX ring_size) \ +{ \ + return buf + name##_mask(idx, ring_size); \ +} \ + \ +static inline void name##_read_packet(void *opaque, \ + const unsigned char *buf, \ + size_t size, \ + RING_IDX masked_prod, \ + RING_IDX *masked_cons, \ + RING_IDX ring_size) \ +{ \ + if (*masked_cons < masked_prod || \ + size <= ring_size - *masked_cons) { \ + memcpy(opaque, buf + *masked_cons, size); \ + } else { \ + memcpy(opaque, buf + *masked_cons, ring_size - *masked_cons); \ + memcpy((unsigned char *)opaque + ring_size - *masked_cons, buf, \ + size - (ring_size - *masked_cons)); \ + } \ + *masked_cons = name##_mask(*masked_cons + size, ring_size); \ +} \ + \ +static inline void name##_write_packet(unsigned char *buf, \ + const void *opaque, \ + size_t size, \ + RING_IDX *masked_prod, \ + RING_IDX masked_cons, \ + RING_IDX ring_size) \ +{ \ + if (*masked_prod < masked_cons || \ + size <= ring_size - *masked_prod) { \ + memcpy(buf + *masked_prod, opaque, size); \ + } else { \ + memcpy(buf + *masked_prod, opaque, ring_size - *masked_prod); \ + memcpy(buf, (unsigned char *)opaque + (ring_size - *masked_prod), \ + size - (ring_size - *masked_prod)); \ + } \ + *masked_prod = name##_mask(*masked_prod + size, ring_size); \ +} \ + \ +static inline RING_IDX name##_queued(RING_IDX prod, \ + RING_IDX cons, \ + RING_IDX ring_size) \ +{ \ + RING_IDX size; \ + \ + if (prod == cons) \ + return 0; \ + \ + prod = name##_mask(prod, ring_size); \ + cons = name##_mask(cons, ring_size); \ + \ + if (prod == cons) \ + return ring_size; \ + \ + if (prod > cons) \ + size = prod - cons; \ + else \ + size = ring_size - (cons - prod); \ + return size; \ +} \ + \ +struct name##_data { \ + unsigned char *in; /* half of the allocation */ \ + unsigned char *out; /* half of the allocation */ \ +} + +#define DEFINE_XEN_FLEX_RING_AND_INTF(name) \ +struct name##_data_intf { \ + RING_IDX in_cons, in_prod; \ + \ + uint8_t pad1[56]; \ + \ + RING_IDX out_cons, out_prod; \ + \ + uint8_t pad2[56]; \ + \ + RING_IDX ring_order; \ + grant_ref_t ref[]; \ +}; \ +DEFINE_XEN_FLEX_RING(name) + #endif /* __XEN_PUBLIC_IO_RING_H__ */ /* diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index 00f5e77d91..ee76a66925 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -770,7 +770,9 @@ DEFINE_XEN_GUEST_HANDLE(xen_sysctl_psr_cat_op_t); #define XEN_SYSCTL_TMEM_OP_SET_CLIENT_INFO 6 #define XEN_SYSCTL_TMEM_OP_GET_POOLS 7 #define XEN_SYSCTL_TMEM_OP_QUERY_FREEABLE_MB 8 +#define XEN_SYSCTL_TMEM_OP_SET_POOLS 9 #define XEN_SYSCTL_TMEM_OP_SAVE_BEGIN 10 +#define XEN_SYSCTL_TMEM_OP_SET_AUTH 11 #define XEN_SYSCTL_TMEM_OP_SAVE_GET_NEXT_PAGE 19 #define XEN_SYSCTL_TMEM_OP_SAVE_GET_NEXT_INV 20 #define XEN_SYSCTL_TMEM_OP_SAVE_END 21 @@ -812,10 +814,14 @@ typedef struct xen_tmem_client xen_tmem_client_t; DEFINE_XEN_GUEST_HANDLE(xen_tmem_client_t); /* - * XEN_SYSCTL_TMEM_OP_GET_POOLS uses the 'pool' array in - * xen_sysctl_tmem_op with this structure. The hypercall will + * XEN_SYSCTL_TMEM_OP_[GET|SET]_POOLS or XEN_SYSCTL_TMEM_OP_SET_AUTH + * uses the 'pool' array in * xen_sysctl_tmem_op with this structure. + * The XEN_SYSCTL_TMEM_OP_GET_POOLS hypercall will * return the number of entries in 'pool' or a negative value * if an error was encountered. + * The XEN_SYSCTL_TMEM_OP_SET_[AUTH|POOLS] will return the number of + * entries in 'pool' processed or a negative value if an error + * was encountered. */ struct xen_tmem_pool_info { union { @@ -823,14 +829,15 @@ struct xen_tmem_pool_info { struct { uint32_t persist:1, /* See TMEM_POOL_PERSIST. */ shared:1, /* See TMEM_POOL_SHARED. */ - rsv:2, + auth:1, /* See TMEM_POOL_AUTH. */ + rsv1:1, pagebits:8, /* TMEM_POOL_PAGESIZE_[SHIFT,MASK]. */ rsv2:12, version:8; /* TMEM_POOL_VERSION_[SHIFT,MASK]. */ } u; } flags; uint32_t id; /* Less than tmem_client.maxpools. */ - uint64_t n_pages; + uint64_t n_pages; /* Zero on XEN_SYSCTL_TMEM_OP_SET_[AUTH|POOLS]. */ uint64_aligned_t uuid[2]; }; typedef struct xen_tmem_pool_info xen_tmem_pool_info_t; diff --git a/xen/include/public/tmem.h b/xen/include/public/tmem.h index 2d805fb3e7..aa0aafaa9d 100644 --- a/xen/include/public/tmem.h +++ b/xen/include/public/tmem.h @@ -51,9 +51,9 @@ #define TMEM_XCHG 10 #endif -/* Privileged commands to HYPERVISOR_tmem_op() */ -#define TMEM_AUTH 101 -#define TMEM_RESTORE_NEW 102 +/* Privileged commands now called via XEN_SYSCTL_tmem_op. */ +#define TMEM_AUTH 101 /* as XEN_SYSCTL_TMEM_OP_SET_AUTH. */ +#define TMEM_RESTORE_NEW 102 /* as XEN_SYSCTL_TMEM_OP_SET_POOL. */ /* Bits for HYPERVISOR_tmem_op(TMEM_NEW_POOL) */ #define TMEM_POOL_PERSIST 1 @@ -92,7 +92,7 @@ struct tmem_op { uint64_t uuid[2]; uint32_t flags; uint32_t arg1; - } creat; /* for cmd == TMEM_NEW_POOL, TMEM_AUTH, TMEM_RESTORE_NEW */ + } creat; /* for cmd == TMEM_NEW_POOL. */ struct { #if __XEN_INTERFACE_VERSION__ < 0x00040600 uint64_t oid[3]; diff --git a/xen/include/xen/tmem_control.h b/xen/include/xen/tmem_control.h index 44bc07faa8..ad04cf707b 100644 --- a/xen/include/xen/tmem_control.h +++ b/xen/include/xen/tmem_control.h @@ -18,6 +18,12 @@ extern rwlock_t tmem_rwlock; int tmem_evict(void); int do_tmem_control(struct xen_sysctl_tmem_op *op); +struct client *client_create(domid_t cli_id); +int do_tmem_new_pool(domid_t this_cli_id, uint32_t d_poolid, uint32_t flags, + uint64_t uuid_lo, uint64_t uuid_hi); + +int tmemc_shared_pool_auth(domid_t cli_id, uint64_t uuid_lo, + uint64_t uuid_hi, bool auth); #endif /* CONFIG_TMEM */ #endif /* __XEN_TMEM_CONTROL_H__ */ diff --git a/xen/include/xen/tmem_xen.h b/xen/include/xen/tmem_xen.h index 13cf7bc772..dc5888c9c3 100644 --- a/xen/include/xen/tmem_xen.h +++ b/xen/include/xen/tmem_xen.h @@ -41,12 +41,6 @@ static inline bool_t tmem_compression_enabled(void) return opt_tmem_compress; } -extern bool_t opt_tmem_shared_auth; -static inline bool_t tmem_shared_auth(void) -{ - return opt_tmem_shared_auth; -} - #ifdef CONFIG_TMEM extern bool_t opt_tmem; static inline bool_t tmem_enabled(void) @@ -198,8 +192,6 @@ static inline int tmem_get_tmemop_from_client(tmem_op_t *op, tmem_cli_op_t uops) switch ( cop.cmd ) { case TMEM_NEW_POOL: u = XLAT_tmem_op_u_creat; break; - case TMEM_AUTH: u = XLAT_tmem_op_u_creat; break; - case TMEM_RESTORE_NEW:u = XLAT_tmem_op_u_creat; break; default: u = XLAT_tmem_op_u_gen ; break; } XLAT_tmem_op(op, &cop); @@ -293,7 +285,6 @@ struct client { long eph_count, eph_count_max; domid_t cli_id; xen_tmem_client_t info; - bool_t shared_auth_required; /* For save/restore/migration. */ bool_t was_frozen; struct list_head persistent_invalidated_list;