From patchwork Thu Aug 17 14:44:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Liu X-Patchwork-Id: 9906507 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 828FC603B5 for ; Thu, 17 Aug 2017 14:48:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 731E228B2C for ; Thu, 17 Aug 2017 14:48:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6785E28B38; Thu, 17 Aug 2017 14:48:54 +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 4296828B2C for ; Thu, 17 Aug 2017 14:48:53 +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 1diM43-0001fB-Ve; Thu, 17 Aug 2017 14:46:27 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1diM42-0001eD-4S for xen-devel@lists.xenproject.org; Thu, 17 Aug 2017 14:46:26 +0000 Received: from [85.158.139.211] by server-16.bemta-5.messagelabs.com id 83/B0-01712-14CA5995; Thu, 17 Aug 2017 14:46:25 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrEIsWRWlGSWpSXmKPExsXitHRDpK7Dmqm RBnOvGVp83zKZyYHR4/CHKywBjFGsmXlJ+RUJrBn/JzWwFhypqNh/7hhLA+PKmC5GTg4JAX+J w/P+s4LYbALKEj87e9lAbBEBPYmmA88Zuxi5OJgF5jBKTJ3bBeRwcAgLOErsulMBUsMioCrxs m8mWC+vgKXEjOVdbBAz5SV2tV0Ei3MCxQ9NWswMYgsJWEjM/tDODmErSHRMP8YE0SsocXLmEx YQm1lAQuLgixfMExh5ZyFJzUKSWsDItIpRvTi1qCy1SNdYL6koMz2jJDcxM0fX0MBULze1uDg xPTUnMalYLzk/dxMjMHQYgGAH495/TocYJTmYlER5f8+aEinEl5SfUpmRWJwRX1Sak1p8iFGG g0NJgrdw9dRIIcGi1PTUirTMHGAQw6QlOHiURHgtQNK8xQWJucWZ6RCpU4z2HAt6Nnxh4uiY8 fMbE8erCf+BZNP3j9+ZhFjy8vNSpcR5760CahMAacsozYMbCou6S4yyUsK8jEBnCvEUpBblZp agyr9iFOdgVBLmFQRZzpOZVwK3+xXQWUxAZ11pnwRyVkkiQkqqgTHtZPLvZBaG4O/z3kv2NAQ sFt0RxXB14VHxY/aOdbL7fI7tsxe4kzvRWCH3+soJuw/vvtwUsjx03dT5LyW/zXG+KXPjdekp z7kbtz9osZ6jKrWmJvVgpnzkLJfYlJdTpy7KsN2SP/nO0e2cLpeyvjumx6WGrci/8oZR+m/TW /EPjtNmPHh+yIZBiaU4I9FQi7moOBEAXiNvMLUCAAA= X-Env-Sender: prvs=395e6b081=wei.liu2@citrix.com X-Msg-Ref: server-10.tower-206.messagelabs.com!1502981183!79283657!1 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.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 52588 invoked from network); 17 Aug 2017 14:46:24 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-10.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 17 Aug 2017 14:46:24 -0000 X-IronPort-AV: E=Sophos;i="5.41,388,1498521600"; d="scan'208";a="435893520" From: Wei Liu To: Xen-devel Date: Thu, 17 Aug 2017 15:44:41 +0100 Message-ID: <20170817144456.18989-17-wei.liu2@citrix.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170817144456.18989-1-wei.liu2@citrix.com> References: <20170817144456.18989-1-wei.liu2@citrix.com> MIME-Version: 1.0 Cc: George Dunlap , Andrew Cooper , Wei Liu , Jan Beulich Subject: [Xen-devel] [PATCH v4 16/31] x86/mm: split out descriptor table code 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 Move the code to pv/descriptor-tables.c. Add "pv_" prefix to {set,destroy}_gdt. Fix up call sites. Move the declarations to new header file. Fix coding style issues while moving code. Signed-off-by: Wei Liu --- xen/arch/x86/domain.c | 11 ++- xen/arch/x86/mm.c | 156 ------------------------------ xen/arch/x86/pv/Makefile | 1 + xen/arch/x86/pv/descriptor-tables.c | 188 ++++++++++++++++++++++++++++++++++++ xen/arch/x86/x86_64/compat/mm.c | 6 +- xen/include/asm-x86/processor.h | 5 - xen/include/asm-x86/pv/processor.h | 40 ++++++++ 7 files changed, 239 insertions(+), 168 deletions(-) create mode 100644 xen/arch/x86/pv/descriptor-tables.c create mode 100644 xen/include/asm-x86/pv/processor.h diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index baaf8151d2..9a25c04f6c 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -64,6 +64,7 @@ #include #include #include +#include DEFINE_PER_CPU(struct vcpu *, curr_vcpu); @@ -986,7 +987,7 @@ int arch_set_info_guest( return rc; if ( !compat ) - rc = (int)set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents); + rc = (int)pv_set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents); else { unsigned long gdt_frames[ARRAY_SIZE(v->arch.pv_vcpu.gdt_frames)]; @@ -996,7 +997,7 @@ int arch_set_info_guest( return -EINVAL; for ( i = 0; i < n; ++i ) gdt_frames[i] = c.cmp->gdt_frames[i]; - rc = (int)set_gdt(v, gdt_frames, c.cmp->gdt_ents); + rc = (int)pv_set_gdt(v, gdt_frames, c.cmp->gdt_ents); } if ( rc != 0 ) return rc; @@ -1095,7 +1096,7 @@ int arch_set_info_guest( { if ( cr3_page ) put_page(cr3_page); - destroy_gdt(v); + pv_destroy_gdt(v); return rc; } @@ -1147,7 +1148,7 @@ int arch_vcpu_reset(struct vcpu *v) { if ( is_pv_vcpu(v) ) { - destroy_gdt(v); + pv_destroy_gdt(v); return vcpu_destroy_pagetables(v); } @@ -1890,7 +1891,7 @@ int domain_relinquish_resources(struct domain *d) * the LDT as it automatically gets squashed with the guest * mappings. */ - destroy_gdt(v); + pv_destroy_gdt(v); } } diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 63549b987c..6cbcdabcd2 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3824,162 +3824,6 @@ long do_update_va_mapping_otherdomain(unsigned long va, u64 val64, } - -/************************* - * Descriptor Tables - */ - -void destroy_gdt(struct vcpu *v) -{ - l1_pgentry_t *pl1e; - unsigned int i; - unsigned long pfn, zero_pfn = PFN_DOWN(__pa(zero_page)); - - v->arch.pv_vcpu.gdt_ents = 0; - pl1e = gdt_ldt_ptes(v->domain, v); - for ( i = 0; i < FIRST_RESERVED_GDT_PAGE; i++ ) - { - pfn = l1e_get_pfn(pl1e[i]); - if ( (l1e_get_flags(pl1e[i]) & _PAGE_PRESENT) && pfn != zero_pfn ) - put_page_and_type(mfn_to_page(pfn)); - l1e_write(&pl1e[i], l1e_from_pfn(zero_pfn, __PAGE_HYPERVISOR_RO)); - v->arch.pv_vcpu.gdt_frames[i] = 0; - } -} - - -long set_gdt(struct vcpu *v, - unsigned long *frames, - unsigned int entries) -{ - struct domain *d = v->domain; - l1_pgentry_t *pl1e; - /* NB. There are 512 8-byte entries per GDT page. */ - unsigned int i, nr_pages = (entries + 511) / 512; - - if ( entries > FIRST_RESERVED_GDT_ENTRY ) - return -EINVAL; - - /* Check the pages in the new GDT. */ - for ( i = 0; i < nr_pages; i++ ) - { - struct page_info *page; - - page = get_page_from_gfn(d, frames[i], NULL, P2M_ALLOC); - if ( !page ) - goto fail; - if ( !get_page_type(page, PGT_seg_desc_page) ) - { - put_page(page); - goto fail; - } - frames[i] = page_to_mfn(page); - } - - /* Tear down the old GDT. */ - destroy_gdt(v); - - /* Install the new GDT. */ - v->arch.pv_vcpu.gdt_ents = entries; - pl1e = gdt_ldt_ptes(d, v); - for ( i = 0; i < nr_pages; i++ ) - { - v->arch.pv_vcpu.gdt_frames[i] = frames[i]; - l1e_write(&pl1e[i], l1e_from_pfn(frames[i], __PAGE_HYPERVISOR_RW)); - } - - return 0; - - fail: - while ( i-- > 0 ) - { - put_page_and_type(mfn_to_page(frames[i])); - } - return -EINVAL; -} - - -long do_set_gdt(XEN_GUEST_HANDLE_PARAM(xen_ulong_t) frame_list, - unsigned int entries) -{ - int nr_pages = (entries + 511) / 512; - unsigned long frames[16]; - struct vcpu *curr = current; - long ret; - - /* Rechecked in set_gdt, but ensures a sane limit for copy_from_user(). */ - if ( entries > FIRST_RESERVED_GDT_ENTRY ) - return -EINVAL; - - if ( copy_from_guest(frames, frame_list, nr_pages) ) - return -EFAULT; - - domain_lock(curr->domain); - - if ( (ret = set_gdt(curr, frames, entries)) == 0 ) - flush_tlb_local(); - - domain_unlock(curr->domain); - - return ret; -} - - -long do_update_descriptor(u64 pa, u64 desc) -{ - struct domain *dom = current->domain; - unsigned long gmfn = pa >> PAGE_SHIFT; - unsigned long mfn; - unsigned int offset; - struct desc_struct *gdt_pent, d; - struct page_info *page; - long ret = -EINVAL; - - offset = ((unsigned int)pa & ~PAGE_MASK) / sizeof(struct desc_struct); - - *(u64 *)&d = desc; - - page = get_page_from_gfn(dom, gmfn, NULL, P2M_ALLOC); - if ( (((unsigned int)pa % sizeof(struct desc_struct)) != 0) || - !page || - !check_descriptor(dom, &d) ) - { - if ( page ) - put_page(page); - return -EINVAL; - } - mfn = page_to_mfn(page); - - /* Check if the given frame is in use in an unsafe context. */ - switch ( page->u.inuse.type_info & PGT_type_mask ) - { - case PGT_seg_desc_page: - if ( unlikely(!get_page_type(page, PGT_seg_desc_page)) ) - goto out; - break; - default: - if ( unlikely(!get_page_type(page, PGT_writable_page)) ) - goto out; - break; - } - - paging_mark_dirty(dom, _mfn(mfn)); - - /* All is good so make the update. */ - gdt_pent = map_domain_page(_mfn(mfn)); - write_atomic((uint64_t *)&gdt_pent[offset], *(uint64_t *)&d); - unmap_domain_page(gdt_pent); - - put_page_type(page); - - ret = 0; /* success */ - - out: - put_page(page); - - return ret; -} - typedef struct e820entry e820entry_t; DEFINE_XEN_GUEST_HANDLE(e820entry_t); diff --git a/xen/arch/x86/pv/Makefile b/xen/arch/x86/pv/Makefile index 501c766cc2..42e9d3723b 100644 --- a/xen/arch/x86/pv/Makefile +++ b/xen/arch/x86/pv/Makefile @@ -1,4 +1,5 @@ obj-y += callback.o +obj-y += descriptor-tables.o obj-y += domain.o obj-y += emulate.o obj-y += emul-gate-op.o diff --git a/xen/arch/x86/pv/descriptor-tables.c b/xen/arch/x86/pv/descriptor-tables.c new file mode 100644 index 0000000000..12dc45b671 --- /dev/null +++ b/xen/arch/x86/pv/descriptor-tables.c @@ -0,0 +1,188 @@ +/****************************************************************************** + * arch/x86/pv/descriptor-tables.c + * + * Descriptor table related code + * + * Copyright (c) 2002-2005 K A Fraser + * Copyright (c) 2004 Christian Limpach + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 +#include + +#include +#include + +/************************* + * Descriptor Tables + */ + +void pv_destroy_gdt(struct vcpu *v) +{ + l1_pgentry_t *pl1e; + unsigned int i; + unsigned long pfn, zero_pfn = PFN_DOWN(__pa(zero_page)); + + v->arch.pv_vcpu.gdt_ents = 0; + pl1e = gdt_ldt_ptes(v->domain, v); + for ( i = 0; i < FIRST_RESERVED_GDT_PAGE; i++ ) + { + pfn = l1e_get_pfn(pl1e[i]); + if ( (l1e_get_flags(pl1e[i]) & _PAGE_PRESENT) && pfn != zero_pfn ) + put_page_and_type(mfn_to_page(pfn)); + l1e_write(&pl1e[i], l1e_from_pfn(zero_pfn, __PAGE_HYPERVISOR_RO)); + v->arch.pv_vcpu.gdt_frames[i] = 0; + } +} + +long pv_set_gdt(struct vcpu *v, unsigned long *frames, unsigned int entries) +{ + struct domain *d = v->domain; + l1_pgentry_t *pl1e; + /* NB. There are 512 8-byte entries per GDT page. */ + unsigned int i, nr_pages = (entries + 511) / 512; + + if ( entries > FIRST_RESERVED_GDT_ENTRY ) + return -EINVAL; + + /* Check the pages in the new GDT. */ + for ( i = 0; i < nr_pages; i++ ) + { + struct page_info *page; + + page = get_page_from_gfn(d, frames[i], NULL, P2M_ALLOC); + if ( !page ) + goto fail; + if ( !get_page_type(page, PGT_seg_desc_page) ) + { + put_page(page); + goto fail; + } + frames[i] = page_to_mfn(page); + } + + /* Tear down the old GDT. */ + pv_destroy_gdt(v); + + /* Install the new GDT. */ + v->arch.pv_vcpu.gdt_ents = entries; + pl1e = gdt_ldt_ptes(d, v); + for ( i = 0; i < nr_pages; i++ ) + { + v->arch.pv_vcpu.gdt_frames[i] = frames[i]; + l1e_write(&pl1e[i], l1e_from_pfn(frames[i], __PAGE_HYPERVISOR_RW)); + } + + return 0; + + fail: + while ( i-- > 0 ) + { + put_page_and_type(mfn_to_page(frames[i])); + } + return -EINVAL; +} + + +long do_set_gdt(XEN_GUEST_HANDLE_PARAM(xen_ulong_t) frame_list, + unsigned int entries) +{ + int nr_pages = (entries + 511) / 512; + unsigned long frames[16]; + struct vcpu *curr = current; + long ret; + + /* Rechecked in pv_set_gdt, but ensures a sane limit for copy_from_user(). */ + if ( entries > FIRST_RESERVED_GDT_ENTRY ) + return -EINVAL; + + if ( copy_from_guest(frames, frame_list, nr_pages) ) + return -EFAULT; + + domain_lock(curr->domain); + + if ( (ret = pv_set_gdt(curr, frames, entries)) == 0 ) + flush_tlb_local(); + + domain_unlock(curr->domain); + + return ret; +} + +long do_update_descriptor(u64 pa, u64 desc) +{ + struct domain *dom = current->domain; + unsigned long gmfn = pa >> PAGE_SHIFT; + unsigned long mfn; + unsigned int offset; + struct desc_struct *gdt_pent, d; + struct page_info *page; + long ret = -EINVAL; + + offset = ((unsigned int)pa & ~PAGE_MASK) / sizeof(struct desc_struct); + + *(u64 *)&d = desc; + + page = get_page_from_gfn(dom, gmfn, NULL, P2M_ALLOC); + if ( (((unsigned int)pa % sizeof(struct desc_struct)) != 0) || + !page || + !check_descriptor(dom, &d) ) + { + if ( page ) + put_page(page); + return -EINVAL; + } + mfn = page_to_mfn(page); + + /* Check if the given frame is in use in an unsafe context. */ + switch ( page->u.inuse.type_info & PGT_type_mask ) + { + case PGT_seg_desc_page: + if ( unlikely(!get_page_type(page, PGT_seg_desc_page)) ) + goto out; + break; + default: + if ( unlikely(!get_page_type(page, PGT_writable_page)) ) + goto out; + break; + } + + paging_mark_dirty(dom, _mfn(mfn)); + + /* All is good so make the update. */ + gdt_pent = map_domain_page(_mfn(mfn)); + write_atomic((uint64_t *)&gdt_pent[offset], *(uint64_t *)&d); + unmap_domain_page(gdt_pent); + + put_page_type(page); + + ret = 0; /* success */ + + out: + put_page(page); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/x86_64/compat/mm.c b/xen/arch/x86/x86_64/compat/mm.c index ef0ff86519..d61fb89c27 100644 --- a/xen/arch/x86/x86_64/compat/mm.c +++ b/xen/arch/x86/x86_64/compat/mm.c @@ -6,13 +6,15 @@ #include #include +#include + int compat_set_gdt(XEN_GUEST_HANDLE_PARAM(uint) frame_list, unsigned int entries) { unsigned int i, nr_pages = (entries + 511) / 512; unsigned long frames[16]; long ret; - /* Rechecked in set_gdt, but ensures a sane limit for copy_from_user(). */ + /* Rechecked in pv_set_gdt, but ensures a sane limit for copy_from_user(). */ if ( entries > FIRST_RESERVED_GDT_ENTRY ) return -EINVAL; @@ -31,7 +33,7 @@ int compat_set_gdt(XEN_GUEST_HANDLE_PARAM(uint) frame_list, unsigned int entries domain_lock(current->domain); - if ( (ret = set_gdt(current, frames, entries)) == 0 ) + if ( (ret = pv_set_gdt(current, frames, entries)) == 0 ) flush_tlb_local(); domain_unlock(current->domain); diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 4bef698633..747fcbdc75 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -466,11 +466,6 @@ extern void init_int80_direct_trap(struct vcpu *v); extern void write_ptbase(struct vcpu *v); -void destroy_gdt(struct vcpu *d); -long set_gdt(struct vcpu *d, - unsigned long *frames, - unsigned int entries); - /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ static always_inline void rep_nop(void) { diff --git a/xen/include/asm-x86/pv/processor.h b/xen/include/asm-x86/pv/processor.h new file mode 100644 index 0000000000..8ab5773871 --- /dev/null +++ b/xen/include/asm-x86/pv/processor.h @@ -0,0 +1,40 @@ +/* + * asm-x86/pv/processor.h + * + * Vcpu interfaces for PV guests + * + * Copyright (C) 2017 Wei Liu + * + * 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 that 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 __X86_PV_PROCESSOR_H__ +#define __X86_PV_PROCESSOR_H__ + +#ifdef CONFIG_PV + +void pv_destroy_gdt(struct vcpu *d); +long pv_set_gdt(struct vcpu *d, unsigned long *frames, unsigned int entries); + +#else + +#include + +static inline void pv_destroy_gdt(struct vcpu *d) {} +static inline long pv_set_gdt(struct vcpu *d, unsigned long *frames, + unsigned int entries) +{ return -EINVAL; } + +#endif + +#endif /* __X86_PV_PROCESSOR_H__ */