| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* |
| * sev_verify_cbit.S - Code for verification of the C-bit position reported |
| * by the Hypervisor when running with SEV enabled. |
| * |
| * Copyright (c) 2020 Joerg Roedel (jroedel@suse.de) |
| * |
| * sev_verify_cbit() is called before switching to a new long-mode page-table |
| * at boot. |
| * |
| * Verify that the C-bit position is correct by writing a random value to |
| * an encrypted memory location while on the current page-table. Then it |
| * switches to the new page-table to verify the memory content is still the |
| * same. After that it switches back to the current page-table and when the |
| * check succeeded it returns. If the check failed the code invalidates the |
| * stack pointer and goes into a hlt loop. The stack-pointer is invalidated to |
| * make sure no interrupt or exception can get the CPU out of the hlt loop. |
| * |
| * New page-table pointer is expected in %rdi (first parameter) |
| * |
| */ |
| SYM_FUNC_START(sev_verify_cbit) |
| #ifdef CONFIG_AMD_MEM_ENCRYPT |
| /* First check if a C-bit was detected */ |
| movq sme_me_mask(%rip), %rsi |
| testq %rsi, %rsi |
| jz 3f |
| |
| /* sme_me_mask != 0 could mean SME or SEV - Check also for SEV */ |
| movq sev_status(%rip), %rsi |
| testq %rsi, %rsi |
| jz 3f |
| |
| /* Save CR4 in %rsi */ |
| movq %cr4, %rsi |
| |
| /* Disable Global Pages */ |
| movq %rsi, %rdx |
| andq $(~X86_CR4_PGE), %rdx |
| movq %rdx, %cr4 |
| |
| /* |
| * Verified that running under SEV - now get a random value using |
| * RDRAND. This instruction is mandatory when running as an SEV guest. |
| * |
| * Don't bail out of the loop if RDRAND returns errors. It is better to |
| * prevent forward progress than to work with a non-random value here. |
| */ |
| 1: rdrand %rdx |
| jnc 1b |
| |
| /* Store value to memory and keep it in %rdx */ |
| movq %rdx, sev_check_data(%rip) |
| |
| /* Backup current %cr3 value to restore it later */ |
| movq %cr3, %rcx |
| |
| /* Switch to new %cr3 - This might unmap the stack */ |
| movq %rdi, %cr3 |
| |
| /* |
| * Compare value in %rdx with memory location. If C-bit is incorrect |
| * this would read the encrypted data and make the check fail. |
| */ |
| cmpq %rdx, sev_check_data(%rip) |
| |
| /* Restore old %cr3 */ |
| movq %rcx, %cr3 |
| |
| /* Restore previous CR4 */ |
| movq %rsi, %cr4 |
| |
| /* Check CMPQ result */ |
| je 3f |
| |
| /* |
| * The check failed, prevent any forward progress to prevent ROP |
| * attacks, invalidate the stack and go into a hlt loop. |
| */ |
| xorq %rsp, %rsp |
| subq $0x1000, %rsp |
| 2: hlt |
| jmp 2b |
| 3: |
| #endif |
| /* Return page-table pointer */ |
| movq %rdi, %rax |
| ret |
| SYM_FUNC_END(sev_verify_cbit) |