Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP1:GA
xen.10697
5aec7393-1-x86-xpti-avoid-copy.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 5aec7393-1-x86-xpti-avoid-copy.patch of Package xen.10697
From: Juergen Gross <jgross@suse.com> Subject: x86/xpti: avoid copying L4 page table contents when possible For mitigation of Meltdown the current L4 page table is copied to the cpu local root page table each time a 64 bit pv guest is entered. Copying can be avoided in cases where the guest L4 page table hasn't been modified while running the hypervisor, e.g. when handling interrupts or any hypercall not modifying the L4 page table or %cr3. So add a per-cpu flag indicating whether the copying should be performed and set that flag only when loading a new %cr3 or modifying the L4 page table. This includes synchronization of the cpu local root page table with other cpus, so add a special synchronization flag for that case. A simple performance check (compiling the hypervisor via "make -j 4") in dom0 with 4 vcpus shows a significant improvement: - real time drops from 112 seconds to 103 seconds - system time drops from 142 seconds to 131 seconds Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> --- a/xen/arch/x86/flushtlb.c +++ b/xen/arch/x86/flushtlb.c @@ -9,6 +9,7 @@ #include <xen/config.h> #include <xen/sched.h> +#include <xen/smp.h> #include <xen/softirq.h> #include <asm/flushtlb.h> #include <asm/page.h> @@ -167,4 +168,7 @@ void flush_area_local(const void *va, un } local_irq_restore(irqfl); + + if ( flags & FLUSH_ROOT_PGTBL ) + get_cpu_info()->root_pgt_changed = 1; } --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -498,6 +498,7 @@ void make_cr3(struct vcpu *v, unsigned l void write_ptbase(struct vcpu *v) { + get_cpu_info()->root_pgt_changed = 1; write_cr3(v->arch.cr3); } @@ -3821,18 +3822,27 @@ long do_mmu_update( case PGT_l4_page_table: rc = mod_l4_entry(va, l4e_from_intpte(req.val), mfn, cmd == MMU_PT_UPDATE_PRESERVE_AD, v); - /* - * No need to sync if all uses of the page can be accounted - * to the page lock we hold, its pinned status, and uses on - * this (v)CPU. - */ - if ( !rc && this_cpu(root_pgt) && - ((page->u.inuse.type_info & PGT_count_mask) > - (1 + !!(page->u.inuse.type_info & PGT_pinned) + - (pagetable_get_pfn(curr->arch.guest_table) == mfn) + - (pagetable_get_pfn(curr->arch.guest_table_user) == - mfn))) ) - sync_guest = 1; + if ( !rc && this_cpu(root_pgt) ) + { + bool_t local_in_use = 0; + + if ( pagetable_get_pfn(curr->arch.guest_table) == mfn ) + { + local_in_use = 1; + get_cpu_info()->root_pgt_changed = 1; + } + + /* + * No need to sync if all uses of the page can be + * accounted to the page lock we hold, its pinned + * status, and uses on this (v)CPU. + */ + if ( (page->u.inuse.type_info & PGT_count_mask) > + (1 + !!(page->u.inuse.type_info & PGT_pinned) + + (pagetable_get_pfn(curr->arch.guest_table_user) == + mfn) + local_in_use) ) + sync_guest = 1; + } break; case PGT_writable_page: perfc_incr(writable_mmu_updates); @@ -3936,7 +3946,8 @@ long do_mmu_update( * Force other vCPU-s of the affected guest to pick up L4 entry * changes (if any). */ - flush_mask(pt_owner->domain_dirty_cpumask, FLUSH_TLB_GLOBAL); + flush_mask(pt_owner->domain_dirty_cpumask, + FLUSH_TLB_GLOBAL | FLUSH_ROOT_PGTBL); } perfc_add(num_page_updates, i); --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -938,6 +938,8 @@ static int shadow_set_l4e(struct vcpu *v /* Write the new entry */ shadow_write_entries(sl4e, &new_sl4e, 1, sl4mfn); + flush_root_pgtbl_domain(v->domain); + flags |= SHADOW_SET_CHANGED; if ( shadow_l4e_get_flags(old_sl4e) & _PAGE_PRESENT ) --- a/xen/arch/x86/smp.c +++ b/xen/arch/x86/smp.c @@ -223,7 +223,7 @@ void invalidate_interrupt(struct cpu_use ack_APIC_irq(); perfc_incr(ipis); if ( !__sync_local_execstate() || - (flush_flags & (FLUSH_TLB_GLOBAL | FLUSH_CACHE)) ) + (flush_flags & (FLUSH_TLB_GLOBAL | FLUSH_CACHE | FLUSH_ROOT_PGTBL)) ) flush_area_local(flush_va, flush_flags); cpumask_clear_cpu(smp_processor_id(), &flush_cpumask); } --- a/xen/arch/x86/x86_64/asm-offsets.c +++ b/xen/arch/x86/x86_64/asm-offsets.c @@ -141,6 +141,7 @@ void __dummy__(void) OFFSET(CPUINFO_use_shadow_spec_ctrl, struct cpu_info, use_shadow_spec_ctrl); OFFSET(CPUINFO_xen_spec_ctrl, struct cpu_info, xen_spec_ctrl); OFFSET(CPUINFO_xen_rsb, struct cpu_info, xen_rsb); + OFFSET(CPUINFO_root_pgt_changed, struct cpu_info, root_pgt_changed); DEFINE(CPUINFO_sizeof, sizeof(struct cpu_info)); BLANK(); --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -45,11 +45,15 @@ restore_all_guest: mov %cr3, %r9 GET_STACK_BASE(%rdx) mov STACK_CPUINFO_FIELD(pv_cr3)(%rdx), %rdi + test %rdi, %rdi + jz .Lrag_keep_cr3 + mov %rdi, %rax + cmpb $0, STACK_CPUINFO_FIELD(root_pgt_changed)(%rdx) + je .Lrag_copy_done + movb $0, STACK_CPUINFO_FIELD(root_pgt_changed)(%rdx) movabs $PADDR_MASK & PAGE_MASK, %rsi movabs $DIRECTMAP_VIRT_START, %rcx - mov %rdi, %rax and %rsi, %rdi - jz .Lrag_keep_cr3 and %r9, %rsi add %rcx, %rdi add %rcx, %rsi @@ -64,6 +68,7 @@ restore_all_guest: sub $(ROOT_PAGETABLE_FIRST_XEN_SLOT - \ ROOT_PAGETABLE_LAST_XEN_SLOT - 1) * 8, %rdi rep movsq +.Lrag_copy_done: mov %r9, STACK_CPUINFO_FIELD(xen_cr3)(%rdx) write_cr3 rax, rdi, rsi .Lrag_keep_cr3: --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -285,6 +285,8 @@ void toggle_guest_pt(struct vcpu *v) v->arch.flags ^= TF_kernel_mode; update_cr3(v); + get_cpu_info()->root_pgt_changed = 1; + #ifdef USER_MAPPINGS_ARE_GLOBAL /* Don't flush user global mappings from the TLB. Don't tick TLB clock. */ asm volatile ( "mov %0, %%cr3" : : "r" (v->arch.cr3) : "memory" ); --- a/xen/include/asm-x86/current.h +++ b/xen/include/asm-x86/current.h @@ -43,6 +43,14 @@ struct cpu_info { int8_t xen_spec_ctrl; uint8_t xen_rsb; + /* + * The following field controls copying of the L4 page table of 64-bit + * PV guests to the per-cpu root page table on entering the guest context. + * If set the L4 page table is being copied to the root page table and + * the field will be reset. + */ + bool_t root_pgt_changed; + /* get_stack_bottom() must be 16-byte aligned */ }; --- a/xen/include/asm-x86/flushtlb.h +++ b/xen/include/asm-x86/flushtlb.h @@ -101,6 +101,8 @@ void write_cr3(unsigned long cr3); #define FLUSH_CACHE 0x400 /* VA for the flush has a valid mapping */ #define FLUSH_VA_VALID 0x800 + /* Flush the per-cpu root page table */ +#define FLUSH_ROOT_PGTBL 0x2000 /* Flush local TLBs/caches. */ void flush_area_local(const void *va, unsigned int flags); @@ -132,4 +134,10 @@ void flush_area_mask(const cpumask_t *, #define flush_tlb_one_all(v) \ flush_tlb_one_mask(&cpu_online_map, v) +#define flush_root_pgtbl_domain(d) \ +{ \ + if ( this_cpu(root_pgt) && is_pv_domain(d) && !is_pv_32bit_domain(d) ) \ + flush_mask((d)->domain_dirty_cpumask, FLUSH_ROOT_PGTBL); \ +} + #endif /* __FLUSHTLB_H__ */
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor