@@ -172,11 +172,21 @@ SYM_FUNC_START(startup_32)
172172 */
173173 call get_sev_encryption_bit
174174 xorl %edx , %edx
175+ #ifdef CONFIG_AMD_MEM_ENCRYPT
175176 testl %eax , %eax
176177 jz 1f
177178 subl $32 , %eax /* Encryption bit is always above bit 31 */
178179 bts %eax , %edx /* Set encryption mask for page tables */
180+ /*
181+ * Mark SEV as active in sev_status so that startup32_check_sev_cbit()
182+ * will do a check. The sev_status memory will be fully initialized
183+ * with the contents of MSR_AMD_SEV_STATUS later in
184+ * set_sev_encryption_mask(). For now it is sufficient to know that SEV
185+ * is active.
186+ */
187+ movl $1 , rva(sev_status)(%ebp )
1791881:
189+ #endif
180190
181191 /* Initialize Page tables to 0 */
182192 leal rva(pgtable)(%ebx ), %edi
@@ -261,6 +271,9 @@ SYM_FUNC_START(startup_32)
261271 movl %esi , %edx
2622721:
263273#endif
274+ /* Check if the C-bit position is correct when SEV is active */
275+ call startup32_check_sev_cbit
276+
264277 pushl $__KERNEL_CS
265278 pushl %eax
266279
@@ -786,6 +799,78 @@ SYM_DATA_START_LOCAL(loaded_image_proto)
786799SYM_DATA_END(loaded_image_proto)
787800#endif
788801
802+ /*
803+ * Check for the correct C-bit position when the startup_32 boot-path is used.
804+ *
805+ * The check makes use of the fact that all memory is encrypted when paging is
806+ * disabled. The function creates 64 bits of random data using the RDRAND
807+ * instruction. RDRAND is mandatory for SEV guests, so always available. If the
808+ * hypervisor violates that the kernel will crash right here.
809+ *
810+ * The 64 bits of random data are stored to a memory location and at the same
811+ * time kept in the %eax and %ebx registers. Since encryption is always active
812+ * when paging is off the random data will be stored encrypted in main memory.
813+ *
814+ * Then paging is enabled. When the C-bit position is correct all memory is
815+ * still mapped encrypted and comparing the register values with memory will
816+ * succeed. An incorrect C-bit position will map all memory unencrypted, so that
817+ * the compare will use the encrypted random data and fail.
818+ */
819+ __HEAD
820+ .code32
821+ SYM_FUNC_START(startup32_check_sev_cbit)
822+ #ifdef CONFIG_AMD_MEM_ENCRYPT
823+ pushl %eax
824+ pushl %ebx
825+ pushl %ecx
826+ pushl %edx
827+
828+ /* Check for non-zero sev_status */
829+ movl rva(sev_status)(%ebp ), %eax
830+ testl %eax , %eax
831+ jz 4f
832+
833+ /*
834+ * Get two 32-bit random values - Don't bail out if RDRAND fails
835+ * because it is better to prevent forward progress if no random value
836+ * can be gathered.
837+ */
838+ 1: rdrand %eax
839+ jnc 1b
840+ 2: rdrand %ebx
841+ jnc 2b
842+
843+ /* Store to memory and keep it in the registers */
844+ movl %eax , rva(sev_check_data)(%ebp )
845+ movl %ebx , rva(sev_check_data+4 )(%ebp )
846+
847+ /* Enable paging to see if encryption is active */
848+ movl %cr0 , %edx /* Backup %cr0 in %edx */
849+ movl $(X86_CR0_PG | X86_CR0_PE), %ecx /* Enable Paging and Protected mode */
850+ movl %ecx , %cr0
851+
852+ cmpl %eax , rva(sev_check_data)(%ebp )
853+ jne 3f
854+ cmpl %ebx , rva(sev_check_data+4 )(%ebp )
855+ jne 3f
856+
857+ movl %edx , %cr0 /* Restore previous %cr0 */
858+
859+ jmp 4f
860+
861+ 3: /* Check failed - hlt the machine */
862+ hlt
863+ jmp 3b
864+
865+ 4:
866+ popl %edx
867+ popl %ecx
868+ popl %ebx
869+ popl %eax
870+ #endif
871+ ret
872+ SYM_FUNC_END(startup32_check_sev_cbit)
873+
789874/*
790875 * Stack and heap for uncompression
791876 */
0 commit comments