History

[S390] kvm: fix address mode switching

598841ca9919d008b520114d8a4378c4ce4e40a1 ([S390] use gmap address spaces for kvm guest images) changed kvm to use a separate address space for kvm guests. This address space was switched in __vcpu_run In some cases (preemption, page fault) there is the possibility that this address space switch is lost. The typical symptom was a huge amount of validity intercepts or random guest addressing exceptions. Fix this by doing the switch in sie_loop and sie_exit and saving the address space in the gmap structure itself. Also use the preempt notifier.

Christian Borntraeger committed 15 years ago

Commit 480e5921 parent 9d037a75 files · +15 −10Browse files

Unified · Split

5 files
  1. arch/s390/include/asm/pgtable.h +2 −0
  2. arch/s390/kernel/asm-offsets.c +3 −0
  3. arch/s390/kernel/entry64.S +6 −0
  4. arch/s390/kvm/kvm-s390.c +2 −2
  5. arch/s390/mm/pgtable.c +2 −8
arch/s390/include/asm/pgtable.h+2−0
@@ -658,12 +658,14 @@ static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) · 657 unmodified lines
658 * struct gmap_struct - guest address space658 * struct gmap_struct - guest address space
659 * @mm: pointer to the parent mm_struct659 * @mm: pointer to the parent mm_struct
660 * @table: pointer to the page directory660 * @table: pointer to the page directory
661 * @asce: address space control element for gmap page table
661 * @crst_list: list of all crst tables used in the guest address space662 * @crst_list: list of all crst tables used in the guest address space
662 */663 */
663struct gmap {664struct gmap {
664 struct list_head list;665 struct list_head list;
665 struct mm_struct *mm;666 struct mm_struct *mm;
666 unsigned long *table;667 unsigned long *table;
668 unsigned long asce;
667 struct list_head crst_list;669 struct list_head crst_list;
668};670};
669 671
arch/s390/kernel/asm-offsets.c+3−0
@@ -10,6 +10,7 @@ · 9 unmodified lines
10#include <linux/sched.h>10#include <linux/sched.h>
11#include <asm/vdso.h>11#include <asm/vdso.h>
12#include <asm/sigp.h>12#include <asm/sigp.h>
13#include <asm/pgtable.h>
13 14
14/*15/*
15 * Make sure that the compiler is new enough. We want a compiler that16 * Make sure that the compiler is new enough. We want a compiler that
@@ -126,6 +127,7 @@ int main(void) · 110 unmodified lines
126 DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack));127 DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack));
127 DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack));128 DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack));
128 DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));129 DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
130 DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
129 DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));131 DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
130 DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));132 DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
131 DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));133 DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
@@ -151,6 +153,7 @@ int main(void) · 19 unmodified lines
151 DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));153 DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
152 DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap));154 DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap));
153 DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));155 DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
156 DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
154#endif /* CONFIG_32BIT */157#endif /* CONFIG_32BIT */
155 return 0;158 return 0;
156}159}
arch/s390/kernel/entry64.S+6−0
@@ -1076,6 +1076,11 @@ sie_loop: · 1075 unmodified lines
1076 lg %r14,__LC_THREAD_INFO # pointer thread_info struct1076 lg %r14,__LC_THREAD_INFO # pointer thread_info struct
1077 tm __TI_flags+7(%r14),_TIF_EXIT_SIE1077 tm __TI_flags+7(%r14),_TIF_EXIT_SIE
1078 jnz sie_exit1078 jnz sie_exit
1079 lg %r14,__LC_GMAP # get gmap pointer
1080 ltgr %r14,%r14
1081 jz sie_gmap
1082 lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce
1083sie_gmap:
1079 lg %r14,__SF_EMPTY(%r15) # get control block pointer1084 lg %r14,__SF_EMPTY(%r15) # get control block pointer
1080 SPP __SF_EMPTY(%r15) # set guest id1085 SPP __SF_EMPTY(%r15) # set guest id
1081 sie 0(%r14)1086 sie 0(%r14)
@@ -1083,6 +1088,7 @@ sie_done: · 1 unmodified line
1083 SPP __LC_CMF_HPP # set host id1088 SPP __LC_CMF_HPP # set host id
1084 lg %r14,__LC_THREAD_INFO # pointer thread_info struct1089 lg %r14,__LC_THREAD_INFO # pointer thread_info struct
1085sie_exit:1090sie_exit:
1091 lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
1086 ni __TI_flags+6(%r14),255-(_TIF_SIE>>8)1092 ni __TI_flags+6(%r14),255-(_TIF_SIE>>8)
1087 lg %r14,__SF_EMPTY+8(%r15) # load guest register save area1093 lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
1088 stmg %r0,%r13,0(%r14) # save guest gprs 0-131094 stmg %r0,%r13,0(%r14) # save guest gprs 0-13
arch/s390/kvm/kvm-s390.c+2−2
@@ -263,10 +263,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) · 262 unmodified lines
263 vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;263 vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
264 restore_fp_regs(&vcpu->arch.guest_fpregs);264 restore_fp_regs(&vcpu->arch.guest_fpregs);
265 restore_access_regs(vcpu->arch.guest_acrs);265 restore_access_regs(vcpu->arch.guest_acrs);
266 gmap_enable(vcpu->arch.gmap);
266}267}
267 268
268void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)269void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
269{270{
271 gmap_disable(vcpu->arch.gmap);
270 save_fp_regs(&vcpu->arch.guest_fpregs);272 save_fp_regs(&vcpu->arch.guest_fpregs);
271 save_access_regs(vcpu->arch.guest_acrs);273 save_access_regs(vcpu->arch.guest_acrs);
272 restore_fp_regs(&vcpu->arch.host_fpregs);274 restore_fp_regs(&vcpu->arch.host_fpregs);
@@ -461,7 +463,6 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) · 188 unmodified lines
461 local_irq_disable();463 local_irq_disable();
462 kvm_guest_enter();464 kvm_guest_enter();
463 local_irq_enable();465 local_irq_enable();
464 gmap_enable(vcpu->arch.gmap);
465 VCPU_EVENT(vcpu, 6, "entering sie flags %x",466 VCPU_EVENT(vcpu, 6, "entering sie flags %x",
466 atomic_read(&vcpu->arch.sie_block->cpuflags));467 atomic_read(&vcpu->arch.sie_block->cpuflags));
467 if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) {468 if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) {
@@ -470,7 +471,6 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) · 2 unmodified lines
470 }471 }
471 VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",472 VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
472 vcpu->arch.sie_block->icptcode);473 vcpu->arch.sie_block->icptcode);
473 gmap_disable(vcpu->arch.gmap);
474 local_irq_disable();474 local_irq_disable();
475 kvm_guest_exit();475 kvm_guest_exit();
476 local_irq_enable();476 local_irq_enable();
arch/s390/mm/pgtable.c+2−8
@@ -160,6 +160,8 @@ struct gmap *gmap_alloc(struct mm_struct *mm) · 159 unmodified lines
160 table = (unsigned long *) page_to_phys(page);160 table = (unsigned long *) page_to_phys(page);
161 crst_table_init(table, _REGION1_ENTRY_EMPTY);161 crst_table_init(table, _REGION1_ENTRY_EMPTY);
162 gmap->table = table;162 gmap->table = table;
163 gmap->asce = _ASCE_TYPE_REGION1 | _ASCE_TABLE_LENGTH |
164 _ASCE_USER_BITS | __pa(table);
163 list_add(&gmap->list, &mm->context.gmap_list);165 list_add(&gmap->list, &mm->context.gmap_list);
164 return gmap;166 return gmap;
165 167
@@ -240,10 +242,6 @@ EXPORT_SYMBOL_GPL(gmap_free); · 74 unmodified lines
240 */242 */
241void gmap_enable(struct gmap *gmap)243void gmap_enable(struct gmap *gmap)
242{244{
243 /* Load primary space page table origin. */
244 S390_lowcore.user_asce = _ASCE_TYPE_REGION1 | _ASCE_TABLE_LENGTH |
245 _ASCE_USER_BITS | __pa(gmap->table);
246 asm volatile("lctlg 1,1,%0\n" : : "m" (S390_lowcore.user_asce) );
247 S390_lowcore.gmap = (unsigned long) gmap;245 S390_lowcore.gmap = (unsigned long) gmap;
248}246}
249EXPORT_SYMBOL_GPL(gmap_enable);247EXPORT_SYMBOL_GPL(gmap_enable);
@@ -254,10 +252,6 @@ EXPORT_SYMBOL_GPL(gmap_enable); · 4 unmodified lines
254 */252 */
255void gmap_disable(struct gmap *gmap)253void gmap_disable(struct gmap *gmap)
256{254{
257 /* Load primary space page table origin. */
258 S390_lowcore.user_asce =
259 gmap->mm->context.asce_bits | __pa(gmap->mm->pgd);
260 asm volatile("lctlg 1,1,%0\n" : : "m" (S390_lowcore.user_asce) );
261 S390_lowcore.gmap = 0UL;255 S390_lowcore.gmap = 0UL;
262}256}
263EXPORT_SYMBOL_GPL(gmap_disable);257EXPORT_SYMBOL_GPL(gmap_disable);