Re: [PATCH v4 2/6] powerpc/pseries: move the PLPKS config inside its own sysfs directory

Nayna Jain
2026-01-15T20:44:56Z

On 1/15/26 5:05 AM, Srish Srinivasan wrote:
> The /sys/firmware/secvar/config directory represents Power LPAR Platform
> KeyStore (PLPKS) configuration properties such as max_object_size, signed_
> update_algorithms, supported_policies, total_size, used_space, and version.
> These attributes describe the PLPKS, and not the secure boot variables
> (secvars).
>
> Create /sys/firmware/plpks directory and move the PLPKS config inside this
> directory. For backwards compatibility, create a soft link from the secvar
> sysfs directory to this config and emit a warning stating that the older
> sysfs path has been deprecated. Separate out the plpks specific
> documentation from secvar.
Again, Thanks for the patch.

Reviewed-by: Nayna Jain <nayna@linux.ibm.com>
>
> Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> .../ABI/testing/sysfs-firmware-plpks | 50 ++++++++++
> Documentation/ABI/testing/sysfs-secvar | 65 -------------
> arch/powerpc/include/asm/plpks.h | 5 +
> arch/powerpc/include/asm/secvar.h | 1 -
> arch/powerpc/kernel/secvar-sysfs.c | 21 ++---
> arch/powerpc/platforms/pseries/Makefile | 2 +-
> arch/powerpc/platforms/pseries/plpks-secvar.c | 29 ------
> arch/powerpc/platforms/pseries/plpks-sysfs.c | 94 +++++++++++++++++++
> 8 files changed, 156 insertions(+), 111 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-firmware-plpks
> create mode 100644 arch/powerpc/platforms/pseries/plpks-sysfs.c
>
> diff --git a/Documentation/ABI/testing/sysfs-firmware-plpks b/Documentation/ABI/testing/sysfs-firmware-plpks
> new file mode 100644
> index 000000000000..af0353f34115
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-firmware-plpks
> @@ -0,0 +1,50 @@
> +What: /sys/firmware/plpks/config
> +Date: February 2023
> +Contact: Nayna Jain <nayna@linux.ibm.com>
> +Description: This optional directory contains read-only config attributes as
> + defined by the PLPKS implementation. All data is in ASCII
> + format.
> +
> +What: /sys/firmware/plpks/config/version
> +Date: February 2023
> +Contact: Nayna Jain <nayna@linux.ibm.com>
> +Description: Config version as reported by the hypervisor in ASCII decimal
> + format.
> +
> +What: /sys/firmware/plpks/config/max_object_size
> +Date: February 2023
> +Contact: Nayna Jain <nayna@linux.ibm.com>
> +Description: Maximum allowed size of objects in the keystore in bytes,
> + represented in ASCII decimal format.
> +
> + This is not necessarily the same as the max size that can be
> + written to an update file as writes can contain more than
> + object data, you should use the size of the update file for
> + that purpose.
> +
> +What: /sys/firmware/plpks/config/total_size
> +Date: February 2023
> +Contact: Nayna Jain <nayna@linux.ibm.com>
> +Description: Total size of the PLPKS in bytes, represented in ASCII decimal
> + format.
> +
> +What: /sys/firmware/plpks/config/used_space
> +Date: February 2023
> +Contact: Nayna Jain <nayna@linux.ibm.com>
> +Description: Current space consumed by the key store, in bytes, represented
> + in ASCII decimal format.
> +
> +What: /sys/firmware/plpks/config/supported_policies
> +Date: February 2023
> +Contact: Nayna Jain <nayna@linux.ibm.com>
> +Description: Bitmask of supported policy flags by the hypervisor, represented
> + as an 8 byte hexadecimal ASCII string. Consult the hypervisor
> + documentation for what these flags are.
> +
> +What: /sys/firmware/plpks/config/signed_update_algorithms
> +Date: February 2023
> +Contact: Nayna Jain <nayna@linux.ibm.com>
> +Description: Bitmask of flags indicating which algorithms the hypervisor
> + supports for signed update of objects, represented as a 16 byte
> + hexadecimal ASCII string. Consult the hypervisor documentation
> + for what these flags mean.
> diff --git a/Documentation/ABI/testing/sysfs-secvar b/Documentation/ABI/testing/sysfs-secvar
> index 1016967a730f..c52a5fd15709 100644
> --- a/Documentation/ABI/testing/sysfs-secvar
> +++ b/Documentation/ABI/testing/sysfs-secvar
> @@ -63,68 +63,3 @@ Contact: Nayna Jain <nayna@linux.ibm.com>
> Description: A write-only file that is used to submit the new value for the
> variable. The size of the file represents the maximum size of
> the variable data that can be written.
> -
> -What: /sys/firmware/secvar/config
> -Date: February 2023
> -Contact: Nayna Jain <nayna@linux.ibm.com>
> -Description: This optional directory contains read-only config attributes as
> - defined by the secure variable implementation. All data is in
> - ASCII format. The directory is only created if the backing
> - implementation provides variables to populate it, which at
> - present is only PLPKS on the pseries platform.
> -
> -What: /sys/firmware/secvar/config/version
> -Date: February 2023
> -Contact: Nayna Jain <nayna@linux.ibm.com>
> -Description: Config version as reported by the hypervisor in ASCII decimal
> - format.
> -
> - Currently only provided by PLPKS on the pseries platform.
> -
> -What: /sys/firmware/secvar/config/max_object_size
> -Date: February 2023
> -Contact: Nayna Jain <nayna@linux.ibm.com>
> -Description: Maximum allowed size of objects in the keystore in bytes,
> - represented in ASCII decimal format.
> -
> - This is not necessarily the same as the max size that can be
> - written to an update file as writes can contain more than
> - object data, you should use the size of the update file for
> - that purpose.
> -
> - Currently only provided by PLPKS on the pseries platform.
> -
> -What: /sys/firmware/secvar/config/total_size
> -Date: February 2023
> -Contact: Nayna Jain <nayna@linux.ibm.com>
> -Description: Total size of the PLPKS in bytes, represented in ASCII decimal
> - format.
> -
> - Currently only provided by PLPKS on the pseries platform.
> -
> -What: /sys/firmware/secvar/config/used_space
> -Date: February 2023
> -Contact: Nayna Jain <nayna@linux.ibm.com>
> -Description: Current space consumed by the key store, in bytes, represented
> - in ASCII decimal format.
> -
> - Currently only provided by PLPKS on the pseries platform.
> -
> -What: /sys/firmware/secvar/config/supported_policies
> -Date: February 2023
> -Contact: Nayna Jain <nayna@linux.ibm.com>
> -Description: Bitmask of supported policy flags by the hypervisor,
> - represented as an 8 byte hexadecimal ASCII string. Consult the
> - hypervisor documentation for what these flags are.
> -
> - Currently only provided by PLPKS on the pseries platform.
> -
> -What: /sys/firmware/secvar/config/signed_update_algorithms
> -Date: February 2023
> -Contact: Nayna Jain <nayna@linux.ibm.com>
> -Description: Bitmask of flags indicating which algorithms the hypervisor
> - supports for signed update of objects, represented as a 16 byte
> - hexadecimal ASCII string. Consult the hypervisor documentation
> - for what these flags mean.
> -
> - Currently only provided by PLPKS on the pseries platform.
> diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
> index f303922bf622..8829a13bfda0 100644
> --- a/arch/powerpc/include/asm/plpks.h
> +++ b/arch/powerpc/include/asm/plpks.h
> @@ -13,6 +13,7 @@
>
> #include <linux/types.h>
> #include <linux/list.h>
> +#include <linux/kobject.h>
>
> // Object policy flags from supported_policies
> #define PLPKS_OSSECBOOTAUDIT PPC_BIT32(1) // OS secure boot must be audit/enforce
> @@ -107,11 +108,15 @@ u16 plpks_get_passwordlen(void);
> void plpks_early_init_devtree(void);
>
> int plpks_populate_fdt(void *fdt);
> +
> +int plpks_config_create_softlink(struct kobject *from);
> #else // CONFIG_PSERIES_PLPKS
> static inline bool plpks_is_available(void) { return false; }
> static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); }
> static inline void plpks_early_init_devtree(void) { }
> static inline int plpks_populate_fdt(void *fdt) { BUILD_BUG(); }
> +static inline int plpks_config_create_softlink(struct kobject *from)
> + { return 0; }
> #endif // CONFIG_PSERIES_PLPKS
>
> #endif // _ASM_POWERPC_PLPKS_H
> diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
> index 4828e0ab7e3c..fd5006307f2a 100644
> --- a/arch/powerpc/include/asm/secvar.h
> +++ b/arch/powerpc/include/asm/secvar.h
> @@ -20,7 +20,6 @@ struct secvar_operations {
> int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
> ssize_t (*format)(char *buf, size_t bufsize);
> int (*max_size)(u64 *max_size);
> - const struct attribute **config_attrs;
>
> // NULL-terminated array of fixed variable names
> // Only used if get_next() isn't provided
> diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
> index ec900bce0257..4111b21962eb 100644
> --- a/arch/powerpc/kernel/secvar-sysfs.c
> +++ b/arch/powerpc/kernel/secvar-sysfs.c
> @@ -12,6 +12,7 @@
> #include <linux/string.h>
> #include <linux/of.h>
> #include <asm/secvar.h>
> +#include <asm/plpks.h>
>
> #define NAME_MAX_SIZE 1024
>
> @@ -145,19 +146,6 @@ static __init int update_kobj_size(void)
> return 0;
> }
>
> -static __init int secvar_sysfs_config(struct kobject *kobj)
> -{
> - struct attribute_group config_group = {
> - .name = "config",
> - .attrs = (struct attribute **)secvar_ops->config_attrs,
> - };
> -
> - if (secvar_ops->config_attrs)
> - return sysfs_create_group(kobj, &config_group);
> -
> - return 0;
> -}
> -
> static __init int add_var(const char *name)
> {
> struct kobject *kobj;
> @@ -260,12 +248,15 @@ static __init int secvar_sysfs_init(void)
> goto err;
> }
>
> - rc = secvar_sysfs_config(secvar_kobj);
> + rc = plpks_config_create_softlink(secvar_kobj);
> if (rc) {
> - pr_err("Failed to create config directory\n");
> + pr_err("Failed to create softlink to PLPKS config directory");
> goto err;
> }
>
> + pr_info("/sys/firmware/secvar/config is now deprecated.\n");
> + pr_info("Will be removed in future versions.\n");
> +
> if (secvar_ops->get_next)
> rc = secvar_sysfs_load();
> else
> diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
> index 931ebaa474c8..3ced289a675b 100644
> --- a/arch/powerpc/platforms/pseries/Makefile
> +++ b/arch/powerpc/platforms/pseries/Makefile
> @@ -30,7 +30,7 @@ obj-$(CONFIG_PAPR_SCM) += papr_scm.o
> obj-$(CONFIG_PPC_SPLPAR) += vphn.o
> obj-$(CONFIG_PPC_SVM) += svm.o
> obj-$(CONFIG_FA_DUMP) += rtas-fadump.o
> -obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
> +obj-$(CONFIG_PSERIES_PLPKS) += plpks.o plpks-sysfs.o
> obj-$(CONFIG_PPC_SECURE_BOOT) += plpks-secvar.o
> obj-$(CONFIG_PSERIES_PLPKS_SED) += plpks_sed_ops.o
> obj-$(CONFIG_SUSPEND) += suspend.o
> diff --git a/arch/powerpc/platforms/pseries/plpks-secvar.c b/arch/powerpc/platforms/pseries/plpks-secvar.c
> index f9e9cc40c9d0..a50ff6943d80 100644
> --- a/arch/powerpc/platforms/pseries/plpks-secvar.c
> +++ b/arch/powerpc/platforms/pseries/plpks-secvar.c
> @@ -20,33 +20,6 @@
> #include <asm/secvar.h>
> #include <asm/plpks.h>
>
> -// Config attributes for sysfs
> -#define PLPKS_CONFIG_ATTR(name, fmt, func) \
> - static ssize_t name##_show(struct kobject *kobj, \
> - struct kobj_attribute *attr, \
> - char *buf) \
> - { \
> - return sysfs_emit(buf, fmt, func()); \
> - } \
> - static struct kobj_attribute attr_##name = __ATTR_RO(name)
> -
> -PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version);
> -PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize);
> -PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize);
> -PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace);
> -PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies);
> -PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms);
> -
> -static const struct attribute *config_attrs[] = {
> - &attr_version.attr,
> - &attr_max_object_size.attr,
> - &attr_total_size.attr,
> - &attr_used_space.attr,
> - &attr_supported_policies.attr,
> - &attr_signed_update_algorithms.attr,
> - NULL,
> -};
> -
> static u32 get_policy(const char *name)
> {
> if ((strcmp(name, "db") == 0) ||
> @@ -225,7 +198,6 @@ static const struct secvar_operations plpks_secvar_ops_static = {
> .set = plpks_set_variable,
> .format = plpks_secvar_format,
> .max_size = plpks_max_size,
> - .config_attrs = config_attrs,
> .var_names = plpks_var_names_static,
> };
>
> @@ -234,7 +206,6 @@ static const struct secvar_operations plpks_secvar_ops_dynamic = {
> .set = plpks_set_variable,
> .format = plpks_secvar_format,
> .max_size = plpks_max_size,
> - .config_attrs = config_attrs,
> .var_names = plpks_var_names_dynamic,
> };
>
> diff --git a/arch/powerpc/platforms/pseries/plpks-sysfs.c b/arch/powerpc/platforms/pseries/plpks-sysfs.c
> new file mode 100644
> index 000000000000..01d526185783
> --- /dev/null
> +++ b/arch/powerpc/platforms/pseries/plpks-sysfs.c
> @@ -0,0 +1,94 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2025 IBM Corporation, Srish Srinivasan <ssrish@linux.ibm.com>
> + *
> + * This code exposes PLPKS config to user via sysfs
> + */
> +
> +#define pr_fmt(fmt) "plpks-sysfs: "fmt
> +
> +#include <linux/init.h>
> +#include <linux/printk.h>
> +#include <linux/types.h>
> +#include <asm/machdep.h>
> +#include <asm/plpks.h>
> +
> +/* config attributes for sysfs */
> +#define PLPKS_CONFIG_ATTR(name, fmt, func) \
> + static ssize_t name##_show(struct kobject *kobj, \
> + struct kobj_attribute *attr, \
> + char *buf) \
> + { \
> + return sysfs_emit(buf, fmt, func()); \
> + } \
> + static struct kobj_attribute attr_##name = __ATTR_RO(name)
> +
> +PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version);
> +PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize);
> +PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize);
> +PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace);
> +PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies);
> +PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n",
> + plpks_get_signedupdatealgorithms);
> +
> +static const struct attribute *config_attrs[] = {
> + &attr_version.attr,
> + &attr_max_object_size.attr,
> + &attr_total_size.attr,
> + &attr_used_space.attr,
> + &attr_supported_policies.attr,
> + &attr_signed_update_algorithms.attr,
> + NULL,
> +};
> +
> +static struct kobject *plpks_kobj, *plpks_config_kobj;
> +
> +int plpks_config_create_softlink(struct kobject *from)
> +{
> + if (!plpks_config_kobj)
> + return -EINVAL;
> + return sysfs_create_link(from, plpks_config_kobj, "config");
> +}
> +
> +static __init int plpks_sysfs_config(struct kobject *kobj)
> +{
> + struct attribute_group config_group = {
> + .name = NULL,
> + .attrs = (struct attribute **)config_attrs,
> + };
> +
> + return sysfs_create_group(kobj, &config_group);
> +}
> +
> +static __init int plpks_sysfs_init(void)
> +{
> + int rc;
> +
> + if (!plpks_is_available())
> + return -ENODEV;
> +
> + plpks_kobj = kobject_create_and_add("plpks", firmware_kobj);
> + if (!plpks_kobj) {
> + pr_err("Failed to create plpks kobj\n");
> + return -ENOMEM;
> + }
> +
> + plpks_config_kobj = kobject_create_and_add("config", plpks_kobj);
> + if (!plpks_config_kobj) {
> + pr_err("Failed to create plpks config kobj\n");
> + kobject_put(plpks_kobj);
> + return -ENOMEM;
> + }
> +
> + rc = plpks_sysfs_config(plpks_config_kobj);
> + if (rc) {
> + pr_err("Failed to create attribute group for plpks config\n");
> + kobject_put(plpks_config_kobj);
> + kobject_put(plpks_kobj);
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> +machine_subsys_initcall(pseries, plpks_sysfs_init);