From patchwork Mon Apr 10 13:27:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Liu X-Patchwork-Id: 9672739 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A09F460244 for ; Mon, 10 Apr 2017 14:08:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8D4B528450 for ; Mon, 10 Apr 2017 14:08:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 81CE42846C; Mon, 10 Apr 2017 14:08:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 566A528450 for ; Mon, 10 Apr 2017 14:08:57 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cxZxN-000363-49; Mon, 10 Apr 2017 14:06:13 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cxZxL-000354-Md for xen-devel@lists.xenproject.org; Mon, 10 Apr 2017 14:06:11 +0000 Received: from [85.158.143.35] by server-10.bemta-6.messagelabs.com id 03/85-13192-3519BE85; Mon, 10 Apr 2017 14:06:11 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprAIsWRWlGSWpSXmKPExsXitHRDpG7QxNc RBns2Clp83zKZyYHR4/CHKywBjFGsmXlJ+RUJrBm7mtawFuyfz1jR+p2jgXFrThcjJ4eEgL/E 08VvmUBsNgFliZ+dvWwgtoiAnkTTgeeMIDazQJ7E2dWLWLsYOTiEBQIkOk6Xg4RZBFQllk0+w Qpi8wpYSGyf1ckEMVJeYlfbRbA4p4ClxMZ918BsIaCaKx92sEHYChId048xQfQKSpyc+YQFYp WExMEXL5gnMPLOQpKahSS1gJFpFaNGcWpRWWqRrpGJXlJRZnpGSW5iZo6uoYGZXm5qcXFiemp OYlKxXnJ+7iZGYOgwAMEOxn0fIw8xSnIwKYnyplu+jhDiS8pPqcxILM6ILyrNSS0+xCjDwaEk wdszASgnWJSanlqRlpkDDGKYtAQHj5IIbxVImre4IDG3ODMdInWKUZfj3dIP75mEWPLy81Klx Hl7QYoEQIoySvPgRsAi6hKjrJQwLyPQUUI8BalFuZklqPKvGMU5GJWEeZNApvBk5pXAbXoFdA QT0BFndr0EOaIkESEl1cCYKN678PESf7sNa5nOW86YfOn1r9QLx/9oRazLiLJ2mSUse15a9ar cSo6c7vTwWv/gZ+ZfDjXWbrH/s7P5iKuB75yTbyo2rYjY80tq8vblq4vjNr6x3L5lolN5TPKx Z8c+35zW36LiqrFXZcEayeBrC7T/ZJ5rvxl3SnkB//L6iR6V0qLHhLkklFiKMxINtZiLihMB/ AWjhaMCAAA= X-Env-Sender: prvs=266623ab3=wei.liu2@citrix.com X-Msg-Ref: server-5.tower-21.messagelabs.com!1491833167!55079064!2 X-Originating-IP: [66.165.176.89] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni44OSA9PiAyMDMwMDc=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.4.12; banners=-,-,- X-VirusChecked: Checked Received: (qmail 58831 invoked from network); 10 Apr 2017 14:06:09 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-5.tower-21.messagelabs.com with RC4-SHA encrypted SMTP; 10 Apr 2017 14:06:09 -0000 X-IronPort-AV: E=Sophos;i="5.37,182,1488844800"; d="scan'208";a="418326547" From: Wei Liu To: Xen-devel Date: Mon, 10 Apr 2017 14:27:16 +0100 Message-ID: <20170410132716.31610-9-wei.liu2@citrix.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170410132716.31610-1-wei.liu2@citrix.com> References: <20170410132716.31610-1-wei.liu2@citrix.com> MIME-Version: 1.0 Cc: Andrew Cooper , Wei Liu , Jan Beulich Subject: [Xen-devel] [PATCH for-next 8/8] x86/domain: move HVM specific code to hvm/domain.c X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP There is only one function arch_set_info_hvm_guest is moved. The check_segment function is also moved since arch_set_info_hvm_guest is the only user. No functional change. Signed-off-by: Wei Liu Acked-by: Jan Beulich --- xen/arch/x86/domain.c | 291 ----------------------------------------- xen/arch/x86/hvm/Makefile | 1 + xen/arch/x86/hvm/domain.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+), 291 deletions(-) create mode 100644 xen/arch/x86/hvm/domain.c diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 4a2363fc96..80a86e1ba2 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1060,297 +1060,6 @@ int arch_set_info_guest( #undef c } -static inline int check_segment(struct segment_register *reg, - enum x86_segment seg) -{ - - if ( reg->attr.fields.pad != 0 ) - { - gprintk(XENLOG_ERR, "Segment attribute bits 12-15 are not zero\n"); - return -EINVAL; - } - - if ( reg->attr.bytes == 0 ) - { - if ( seg != x86_seg_ds && seg != x86_seg_es ) - { - gprintk(XENLOG_ERR, "Null selector provided for CS, SS or TR\n"); - return -EINVAL; - } - return 0; - } - - if ( seg == x86_seg_tr ) - { - if ( reg->attr.fields.s ) - { - gprintk(XENLOG_ERR, "Code or data segment provided for TR\n"); - return -EINVAL; - } - - if ( reg->attr.fields.type != SYS_DESC_tss_busy ) - { - gprintk(XENLOG_ERR, "Non-32-bit-TSS segment provided for TR\n"); - return -EINVAL; - } - } - else if ( !reg->attr.fields.s ) - { - gprintk(XENLOG_ERR, - "System segment provided for a code or data segment\n"); - return -EINVAL; - } - - if ( !reg->attr.fields.p ) - { - gprintk(XENLOG_ERR, "Non-present segment provided\n"); - return -EINVAL; - } - - if ( seg == x86_seg_cs && !(reg->attr.fields.type & 0x8) ) - { - gprintk(XENLOG_ERR, "Non-code segment provided for CS\n"); - return -EINVAL; - } - - if ( seg == x86_seg_ss && - ((reg->attr.fields.type & 0x8) || !(reg->attr.fields.type & 0x2)) ) - { - gprintk(XENLOG_ERR, "Non-writeable segment provided for SS\n"); - return -EINVAL; - } - - if ( reg->attr.fields.s && seg != x86_seg_ss && seg != x86_seg_cs && - (reg->attr.fields.type & 0x8) && !(reg->attr.fields.type & 0x2) ) - { - gprintk(XENLOG_ERR, "Non-readable segment provided for DS or ES\n"); - return -EINVAL; - } - - return 0; -} - -/* Called by VCPUOP_initialise for HVM guests. */ -int arch_set_info_hvm_guest(struct vcpu *v, const vcpu_hvm_context_t *ctx) -{ - struct cpu_user_regs *uregs = &v->arch.user_regs; - struct segment_register cs, ds, ss, es, tr; - const char *errstr; - int rc; - - if ( ctx->pad != 0 ) - return -EINVAL; - - switch ( ctx->mode ) - { - default: - return -EINVAL; - - case VCPU_HVM_MODE_32B: - { - const struct vcpu_hvm_x86_32 *regs = &ctx->cpu_regs.x86_32; - uint32_t limit; - - if ( ctx->cpu_regs.x86_32.pad1 != 0 || - ctx->cpu_regs.x86_32.pad2[0] != 0 || - ctx->cpu_regs.x86_32.pad2[1] != 0 || - ctx->cpu_regs.x86_32.pad2[2] != 0 ) - return -EINVAL; - -#define SEG(s, r) ({ \ - s = (struct segment_register){ .base = (r)->s ## _base, \ - .limit = (r)->s ## _limit, \ - .attr.bytes = (r)->s ## _ar }; \ - /* Set accessed / busy bit for present segments. */ \ - if ( s.attr.fields.p ) \ - s.attr.fields.type |= (x86_seg_##s != x86_seg_tr ? 1 : 2); \ - check_segment(&s, x86_seg_ ## s); }) - - rc = SEG(cs, regs); - rc |= SEG(ds, regs); - rc |= SEG(ss, regs); - rc |= SEG(es, regs); - rc |= SEG(tr, regs); -#undef SEG - - if ( rc != 0 ) - return rc; - - /* Basic sanity checks. */ - limit = cs.limit; - if ( cs.attr.fields.g ) - limit = (limit << 12) | 0xfff; - if ( regs->eip > limit ) - { - gprintk(XENLOG_ERR, "EIP (%#08x) outside CS limit (%#08x)\n", - regs->eip, limit); - return -EINVAL; - } - - if ( ss.attr.fields.dpl != cs.attr.fields.dpl ) - { - gprintk(XENLOG_ERR, "SS.DPL (%u) is different than CS.DPL (%u)\n", - ss.attr.fields.dpl, cs.attr.fields.dpl); - return -EINVAL; - } - - if ( ds.attr.fields.p && ds.attr.fields.dpl > cs.attr.fields.dpl ) - { - gprintk(XENLOG_ERR, "DS.DPL (%u) is greater than CS.DPL (%u)\n", - ds.attr.fields.dpl, cs.attr.fields.dpl); - return -EINVAL; - } - - if ( es.attr.fields.p && es.attr.fields.dpl > cs.attr.fields.dpl ) - { - gprintk(XENLOG_ERR, "ES.DPL (%u) is greater than CS.DPL (%u)\n", - es.attr.fields.dpl, cs.attr.fields.dpl); - return -EINVAL; - } - - if ( (regs->efer & EFER_LMA) && !(regs->efer & EFER_LME) ) - { - gprintk(XENLOG_ERR, "EFER.LMA set without EFER.LME (%#016lx)\n", - regs->efer); - return -EINVAL; - } - - uregs->rax = regs->eax; - uregs->rcx = regs->ecx; - uregs->rdx = regs->edx; - uregs->rbx = regs->ebx; - uregs->rsp = regs->esp; - uregs->rbp = regs->ebp; - uregs->rsi = regs->esi; - uregs->rdi = regs->edi; - uregs->rip = regs->eip; - uregs->rflags = regs->eflags; - - v->arch.hvm_vcpu.guest_cr[0] = regs->cr0; - v->arch.hvm_vcpu.guest_cr[3] = regs->cr3; - v->arch.hvm_vcpu.guest_cr[4] = regs->cr4; - v->arch.hvm_vcpu.guest_efer = regs->efer; - } - break; - - case VCPU_HVM_MODE_64B: - { - const struct vcpu_hvm_x86_64 *regs = &ctx->cpu_regs.x86_64; - - /* Basic sanity checks. */ - if ( !is_canonical_address(regs->rip) ) - { - gprintk(XENLOG_ERR, "RIP contains a non-canonical address (%#lx)\n", - regs->rip); - return -EINVAL; - } - - if ( !(regs->cr0 & X86_CR0_PG) ) - { - gprintk(XENLOG_ERR, "CR0 doesn't have paging enabled (%#016lx)\n", - regs->cr0); - return -EINVAL; - } - - if ( !(regs->cr4 & X86_CR4_PAE) ) - { - gprintk(XENLOG_ERR, "CR4 doesn't have PAE enabled (%#016lx)\n", - regs->cr4); - return -EINVAL; - } - - if ( !(regs->efer & EFER_LME) ) - { - gprintk(XENLOG_ERR, "EFER doesn't have LME enabled (%#016lx)\n", - regs->efer); - return -EINVAL; - } - - uregs->rax = regs->rax; - uregs->rcx = regs->rcx; - uregs->rdx = regs->rdx; - uregs->rbx = regs->rbx; - uregs->rsp = regs->rsp; - uregs->rbp = regs->rbp; - uregs->rsi = regs->rsi; - uregs->rdi = regs->rdi; - uregs->rip = regs->rip; - uregs->rflags = regs->rflags; - - v->arch.hvm_vcpu.guest_cr[0] = regs->cr0; - v->arch.hvm_vcpu.guest_cr[3] = regs->cr3; - v->arch.hvm_vcpu.guest_cr[4] = regs->cr4; - v->arch.hvm_vcpu.guest_efer = regs->efer; - -#define SEG(l, a) (struct segment_register){ .limit = (l), .attr.bytes = (a) } - cs = SEG(~0u, 0xa9b); /* 64bit code segment. */ - ds = ss = es = SEG(~0u, 0xc93); - tr = SEG(0x67, 0x8b); /* 64bit TSS (busy). */ -#undef SEG - } - break; - - } - - if ( v->arch.hvm_vcpu.guest_efer & EFER_LME ) - v->arch.hvm_vcpu.guest_efer |= EFER_LMA; - - if ( v->arch.hvm_vcpu.guest_cr[4] & ~hvm_cr4_guest_valid_bits(v, 0) ) - { - gprintk(XENLOG_ERR, "Bad CR4 value: %#016lx\n", - v->arch.hvm_vcpu.guest_cr[4]); - return -EINVAL; - } - - errstr = hvm_efer_valid(v, v->arch.hvm_vcpu.guest_efer, -1); - if ( errstr ) - { - gprintk(XENLOG_ERR, "Bad EFER value (%#016lx): %s\n", - v->arch.hvm_vcpu.guest_efer, errstr); - return -EINVAL; - } - - hvm_update_guest_cr(v, 0); - hvm_update_guest_cr(v, 3); - hvm_update_guest_cr(v, 4); - hvm_update_guest_efer(v); - - if ( hvm_paging_enabled(v) && !paging_mode_hap(v->domain) ) - { - /* Shadow-mode CR3 change. Check PDBR and update refcounts. */ - struct page_info *page = get_page_from_gfn(v->domain, - v->arch.hvm_vcpu.guest_cr[3] >> PAGE_SHIFT, - NULL, P2M_ALLOC); - if ( !page ) - { - gprintk(XENLOG_ERR, "Invalid CR3: %#lx\n", - v->arch.hvm_vcpu.guest_cr[3]); - return -EINVAL; - } - - v->arch.guest_table = pagetable_from_page(page); - } - - hvm_set_segment_register(v, x86_seg_cs, &cs); - hvm_set_segment_register(v, x86_seg_ds, &ds); - hvm_set_segment_register(v, x86_seg_ss, &ss); - hvm_set_segment_register(v, x86_seg_es, &es); - hvm_set_segment_register(v, x86_seg_tr, &tr); - - /* Sync AP's TSC with BSP's. */ - v->arch.hvm_vcpu.cache_tsc_offset = - v->domain->vcpu[0]->arch.hvm_vcpu.cache_tsc_offset; - hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset, - v->domain->arch.hvm_domain.sync_tsc); - - paging_update_paging_modes(v); - - v->is_initialised = 1; - set_bit(_VPF_down, &v->pause_flags); - - return 0; -} - int arch_initialise_vcpu(struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg) { int rc; diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile index 0a3d0f4f7e..4dc0773a93 100644 --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -4,6 +4,7 @@ subdir-y += vmx obj-y += asid.o obj-y += dm.o obj-bin-y += dom0_build.init.o +obj-y += domain.o obj-y += emulate.o obj-y += hpet.o obj-y += hvm.o diff --git a/xen/arch/x86/hvm/domain.c b/xen/arch/x86/hvm/domain.c new file mode 100644 index 0000000000..c3358f4f8d --- /dev/null +++ b/xen/arch/x86/hvm/domain.c @@ -0,0 +1,322 @@ +/****************************************************************************** + * arch/x86/hvm/domain.c + * + * HVM-specific domain handling + */ + +/* + * Copyright (C) 1995 Linus Torvalds + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 + */ + + +#include +#include +#include +#include +#include + +#include + +static inline int check_segment(struct segment_register *reg, + enum x86_segment seg) +{ + + if ( reg->attr.fields.pad != 0 ) + { + gprintk(XENLOG_ERR, "Segment attribute bits 12-15 are not zero\n"); + return -EINVAL; + } + + if ( reg->attr.bytes == 0 ) + { + if ( seg != x86_seg_ds && seg != x86_seg_es ) + { + gprintk(XENLOG_ERR, "Null selector provided for CS, SS or TR\n"); + return -EINVAL; + } + return 0; + } + + if ( seg == x86_seg_tr ) + { + if ( reg->attr.fields.s ) + { + gprintk(XENLOG_ERR, "Code or data segment provided for TR\n"); + return -EINVAL; + } + + if ( reg->attr.fields.type != SYS_DESC_tss_busy ) + { + gprintk(XENLOG_ERR, "Non-32-bit-TSS segment provided for TR\n"); + return -EINVAL; + } + } + else if ( !reg->attr.fields.s ) + { + gprintk(XENLOG_ERR, + "System segment provided for a code or data segment\n"); + return -EINVAL; + } + + if ( !reg->attr.fields.p ) + { + gprintk(XENLOG_ERR, "Non-present segment provided\n"); + return -EINVAL; + } + + if ( seg == x86_seg_cs && !(reg->attr.fields.type & 0x8) ) + { + gprintk(XENLOG_ERR, "Non-code segment provided for CS\n"); + return -EINVAL; + } + + if ( seg == x86_seg_ss && + ((reg->attr.fields.type & 0x8) || !(reg->attr.fields.type & 0x2)) ) + { + gprintk(XENLOG_ERR, "Non-writeable segment provided for SS\n"); + return -EINVAL; + } + + if ( reg->attr.fields.s && seg != x86_seg_ss && seg != x86_seg_cs && + (reg->attr.fields.type & 0x8) && !(reg->attr.fields.type & 0x2) ) + { + gprintk(XENLOG_ERR, "Non-readable segment provided for DS or ES\n"); + return -EINVAL; + } + + return 0; +} + +/* Called by VCPUOP_initialise for HVM guests. */ +int arch_set_info_hvm_guest(struct vcpu *v, const vcpu_hvm_context_t *ctx) +{ + struct cpu_user_regs *uregs = &v->arch.user_regs; + struct segment_register cs, ds, ss, es, tr; + const char *errstr; + int rc; + + if ( ctx->pad != 0 ) + return -EINVAL; + + switch ( ctx->mode ) + { + default: + return -EINVAL; + + case VCPU_HVM_MODE_32B: + { + const struct vcpu_hvm_x86_32 *regs = &ctx->cpu_regs.x86_32; + uint32_t limit; + + if ( ctx->cpu_regs.x86_32.pad1 != 0 || + ctx->cpu_regs.x86_32.pad2[0] != 0 || + ctx->cpu_regs.x86_32.pad2[1] != 0 || + ctx->cpu_regs.x86_32.pad2[2] != 0 ) + return -EINVAL; + +#define SEG(s, r) ({ \ + s = (struct segment_register){ .base = (r)->s ## _base, \ + .limit = (r)->s ## _limit, \ + .attr.bytes = (r)->s ## _ar }; \ + /* Set accessed / busy bit for present segments. */ \ + if ( s.attr.fields.p ) \ + s.attr.fields.type |= (x86_seg_##s != x86_seg_tr ? 1 : 2); \ + check_segment(&s, x86_seg_ ## s); }) + + rc = SEG(cs, regs); + rc |= SEG(ds, regs); + rc |= SEG(ss, regs); + rc |= SEG(es, regs); + rc |= SEG(tr, regs); +#undef SEG + + if ( rc != 0 ) + return rc; + + /* Basic sanity checks. */ + limit = cs.limit; + if ( cs.attr.fields.g ) + limit = (limit << 12) | 0xfff; + if ( regs->eip > limit ) + { + gprintk(XENLOG_ERR, "EIP (%#08x) outside CS limit (%#08x)\n", + regs->eip, limit); + return -EINVAL; + } + + if ( ss.attr.fields.dpl != cs.attr.fields.dpl ) + { + gprintk(XENLOG_ERR, "SS.DPL (%u) is different than CS.DPL (%u)\n", + ss.attr.fields.dpl, cs.attr.fields.dpl); + return -EINVAL; + } + + if ( ds.attr.fields.p && ds.attr.fields.dpl > cs.attr.fields.dpl ) + { + gprintk(XENLOG_ERR, "DS.DPL (%u) is greater than CS.DPL (%u)\n", + ds.attr.fields.dpl, cs.attr.fields.dpl); + return -EINVAL; + } + + if ( es.attr.fields.p && es.attr.fields.dpl > cs.attr.fields.dpl ) + { + gprintk(XENLOG_ERR, "ES.DPL (%u) is greater than CS.DPL (%u)\n", + es.attr.fields.dpl, cs.attr.fields.dpl); + return -EINVAL; + } + + if ( (regs->efer & EFER_LMA) && !(regs->efer & EFER_LME) ) + { + gprintk(XENLOG_ERR, "EFER.LMA set without EFER.LME (%#016lx)\n", + regs->efer); + return -EINVAL; + } + + uregs->rax = regs->eax; + uregs->rcx = regs->ecx; + uregs->rdx = regs->edx; + uregs->rbx = regs->ebx; + uregs->rsp = regs->esp; + uregs->rbp = regs->ebp; + uregs->rsi = regs->esi; + uregs->rdi = regs->edi; + uregs->rip = regs->eip; + uregs->rflags = regs->eflags; + + v->arch.hvm_vcpu.guest_cr[0] = regs->cr0; + v->arch.hvm_vcpu.guest_cr[3] = regs->cr3; + v->arch.hvm_vcpu.guest_cr[4] = regs->cr4; + v->arch.hvm_vcpu.guest_efer = regs->efer; + } + break; + + case VCPU_HVM_MODE_64B: + { + const struct vcpu_hvm_x86_64 *regs = &ctx->cpu_regs.x86_64; + + /* Basic sanity checks. */ + if ( !is_canonical_address(regs->rip) ) + { + gprintk(XENLOG_ERR, "RIP contains a non-canonical address (%#lx)\n", + regs->rip); + return -EINVAL; + } + + if ( !(regs->cr0 & X86_CR0_PG) ) + { + gprintk(XENLOG_ERR, "CR0 doesn't have paging enabled (%#016lx)\n", + regs->cr0); + return -EINVAL; + } + + if ( !(regs->cr4 & X86_CR4_PAE) ) + { + gprintk(XENLOG_ERR, "CR4 doesn't have PAE enabled (%#016lx)\n", + regs->cr4); + return -EINVAL; + } + + if ( !(regs->efer & EFER_LME) ) + { + gprintk(XENLOG_ERR, "EFER doesn't have LME enabled (%#016lx)\n", + regs->efer); + return -EINVAL; + } + + uregs->rax = regs->rax; + uregs->rcx = regs->rcx; + uregs->rdx = regs->rdx; + uregs->rbx = regs->rbx; + uregs->rsp = regs->rsp; + uregs->rbp = regs->rbp; + uregs->rsi = regs->rsi; + uregs->rdi = regs->rdi; + uregs->rip = regs->rip; + uregs->rflags = regs->rflags; + + v->arch.hvm_vcpu.guest_cr[0] = regs->cr0; + v->arch.hvm_vcpu.guest_cr[3] = regs->cr3; + v->arch.hvm_vcpu.guest_cr[4] = regs->cr4; + v->arch.hvm_vcpu.guest_efer = regs->efer; + +#define SEG(l, a) (struct segment_register){ .limit = (l), .attr.bytes = (a) } + cs = SEG(~0u, 0xa9b); /* 64bit code segment. */ + ds = ss = es = SEG(~0u, 0xc93); + tr = SEG(0x67, 0x8b); /* 64bit TSS (busy). */ +#undef SEG + } + break; + + } + + if ( v->arch.hvm_vcpu.guest_efer & EFER_LME ) + v->arch.hvm_vcpu.guest_efer |= EFER_LMA; + + if ( v->arch.hvm_vcpu.guest_cr[4] & ~hvm_cr4_guest_valid_bits(v, 0) ) + { + gprintk(XENLOG_ERR, "Bad CR4 value: %#016lx\n", + v->arch.hvm_vcpu.guest_cr[4]); + return -EINVAL; + } + + errstr = hvm_efer_valid(v, v->arch.hvm_vcpu.guest_efer, -1); + if ( errstr ) + { + gprintk(XENLOG_ERR, "Bad EFER value (%#016lx): %s\n", + v->arch.hvm_vcpu.guest_efer, errstr); + return -EINVAL; + } + + hvm_update_guest_cr(v, 0); + hvm_update_guest_cr(v, 3); + hvm_update_guest_cr(v, 4); + hvm_update_guest_efer(v); + + if ( hvm_paging_enabled(v) && !paging_mode_hap(v->domain) ) + { + /* Shadow-mode CR3 change. Check PDBR and update refcounts. */ + struct page_info *page = get_page_from_gfn(v->domain, + v->arch.hvm_vcpu.guest_cr[3] >> PAGE_SHIFT, + NULL, P2M_ALLOC); + if ( !page ) + { + gprintk(XENLOG_ERR, "Invalid CR3: %#lx\n", + v->arch.hvm_vcpu.guest_cr[3]); + return -EINVAL; + } + + v->arch.guest_table = pagetable_from_page(page); + } + + hvm_set_segment_register(v, x86_seg_cs, &cs); + hvm_set_segment_register(v, x86_seg_ds, &ds); + hvm_set_segment_register(v, x86_seg_ss, &ss); + hvm_set_segment_register(v, x86_seg_es, &es); + hvm_set_segment_register(v, x86_seg_tr, &tr); + + /* Sync AP's TSC with BSP's. */ + v->arch.hvm_vcpu.cache_tsc_offset = + v->domain->vcpu[0]->arch.hvm_vcpu.cache_tsc_offset; + hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset, + v->domain->arch.hvm_domain.sync_tsc); + + paging_update_paging_modes(v); + + v->is_initialised = 1; + set_bit(_VPF_down, &v->pause_flags); + + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */