| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- /*
- * AMD Memory Encryption Support
- *
- * Copyright (C) 2016 Advanced Micro Devices, Inc.
- *
- * Author: Tom Lendacky <thomas.lendacky@amd.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/linkage.h>
- #include <linux/init.h>
- #include <linux/mm.h>
- #include <asm/tlbflush.h>
- #include <asm/fixmap.h>
- /*
- * Since SME related variables are set early in the boot process they must
- * reside in the .data section so as not to be zeroed out when the .bss
- * section is later cleared.
- */
- unsigned long sme_me_mask __section(.data) = 0;
- EXPORT_SYMBOL_GPL(sme_me_mask);
- /* Buffer used for early in-place encryption by BSP, no locking needed */
- static char sme_early_buffer[PAGE_SIZE] __aligned(PAGE_SIZE);
- /*
- * This routine does not change the underlying encryption setting of the
- * page(s) that map this memory. It assumes that eventually the memory is
- * meant to be accessed as either encrypted or decrypted but the contents
- * are currently not in the desired state.
- *
- * This routine follows the steps outlined in the AMD64 Architecture
- * Programmer's Manual Volume 2, Section 7.10.8 Encrypt-in-Place.
- */
- static void __init __sme_early_enc_dec(resource_size_t paddr,
- unsigned long size, bool enc)
- {
- void *src, *dst;
- size_t len;
- if (!sme_me_mask)
- return;
- local_flush_tlb();
- wbinvd();
- /*
- * There are limited number of early mapping slots, so map (at most)
- * one page at time.
- */
- while (size) {
- len = min_t(size_t, sizeof(sme_early_buffer), size);
- /*
- * Create mappings for the current and desired format of
- * the memory. Use a write-protected mapping for the source.
- */
- src = enc ? early_memremap_decrypted_wp(paddr, len) :
- early_memremap_encrypted_wp(paddr, len);
- dst = enc ? early_memremap_encrypted(paddr, len) :
- early_memremap_decrypted(paddr, len);
- /*
- * If a mapping can't be obtained to perform the operation,
- * then eventual access of that area in the desired mode
- * will cause a crash.
- */
- BUG_ON(!src || !dst);
- /*
- * Use a temporary buffer, of cache-line multiple size, to
- * avoid data corruption as documented in the APM.
- */
- memcpy(sme_early_buffer, src, len);
- memcpy(dst, sme_early_buffer, len);
- early_memunmap(dst, len);
- early_memunmap(src, len);
- paddr += len;
- size -= len;
- }
- }
- void __init sme_early_encrypt(resource_size_t paddr, unsigned long size)
- {
- __sme_early_enc_dec(paddr, size, true);
- }
- void __init sme_early_decrypt(resource_size_t paddr, unsigned long size)
- {
- __sme_early_enc_dec(paddr, size, false);
- }
- void __init sme_early_init(void)
- {
- unsigned int i;
- if (!sme_me_mask)
- return;
- early_pmd_flags = __sme_set(early_pmd_flags);
- __supported_pte_mask = __sme_set(__supported_pte_mask);
- /* Update the protection map with memory encryption mask */
- for (i = 0; i < ARRAY_SIZE(protection_map); i++)
- protection_map[i] = pgprot_encrypted(protection_map[i]);
- }
- void __init sme_encrypt_kernel(void)
- {
- }
- void __init sme_enable(void)
- {
- }
|