From: Juergen Gross <jgross@suse.com>
To: xen-devel@lists.xenproject.org
Cc: Juergen Gross <jgross@suse.com>,
andrew.cooper3@citrix.com, dfaggioli@suse.com, jbeulich@suse.com
Subject: [PATCH v3 10/17] x86: allocate per-vcpu stacks for interrupt entries
Date: Fri, 9 Feb 2018 15:01:44 +0100 [thread overview]
Message-ID: <20180209140151.24714-11-jgross@suse.com> (raw)
In-Reply-To: <20180209140151.24714-1-jgross@suse.com>
In case of XPTI being active for a pv-domain allocate and initialize
per-vcpu stacks. The stacks are added to the per-domain mappings of
the pv-domain.
Signed-off-by: Juergen Gross <jgross@suse.com>
---
V3:
- move xpti code to xpti.c
- directly modify page table entries as needed for stub and stack
page (Jan Beulich)
- use one page for all stacks and TSS
- remap global stub instead allocating one for each vcpu
---
xen/arch/x86/pv/domain.c | 2 +
xen/arch/x86/pv/xpti.c | 117 +++++++++++++++++++++++++++++++++++++++---
xen/include/asm-x86/config.h | 13 ++++-
xen/include/asm-x86/current.h | 49 +++++++++++++-----
xen/include/asm-x86/domain.h | 3 ++
xen/include/asm-x86/pv/mm.h | 2 +
6 files changed, 166 insertions(+), 20 deletions(-)
diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c
index a007af94dd..550fbbf0fe 100644
--- a/xen/arch/x86/pv/domain.c
+++ b/xen/arch/x86/pv/domain.c
@@ -120,6 +120,8 @@ void pv_vcpu_destroy(struct vcpu *v)
pv_destroy_gdt_ldt_l1tab(v);
xfree(v->arch.pv_vcpu.trap_ctxt);
v->arch.pv_vcpu.trap_ctxt = NULL;
+
+ xpti_vcpu_destroy(v);
}
int pv_vcpu_initialise(struct vcpu *v)
diff --git a/xen/arch/x86/pv/xpti.c b/xen/arch/x86/pv/xpti.c
index 0b17d77d74..1356541804 100644
--- a/xen/arch/x86/pv/xpti.c
+++ b/xen/arch/x86/pv/xpti.c
@@ -19,13 +19,28 @@
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
+#include <xen/domain_page.h>
#include <xen/errno.h>
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/sched.h>
+#define XPTI_STACK_SIZE 512
+#define XPTI_STACK_N (XPTI_STACK_SIZE / 8)
+
+struct xpti_stack {
+ struct tss_struct tss;
+ char pad[PAGE_SIZE - sizeof(struct cpu_info) - sizeof(struct tss_struct) -
+ XPTI_STACK_SIZE * 4];
+ uint64_t df_stack[XPTI_STACK_N];
+ uint64_t nmi_stack[XPTI_STACK_N];
+ uint64_t mce_stack[XPTI_STACK_N];
+ uint64_t primary_stack[XPTI_STACK_N];
+ struct cpu_info cpu_info;
+};
+
struct xpti_domain {
- int pad;
+ l1_pgentry_t **perdom_l1tab;
};
static __read_mostly enum {
@@ -64,14 +79,92 @@ custom_runtime_param("xpti", parse_xpti);
void xpti_domain_destroy(struct domain *d)
{
- xfree(d->arch.pv_domain.xpti);
+ struct xpti_domain *xd = d->arch.pv_domain.xpti;
+
+ if ( !xd )
+ return;
+
+ xfree(xd->perdom_l1tab);
+ xfree(xd);
d->arch.pv_domain.xpti = NULL;
}
+void xpti_vcpu_destroy(struct vcpu *v)
+{
+ if ( v->domain->arch.pv_domain.xpti )
+ {
+ free_xenheap_page(v->arch.pv_vcpu.stack_regs);
+ v->arch.pv_vcpu.stack_regs = NULL;
+ destroy_perdomain_mapping(v->domain, XPTI_START(v), STACK_PAGES);
+ }
+}
+
+static int xpti_vcpu_init(struct vcpu *v)
+{
+ struct domain *d = v->domain;
+ struct xpti_domain *xd = d->arch.pv_domain.xpti;
+ void *ptr;
+ struct cpu_info *info;
+ struct xpti_stack *stack;
+ struct tss_struct *tss;
+ l1_pgentry_t *pl1e;
+ unsigned int i;
+ int rc;
+
+ /* Populate page tables. */
+ rc = create_perdomain_mapping(d, XPTI_START(v), STACK_PAGES,
+ xd->perdom_l1tab, NULL);
+ if ( rc )
+ goto done;
+ pl1e = xd->perdom_l1tab[l2_table_offset(XPTI_START(v))] +
+ l1_table_offset(XPTI_START(v));
+
+ /* Map stacks and TSS. */
+ rc = create_perdomain_mapping(d, XPTI_TSS(v), 1,
+ NULL, NIL(struct page_info *));
+ if ( rc )
+ goto done;
+
+ ptr = alloc_xenheap_page();
+ if ( !ptr )
+ {
+ rc = -ENOMEM;
+ goto done;
+ }
+ clear_page(ptr);
+ l1e_write(pl1e + STACK_PAGES - 1,
+ l1e_from_pfn(virt_to_mfn(ptr), __PAGE_HYPERVISOR_RW));
+ info = (struct cpu_info *)((unsigned long)ptr + PAGE_SIZE) - 1;
+ info->flags = ON_VCPUSTACK;
+ v->arch.pv_vcpu.stack_regs = &info->guest_cpu_user_regs;
+
+ /* stack just used for generating the correct addresses. */
+ stack = (struct xpti_stack *)XPTI_TSS(v);
+ tss = ptr;
+ tss->rsp0 = (unsigned long)&stack->cpu_info.guest_cpu_user_regs.es;
+ tss->rsp1 = 0x8600111111111111ul; /* poison */
+ tss->rsp2 = 0x8600111111111111ul; /* poison */
+ tss->ist[IST_MCE - 1] = (unsigned long)&stack->mce_stack[XPTI_STACK_N];
+ tss->ist[IST_DF - 1] = (unsigned long)&stack->df_stack[XPTI_STACK_N];
+ tss->ist[IST_NMI - 1] = (unsigned long)&stack->nmi_stack[XPTI_STACK_N];
+ for ( i = IST_MAX; i < ARRAY_SIZE(tss->ist); i++ )
+ tss->ist[i] = 0x8600111111111111ul; /* poison */
+ tss->bitmap = IOBMP_INVALID_OFFSET;
+
+ /* Map stub trampolines. */
+ l1e_write(pl1e + STACK_PAGES - 2,
+ l1e_from_pfn(virt_to_mfn(xpti_lstar), __PAGE_HYPERVISOR_RX));
+
+ done:
+ return rc;
+}
+
int xpti_domain_init(struct domain *d)
{
bool xpti = false;
- int ret = 0;
+ int ret = -ENOMEM;
+ struct vcpu *v;
+ struct xpti_domain *xd;
if ( !is_pv_domain(d) || is_pv_32bit_domain(d) )
return 0;
@@ -96,11 +189,21 @@ int xpti_domain_init(struct domain *d)
if ( !xpti )
return 0;
- d->arch.pv_domain.xpti = xmalloc(struct xpti_domain);
- if ( !d->arch.pv_domain.xpti )
- {
- ret = -ENOMEM;
+ xd = xzalloc(struct xpti_domain);
+ if ( !xd )
goto done;
+ d->arch.pv_domain.xpti = xd;
+
+ xd->perdom_l1tab = xzalloc_array(l1_pgentry_t *,
+ l2_table_offset((d->max_vcpus - 1) << XPTI_VA_SHIFT) + 1);
+ if ( !xd->perdom_l1tab )
+ goto done;
+
+ for_each_vcpu( d, v )
+ {
+ ret = xpti_vcpu_init(v);
+ if ( ret )
+ goto done;
}
printk("Enabling Xen Pagetable protection (XPTI) for Domain %d\n",
diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h
index 9ef9d03ca7..b563a2f85b 100644
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -66,6 +66,7 @@
#endif
#define STACK_ORDER 3
+#define STACK_PAGES (1 << STACK_ORDER)
#define STACK_SIZE (PAGE_SIZE << STACK_ORDER)
#define TRAMPOLINE_STACK_SPACE PAGE_SIZE
@@ -202,7 +203,7 @@ extern unsigned char boot_edid_info[128];
/* Slot 260: per-domain mappings (including map cache). */
#define PERDOMAIN_VIRT_START (PML4_ADDR(260))
#define PERDOMAIN_SLOT_MBYTES (PML4_ENTRY_BYTES >> (20 + PAGETABLE_ORDER))
-#define PERDOMAIN_SLOTS 3
+#define PERDOMAIN_SLOTS 4
#define PERDOMAIN_VIRT_SLOT(s) (PERDOMAIN_VIRT_START + (s) * \
(PERDOMAIN_SLOT_MBYTES << 20))
/* Slot 261: machine-to-phys conversion table (256GB). */
@@ -310,6 +311,16 @@ extern unsigned long xen_phys_start;
#define ARG_XLAT_START(v) \
(ARG_XLAT_VIRT_START + ((v)->vcpu_id << ARG_XLAT_VA_SHIFT))
+/* Per-vcpu XPTI pages. The fourth per-domain-mapping sub-area. */
+#define XPTI_VIRT_START PERDOMAIN_VIRT_SLOT(3)
+#define XPTI_VA_SHIFT (PAGE_SHIFT + STACK_ORDER)
+#define XPTI_TRAMPOLINE_OFF ((STACK_PAGES - 2) << PAGE_SHIFT)
+#define XPTI_TSS_OFF ((STACK_PAGES - 1) << PAGE_SHIFT)
+#define XPTI_START(v) (XPTI_VIRT_START + \
+ ((v)->vcpu_id << XPTI_VA_SHIFT))
+#define XPTI_TRAMPOLINE(v) (XPTI_START(v) + XPTI_TRAMPOLINE_OFF)
+#define XPTI_TSS(v) (XPTI_START(v) + XPTI_TSS_OFF)
+
#define NATIVE_VM_ASSIST_VALID ((1UL << VMASST_TYPE_4gb_segments) | \
(1UL << VMASST_TYPE_4gb_segments_notify) | \
(1UL << VMASST_TYPE_writable_pagetables) | \
diff --git a/xen/include/asm-x86/current.h b/xen/include/asm-x86/current.h
index 83d226a1ba..5963114e08 100644
--- a/xen/include/asm-x86/current.h
+++ b/xen/include/asm-x86/current.h
@@ -12,7 +12,7 @@
#include <asm/page.h>
/*
- * Xen's cpu stacks are 8 pages (8-page aligned), arranged as:
+ * Xen's physical cpu stacks are 8 pages (8-page aligned), arranged as:
*
* 7 - Primary stack (with a struct cpu_info at the top)
* 6 - Primary stack
@@ -25,6 +25,19 @@
*/
/*
+ * The vcpu stacks used for XPTI are 8-page aligned in virtual address space
+ * like the physical cpu stacks, but most of that area is unpopulated.
+ * As each stack needs only space for the interrupted context and (in case
+ * of the primary stack) maybe a cpu_info structure, all stacks can be put
+ * into a single page. The Syscall trampolines are mapped directly below the
+ * stack page.
+ *
+ * 7 - Primary stack (with a struct cpu_info at the top), IST stacks and TSS
+ * 6 - Syscall trampolines
+ * 0 - 5 unused
+ */
+
+/*
* Identify which stack page the stack pointer is on. Returns an index
* as per the comment above.
*/
@@ -37,17 +50,29 @@ struct vcpu;
struct cpu_info {
struct cpu_user_regs guest_cpu_user_regs;
- unsigned int processor_id;
- struct vcpu *current_vcpu;
- unsigned long per_cpu_offset;
- unsigned long cr4;
-
- /* See asm-x86/spec_ctrl_asm.h for usage. */
- unsigned int shadow_spec_ctrl;
- bool use_shadow_spec_ctrl;
- uint8_t bti_ist_info;
-
- unsigned long __pad;
+ union {
+ /* per physical cpu mapping */
+ struct {
+ struct vcpu *current_vcpu;
+ unsigned long per_cpu_offset;
+ unsigned long cr4;
+
+ /* See asm-x86/spec_ctrl_asm.h for usage. */
+ unsigned int shadow_spec_ctrl;
+ bool use_shadow_spec_ctrl;
+ uint8_t bti_ist_info;
+ unsigned long p_pad;
+ };
+ /* per vcpu mapping (xpti) */
+ struct {
+ unsigned long v_pad[4];
+ unsigned long stack_bottom_cpu;
+ };
+ };
+ unsigned int processor_id; /* per physical cpu mapping only */
+ unsigned int flags;
+#define ON_VCPUSTACK 0x00000001
+#define VCPUSTACK_ACTIVE 0x00000002
/* get_stack_bottom() must be 16-byte aligned */
};
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index b33c286807..1a4e92481c 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -505,6 +505,9 @@ struct pv_vcpu
/* Deferred VA-based update state. */
bool_t need_update_runstate_area;
struct vcpu_time_info pending_system_time;
+
+ /* If XPTI is active: pointer to user regs on stack. */
+ struct cpu_user_regs *stack_regs;
};
typedef enum __packed {
diff --git a/xen/include/asm-x86/pv/mm.h b/xen/include/asm-x86/pv/mm.h
index dfac89df0b..34c51bcfba 100644
--- a/xen/include/asm-x86/pv/mm.h
+++ b/xen/include/asm-x86/pv/mm.h
@@ -31,6 +31,7 @@ void pv_destroy_gdt(struct vcpu *v);
bool pv_map_ldt_shadow_page(unsigned int off);
bool pv_destroy_ldt(struct vcpu *v);
+void xpti_vcpu_destroy(struct vcpu *v);
int xpti_domain_init(struct domain *d);
void xpti_domain_destroy(struct domain *d);
@@ -65,6 +66,7 @@ static inline bool pv_map_ldt_shadow_page(unsigned int off) { return false; }
static inline bool pv_destroy_ldt(struct vcpu *v)
{ ASSERT_UNREACHABLE(); return false; }
+static inline void xpti_vcpu_init(struct vcpu *v) { }
static inline int xpti_domain_init(struct domain *d) { return 0; }
static inline void xpti_domain_destroy(struct domain *d) { }
--
2.13.6
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel
next prev parent reply other threads:[~2018-02-09 14:02 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-09 14:01 [PATCH v3 00/17] Alternative Meltdown mitigation Juergen Gross
2018-02-09 14:01 ` [PATCH v3 01/17] x86: don't use hypervisor stack size for dumping guest stacks Juergen Gross
2018-02-09 14:01 ` [PATCH v3 02/17] x86: do a revert of e871e80c38547d9faefc6604532ba3e985e65873 Juergen Gross
2018-02-13 10:14 ` Jan Beulich
2018-02-09 14:01 ` [PATCH v3 03/17] x86: revert 5784de3e2067ed73efc2fe42e62831e8ae7f46c4 Juergen Gross
2018-02-09 14:01 ` [PATCH v3 04/17] x86: don't access saved user regs via rsp in trap handlers Juergen Gross
2018-02-09 14:01 ` [PATCH v3 05/17] x86: add a xpti command line parameter Juergen Gross
2018-02-09 14:01 ` [PATCH v3 06/17] x86: allow per-domain mappings without NX bit or with specific mfn Juergen Gross
2018-02-09 14:01 ` [PATCH v3 07/17] xen/x86: split _set_tssldt_desc() into ldt and tss specific functions Juergen Gross
2018-02-09 14:01 ` [PATCH v3 08/17] x86: add support for spectre mitigation with local thunk Juergen Gross
2018-02-09 14:01 ` [PATCH v3 09/17] x86: create syscall stub for per-domain mapping Juergen Gross
2018-02-09 14:01 ` Juergen Gross [this message]
2018-02-09 14:01 ` [PATCH v3 11/17] x86: modify interrupt handlers to support stack switching Juergen Gross
2018-02-09 14:01 ` [PATCH v3 12/17] x86: activate per-vcpu stacks in case of xpti Juergen Gross
2018-02-09 14:01 ` [PATCH v3 13/17] x86: allocate hypervisor L4 page table for XPTI Juergen Gross
2018-02-09 14:01 ` [PATCH v3 14/17] xen: add domain pointer to fill_ro_mpt() and zap_ro_mpt() functions Juergen Gross
2018-02-09 14:01 ` [PATCH v3 15/17] x86: fill XPTI shadow pages and keep them in sync with guest L4 Juergen Gross
2018-02-09 14:01 ` [PATCH v3 16/17] x86: do page table switching when entering/leaving hypervisor Juergen Gross
2018-02-09 14:01 ` [PATCH v3 17/17] x86: hide most hypervisor mappings in XPTI shadow page tables Juergen Gross
2018-02-12 17:54 ` [PATCH v3 00/17] Alternative Meltdown mitigation Dario Faggioli
2018-02-13 11:36 ` Juergen Gross
2018-02-13 14:16 ` Jan Beulich
[not found] ` <5A83014E02000078001A7619@suse.com>
2018-02-13 14:29 ` Juergen Gross
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180209140151.24714-11-jgross@suse.com \
--to=jgross@suse.com \
--cc=andrew.cooper3@citrix.com \
--cc=dfaggioli@suse.com \
--cc=jbeulich@suse.com \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).