On Fri, Sep 04, 2020 at 07:58:46PM +0530, Divya Bharathi wrote:
> The Dell WMI Systems Management Driver provides a sysfs
> interface for systems management to enable BIOS configuration
> capability on certain Dell Systems.
> 
> This driver allows user to configure Dell systems with a
> uniform common interface. To facilitate this, the patch
> introduces a generic way for driver to be able to create
> configurable BIOS Attributes available in Setup (F2) screen.
> 
> Cc: Hans de Goede <hdego...@redhat.com>
> Cc: Andy Shevchenko <andy.shevche...@gmail.com>
> 
> Co-developed-by: Mario Limonciello <mario.limoncie...@dell.com>
> Signed-off-by: Mario Limonciello <mario.limoncie...@dell.com>
> Co-developed-by: Prasanth KSR <prasanth....@dell.com>
> Signed-off-by: Prasanth KSR <prasanth....@dell.com>
> Signed-off-by: Divya Bharathi <divya_bhara...@dell.com>
> ---
> 
> ChangeLog from v1 to v2:
>  - use pr_fmt instead of pr_err(DRIVER_NAME
>  - re-order variables reverse xmas tree order
>  - correct returns of -1 to error codes
>  - correct usage of {} on some split line statements
>  - Refine all documentation deficiencies suggested by Hans
>  - Merge all attributes to a single directory
>  - Overhaul WMI interface interaction as suggested by Hans
>    * Move WMI driver registration to start of module
>    * Remove usage of lists that only use first entry for WMI interfaces
>    * Create a global structure shared across interface source files
>    * Make get_current_password function static
>    * Remove get_pending changes function, shared across global structure now.
> - Overhaul use of mutexes
>    * Make kset list mutex shared across source files
>    * Remove unneeded dell-wmi-sysman call_mutex
>    * Keep remaining call_mutexes in WMI functions
> - Move security area calculation into a function
> - Use NLS helper for utf8->utf16 conversion
> 
>  .../testing/sysfs-platform-dell-wmi-sysman    | 126 ++++
>  MAINTAINERS                                   |   9 +
>  drivers/platform/x86/Kconfig                  |  12 +
>  drivers/platform/x86/Makefile                 |   8 +
>  .../x86/dell-wmi-biosattr-interface.c         | 198 ++++++
>  .../platform/x86/dell-wmi-enum-attributes.c   | 214 +++++++
>  .../platform/x86/dell-wmi-int-attributes.c    | 195 ++++++
>  .../x86/dell-wmi-passobj-attributes.c         | 168 +++++
>  .../x86/dell-wmi-passwordattr-interface.c     | 200 ++++++
>  .../platform/x86/dell-wmi-string-attributes.c | 177 ++++++
>  .../platform/x86/dell-wmi-sysman-attributes.c | 572 ++++++++++++++++++
>  .../platform/x86/dell-wmi-sysman-attributes.h | 132 ++++
>  12 files changed, 2011 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
>  create mode 100644 drivers/platform/x86/dell-wmi-biosattr-interface.c
>  create mode 100644 drivers/platform/x86/dell-wmi-enum-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-int-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-passobj-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-passwordattr-interface.c
>  create mode 100644 drivers/platform/x86/dell-wmi-string-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman-attributes.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman 
> b/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
> new file mode 100644
> index 000000000000..e4b608275ea4
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
> @@ -0,0 +1,126 @@
> +What:                /sys/devices/platform/dell-wmi-sysman/attributes/
> +Date:                December 2020
> +KernelVersion:       5.10
> +Contact:     Divya Bharathi <divya.bhara...@dell.com>,
> +             Mario Limonciello <mario.limoncie...@dell.com>,
> +             Prasanth KSR <prasanth....@dell.com>
> +Description:
> +             The Dell WMI Systems Management Driver provides a sysfs 
> interface
> +             for systems management software to enable BIOS configuration
> +             capability on certain Dell systems. This directory exposes
> +             interfaces for interacting with BIOS attributes.
> +
> +             Attributes can accept a set of pre-defined valid values or a 
> range of
> +             numerical values or a string. An atribute can accept float as 
> well,
> +             if so '.' is used as decimal separator.
> +
> +             Also, BIOS Admin password and System Password can be set, reset 
> or
> +             cleared using these attributes. An "Admin" password is used for
> +             preventing modification to the BIOS settings. A "System" 
> password is
> +             required to boot a machine.
> +
> +             current_value:  A file that can be read to obtain the current
> +             value of the <attr>
> +
> +             This file can also be written to in order to update
> +             the value of a <attr>
> +
> +             default_value:  A file that can be read to obtain the default
> +             value of the <attr>
> +
> +             display_name:   A file that can be read to obtain a user 
> friendly
> +             description of the at <attr>
> +
> +             display_name_language_code:     A file that can be read to 
> obtain
> +             the IETF language tag corresponding to the "display_name" of 
> the <attr>
> +
> +             modifier:       A file that can be read to obtain 
> attribute-level
> +             dependency rule. It says an attribute X will become read-only or
> +             suppressed,     if attribute Y is not configured.
> +             For example, AutoOnHr becomes read-only if AutoOn is disabled
> +
> +             possible_value: A file that can be read to obtain the possible
> +             values of the <attr>. Values are separated using semi-colon.
> +
> +             value_modifier: A file that can be read to obtain value-level
> +             dependency. This file is similar to modifier but here, an 
> attribute's
> +             current value will be forcefully changed based dependent 
> attributes
> +             value.
> +             For example, current value of LegacyOrom will become Disabled if
> +             SecureBoot is Enabled.
> +
> +             lower_bound:    A file that can be read to obtain the lower
> +             bound value of the <attr>
> +
> +             upper_bound:    A file that can be read to obtain the upper
> +             bound value of the <attr>
> +
> +             scalar_increment:       A file that can be read to obtain the
> +             resolution of the incremental value this attribute accepts.
> +
> +             max_length:     A file that can be read to obtain the maximum
> +             length value of the <attr>
> +
> +             min_length:     A file that can be read to obtain the minimum
> +             length value of the <attr>
> +
> +             is_password_set:        A file that can be read
> +             to obtain flag to see if a password is set on <attr>
> +
> +             max_password_length:    A file that can be read to obtain the
> +             maximum length of the Password
> +
> +             min_password_length:    A file that can be read to obtain the
> +             minimum length of the Password
> +
> +             current_password: A write only value used for privileged access
> +             such as setting attributes when a system or admin password is 
> set
> +             or resetting to a new password
> +
> +             new_password: A write only value that when used in tandem with
> +             current_password will reset a system or admin password.
> +
> +What:                
> /sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
> +Date:                December 2020
> +KernelVersion:       5.10
> +Contact:     Divya Bharathi <divya.bhara...@dell.com>,
> +             Mario Limonciello <mario.limoncie...@dell.com>,
> +             Prasanth KSR <prasanth....@dell.com>
> +Description:
> +             This attribute can be used to reset the BIOS Configuration.
> +             Specifically, it tells which type of reset BIOS configuration 
> is being
> +             requested on the host.
> +
> +             Reading from it returns a list of supported options encoded as:
> +
> +                     'builtinsafe' (Built in safe configuration profile)
> +                     'lastknowngood' (Last known good saved configuration 
> profile)
> +                     'factory' (Default factory settings configuration 
> profile)
> +                     'custom' (Custom saved configuration profile)
> +
> +             The currently selected option is printed in square brackets as
> +             shown below:
> +
> +             # echo "factory" > 
> sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
> +
> +             # cat sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
> +             # builtinsafe lastknowngood [factory] custom
> +
> +             Note that any changes to this attribute requires a reboot
> +             for changes to take effect.
> +
> +What:                
> /sys/devices/platform/dell-wmi-sysman/attributes/pending_reboot
> +Date:                December 2020
> +KernelVersion:       5.10
> +Contact:     Divya Bharathi <divya.bhara...@dell.com>,
> +             Mario Limonciello <mario.limoncie...@dell.com>,
> +             Prasanth KSR <prasanth....@dell.com>
> +Description:
> +             A read-only attribute reads 1 if a reboot is necessary to apply
> +             pending BIOS attribute changes.
> +
> +                     0:      All BIOS attributes setting are current
> +                     1:      A reboot is necessary to get pending BIOS 
> attribute changes
> +                             applied
> +
> +
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 592467ba3f4d..36ca5671a62d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4940,6 +4940,15 @@ M:     Mario Limonciello <mario.limoncie...@dell.com>
>  S:   Maintained
>  F:   drivers/platform/x86/dell-wmi-descriptor.c
>  
> +DELL WMI SYSMAN DRIVER
> +M:   Divya Bharathi <divya.bhara...@dell.com>
> +M:   Mario Limonciello <mario.limoncie...@dell.com>
> +M:   Prasanth Ksr <prasanth....@dell.com>
> +L:   platform-driver-...@vger.kernel.org
> +S:   Maintained
> +F:   drivers/platform/x86/dell-wmi-*-attributes.*
> +F:   drivers/platform/x86/dell-wmi-*-interface.c
> +
>  DELL WMI NOTIFICATIONS DRIVER
>  M:   Matthew Garrett <mj...@srcf.ucam.org>
>  M:   Pali Rohár <p...@kernel.org>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 40219bba6801..80646b328d72 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -430,6 +430,18 @@ config DELL_WMI
>         To compile this driver as a module, choose M here: the module will
>         be called dell-wmi.
>  
> +config DELL_WMI_SYSMAN
> +     tristate "Dell WMI SYSMAN"
> +     depends on ACPI_WMI
> +     depends on DMI
> +     select NLS
> +     help
> +       This driver allows changing BIOS settings on many Dell machines from
> +       2018 and newer without the use of any additional software.
> +
> +       To compile this driver as a module, choose M here: the module will
> +       be called dell-wmi-sysman.
> +
>  config DELL_WMI_DESCRIPTOR
>       tristate
>       depends on ACPI_WMI
> diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
> index 5f823f7eff45..dc2ccb574192 100644
> --- a/drivers/platform/x86/Makefile
> +++ b/drivers/platform/x86/Makefile
> @@ -47,6 +47,14 @@ obj-$(CONFIG_DELL_WMI)                     += dell-wmi.o
>  obj-$(CONFIG_DELL_WMI_DESCRIPTOR)    += dell-wmi-descriptor.o
>  obj-$(CONFIG_DELL_WMI_AIO)           += dell-wmi-aio.o
>  obj-$(CONFIG_DELL_WMI_LED)           += dell-wmi-led.o
> +obj-$(CONFIG_DELL_WMI_SYSMAN)  += dell-wmi-sysman.o
> +dell-wmi-sysman-objs := dell-wmi-sysman-attributes.o \
> +                              dell-wmi-enum-attributes.o \
> +                              dell-wmi-int-attributes.o \
> +                              dell-wmi-string-attributes.o \
> +                              dell-wmi-passobj-attributes.o \
> +                              dell-wmi-passwordattr-interface.o \
> +                              dell-wmi-biosattr-interface.o
>  
>  # Fujitsu
>  obj-$(CONFIG_AMILO_RFKILL)   += amilo-rfkill.o
> diff --git a/drivers/platform/x86/dell-wmi-biosattr-interface.c 
> b/drivers/platform/x86/dell-wmi-biosattr-interface.c
> new file mode 100644
> index 000000000000..dda38d448fec
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-biosattr-interface.c
> @@ -0,0 +1,198 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to SET methods under BIOS attributes interface 
> GUID for use
> + * with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include <linux/nls.h>
> +#include <linux/wmi.h>
> +#include "dell-wmi-sysman-attributes.h"
> +
> +#define SETDEFAULTVALUES_METHOD_ID                                   0x02
> +#define SETBIOSDEFAULTS_METHOD_ID                                    0x03
> +#define SETATTRIBUTE_METHOD_ID                                               
> 0x04
> +
> +static DEFINE_MUTEX(call_mutex);
> +
> +extern struct dell_wmi_sysman_priv wmi_priv;
> +
> +static int call_biosattributes_interface(struct wmi_device *wdev, char 
> *in_args, size_t size,
> +                                     int method_id)
> +{
> +     struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
> +     struct acpi_buffer input;
> +     union acpi_object *obj;
> +     acpi_status status;
> +     int ret = -EIO;
> +
> +     input.length =  (acpi_size) size;
> +     input.pointer = in_args;
> +     status = wmidev_evaluate_method(wdev, 0, method_id, &input, &output);
> +     if (ACPI_FAILURE(status))
> +             return -EIO;
> +     obj = (union acpi_object *)output.pointer;
> +     if (obj->type == ACPI_TYPE_INTEGER)
> +             ret = obj->integer.value;
> +
> +     kfree(output.pointer);
> +     kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
> +     return map_wmi_error(ret);
> +}
> +
> +/**
> + * set_attribute() - Update an attribute value
> + * @a_name: The attribute name
> + * @a_value: The attribute value
> + *
> + * Sets an attribute to new value
> + **/
> +int set_attribute(const char *a_name, const char *a_value)
> +{
> +     size_t security_area_size, string_area_size, buffer_size;
> +     char *attribute_name, *attribute_value;
> +     u8 *name_len, *value_len;
> +     char *buffer;
> +     int ret;
> +
> +     /* build/calculate buffer */
> +     security_area_size = calculate_security_buffer();
> +     string_area_size = (strlen(a_name) + strlen(a_value))*2;
> +     buffer_size = security_area_size + string_area_size + sizeof(u16) * 2;
> +     buffer = kzalloc(buffer_size, GFP_KERNEL);
> +     if (!buffer)
> +             return -ENOMEM;
> +
> +     /* build security area */
> +     if (strlen(wmi_priv.current_admin_password) > 0)
> +             populate_security_buffer(buffer, 
> wmi_priv.current_admin_password);
> +
> +     /* build variables to set */
> +     name_len = buffer + security_area_size;
> +     attribute_name = name_len + sizeof(u16);
> +     *name_len = utf8s_to_utf16s(a_name, strlen(a_name), UTF16_HOST_ENDIAN,
> +                                 (wchar_t *) attribute_name, MAX_BUFF) * 2;
> +     if (*name_len < 0) {
> +             ret = -EINVAL;
> +             pr_err("UTF16 conversion failed");
> +             goto out_set_attribute;
> +     }
> +
> +     value_len = (u8 *) attribute_name + *name_len;
> +     attribute_value = value_len + sizeof(u16);
> +     *value_len = utf8s_to_utf16s(a_value, strlen(a_value), 
> UTF16_HOST_ENDIAN,
> +                                 (wchar_t *) attribute_value, MAX_BUFF) * 2;
> +     if (*value_len < 0) {
> +             ret = -EINVAL;
> +             pr_err("UTF16 conversion failed");
> +             goto out_set_attribute;
> +     }
> +
> +     mutex_lock(&call_mutex);
> +     if (!wmi_priv.bios_attr_wdev) {
> +             ret = -ENODEV;
> +             pr_err("no WMI backend bound");
> +             goto out_set_attribute;
> +     }
> +
> +     ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
> +                                         buffer, buffer_size,
> +                                         SETATTRIBUTE_METHOD_ID);
> +     if (ret == -EOPNOTSUPP)
> +             dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must 
> be configured");
> +     else if (ret == -EACCES)
> +             dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password");
> +
> +     wmi_priv.pending_changes = 1;
> +out_set_attribute:
> +     kfree(buffer);
> +     mutex_unlock(&call_mutex);
> +
> +     return ret;
> +}
> +
> +/**
> + * set_bios_defaults() - Resets BIOS defaults
> + * @deftype: the type of BIOS value reset to issue.
> + *
> + * Resets BIOS defaults
> + **/
> +int set_bios_defaults(u8 deftype)
> +{
> +     size_t security_area_size, buffer_size;
> +     size_t integer_area_size = sizeof(u8);
> +     u8 *defaultType;
> +     char *buffer;
> +     int ret;
> +
> +     security_area_size = calculate_security_buffer();
> +     buffer_size = security_area_size + integer_area_size;
> +     buffer = kzalloc(buffer_size, GFP_KERNEL);
> +     if (!buffer)
> +             return -ENOMEM;
> +
> +     /* build security area */
> +     if (strlen(wmi_priv.current_admin_password) > 0)
> +             populate_security_buffer(buffer, 
> wmi_priv.current_admin_password);
> +
> +     mutex_lock(&call_mutex);
> +     if (!wmi_priv.bios_attr_wdev) {
> +             ret = -ENODEV;
> +             pr_err("no WMI backend bound");
> +             goto out_bios_defaults;
> +     }
> +
> +     defaultType = buffer + security_area_size;
> +     *defaultType = deftype;
> +
> +     ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, 
> buffer_size,
> +                                         SETBIOSDEFAULTS_METHOD_ID);
> +     if (ret)
> +             dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults 
> failed: %d", ret);
> +     wmi_priv.pending_changes = 1;
> +out_bios_defaults:
> +     kfree(buffer);
> +     mutex_unlock(&call_mutex);
> +
> +     return ret;
> +}
> +
> +static int dell_wmi_bios_attr_set_interface_probe(struct wmi_device *wdev, 
> const void *context)
> +{
> +     wmi_priv.bios_attr_wdev = wdev;
> +     return 0;
> +}
> +
> +static int dell_wmi_bios_attr_set_interface_remove(struct wmi_device *wdev)
> +{
> +     mutex_lock(&call_mutex);
> +     wmi_priv.bios_attr_wdev = NULL;
> +     mutex_unlock(&call_mutex);
> +     return 0;
> +}
> +
> +static const struct wmi_device_id 
> dell_wmi_bios_attr_set_interface_id_table[] = {
> +     { .guid_string = DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID },
> +     { },
> +};
> +static struct wmi_driver dell_wmi_bios_attr_set_interface_driver = {
> +     .driver = {
> +             .name = DRIVER_NAME"-set"
> +     },
> +     .probe = dell_wmi_bios_attr_set_interface_probe,
> +     .remove = dell_wmi_bios_attr_set_interface_remove,
> +     .id_table = dell_wmi_bios_attr_set_interface_id_table,
> +};
> +
> +int init_dell_wmi_bios_attr_set_interface(void)
> +{
> +     return wmi_driver_register(&dell_wmi_bios_attr_set_interface_driver);
> +}
> +
> +void exit_dell_wmi_bios_attr_set_interface(void)
> +{
> +     wmi_driver_unregister(&dell_wmi_bios_attr_set_interface_driver);
> +}
> +
> +MODULE_DEVICE_TABLE(wmi, dell_wmi_bios_attr_set_interface_id_table);
> diff --git a/drivers/platform/x86/dell-wmi-enum-attributes.c 
> b/drivers/platform/x86/dell-wmi-enum-attributes.c
> new file mode 100644
> index 000000000000..f2370f067b6d
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-enum-attributes.c
> @@ -0,0 +1,214 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to enumeration type attributes under BIOS 
> Enumeration GUID for use
> + * with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman-attributes.h"
> +
> +static DEFINE_MUTEX(enum_mutex);
> +extern struct mutex kset_mutex;
> +
> +/* kept variable names same as in sysfs file name for sysfs_show macro 
> definition */
> +struct enumeration_data {
> +     char display_name_language_code[MAX_BUFF];
> +     char attribute_name[MAX_BUFF];
> +     char display_name[MAX_BUFF];
> +     char default_value[MAX_BUFF];
> +     char current_value[MAX_BUFF];
> +     char modifier[MAX_BUFF];
> +     int value_modifier_count;
> +     char value_modifier[MAX_BUFF];
> +     int possible_value_count;
> +     char possible_value[MAX_BUFF];
> +     char type[MAX_BUFF];
> +};
> +
> +static struct enumeration_data *enumeration_data;
> +static int enumeration_instances_count;
> +get_instance_id(enumeration);
> +
> +static ssize_t current_value_show(struct kobject *kobj, struct 
> kobj_attribute *attr, char *buf)
> +{
> +     int instance_id;
> +
> +     if (!capable(CAP_SYS_ADMIN))
> +             return -EPERM;
> +     instance_id = get_enumeration_instance_id(kobj);
> +     if (instance_id >= 0) {
> +             union acpi_object *obj;
> +
> +             obj = get_wmiobj_pointer(instance_id, 
> DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +             if (!obj)
> +                     return -AE_ERROR;
> +             strncpy_attr(enumeration_data[instance_id].current_value,
> +                    obj->package.elements[CURRENT_VAL].string.pointer);
> +             kfree(obj);
> +             return sprintf(buf, "%s\n", 
> enumeration_data[instance_id].current_value);
> +     }
> +     return -EIO;
> +}
> +
> +/**
> + * validate_enumeration_input() - Validate input of current_value against 
> possible values
> + * @instance_id: The instance on which input is validated
> + * @buf: Input value
> + **/
> +int validate_enumeration_input(int instance_id, const char *buf)
> +{
> +     char *options, *tmp, *p;
> +     int ret = -EINVAL;
> +
> +     options = tmp = kstrdup((enumeration_data[instance_id].possible_value), 
> GFP_KERNEL);
> +     if (!options)
> +             return -ENOMEM;
> +
> +     while ((p = strsep(&options, ";")) != NULL) {
> +             if (!*p)
> +                     continue;
> +             if (!strncasecmp(p, buf, strlen(p))) {
> +                     ret = 0;
> +                     break;
> +             }
> +     }
> +
> +     kfree(tmp);
> +     return ret;
> +}
> +
> +attribute_s_property_show(display_name_language_code, enumeration);
> +static struct kobj_attribute displ_langcode =
> +             __ATTR_RO(display_name_language_code);
> +
> +attribute_s_property_show(display_name, enumeration);
> +struct kobj_attribute displ_name =
> +             __ATTR_RO(display_name);
> +
> +attribute_s_property_show(default_value, enumeration);
> +struct kobj_attribute default_val =
> +             __ATTR_RO(default_value);
> +
> +attribute_property_store(current_value, enumeration);
> +struct kobj_attribute current_val =
> +             __ATTR_RW(current_value);
> +
> +attribute_s_property_show(modifier, enumeration);
> +struct kobj_attribute modifier =
> +             __ATTR_RO(modifier);
> +
> +attribute_s_property_show(value_modifier, enumeration);
> +struct kobj_attribute value_modfr =
> +             __ATTR_RO(value_modifier);
> +
> +attribute_s_property_show(possible_value, enumeration);
> +struct kobj_attribute poss_val =
> +             __ATTR_RO(possible_value);
> +
> +attribute_s_property_show(type, enumeration);
> +struct kobj_attribute type =
> +             __ATTR_RO(type);
> +
> +static struct attribute *enumeration_attrs[] = {
> +     &displ_langcode.attr,
> +     &displ_name.attr,
> +     &default_val.attr,
> +     &current_val.attr,
> +     &modifier.attr,
> +     &value_modfr.attr,
> +     &poss_val.attr,
> +     &type.attr,
> +     NULL,
> +};
> +
> +static const struct attribute_group enumeration_attr_group = {
> +     .attrs = enumeration_attrs,
> +};
> +
> +int alloc_enum_data(void)
> +{
> +     int ret = 0;
> +
> +     enumeration_instances_count = 
> get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +     enumeration_data = kzalloc((sizeof(struct enumeration_data) * 
> enumeration_instances_count),
> +                                     GFP_KERNEL);
> +     if (!enumeration_data)
> +             ret = -ENOMEM;
> +     return ret;
> +}
> +
> +/**
> + * populate_enum_data() - Populate all properties of an instance under 
> enumeration attribute
> + * @enumeration_obj: ACPI object with enumeration data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + **/
> +int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
> +                     struct kobject *attr_name_kobj)
> +{
> +     int retval = sysfs_create_group(attr_name_kobj, 
> &enumeration_attr_group);
> +     int i, next_obj;
> +
> +     if (retval)
> +             goto out;
> +
> +     mutex_lock(&enum_mutex);
> +     strncpy_attr(enumeration_data[instance_id].attribute_name,
> +             enumeration_obj[ATTR_NAME].string.pointer);
> +     strncpy_attr(enumeration_data[instance_id].display_name_language_code,
> +             enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer);
> +     strncpy_attr(enumeration_data[instance_id].display_name,
> +             enumeration_obj[DISPLAY_NAME].string.pointer);
> +     strncpy_attr(enumeration_data[instance_id].default_value,
> +             enumeration_obj[DEFAULT_VAL].string.pointer);
> +     strncpy_attr(enumeration_data[instance_id].current_value,
> +             enumeration_obj[CURRENT_VAL].string.pointer);
> +     strncpy_attr(enumeration_data[instance_id].modifier,
> +             enumeration_obj[MODIFIER].string.pointer);
> +
> +     next_obj = MODIFIER + 1;
> +
> +     enumeration_data[instance_id].value_modifier_count =
> +             (uintptr_t)enumeration_obj[next_obj].string.pointer;
> +
> +     for (i = 0; i < enumeration_data[instance_id].value_modifier_count; 
> i++) {
> +             strcat(enumeration_data[instance_id].value_modifier,
> +                     enumeration_obj[++next_obj].string.pointer);
> +             strcat(enumeration_data[instance_id].value_modifier, ";");
> +     }
> +
> +     enumeration_data[instance_id].possible_value_count =
> +             (uintptr_t) enumeration_obj[++next_obj].string.pointer;
> +
> +     for (i = 0; i < enumeration_data[instance_id].possible_value_count; 
> i++) {
> +             strcat(enumeration_data[instance_id].possible_value,
> +                     enumeration_obj[++next_obj].string.pointer);
> +             strcat(enumeration_data[instance_id].possible_value, ";");
> +     }
> +     strncpy_attr(enumeration_data[instance_id].type, "enumeration");
> +     mutex_unlock(&enum_mutex);
> +
> +out:
> +     return retval;
> +}
> +
> +/**
> + * exit_enum_attributes() - Clear all attribute data
> + * @kset: The kset to free
> + *
> + * Clears all data allocated for this group of attributes
> + **/
> +void exit_enum_attributes(struct kset *kset)
> +{
> +     struct kobject *pos, *next;
> +
> +     mutex_lock(&kset_mutex);
> +     list_for_each_entry_safe(pos, next, &kset->list, entry) {
> +             sysfs_remove_group(pos, &enumeration_attr_group);
> +     }
> +     mutex_unlock(&kset_mutex);
> +     mutex_lock(&enum_mutex);
> +     kfree(enumeration_data);
> +     mutex_unlock(&enum_mutex);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-int-attributes.c 
> b/drivers/platform/x86/dell-wmi-int-attributes.c
> new file mode 100644
> index 000000000000..d922d4f73ce9
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-int-attributes.c
> @@ -0,0 +1,195 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to integer type attributes under BIOS Integer 
> GUID for use with
> + * dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman-attributes.h"
> +
> +static DEFINE_MUTEX(int_mutex);
> +extern struct mutex kset_mutex;
> +
> +enum int_properties {LOWER_BOUND = 6, UPPER_BOUND, SCALAR_INCR};
> +
> +/* kept variable names same as in sysfs file name for sysfs_show macro 
> definition */
> +struct integer_data {
> +     char display_name_language_code[MAX_BUFF];
> +     char attribute_name[MAX_BUFF];
> +     char display_name[MAX_BUFF];
> +     int default_value;
> +     int current_value;
> +     char modifier[MAX_BUFF];
> +     int lower_bound;
> +     int upper_bound;
> +     int scalar_increment;
> +     char type[MAX_BUFF];
> +};
> +
> +static struct integer_data *integer_data;
> +static int integer_instances_count;
> +get_instance_id(integer);
> +
> +static ssize_t current_value_show(struct kobject *kobj, struct 
> kobj_attribute *attr, char *buf)
> +{
> +     int instance_id;
> +
> +     if (!capable(CAP_SYS_ADMIN))
> +             return -EPERM;
> +     instance_id = get_integer_instance_id(kobj);
> +     if (instance_id >= 0) {
> +             union acpi_object *obj;
> +
> +             obj = get_wmiobj_pointer(instance_id, 
> DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
> +             if (!obj)
> +                     return -AE_ERROR;
> +             integer_data[instance_id].current_value =
> +                     
> (uintptr_t)obj->package.elements[CURRENT_VAL].string.pointer;
> +             kfree(obj);
> +             return sprintf(buf, "%d\n", 
> integer_data[instance_id].current_value);
> +     }
> +     return -EIO;
> +}
> +
> +/**
> + * validate_integer_input() - Validate input of current_value against lower 
> and upper bound
> + * @instance_id: The instance on which input is validated
> + * @buf: Input value
> + **/
> +int validate_integer_input(int instance_id, const char *buf)
> +{
> +     int ret = -EINVAL;
> +     int in_val;
> +
> +     if (kstrtoint(buf, 0, &in_val))
> +             return ret;
> +     if ((in_val >= integer_data[instance_id].lower_bound) &&
> +     (in_val <= integer_data[instance_id].upper_bound))
> +             ret = 0;
> +
> +     return ret;
> +}
> +
> +attribute_s_property_show(display_name_language_code, integer);
> +static struct kobj_attribute integer_displ_langcode =
> +     __ATTR_RO(display_name_language_code);
> +
> +attribute_s_property_show(display_name, integer);
> +struct kobj_attribute integer_displ_name =
> +     __ATTR_RO(display_name);
> +
> +attribute_n_property_show(default_value, integer);
> +struct kobj_attribute integer_default_val =
> +     __ATTR_RO(default_value);
> +
> +attribute_property_store(current_value, integer);
> +struct kobj_attribute integer_current_val =
> +     __ATTR_RW(current_value);
> +
> +attribute_s_property_show(modifier, integer);
> +struct kobj_attribute integer_modifier =
> +     __ATTR_RO(modifier);
> +
> +attribute_n_property_show(lower_bound, integer);
> +struct kobj_attribute integer_lower_bound =
> +     __ATTR_RO(lower_bound);
> +
> +attribute_n_property_show(upper_bound, integer);
> +struct kobj_attribute integer_upper_bound =
> +     __ATTR_RO(upper_bound);
> +
> +attribute_n_property_show(scalar_increment, integer);
> +struct kobj_attribute integer_scalar_increment =
> +     __ATTR_RO(scalar_increment);
> +
> +attribute_s_property_show(type, integer);
> +struct kobj_attribute integer_type =
> +     __ATTR_RO(type);
> +
> +static struct attribute *integer_attrs[] = {
> +     &integer_displ_langcode.attr,
> +     &integer_displ_name.attr,
> +     &integer_default_val.attr,
> +     &integer_current_val.attr,
> +     &integer_modifier.attr,
> +     &integer_lower_bound.attr,
> +     &integer_upper_bound.attr,
> +     &integer_scalar_increment.attr,
> +     &integer_type.attr,
> +     NULL,
> +};
> +
> +static const struct attribute_group integer_attr_group = {
> +     .attrs = integer_attrs,
> +};
> +
> +int alloc_int_data(void)
> +{
> +     int ret = 0;
> +
> +     integer_instances_count = 
> get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
> +     integer_data = kzalloc((sizeof(struct integer_data) * 
> integer_instances_count), GFP_KERNEL);
> +     if (!integer_data)
> +             ret = -ENOMEM;
> +     return ret;
> +}
> +
> +/**
> + * populate_enum_data() - Populate all properties of an instance under 
> integer attribute
> + * @integer_obj: ACPI object with integer data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + **/
> +int populate_int_data(union acpi_object *integer_obj, int instance_id,
> +                     struct kobject *attr_name_kobj)
> +{
> +     int retval = sysfs_create_group(attr_name_kobj, &integer_attr_group);
> +
> +     if (retval)
> +             goto out;
> +
> +     mutex_lock(&int_mutex);
> +     strncpy_attr(integer_data[instance_id].attribute_name,
> +             integer_obj[ATTR_NAME].string.pointer);
> +     strncpy_attr(integer_data[instance_id].display_name_language_code,
> +             integer_obj[DISPL_NAME_LANG_CODE].string.pointer);
> +     strncpy_attr(integer_data[instance_id].display_name,
> +             integer_obj[DISPLAY_NAME].string.pointer);
> +     integer_data[instance_id].default_value =
> +             (uintptr_t)integer_obj[DEFAULT_VAL].string.pointer;
> +     integer_data[instance_id].current_value =
> +             (uintptr_t)integer_obj[CURRENT_VAL].string.pointer;
> +     strncpy_attr(integer_data[instance_id].modifier, 
> integer_obj[MODIFIER].string.pointer);
> +     integer_data[instance_id].lower_bound =
> +             (uintptr_t)integer_obj[LOWER_BOUND].string.pointer;
> +     integer_data[instance_id].upper_bound =
> +             (uintptr_t)integer_obj[UPPER_BOUND].string.pointer;
> +     integer_data[instance_id].scalar_increment =
> +             (uintptr_t)integer_obj[SCALAR_INCR].string.pointer;
> +     strncpy_attr(integer_data[instance_id].type, "integer");
> +     mutex_unlock(&int_mutex);
> +
> +out:
> +     return retval;
> +}
> +
> +/**
> + * exit_int_attributes() - Clear all attribute data
> + * @kset: The kset to free
> + *
> + * Clears all data allocated for this group of attributes
> + **/
> +void exit_int_attributes(struct kset *kset)
> +{
> +     struct kobject *pos, *next;
> +
> +     mutex_lock(&kset_mutex);
> +     list_for_each_entry_safe(pos, next, &kset->list, entry) {
> +             sysfs_remove_group(pos, &integer_attr_group);
> +     }
> +     mutex_unlock(&kset_mutex);
> +     mutex_lock(&int_mutex);
> +     kfree(integer_data);
> +     mutex_unlock(&int_mutex);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-passobj-attributes.c 
> b/drivers/platform/x86/dell-wmi-passobj-attributes.c
> new file mode 100644
> index 000000000000..87bb7772bb18
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-passobj-attributes.c
> @@ -0,0 +1,168 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to password object type attributes under BIOS 
> Password Object GUID for
> + * use with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman-attributes.h"
> +
> +static DEFINE_MUTEX(po_mutex);
> +extern struct mutex kset_mutex;
> +
> +enum po_properties {IS_PASS_SET = 1, MIN_PASS_LEN, MAX_PASS_LEN};
> +
> +/* kept variable names same as in sysfs file name for sysfs_show macro 
> definition */
> +struct po_data {
> +     char attribute_name[MAX_BUFF];
> +     int is_password_set;
> +     int min_password_length;
> +     int max_password_length;
> +     char type[MAX_BUFF];
> +};
> +
> +static struct po_data *po_data;
> +static int po_instances_count;
> +get_instance_id(po);
> +
> +static ssize_t is_password_set_show(struct kobject *kobj, struct 
> kobj_attribute *attr, char *buf)
> +{
> +     int instance_id = get_po_instance_id(kobj);
> +
> +     if (instance_id >= 0) {
> +             union acpi_object *obj;
> +
> +             obj = get_wmiobj_pointer(instance_id, 
> DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
> +             if (!obj)
> +                     return -AE_ERROR;
> +             po_data[instance_id].is_password_set =
> +                     
> (uintptr_t)obj->package.elements[IS_PASS_SET].string.pointer;
> +             kfree(obj);
> +             return sprintf(buf, "%d\n", 
> po_data[instance_id].is_password_set);
> +     }
> +     return -EIO;
> +}
> +
> +struct kobj_attribute po_is_pass_set =
> +             __ATTR_RO(is_password_set);
> +
> +static ssize_t current_password_store(struct kobject *kobj,
> +                                   struct kobj_attribute *attr,
> +                                   const char *buf, size_t count)
> +{
> +     char *p = memchr(buf, '\n', count);
> +     int ret;
> +
> +     if (p != NULL)
> +             *p = '\0';
> +     if (strlen(buf) > MAX_BUFF)
> +             return -EINVAL;
> +
> +     ret = set_current_password(kobj->name, buf);
> +     return ret ? ret : count;
> +}
> +
> +struct kobj_attribute po_current_password =
> +             __ATTR_WO(current_password);
> +
> +static ssize_t new_password_store(struct kobject *kobj,
> +                               struct kobj_attribute *attr,
> +                               const char *buf, size_t count)
> +{
> +     char *p = memchr(buf, '\n', count);
> +     int ret;
> +
> +     if (p != NULL)
> +             *p = '\0';
> +     if (strlen(buf) > MAX_BUFF)
> +             return -EINVAL;
> +
> +     ret = set_new_password(kobj->name, buf);
> +     return ret ? ret : count;
> +}
> +
> +struct kobj_attribute po_new_password =
> +             __ATTR_WO(new_password);
> +
> +attribute_n_property_show(min_password_length, po);
> +struct kobj_attribute po_min_pass_length =
> +             __ATTR_RO(min_password_length);
> +
> +attribute_n_property_show(max_password_length, po);
> +struct kobj_attribute po_max_pass_length =
> +             __ATTR_RO(max_password_length);
> +
> +attribute_s_property_show(type, po);
> +struct kobj_attribute po_type =
> +     __ATTR_RO(type);
> +
> +static struct attribute *po_attrs[] = {
> +     &po_is_pass_set.attr,
> +     &po_min_pass_length.attr,
> +     &po_max_pass_length.attr,
> +     &po_current_password.attr,
> +     &po_new_password.attr,
> +     &po_type.attr,
> +     NULL,
> +};
> +
> +static const struct attribute_group po_attr_group = {
> +     .attrs = po_attrs,
> +};
> +
> +int alloc_po_data(void)
> +{
> +     int ret = 0;
> +
> +     po_instances_count = 
> get_instance_count(DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
> +     po_data = kzalloc((sizeof(struct po_data) * po_instances_count), 
> GFP_KERNEL);
> +     if (!po_data)
> +             ret = -ENOMEM;
> +     return ret;
> +}
> +
> +/**
> + * populate_po_data() - Populate all properties of an instance under 
> password object attribute
> + * @po_obj: ACPI object with password object data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + **/
> +int populate_po_data(union acpi_object *po_obj, int instance_id, struct 
> kobject *attr_name_kobj)
> +{
> +     int retval = sysfs_create_group(attr_name_kobj, &po_attr_group);
> +
> +     if (retval)
> +             goto out;
> +
> +     mutex_lock(&po_mutex);
> +     strncpy_attr(po_data[instance_id].attribute_name, 
> po_obj[ATTR_NAME].string.pointer);
> +     po_data[instance_id].is_password_set = 
> (uintptr_t)po_obj[IS_PASS_SET].string.pointer;
> +     po_data[instance_id].min_password_length = 
> (uintptr_t)po_obj[MIN_PASS_LEN].string.pointer;
> +     po_data[instance_id].max_password_length = (uintptr_t) 
> po_obj[MAX_PASS_LEN].string.pointer;
> +     strncpy_attr(po_data[instance_id].type, "password_object");
> +     mutex_unlock(&po_mutex);
> +
> +out:
> +     return retval;
> +}
> +
> +/**
> + * exit_po_attributes() - Clear all attribute data
> + * @kset: The kset to free
> + *
> + * Clears all data allocated for this group of attributes
> + **/
> +void exit_po_attributes(struct kset *kset)
> +{
> +     struct kobject *pos, *next;
> +
> +     mutex_lock(&kset_mutex);
> +     list_for_each_entry_safe(pos, next, &kset->list, entry) {
> +             sysfs_remove_group(pos, &po_attr_group);
> +     }
> +     mutex_unlock(&kset_mutex);
> +     mutex_lock(&po_mutex);
> +     kfree(po_data);
> +     mutex_unlock(&po_mutex);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-passwordattr-interface.c 
> b/drivers/platform/x86/dell-wmi-passwordattr-interface.c
> new file mode 100644
> index 000000000000..d105608cbb86
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-passwordattr-interface.c
> @@ -0,0 +1,200 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to SET password methods under BIOS attributes 
> interface GUID
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include <linux/nls.h>
> +#include <linux/wmi.h>
> +#include "dell-wmi-sysman-attributes.h"
> +
> +static DEFINE_MUTEX(call_mutex);
> +extern struct dell_wmi_sysman_priv wmi_priv;
> +
> +static int call_password_interface(struct wmi_device *wdev, char *in_args, 
> size_t size)
> +{
> +     struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
> +     struct acpi_buffer input;
> +     union acpi_object *obj;
> +     acpi_status status;
> +     int ret = -EIO;
> +
> +     input.length =  (acpi_size) size;
> +     input.pointer = in_args;
> +     status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
> +     if (ACPI_FAILURE(status))
> +             return -EIO;
> +     obj = (union acpi_object *)output.pointer;
> +     if (obj->type == ACPI_TYPE_INTEGER)
> +             ret = obj->integer.value;
> +
> +     kfree(output.pointer);
> +     kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
> +     return map_wmi_error(ret);
> +}
> +
> +/**
> + * get_current_password() - Get the current stored password value
> + * @password_type: The type of password to store
> + **/
> +static char *get_current_password(const char *password_type)
> +{
> +     if (strcmp(password_type, "Admin") == 0)
> +             return wmi_priv.current_admin_password;
> +     if (strcmp(password_type, "System") == 0)
> +             return wmi_priv.current_system_password;
> +     dev_err(&wmi_priv.password_attr_wdev->dev, "unknown password type %s", 
> password_type);
> +     return NULL;
> +}
> +
> +/**
> + * set_current_password() - Store current password
> + * @password_type: The type of password to store
> + * @current: The current value
> + *
> + * Sets the current value of the password.
> + * This is used for:
> + *  - Resetting password
> + *  - Basis for any functions requiring password to execute
> + **/
> +int set_current_password(const char *password_type, const char *cur)
> +{
> +     char *current_password = get_current_password(password_type);
> +
> +     if (!current_password)
> +             return -ENODEV;
> +     strncpy(current_password, cur, (strlen(cur) + 1));
> +     return 0;
> +}
> +
> +/**
> + * set_new_password() - Sets a system admin password
> + * @password_type: The type of password to set
> + * @new: The new password
> + *
> + * Sets the password using plaintext interface
> + **/
> +int set_new_password(const char *password_type, const char *new)
> +{
> +     char *current_password, *type_value, *old_value, *new_value;
> +     size_t security_area_size, string_area_size, buffer_size;
> +     u8 *type_len, *old_len, *new_len;
> +     char *buffer;
> +     int ret;
> +
> +     /* only allow one password set at a time */
> +     mutex_lock(&call_mutex);
> +     if (!wmi_priv.password_attr_wdev) {
> +             ret = -ENODEV;
> +             pr_err("no WMI backend bound");
> +             goto out_close_mutex;
> +     }
> +     current_password = get_current_password(password_type);
> +     if (!current_password) {
> +             ret = -ENODEV;
> +             goto out_close_mutex;
> +     }
> +
> +     /* build/calculate buffer */
> +     security_area_size = calculate_security_buffer();
> +     string_area_size = (strlen(password_type) + strlen(current_password) + 
> strlen(new))*2;
> +     buffer_size = security_area_size + string_area_size + sizeof(u16) * 3;
> +     buffer = kzalloc(buffer_size, GFP_KERNEL);
> +     if (!buffer) {
> +             ret = -ENOMEM;
> +             goto out_close_mutex;
> +     }
> +
> +     /* build security area */
> +     if (strlen(current_password) > 0)
> +             populate_security_buffer(buffer, current_password);
> +
> +     /* build variables to set */
> +     type_len = buffer + security_area_size;
> +     type_value = type_len + sizeof(u16);
> +     *type_len = utf8s_to_utf16s(password_type, strlen(password_type), 
> UTF16_HOST_ENDIAN,
> +                                 (wchar_t *) type_value, MAX_BUFF) * 2;
> +     if (*type_len < 0) {
> +             ret = -EINVAL;
> +             pr_err("UTF16 conversion failed");
> +             goto out_cleanup;
> +     }
> +
> +     old_len = type_value + *type_len;
> +     old_value = old_len + sizeof(u16);
> +     *old_len = utf8s_to_utf16s(current_password, strlen(current_password), 
> UTF16_HOST_ENDIAN,
> +                                (wchar_t *) old_value, MAX_BUFF) * 2;
> +     if (*old_len < 0) {
> +             ret = -EINVAL;
> +             pr_err("UTF16 conversion failed");
> +             goto out_cleanup;
> +     }
> +
> +     new_len = old_value + *old_len;
> +     new_value = new_len + sizeof(u16);
> +     *new_len = utf8s_to_utf16s(new, strlen(new), UTF16_HOST_ENDIAN,
> +                                (wchar_t *) new_value, MAX_BUFF) * 2;
> +     if (*new_len < 0) {
> +             ret = -EINVAL;
> +             pr_err("UTF16 conversion failed");
> +             goto out_cleanup;
> +     }
> +
> +     ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, 
> buffer_size);
> +     /* update current password so commands work after reset */
> +     if (!ret)
> +             ret = set_current_password(password_type, new);
> +     /* explain to user the detailed failure reason */
> +     else if (ret == -EOPNOTSUPP)
> +             dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must 
> be configured");
> +     else if (ret == -EACCES)
> +             dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password");
> +
> +out_cleanup:
> +     kfree(buffer);
> +
> +out_close_mutex:
> +     mutex_unlock(&call_mutex);
> +
> +     return ret;
> +}
> +
> +static int dell_wmi_bios_attr_pass_interface_probe(struct wmi_device *wdev, 
> const void *context)
> +{
> +     wmi_priv.password_attr_wdev = wdev;
> +     return 0;
> +}
> +
> +static int dell_wmi_bios_attr_pass_interface_remove(struct wmi_device *wdev)
> +{
> +     mutex_lock(&call_mutex);
> +     wmi_priv.password_attr_wdev = NULL;
> +     mutex_unlock(&call_mutex);
> +     return 0;
> +}
> +
> +static const struct wmi_device_id 
> dell_wmi_bios_attr_pass_interface_id_table[] = {
> +     { .guid_string = DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID },
> +     { },
> +};
> +static struct wmi_driver dell_wmi_bios_attr_pass_interface_driver = {
> +     .driver = {
> +             .name = DRIVER_NAME"-password"
> +     },
> +     .probe = dell_wmi_bios_attr_pass_interface_probe,
> +     .remove = dell_wmi_bios_attr_pass_interface_remove,
> +     .id_table = dell_wmi_bios_attr_pass_interface_id_table,
> +};
> +
> +int init_dell_wmi_bios_attr_pass_interface(void)
> +{
> +     return wmi_driver_register(&dell_wmi_bios_attr_pass_interface_driver);
> +}
> +
> +void exit_dell_wmi_bios_attr_pass_interface(void)
> +{
> +     wmi_driver_unregister(&dell_wmi_bios_attr_pass_interface_driver);
> +}
> +
> +MODULE_DEVICE_TABLE(wmi, dell_wmi_bios_attr_pass_interface_id_table);
> diff --git a/drivers/platform/x86/dell-wmi-string-attributes.c 
> b/drivers/platform/x86/dell-wmi-string-attributes.c
> new file mode 100644
> index 000000000000..397de6fb13a3
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-string-attributes.c
> @@ -0,0 +1,177 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to string type attributes under BIOS String GUID 
> for use with
> + * dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman-attributes.h"
> +
> +static DEFINE_MUTEX(str_mutex);
> +extern struct mutex kset_mutex;
> +
> +enum string_properties {MIN_LEN = 6, MAX_LEN};
> +
> +/* kept variable names same as in sysfs file name for sysfs_show macro 
> definition */
> +struct str_data {
> +     char display_name_language_code[MAX_BUFF];
> +     char attribute_name[MAX_BUFF];
> +     char display_name[MAX_BUFF];
> +     char default_value[MAX_BUFF];
> +     char current_value[MAX_BUFF];
> +     char modifier[MAX_BUFF];
> +     int min_length;
> +     int max_length;
> +     char type[MAX_BUFF];
> +};
> +
> +static struct str_data *str_data;
> +static int str_instances_count;
> +get_instance_id(str);
> +
> +static ssize_t current_value_show(struct kobject *kobj, struct 
> kobj_attribute *attr, char *buf)
> +{
> +     int instance_id;
> +
> +     if (!capable(CAP_SYS_ADMIN))
> +             return -EPERM;
> +     instance_id = get_str_instance_id(kobj);
> +     if (instance_id >= 0) {
> +             union acpi_object *obj;
> +
> +             obj = get_wmiobj_pointer(instance_id, 
> DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
> +             if (!obj)
> +                     return -AE_ERROR;
> +             strncpy_attr(str_data[instance_id].current_value,
> +                     obj->package.elements[CURRENT_VAL].string.pointer);
> +             kfree(obj);
> +             return sprintf(buf, "%s\n", 
> str_data[instance_id].current_value);
> +     }
> +     return -EIO;
> +}
> +
> +/**
> + * validate_str_input() - Validate input of current_value against min and 
> max lengths
> + * @instance_id: The instance on which input is validated
> + * @buf: Input value
> + **/
> +int validate_str_input(int instance_id, const char *buf)
> +{
> +     int in_len = strlen(buf);
> +
> +     if ((in_len >= str_data[instance_id].min_length) &&
> +     (in_len <= str_data[instance_id].max_length))
> +             return 0;
> +
> +     return -EINVAL;
> +}
> +
> +attribute_s_property_show(display_name_language_code, str);
> +static struct kobj_attribute str_displ_langcode =
> +             __ATTR_RO(display_name_language_code);
> +
> +attribute_s_property_show(display_name, str);
> +struct kobj_attribute str_displ_name =
> +             __ATTR_RO(display_name);
> +
> +attribute_s_property_show(default_value, str);
> +struct kobj_attribute str_default_val =
> +             __ATTR_RO(default_value);
> +
> +attribute_property_store(current_value, str);
> +struct kobj_attribute str_current_val =
> +             __ATTR_RW(current_value);
> +
> +attribute_s_property_show(modifier, str);
> +struct kobj_attribute str_modifier =
> +             __ATTR_RO(modifier);
> +
> +attribute_n_property_show(min_length, str);
> +struct kobj_attribute str_min_length =
> +             __ATTR_RO(min_length);
> +
> +attribute_n_property_show(max_length, str);
> +struct kobj_attribute str_max_length =
> +             __ATTR_RO(max_length);
> +
> +attribute_s_property_show(type, str);
> +struct kobj_attribute str_type =
> +     __ATTR_RO(type);
> +
> +static struct attribute *str_attrs[] = {
> +     &str_displ_langcode.attr,
> +     &str_displ_name.attr,
> +     &str_default_val.attr,
> +     &str_current_val.attr,
> +     &str_modifier.attr,
> +     &str_min_length.attr,
> +     &str_max_length.attr,
> +     &str_type.attr,
> +     NULL,
> +};
> +
> +static const struct attribute_group str_attr_group = {
> +     .attrs = str_attrs,
> +};
> +
> +int alloc_str_data(void)
> +{
> +     int ret = 0;
> +
> +     str_instances_count = 
> get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
> +     str_data = kzalloc((sizeof(struct str_data) * str_instances_count), 
> GFP_KERNEL);
> +     if (!str_data)
> +             ret = -ENOMEM;
> +     return ret;
> +}
> +
> +/**
> + * populate_enum_data() - Populate all properties of an instance under 
> string attribute
> + * @str_obj: ACPI object with integer data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + **/
> +int populate_str_data(union acpi_object *str_obj, int instance_id, struct 
> kobject *attr_name_kobj)
> +{
> +     int retval = sysfs_create_group(attr_name_kobj, &str_attr_group);
> +
> +     if (retval)
> +             goto out;
> +
> +     mutex_lock(&str_mutex);
> +     strncpy_attr(str_data[instance_id].attribute_name, 
> str_obj[ATTR_NAME].string.pointer);
> +     strncpy_attr(str_data[instance_id].display_name_language_code,
> +             str_obj[DISPL_NAME_LANG_CODE].string.pointer);
> +     strncpy_attr(str_data[instance_id].display_name, 
> str_obj[DISPLAY_NAME].string.pointer);
> +     strncpy_attr(str_data[instance_id].default_value, 
> str_obj[DEFAULT_VAL].string.pointer);
> +     strncpy_attr(str_data[instance_id].current_value, 
> str_obj[CURRENT_VAL].string.pointer);
> +     strncpy_attr(str_data[instance_id].modifier, 
> str_obj[MODIFIER].string.pointer);
> +     str_data[instance_id].min_length = 
> (uintptr_t)str_obj[MIN_LEN].string.pointer;
> +     str_data[instance_id].max_length = (uintptr_t) 
> str_obj[MAX_LEN].string.pointer;
> +     strncpy_attr(str_data[instance_id].type, "string");
> +     mutex_unlock(&str_mutex);
> +
> +out:
> +     return retval;
> +}
> +
> +/**
> + * exit_str_attributes() - Clear all attribute data
> + * @kset: The kset to free
> + *
> + * Clears all data allocated for this group of attributes
> + **/
> +void exit_str_attributes(struct kset *kset)
> +{
> +     struct kobject *pos, *next;
> +
> +     mutex_lock(&kset_mutex);
> +     list_for_each_entry_safe(pos, next, &kset->list, entry) {
> +             sysfs_remove_group(pos, &str_attr_group);
> +     }
> +     mutex_unlock(&kset_mutex);
> +     mutex_lock(&str_mutex);
> +     kfree(str_data);
> +     mutex_unlock(&str_mutex);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-sysman-attributes.c 
> b/drivers/platform/x86/dell-wmi-sysman-attributes.c
> new file mode 100644
> index 000000000000..139d8f5d3d8e
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman-attributes.c
> @@ -0,0 +1,572 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Common methods for use with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/dmi.h>
> +#include <linux/wmi.h>
> +#include "dell-wmi-sysman-attributes.h"
> +
> +DEFINE_MUTEX(kset_mutex);
> +
> +#define MAX_TYPES  4
> +
> +static struct platform_device *platform_device;
> +
> +static struct platform_driver platform_driver = {
> +     .driver = {
> +             .name = DRIVER_NAME,
> +     },
> +};
> +
> +/* global structure used by multiple WMI interfaces */
> +struct dell_wmi_sysman_priv wmi_priv;
> +
> +/* attribute directory under platform dev */
> +struct kset *main_dir_kset;
> +
> +/* reset bios to defaults */
> +static const char * const reset_types[] = {"builtinsafe", "lastknowngood", 
> "factory", "custom"};
> +static int reset_option = -1;
> +
> +/**
> + * calculate_security_buffer() - determines size of security buffer for 
> authentication scheme
> + *
> + * Currently only supported type is Admin password
> + **/
> +size_t calculate_security_buffer(void)
> +{
> +     if (strlen(wmi_priv.current_admin_password) > 0) {
> +             return (sizeof(u32) * 2) +
> +                     strlen(wmi_priv.current_admin_password) +
> +                     strlen(wmi_priv.current_admin_password) % 2;
> +     }
> +     return sizeof(u32) * 2;
> +}
> +
> +/**
> + * populate_security_buffer() - builds a security buffer for authentication 
> scheme
> + * @buffer: the buffer to populate
> + * @authentication: the authentication content
> + *
> + * Currently only supported type is PLAIN TEXT
> + **/
> +void populate_security_buffer(char *buffer, char *authentication)
> +{
> +     char *auth = buffer + sizeof(u32)*2;
> +     u32 *sectype = (u32 *) buffer;
> +     u32 *seclen = sectype + 1;
> +     /* plain text */
> +     *sectype = 1;
> +     *seclen = strlen(authentication);
> +     strncpy(auth, authentication, *seclen);
> +}
> +
> +/**
> + * map_wmi_error() - map errors from WMI methods to kernel error codes
> + **/
> +int map_wmi_error(int error_code)
> +{
> +     switch (error_code) {
> +     case 0:
> +             /* success */
> +             return 0;
> +     case 1:
> +             /* failed */
> +             return -EIO;
> +     case 2:
> +             /* invalid parameter */
> +             return -EINVAL;
> +     case 3:
> +             /* access denied */
> +             return -EACCES;
> +     case 4:
> +             /* not supported */
> +             return -EOPNOTSUPP;
> +     case 5:
> +             /* memory error */
> +             return -ENOMEM;
> +     case 6:
> +             /* protocol error */
> +             return -EPROTO;
> +     }
> +     /* unspecified error */
> +     return -EIO;
> +}
> +
> +/**
> + * reset_bios_show() - sysfs implementaton for read reset_bios
> + * @kobj: Kernel object for this attribute
> + * @attr: Kernel object attribute
> + * @buf: The buffer to display to userspace
> + **/
> +static ssize_t reset_bios_show(struct kobject *kobj, struct kobj_attribute 
> *attr, char *buf)
> +{
> +     char *start = buf;
> +     int i;
> +
> +     for (i = 0; i < MAX_TYPES; i++) {
> +             if (i == reset_option)
> +                     buf += sprintf(buf, "[%s] ", reset_types[i]);
> +             else
> +                     buf += sprintf(buf, "%s ", reset_types[i]);
> +     }
> +     buf += sprintf(buf, "\n");
> +     return buf-start;
> +}
> +
> +/**
> + * reset_bios_store() - sysfs implementaton for write reset_bios
> + * @kobj: Kernel object for this attribute
> + * @attr: Kernel object attribute
> + * @buf: The buffer from userspace
> + * @count: the size of the buffer from userspace
> + **/
> +static ssize_t reset_bios_store(struct kobject *kobj,
> +                             struct kobj_attribute *attr, const char *buf, 
> size_t count)
> +{
> +     int len, ret, i;
> +     int type = -1;
> +     char *p;
> +
> +     p = memchr(buf, '\n', count);
> +     if (p != NULL)
> +             *p = '\0';
> +     len = p ? p - buf : count;
> +
> +     for (i = 0; i < MAX_TYPES; i++) {
> +             if (len == strlen(reset_types[i])
> +                 && !strncmp(buf, reset_types[i], len)) {
> +                     type = i;
> +                     break;
> +             }
> +     }
> +
> +     if (type < 0 || type >= MAX_TYPES) {
> +             ret = -EINVAL;
> +             goto out;
> +     }
> +
> +     ret = set_bios_defaults(type);
> +     dev_dbg(&platform_device->dev, "reset all attributes request type %d: 
> %d", type, ret);
> +     if (ret) {
> +             ret = -EINVAL;
> +     } else {
> +             reset_option = type;
> +             ret = count;
> +     }
> +
> +out:
> +     return ret;
> +}
> +
> +/**
> + * pending_reboot_show() - sysfs implementaton for read pending_reboot
> + * @kobj: Kernel object for this attribute
> + * @attr: Kernel object attribute
> + * @buf: The buffer to display to userspace
> + *
> + * Stores default value as 0
> + * When current_value is changed this attribute is set to 1 to notify reboot 
> may be required
> + **/
> +static ssize_t pending_reboot_show(struct kobject *kobj, struct 
> kobj_attribute *attr,
> +                                char *buf)
> +{
> +     return sprintf(buf, "%d\n", wmi_priv.pending_changes);
> +}
> +
> +static struct kobj_attribute reset_bios = __ATTR_RW(reset_bios);
> +static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
> +
> +
> +/**
> + * create_reset_bios() - Creates reset_bios and pending_reboot attributes
> + **/
> +static int create_reset_bios(void)
> +{
> +     int ret = sysfs_create_file(&main_dir_kset->kobj, &reset_bios.attr);
> +
> +     if (ret) {
> +             dev_dbg(&platform_device->dev, "could not create reset_bios 
> file");
> +             return ret;
> +     }
> +
> +     ret = sysfs_create_file(&main_dir_kset->kobj, &pending_reboot.attr);
> +     if (ret) {
> +             dev_dbg(&platform_device->dev, "could not create 
> changing_pending_reboot file");
> +             sysfs_remove_file(&main_dir_kset->kobj, &reset_bios.attr);
> +     }
> +     return ret;
> +}
> +
> +static void release_reset_bios_data(void)
> +{
> +     sysfs_remove_file(&main_dir_kset->kobj, &reset_bios.attr);
> +     sysfs_remove_file(&main_dir_kset->kobj, &pending_reboot.attr);
> +}
> +
> +static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
> +                           char *buf)
> +{
> +     struct kobj_attribute *kattr;
> +     ssize_t ret = -EIO;
> +
> +     kattr = container_of(attr, struct kobj_attribute, attr);
> +     if (kattr->show)
> +             ret = kattr->show(kobj, kattr, buf);
> +     return ret;
> +}
> +
> +static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
> +                            const char *buf, size_t count)
> +{
> +     struct kobj_attribute *kattr;
> +     ssize_t ret = -EIO;
> +
> +     kattr = container_of(attr, struct kobj_attribute, attr);
> +     if (kattr->store)
> +             ret = kattr->store(kobj, kattr, buf, count);
> +     return ret;
> +}
> +
> +const struct sysfs_ops kobj_sysfs_ops = {
> +     .show   = kobj_attr_show,
> +     .store  = kobj_attr_store,
> +};
compile issue (x86_64, make defconfig, make menuconifg selected all pdx86
options built before using git am)  after git am building and selecting y for
the new config's defined by this patch:

Intel SCU IPC utility driver (INTEL_SCU_IPC_UTIL) [Y/n/m/?] y
UPD     include/config/kernel.release
UPD     include/generated/utsrelease.h
CALL    scripts/checksyscalls.sh
CALL    scripts/atomic/check-atomics.sh
DESCEND  objtool
CHK     include/generated/compile.h
CC      init/version.o
AR      init/built-in.a
CC      kernel/sys.o
CC      kernel/module.o
CC      kernel/trace/trace.o
AR      kernel/trace/built-in.a
AR      kernel/built-in.a
CC drivers/base/firmware_loader/fallback_table.o
CC      drivers/base/firmware_loader/main.o
CC drivers/base/firmware_loader/fallback.o
AR drivers/base/firmware_loader/built-in.a
AR      drivers/base/built-in.a
CC drivers/platform/x86/dell-wmi-sysman-attributes.o
CC drivers/platform/x86/dell-wmi-enum-attributes.o
CC drivers/platform/x86/dell-wmi-int-attributes.o
CC drivers/platform/x86/dell-wmi-string-attributes.o
CC drivers/platform/x86/dell-wmi-passobj-attributes.o
CC drivers/platform/x86/dell-wmi-passwordattr-interface.o
CC drivers/platform/x86/dell-wmi-biosattr-interface.o
AR drivers/platform/x86/built-in.a
AR drivers/platform/built-in.a
AR drivers/built-in.a
CC net/ethtool/ioctl.o
AR net/ethtool/built-in.a
AR net/built-in.a
GEN .version
CHK include/generated/compile.h
UPD include/generated/compile.h
CC init/version.o
AR init/built-in.a
LD vmlinux.o
drivers/platform/x86/dell-wmi-sysman-attributes.o:(.rodata+0x20): multiple
definition of `kobj_sysfs_ops'
lib/kobject.o:(.rodata+0x40): first defined here
Makefile:1166: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1

--mark

Reply via email to