diff options
| -rw-r--r-- | arch/x86/mm/tlb.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index a1561957dccb..5bfe61a5e8e3 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c | |||
| @@ -151,6 +151,34 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next, | |||
| 151 | local_irq_restore(flags); | 151 | local_irq_restore(flags); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static void sync_current_stack_to_mm(struct mm_struct *mm) | ||
| 155 | { | ||
| 156 | unsigned long sp = current_stack_pointer; | ||
| 157 | pgd_t *pgd = pgd_offset(mm, sp); | ||
| 158 | |||
| 159 | if (CONFIG_PGTABLE_LEVELS > 4) { | ||
| 160 | if (unlikely(pgd_none(*pgd))) { | ||
| 161 | pgd_t *pgd_ref = pgd_offset_k(sp); | ||
| 162 | |||
| 163 | set_pgd(pgd, *pgd_ref); | ||
| 164 | } | ||
| 165 | } else { | ||
| 166 | /* | ||
| 167 | * "pgd" is faked. The top level entries are "p4d"s, so sync | ||
| 168 | * the p4d. This compiles to approximately the same code as | ||
| 169 | * the 5-level case. | ||
| 170 | */ | ||
| 171 | p4d_t *p4d = p4d_offset(pgd, sp); | ||
| 172 | |||
| 173 | if (unlikely(p4d_none(*p4d))) { | ||
| 174 | pgd_t *pgd_ref = pgd_offset_k(sp); | ||
| 175 | p4d_t *p4d_ref = p4d_offset(pgd_ref, sp); | ||
| 176 | |||
| 177 | set_p4d(p4d, *p4d_ref); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 154 | void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, | 182 | void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, |
| 155 | struct task_struct *tsk) | 183 | struct task_struct *tsk) |
| 156 | { | 184 | { |
| @@ -226,11 +254,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, | |||
| 226 | * mapped in the new pgd, we'll double-fault. Forcibly | 254 | * mapped in the new pgd, we'll double-fault. Forcibly |
| 227 | * map it. | 255 | * map it. |
| 228 | */ | 256 | */ |
| 229 | unsigned int index = pgd_index(current_stack_pointer); | 257 | sync_current_stack_to_mm(next); |
| 230 | pgd_t *pgd = next->pgd + index; | ||
| 231 | |||
| 232 | if (unlikely(pgd_none(*pgd))) | ||
| 233 | set_pgd(pgd, init_mm.pgd[index]); | ||
| 234 | } | 258 | } |
| 235 | 259 | ||
| 236 | /* Stop remote flushes for the previous mm */ | 260 | /* Stop remote flushes for the previous mm */ |
