|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | +/* |
| 3 | + * sev_verify_cbit.S - Code for verification of the C-bit position reported |
| 4 | + * by the Hypervisor when running with SEV enabled. |
| 5 | + * |
| 6 | + * Copyright (c) 2020 Joerg Roedel (jroedel@suse.de) |
| 7 | + * |
| 8 | + * sev_verify_cbit() is called before switching to a new long-mode page-table |
| 9 | + * at boot. |
| 10 | + * |
| 11 | + * Verify that the C-bit position is correct by writing a random value to |
| 12 | + * an encrypted memory location while on the current page-table. Then it |
| 13 | + * switches to the new page-table to verify the memory content is still the |
| 14 | + * same. After that it switches back to the current page-table and when the |
| 15 | + * check succeeded it returns. If the check failed the code invalidates the |
| 16 | + * stack pointer and goes into a hlt loop. The stack-pointer is invalidated to |
| 17 | + * make sure no interrupt or exception can get the CPU out of the hlt loop. |
| 18 | + * |
| 19 | + * New page-table pointer is expected in %rdi (first parameter) |
| 20 | + * |
| 21 | + */ |
| 22 | +SYM_FUNC_START(sev_verify_cbit) |
| 23 | +#ifdef CONFIG_AMD_MEM_ENCRYPT |
| 24 | + /* First check if a C-bit was detected */ |
| 25 | + movq sme_me_mask(%rip), %rsi |
| 26 | + testq %rsi, %rsi |
| 27 | + jz 3f |
| 28 | + |
| 29 | + /* sme_me_mask != 0 could mean SME or SEV - Check also for SEV */ |
| 30 | + movq sev_status(%rip), %rsi |
| 31 | + testq %rsi, %rsi |
| 32 | + jz 3f |
| 33 | + |
| 34 | + /* Save CR4 in %rsi */ |
| 35 | + movq %cr4, %rsi |
| 36 | + |
| 37 | + /* Disable Global Pages */ |
| 38 | + movq %rsi, %rdx |
| 39 | + andq $(~X86_CR4_PGE), %rdx |
| 40 | + movq %rdx, %cr4 |
| 41 | + |
| 42 | + /* |
| 43 | + * Verified that running under SEV - now get a random value using |
| 44 | + * RDRAND. This instruction is mandatory when running as an SEV guest. |
| 45 | + * |
| 46 | + * Don't bail out of the loop if RDRAND returns errors. It is better to |
| 47 | + * prevent forward progress than to work with a non-random value here. |
| 48 | + */ |
| 49 | +1: rdrand %rdx |
| 50 | + jnc 1b |
| 51 | + |
| 52 | + /* Store value to memory and keep it in %rdx */ |
| 53 | + movq %rdx, sev_check_data(%rip) |
| 54 | + |
| 55 | + /* Backup current %cr3 value to restore it later */ |
| 56 | + movq %cr3, %rcx |
| 57 | + |
| 58 | + /* Switch to new %cr3 - This might unmap the stack */ |
| 59 | + movq %rdi, %cr3 |
| 60 | + |
| 61 | + /* |
| 62 | + * Compare value in %rdx with memory location. If C-bit is incorrect |
| 63 | + * this would read the encrypted data and make the check fail. |
| 64 | + */ |
| 65 | + cmpq %rdx, sev_check_data(%rip) |
| 66 | + |
| 67 | + /* Restore old %cr3 */ |
| 68 | + movq %rcx, %cr3 |
| 69 | + |
| 70 | + /* Restore previous CR4 */ |
| 71 | + movq %rsi, %cr4 |
| 72 | + |
| 73 | + /* Check CMPQ result */ |
| 74 | + je 3f |
| 75 | + |
| 76 | + /* |
| 77 | + * The check failed, prevent any forward progress to prevent ROP |
| 78 | + * attacks, invalidate the stack and go into a hlt loop. |
| 79 | + */ |
| 80 | + xorq %rsp, %rsp |
| 81 | + subq $0x1000, %rsp |
| 82 | +2: hlt |
| 83 | + jmp 2b |
| 84 | +3: |
| 85 | +#endif |
| 86 | + /* Return page-table pointer */ |
| 87 | + movq %rdi, %rax |
| 88 | + ret |
| 89 | +SYM_FUNC_END(sev_verify_cbit) |
0 commit comments