diff mbox series

[1/1] x86: Export information about hardware memory encryption to sysfs

Message ID 20210910213337.48017-2-martin.fernandez@eclypsium.com
State New
Headers show
Series x86: Export information about hardware memory encryption to sysfs | expand

Commit Message

Martin Fernandez Sept. 10, 2021, 9:33 p.m. UTC
Show on each local memory node if all system memory is flagged with
EFI_MEMORY_CPU_CRYPTO

Reviewed-by: Richard Hughes <hughsient@gmail.com>
Signed-off-by: Martin Fernandez <martin.fernandez@eclypsium.com>
---
 Documentation/ABI/testing/sysfs-devices-node | 11 +++
 arch/x86/include/asm/numa.h                  |  2 +
 arch/x86/mm/numa.c                           |  5 ++
 arch/x86/mm/numa_emulation.c                 |  2 +-
 arch/x86/platform/efi/efi.c                  | 27 +++++++
 drivers/base/node.c                          | 80 +++++++++++++++++++-
 include/linux/efi.h                          |  7 ++
 include/linux/node.h                         |  5 ++
 8 files changed, 137 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-node

Comments

Dave Hansen Sept. 10, 2021, 9:42 p.m. UTC | #1
On 9/10/21 2:33 PM, Martin Fernandez wrote:
> +static void __init efi_set_mem_crypto(void)
> +{
> +	efi_memory_desc_t *md;
> +
> +	efi_mem_crypto = EFI_MEM_ENCRYPTION_CAPABLE;
> +
> +	for_each_efi_memory_desc(md) {
> +		switch (md->type) {
> +		/* System memory after ExitBootServices */
> +		case EFI_LOADER_CODE:
> +		case EFI_LOADER_DATA:
> +		case EFI_BOOT_SERVICES_CODE:
> +		case EFI_BOOT_SERVICES_DATA:
> +		case EFI_CONVENTIONAL_MEMORY:
> +		case EFI_ACPI_RECLAIM_MEMORY:
> +			if (!(md->attribute & EFI_MEMORY_CPU_CRYPTO)) {
> +				efi_mem_crypto = EFI_MEM_ENCRYPTION_NOT_CAPABLE;
> +				return;
> +			}
> +		}
> +	}
> +}

If the ABI is per-NUMA-node, shouldn't this be determining and reporting
of each individual node is EFI_MEMORY_CPU_CRYPTO instead of reporting a
system-wide value?

I understand that this was a lot easier to hack together than doing
that, but it could be extremely misleading to an end user.

Would it be possible that 'efi_mem_crypto' would need to be updated on a
memory hotplug event?
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-devices-node b/Documentation/ABI/testing/sysfs-devices-node
new file mode 100644
index 000000000000..8578e49c328a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-node
@@ -0,0 +1,11 @@ 
+What:		/sys/devices/system/node/nodeX/crypto_capable
+Date:		September 2021
+Contact:	Martin Fernandez <martin.fernandez@eclypsium.com>
+Users:		fwupd
+Description:
+		This value is 1 if all system memory is marked with
+		EFI_MEMORY_CPU_CRYPTO, indicating that the system
+		memory is capable of being protected with the CPU’s
+		memory cryptographic capabilities. It is 0
+		otherwise. This attribute will only be available if
+		node X is local.
diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h
index e3bae2b60a0d..fc2e8c2e0d14 100644
--- a/arch/x86/include/asm/numa.h
+++ b/arch/x86/include/asm/numa.h
@@ -20,6 +20,8 @@ 
 #define NODE_MIN_SIZE (4*1024*1024)
 
 extern int numa_off;
