diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2011-09-20 11:07:28 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2011-09-20 11:07:34 -0400 |
commit | 480e5926ce3bb61ec229be2dab08bdce8abb8d2e (patch) | |
tree | b252230da3bba55a8e4ebd747767257c781670d7 /arch/s390/mm | |
parent | 9d037a777695993ec7437e5f451647dea7919d4c (diff) |
[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.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r-- | arch/s390/mm/pgtable.c | 10 |
1 files changed, 2 insertions, 8 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 4d1f2bce87b3..f69ff3c13496 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -160,6 +160,8 @@ struct gmap *gmap_alloc(struct mm_struct *mm) | |||
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); | |||
240 | */ | 242 | */ |
241 | void gmap_enable(struct gmap *gmap) | 243 | void 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 | } |
249 | EXPORT_SYMBOL_GPL(gmap_enable); | 247 | EXPORT_SYMBOL_GPL(gmap_enable); |
@@ -254,10 +252,6 @@ EXPORT_SYMBOL_GPL(gmap_enable); | |||
254 | */ | 252 | */ |
255 | void gmap_disable(struct gmap *gmap) | 253 | void 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 | } |
263 | EXPORT_SYMBOL_GPL(gmap_disable); | 257 | EXPORT_SYMBOL_GPL(gmap_disable); |