[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 16/31] x86/mm: split out descriptor table code
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 <wei.liu2@xxxxxxxxxx> --- 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 <compat/vcpu.h> #include <asm/psr.h> #include <asm/pv/domain.h> +#include <asm/pv/processor.h> 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 <http://www.gnu.org/licenses/>. + */ + +#include <xen/guest_access.h> +#include <xen/hypercall.h> + +#include <asm/p2m.h> +#include <asm/pv/processor.h> + +/************************* + * 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 <asm/mem_paging.h> #include <asm/mem_sharing.h> +#include <asm/pv/processor.h> + 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 <wei.liu2@xxxxxxxxxx> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#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 <xen/errno.h> + +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__ */ -- 2.11.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |