x86/ioremap: Add hypervisor callback for private MMIO mapping in coco VM
authorMichael Kelley <mikelley@microsoft.com>
Thu, 9 Mar 2023 02:40:02 +0000 (18:40 -0800)
committerBorislav Petkov (AMD) <bp@alien8.de>
Sun, 26 Mar 2023 21:42:40 +0000 (23:42 +0200)
Current code always maps MMIO devices as shared (decrypted) in a
confidential computing VM. But Hyper-V guest VMs on AMD SEV-SNP with vTOM
use a paravisor running in VMPL0 to emulate some devices, such as the
IO-APIC and TPM. In such a case, the device must be accessed as private
(encrypted) because the paravisor emulates the device at an address below
vTOM, where all accesses are encrypted.

Add a new hypervisor callback to determine if an MMIO address should
be mapped private. The callback allows hypervisor-specific code to handle
any quirks, the use of a paravisor, etc. in determining whether a mapping
must be private. If the callback is not used by a hypervisor, default
to returning "false", which is consistent with normal coco VM behavior.

Use this callback as another special case to check for when doing
ioremap().  Just checking the starting address is sufficient as an
ioremap range must be all private or all shared.

Also make the callback in early boot IO-APIC mapping code that uses the
fixmap.

  [ bp: Touchups. ]

Signed-off-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/1678329614-3482-2-git-send-email-mikelley@microsoft.com
arch/x86/include/asm/x86_init.h
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/x86_init.c
arch/x86/mm/ioremap.c

index c1c8c581759d69bfe807a81bfa5eb3a799d2ebc8..acc20ae4079d312008cb80c6f50d6b0599721d6d 100644 (file)
@@ -259,11 +259,15 @@ struct x86_legacy_features {
  *                             VMMCALL under SEV-ES.  Needs to return 'false'
  *                             if the checks fail.  Called from the #VC
  *                             exception handler.
+ * @is_private_mmio:           For CoCo VMs, must map MMIO address as private.
+ *                             Used when device is emulated by a paravisor
+ *                             layer in the VM context.
  */
 struct x86_hyper_runtime {
        void (*pin_vcpu)(int cpu);
        void (*sev_es_hcall_prepare)(struct ghcb *ghcb, struct pt_regs *regs);
        bool (*sev_es_hcall_finish)(struct ghcb *ghcb, struct pt_regs *regs);
+       bool (*is_private_mmio)(u64 addr);
 };
 
 /**
index 1f83b052bb74e0894abd128d4c71dcd4e5e80f96..146671de9ddc418e7e3888801f2fb288a243543c 100644 (file)
@@ -66,6 +66,7 @@
 #include <asm/hw_irq.h>
 #include <asm/apic.h>
 #include <asm/pgtable.h>
+#include <asm/x86_init.h>
 
 #define        for_each_ioapic(idx)            \
        for ((idx) = 0; (idx) < nr_ioapics; (idx)++)
@@ -2680,10 +2681,15 @@ static void io_apic_set_fixmap(enum fixed_addresses idx, phys_addr_t phys)
        pgprot_t flags = FIXMAP_PAGE_NOCACHE;
 
        /*
-        * Ensure fixmaps for IOAPIC MMIO respect memory encryption pgprot
+        * Ensure fixmaps for IO-APIC MMIO respect memory encryption pgprot
         * bits, just like normal ioremap():
         */
-       flags = pgprot_decrypted(flags);
+       if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
+               if (x86_platform.hyper.is_private_mmio(phys))
+                       flags = pgprot_encrypted(flags);
+               else
+                       flags = pgprot_decrypted(flags);
+       }
 
        __set_fixmap(idx, phys, flags);
 }
index ef80d361b4632ec64bb8aacd0f0bf6e88acb1021..95be3831df73b0ecc17be92712df5bb33d4257a2 100644 (file)
@@ -134,6 +134,7 @@ static void enc_status_change_prepare_noop(unsigned long vaddr, int npages, bool
 static bool enc_status_change_finish_noop(unsigned long vaddr, int npages, bool enc) { return false; }
 static bool enc_tlb_flush_required_noop(bool enc) { return false; }
 static bool enc_cache_flush_required_noop(void) { return false; }
+static bool is_private_mmio_noop(u64 addr) {return false; }
 
 struct x86_platform_ops x86_platform __ro_after_init = {
        .calibrate_cpu                  = native_calibrate_cpu_early,
@@ -149,6 +150,7 @@ struct x86_platform_ops x86_platform __ro_after_init = {
        .realmode_reserve               = reserve_real_mode,
        .realmode_init                  = init_real_mode,
        .hyper.pin_vcpu                 = x86_op_int_noop,
+       .hyper.is_private_mmio          = is_private_mmio_noop,
 
        .guest = {
                .enc_status_change_prepare = enc_status_change_prepare_noop,
index 6453fbaedb081d204d49985dbbc73cb867ea736c..aa7d279321ea0cca935374b16b96fa349cdaacd2 100644 (file)
@@ -116,6 +116,11 @@ static void __ioremap_check_other(resource_size_t addr, struct ioremap_desc *des
        if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
                return;
 
+       if (x86_platform.hyper.is_private_mmio(addr)) {
+               desc->flags |= IORES_MAP_ENCRYPTED;
+               return;
+       }
+
        if (!IS_ENABLED(CONFIG_EFI))
                return;