|
@@ -14,6 +14,7 @@
|
|
|
#include <linux/start_kernel.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/memblock.h>
|
|
|
+#include <linux/mem_encrypt.h>
|
|
|
|
|
|
#include <asm/processor.h>
|
|
|
#include <asm/proto.h>
|
|
@@ -45,9 +46,10 @@ static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
|
|
|
return ptr - (void *)_text + (void *)physaddr;
|
|
|
}
|
|
|
|
|
|
-void __head __startup_64(unsigned long physaddr)
|
|
|
+unsigned long __head __startup_64(unsigned long physaddr)
|
|
|
{
|
|
|
unsigned long load_delta, *p;
|
|
|
+ unsigned long pgtable_flags;
|
|
|
pgdval_t *pgd;
|
|
|
p4dval_t *p4d;
|
|
|
pudval_t *pud;
|
|
@@ -68,6 +70,12 @@ void __head __startup_64(unsigned long physaddr)
|
|
|
if (load_delta & ~PMD_PAGE_MASK)
|
|
|
for (;;);
|
|
|
|
|
|
+ /* Activate Secure Memory Encryption (SME) if supported and enabled */
|
|
|
+ sme_enable();
|
|
|
+
|
|
|
+ /* Include the SME encryption mask in the fixup value */
|
|
|
+ load_delta += sme_get_me_mask();
|
|
|
+
|
|
|
/* Fixup the physical addresses in the page table */
|
|
|
|
|
|
pgd = fixup_pointer(&early_top_pgt, physaddr);
|
|
@@ -94,28 +102,30 @@ void __head __startup_64(unsigned long physaddr)
|
|
|
|
|
|
pud = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
|
|
|
pmd = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
|
|
|
+ pgtable_flags = _KERNPG_TABLE + sme_get_me_mask();
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
|
|
|
p4d = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
|
|
|
|
|
|
i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
|
|
|
- pgd[i + 0] = (pgdval_t)p4d + _KERNPG_TABLE;
|
|
|
- pgd[i + 1] = (pgdval_t)p4d + _KERNPG_TABLE;
|
|
|
+ pgd[i + 0] = (pgdval_t)p4d + pgtable_flags;
|
|
|
+ pgd[i + 1] = (pgdval_t)p4d + pgtable_flags;
|
|
|
|
|
|
i = (physaddr >> P4D_SHIFT) % PTRS_PER_P4D;
|
|
|
- p4d[i + 0] = (pgdval_t)pud + _KERNPG_TABLE;
|
|
|
- p4d[i + 1] = (pgdval_t)pud + _KERNPG_TABLE;
|
|
|
+ p4d[i + 0] = (pgdval_t)pud + pgtable_flags;
|
|
|
+ p4d[i + 1] = (pgdval_t)pud + pgtable_flags;
|
|
|
} else {
|
|
|
i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
|
|
|
- pgd[i + 0] = (pgdval_t)pud + _KERNPG_TABLE;
|
|
|
- pgd[i + 1] = (pgdval_t)pud + _KERNPG_TABLE;
|
|
|
+ pgd[i + 0] = (pgdval_t)pud + pgtable_flags;
|
|
|
+ pgd[i + 1] = (pgdval_t)pud + pgtable_flags;
|
|
|
}
|
|
|
|
|
|
i = (physaddr >> PUD_SHIFT) % PTRS_PER_PUD;
|
|
|
- pud[i + 0] = (pudval_t)pmd + _KERNPG_TABLE;
|
|
|
- pud[i + 1] = (pudval_t)pmd + _KERNPG_TABLE;
|
|
|
+ pud[i + 0] = (pudval_t)pmd + pgtable_flags;
|
|
|
+ pud[i + 1] = (pudval_t)pmd + pgtable_flags;
|
|
|
|
|
|
pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL;
|
|
|
+ pmd_entry += sme_get_me_mask();
|
|
|
pmd_entry += physaddr;
|
|
|
|
|
|
for (i = 0; i < DIV_ROUND_UP(_end - _text, PMD_SIZE); i++) {
|
|
@@ -136,9 +146,30 @@ void __head __startup_64(unsigned long physaddr)
|
|
|
pmd[i] += load_delta;
|
|
|
}
|
|
|
|
|
|
- /* Fixup phys_base */
|
|
|
+ /*
|
|
|
+ * Fixup phys_base - remove the memory encryption mask to obtain
|
|
|
+ * the true physical address.
|
|
|
+ */
|
|
|
p = fixup_pointer(&phys_base, physaddr);
|
|
|
- *p += load_delta;
|
|
|
+ *p += load_delta - sme_get_me_mask();
|
|
|
+
|
|
|
+ /* Encrypt the kernel (if SME is active) */
|
|
|
+ sme_encrypt_kernel();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Return the SME encryption mask (if SME is active) to be used as a
|
|
|
+ * modifier for the initial pgdir entry programmed into CR3.
|
|
|
+ */
|
|
|
+ return sme_get_me_mask();
|
|
|
+}
|
|
|
+
|
|
|
+unsigned long __startup_secondary_64(void)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Return the SME encryption mask (if SME is active) to be used as a
|
|
|
+ * modifier for the initial pgdir entry programmed into CR3.
|
|
|
+ */
|
|
|
+ return sme_get_me_mask();
|
|
|
}
|
|
|
|
|
|
/* Wipe all early page tables except for the kernel symbol map */
|