/* 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 ([email protected]) * * 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. */ xorl %esp, %esp subq $0x1000, %rsp 2: hlt jmp 2b 3: #endif /* Return page-table pointer */ movq %rdi, %rax RET SYM_FUNC_END(sev_verify_cbit)