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) |
90 | |