mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-02 20:46:41 +07:00
x86/mm: Encrypt the initrd earlier for BSP microcode update
Currently the BSP microcode update code examines the initrd very early in the boot process. If SME is active, the initrd is treated as being encrypted but it has not been encrypted (in place) yet. Update the early boot code that encrypts the kernel to also encrypt the initrd so that early BSP microcode updates work. Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Reviewed-by: Borislav Petkov <bp@suse.de> Cc: Borislav Petkov <bp@alien8.de> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/20180110192634.6026.10452.stgit@tlendack-t1.amdoffice.net Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
cc5f01e28d
commit
107cd25321
@ -39,7 +39,7 @@ void __init sme_unmap_bootdata(char *real_mode_data);
|
||||
|
||||
void __init sme_early_init(void);
|
||||
|
||||
void __init sme_encrypt_kernel(void);
|
||||
void __init sme_encrypt_kernel(struct boot_params *bp);
|
||||
void __init sme_enable(struct boot_params *bp);
|
||||
|
||||
int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
|
||||
@ -67,7 +67,7 @@ static inline void __init sme_unmap_bootdata(char *real_mode_data) { }
|
||||
|
||||
static inline void __init sme_early_init(void) { }
|
||||
|
||||
static inline void __init sme_encrypt_kernel(void) { }
|
||||
static inline void __init sme_encrypt_kernel(struct boot_params *bp) { }
|
||||
static inline void __init sme_enable(struct boot_params *bp) { }
|
||||
|
||||
static inline bool sme_active(void) { return false; }
|
||||
|
@ -157,8 +157,8 @@ unsigned long __head __startup_64(unsigned long physaddr,
|
||||
p = fixup_pointer(&phys_base, physaddr);
|
||||
*p += load_delta - sme_get_me_mask();
|
||||
|
||||
/* Encrypt the kernel (if SME is active) */
|
||||
sme_encrypt_kernel();
|
||||
/* Encrypt the kernel and related (if SME is active) */
|
||||
sme_encrypt_kernel(bp);
|
||||
|
||||
/*
|
||||
* Return the SME encryption mask (if SME is active) to be used as a
|
||||
|
@ -364,16 +364,6 @@ static void __init reserve_initrd(void)
|
||||
!ramdisk_image || !ramdisk_size)
|
||||
return; /* No initrd provided by bootloader */
|
||||
|
||||
/*
|
||||
* If SME is active, this memory will be marked encrypted by the
|
||||
* kernel when it is accessed (including relocation). However, the
|
||||
* ramdisk image was loaded decrypted by the bootloader, so make
|
||||
* sure that it is encrypted before accessing it. For SEV the
|
||||
* ramdisk will already be encrypted, so only do this for SME.
|
||||
*/
|
||||
if (sme_active())
|
||||
sme_early_encrypt(ramdisk_image, ramdisk_end - ramdisk_image);
|
||||
|
||||
initrd_start = 0;
|
||||
|
||||
mapped_size = memblock_mem_size(max_pfn_mapped);
|
||||
|
@ -738,11 +738,12 @@ static unsigned long __init sme_pgtable_calc(unsigned long len)
|
||||
return total;
|
||||
}
|
||||
|
||||
void __init sme_encrypt_kernel(void)
|
||||
void __init sme_encrypt_kernel(struct boot_params *bp)
|
||||
{
|
||||
unsigned long workarea_start, workarea_end, workarea_len;
|
||||
unsigned long execute_start, execute_end, execute_len;
|
||||
unsigned long kernel_start, kernel_end, kernel_len;
|
||||
unsigned long initrd_start, initrd_end, initrd_len;
|
||||
struct sme_populate_pgd_data ppd;
|
||||
unsigned long pgtable_area_len;
|
||||
unsigned long decrypted_base;
|
||||
@ -751,14 +752,15 @@ void __init sme_encrypt_kernel(void)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Prepare for encrypting the kernel by building new pagetables with
|
||||
* the necessary attributes needed to encrypt the kernel in place.
|
||||
* Prepare for encrypting the kernel and initrd by building new
|
||||
* pagetables with the necessary attributes needed to encrypt the
|
||||
* kernel in place.
|
||||
*
|
||||
* One range of virtual addresses will map the memory occupied
|
||||
* by the kernel as encrypted.
|
||||
* by the kernel and initrd as encrypted.
|
||||
*
|
||||
* Another range of virtual addresses will map the memory occupied
|
||||
* by the kernel as decrypted and write-protected.
|
||||
* by the kernel and initrd as decrypted and write-protected.
|
||||
*
|
||||
* The use of write-protect attribute will prevent any of the
|
||||
* memory from being cached.
|
||||
@ -769,6 +771,20 @@ void __init sme_encrypt_kernel(void)
|
||||
kernel_end = ALIGN(__pa_symbol(_end), PMD_PAGE_SIZE);
|
||||
kernel_len = kernel_end - kernel_start;
|
||||
|
||||
initrd_start = 0;
|
||||
initrd_end = 0;
|
||||
initrd_len = 0;
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
initrd_len = (unsigned long)bp->hdr.ramdisk_size |
|
||||
((unsigned long)bp->ext_ramdisk_size << 32);
|
||||
if (initrd_len) {
|
||||
initrd_start = (unsigned long)bp->hdr.ramdisk_image |
|
||||
((unsigned long)bp->ext_ramdisk_image << 32);
|
||||
initrd_end = PAGE_ALIGN(initrd_start + initrd_len);
|
||||
initrd_len = initrd_end - initrd_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the encryption workarea to be immediately after the kernel */
|
||||
workarea_start = kernel_end;
|
||||
|
||||
@ -791,6 +807,8 @@ void __init sme_encrypt_kernel(void)
|
||||
*/
|
||||
pgtable_area_len = sizeof(pgd_t) * PTRS_PER_PGD;
|
||||
pgtable_area_len += sme_pgtable_calc(execute_end - kernel_start) * 2;
|
||||
if (initrd_len)
|
||||
pgtable_area_len += sme_pgtable_calc(initrd_len) * 2;
|
||||
|
||||
/* PUDs and PMDs needed in the current pagetables for the workarea */
|
||||
pgtable_area_len += sme_pgtable_calc(execute_len + pgtable_area_len);
|
||||
@ -829,9 +847,9 @@ void __init sme_encrypt_kernel(void)
|
||||
|
||||
/*
|
||||
* A new pagetable structure is being built to allow for the kernel
|
||||
* to be encrypted. It starts with an empty PGD that will then be
|
||||
* populated with new PUDs and PMDs as the encrypted and decrypted
|
||||
* kernel mappings are created.
|
||||
* and initrd to be encrypted. It starts with an empty PGD that will
|
||||
* then be populated with new PUDs and PMDs as the encrypted and
|
||||
* decrypted kernel mappings are created.
|
||||
*/
|
||||
ppd.pgd = ppd.pgtable_area;
|
||||
memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD);
|
||||
@ -844,6 +862,12 @@ void __init sme_encrypt_kernel(void)
|
||||
* the base of the mapping.
|
||||
*/
|
||||
decrypted_base = (pgd_index(workarea_end) + 1) & (PTRS_PER_PGD - 1);
|
||||
if (initrd_len) {
|
||||
unsigned long check_base;
|
||||
|
||||
check_base = (pgd_index(initrd_end) + 1) & (PTRS_PER_PGD - 1);
|
||||
decrypted_base = max(decrypted_base, check_base);
|
||||
}
|
||||
decrypted_base <<= PGDIR_SHIFT;
|
||||
|
||||
/* Add encrypted kernel (identity) mappings */
|
||||
@ -858,6 +882,21 @@ void __init sme_encrypt_kernel(void)
|
||||
ppd.vaddr_end = kernel_end + decrypted_base;
|
||||
sme_map_range_decrypted_wp(&ppd);
|
||||
|
||||
if (initrd_len) {
|
||||
/* Add encrypted initrd (identity) mappings */
|
||||
ppd.paddr = initrd_start;
|
||||
ppd.vaddr = initrd_start;
|
||||
ppd.vaddr_end = initrd_end;
|
||||
sme_map_range_encrypted(&ppd);
|
||||
/*
|
||||
* Add decrypted, write-protected initrd (non-identity) mappings
|
||||
*/
|
||||
ppd.paddr = initrd_start;
|
||||
ppd.vaddr = initrd_start + decrypted_base;
|
||||
ppd.vaddr_end = initrd_end + decrypted_base;
|
||||
sme_map_range_decrypted_wp(&ppd);
|
||||
}
|
||||
|
||||
/* Add decrypted workarea mappings to both kernel mappings */
|
||||
ppd.paddr = workarea_start;
|
||||
ppd.vaddr = workarea_start;
|
||||
@ -873,6 +912,11 @@ void __init sme_encrypt_kernel(void)
|
||||
sme_encrypt_execute(kernel_start, kernel_start + decrypted_base,
|
||||
kernel_len, workarea_start, (unsigned long)ppd.pgd);
|
||||
|
||||
if (initrd_len)
|
||||
sme_encrypt_execute(initrd_start, initrd_start + decrypted_base,
|
||||
initrd_len, workarea_start,
|
||||
(unsigned long)ppd.pgd);
|
||||
|
||||
/*
|
||||
* At this point we are running encrypted. Remove the mappings for
|
||||
* the decrypted areas - all that is needed for this is to remove
|
||||
@ -882,6 +926,12 @@ void __init sme_encrypt_kernel(void)
|
||||
ppd.vaddr_end = kernel_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
|
||||
if (initrd_len) {
|
||||
ppd.vaddr = initrd_start + decrypted_base;
|
||||
ppd.vaddr_end = initrd_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
}
|
||||
|
||||
ppd.vaddr = workarea_start + decrypted_base;
|
||||
ppd.vaddr_end = workarea_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
|
@ -22,9 +22,9 @@ ENTRY(sme_encrypt_execute)
|
||||
|
||||
/*
|
||||
* Entry parameters:
|
||||
* RDI - virtual address for the encrypted kernel mapping
|
||||
* RSI - virtual address for the decrypted kernel mapping
|
||||
* RDX - length of kernel
|
||||
* RDI - virtual address for the encrypted mapping
|
||||
* RSI - virtual address for the decrypted mapping
|
||||
* RDX - length to encrypt
|
||||
* RCX - virtual address of the encryption workarea, including:
|
||||
* - stack page (PAGE_SIZE)
|
||||
* - encryption routine page (PAGE_SIZE)
|
||||
@ -41,9 +41,9 @@ ENTRY(sme_encrypt_execute)
|
||||
addq $PAGE_SIZE, %rax /* Workarea encryption routine */
|
||||
|
||||
push %r12
|
||||
movq %rdi, %r10 /* Encrypted kernel */
|
||||
movq %rsi, %r11 /* Decrypted kernel */
|
||||
movq %rdx, %r12 /* Kernel length */
|
||||
movq %rdi, %r10 /* Encrypted area */
|
||||
movq %rsi, %r11 /* Decrypted area */
|
||||
movq %rdx, %r12 /* Area length */
|
||||
|
||||
/* Copy encryption routine into the workarea */
|
||||
movq %rax, %rdi /* Workarea encryption routine */
|
||||
@ -52,10 +52,10 @@ ENTRY(sme_encrypt_execute)
|
||||
rep movsb
|
||||
|
||||
/* Setup registers for call */
|
||||
movq %r10, %rdi /* Encrypted kernel */
|
||||
movq %r11, %rsi /* Decrypted kernel */
|
||||
movq %r10, %rdi /* Encrypted area */
|
||||
movq %r11, %rsi /* Decrypted area */
|
||||
movq %r8, %rdx /* Pagetables used for encryption */
|
||||
movq %r12, %rcx /* Kernel length */
|
||||
movq %r12, %rcx /* Area length */
|
||||
movq %rax, %r8 /* Workarea encryption routine */
|
||||
addq $PAGE_SIZE, %r8 /* Workarea intermediate copy buffer */
|
||||
|
||||
@ -71,7 +71,7 @@ ENDPROC(sme_encrypt_execute)
|
||||
|
||||
ENTRY(__enc_copy)
|
||||
/*
|
||||
* Routine used to encrypt kernel.
|
||||
* Routine used to encrypt memory in place.
|
||||
* This routine must be run outside of the kernel proper since
|
||||
* the kernel will be encrypted during the process. So this
|
||||
* routine is defined here and then copied to an area outside
|
||||
@ -79,19 +79,19 @@ ENTRY(__enc_copy)
|
||||
* during execution.
|
||||
*
|
||||
* On entry the registers must be:
|
||||
* RDI - virtual address for the encrypted kernel mapping
|
||||
* RSI - virtual address for the decrypted kernel mapping
|
||||
* RDI - virtual address for the encrypted mapping
|
||||
* RSI - virtual address for the decrypted mapping
|
||||
* RDX - address of the pagetables to use for encryption
|
||||
* RCX - length of kernel
|
||||
* RCX - length of area
|
||||
* R8 - intermediate copy buffer
|
||||
*
|
||||
* RAX - points to this routine
|
||||
*
|
||||
* The kernel will be encrypted by copying from the non-encrypted
|
||||
* kernel space to an intermediate buffer and then copying from the
|
||||
* intermediate buffer back to the encrypted kernel space. The physical
|
||||
* addresses of the two kernel space mappings are the same which
|
||||
* results in the kernel being encrypted "in place".
|
||||
* The area will be encrypted by copying from the non-encrypted
|
||||
* memory space to an intermediate buffer and then copying from the
|
||||
* intermediate buffer back to the encrypted memory space. The physical
|
||||
* addresses of the two mappings are the same which results in the area
|
||||
* being encrypted "in place".
|
||||
*/
|
||||
/* Enable the new page tables */
|
||||
mov %rdx, %cr3
|
||||
@ -106,9 +106,9 @@ ENTRY(__enc_copy)
|
||||
push %r15
|
||||
push %r12
|
||||
|
||||
movq %rcx, %r9 /* Save kernel length */
|
||||
movq %rdi, %r10 /* Save encrypted kernel address */
|
||||
movq %rsi, %r11 /* Save decrypted kernel address */
|
||||
movq %rcx, %r9 /* Save area length */
|
||||
movq %rdi, %r10 /* Save encrypted area address */
|
||||
movq %rsi, %r11 /* Save decrypted area address */
|
||||
|
||||
/* Set the PAT register PA5 entry to write-protect */
|
||||
movl $MSR_IA32_CR_PAT, %ecx
|
||||
@ -128,13 +128,13 @@ ENTRY(__enc_copy)
|
||||
movq %r9, %r12
|
||||
|
||||
2:
|
||||
movq %r11, %rsi /* Source - decrypted kernel */
|
||||
movq %r11, %rsi /* Source - decrypted area */
|
||||
movq %r8, %rdi /* Dest - intermediate copy buffer */
|
||||
movq %r12, %rcx
|
||||
rep movsb
|
||||
|
||||
movq %r8, %rsi /* Source - intermediate copy buffer */
|
||||
movq %r10, %rdi /* Dest - encrypted kernel */
|
||||
movq %r10, %rdi /* Dest - encrypted area */
|
||||
movq %r12, %rcx
|
||||
rep movsb
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user