From patchwork Tue Apr 7 17:38:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11478459 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CEBBC92A for ; Tue, 7 Apr 2020 17:40:01 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9E92720768 for ; Tue, 7 Apr 2020 17:40:01 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=xen.org header.i=@xen.org header.b="q+fzA2Z+" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9E92720768 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=xen.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBh-0000uO-KU; Tue, 07 Apr 2020 17:39:01 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBg-0000ts-8E for xen-devel@lists.xenproject.org; Tue, 07 Apr 2020 17:39:00 +0000 X-Inumbo-ID: a676ad8e-78f6-11ea-8122-12813bfff9fa Received: from mail.xenproject.org (unknown [104.130.215.37]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id a676ad8e-78f6-11ea-8122-12813bfff9fa; Tue, 07 Apr 2020 17:38:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org; s=20200302mail; h=Content-Transfer-Encoding:Content-Type:MIME-Version: References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=sUupaxZe1m2wsdVWEzsPraTd+XGtEAcP1dSKKA8pr8Y=; b=q+fzA2Z+09+F7KEUbp/OSvrfy4 usYZ1zrMioIRKAZFi8+zCmWBGxPO69g2PklYDR1duDXq+lCoyISqQkjb/P0FYZUq2YsuJQy+1QjFI peVzmkbqLoFAoiGCgZR0qKG61ENVESl9sxLsfLbHTD+FH/mky1XTgcis3u95ddcUUVO4=; Received: from xenbits.xenproject.org ([104.239.192.120]) by mail.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBZ-0000Jc-1P; Tue, 07 Apr 2020 17:38:53 +0000 Received: from 54-240-197-232.amazon.com ([54.240.197.232] helo=u2f063a87eabd5f.cbg10.amazon.com) by xenbits.xenproject.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1jLsBY-00088J-H6; Tue, 07 Apr 2020 17:38:52 +0000 From: Paul Durrant To: xen-devel@lists.xenproject.org Subject: [PATCH v2 1/5] xen/common: introduce a new framework for save/restore of 'domain' context Date: Tue, 7 Apr 2020 18:38:43 +0100 Message-Id: <20200407173847.1595-2-paul@xen.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200407173847.1595-1-paul@xen.org> References: <20200407173847.1595-1-paul@xen.org> MIME-Version: 1.0 X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Julien Grall , Wei Liu , Paul Durrant , Andrew Cooper , Paul Durrant , Ian Jackson , George Dunlap , Jan Beulich , Volodymyr Babchuk , =?utf-8?q?Roger_Pau_Monn?= =?utf-8?q?=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" To allow enlightened HVM guests (i.e. those that have PV drivers) to be migrated without their co-operation it will be necessary to transfer 'PV' state such as event channel state, grant entry state, etc. Currently there is a framework (entered via the hvm_save/load() functions) that allows a domain's 'HVM' (architectural) state to be transferred but 'PV' state is also common with pure PV guests and so this framework is not really suitable. This patch adds the new public header and low level implementation of a new common framework, entered via the domain_save/load() functions. Subsequent patches will introduce other parts of the framework, and code that will make use of it within the current version of the libxc migration stream. This patch also marks the HVM-only framework as deprecated in favour of the new framework. Signed-off-by: Paul Durrant --- Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Jan Beulich Cc: Julien Grall Cc: Stefano Stabellini Cc: Wei Liu Cc: Volodymyr Babchuk Cc: "Roger Pau Monné" v2: - Allow multi-stage save/load to avoid the need to double-buffer - Get rid of the masks and add an 'ignore' flag instead - Create copy function union to preserve const save buffer - Deprecate HVM-only framework --- xen/common/Makefile | 1 + xen/common/save.c | 329 +++++++++++++++++++++++++ xen/include/public/arch-arm/hvm/save.h | 5 + xen/include/public/arch-x86/hvm/save.h | 5 + xen/include/public/save.h | 84 +++++++ xen/include/xen/save.h | 152 ++++++++++++ 6 files changed, 576 insertions(+) create mode 100644 xen/common/save.c create mode 100644 xen/include/public/save.h create mode 100644 xen/include/xen/save.h diff --git a/xen/common/Makefile b/xen/common/Makefile index e8cde65370..90553ba5d7 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -37,6 +37,7 @@ obj-y += radix-tree.o obj-y += rbtree.o obj-y += rcupdate.o obj-y += rwlock.o +obj-y += save.o obj-y += shutdown.o obj-y += softirq.o obj-y += sort.o diff --git a/xen/common/save.c b/xen/common/save.c new file mode 100644 index 0000000000..6cdac3785b --- /dev/null +++ b/xen/common/save.c @@ -0,0 +1,329 @@ +/* + * save.c: Save and restore PV guest state common to all domain types. + * + * Copyright Amazon.com Inc. or its affiliates. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; If not, see . + */ + +#include + +union domain_copy_entry { + domain_write_entry write; + domain_read_entry read; +}; + +struct domain_context { + bool log; + struct domain_save_descriptor desc; + size_t data_len; + union domain_copy_entry copy; + void *priv; +}; + +static struct { + const char *name; + bool per_vcpu; + domain_save_handler save; + domain_load_handler load; +} handlers[DOMAIN_SAVE_CODE_MAX + 1]; + +void __init domain_register_save_type(unsigned int tc, const char *name, + bool per_vcpu, + domain_save_handler save, + domain_load_handler load) +{ + BUG_ON(tc > ARRAY_SIZE(handlers)); + + ASSERT(!handlers[tc].save); + ASSERT(!handlers[tc].load); + + handlers[tc].name = name; + handlers[tc].per_vcpu = per_vcpu; + handlers[tc].save = save; + handlers[tc].load = load; +} + +int domain_save_begin(struct domain_context *c, unsigned int tc, + const char *name, const struct vcpu *v, size_t len) +{ + int rc; + + if ( c->log ) + gdprintk(XENLOG_INFO, "%pv save: %s (%lu)\n", v, name, + (unsigned long)len); + + BUG_ON(tc != c->desc.typecode); + BUG_ON(v->vcpu_id != c->desc.vcpu_id); + + ASSERT(!c->data_len); + c->data_len = c->desc.length = len; + + rc = c->copy.write(c->priv, &c->desc, sizeof(c->desc)); + if ( rc ) + return rc; + + c->desc.length = 0; + + return 0; +} + +int domain_save_data(struct domain_context *c, const void *src, size_t len) +{ + if ( c->desc.length + len > c->data_len ) + return -ENOSPC; + + c->desc.length += len; + + return c->copy.write(c->priv, src, len); +} + +int domain_save_end(struct domain_context *c) +{ + /* + * If desc.length does not match the length specified in + * domain_save_begin(), there should have been more data. + */ + if ( c->desc.length != c->data_len ) + return -EIO; + + c->data_len = 0; + + return 0; +} + +int domain_save(struct domain *d, domain_write_entry write, void *priv, + bool dry_run) +{ + struct domain_context c = { + .copy.write = write, + .priv = priv, + .log = !dry_run, + }; + struct domain_save_header h = { + .magic = DOMAIN_SAVE_MAGIC, + .version = DOMAIN_SAVE_VERSION, + }; + struct domain_save_header e; + unsigned int i; + int rc; + + ASSERT(d != current->domain); + + if ( d->is_dying ) + return -EINVAL; + + domain_pause(d); + + c.desc.typecode = DOMAIN_SAVE_CODE(HEADER); + + rc = DOMAIN_SAVE_ENTRY(HEADER, &c, d->vcpu[0], &h, sizeof(h)); + if ( rc ) + goto out; + + for ( i = 0; i < ARRAY_SIZE(handlers); i++ ) + { + domain_save_handler save = handlers[i].save; + + if ( !save ) + continue; + + memset(&c.desc, 0, sizeof(c.desc)); + c.desc.typecode = i; + + if ( handlers[i].per_vcpu ) + { + struct vcpu *v; + + for_each_vcpu ( d, v ) + { + c.desc.vcpu_id = v->vcpu_id; + + rc = save(v, &c, dry_run); + if ( rc ) + goto out; + } + } + else + { + rc = save(d->vcpu[0], &c, dry_run); + if ( rc ) + goto out; + } + } + + memset(&c.desc, 0, sizeof(c.desc)); + c.desc.typecode = DOMAIN_SAVE_CODE(END); + + rc = DOMAIN_SAVE_ENTRY(END, &c, d->vcpu[0], &e, 0); + + out: + domain_unpause(d); + + return rc; +} + +int domain_load_begin(struct domain_context *c, unsigned int tc, + const char *name, const struct vcpu *v, size_t len, + bool exact) +{ + if ( c->log ) + gdprintk(XENLOG_INFO, "%pv load: %s (%lu)\n", v, name, + (unsigned long)len); + + BUG_ON(tc != c->desc.typecode); + BUG_ON(v->vcpu_id != c->desc.vcpu_id); + + if ( (exact && (len != c->desc.length)) || + (len < c->desc.length) ) + return -EINVAL; + + ASSERT(!c->data_len); + c->data_len = len; + + return 0; +} + +int domain_load_data(struct domain_context *c, void *dst, size_t len) +{ + size_t copy_len = min_t(size_t, len, c->desc.length); + int rc; + + if ( c->data_len < len ) + return -ENODATA; + + c->data_len -= len; + c->desc.length -= copy_len; + + rc = c->copy.read(c->priv, dst, copy_len); + if ( rc ) + return rc; + + /* Zero extend if the descriptor is exhausted */ + len -= copy_len; + if ( len ) + { + dst += copy_len; + memset(dst, 0, len); + } + + return 0; +} + +int domain_load_end(struct domain_context *c) +{ + /* If data_len is non-zero there is unread data */ + if ( c->data_len ) + return -EIO; + + return 0; +} + +int domain_load(struct domain *d, domain_read_entry read, void *priv) +{ + struct domain_context c = { + .copy.read = read, + .priv = priv, + .log = true, + }; + struct domain_save_header h; + int rc; + + ASSERT(d != current->domain); + + if ( d->is_dying ) + return -EINVAL; + + rc = c.copy.read(c.priv, &c.desc, sizeof(c.desc)); + if ( rc ) + return rc; + + if ( c.desc.typecode != DOMAIN_SAVE_CODE(HEADER) || c.desc.vcpu_id || + c.desc.flags ) + return -EINVAL; + + rc = DOMAIN_LOAD_ENTRY(HEADER, &c, d->vcpu[0], &h, sizeof(h), true); + if ( rc ) + return rc; + + if ( h.magic != DOMAIN_SAVE_MAGIC || h.version != DOMAIN_SAVE_VERSION ) + return -EINVAL; + + domain_pause(d); + + for (;;) + { + unsigned int i; + unsigned int flags; + domain_load_handler load; + struct vcpu *v; + + rc = c.copy.read(c.priv, &c.desc, sizeof(c.desc)); + if ( rc ) + break; + + rc = -EINVAL; + + flags = c.desc.flags; + if ( flags & ~DOMAIN_SAVE_FLAG_IGNORE ) + break; + + if ( c.desc.typecode == DOMAIN_SAVE_CODE(END) ) { + if ( !(flags & DOMAIN_SAVE_FLAG_IGNORE) ) + rc = DOMAIN_LOAD_ENTRY(END, &c, d->vcpu[0], NULL, 0, true); + + break; + } + + i = c.desc.typecode; + if ( i >= ARRAY_SIZE(handlers) ) + break; + + if ( (!handlers[i].per_vcpu && c.desc.vcpu_id) || + (c.desc.vcpu_id >= d->max_vcpus) ) + break; + + v = d->vcpu[c.desc.vcpu_id]; + + if ( flags & DOMAIN_SAVE_FLAG_IGNORE ) + { + /* Sink the data */ + rc = domain_load_entry(&c, c.desc.typecode, "IGNORED", + v, NULL, c.desc.length, true); + if ( rc ) + break; + + continue; + } + + load = handlers[i].load; + + rc = load ? load(v, &c) : -EOPNOTSUPP; + if ( rc ) + break; + } + + domain_unpause(d); + + return rc; +} + +/* + * 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/arch-arm/hvm/save.h b/xen/include/public/arch-arm/hvm/save.h index 75b8e65bcb..d5b0c15203 100644 --- a/xen/include/public/arch-arm/hvm/save.h +++ b/xen/include/public/arch-arm/hvm/save.h @@ -26,6 +26,11 @@ #ifndef __XEN_PUBLIC_HVM_SAVE_ARM_H__ #define __XEN_PUBLIC_HVM_SAVE_ARM_H__ +/* + * Further use of HVM state is deprecated. New state records should only + * be added to the domain state header: public/save.h + */ + #endif /* diff --git a/xen/include/public/arch-x86/hvm/save.h b/xen/include/public/arch-x86/hvm/save.h index 773a380bc2..e61e2dbcd7 100644 --- a/xen/include/public/arch-x86/hvm/save.h +++ b/xen/include/public/arch-x86/hvm/save.h @@ -648,6 +648,11 @@ struct hvm_msr { */ #define HVM_SAVE_CODE_MAX 20 +/* + * Further use of HVM state is deprecated. New state records should only + * be added to the domain state header: public/save.h + */ + #endif /* __XEN_PUBLIC_HVM_SAVE_X86_H__ */ /* diff --git a/xen/include/public/save.h b/xen/include/public/save.h new file mode 100644 index 0000000000..7e5f8752bd --- /dev/null +++ b/xen/include/public/save.h @@ -0,0 +1,84 @@ +/* + * save.h + * + * Structure definitions for common PV/HVM domain state that is held by + * Xen and must be saved along with the domain's memory. + * + * Copyright Amazon.com Inc. or its affiliates. + * + * 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. + */ + +#ifndef __XEN_PUBLIC_SAVE_H__ +#define __XEN_PUBLIC_SAVE_H__ + +#include "xen.h" + +/* Each entry is preceded by a descriptor */ +struct domain_save_descriptor { + uint16_t typecode; + /* + * Each entry will contain either to global or per-vcpu domain state. + * Entries relating to global state should have zero in this field. + */ + uint16_t vcpu_id; + uint32_t flags; + /* + * When restoring state this flag can be set in a descriptor to cause + * its content to be ignored. + * + * NOTE: It is invalid to set this flag for HEADER or END records (see + * below). + */ +#define _DOMAIN_SAVE_FLAG_IGNORE 0 +#define DOMAIN_SAVE_FLAG_IGNORE (1u << _DOMAIN_SAVE_FLAG_IGNORE) + + /* Entry length not including this descriptor */ + uint64_t length; +}; + +/* + * Each entry has a type associated with it. DECLARE_DOMAIN_SAVE_TYPE + * binds these things together. + */ +#define DECLARE_DOMAIN_SAVE_TYPE(_x, _code, _type) \ + struct __DOMAIN_SAVE_TYPE_##_x { char c[_code]; _type t; }; + +#define DOMAIN_SAVE_CODE(_x) \ + (sizeof(((struct __DOMAIN_SAVE_TYPE_##_x *)(0))->c)) +#define DOMAIN_SAVE_TYPE(_x) \ + typeof(((struct __DOMAIN_SAVE_TYPE_##_x *)(0))->t) + +/* Terminating entry */ +struct domain_save_end {}; +DECLARE_DOMAIN_SAVE_TYPE(END, 0, struct domain_save_end); + +#define DOMAIN_SAVE_MAGIC 0x53415645 +#define DOMAIN_SAVE_VERSION 0x00000001 + +/* Initial entry */ +struct domain_save_header { + uint32_t magic; /* Must be DOMAIN_SAVE_MAGIC */ + uint32_t version; /* Save format version */ +}; +DECLARE_DOMAIN_SAVE_TYPE(HEADER, 1, struct domain_save_header); + +#define DOMAIN_SAVE_CODE_MAX 1 + +#endif /* __XEN_PUBLIC_SAVE_H__ */ diff --git a/xen/include/xen/save.h b/xen/include/xen/save.h new file mode 100644 index 0000000000..879bbb4390 --- /dev/null +++ b/xen/include/xen/save.h @@ -0,0 +1,152 @@ +/* + * save.h: support routines for save/restore + * + * Copyright Amazon.com Inc. or its affiliates. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; If not, see . + */ + +#ifndef __XEN_SAVE_H__ +#define __XEN_SAVE_H__ + +#include +#include +#include + +#include +#include + +struct domain_context; + +int domain_save_begin(struct domain_context *c, unsigned int tc, + const char *name, const struct vcpu *v, size_t len); + +#define DOMAIN_SAVE_BEGIN(_x, _c, _v, _len) \ + domain_save_begin((_c), DOMAIN_SAVE_CODE(_x), #_x, (_v), (_len)) + +int domain_save_data(struct domain_context *c, const void *data, size_t len); +int domain_save_end(struct domain_context *c); + +static inline int domain_save_entry(struct domain_context *c, + unsigned int tc, const char *name, + const struct vcpu *v, const void *src, + size_t len) +{ + int rc; + + rc = domain_save_begin(c, tc, name, v, len); + if ( rc ) + return rc; + + rc = domain_save_data(c, src, len); + if ( rc ) + return rc; + + return domain_save_end(c); +} + +#define DOMAIN_SAVE_ENTRY(_x, _c, _v, _src, _len) \ + domain_save_entry((_c), DOMAIN_SAVE_CODE(_x), #_x, (_v), (_src), (_len)) + +int domain_load_begin(struct domain_context *c, unsigned int tc, + const char *name, const struct vcpu *v, size_t len, + bool exact); + +#define DOMAIN_LOAD_BEGIN(_x, _c, _v, _len, _exact) \ + domain_load_begin((_c), DOMAIN_SAVE_CODE(_x), #_x, (_v), (_len), \ + (_exact)); + +int domain_load_data(struct domain_context *c, void *data, size_t len); +int domain_load_end(struct domain_context *c); + +static inline int domain_load_entry(struct domain_context *c, + unsigned int tc, const char *name, + const struct vcpu *v, void *dst, + size_t len, bool exact) +{ + int rc; + + rc = domain_load_begin(c, tc, name, v, len, exact); + if ( rc ) + return rc; + + rc = domain_load_data(c, dst, len); + if ( rc ) + return rc; + + return domain_load_end(c); +} + +#define DOMAIN_LOAD_ENTRY(_x, _c, _v, _dst, _len, _exact) \ + domain_load_entry((_c), DOMAIN_SAVE_CODE(_x), #_x, (_v), (_dst), (_len), \ + (_exact)) + +/* + * The 'dry_run' flag indicates that the caller of domain_save() (see + * below) is not trying to actually acquire the data, only the size + * of the data. The save handler can therefore limit work to only that + * which is necessary to call DOMAIN_SAVE_BEGIN/ENTRY() with an accurate + * value for '_len'. + */ +typedef int (*domain_save_handler)(const struct vcpu *v, + struct domain_context *h, + bool dry_run); +typedef int (*domain_load_handler)(struct vcpu *v, + struct domain_context *h); + +void domain_register_save_type(unsigned int tc, const char *name, + bool per_vcpu, + domain_save_handler save, + domain_load_handler load); + +/* + * Register save and restore handlers. Save handlers will be invoked + * in order of DOMAIN_SAVE_CODE(). + */ +#define DOMAIN_REGISTER_SAVE_RESTORE(_x, _per_vcpu, _save, _load) \ +static int __init __domain_register_##_x##_save_restore(void) \ +{ \ + domain_register_save_type( \ + DOMAIN_SAVE_CODE(_x), \ + #_x, \ + (_per_vcpu), \ + &(_save), \ + &(_load)); \ + \ + return 0; \ +} \ +__initcall(__domain_register_##_x##_save_restore); + +/* Copy callback functions */ +typedef int (*domain_write_entry)(void *priv, const void *data, size_t len); +typedef int (*domain_read_entry)(void *priv, void *data, size_t len); + +/* + * Entry points: + * + * int domain_save(struct domain *d, domain_copy_entry copy, void *priv, + * bool dry_run); + * int domain_load(struct domain *d, domain_copy_entry copy, void *priv); + * + * write/read: This is a callback function provided by the caller that will + * be used to write to (in the save case) or read from (in the + * load case) the context buffer. + * priv: This is a pointer that will be passed to the copy function to + * allow it to identify the context buffer and the current state + * of the save or load operation. + */ +int domain_save(struct domain *d, domain_write_entry write, void *priv, + bool dry_run); +int domain_load(struct domain *d, domain_read_entry read, void *priv); + +#endif /* __XEN_SAVE_H__ */ From patchwork Tue Apr 7 17:38:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11478463 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B617092A for ; Tue, 7 Apr 2020 17:40:32 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8736620768 for ; Tue, 7 Apr 2020 17:40:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=xen.org header.i=@xen.org header.b="1HY+8lqR" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8736620768 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=xen.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBs-0000za-BC; Tue, 07 Apr 2020 17:39:12 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBq-0000yd-8Y for xen-devel@lists.xenproject.org; Tue, 07 Apr 2020 17:39:10 +0000 X-Inumbo-ID: a808f42c-78f6-11ea-8122-12813bfff9fa Received: from mail.xenproject.org (unknown [104.130.215.37]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id a808f42c-78f6-11ea-8122-12813bfff9fa; Tue, 07 Apr 2020 17:38:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org; s=20200302mail; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=Z1elA0lD7gZxiRrnC8vcJ37IU6sE2cBRKl8cN8x+k6w=; b=1HY+8lqR7v91p/05Us2yTfnmKA mfUjRfkmcMrDC2y4NJ/zuOw0QwodHnWuVp193ywwPo2p/mTA6xmm0XwoWuyUHqUOYzCyY1t+oSQwl fU560xZ4Vb1PtiCaQUO/wToZuonylFXPNNO5NwVuiwUmWIBiD97Y7svraykl4e9XZb98=; Received: from xenbits.xenproject.org ([104.239.192.120]) by mail.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBa-0000Jp-PJ; Tue, 07 Apr 2020 17:38:54 +0000 Received: from 54-240-197-232.amazon.com ([54.240.197.232] helo=u2f063a87eabd5f.cbg10.amazon.com) by xenbits.xenproject.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1jLsBa-00088J-GF; Tue, 07 Apr 2020 17:38:54 +0000 From: Paul Durrant To: xen-devel@lists.xenproject.org Subject: [PATCH v2 2/5] xen/common/domctl: introduce XEN_DOMCTL_get/setdomaincontext Date: Tue, 7 Apr 2020 18:38:44 +0100 Message-Id: <20200407173847.1595-3-paul@xen.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200407173847.1595-1-paul@xen.org> References: <20200407173847.1595-1-paul@xen.org> MIME-Version: 1.0 X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Julien Grall , Wei Liu , Paul Durrant , Andrew Cooper , Paul Durrant , Ian Jackson , George Dunlap , Jan Beulich , Daniel De Graaf Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" These domctls provide a mechanism to get and set domain context from the toolstack. Signed-off-by: Paul Durrant Reviewed-by: Julien Grall --- Cc: Daniel De Graaf Cc: Ian Jackson Cc: Wei Liu Cc: Andrew Cooper Cc: George Dunlap Cc: Jan Beulich Cc: Julien Grall Cc: Stefano Stabellini v2: - drop mask parameter - const-ify some more buffers --- tools/flask/policy/modules/xen.if | 4 +- tools/libxc/include/xenctrl.h | 5 ++ tools/libxc/xc_domain.c | 54 +++++++++++++ xen/common/domctl.c | 117 ++++++++++++++++++++++++++++ xen/include/public/domctl.h | 44 ++++++++++- xen/xsm/flask/hooks.c | 6 ++ xen/xsm/flask/policy/access_vectors | 4 + 7 files changed, 231 insertions(+), 3 deletions(-) diff --git a/tools/flask/policy/modules/xen.if b/tools/flask/policy/modules/xen.if index 8eb2293a52..2bc9db4f64 100644 --- a/tools/flask/policy/modules/xen.if +++ b/tools/flask/policy/modules/xen.if @@ -53,7 +53,7 @@ define(`create_domain_common', ` allow $1 $2:domain2 { set_cpu_policy settsc setscheduler setclaim set_vnumainfo get_vnumainfo cacheflush psr_cmt_op psr_alloc soft_reset - resource_map get_cpu_policy }; + resource_map get_cpu_policy setcontext }; allow $1 $2:security check_context; allow $1 $2:shadow enable; allow $1 $2:mmu { map_read map_write adjust memorymap physmap pinpage mmuext_op updatemp }; @@ -97,7 +97,7 @@ define(`migrate_domain_out', ` allow $1 $2:hvm { gethvmc getparam }; allow $1 $2:mmu { stat pageinfo map_read }; allow $1 $2:domain { getaddrsize getvcpucontext pause destroy }; - allow $1 $2:domain2 gettsc; + allow $1 $2:domain2 { gettsc getcontext }; allow $1 $2:shadow { enable disable logdirty }; ') diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index 58fa931de1..06ca8e9a74 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -867,6 +867,11 @@ int xc_domain_hvm_setcontext(xc_interface *xch, uint8_t *hvm_ctxt, uint32_t size); +int xc_domain_getcontext(xc_interface *xch, uint32_t domid, + void *ctxt_buf, size_t *size); +int xc_domain_setcontext(xc_interface *xch, uint32_t domid, + const void *ctxt_buf, size_t size); + /** * This function will return guest IO ABI protocol * diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 71829c2bce..212d1489dd 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -537,6 +537,60 @@ int xc_domain_hvm_setcontext(xc_interface *xch, return ret; } +int xc_domain_getcontext(xc_interface *xch, uint32_t domid, + void *ctxt_buf, size_t *size) +{ + int ret; + DECLARE_DOMCTL; + DECLARE_HYPERCALL_BOUNCE(ctxt_buf, *size, XC_HYPERCALL_BUFFER_BOUNCE_OUT); + + if ( xc_hypercall_bounce_pre(xch, ctxt_buf) ) + return -1; + + domctl.cmd = XEN_DOMCTL_getdomaincontext; + domctl.domain = domid; + domctl.u.getdomaincontext.size = *size; + set_xen_guest_handle(domctl.u.setdomaincontext.buffer, ctxt_buf); + + ret = do_domctl(xch, &domctl); + + xc_hypercall_bounce_post(xch, ctxt_buf); + + if ( ret ) + return ret; + + *size = domctl.u.getdomaincontext.size; + if ( *size != domctl.u.getdomaincontext.size ) + { + errno = EOVERFLOW; + return -1; + } + + return 0; +} + +int xc_domain_setcontext(xc_interface *xch, uint32_t domid, + const void *ctxt_buf, size_t size) +{ + int ret; + DECLARE_DOMCTL; + DECLARE_HYPERCALL_BOUNCE_IN(ctxt_buf, size); + + if ( xc_hypercall_bounce_pre(xch, ctxt_buf) ) + return -1; + + domctl.cmd = XEN_DOMCTL_setdomaincontext; + domctl.domain = domid; + domctl.u.setdomaincontext.size = size; + set_xen_guest_handle(domctl.u.setdomaincontext.buffer, ctxt_buf); + + ret = do_domctl(xch, &domctl); + + xc_hypercall_bounce_post(xch, ctxt_buf); + + return ret; +} + int xc_vcpu_getcontext(xc_interface *xch, uint32_t domid, uint32_t vcpu, diff --git a/xen/common/domctl.c b/xen/common/domctl.c index a69b3b59a8..2e5c6a46d9 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -358,6 +359,113 @@ static struct vnuma_info *vnuma_init(const struct xen_domctl_vnuma *uinfo, return ERR_PTR(ret); } +struct domctl_context +{ + void *buffer; + size_t len; + size_t cur; +}; + +static int accumulate_size(void *priv, const void *data, size_t len) +{ + struct domctl_context *c = priv; + + if ( c->len + len < c->len ) + return -EOVERFLOW; + + c->len += len; + + return 0; +} + +static int save_data(void *priv, const void *data, size_t len) +{ + struct domctl_context *c = priv; + + if ( c->len - c->cur < len ) + return -ENOSPC; + + memcpy(c->buffer + c->cur, data, len); + c->cur += len; + + return 0; +} + +static int getdomaincontext(struct domain *d, + struct xen_domctl_getdomaincontext *gdc) +{ + struct domctl_context c = { }; + int rc; + + if ( d == current->domain ) + return -EPERM; + + if ( guest_handle_is_null(gdc->buffer) ) /* query for buffer size */ + { + if ( gdc->size ) + return -EINVAL; + + /* dry run to acquire buffer size */ + rc = domain_save(d, accumulate_size, &c, true); + if ( rc ) + return rc; + + gdc->size = c.len; + return 0; + } + + c.len = gdc->size; + c.buffer = xmalloc_bytes(c.len); + if ( !c.buffer ) + return -ENOMEM; + + rc = domain_save(d, save_data, &c, false); + + gdc->size = c.cur; + if ( !rc && copy_to_guest(gdc->buffer, c.buffer, gdc->size) ) + rc = -EFAULT; + + xfree(c.buffer); + + return rc; +} + +static int load_data(void *priv, void *data, size_t len) +{ + struct domctl_context *c = priv; + + if ( c->len - c->cur < len ) + return -ENODATA; + + if ( data ) + memcpy(data, c->buffer + c->cur, len); + + c->cur += len; + + return 0; +} + +static int setdomaincontext(struct domain *d, + const struct xen_domctl_setdomaincontext *sdc) +{ + struct domctl_context c = { .len = sdc->size }; + int rc; + + if ( d == current->domain ) + return -EPERM; + + c.buffer = xmalloc_bytes(c.len); + if ( !c.buffer ) + return -ENOMEM; + + rc = !copy_from_guest(c.buffer, sdc->buffer, c.len) ? + domain_load(d, load_data, &c) : -EFAULT; + + xfree(c.buffer); + + return rc; +} + long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) { long ret = 0; @@ -942,6 +1050,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) copyback = 1; break; + case XEN_DOMCTL_getdomaincontext: + ret = getdomaincontext(d, &op->u.getdomaincontext); + copyback = !ret; + break; + + case XEN_DOMCTL_setdomaincontext: + ret = setdomaincontext(d, &op->u.setdomaincontext); + break; + default: ret = arch_do_domctl(op, d, u_domctl); break; diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 1ad34c35eb..8ab39acf0c 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -38,7 +38,7 @@ #include "hvm/save.h" #include "memory.h" -#define XEN_DOMCTL_INTERFACE_VERSION 0x00000012 +#define XEN_DOMCTL_INTERFACE_VERSION 0x00000013 /* * NB. xen_domctl.domain is an IN/OUT parameter for this operation. @@ -1129,6 +1129,44 @@ struct xen_domctl_vuart_op { */ }; +/* + * Get/Set domain PV context. The same struct xen_domctl_domaincontext + * is used for both commands but with slightly different field semantics + * as follows: + * + * XEN_DOMCTL_getdomaincontext + * --------------------------- + * + * buffer (IN): The buffer into which the context data should be + * copied, or NULL to query the buffer size that should + * be allocated. + * size (IN/OUT): If 'buffer' is NULL then the value passed in must be + * zero, and the value passed out will be the size of the + * buffer to allocate. + * If 'buffer' is non-NULL then the value passed in must + * be the size of the buffer into which data may be copied. + */ +struct xen_domctl_getdomaincontext { + uint64_t size; + XEN_GUEST_HANDLE_64(void) buffer; +}; + +/* XEN_DOMCTL_setdomaincontext + * --------------------------- + * + * buffer (IN): The buffer from which the context data should be + * copied. + * size (IN): The size of the buffer from which data may be copied. + * This data must include DOMAIN_SAVE_CODE_HEADER at the + * start and terminate with a DOMAIN_SAVE_CODE_END record. + * Any data beyond the DOMAIN_SAVE_CODE_END record will be + * ignored. + */ +struct xen_domctl_setdomaincontext { + uint64_t size; + XEN_GUEST_HANDLE_64(const_void) buffer; +}; + struct xen_domctl { uint32_t cmd; #define XEN_DOMCTL_createdomain 1 @@ -1210,6 +1248,8 @@ struct xen_domctl { #define XEN_DOMCTL_vuart_op 81 #define XEN_DOMCTL_get_cpu_policy 82 #define XEN_DOMCTL_set_cpu_policy 83 +#define XEN_DOMCTL_getdomaincontext 84 +#define XEN_DOMCTL_setdomaincontext 85 #define XEN_DOMCTL_gdbsx_guestmemio 1000 #define XEN_DOMCTL_gdbsx_pausevcpu 1001 #define XEN_DOMCTL_gdbsx_unpausevcpu 1002 @@ -1270,6 +1310,8 @@ struct xen_domctl { struct xen_domctl_monitor_op monitor_op; struct xen_domctl_psr_alloc psr_alloc; struct xen_domctl_vuart_op vuart_op; + struct xen_domctl_getdomaincontext getdomaincontext; + struct xen_domctl_setdomaincontext setdomaincontext; uint8_t pad[128]; } u; }; diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 8af8602b46..d94d0fc125 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -744,6 +744,12 @@ static int flask_domctl(struct domain *d, int cmd) case XEN_DOMCTL_get_cpu_policy: return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__GET_CPU_POLICY); + case XEN_DOMCTL_setdomaincontext: + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SETCONTEXT); + + case XEN_DOMCTL_getdomaincontext: + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__GETCONTEXT); + default: return avc_unknown_permission("domctl", cmd); } diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index c055c14c26..fccfb9de82 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -245,6 +245,10 @@ class domain2 resource_map # XEN_DOMCTL_get_cpu_policy get_cpu_policy +# XEN_DOMCTL_setdomaincontext + setcontext +# XEN_DOMCTL_getdomaincontext + getcontext } # Similar to class domain, but primarily contains domctls related to HVM domains From patchwork Tue Apr 7 17:38:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11478457 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C0C5C1392 for ; Tue, 7 Apr 2020 17:39:55 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9CD0020768 for ; Tue, 7 Apr 2020 17:39:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=xen.org header.i=@xen.org header.b="WDHfIR4+" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9CD0020768 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=xen.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBn-0000x2-24; Tue, 07 Apr 2020 17:39:07 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBl-0000wR-8M for xen-devel@lists.xenproject.org; Tue, 07 Apr 2020 17:39:05 +0000 X-Inumbo-ID: a7ccf22e-78f6-11ea-8122-12813bfff9fa Received: from mail.xenproject.org (unknown [104.130.215.37]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id a7ccf22e-78f6-11ea-8122-12813bfff9fa; Tue, 07 Apr 2020 17:38:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org; s=20200302mail; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=NoImRX3eY+SbLgUw7UBsBIQQ9vFVsWZzEUGCK32pEkU=; b=WDHfIR4+Ci6snrNcyyALiyBXHc 7GOixTx2dYdvSbRu4ZMfg9QzMWbnwB/R6lMaFdy34oD2LSnCHjKJAqsMEb8QaY21Tz/Tpie5MevAs H9gmVFMNc/yd2h9FYdijfeZ1VXo9CSAEBiHzPYmgLRk0/SVSvVECJxXSnJDvi5nFF48M=; Received: from xenbits.xenproject.org ([104.239.192.120]) by mail.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBb-0000Jv-QQ; Tue, 07 Apr 2020 17:38:55 +0000 Received: from 54-240-197-232.amazon.com ([54.240.197.232] helo=u2f063a87eabd5f.cbg10.amazon.com) by xenbits.xenproject.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1jLsBb-00088J-Hi; Tue, 07 Apr 2020 17:38:55 +0000 From: Paul Durrant To: xen-devel@lists.xenproject.org Subject: [PATCH v2 3/5] tools/misc: add xen-domctx to present domain context Date: Tue, 7 Apr 2020 18:38:45 +0100 Message-Id: <20200407173847.1595-4-paul@xen.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200407173847.1595-1-paul@xen.org> References: <20200407173847.1595-1-paul@xen.org> MIME-Version: 1.0 X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Paul Durrant , Ian Jackson , Wei Liu , Paul Durrant Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" This tool is analogous to 'xen-hvmctx' which presents HVM context. Subsequent patches will add 'dump' functions when new records are introduced. Signed-off-by: Paul Durrant --- Cc: Ian Jackson Cc: Wei Liu v2: - Change name from 'xen-ctx' to 'xen-domctx' --- .gitignore | 1 + tools/misc/Makefile | 4 ++ tools/misc/xen-domctx.c | 145 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 tools/misc/xen-domctx.c diff --git a/.gitignore b/.gitignore index 4ca679ddbc..744c0529bb 100644 --- a/.gitignore +++ b/.gitignore @@ -208,6 +208,7 @@ tools/misc/xen_cpuperf tools/misc/xen-cpuid tools/misc/xen-detect tools/misc/xen-diag +tools/misc/xen-domctx tools/misc/xen-tmem-list-parse tools/misc/xen-livepatch tools/misc/xenperf diff --git a/tools/misc/Makefile b/tools/misc/Makefile index 63947bfadc..ef25524354 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -30,6 +30,7 @@ INSTALL_SBIN += xenpm INSTALL_SBIN += xenwatchdogd INSTALL_SBIN += xen-livepatch INSTALL_SBIN += xen-diag +INSTALL_SBIN += xen-domctx INSTALL_SBIN += $(INSTALL_SBIN-y) # Everything to be installed in a private bin/ @@ -108,6 +109,9 @@ xen-livepatch: xen-livepatch.o xen-diag: xen-diag.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) +xen-domctx: xen-domctx.o + $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) + xen-lowmemd: xen-lowmemd.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenevtchn) $(LDLIBS_libxenctrl) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS) diff --git a/tools/misc/xen-domctx.c b/tools/misc/xen-domctx.c new file mode 100644 index 0000000000..d663522a8b --- /dev/null +++ b/tools/misc/xen-domctx.c @@ -0,0 +1,145 @@ +/* + * xen-domctx.c + * + * Print out domain save records in a human-readable way. + * + * Copyright Amazon.com Inc. or its affiliates. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static void *buf = NULL; +static size_t len, off; + +#define READ(_x) do { \ + if ( len - off < sizeof (_x) ) \ + { \ + fprintf(stderr, \ + "Error: need another %lu bytes, only %lu available\n", \ + sizeof(_x), len - off); \ + exit(1); \ + } \ + memcpy(&(_x), buf + off, sizeof (_x)); \ +} while (0) + +static void dump_header(struct domain_save_descriptor *desc) +{ + DOMAIN_SAVE_TYPE(HEADER) h; + READ(h); + printf(" HEADER: magic %#x, version %u\n", + h.magic, h.version); + + off += desc->length; +} + +static void dump_end(struct domain_save_descriptor *desc) +{ + DOMAIN_SAVE_TYPE(END) e; + READ(e); + printf(" END\n"); +} + +int main(int argc, char **argv) +{ + uint32_t domid; + unsigned int entry; + xc_interface *xch; + int rc; + + if ( argc != 2 || !argv[1] || (rc = atoi(argv[1])) < 0 ) + { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(1); + } + domid = rc; + + xch = xc_interface_open(0,0,0); + if ( !xch ) + { + fprintf(stderr, "Error: can't open libxc handle\n"); + exit(1); + } + + rc = xc_domain_getcontext(xch, domid, NULL, &len); + if ( rc < 0 ) + { + fprintf(stderr, "Error: can't get record length for dom %u: %s\n", + domid, strerror(errno)); + exit(1); + } + + buf = malloc(len); + if ( !buf ) + { + fprintf(stderr, "Error: can't allocate %lu bytes\n", len); + exit(1); + } + + rc = xc_domain_getcontext(xch, domid, buf, &len); + if ( rc < 0 ) + { + fprintf(stderr, "Error: can't get domain record for dom %u: %s\n", + domid, strerror(errno)); + exit(1); + } + off = 0; + + printf("Domain save records for d%u\n", domid); + + entry = 0; + for (;;) { + struct domain_save_descriptor desc; + + READ(desc); + printf("[%u] type %u v%u, length %lu\n", entry++, + desc.typecode, desc.vcpu_id, (unsigned long)desc.length); + off += sizeof(desc); + + switch (desc.typecode) + { + case DOMAIN_SAVE_CODE(HEADER): dump_header(&desc); break; + case DOMAIN_SAVE_CODE(END): dump_end(&desc); return 0; + default: + printf("Unknown type %u: skipping\n", desc.typecode); + off += desc.length; + break; + } + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ From patchwork Tue Apr 7 17:38:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11478455 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0004492A for ; Tue, 7 Apr 2020 17:39:19 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CF2EF20692 for ; Tue, 7 Apr 2020 17:39:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=xen.org header.i=@xen.org header.b="AXG13KXW" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CF2EF20692 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=xen.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBf-0000tI-Ap; Tue, 07 Apr 2020 17:38:59 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBe-0000tC-Sb for xen-devel@lists.xenproject.org; Tue, 07 Apr 2020 17:38:58 +0000 X-Inumbo-ID: a9098328-78f6-11ea-9e09-bc764e2007e4 Received: from mail.xenproject.org (unknown [104.130.215.37]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id a9098328-78f6-11ea-9e09-bc764e2007e4; Tue, 07 Apr 2020 17:38:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org; s=20200302mail; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=Ps875/EWiRlLqTbL2/+Wxcz2/Dd5l8riK/3CroagOVs=; b=AXG13KXWJn19cdDUsxn5hH5ABl 3zH4Mzm/3hDY3LiNP0x31d5U1G6k8taDV4mVvB7xC9czHJayCQe2hANh++MeovQluvPnrgfQ8EHTm pojFqePAurgx/dw9YXq1Q7lV+7e7sgsNrCU7RLo6+bkU8WWTPV8KtkxT6bLvX1uI0xWM=; Received: from xenbits.xenproject.org ([104.239.192.120]) by mail.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBd-0000K5-EN; Tue, 07 Apr 2020 17:38:57 +0000 Received: from 54-240-197-232.amazon.com ([54.240.197.232] helo=u2f063a87eabd5f.cbg10.amazon.com) by xenbits.xenproject.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1jLsBd-00088J-5a; Tue, 07 Apr 2020 17:38:57 +0000 From: Paul Durrant To: xen-devel@lists.xenproject.org Subject: [PATCH v2 4/5] common/domain: add a domain context record for shared_info... Date: Tue, 7 Apr 2020 18:38:46 +0100 Message-Id: <20200407173847.1595-5-paul@xen.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200407173847.1595-1-paul@xen.org> References: <20200407173847.1595-1-paul@xen.org> MIME-Version: 1.0 X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Julien Grall , Wei Liu , Paul Durrant , Andrew Cooper , Paul Durrant , Ian Jackson , George Dunlap , Jan Beulich Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" ... and update xen-domctx to dump some information describing the record. Signed-off-by: Paul Durrant --- Cc: Ian Jackson Cc: Wei Liu Cc: Andrew Cooper Cc: George Dunlap Cc: Jan Beulich Cc: Julien Grall Cc: Stefano Stabellini v2: - Drop the header change to define a 'Xen' page size and instead use a variable length struct now that the framework makes this is feasible - Guard use of 'has_32bit_shinfo' in common code with CONFIG_COMPAT --- tools/misc/xen-domctx.c | 11 ++++++ xen/common/domain.c | 81 +++++++++++++++++++++++++++++++++++++++ xen/include/public/save.h | 10 ++++- 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/tools/misc/xen-domctx.c b/tools/misc/xen-domctx.c index d663522a8b..a8d3922321 100644 --- a/tools/misc/xen-domctx.c +++ b/tools/misc/xen-domctx.c @@ -59,6 +59,16 @@ static void dump_header(struct domain_save_descriptor *desc) off += desc->length; } +static void dump_shared_info(struct domain_save_descriptor *desc) +{ + DOMAIN_SAVE_TYPE(SHARED_INFO) s; + READ(s); + printf(" SHARED_INFO: field_width %u buffer size: %lu\n", + s.field_width, desc->length - sizeof(s)); + + off += desc->length; +} + static void dump_end(struct domain_save_descriptor *desc) { DOMAIN_SAVE_TYPE(END) e; @@ -125,6 +135,7 @@ int main(int argc, char **argv) switch (desc.typecode) { case DOMAIN_SAVE_CODE(HEADER): dump_header(&desc); break; + case DOMAIN_SAVE_CODE(SHARED_INFO): dump_shared_info(&desc); break; case DOMAIN_SAVE_CODE(END): dump_end(&desc); return 0; default: printf("Unknown type %u: skipping\n", desc.typecode); diff --git a/xen/common/domain.c b/xen/common/domain.c index 3dcd73f67c..8b72462e07 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1646,6 +1647,86 @@ int continue_hypercall_on_cpu( return 0; } +static int save_shared_info(const struct vcpu *v, struct domain_context *c, + bool dry_run) +{ + struct domain *d = v->domain; + struct domain_shared_info_context ctxt = {}; + size_t hdr_size = offsetof(typeof(ctxt), buffer); + size_t size = hdr_size + PAGE_SIZE; + int rc; + + rc = DOMAIN_SAVE_BEGIN(SHARED_INFO, c, v, size); + if ( rc ) + return rc; + + if ( !dry_run ) + ctxt.field_width = +#ifdef CONFIG_COMPAT + has_32bit_shinfo(d) ? 4 : +#endif + 8; + + rc = domain_save_data(c, &ctxt, hdr_size); + if ( rc ) + return rc; + + rc = domain_save_data(c, d->shared_info, PAGE_SIZE); + if ( rc ) + return rc; + + return domain_save_end(c); +} + +static int load_shared_info(struct vcpu *v, struct domain_context *c) +{ + struct domain *d = v->domain; + struct domain_shared_info_context ctxt = {}; + size_t hdr_size = offsetof(typeof(ctxt), buffer); + size_t size = hdr_size + PAGE_SIZE; + unsigned int i; + int rc; + + rc = DOMAIN_LOAD_BEGIN(SHARED_INFO, c, v, size, true); + if ( rc ) + return rc; + + rc = domain_load_data(c, &ctxt, hdr_size); + if ( rc ) + return rc; + + for ( i = 0; i < ARRAY_SIZE(ctxt.pad); i++ ) + if ( ctxt.pad[i] ) + return -EINVAL; + + switch ( ctxt.field_width ) + { +#ifdef CONFIG_COMPAT + case 4: + d->arch.has_32bit_shinfo = 1; + break; +#endif + case 8: +#ifdef CONFIG_COMPAT + d->arch.has_32bit_shinfo = 0; +#endif + break; + + default: + rc = -EINVAL; + break; + } + + rc = domain_load_data(c, d->shared_info, PAGE_SIZE); + if ( rc ) + return rc; + + return domain_load_end(c); +} + +DOMAIN_REGISTER_SAVE_RESTORE(SHARED_INFO, false, save_shared_info, + load_shared_info); + /* * Local variables: * mode: C diff --git a/xen/include/public/save.h b/xen/include/public/save.h index 7e5f8752bd..ed994a8765 100644 --- a/xen/include/public/save.h +++ b/xen/include/public/save.h @@ -79,6 +79,14 @@ struct domain_save_header { }; DECLARE_DOMAIN_SAVE_TYPE(HEADER, 1, struct domain_save_header); -#define DOMAIN_SAVE_CODE_MAX 1 +struct domain_shared_info_context { + uint8_t field_width; + uint8_t pad[7]; + uint8_t buffer[]; /* Implementation specific size */ +}; + +DECLARE_DOMAIN_SAVE_TYPE(SHARED_INFO, 2, struct domain_shared_info_context); + +#define DOMAIN_SAVE_CODE_MAX 2 #endif /* __XEN_PUBLIC_SAVE_H__ */ From patchwork Tue Apr 7 17:38:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11478465 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B3C8692A for ; Tue, 7 Apr 2020 17:40:49 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8EBD320768 for ; Tue, 7 Apr 2020 17:40:49 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=xen.org header.i=@xen.org header.b="BvBtO5Y/" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8EBD320768 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=xen.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBw-00011q-L4; Tue, 07 Apr 2020 17:39:16 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBv-00011A-8j for xen-devel@lists.xenproject.org; Tue, 07 Apr 2020 17:39:15 +0000 X-Inumbo-ID: a9687fae-78f6-11ea-8122-12813bfff9fa Received: from mail.xenproject.org (unknown [104.130.215.37]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id a9687fae-78f6-11ea-8122-12813bfff9fa; Tue, 07 Apr 2020 17:38:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xen.org; s=20200302mail; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=Q2rIXcUFs3l8U7hmdpz4Jn++ooIAw0V/fXHD3NFbNzU=; b=BvBtO5Y/ntoShIdAIY+Mqo/JSK 92IGBsG3n140xv2nkusxnRR3vQWyG0fQ17AqE4fFbqzhiMnb2JJ4/2tT1bAKdgj940HMxph7XX1Oo PRr9P6/GdraH5wZRU/QJ27UShK40sSz4bpMdFSivXh0Gh6gpvDrWPOGHqG8gojLOLyWI=; Received: from xenbits.xenproject.org ([104.239.192.120]) by mail.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jLsBe-0000KD-FY; Tue, 07 Apr 2020 17:38:58 +0000 Received: from 54-240-197-232.amazon.com ([54.240.197.232] helo=u2f063a87eabd5f.cbg10.amazon.com) by xenbits.xenproject.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1jLsBe-00088J-71; Tue, 07 Apr 2020 17:38:58 +0000 From: Paul Durrant To: xen-devel@lists.xenproject.org Subject: [PATCH v2 5/5] tools/libxc: make use of domain context SHARED_INFO record... Date: Tue, 7 Apr 2020 18:38:47 +0100 Message-Id: <20200407173847.1595-6-paul@xen.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200407173847.1595-1-paul@xen.org> References: <20200407173847.1595-1-paul@xen.org> MIME-Version: 1.0 X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Paul Durrant , Ian Jackson , Wei Liu , Paul Durrant Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" ... in the save/restore code. This patch replaces direct mapping of the shared_info_frame (retrieved using XEN_DOMCTL_getdomaininfo) with save/load of the domain context SHARED_INFO record. No modifications are made to the definition of the migration stream at this point. Subsequent patches will define a record in the libxc domain image format for passing domain context and convert the save/restore code to use that. Signed-off-by: Paul Durrant --- Cc: Ian Jackson Cc: Wei Liu v2: - Re-based (now making use of DOMAIN_SAVE_FLAG_IGNORE) --- tools/libxc/xc_sr_common.h | 7 +++- tools/libxc/xc_sr_common_x86.c | 59 ++++++++++++++++++++++++++++++ tools/libxc/xc_sr_common_x86.h | 4 ++ tools/libxc/xc_sr_common_x86_pv.c | 53 +++++++++++++++++++++++++++ tools/libxc/xc_sr_common_x86_pv.h | 3 ++ tools/libxc/xc_sr_restore_x86_pv.c | 40 ++++++++------------ tools/libxc/xc_sr_save_x86_pv.c | 26 ++----------- tools/libxc/xg_save_restore.h | 1 + 8 files changed, 144 insertions(+), 49 deletions(-) diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h index 5dd51ccb15..db6519cdcc 100644 --- a/tools/libxc/xc_sr_common.h +++ b/tools/libxc/xc_sr_common.h @@ -287,6 +287,11 @@ struct xc_sr_context { struct /* x86 */ { + struct { + void *buffer; + unsigned int len; + } domain_context; + struct /* x86 PV guest. */ { /* 4 or 8; 32 or 64 bit domain */ @@ -314,7 +319,7 @@ struct xc_sr_context /* The guest pfns containing the p2m leaves */ xen_pfn_t *p2m_pfns; - /* Read-only mapping of guests shared info page */ + /* Pointer to shared_info (located in context buffer) */ shared_info_any_t *shinfo; /* p2m generation count for verifying validity of local p2m. */ diff --git a/tools/libxc/xc_sr_common_x86.c b/tools/libxc/xc_sr_common_x86.c index 011684df97..e87dc0f0f3 100644 --- a/tools/libxc/xc_sr_common_x86.c +++ b/tools/libxc/xc_sr_common_x86.c @@ -42,6 +42,65 @@ int handle_x86_tsc_info(struct xc_sr_context *ctx, struct xc_sr_record *rec) return 0; } +int x86_get_context(struct xc_sr_context *ctx) +{ + xc_interface *xch = ctx->xch; + size_t len = 0; + int rc; + + if ( ctx->x86.domain_context.buffer ) + { + ERROR("Domain context already present"); + return -1; + } + + rc = xc_domain_getcontext(xch, ctx->domid, NULL, &len); + if ( rc < 0 ) + { + PERROR("Unable to get size of domain context"); + return -1; + } + + ctx->x86.domain_context.buffer = malloc(len); + if ( ctx->x86.domain_context.buffer == NULL ) + { + PERROR("Unable to allocate memory for domain context"); + return -1; + } + + rc = xc_domain_getcontext(xch, ctx->domid, + ctx->x86.domain_context.buffer, &len); + if ( rc < 0 ) + { + PERROR("Unable to get domain context"); + return -1; + } + + ctx->x86.domain_context.len = len; + + return 0; +} + +int x86_set_context(struct xc_sr_context *ctx) +{ + xc_interface *xch = ctx->xch; + + if ( !ctx->x86.domain_context.buffer ) + { + ERROR("Domain context not present"); + return -1; + } + + return xc_domain_setcontext(xch, ctx->domid, + ctx->x86.domain_context.buffer, + ctx->x86.domain_context.len); +} + +void x86_cleanup(struct xc_sr_context *ctx) +{ + free(ctx->x86.domain_context.buffer); +} + /* * Local variables: * mode: C diff --git a/tools/libxc/xc_sr_common_x86.h b/tools/libxc/xc_sr_common_x86.h index ebc4355bd1..501c9e52ba 100644 --- a/tools/libxc/xc_sr_common_x86.h +++ b/tools/libxc/xc_sr_common_x86.h @@ -14,6 +14,10 @@ int write_x86_tsc_info(struct xc_sr_context *ctx); */ int handle_x86_tsc_info(struct xc_sr_context *ctx, struct xc_sr_record *rec); +int x86_get_context(struct xc_sr_context *ctx); +int x86_set_context(struct xc_sr_context *ctx); +void x86_cleanup(struct xc_sr_context *ctx); + #endif /* * Local variables: diff --git a/tools/libxc/xc_sr_common_x86_pv.c b/tools/libxc/xc_sr_common_x86_pv.c index d3d425cb82..7354fd6052 100644 --- a/tools/libxc/xc_sr_common_x86_pv.c +++ b/tools/libxc/xc_sr_common_x86_pv.c @@ -182,6 +182,59 @@ int x86_pv_map_m2p(struct xc_sr_context *ctx) return rc; } +int x86_pv_get_shinfo(struct xc_sr_context *ctx) +{ + unsigned int off = 0; + struct domain_save_descriptor *desc; + int rc; + + rc = x86_get_context(ctx); + if ( rc ) + return rc; + + do { + if ( ctx->x86.domain_context.len - off < sizeof(*desc) ) + return -1; + + desc = ctx->x86.domain_context.buffer + off; + off += sizeof(*desc); + + switch (desc->typecode) + { + case DOMAIN_SAVE_CODE(SHARED_INFO): + { + DOMAIN_SAVE_TYPE(SHARED_INFO) *s; + + if ( ctx->x86.domain_context.len - off < sizeof(*s) ) + return -1; + + s = ctx->x86.domain_context.buffer + off; + ctx->x86.pv.shinfo = (shared_info_any_t *)s->buffer; + /* fall through */ + } + case DOMAIN_SAVE_CODE(HEADER): + off += desc->length; + /* fall through */ + case DOMAIN_SAVE_CODE(END): + break; + default: + desc->flags |= DOMAIN_SAVE_FLAG_IGNORE; + off += desc->length; + break; + } + } while ( desc->typecode != DOMAIN_SAVE_CODE(END) ); + + if ( !ctx->x86.pv.shinfo ) + return -1; + + return 0; +} + +int x86_pv_set_shinfo(struct xc_sr_context *ctx) +{ + return ctx->x86.pv.shinfo ? x86_set_context(ctx) : -1; +} + /* * Local variables: * mode: C diff --git a/tools/libxc/xc_sr_common_x86_pv.h b/tools/libxc/xc_sr_common_x86_pv.h index 2ed03309af..01442f48fb 100644 --- a/tools/libxc/xc_sr_common_x86_pv.h +++ b/tools/libxc/xc_sr_common_x86_pv.h @@ -97,6 +97,9 @@ int x86_pv_domain_info(struct xc_sr_context *ctx); */ int x86_pv_map_m2p(struct xc_sr_context *ctx); +int x86_pv_get_shinfo(struct xc_sr_context *ctx); +int x86_pv_set_shinfo(struct xc_sr_context *ctx); + #endif /* * Local variables: diff --git a/tools/libxc/xc_sr_restore_x86_pv.c b/tools/libxc/xc_sr_restore_x86_pv.c index 904ccc462a..4dbc7f0da5 100644 --- a/tools/libxc/xc_sr_restore_x86_pv.c +++ b/tools/libxc/xc_sr_restore_x86_pv.c @@ -864,8 +864,7 @@ static int handle_shared_info(struct xc_sr_context *ctx, { xc_interface *xch = ctx->xch; unsigned int i; - int rc = -1; - shared_info_any_t *guest_shinfo = NULL; + int rc; const shared_info_any_t *old_shinfo = rec->data; if ( !ctx->x86.pv.restore.seen_pv_info ) @@ -878,39 +877,30 @@ static int handle_shared_info(struct xc_sr_context *ctx, { ERROR("X86_PV_SHARED_INFO record wrong size: length %u" ", expected 4096", rec->length); - goto err; + return -1; } - guest_shinfo = xc_map_foreign_range( - xch, ctx->domid, PAGE_SIZE, PROT_READ | PROT_WRITE, - ctx->dominfo.shared_info_frame); - if ( !guest_shinfo ) - { - PERROR("Failed to map Shared Info at mfn %#lx", - ctx->dominfo.shared_info_frame); - goto err; - } + rc = x86_pv_get_shinfo(ctx); + if ( rc ) + return rc; - MEMCPY_FIELD(guest_shinfo, old_shinfo, vcpu_info, ctx->x86.pv.width); - MEMCPY_FIELD(guest_shinfo, old_shinfo, arch, ctx->x86.pv.width); + MEMCPY_FIELD(ctx->x86.pv.shinfo, old_shinfo, vcpu_info, + ctx->x86.pv.width); + MEMCPY_FIELD(ctx->x86.pv.shinfo, old_shinfo, arch, ctx->x86.pv.width); - SET_FIELD(guest_shinfo, arch.pfn_to_mfn_frame_list_list, + SET_FIELD(ctx->x86.pv.shinfo, arch.pfn_to_mfn_frame_list_list, 0, ctx->x86.pv.width); - MEMSET_ARRAY_FIELD(guest_shinfo, evtchn_pending, 0, ctx->x86.pv.width); + MEMSET_ARRAY_FIELD(ctx->x86.pv.shinfo, evtchn_pending, 0, + ctx->x86.pv.width); for ( i = 0; i < XEN_LEGACY_MAX_VCPUS; i++ ) - SET_FIELD(guest_shinfo, vcpu_info[i].evtchn_pending_sel, + SET_FIELD(ctx->x86.pv.shinfo, vcpu_info[i].evtchn_pending_sel, 0, ctx->x86.pv.width); - MEMSET_ARRAY_FIELD(guest_shinfo, evtchn_mask, 0xff, ctx->x86.pv.width); - - rc = 0; + MEMSET_ARRAY_FIELD(ctx->x86.pv.shinfo, evtchn_mask, 0xff, + ctx->x86.pv.width); - err: - if ( guest_shinfo ) - munmap(guest_shinfo, PAGE_SIZE); - - return rc; + return x86_pv_set_shinfo(ctx); } /* restore_ops function. */ diff --git a/tools/libxc/xc_sr_save_x86_pv.c b/tools/libxc/xc_sr_save_x86_pv.c index f3ccf5bb4b..7c4fcffa92 100644 --- a/tools/libxc/xc_sr_save_x86_pv.c +++ b/tools/libxc/xc_sr_save_x86_pv.c @@ -9,25 +9,6 @@ static inline bool is_canonical_address(xen_vaddr_t vaddr) return ((int64_t)vaddr >> 47) == ((int64_t)vaddr >> 63); } -/* - * Maps the guests shared info page. - */ -static int map_shinfo(struct xc_sr_context *ctx) -{ - xc_interface *xch = ctx->xch; - - ctx->x86.pv.shinfo = xc_map_foreign_range( - xch, ctx->domid, PAGE_SIZE, PROT_READ, ctx->dominfo.shared_info_frame); - if ( !ctx->x86.pv.shinfo ) - { - PERROR("Failed to map shared info frame at mfn %#lx", - ctx->dominfo.shared_info_frame); - return -1; - } - - return 0; -} - /* * Copy a list of mfns from a guest, accounting for differences between guest * and toolstack width. Can fail if truncation would occur. @@ -1041,7 +1022,7 @@ static int x86_pv_setup(struct xc_sr_context *ctx) if ( rc ) return rc; - rc = map_shinfo(ctx); + rc = x86_pv_get_shinfo(ctx); if ( rc ) return rc; @@ -1112,12 +1093,11 @@ static int x86_pv_cleanup(struct xc_sr_context *ctx) if ( ctx->x86.pv.p2m ) munmap(ctx->x86.pv.p2m, ctx->x86.pv.p2m_frames * PAGE_SIZE); - if ( ctx->x86.pv.shinfo ) - munmap(ctx->x86.pv.shinfo, PAGE_SIZE); - if ( ctx->x86.pv.m2p ) munmap(ctx->x86.pv.m2p, ctx->x86.pv.nr_m2p_frames * PAGE_SIZE); + x86_cleanup(ctx); + return 0; } diff --git a/tools/libxc/xg_save_restore.h b/tools/libxc/xg_save_restore.h index 303081df0d..296b523963 100644 --- a/tools/libxc/xg_save_restore.h +++ b/tools/libxc/xg_save_restore.h @@ -19,6 +19,7 @@ #include #include +#include /* ** We process save/restore/migrate in batches of pages; the below