+extern bool dummy_numa;
+extern int emu_nid_to_phys[];
 
 /*
  * __apicid_to_node[] stores the raw mapping between physical apicid and
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index a1b5c71099e6..f2b70b6de87f 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -20,6 +20,7 @@ 
 #include "numa_internal.h"
 
 int numa_off;
+bool dummy_numa;
 nodemask_t numa_nodes_parsed __initdata;
 
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
@@ -712,6 +713,8 @@  static int __init dummy_numa_init(void)
 	node_set(0, numa_nodes_parsed);
 	numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
 
+	dummy_numa = true;
+
 	return 0;
 }
 
@@ -724,6 +727,8 @@  static int __init dummy_numa_init(void)
  */
 void __init x86_numa_init(void)
 {
+	dummy_numa = false;
+
 	if (!numa_off) {
 #ifdef CONFIG_ACPI_NUMA
 		if (!numa_init(x86_acpi_numa_init))
diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c
index 737491b13728..d92edbede560 100644
--- a/arch/x86/mm/numa_emulation.c
+++ b/arch/x86/mm/numa_emulation.c
@@ -10,7 +10,7 @@ 
 
 #include "numa_internal.h"
 
-static int emu_nid_to_phys[MAX_NUMNODES];
+int emu_nid_to_phys[MAX_NUMNODES];
 static char *emu_cmdline __initdata;
 
 int __init numa_emu_cmdline(char *str)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 147c30a81f15..778a2d21d0d0 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -441,6 +441,31 @@  static int __init efi_config_init(const efi_config_table_type_t *arch_tables)
 	return ret;
 }
 
+enum efi_mem_crypto_t efi_mem_crypto = EFI_MEM_ENCRYPTION_NOT_CAPABLE;
+
+static void __init efi_set_mem_crypto(void)
+{
+	efi_memory_desc_t *md;
+
+	efi_mem_crypto = EFI_MEM_ENCRYPTION_CAPABLE;
+
+	for_each_efi_memory_desc(md) {
+		switch (md->type) {
+		/* System memory after ExitBootServices */
+		case EFI_LOADER_CODE:
+		case EFI_LOADER_DATA:
+		case EFI_BOOT_SERVICES_CODE:
+		case EFI_BOOT_SERVICES_DATA:
+		case EFI_CONVENTIONAL_MEMORY:
+		case EFI_ACPI_RECLAIM_MEMORY:
+			if (!(md->attribute & EFI_MEMORY_CPU_CRYPTO)) {
+				efi_mem_crypto = EFI_MEM_ENCRYPTION_NOT_CAPABLE;
+				return;
+			}
+		}
+	}
+}
+
 void __init efi_init(void)
 {
 	if (IS_ENABLED(CONFIG_X86_32) &&
@@ -494,6 +519,8 @@  void __init efi_init(void)
 	set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 	efi_clean_memmap();
 
+	efi_set_mem_crypto();
+
 	if (efi_enabled(EFI_DBG))
 		efi_print_memmap();
 }
diff --git a/drivers/base/node.c b/drivers/base/node.c
index be16bbff11cc..c01ba33f2054 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -20,6 +20,7 @@ 
 #include <linux/pm_runtime.h>
 #include <linux/swap.h>
 #include <linux/slab.h>
+#include <linux/efi.h>
 
 static struct bus_type node_subsys = {
 	.name = "node",
@@ -68,6 +69,15 @@  static inline ssize_t cpulist_read(struct file *file, struct kobject *kobj,
 
 static BIN_ATTR_RO(cpulist, 0);
 
+#if defined(CONFIG_NUMA) && defined(CONFIG_EFI)
+static ssize_t crypto_capable_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%d\n", efi_mem_crypto);
+}
+static DEVICE_ATTR_RO(crypto_capable);
+#endif
+
 /**
  * struct node_access_nodes - Access class device to hold user visible
  * 			      relationships to other nodes.
@@ -584,6 +594,23 @@  static const struct attribute_group *node_dev_groups[] = {
 	NULL
 };
 
+#if defined(CONFIG_NUMA) && defined(CONFIG_EFI)
+static struct attribute *node_dev_crypto_attrs[] = {
+	&dev_attr_crypto_capable.attr,
+	NULL
+};
+
+static const struct attribute_group node_dev_crypto_group = {
+	.attrs = node_dev_crypto_attrs,
+};
+
+static const struct attribute_group *node_dev_crypto_groups[] = {
+	&node_dev_group,
+	&node_dev_crypto_group,
+	NULL
+};
+#endif
+
 #ifdef CONFIG_HUGETLBFS
 /*
  * hugetlbfs per node attributes registration interface:
@@ -644,6 +671,21 @@  static void node_device_release(struct device *dev)
 	kfree(node);
 }
 
+#if defined(CONFIG_NUMA) && defined(CONFIG_EFI)
+static const struct attribute_group **select_attr_groups(bool cpu_local)
+{
+	if (cpu_local)
+		return node_dev_crypto_groups;
+	else
+		return node_dev_groups;
+}
+#else
+static const struct attribute_group **select_attr_groups(bool cpu_local)
+{
+	return node_dev_groups;
+}
+#endif
+
 /*
  * register_node - Setup a sysfs device for a node.
  * @num - Node number to use when creating the device.
@@ -657,7 +699,8 @@  static int register_node(struct node *node, int num)
 	node->dev.id = num;
 	node->dev.bus = &node_subsys;
 	node->dev.release = node_device_release;
-	node->dev.groups = node_dev_groups;
+	node->dev.groups = select_attr_groups(node->cpu_local);
+
 	error = device_register(&node->dev);
 
 	if (error)
@@ -974,6 +1017,39 @@  static void init_node_hugetlb_work(int nid) { }
 
 #endif
 
+#ifdef CONFIG_NUMA
+#ifdef CONFIG_NUMA_EMU
+static int get_real_nid(int nid)
+{
+	return emu_nid_to_phys[nid];
+}
+#else
+static int get_real_nid(int nid)
+{
+	return nid;
+}
+#endif
+
+static void set_cpu_local(int nid)
+{
+	int real_nid;
+	bool cpu_local;
+
+	real_nid = get_real_nid(nid);
+
+#ifdef CONFIG_ACPI_NUMA
+	cpu_local =
+		dummy_numa ? real_nid == 0 : node_to_pxm(real_nid) != PXM_INVAL;
+#else
+	cpu_local = real_nid == 0;
+#endif
+
+	node_devices[nid]->cpu_local = cpu_local;
+}
+#else
+#define set_cpu_local(nid)
+#endif /* CONFIG_NUMA */
+
 int __register_one_node(int nid)
 {
 	int error;
@@ -983,6 +1059,8 @@  int __register_one_node(int nid)
 	if (!node_devices[nid])
 		return -ENOMEM;
 
+	set_cpu_local(nid);
+
 	error = register_node(node_devices[nid], nid);
 
 	/* link cpu under this node */
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 6b5d36babfcc..0d9b304b204e 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1282,4 +1282,11 @@  static inline struct efi_mokvar_table_entry *efi_mokvar_entry_find(
 }
 #endif
 
+enum efi_mem_crypto_t {
+	EFI_MEM_ENCRYPTION_NOT_CAPABLE,
+	EFI_MEM_ENCRYPTION_CAPABLE,
+};
+
+extern enum efi_mem_crypto_t efi_mem_crypto;
+
 #endif /* _LINUX_EFI_H */
diff --git a/include/linux/node.h b/include/linux/node.h
index 8e5a29897936..6df1f90480f2 100644
--- a/include/linux/node.h
+++ b/include/linux/node.h
@@ -19,6 +19,8 @@ 
 #include <linux/cpumask.h>
 #include <linux/list.h>
 #include <linux/workqueue.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_numa.h>
 
 /**
  * struct node_hmem_attrs - heterogeneous memory performance attributes
@@ -92,6 +94,9 @@  struct node {
 	struct list_head cache_attrs;
 	struct device *cache_dev;
 #endif
+#ifdef CONFIG_NUMA
+	bool cpu_local;
+#endif
 };
 
 struct memory_block;