diff options
Diffstat (limited to 'arch/x86/entry/calling.h')
| -rw-r--r-- | arch/x86/entry/calling.h | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h index 3fd8bc560fae..3f48f695d5e6 100644 --- a/arch/x86/entry/calling.h +++ b/arch/x86/entry/calling.h | |||
| @@ -1,6 +1,11 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | #include <linux/jump_label.h> | 2 | #include <linux/jump_label.h> |
| 3 | #include <asm/unwind_hints.h> | 3 | #include <asm/unwind_hints.h> |
| 4 | #include <asm/cpufeatures.h> | ||
| 5 | #include <asm/page_types.h> | ||
| 6 | #include <asm/percpu.h> | ||
| 7 | #include <asm/asm-offsets.h> | ||
| 8 | #include <asm/processor-flags.h> | ||
| 4 | 9 | ||
| 5 | /* | 10 | /* |
| 6 | 11 | ||
| @@ -187,6 +192,148 @@ For 32-bit we have the following conventions - kernel is built with | |||
| 187 | #endif | 192 | #endif |
| 188 | .endm | 193 | .endm |
| 189 | 194 | ||
| 195 | #ifdef CONFIG_PAGE_TABLE_ISOLATION | ||
| 196 | |||
| 197 | /* | ||
| 198 | * PAGE_TABLE_ISOLATION PGDs are 8k. Flip bit 12 to switch between the two | ||
| 199 | * halves: | ||
| 200 | */ | ||
| 201 | #define PTI_USER_PGTABLE_BIT PAGE_SHIFT | ||
| 202 | #define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT) | ||
| 203 | #define PTI_USER_PCID_BIT X86_CR3_PTI_PCID_USER_BIT | ||
| 204 | #define PTI_USER_PCID_MASK (1 << PTI_USER_PCID_BIT) | ||
| 205 | #define PTI_USER_PGTABLE_AND_PCID_MASK (PTI_USER_PCID_MASK | PTI_USER_PGTABLE_MASK) | ||
| 206 | |||
| 207 | .macro SET_NOFLUSH_BIT reg:req | ||
| 208 | bts $X86_CR3_PCID_NOFLUSH_BIT, \reg | ||
| 209 | .endm | ||
| 210 | |||
| 211 | .macro ADJUST_KERNEL_CR3 reg:req | ||
| 212 | ALTERNATIVE "", "SET_NOFLUSH_BIT \reg", X86_FEATURE_PCID | ||
| 213 | /* Clear PCID and "PAGE_TABLE_ISOLATION bit", point CR3 at kernel pagetables: */ | ||
| 214 | andq $(~PTI_USER_PGTABLE_AND_PCID_MASK), \reg | ||
| 215 | .endm | ||
| 216 | |||
| 217 | .macro SWITCH_TO_KERNEL_CR3 scratch_reg:req | ||
| 218 | ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI | ||
| 219 | mov %cr3, \scratch_reg | ||
| 220 | ADJUST_KERNEL_CR3 \scratch_reg | ||
| 221 | mov \scratch_reg, %cr3 | ||
| 222 | .Lend_\@: | ||
| 223 | .endm | ||
| 224 | |||
| 225 | #define THIS_CPU_user_pcid_flush_mask \ | ||
| 226 | PER_CPU_VAR(cpu_tlbstate) + TLB_STATE_user_pcid_flush_mask | ||
| 227 | |||
| 228 | .macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req | ||
| 229 | ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI | ||
| 230 | mov %cr3, \scratch_reg | ||
| 231 | |||
| 232 | ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID | ||
| 233 | |||
| 234 | /* | ||
| 235 | * Test if the ASID needs a flush. | ||
| 236 | */ | ||
| 237 | movq \scratch_reg, \scratch_reg2 | ||
| 238 | andq $(0x7FF), \scratch_reg /* mask ASID */ | ||
| 239 | bt \scratch_reg, THIS_CPU_user_pcid_flush_mask | ||
| 240 | jnc .Lnoflush_\@ | ||
| 241 | |||
| 242 | /* Flush needed, clear the bit */ | ||
| 243 | btr \scratch_reg, THIS_CPU_user_pcid_flush_mask | ||
| 244 | movq \scratch_reg2, \scratch_reg | ||
| 245 | jmp .Lwrcr3_pcid_\@ | ||
| 246 | |||
| 247 | .Lnoflush_\@: | ||
| 248 | movq \scratch_reg2, \scratch_reg | ||
| 249 | SET_NOFLUSH_BIT \scratch_reg | ||
| 250 | |||
| 251 | .Lwrcr3_pcid_\@: | ||
| 252 | /* Flip the ASID to the user version */ | ||
| 253 | orq $(PTI_USER_PCID_MASK), \scratch_reg | ||
| 254 | |||
| 255 | .Lwrcr3_\@: | ||
| 256 | /* Flip the PGD to the user version */ | ||
| 257 | orq $(PTI_USER_PGTABLE_MASK), \scratch_reg | ||
| 258 | mov \scratch_reg, %cr3 | ||
| 259 | .Lend_\@: | ||
| 260 | .endm | ||
| 261 | |||
| 262 | .macro SWITCH_TO_USER_CR3_STACK scratch_reg:req | ||
| 263 | pushq %rax | ||
| 264 | SWITCH_TO_USER_CR3_NOSTACK scratch_reg=\scratch_reg scratch_reg2=%rax | ||
| 265 | popq %rax | ||
| 266 | .endm | ||
| 267 | |||
| 268 | .macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req | ||
| 269 | ALTERNATIVE "jmp .Ldone_\@", "", X86_FEATURE_PTI | ||
| 270 | movq %cr3, \scratch_reg | ||
| 271 | movq \scratch_reg, \save_reg | ||
| 272 | /* | ||
| 273 | * Test the user pagetable bit. If set, then the user page tables | ||
| 274 | * are active. If clear CR3 already has the kernel page table | ||
| 275 | * active. | ||
| 276 | */ | ||
| 277 | bt $PTI_USER_PGTABLE_BIT, \scratch_reg | ||
| 278 | jnc .Ldone_\@ | ||
| 279 | |||
| 280 | ADJUST_KERNEL_CR3 \scratch_reg | ||
| 281 | movq \scratch_reg, %cr3 | ||
| 282 | |||
| 283 | .Ldone_\@: | ||
| 284 | .endm | ||
| 285 | |||
| 286 | .macro RESTORE_CR3 scratch_reg:req save_reg:req | ||
| 287 | ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI | ||
| 288 | |||
| 289 | ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID | ||
| 290 | |||
| 291 | /* | ||
| 292 | * KERNEL pages can always resume with NOFLUSH as we do | ||
| 293 | * explicit flushes. | ||
| 294 | */ | ||
| 295 | bt $PTI_USER_PGTABLE_BIT, \save_reg | ||
| 296 | jnc .Lnoflush_\@ | ||
| 297 | |||
| 298 | /* | ||
| 299 | * Check if there's a pending flush for the user ASID we're | ||
| 300 | * about to set. | ||
| 301 | */ | ||
| 302 | movq \save_reg, \scratch_reg | ||
| 303 | andq $(0x7FF), \scratch_reg | ||
| 304 | bt \scratch_reg, THIS_CPU_user_pcid_flush_mask | ||
| 305 | jnc .Lnoflush_\@ | ||
| 306 | |||
| 307 | btr \scratch_reg, THIS_CPU_user_pcid_flush_mask | ||
| 308 | jmp .Lwrcr3_\@ | ||
| 309 | |||
| 310 | .Lnoflush_\@: | ||
| 311 | SET_NOFLUSH_BIT \save_reg | ||
| 312 | |||
| 313 | .Lwrcr3_\@: | ||
| 314 | /* | ||
| 315 | * The CR3 write could be avoided when not changing its value, | ||
| 316 | * but would require a CR3 read *and* a scratch register. | ||
| 317 | */ | ||
| 318 | movq \save_reg, %cr3 | ||
| 319 | .Lend_\@: | ||
| 320 | .endm | ||
| 321 | |||
| 322 | #else /* CONFIG_PAGE_TABLE_ISOLATION=n: */ | ||
| 323 | |||
| 324 | .macro SWITCH_TO_KERNEL_CR3 scratch_reg:req | ||
| 325 | .endm | ||
| 326 | .macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req | ||
| 327 | .endm | ||
| 328 | .macro SWITCH_TO_USER_CR3_STACK scratch_reg:req | ||
| 329 | .endm | ||
| 330 | .macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req | ||
| 331 | .endm | ||
| 332 | .macro RESTORE_CR3 scratch_reg:req save_reg:req | ||
| 333 | .endm | ||
| 334 | |||
| 335 | #endif | ||
| 336 | |||
| 190 | #endif /* CONFIG_X86_64 */ | 337 | #endif /* CONFIG_X86_64 */ |
| 191 | 338 | ||
| 192 | /* | 339 | /* |
