X86 platform drivers
 help / color / mirror / Atom feed
From: "Limonciello, Mario" <mario.limonciello@amd.com>
To: Jorge Lopez <jorgealtxwork@gmail.com>
Cc: hdegoede@redhat.com, platform-driver-x86@vger.kernel.org
Subject: Re: [PATCH v1 1/1] Introduction of HP-BIOSCFG driver
Date: Mon, 10 Oct 2022 16:31:39 -0500	[thread overview]
Message-ID: <d88e15ba-9e3f-310d-118b-7ccb2fbe1ca9@amd.com> (raw)
In-Reply-To: <CAOOmCE--qzRCOgpfpW5j5VmnCPExdTVDM9yQ-PcXrec76e492Q@mail.gmail.com>

On 10/10/2022 16:26, Jorge Lopez wrote:
> Hi Mario,
> 
> On Mon, Oct 10, 2022 at 11:57 AM Limonciello, Mario
> <mario.limonciello@amd.com> wrote:
>>
>> Hi Jorge,
>>
>> Thanks for submitting this.  I had a try with a HP pro x360 435 that I
>> have on my side.
>>
>> I have some high level comments nested and below.
>>
>> 1) I noticed that some attributes are definitely read only, I wonder if
>> it makes sense to set current_value as "r" instead of "rw" in those cases.
>>
>> Such as "Born On Date" or "AMD PSP FW Version" and "BIOS Build Version"
> 
> It is a valid point.  The data reported by BIOS has an extra field
> that indicates if
> an attribute is readOnly or not.  Although all attributes are given
> 'rw' permissions,
> the driver checks for the IsReadOnly value to determine if the write
> command is allowed.
> 

Thanks.  If you make this change for v2, I can make the matching change 
in fwupd so that if it notices current_value permissions like this that 
it shows read only there too.

>>
>> 2) I noticed that "pending_reboot" is only updated for two attributes,
>> should it be updated for more than that?
>>
> 
> At this time, updating two attributes requires the system to reboot.   A reboot
> is necessary because BIOS requires the user to enter the Physical
> Presence Indicator
> (PPI) upon reboot.  I will check with the BIOS team if any other
> attributes require
> a reboot for the data to be updated.

I think other vendors use the "pending_reboot" to indicate that changes 
aren't technically "effective" until the reboot as well, not just PPI.

> 
>> 3) I didn't look exhaustively, but in a lot of cases the attribute name and
>> display_name key seem to have the same values.  Is that intended?
>>
> At this time, the attribute name and display key name are the same.
> This behavior is necessary for customers to reuse their signed payload
> created in
> CMSL (Windows) to be leveraged by the Linux driver.
> 

OK thanks.

This leaves some funny side effects on my system.  For example I don't 
know what this attribute means.  Do I get to remove a day of the week? =)

$ sudo grep -v foo 
/sys/class/firmware-attributes/hp-bioscfg/attributes/Tuesday/*
/sys/class/firmware-attributes/hp-bioscfg/attributes/Tuesday/current_value:Disable
/sys/class/firmware-attributes/hp-bioscfg/attributes/Tuesday/display_name:Tuesday
/sys/class/firmware-attributes/hp-bioscfg/attributes/Tuesday/display_name_language_code:en_US.UTF-8
/sys/class/firmware-attributes/hp-bioscfg/attributes/Tuesday/possible_values:Disable;Enable
/sys/class/firmware-attributes/hp-bioscfg/attributes/Tuesday/type:enumeration

If there are a lot of attributes like this, you should consider an extra 
override to exclude them from exporting or to better explain them in teh 
driver.

BTW I have a few other comments nested inline, take a look at those too.

> 
>> On 10/10/2022 11:23, Jorge Lopez wrote:
>>> The purpose for this patch is submit HP BIOSCFG driver to be list of
>>> HP Linux kernel drivers.  HP BIOS Configuration driver purpose is to
>>> provide a driver supporting the latest sysfs class firmware attributes
>>> framework allowing the user to change BIOS settings and security
>>> solutions on HP Inc.’s commercial notebooks.
>>>
>>> Many features of HP Commercial PC’s can be managed using Windows
>>> Management Instrumentation (WMI). WMI is an implementation of Web-Based
>>> Enterprise Management (WBEM) that provides a standards-based interface
>>> for changing and monitoring system settings.  HP BISOCFG driver provides
>>> a native Linux solution and the exposed features facilitates the
>>> migration to Linux environments.
>>>
>>> The Linux security features to be provided in hp-bioscfg driver enables
>>> managing the BIOS settings and security solutions via sysfs, a virtual
>>> filesystem that can be used by user-mode applications.   The new
>>> documentation cover features such Secure Platform Management, Sure
>>> Admin, and Sure Start.  Each section provides security feature
>>> description and identifies sysfs directories and files exposed by
>>> the driver.
>>>
>>> Many HP Commercial PC’s include a feature called Secure Platform
>>> Management (SPM), which replaces older password-based BIOS settings
>>> management with public key cryptography. PC secure product management
>>> begins when a target system is provisioned with cryptographic keys
>>> that are used to ensure the integrity of communications between system
>>> management utilities and the BIOS.
>>>
>>> HP Commercial PC’s have several BIOS settings that control its behaviour
>>> and capabilities, many of which are related to security. To prevent
>>> unauthorized changes to these settings, the system can be configured
>>> to use a Sure Admin cryptographic signature-based authorization string
>>> that the BIOS will use to verify authorization to modify the setting.
>>>
>>> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
>>>
>>> ---
>>> Based on the latest platform-drivers-x86.git/for-next
>>> ---
>>>    .../testing/sysfs-class-firmware-attributes   |  175 ++-
>>>    drivers/platform/x86/Kconfig                  |    1 +
>>>    drivers/platform/x86/Makefile                 |    1 +
>>>    drivers/platform/x86/hp/Kconfig               |   35 +
>>>    drivers/platform/x86/hp/Makefile              |   19 +
>>>    drivers/platform/x86/hp/biosattr-interface.c  |  286 +++++
>>>    drivers/platform/x86/hp/bioscfg.c             | 1029 +++++++++++++++++
>>>    drivers/platform/x86/hp/bioscfg.h             |  667 +++++++++++
>>>    drivers/platform/x86/hp/enum-attributes.c     |  504 ++++++++
>>>    drivers/platform/x86/hp/int-attributes.c      |  461 ++++++++
>>>    drivers/platform/x86/hp/ordered-attributes.c  |  568 +++++++++
>>>    .../platform/x86/hp/passwdattr-interface.c    |   50 +
>>>    .../platform/x86/hp/passwdobj-attributes.c    |  640 ++++++++++
>>>    drivers/platform/x86/hp/spmobj-attributes.c   |  408 +++++++
>>>    drivers/platform/x86/hp/string-attributes.c   |  447 +++++++
>>>    .../platform/x86/hp/sureadmin-attributes.c    |  984 ++++++++++++++++
>>>    .../platform/x86/hp/surestart-attributes.c    |  145 +++
>>>    17 files changed, 6419 insertions(+), 1 deletion(-)
>>>    create mode 100644 drivers/platform/x86/hp/Kconfig
>>>    create mode 100644 drivers/platform/x86/hp/Makefile
>>>    create mode 100644 drivers/platform/x86/hp/biosattr-interface.c
>>>    create mode 100644 drivers/platform/x86/hp/bioscfg.c
>>>    create mode 100644 drivers/platform/x86/hp/bioscfg.h
>>>    create mode 100644 drivers/platform/x86/hp/enum-attributes.c
>>>    create mode 100644 drivers/platform/x86/hp/int-attributes.c
>>>    create mode 100644 drivers/platform/x86/hp/ordered-attributes.c
>>>    create mode 100644 drivers/platform/x86/hp/passwdattr-interface.c
>>>    create mode 100644 drivers/platform/x86/hp/passwdobj-attributes.c
>>>    create mode 100644 drivers/platform/x86/hp/spmobj-attributes.c
>>>    create mode 100644 drivers/platform/x86/hp/string-attributes.c
>>>    create mode 100644 drivers/platform/x86/hp/sureadmin-attributes.c
>>>    create mode 100644 drivers/platform/x86/hp/surestart-attributes.c
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
>>> index 4cdba3477176..d3830b8a398f 100644
>>> --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
>>> +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
>>> @@ -22,6 +22,13 @@ Description:
>>>                        - integer: a range of numerical values
>>>                        - string
>>>
>>> +             HP specific types
>>> +             -----------------
>>> +                     - ordered-list - a set of ordered list valid values
>>> +                     - sure-admin
>>> +                     - sure-start
>>> +
>>> +
>>>                All attribute types support the following values:
>>>
>>>                current_value:
>>> @@ -126,6 +133,63 @@ Description:
>>>                                        value will not be effective through sysfs until this rule is
>>>                                        met.
>>>
>>> +             HP specific class extensions
>>> +             ------------------------------
>>> +
>>> +             On HP systems the following additional attributes are available:
>>> +
>>> +             "ordered-list"-type specific properties:
>>> +
>>> +             elements:
>>> +                                     A file that can be read to obtain the possible
>>> +                                     list of values of the <attr>. Values are separated using
>>> +                                     semi-colon (``;``)
>>
>> This should be clarified that it's values of particular priority when
>> written to current_value.
>>
>>> +
>>> +             "sure-admin"-type specific properties:
>>> +
>>> +             settings:
>>> +                                     A file associated with Sure Admin. BIOS settings can
>>> +                                     be read or written through the Sure Admin settings file in sysfs.
>>> +
>>> +                                     [BIOS setting],[new value],[auth token]
>>> +
>>> +                                     Sample settings reported data
>>> +
>>> +                                     {
>>> +                                             "Class": "HPBIOS_BIOSEnumeration",
>>> +                                             "Name": "USB Storage Boot",
>>> +                                             "Path": "\\Advanced\\Boot Options",
>>> +                                             "IsReadOnly": 0,
>>> +                                             ...
>>> +                                             "Value": "Enable",
>>> +                                             "Size": 2,
>>> +                                             "PossibleValues": [
>>> +                                                     "Disable",
>>> +                                                     "Enable"
>>> +                                                     ]
>>> +                                     }
>>> +
>>> +                                     This file can also be written to in order to update
>>> +                                     the value sof a <attr> using a CMSL generated payload.
>>> +                                     For example:
>>> +
>>> +                                     <attr>,[value],[CMSL generated payload]
>>> +
>>> +             "sure-start"-type specific properties:
>>> +
>>> +             audit_log_entries:
>>> +                                     A read-only file that returns the events in the log.
>>> +
>>> +                                     Audit log entry format
>>> +
>>> +                                     Byte 0-15:   Requested Audit Log entry  (Each Audit log is 16 bytes)
>>> +                                     Byte 16-127: Unused
>>> +
>>> +             audit_log_entry_count:
>>> +                                     A read-only file that returns the number of existing audit log events available to be read.
>>> +
>>> +                                     [No of entries],[log entry size],[Max number of entries supported]
>>> +
>>>    What:               /sys/class/firmware-attributes/*/authentication/
>>>    Date:               February 2021
>>>    KernelVersion:      5.11
>>> @@ -206,7 +270,7 @@ Description:
>>>                Drivers may emit a CHANGE uevent when a password is set or unset
>>>                userspace may check it again.
>>>
>>> -             On Dell and Lenovo systems, if Admin password is set, then all BIOS attributes
>>> +             On Dell, Lenovo, and HP systems, if Admin password is set, then all BIOS attributes
>>>                require password validation.
>>>                On Lenovo systems if you change the Admin password the new password is not active until
>>>                the next boot.
>>> @@ -296,6 +360,15 @@ Description:
>>>                                                echo "signature" > authentication/Admin/signature
>>>                                                echo "password" > authentication/Admin/certificate_to_password
>>>
>>> +             HP specific class extensions
>>> +             --------------------------------
>>> +
>>> +             On HP systems the following additional settings are available:
>>> +
>>> +             role: enhanced-bios-auth:
>>> +                                     This role is specific to Secure Platform Management (SPM) attribute.
>>> +                                     It requires configuring an endorsement (kek) and signing certificate (sk).
>>> +
>>>
>>>    What:               /sys/class/firmware-attributes/*/attributes/pending_reboot
>>>    Date:               February 2021
>>> @@ -364,3 +437,103 @@ Description:
>>>                use it to enable extra debug attributes or BIOS features for testing purposes.
>>>
>>>                Note that any changes to this attribute requires a reboot for changes to take effect.
>>> +
>>> +
>>> +             HP specific class extensions
>>> +             --------------------------------
>>> +
>>> +What:                /sys/class/firmware-attributes/*/authentication/SPM/kek
>>> +Date:                March 29
>>> +KernelVersion:       5.18
>>> +Contact:     "Jorge Lopez" <jorge.lopez2@hp.com>
>>> +Description: 'kek' is a write-only file that can be used to configure the
>>> +             RSA public key that will be used by the BIOS to verify
>>> +             signatures when setting the signing key.  When written,
>>> +             the bytes should correspond to the KEK certificate
>>> +             (x509 .DER format containing an OU).  The size of the
>>> +             certificate must be less than or equal to 4095 bytes.
>>> +
>>> +
>>> +What:                /sys/class/firmware-attributes/*/authentication/SPM/sk
>>> +Date:                March 29
>>> +KernelVersion:       5.18
>>> +Contact:     "Jorge Lopez" <jorge.lopez2@hp.com>
>>> +Description: 'sk' is a write-only file that can be used to configure the RSA
>>> +             public key that will be used by the BIOS to verify signatures
>>> +             when configuring BIOS settings and security features.  When
>>> +             written, the bytes should correspond to the modulus of the
>>> +             public key.  The exponent is assumed to be 0x10001.
>>> +
>>> +
>>> +What:                /sys/class/firmware-attributes/*/authentication/SPM/status
>>> +Date:                March 29
>>> +KernelVersion:       5.18
>>> +Contact:     "Jorge Lopez" <jorge.lopez2@hp.com>
>>> +Description: 'status' is a read-only file that returns ASCII text reporting
>>> +             the status information.
>>> +
>>> +               State:  Not Provisioned / Provisioned / Provisioning in progress
>>> +               Version:  Major.   Minor
>>> +               Feature Bit Mask: <16-bit unsigned number display in hex>
>>> +               SPM Counter: <16-bit unsigned number display in base 10>
>>> +               Signing Key Public Key Modulus (base64):
>>> +               KEK Public Key Modulus (base64):
>>> +
>>> +
>>> +What:                /sys/class/firmware-attributes/*/authentication/SPM/statusbin
>>> +Date:                March 29
>>> +KernelVersion:       5.18
>>> +Contact:     "Jorge Lopez" <jorge.lopez2@hp.com>
>>> +Description: 'statusbin' is a read-only file that returns identical status
>>> +             information reported by 'status' file in binary format.
>>> +
>>> +
>>> +What:                /sys/class/firmware-attributes/*/attributes/Sure_Admin/settings
>>> +Date:                March 29
>>> +KernelVersion:       5.18
>>> +Contact:     "Jorge Lopez" <jorge.lopez2@hp.com>
>>> +Description: 'settings' is a file associated with Sure Admin. BIOS settings can
>>> +             be read or written through the Sure Admin settings file in sysfs.
>>> +
>>> +             Expected data format to update BIOS setting
>>> +
>>> +               [BIOS setting],[new value],[auth token]
>>> +
>>> +             Sample settings reported data
>>> +
>>> +               {
>>> +                       "Class": "HPBIOS_BIOSEnumeration",
>>> +                       "Name": "USB Storage Boot",
>>> +                       "Path": "\\Advanced\\Boot Options",
>>> +                       "IsReadOnly": 0,
>>> +                       ...
>>> +                       "Value": "Enable",
>>> +                       "Size": 2,
>>> +                       "PossibleValues": [
>>> +                             "Disable",
>>> +                             "Enable"
>>> +                             ]
>>> +               }
>>> +
>>> +
>>> +What:                /sys/class/firmware-attributes/*/attributes/Sure_Start/audit_log_entry_count
>>> +Date:                March 29
>>> +KernelVersion:       5.18
>>> +Contact:     "Jorge Lopez" <jorge.lopez2@hp.com>
>>> +Description: audit_log_entry_count is a read-only file that returns the
>>> +             number of existing audit log events available to be read.
>>> +
>>> +               [No of entries],[log entry size],[Max number of entries supported]
>>> +
>>> +
>>> +What:                /sys/class/firmware-attributes/*/attributes/Sure_Start/audit_log_entries
>>> +Date:                March 29
>>> +KernelVersion:       5.18
>>> +Contact:     "Jorge Lopez" <jorge.lopez2@hp.com>
>>> +Description: audit_log_entries is a read-only file that returns the events
>>> +             in the log.
>>> +
>>> +             Audit log entry format
>>> +
>>> +               Byte 0-15:   Requested Audit Log entry  (Each Audit log is 16 bytes)
>>> +               Byte 16-127: Unused
>>> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
>>> index f5312f51de19..013f5510b5f2 100644
>>> --- a/drivers/platform/x86/Kconfig
>>> +++ b/drivers/platform/x86/Kconfig
>>> @@ -366,6 +366,7 @@ config EEEPC_WMI
>>>          here.
>>>
>>>    source "drivers/platform/x86/dell/Kconfig"
>>> +source "drivers/platform/x86/hp/Kconfig"
>>>
>>>    config AMILO_RFKILL
>>>        tristate "Fujitsu-Siemens Amilo rfkill support"
>>> diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
>>> index 5a428caa654a..7f4fdec482a5 100644
>>> --- a/drivers/platform/x86/Makefile
>>> +++ b/drivers/platform/x86/Makefile
>>> @@ -58,6 +58,7 @@ obj-$(CONFIG_GPD_POCKET_FAN)        += gpd-pocket-fan.o
>>>    obj-$(CONFIG_HP_ACCEL)              += hp_accel.o
>>>    obj-$(CONFIG_HP_WMI)                += hp-wmi.o
>>>    obj-$(CONFIG_TC1100_WMI)    += tc1100-wmi.o
>>> +obj-$(CONFIG_HP_BIOSCFG)        += hp/
>>>
>>>    # Hewlett Packard Enterprise
>>>    obj-$(CONFIG_UV_SYSFS)       += uv_sysfs.o
>>> diff --git a/drivers/platform/x86/hp/Kconfig b/drivers/platform/x86/hp/Kconfig
>>> new file mode 100644
>>> index 000000000000..b17b99449ee5
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/Kconfig
>>> @@ -0,0 +1,35 @@
>>> +# SPDX-License-Identifier: GPL-2.0-only
>>> +#
>>> +# HP X86 Platform Specific Drivers
>>> +#
>>> +
>>> +menuconfig X86_PLATFORM_DRIVERS_HP
>>> +     bool "HP X86 Platform Specific Device Drivers"
>>> +     depends on X86_PLATFORM_DEVICES
>>> +     help
>>> +       Say Y here to get to see options for device drivers for various
>>> +       HP x86 platforms, including vendor-specific laptop extension drivers.
>>> +       This option alone does not add any kernel code.
>>> +
>>> +       If you say N, all options in this submenu will be skipped and disabled.
>>> +
>>
>> Presumably if this is going into it's own directory you should move all
>> platform-x86 HP drivers to this directory earlier in the series too.
>>
>>> +if X86_PLATFORM_DRIVERS_HP
>>> +
>>> +config HP_BIOSCFG
>>> +     tristate "HP BIOS Configuration Driver"
>>> +     default m
>>> +     depends on ACPI_WMI
>>> +     depends on DMI
>>> +     select NLS
>>> +     select FW_ATTR_CLASS
>>> +     help
>>> +       This driver enables administrators to securely manage BIOS settings
>>> +       using digital certificates and public-key cryptography that eliminate
>>> +       the need for passwords for both remote and local management. It supports
>>> +          changing BIOS settings on many HP 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 hp-bioscfg.
>>> +
>>> +endif # X86_PLATFORM_DRIVERS_HP
>>> diff --git a/drivers/platform/x86/hp/Makefile b/drivers/platform/x86/hp/Makefile
>>> new file mode 100644
>>> index 000000000000..e3790e223084
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/Makefile
>>> @@ -0,0 +1,19 @@
>>> +obj-m           := hp-bioscfg.o
>>> +
>>> +hp-bioscfg-objs := bioscfg.o         \
>>> +     enum-attributes.o       \
>>> +     int-attributes.o        \
>>> +     string-attributes.o     \
>>> +     passwdobj-attributes.o  \
>>> +     biosattr-interface.o    \
>>> +     passwdattr-interface.o  \
>>> +     ordered-attributes.o    \
>>> +     surestart-attributes.o  \
>>> +     spmobj-attributes.o     \
>>> +     sureadmin-attributes.o
>>> +
>>> +default:
>>> +     make -C /lib/modules/`uname -r`/build M=$(PWD) hp-bioscfg.ko
>>> +
>>> +clean:
>>> +     make -C /lib/modules/`uname -r`/build M=$(PWD) clean
>>> diff --git a/drivers/platform/x86/hp/biosattr-interface.c b/drivers/platform/x86/hp/biosattr-interface.c
>>> new file mode 100644
>>> index 000000000000..c983ef21a9ed
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/biosattr-interface.c
>>> @@ -0,0 +1,286 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to methods under BIOS interface GUID
>>> + * for use with hp-bioscfg driver.
>>> + *
>>> + *  Copyright (c) 2022 Hewlett-Packard Inc.
>>> + */
>>> +
>>> +#include <linux/wmi.h>
>>> +#include "bioscfg.h"
>>> +#include <stddef.h>
>>> +
>>
>> I applied this to 6.0 but failed to build:
>>
>> drivers/platform/x86/hp/biosattr-interface.c:11:10: fatal error:
>> stddef.h: No such file or directory
>>      11 | #include <stddef.h>
>>         |          ^~~~~~~~~~
>>
>> I was able to fix my local build using this patch:
>>
>> --- a/drivers/platform/x86/hp/biosattr-interface.c
>> +++ b/drivers/platform/x86/hp/biosattr-interface.c
>> @@ -6,9 +6,9 @@
>>     *  Copyright (c) 2022 Hewlett-Packard Inc.
>>     */
>>
>> -#include <linux/wmi.h>
>>    #include "bioscfg.h"
>> -#include <stddef.h>
>> +#include <linux/stddef.h>
>> +#include <linux/wmi.h>
>>
>>    #define SET_DEFAULT_VALUES_METHOD_ID   0x02
>>    #define SET_BIOS_DEFAULTS_METHOD_ID    0x03
>>
>>> +#define SET_DEFAULT_VALUES_METHOD_ID 0x02
>>> +#define SET_BIOS_DEFAULTS_METHOD_ID  0x03
>>> +#define SET_ATTRIBUTE_METHOD_ID              0x04
>>> +
>>> +/*
>>> + * set_attribute() - Update an attribute value
>>> + * @a_name: The attribute name
>>> + * @a_value: The attribute value
>>> + *
>>> + * Sets an attribute to new value
>>> + */
>>> +int hp_set_attribute(const char *a_name, const char *a_value)
>>> +{
>>> +     size_t security_area_size;
>>> +     size_t a_name_size, a_value_size;
>>> +     u16 *buffer = NULL;
>>> +     u16 *start = NULL;
>>> +     int  buffer_size;
>>> +     int ret;
>>> +     int instance;
>>> +     char *auth_empty_value = " ";
>>> +
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     if (!bioscfg_drv.bios_attr_wdev) {
>>> +             ret = -ENODEV;
>>> +             goto out_set_attribute;
>>> +     }
>>> +
>>> +     instance = get_password_instance_for_type(SETUP_PASSWD);
>>> +     if (instance < 0)
>>> +             goto out_set_attribute;
>>> +
>>> +     if (strlen(bioscfg_drv.password_data[instance].current_password) == 0)
>>> +             strncpy(bioscfg_drv.password_data[instance].current_password,
>>> +                     auth_empty_value,
>>> +                     sizeof(bioscfg_drv.password_data[instance].current_password));
>>> +
>>> +     a_name_size = calculate_string_buffer(a_name);
>>> +     a_value_size = calculate_string_buffer(a_value);
>>> +     security_area_size = calculate_security_buffer(bioscfg_drv.password_data[instance].current_password);
>>> +     buffer_size = a_name_size + a_value_size + security_area_size;
>>> +
>>> +     buffer = kzalloc(buffer_size, GFP_KERNEL);
>>> +     if (!buffer) {
>>> +             ret = -ENOMEM;
>>> +             goto out_set_attribute;
>>> +     }
>>> +
>>> +     /* build variables to set */
>>> +     start = buffer;
>>> +     start = ascii_to_utf16_unicode(start, a_name);
>>> +     if (!start)
>>> +             goto out_set_attribute;
>>> +
>>> +     start = ascii_to_utf16_unicode(start, a_value);
>>> +     if (!start)
>>> +             goto out_set_attribute;
>>> +
>>> +     populate_security_buffer(start, bioscfg_drv.password_data[instance].current_password);
>>> +     ret = hp_wmi_set_bios_setting(buffer, buffer_size);
>>> +
>>> +
>>> +out_set_attribute:
>>> +     kfree(buffer);
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * hp_wmi_perform_query
>>> + *
>>> + * query:    The commandtype (enum hp_wmi_commandtype)
>>> + * write:    The command (enum hp_wmi_command)
>>> + * buffer:   Buffer used as input and/or output
>>> + * insize:   Size of input buffer
>>> + * outsize:  Size of output buffer
>>> + *
>>> + * returns zero on success
>>> + *         an HP WMI query specific error code (which is positive)
>>> + *         -EINVAL if the query was not successful at all
>>> + *         -EINVAL if the output buffer size exceeds buffersize
>>> + *
>>> + * Note: The buffersize must at least be the maximum of the input and output
>>> + *       size. E.g. Battery info query is defined to have 1 byte input
>>> + *       and 128 byte output. The caller would do:
>>> + *       buffer = kzalloc(128, GFP_KERNEL);
>>> + *       ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128)
>>> + */
>>> +int hp_wmi_perform_query(int query, enum hp_wmi_command command, void *buffer, int insize, int outsize)
>>> +{
>>> +     struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL };
>>> +     struct bios_return *bios_return;
>>> +     union acpi_object *obj = NULL;
>>> +     struct bios_args *args = NULL;
>>> +     int mid, actual_insize, actual_outsize;
>>> +     size_t bios_args_size;
>>> +     int ret;
>>> +
>>> +     mid = encode_outsize_for_pvsz(outsize);
>>> +     if (WARN_ON(mid < 0))
>>> +             return mid;
>>> +
>>> +     actual_insize = insize;
>>> +     bios_args_size = struct_size(args, data, insize);
>>> +     args = kmalloc(bios_args_size, GFP_KERNEL);
>>> +     if (!args)
>>> +             return -ENOMEM;
>>> +
>>> +     input.length = bios_args_size;
>>> +     input.pointer = args;
>>> +
>>> +     args->signature = 0x55434553;
>>> +     args->command = command;
>>> +     args->commandtype = query;
>>> +     args->datasize = insize;
>>> +     memcpy(args->data, buffer, flex_array_size(args, data, insize));
>>> +
>>> +     ret = wmi_evaluate_method(HP_WMI_BIOS_GUID, 0, mid, &input, &output);
>>> +     bioscfg_drv.last_wmi_status = ret;
>>> +     if (ret)
>>> +             goto out_free;
>>> +
>>> +     obj = output.pointer;
>>> +     if (!obj) {
>>> +             ret = -EINVAL;
>>> +             goto out_free;
>>> +     }
>>> +
>>> +     bios_return = (struct bios_return *)obj->buffer.pointer;
>>> +     ret = bios_return->return_code;
>>> +     bioscfg_drv.last_wmi_status = ret;
>>> +     if (ret) {
>>> +             if (ret != HPWMI_RET_UNKNOWN_COMMAND &&
>>> +                 ret != HPWMI_RET_UNKNOWN_CMDTYPE)
>>> +                     pr_warn("query 0x%x returned error 0x%x\n", query, ret);
>>> +             goto out_free;
>>> +     }
>>> +
>>> +     /* Ignore output data of zero size */
>>> +     if (!outsize)
>>> +             goto out_free;
>>> +
>>> +     actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
>>> +     memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
>>> +     memset(buffer + actual_outsize, 0, outsize - actual_outsize);
>>> +
>>> +out_free:
>>> +     kfree(obj);
>>> +     kfree(args);
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * ascii_to_utf16_unicode -  Convert ascii string to UTF-16 unicode
>>> + *
>>> + * @p:   Unicode buffer address
>>> + * @str: string to convert to unicode
>>> + *
>>> + * Returns a void pointer to the buffer containing unicode string
>>> + */
>>> +void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
>>> +{
>>> +     int len = strlen(str);
>>> +     int ret;
>>> +
>>> +     /*
>>> +      * Add null character when reading an empty string
>>> +      */
>>> +     if (len == 0) {
>>> +             *p++ = 2;
>>> +             *p++ = (u8)0x00;
>>> +             return p;
>>> +     }
>>> +     *p++ = len * 2;
>>> +     ret = utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
>>> +
>>> +     if (ret < 0) {
>>> +             dev_err(bioscfg_drv.class_dev, "UTF16 conversion failed\n");
>>> +             goto ascii_to_utf16_unicode_out;
>>> +     }
>>> +
>>> +     if ((ret * sizeof(u16)) > U16_MAX) {
>>> +             dev_err(bioscfg_drv.class_dev, "Error string too long\n");
>>> +             goto ascii_to_utf16_unicode_out;
>>> +     }
>>> +
>>> +ascii_to_utf16_unicode_out:
>>> +     p += len;
>>> +     return p;
>>> +}
>>> +
>>> +/*
>>> + * hp_wmi_set_bios_setting - Set setting's value in BIOS
>>> + *
>>> + * @input_buffer: Input buffer address
>>> + * @input_size:   Input buffer size
>>> + *
>>> + * Returns: Count of unicode characters written to BIOS if successful, otherwise
>>> + *           -ENOMEM unable to allocate memory
>>> + *           -EINVAL buffer not allocated or too small
>>> + */
>>> +int hp_wmi_set_bios_setting(void *input_buffer, int input_size)
>>> +{
>>> +     union acpi_object *obj;
>>> +     struct acpi_buffer input = {input_size, input_buffer};
>>> +     struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
>>> +     int ret = 0;
>>> +
>>> +     ret = wmi_evaluate_method(HP_WMI_SET_BIOS_SETTING_GUID, 0, 1, &input, &output);
>>> +
>>> +     obj = output.pointer;
>>> +     if (!obj)
>>> +             return -EINVAL;
>>> +
>>> +     if (obj->type != ACPI_TYPE_INTEGER)
>>> +             ret = -EINVAL;
>>> +
>>> +     ret = obj->integer.value;
>>> +
>>> +     kfree(obj);
>>> +     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)
>>> +{
>>> +     return -EOPNOTSUPP;
>>> +}
>>> +
>>> +static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
>>> +{
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     bioscfg_drv.bios_attr_wdev = wdev;
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +     return 0;
>>> +}
>>> +
>>> +static void bios_attr_set_interface_remove(struct wmi_device *wdev)
>>> +{
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     bioscfg_drv.bios_attr_wdev = NULL;
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +}
>>> +
>>> +static const struct wmi_device_id bios_attr_set_interface_id_table[] = {
>>> +     { .guid_string = HP_WMI_BIOS_GUID},
>>> +     { },
>>> +};
>>> +static struct wmi_driver bios_attr_set_interface_driver = {
>>> +     .driver = {
>>> +             .name = DRIVER_NAME
>>> +     },
>>> +     .probe = bios_attr_set_interface_probe,
>>> +     .remove = bios_attr_set_interface_remove,
>>> +     .id_table = bios_attr_set_interface_id_table,
>>> +};
>>> +
>>> +int init_bios_attr_set_interface(void)
>>> +{
>>> +     return wmi_driver_register(&bios_attr_set_interface_driver);
>>> +}
>>> +
>>> +void exit_bios_attr_set_interface(void)
>>> +{
>>> +     wmi_driver_unregister(&bios_attr_set_interface_driver);
>>> +}
>>> +
>>> +MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
>>> diff --git a/drivers/platform/x86/hp/bioscfg.c b/drivers/platform/x86/hp/bioscfg.c
>>> new file mode 100644
>>> index 000000000000..f08bcae5752a
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/bioscfg.c
>>> @@ -0,0 +1,1029 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Common methods for use with hp-bioscfg driver
>>> + *
>>> + *  Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#include <asm-generic/errno-base.h>
>>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>> +
>>> +#include <linux/fs.h>
>>> +#include <linux/dmi.h>
>>> +#include <linux/module.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/wmi.h>
>>> +#include "bioscfg.h"
>>> +#include "../firmware_attributes_class.h"
>>> +#include <linux/nls.h>
>>> +
>>> +MODULE_AUTHOR("Jorge Lopez <jorge.lopez2@hp.com>");
>>> +MODULE_DESCRIPTION("HP BIOS Configuration Driver");
>>> +MODULE_LICENSE("GPL");
>>> +
>>> +
>>> +#define MAX_TYPES  4
>>> +
>>> +struct bioscfg_priv bioscfg_drv = {
>>> +     .mutex = __MUTEX_INITIALIZER(bioscfg_drv.mutex),
>>> +};
>>> +
>>> +/* reset bios to defaults */
>>> +static const char * const reset_types[] = {"builtinsafe", "lastknowngood", "factory", "custom"};
>>> +static struct class *fw_attr_class;
>>> +
>>> +int get_integer_from_buffer(int **buffer, int *integer)
>>> +{
>>> +     int *ptr = PTR_ALIGN(*buffer, 4);
>>> +     *integer = *(ptr++);
>>> +     *buffer = ptr;
>>> +     return 0;
>>> +}
>>> +
>>> +int get_string_from_buffer(u16 **buffer, char **str)
>>> +{
>>> +     u16 *ptr = *buffer;
>>> +     u16 ptrlen;
>>> +
>>> +     u16 size;
>>> +     int i;
>>> +     char *output = NULL;
>>> +     int escape = 0;
>>> +
>>> +     ptrlen = *(ptr++);
>>> +     size = ptrlen / 2;
>>> +
>>> +     for (i = 0; i < size; i++)
>>> +             if (ptr[i] == '\\' || ptr[i] == '\r' || ptr[i] == '\n' || ptr[i] == '\t')
>>> +                     escape++;
>>> +
>>> +     size += escape;
>>> +     *str = kcalloc(size + 1, sizeof(char), GFP_KERNEL);
>>> +     if (!*str)
>>> +             return -ENOMEM;
>>> +
>>> +     output = *str;
>>> +
>>> +     /*
>>> +      * convert from UTF-16 unicode to ASCII
>>> +      */
>>> +     utf16s_to_utf8s(ptr, ptrlen, UTF16_HOST_ENDIAN, output, size);
>>> +
>>> +     for (i = 0; i < size; i++) {
>>> +             if (*ptr == '\\' || *ptr == '\r' || *ptr == '\n' || *ptr == '\t')
>>> +                     output[i++] = '\\';
>>> +
>>> +             if (*ptr == '\r')
>>> +                     output[i] = 'r';
>>> +             else if (*ptr == '\n')
>>> +                     output[i] = 'n';
>>> +             else if (*ptr == '\t')
>>> +                     output[i] = 't';
>>> +             else if (*ptr == '"')
>>> +                     output[i] = '\'';
>>> +             else
>>> +                     output[i] = *ptr;
>>> +             ptr++;
>>> +     }
>>> +
>>> +     *buffer = ptr;
>>> +     return 0;
>>> +}
>>> +
>>> +int store_acpi_string_from_buffer(u16 **buffer, char *str_data, int str_data_len)
>>> +{
>>> +     int ret;
>>> +     char *str_read = NULL;
>>> +
>>> +     ret  = get_string_from_buffer(buffer, &str_read);
>>> +     if (ACPI_SUCCESS(ret))
>>> +             strscpy(str_data, str_read, str_data_len);
>>> +
>>> +     pr_warn("%s\n", str_data);
>>> +
>>> +     kfree(str_read);
>>> +     str_read = NULL;
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * populate_string_buffer() - populates a string buffer
>>> + * @buffer: the start of the destination buffer
>>> + * @buffer_len: length of the destination buffer
>>> + * @str: the string to insert into buffer
>>> + */
>>> +ssize_t populate_string_buffer(u16 *buffer, size_t buffer_len, const char *str)
>>> +{
>>> +     u16 *target = buffer;
>>> +     int ret;
>>> +
>>> +     ret = utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN,
>>> +                           target, buffer_len - sizeof(u16));
>>> +     if (ret < 0) {
>>> +             dev_err(bioscfg_drv.class_dev, "UTF16 conversion failed\n");
>>> +             return ret;
>>> +     }
>>> +     if ((ret * sizeof(u16)) > U16_MAX) {
>>> +             dev_err(bioscfg_drv.class_dev, "Error string too long\n");
>>> +             return -ERANGE;
>>> +     }
>>> +     return buffer_len;
>>> +}
>>> +
>>> +/*
>>> + * calculate_string_buffer() - determines size of string buffer for use with BIOS communication
>>> + * @str: the string to calculate based upon
>>> + */
>>> +size_t calculate_string_buffer(const char *str)
>>> +{
>>> +     /* u16 length field + one UTF16 char for each input char */
>>> +     int size =  sizeof(u16) + strlen(str) * sizeof(u16);
>>> +
>>> +     return size;
>>> +}
>>> +
>>> +int wmi_error_and_message(int error_code, char *msg)
>>> +{
>>> +     char *error_msg = NULL;
>>> +     int ret = -EIO;
>>> +
>>> +     switch (error_code) {
>>> +     case SUCCESS:
>>> +             error_msg = "Success";
>>> +             ret = 0;
>>> +             break;
>>> +     case CMD_FAILED:
>>> +             error_msg = "Command failed";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case INVALID_SIGN:
>>> +             error_msg = "Invalid signature";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case INVALID_CMD_VALUE:
>>> +             error_msg = "Invalid command value/Feature not supported";
>>> +             ret = -EOPNOTSUPP;
>>> +             break;
>>> +     case INVALID_CMD_TYPE:
>>> +             error_msg = "Invalid command type";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case INVALID_DATA_SIZE:
>>> +             error_msg = "Invalid data size";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case INVALID_CMD_PARAM:
>>> +             error_msg = "Invalid command parameter";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case ENCRYP_CMD_REQUIRED:
>>> +             error_msg = "Secure/encrypted command required";
>>> +             ret = -EACCES;
>>> +             break;
>>> +     case NO_SECURE_SESSION:
>>> +             error_msg = "No secure session established";
>>> +             ret = -EACCES;
>>> +             break;
>>> +     case SECURE_SESSION_FOUND:
>>> +             error_msg = "Secure session already established";
>>> +             ret = -EACCES;
>>> +             break;
>>> +     case SECURE_SESSION_FAILED:
>>> +             error_msg = "Secure session failed";
>>> +             ret = -EIO;
>>> +             break;
>>> +     case AUTH_FAILED:
>>> +             error_msg = "Other permission/Authentication failed";
>>> +             ret = -EACCES;
>>> +             break;
>>> +     case INVALID_BIOS_AUTH:
>>> +             error_msg = "Invalid BIOS administrator password";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case NONCE_DID_NOT_MATCH:
>>> +             error_msg = "Nonce did not match";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case GENERIC_ERROR:
>>> +             error_msg = "Generic/Other error";
>>> +             ret = -EIO;
>>> +             break;
>>> +     case BIOS_ADMIN_POLICY_NOT_MET:
>>> +             error_msg = "BIOS Admin password does not meet password policy requirements";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case BIOS_ADMIN_NOT_SET:
>>> +             error_msg = "BIOS Setup password is not set.";
>>> +             ret = -EPERM;
>>> +             break;
>>> +     case P21_NO_PROVISIONED:
>>> +             error_msg = "P21 is not provisioned";
>>> +             ret = -EPERM;
>>> +             break;
>>> +     case P21_PROVISION_IN_PROGRESS:
>>> +             error_msg = "P21 is already provisioned or provisioning is in progress and a signing key has already been sent.";
>>> +             ret = -EINPROGRESS;
>>> +             break;
>>> +     case P21_IN_USE:
>>> +             error_msg = "P21 in use (cannot deprovision)";
>>> +             ret = -EPERM;
>>> +             break;
>>
>> What exactly is P21?  Can this be a more friendly error?
>>
>>> +     case HEP_NOT_ACTIVE:
>>> +             error_msg = "HEP not activated";
>>> +             ret = -EPERM;
>>> +             break;
>>> +     case HEP_ALREADY_SET:
>>> +             error_msg = "HEP Transport already set";
>>> +             ret = -EINVAL;
>>> +             break;
>>> +     case HEP_CHECK_STATE:
>>> +             error_msg = "Check the current HEP state";
>>> +             ret = -EINVAL;
>>> +             break;
>>
>> What's HEP?  Can this be a more friendly error?
>>
>>> +     default:
>>> +             error_msg = "Generic/Other error";
>>> +             ret = -EIO;
>>> +             break;
>>> +     }
>>> +
>>> +     sprintf(msg, "%d,\"%s\"", error_code, error_msg);
>>> +     return error_code;
>>> +}
>>> +
>>> +/*
>>> + * 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)
>>> +{
>>> +     return -EOPNOTSUPP;
>>> +}
>>> +
>>> +/*
>>> + * 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)
>>> +{
>>> +     return -EOPNOTSUPP;
>>> +}
>>> +static struct kobj_attribute reset_bios = __ATTR_RW(reset_bios);
>>> +
>>> +/*
>>> + * 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", bioscfg_drv.pending_reboot);
>>> +}
>>> +static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
>>> +
>>> +/*
>>> + * last_error_show() - sysfs implementaton for reporting the WMI
>>> + * error/success value.
>>> + * @kobj: Kernel object for this attribute
>>> + * @attr: Kernel object attribute
>>> + * @buf: The buffer to display to userspace
>>> + */
>>> +static ssize_t last_error_show(struct kobject *kobj,
>>> +                            struct kobj_attribute *attr,
>>> +                                char *buf)
>>> +{
>>> +     wmi_error_and_message(bioscfg_drv.last_wmi_status, buf);
>>> +     return sprintf(buf, "%s\n", buf);
>>> +}
>>> +static struct kobj_attribute last_error = __ATTR_RO(last_error);
>>> +
>>> +/*
>>> + * create_attributes_level_sysfs_files() - Creates reset_bios,
>>> + * pending_reboot, and last_error attributes
>>> + */
>>> +static int create_attributes_level_sysfs_files(void)
>>> +{
>>> +     int ret;
>>> +
>>> +     ret = sysfs_create_file(&bioscfg_drv.main_dir_kset->kobj, &reset_bios.attr);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     ret = sysfs_create_file(&bioscfg_drv.main_dir_kset->kobj, &pending_reboot.attr);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     ret = sysfs_create_file(&bioscfg_drv.main_dir_kset->kobj, &last_error.attr);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     bioscfg_drv.last_wmi_status = 0;
>>> +     return 0;
>>> +}
>>> +
>>> +
>>> +static ssize_t bioscfg_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 bioscfg_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;
>>> +}
>>> +
>>> +static const struct sysfs_ops bioscfg_kobj_sysfs_ops = {
>>> +     .show   = bioscfg_attr_show,
>>> +     .store  = bioscfg_attr_store,
>>> +};
>>> +
>>> +static void attr_name_release(struct kobject *kobj)
>>> +{
>>> +     kfree(kobj);
>>> +}
>>> +
>>> +static struct kobj_type attr_name_ktype = {
>>> +     .release        = attr_name_release,
>>> +     .sysfs_ops      = &bioscfg_kobj_sysfs_ops,
>>> +};
>>> +
>>> +/*
>>> + * strlcpy_attr - Copy a length-limited, NULL-terminated string with bound checks
>>> + * @dest: Where to copy the string to
>>> + * @src: Where to copy the string from
>>> + */
>>> +void strlcpy_attr(char *dest, char *src)
>>> +{
>>> +     size_t len = strlen(src) + 1;
>>> +
>>> +     if (len > 1 && len <= MAX_BUFF)
>>> +             strscpy(dest, src, len);
>>> +
>>> +     /*
>>> +      * len can be zero because any property not-applicable to attribute can
>>> +      * be empty so check only for too long buffers and log error
>>> +      */
>>> +     if (len > MAX_BUFF)
>>> +             pr_err("Source string returned from BIOS is out of bound!\n");
>>> +}
>>> +
>>> +/*
>>> + * get_wmiobj_pointer() - Get Content of WMI block for particular instance
>>> + *
>>> + * @instance_id: WMI instance ID
>>> + * @guid_string: WMI GUID (in str form)
>>> + *
>>> + * Fetches the content for WMI block (instance_id) under GUID (guid_string)
>>> + * Caller must kfree the return
>>> + */
>>> +union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string)
>>> +{
>>> +     struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
>>> +     acpi_status status;
>>> +
>>> +     status = wmi_query_block(guid_string, instance_id, &out);
>>> +     return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
>>> +}
>>> +
>>> +/*
>>> + * get_instance_count() - Compute total number of instances under guid_string
>>> + *
>>> + * @guid_string: WMI GUID (in string form)
>>> + */
>>> +int get_instance_count(const char *guid_string)
>>> +{
>>> +     union acpi_object *wmi_obj = NULL;
>>> +     int i = 0;
>>> +
>>> +     do {
>>> +             kfree(wmi_obj);
>>> +             wmi_obj = get_wmiobj_pointer(i, guid_string);
>>> +             i++;
>>> +     } while (wmi_obj);
>>> +
>>> +     return (i-1);
>>> +}
>>> +
>>> +/*
>>> + * alloc_attributes_data() - Allocate attributes data for a particular type
>>> + *
>>> + * @attr_type: Attribute type to allocate
>>> + */
>>> +static int alloc_attributes_data(int attr_type)
>>> +{
>>> +     int retval = 0;
>>> +
>>> +     switch (attr_type) {
>>> +     case HPWMI_STRING_TYPE:
>>> +             retval = alloc_string_data();
>>> +             break;
>>> +     case HPWMI_INTEGER_TYPE:
>>> +             retval = alloc_integer_data();
>>> +             break;
>>> +     case HPWMI_ENUMERATION_TYPE:
>>> +             retval = alloc_enumeration_data();
>>> +             break;
>>> +     case HPWMI_ORDERED_LIST_TYPE:
>>> +             retval = alloc_ordered_list_data();
>>> +             break;
>>> +     case HPWMI_PASSWORD_TYPE:
>>> +             retval = alloc_password_data();
>>> +             break;
>>> +     default:
>>> +             break;
>>> +     }
>>> +
>>> +     return retval;
>>> +}
>>> +
>>> +int convert_hexstr_to_int(char *str, int *int_value)
>>> +{
>>> +     int ret;
>>> +
>>> +     ret = kstrtou32(str, 10, int_value);
>>> +     return ret;
>>> +}
>>> +
>>> +int convert_hexstr_to_str(char **hex, int input_len, char **str, int *len)
>>> +{
>>> +     int ret = 0;
>>> +     int new_len = 0;
>>> +     char tmp[] = "0x00";
>>> +     char *input = *hex;
>>> +     char *new_str = NULL;
>>> +     long  ch;
>>> +     int i;
>>> +
>>> +     if (input_len <= 0 || hex == NULL || str == NULL || len == NULL)
>>> +             return -EINVAL;
>>> +
>>> +     *len = 0;
>>> +     *str = NULL;
>>> +
>>> +     new_str = kmalloc(input_len, GFP_KERNEL);
>>> +     if (!new_str)
>>> +             return -ENOMEM;
>>> +
>>> +     for (i = 0; i < input_len; i += 5) {
>>> +             strncpy(tmp, input + i, strlen(tmp));
>>> +             if (kstrtol(tmp, 16, &ch) == 0) {
>>> +                     // escape char
>>> +                     if (ch == '\\' || ch == '\r' || ch == '\n' || ch == '\t') {
>>> +                             if (ch == '\r')
>>> +                                     ch = 'r';
>>> +                             else if (ch == '\n')
>>> +                                     ch = 'n';
>>> +                             else if (ch == '\t')
>>> +                                     ch = 't';
>>> +                             new_str[new_len++] = '\\';
>>> +                     }
>>> +                     new_str[new_len++] = ch;
>>> +                     if (ch == '\0')
>>> +                             break;
>>> +             }
>>> +     }
>>> +
>>> +     if (new_len) {
>>> +             new_str[new_len] = '\0';
>>> +             *str = krealloc(new_str, (new_len + 1) * sizeof(char), GFP_KERNEL);
>>> +             if (*str)
>>> +                     *len = new_len;
>>> +             else
>>> +                     ret = -ENOMEM;
>>> +     } else {
>>> +             ret = -EFAULT;
>>> +     }
>>> +
>>> +     if (ret)
>>> +             kfree(new_str);
>>> +     return ret;
>>> +}
>>> +
>>> +/* map output size to the corresponding WMI method id */
>>> +inline int encode_outsize_for_pvsz(int outsize)
>>> +{
>>> +     if (outsize > 4096)
>>> +             return -EINVAL;
>>> +     if (outsize > 1024)
>>> +             return 5;
>>> +     if (outsize > 128)
>>> +             return 4;
>>> +     if (outsize > 4)
>>> +             return 3;
>>> +     if (outsize > 0)
>>> +             return 2;
>>> +     return 1;
>>> +}
>>> +
>>> +/**
>>> + * destroy_attribute_objs() - Free a kset of kobjects
>>> + * @kset: The kset to destroy
>>> + *
>>> + * Fress kobjects created for each attribute_name under attribute type kset
>>> + */
>>> +static void destroy_attribute_objs(struct kset *kset)
>>> +{
>>> +     struct kobject *pos, *next;
>>> +
>>> +     list_for_each_entry_safe(pos, next, &kset->list, entry)
>>> +             kobject_put(pos);
>>> +}
>>> +
>>> +/**
>>> + * release_attributes_data() - Clean-up all sysfs directories and files created
>>> + */
>>> +static void release_attributes_data(void)
>>> +{
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +
>>> +     exit_string_attributes();
>>> +     exit_integer_attributes();
>>> +     exit_enumeration_attributes();
>>> +     exit_ordered_list_attributes();
>>> +     exit_password_attributes();
>>> +     exit_sure_start_attributes();
>>> +     exit_sure_admin_attributes();
>>> +     exit_secure_platform_attributes();
>>> +
>>> +     if (bioscfg_drv.authentication_dir_kset) {
>>> +             destroy_attribute_objs(bioscfg_drv.authentication_dir_kset);
>>> +             kset_unregister(bioscfg_drv.authentication_dir_kset);
>>> +             bioscfg_drv.authentication_dir_kset = NULL;
>>> +     }
>>> +     if (bioscfg_drv.main_dir_kset) {
>>> +             sysfs_remove_file(&bioscfg_drv.main_dir_kset->kobj, &reset_bios.attr);
>>> +             sysfs_remove_file(&bioscfg_drv.main_dir_kset->kobj, &pending_reboot.attr);
>>> +             sysfs_remove_file(&bioscfg_drv.main_dir_kset->kobj, &last_error.attr);
>>> +             destroy_attribute_objs(bioscfg_drv.main_dir_kset);
>>> +             kset_unregister(bioscfg_drv.main_dir_kset);
>>> +             bioscfg_drv.main_dir_kset = NULL;
>>> +     }
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +}
>>> +
>>> +
>>> +/*
>>> + * hp_add_other_attributes - Initialize HP custom attributes not reported by
>>> + * BIOS and required to support Secure Platform, Sure Start, and Sure
>>> + * Admin.
>>> + * @attr_type: Custom HP attribute not reported by BIOS
>>> + *
>>> + * Initialiaze all 3 types of attributes: Platform, Sure Start, and Sure
>>> + * Admin object.  Populates each attrbute types respective properties
>>> + * under sysfs files.
>>> + *
>>> + * Returns zero(0) if successful.  Otherwise, a negative value.
>>> + */
>>> +static int hp_add_other_attributes(int attr_type)
>>> +{
>>> +     struct kobject *attr_name_kobj;
>>> +     union acpi_object *obj = NULL;
>>> +     int retval = 0;
>>> +     u8 *attr_name;
>>> +
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +
>>> +     attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
>>> +     if (!attr_name_kobj) {
>>> +             retval = -ENOMEM;
>>> +             goto err_other_attr_init;
>>> +     }
>>> +
>>> +     /* Check if attribute type is supported */
>>> +     switch (attr_type) {
>>> +     case HPWMI_SECURE_PLATFORM_TYPE:
>>> +             attr_name_kobj->kset = bioscfg_drv.authentication_dir_kset;
>>> +             attr_name = SPM_STR;
>>> +             break;
>>> +
>>> +     case HPWMI_SURE_START_TYPE:
>>> +             attr_name_kobj->kset = bioscfg_drv.main_dir_kset;
>>> +             attr_name = SURE_START_STR;
>>> +             break;
>>> +
>>> +     case HPWMI_SURE_ADMIN_TYPE:
>>> +             attr_name_kobj->kset = bioscfg_drv.main_dir_kset;
>>> +             attr_name = SURE_ADMIN_STR;
>>> +             break;
>>> +     default:
>>> +             pr_err("Error: Unknown attr_type: %d\n", attr_type);
>>> +             retval = -EINVAL;
>>> +             goto err_other_attr_init;
>>> +     }
>>> +
>>> +     retval = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,
>>> +                                   NULL, "%s", attr_name);
>>> +     if (retval) {
>>> +             pr_err("Error encountered [%d]\n", retval);
>>> +             kobject_put(attr_name_kobj);
>>> +             goto err_other_attr_init;
>>> +     }
>>> +
>>> +     /* Populate attribute data */
>>> +     switch (attr_type) {
>>> +     case HPWMI_SECURE_PLATFORM_TYPE:
>>> +             retval = populate_secure_platform_data(attr_name_kobj);
>>> +             break;
>>> +
>>> +     case HPWMI_SURE_START_TYPE:
>>> +             retval = populate_sure_start_data(attr_name_kobj);
>>> +             break;
>>> +
>>> +     case HPWMI_SURE_ADMIN_TYPE:
>>> +             retval = populate_sure_admin_data(attr_name_kobj);
>>> +             break;
>>> +
>>> +     default:
>>> +             goto err_other_attr_init;
>>> +     }
>>> +
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +     return 0;
>>> +
>>> +err_other_attr_init:
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +     kfree(obj);
>>> +     return retval;
>>> +}
>>> +
>>> +/*
>>> + * hp_init_bios_attributes - Initialize all attributes for a type
>>> + * @attr_type: The attribute type to initialize
>>> + * @guid: The WMI GUID associated with this type to initialize
>>> + *
>>> + * Initialiaze all 5 types of attributes: enumeration, integer,
>>> + * string, password, ordered list  object.  Populates each attrbute types
>>> + * respective properties under sysfs files
>>> + */
>>> +static int hp_init_bios_attributes(int attr_type, const char *guid)
>>> +{
>>> +     struct kobject *attr_name_kobj;
>>> +     union acpi_object *obj = NULL;
>>> +     union acpi_object *elements;
>>> +     struct kset *tmp_set;
>>> +     int min_elements;
>>> +     char *str = NULL;
>>> +     char *temp_str = NULL;
>>> +     char *str_value = NULL;
>>> +     int str_len;
>>> +     int ret = 0;
>>> +
>>> +     /* instance_id needs to be reset for each type GUID
>>> +      * also, instance IDs are unique within GUID but not across
>>> +      */
>>> +     int instance_id = 0;
>>> +     int retval = 0;
>>> +
>>> +     retval = alloc_attributes_data(attr_type);
>>> +     if (retval)
>>> +             return retval;
>>> +
>>> +     switch (attr_type) {
>>> +     case HPWMI_STRING_TYPE:
>>> +             min_elements = 12;
>>> +             break;
>>> +     case HPWMI_INTEGER_TYPE:
>>> +             min_elements = 13;
>>> +             break;
>>> +     case HPWMI_ENUMERATION_TYPE:
>>> +             min_elements = 13;
>>> +             break;
>>> +     case HPWMI_ORDERED_LIST_TYPE:
>>> +             min_elements = 12;
>>> +             break;
>>> +     case HPWMI_PASSWORD_TYPE:
>>> +             min_elements = 15;
>>> +             break;
>>> +     default:
>>> +             pr_err("Error: Unknown attr_type: %d\n", attr_type);
>>> +             return -EINVAL;
>>> +     }
>>> +
>>> +     /* need to use specific instance_id and guid combination to get right data */
>>> +     obj = get_wmiobj_pointer(instance_id, guid);
>>> +
>>> +     if (!obj)
>>> +             return -ENODEV;
>>> +
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     while (obj) {
>>> +             if (obj->type != ACPI_TYPE_PACKAGE && obj->type != ACPI_TYPE_BUFFER) {
>>> +                     pr_err("Error: Expected ACPI-package or buffer type, got: %d\n", obj->type);
>>> +                     retval = -EIO;
>>> +                     goto err_attr_init;
>>> +             }
>>> +
>>> +             /* Take action appropriate to each ACPI TYPE */
>>> +             if (obj->type == ACPI_TYPE_PACKAGE) {
>>> +                     if (obj->package.count < min_elements) {
>>> +                             pr_err("Error: ACPI-package does not have enough elements: %d < %d\n",
>>> +                                    obj->package.count, min_elements);
>>> +                             goto nextobj;
>>> +                     }
>>> +
>>> +                     elements = obj->package.elements;
>>> +                     /* sanity checking */
>>> +                     if (elements[NAME].type != ACPI_TYPE_STRING) {
>>> +                             pr_debug("incorrect element type\n");
>>> +                             goto nextobj;
>>> +                     }
>>> +                     if (strlen(elements[NAME].string.pointer) == 0) {
>>> +                             pr_debug("empty attribute found\n");
>>> +                             goto nextobj;
>>> +                     }
>>> +                     if (attr_type == HPWMI_PASSWORD_TYPE)
>>> +                             tmp_set = bioscfg_drv.authentication_dir_kset;
>>> +                     else
>>> +                             tmp_set = bioscfg_drv.main_dir_kset;
>>> +
>>> +                     /* convert attribute name to string */
>>> +                     retval = convert_hexstr_to_str(&(elements[NAME].string.pointer),
>>> +                                                    elements[NAME].string.length,
>>> +                                                    &str_value, &str_len);
>>> +
>>> +                     if (ACPI_FAILURE(retval)) {
>>> +                             pr_warn("Failed to populate integer package data. Error [0%0x]\n", ret);
>>> +                             kfree(str_value);
>>> +                             return ret;
>>> +                     }
>>> +
>>> +                     if (kset_find_obj(tmp_set, str_value)) {
>>> +                             pr_debug("Duplicate attribute name found - %s\n",
>>> +                                      str_value);
>>> +                             goto nextobj;
>>> +                     }
>>> +
>>> +                     /* build attribute */
>>> +                     attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
>>> +                     if (!attr_name_kobj) {
>>> +                             retval = -ENOMEM;
>>> +                             goto err_attr_init;
>>> +                     }
>>> +
>>> +                     attr_name_kobj->kset = tmp_set;
>>> +
>>> +                     retval = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,
>>> +                                                   NULL, "%s", str_value);
>>> +                     if (retval) {
>>> +                             kobject_put(attr_name_kobj);
>>> +                             goto err_attr_init;
>>> +                     }
>>> +
>>> +                     /* enumerate all of these attributes */
>>> +                     switch (attr_type) {
>>> +                     case HPWMI_STRING_TYPE:
>>> +                             retval = populate_string_package_data(elements,
>>> +                                                                   instance_id,
>>> +                                                                   attr_name_kobj);
>>> +                             break;
>>> +                     case HPWMI_INTEGER_TYPE:
>>> +                             retval = populate_integer_package_data(elements,
>>> +                                                                    instance_id,
>>> +                                                                    attr_name_kobj);
>>> +                             break;
>>> +                     case HPWMI_ENUMERATION_TYPE:
>>> +                             retval = populate_enumeration_package_data(elements,
>>> +                                                                        instance_id,
>>> +                                                                        attr_name_kobj);
>>> +                             break;
>>> +                     case HPWMI_ORDERED_LIST_TYPE:
>>> +                             retval = populate_ordered_list_package_data(elements,
>>> +                                                                         instance_id,
>>> +                                                                         attr_name_kobj);
>>> +                             break;
>>> +                     case HPWMI_PASSWORD_TYPE:
>>> +                             retval = populate_password_package_data(elements,
>>> +                                                                     instance_id,
>>> +                                                                     attr_name_kobj);
>>> +                             break;
>>> +                     default:
>>> +                             break;
>>> +                     }
>>> +
>>> +                     kfree(str_value);
>>> +                     str_value = NULL;
>>> +             }
>>> +
>>> +             if (obj->type == ACPI_TYPE_BUFFER) {
>>> +                     retval = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str);
>>> +
>>> +                     if (attr_type == HPWMI_PASSWORD_TYPE || attr_type == HPWMI_SECURE_PLATFORM_TYPE)
>>> +                             tmp_set = bioscfg_drv.authentication_dir_kset;
>>> +                     else
>>> +                             tmp_set = bioscfg_drv.main_dir_kset;
>>> +
>>> +                     if (kset_find_obj(tmp_set, str)) {
>>> +                             pr_warn("Duplicate attribute name found - %s\n",
>>> +                                      str);
>>> +                             goto nextobj;
>>> +                     }
>>> +
>>> +                     /* build attribute */
>>> +                     attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
>>> +                     if (!attr_name_kobj) {
>>> +                             retval = -ENOMEM;
>>> +                             goto err_attr_init;
>>> +                     }
>>> +
>>> +                     attr_name_kobj->kset = tmp_set;
>>> +
>>> +                     temp_str = str;
>>> +                     if (attr_type == HPWMI_SECURE_PLATFORM_TYPE)
>>> +                             temp_str = "SPM";
>>> +
>>> +                     retval = kobject_init_and_add(attr_name_kobj,
>>> +                                                   &attr_name_ktype, NULL, "%s",
>>> +                                                   temp_str);
>>> +                     if (retval) {
>>> +                             kobject_put(attr_name_kobj);
>>> +                             goto err_attr_init;
>>> +                     }
>>> +
>>> +                     /* enumerate all of these attributes */
>>> +                     switch (attr_type) {
>>> +                     case HPWMI_STRING_TYPE:
>>> +                             retval = populate_string_buffer_data(obj, instance_id, attr_name_kobj);
>>> +                             break;
>>> +                     case HPWMI_INTEGER_TYPE:
>>> +                             retval = populate_integer_buffer_data(obj, instance_id, attr_name_kobj);
>>> +                             break;
>>> +                     case HPWMI_ENUMERATION_TYPE:
>>> +                             retval = populate_enumeration_buffer_data(obj, instance_id, attr_name_kobj);
>>> +                             break;
>>> +                     case HPWMI_ORDERED_LIST_TYPE:
>>> +                             retval = populate_ordered_list_buffer_data(obj, instance_id, attr_name_kobj);
>>> +                             break;
>>> +                     case HPWMI_PASSWORD_TYPE:
>>> +                             retval = populate_password_buffer_data(obj, instance_id, attr_name_kobj);
>>> +                             break;
>>> +                     default:
>>> +                             break;
>>> +                     }
>>> +             }
>>> +
>>> +nextobj:
>>> +             kfree(obj);
>>> +             instance_id++;
>>> +             obj = get_wmiobj_pointer(instance_id, guid);
>>> +     }
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +     return 0;
>>> +
>>> +err_attr_init:
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +     kfree(obj);
>>> +     return retval;
>>> +}
>>> +
>>> +static int __init bioscfg_init(void)
>>> +{
>>> +     int ret = 0;
>>> +     int bios_capable = wmi_has_guid(HP_WMI_BIOS_GUID);
>>> +
>>> +     if (!bios_capable) {
>>> +             pr_err("Unable to run on non-HP system\n");
>>> +             return -ENODEV;
>>> +     }
>>> +
>>> +     ret = init_bios_attr_set_interface();
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     ret = init_bios_attr_pass_interface();
>>> +     if (ret)
>>> +             goto err_exit_bios_attr_set_interface;
>>> +
>>> +     if (!bioscfg_drv.bios_attr_wdev || !bioscfg_drv.password_attr_wdev) {
>>> +             pr_debug("Failed to find set or pass interface\n");
>>> +             ret = -ENODEV;
>>> +             goto err_exit_bios_attr_pass_interface;
>>> +     }
>>> +
>>> +     ret = fw_attributes_class_get(&fw_attr_class);
>>> +     if (ret)
>>> +             goto err_exit_bios_attr_pass_interface;
>>> +
>>> +     bioscfg_drv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0),
>>> +                                           NULL, "%s", DRIVER_NAME);
>>> +     if (IS_ERR(bioscfg_drv.class_dev)) {
>>> +             ret = PTR_ERR(bioscfg_drv.class_dev);
>>> +             goto err_unregister_class;
>>> +     }
>>> +
>>> +     bioscfg_drv.main_dir_kset = kset_create_and_add("attributes", NULL,
>>> +                                                  &bioscfg_drv.class_dev->kobj);
>>> +     if (!bioscfg_drv.main_dir_kset) {
>>> +             ret = -ENOMEM;
>>> +             pr_debug("Failed to create and add attributes\n");
>>> +             goto err_destroy_classdev;
>>> +     }
>>> +
>>> +     bioscfg_drv.authentication_dir_kset = kset_create_and_add("authentication", NULL,
>>> +                                                             &bioscfg_drv.class_dev->kobj);
>>> +     if (!bioscfg_drv.authentication_dir_kset) {
>>> +             ret = -ENOMEM;
>>> +             pr_debug("Failed to create and add authentication\n");
>>> +             goto err_release_attributes_data;
>>> +     }
>>> +
>>> +     /*
>>> +      * sysfs level attributes.
>>> +      * - reset_bios
>>> +      * - pending_reboot
>>> +      * - last_error (WMI error)
>>> +      */
>>> +     ret = create_attributes_level_sysfs_files();
>>> +     if (ret)
>>> +             pr_debug("Failed to create sysfs level attributes\n");
>>> +
>>> +     ret = hp_init_bios_attributes(HPWMI_STRING_TYPE, HP_WMI_BIOS_STRING_GUID);
>>> +     if (ret)
>>> +             pr_debug("Failed to populate string type attributes\n");
>>> +
>>> +     ret = hp_init_bios_attributes(HPWMI_INTEGER_TYPE, HP_WMI_BIOS_INTEGER_GUID);
>>> +     if (ret)
>>> +             pr_debug("Failed to populate integer type attributes\n");
>>> +
>>> +     ret = hp_init_bios_attributes(HPWMI_ENUMERATION_TYPE, HP_WMI_BIOS_ENUMERATION_GUID);
>>> +     if (ret)
>>> +             pr_debug("Failed to populate enumeration type attributes\n");
>>> +
>>> +     ret = hp_init_bios_attributes(HPWMI_ORDERED_LIST_TYPE, HP_WMI_BIOS_ORDERED_LIST_GUID);
>>> +     if (ret)
>>> +             pr_debug("Failed to populate ordered list object type attributes\n");
>>> +
>>> +     ret = hp_init_bios_attributes(HPWMI_PASSWORD_TYPE, HP_WMI_BIOS_PASSWORD_GUID);
>>> +     if (ret)
>>> +             pr_debug("Failed to populate password object type attributes\n");
>>> +
>>> +     ret = hp_add_other_attributes(HPWMI_SECURE_PLATFORM_TYPE);
>>> +     if (ret)
>>> +             pr_debug("Failed to populate secure platform object type attribute\n");
>>> +
>>> +     ret = hp_add_other_attributes(HPWMI_SURE_START_TYPE);
>>> +     if (ret)
>>> +             pr_debug("Failed to populate sure start object type attribute\n");
>>> +
>>> +     ret = hp_add_other_attributes(HPWMI_SURE_ADMIN_TYPE);
>>> +     if (ret)
>>> +             pr_debug("Failed to populate sure admin object type attribute\n");
>>> +
>>> +     return 0;
>>> +
>>> +err_release_attributes_data:
>>> +     release_attributes_data();
>>> +
>>> +err_destroy_classdev:
>>> +     device_destroy(fw_attr_class, MKDEV(0, 0));
>>> +
>>> +err_unregister_class:
>>> +     fw_attributes_class_put();
>>> +
>>> +err_exit_bios_attr_pass_interface:
>>> +     exit_bios_attr_pass_interface();
>>> +
>>> +err_exit_bios_attr_set_interface:
>>> +     exit_bios_attr_set_interface();
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +static void __exit bioscfg_exit(void)
>>> +{
>>> +     release_attributes_data();
>>> +     device_destroy(fw_attr_class, MKDEV(0, 0));
>>> +
>>> +     fw_attributes_class_put();
>>> +     exit_bios_attr_set_interface();
>>> +     exit_bios_attr_pass_interface();
>>> +}
>>> +
>>> +module_init(bioscfg_init);
>>> +module_exit(bioscfg_exit);
>>> diff --git a/drivers/platform/x86/hp/bioscfg.h b/drivers/platform/x86/hp/bioscfg.h
>>> new file mode 100644
>>> index 000000000000..ac02c8c1e5f2
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/bioscfg.h
>>> @@ -0,0 +1,667 @@
>>> +/* SPDX-License-Identifier: GPL-2.0
>>> + *
>>> + * Definitions for kernel modules using hp_bioscfg driver
>>> + *
>>> + *  Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#ifndef _HP_BIOSCFG_H_
>>> +#define _HP_BIOSCFG_H_
>>> +
>>> +#include <linux/wmi.h>
>>> +#include <linux/types.h>
>>> +#include <linux/device.h>
>>> +#include <linux/module.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/capability.h>
>>> +#include <linux/nls.h>
>>> +
>>> +
>>> +#define DRIVER_NAME  "hp-bioscfg"
>>> +
>>> +#define MAX_BUFF             512
>>> +#define MAX_KEY_MOD          256
>>> +#define MAX_PASSWD_SIZE              64
>>> +#define MAX_MESSAGE_SIZE        256
>>> +
>>> +#define SPM_STR_DESC "Secure Platform Management"
>>> +#define SPM_STR              "SPM"
>>> +#define SURE_START_DESC "Sure Start"
>>> +#define SURE_START_STR  "Sure_Start"
>>> +#define SURE_ADMIN_DESC "Sure Admin"
>>> +#define SURE_ADMIN_STR  "Sure_Admin"
>>> +#define SETUP_PASSWD "Setup Password"
>>> +#define POWER_ON_PASSWD      "Power-On Password"
>>> +
>>> +#define LANG_CODE_STR        "en_US.UTF-8"
>>> +
>>> +/* Sure Admin Functions */
>>> +
>>> +#define UTF_PREFIX   ((unsigned char *)"<utf-16/>")
>>> +#define BEAM_PREFIX  ((unsigned char *)"<BEAM/>")
>>> +
>>> +/* mechanism - Authentication attribute */
>>> +
>>> +#define MAX_MECHANISM_TYPES 3
>>> +
>>> +enum mechanism_values {
>>> +     PASSWORD        = 0x00,
>>> +     NOT_PROVISION   = 0x00,
>>> +     SIGNING_KEY     = 0x01,
>>> +     ENDORSEMENT_KEY = 0x02
>>> +};
>>> +
>>> +static const char * const spm_mechanism_types[] = {
>>> +     "not provision",
>>> +     "signing-key",
>>> +     "endorsement-key"
>>> +};
>>> +
>>> +static const char * const passwd_mechanism_types[] = {
>>> +     "password",
>>> +};
>>> +
>>> +/* roles - Authentication attribute */
>>> +enum role_values {
>>> +     BIOS_ADMIN      = 0x00,
>>> +     POWER_ON        = 0x01,
>>> +     BIOS_SPM        = 0x02
>>> +};
>>> +
>>> +static const char * const role_type[] = {
>>> +     "bios-admin",
>>> +     "power-on",
>>> +     "enhanced-bios-auth"
>>> +};
>>> +
>>> +
>>> +#define HP_WMI_BIOS_GUID             "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
>>> +
>>> +#define HP_WMI_BIOS_STRING_GUID              "988D08E3-68F4-4c35-AF3E-6A1B8106F83C"
>>> +#define HP_WMI_BIOS_INTEGER_GUID     "8232DE3D-663D-4327-A8F4-E293ADB9BF05"
>>> +#define HP_WMI_BIOS_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-4A3C09E75133"
>>> +#define HP_WMI_BIOS_ORDERED_LIST_GUID        "14EA9746-CE1F-4098-A0E0-7045CB4DA745"
>>> +#define HP_WMI_BIOS_PASSWORD_GUID    "322F2028-0F84-4901-988E-015176049E2D"
>>> +#define HP_WMI_SET_BIOS_SETTING_GUID "1F4C91EB-DC5C-460b-951D-C7CB9B4B8D5E"
>>> +
>>> +enum hp_wmi_spm_commandtype {
>>> +     HPWMI_SECUREPLATFORM_GET_STATE  = 0x10,
>>> +     HPWMI_SECUREPLATFORM_SET_KEK    = 0x11,
>>> +     HPWMI_SECUREPLATFORM_SET_SK     = 0x12,
>>> +};
>>> +
>>> +enum hp_wmi_surestart_commandtype {
>>> +     HPWMI_SURESTART_GET_LOG_COUNT   = 0x01,
>>> +     HPWMI_SURESTART_GET_LOG         = 0x02,
>>> +};
>>> +
>>> +enum hp_wmi_command {
>>> +     HPWMI_READ              = 0x01,
>>> +     HPWMI_WRITE             = 0x02,
>>> +     HPWMI_ODM               = 0x03,
>>> +     HPWMI_SURESTART         = 0x20006,
>>> +     HPWMI_GM                = 0x20008,
>>> +     HPWMI_SECUREPLATFORM    = 0x20010,
>>> +};
>>> +
>>> +struct bios_return {
>>> +     u32 sigpass;
>>> +     u32 return_code;
>>> +};
>>> +
>>> +enum hp_return_value {
>>> +     HPWMI_RET_WRONG_SIGNATURE       = 0x02,
>>> +     HPWMI_RET_UNKNOWN_COMMAND       = 0x03,
>>> +     HPWMI_RET_UNKNOWN_CMDTYPE       = 0x04,
>>> +     HPWMI_RET_INVALID_PARAMETERS    = 0x05,
>>> +};
>>> +
>>> +enum wmi_error_values {
>>> +     SUCCESS                 = 0x00,
>>> +     CMD_FAILED                      = 0x01,
>>> +     INVALID_SIGN                    = 0x02,
>>> +     INVALID_CMD_VALUE               = 0x03,
>>> +     INVALID_CMD_TYPE                = 0x04,
>>> +     INVALID_DATA_SIZE               = 0x05,
>>> +     INVALID_CMD_PARAM               = 0x06,
>>> +     ENCRYP_CMD_REQUIRED             = 0x07,
>>> +     NO_SECURE_SESSION               = 0x08,
>>> +     SECURE_SESSION_FOUND            = 0x09,
>>> +     SECURE_SESSION_FAILED           = 0x0A,
>>> +     AUTH_FAILED                     = 0x0B,
>>> +     INVALID_BIOS_AUTH               = 0x0E,
>>> +     NONCE_DID_NOT_MATCH             = 0x18,
>>> +     GENERIC_ERROR                   = 0x1C,
>>> +     BIOS_ADMIN_POLICY_NOT_MET       = 0x28,
>>> +     BIOS_ADMIN_NOT_SET              = 0x38,
>>> +     P21_NO_PROVISIONED              = 0x1000,
>>> +     P21_PROVISION_IN_PROGRESS       = 0x1001,
>>> +     P21_IN_USE                      = 0x1002,
>>> +     HEP_NOT_ACTIVE                  = 0x1004,
>>> +     HEP_ALREADY_SET         = 0x1006,
>>> +     HEP_CHECK_STATE         = 0x1007
>>> +};
>>> +
>>> +enum spm_features {
>>> +     HEP_ENABLED             = 0x01,
>>> +     PLATFORM_RECOVERY       = 0x02,
>>> +     ENHANCED_BIOS_AUTH_MODE = 0x04
>>> +};
>>> +
>>> +
>>> +/*
>>> + * struct bios_args buffer is dynamically allocated.  New WMI command types
>>> + * were introduced that exceeds 128-byte data size.  Changes to handle
>>> + * the data size allocation scheme were kept in hp_wmi_perform_qurey function.
>>> + */
>>> +struct bios_args {
>>> +     u32 signature;
>>> +     u32 command;
>>> +     u32 commandtype;
>>> +     u32 datasize;
>>> +     u8 data[];
>>> +};
>>> +
>>> +
>>> +#pragma pack(1)
>>> +struct secureplatform_provisioning_data {
>>> +     u8 state;
>>> +     u8 version[2];
>>> +     u8 reserved1;
>>> +     u32 features;
>>> +     u32 nonce;
>>> +     u8 reserved2[28];
>>> +     u8 sk_mod[MAX_KEY_MOD];
>>> +     u8 kek_mod[MAX_KEY_MOD];
>>> +};
>>> +
>>> +#pragma pack()
>>> +
>>> +
>>> +struct string_data {
>>> +     struct kobject *attr_name_kobj;
>>> +     u8 attribute_name[MAX_BUFF];
>>> +     u8 display_name[MAX_BUFF];
>>> +     u8 current_value[MAX_BUFF];
>>> +     u8 new_value[MAX_BUFF];
>>> +     u8 path[MAX_BUFF];
>>> +     u32 is_readonly;
>>> +     u32 display_in_ui;
>>> +     u32 requires_physical_presence;
>>> +     u32 sequence;
>>> +     u32 prerequisitesize;
>>> +     u8 prerequisites[MAX_BUFF];
>>> +     u32 security_level;
>>> +     u32 min_length;
>>> +     u32 max_length;
>>> +     u8 display_name_language_code[MAX_BUFF];
>>> +     u32 type;
>>> +};
>>> +
>>> +struct integer_data {
>>> +     struct kobject *attr_name_kobj;
>>> +     u8 attribute_name[MAX_BUFF];
>>> +     u8 display_name[MAX_BUFF];
>>> +     u32 current_value;
>>> +     u32 new_value;
>>> +     u8 path[MAX_BUFF];
>>> +     u32 is_readonly;
>>> +     u32 display_in_ui;
>>> +     u32 requires_physical_presence;
>>> +     u32 sequence;
>>> +     u32 prerequisitesize;
>>> +     u8 prerequisites[MAX_BUFF];
>>> +     u32 security_level;
>>> +     u32 lower_bound;
>>> +     u32 upper_bound;
>>> +     u32 scalar_increment;
>>> +     u8 display_name_language_code[MAX_BUFF];
>>> +     u32 type;
>>> +};
>>> +
>>> +struct enumeration_data {
>>> +     struct kobject *attr_name_kobj;
>>> +     u8 attribute_name[MAX_BUFF];
>>> +     u8 display_name[MAX_BUFF];
>>> +     u8 path[MAX_BUFF];
>>> +     u32 is_readonly;
>>> +     u32 display_in_ui;
>>> +     u32 requires_physical_presence;
>>> +     u32 sequence;
>>> +     u32 prerequisitesize;
>>> +     u8 prerequisites[MAX_BUFF];
>>> +     u32 security_level;
>>> +     u8 current_value[MAX_BUFF];
>>> +     u8 new_value[MAX_BUFF];
>>> +     u32 size;
>>> +     u8 possible_values[MAX_BUFF];
>>> +     u8 display_name_language_code[MAX_BUFF];
>>> +     u32 type;
>>> +};
>>> +
>>> +struct ordered_list_data {
>>> +     struct kobject *attr_name_kobj;
>>> +     u8 attribute_name[MAX_BUFF];
>>> +     u8 display_name[MAX_BUFF];
>>> +     u8 current_value[MAX_BUFF];
>>> +     u8 new_value[MAX_BUFF];
>>> +     u8 path[MAX_BUFF];
>>> +     u32 is_readonly;
>>> +     u32 display_in_ui;
>>> +     u32 requires_physical_presence;
>>> +     u32 sequence;
>>> +     u32 prerequisitesize;
>>> +     u8 prerequisites[MAX_BUFF];
>>> +     u32 security_level;
>>> +     u32 size;
>>> +     u8 elements[MAX_BUFF];
>>> +     u8 display_name_language_code[MAX_BUFF];
>>> +     u32 type;
>>> +};
>>> +
>>> +struct password_data {
>>> +     struct kobject *attr_name_kobj;
>>> +     u8 attribute_name[MAX_BUFF];
>>> +     u8 display_name[MAX_BUFF];
>>> +     u8 current_password[MAX_PASSWD_SIZE];
>>> +     u8 new_password[MAX_PASSWD_SIZE];
>>> +     u8 path[MAX_BUFF];
>>> +     u32 is_readonly;
>>> +     u32 display_in_ui;
>>> +     u32 requires_physical_presence;
>>> +     u32 sequence;
>>> +     u32 prerequisitesize;
>>> +     u8 prerequisites[MAX_BUFF];
>>> +     u32 security_level;
>>> +     u32 min_password_length;
>>> +     u32 max_password_length;
>>> +     u32 encoding_size;
>>> +     u8 supported_encoding[MAX_BUFF];
>>> +     u8 display_name_language_code[MAX_BUFF];
>>> +     u32 is_enabled;
>>> +
>>> +     // 'bios-admin' 'power-on'
>>> +     u32 role;
>>> +
>>> +     //'password'
>>> +     u32 mechanism;
>>> +     u32 type;
>>> +};
>>> +
>>> +struct secure_platform_data {
>>> +     struct kobject *attr_name_kobj;
>>> +     u8 attribute_name[MAX_BUFF];
>>> +     u8 display_name[MAX_BUFF];
>>> +
>>> +     u8 *endorsement_key;
>>> +     u8 *signing_key;
>>> +
>>> +     u32 is_enabled;
>>> +     u32 mechanism;
>>> +     u32 type;
>>> +};
>>> +
>>> +struct bioscfg_priv {
>>> +     struct wmi_device *password_attr_wdev;
>>> +     struct wmi_device *bios_attr_wdev;
>>> +     struct kset *authentication_dir_kset;
>>> +     struct kset *main_dir_kset;
>>> +     struct device *class_dev;
>>> +     struct string_data *string_data;
>>> +     u32 string_instances_count;
>>> +     struct integer_data *integer_data;
>>> +     u32 integer_instances_count;
>>> +     struct enumeration_data *enumeration_data;
>>> +     u32 enumeration_instances_count;
>>> +     struct ordered_list_data *ordered_list_data;
>>> +     u32 ordered_list_instances_count;
>>> +     struct password_data *password_data;
>>> +     u32 password_instances_count;
>>> +
>>> +     struct kobject *sure_start_attr_kobj;
>>> +     struct kobject *sure_admin_attr_kobj;
>>> +     struct secure_platform_data spm_data;
>>> +
>>> +     int  last_wmi_status;
>>> +     bool pending_reboot;
>>> +     struct mutex mutex;
>>> +};
>>> +
>>> +/* global structure used by multiple WMI interfaces */
>>> +extern struct bioscfg_priv bioscfg_drv;
>>> +
>>> +enum hp_wmi_data_type {
>>> +     HPWMI_STRING_TYPE               = 0x00,
>>> +     HPWMI_INTEGER_TYPE              = 0x01,
>>> +     HPWMI_ENUMERATION_TYPE          = 0x02,
>>> +     HPWMI_ORDERED_LIST_TYPE         = 0x03,
>>> +     HPWMI_PASSWORD_TYPE             = 0x04,
>>> +     HPWMI_SECURE_PLATFORM_TYPE      = 0x05,
>>> +     HPWMI_SURE_START_TYPE           = 0x06,
>>> +     HPWMI_SURE_ADMIN_TYPE           = 0x07,
>>> +};
>>> +
>>> +enum hp_wmi_data_elements {
>>> +
>>> +     /* Common elements */
>>> +     NAME = 0,
>>> +     VALUE = 1,
>>> +     PATH = 2,
>>> +     IS_READONLY = 3,
>>> +     DISPLAY_IN_UI = 4,
>>> +     REQUIRES_PHYSICAL_PRESENCE = 5,
>>> +     SEQUENCE = 6,
>>> +     PREREQUISITE_SIZE = 7,
>>> +     PREREQUISITES = 8,
>>> +     SECURITY_LEVEL = 9,
>>> +
>>> +     /* String elements */
>>> +     STR_MIN_LENGTH = 10,
>>> +     STR_MAX_LENGTH = 11,
>>> +
>>> +     /* Integer elements */
>>> +     INT_LOWER_BOUND = 10,
>>> +     INT_UPPER_BOUND = 11,
>>> +     INT_SCALAR_INCREMENT = 12,
>>> +
>>> +     /* Enumeration elements */
>>> +     ENUM_CURRENT_VALUE = 10,
>>> +     ENUM_SIZE = 11,
>>> +     ENUM_POSSIBLE_VALUES = 12,
>>> +
>>> +     /* Ordered list elements */
>>> +     ORD_LIST_SIZE = 10,
>>> +     ORD_LIST_ELEMENTS = 11,
>>> +
>>> +     /* Password elements */
>>> +     PSWD_MIN_LENGTH = 10,
>>> +     PSWD_MAX_LENGTH = 11,
>>> +     PSWD_SIZE = 12,
>>> +     PSWD_SUPPORTED_ENCODING = 13,
>>> +     PSWD_IS_SET = 14
>>> +};
>>> +
>>> +
>>> +static const int hp_wmi_elements_count[] = {
>>> +     12,   // string
>>> +     13,   // integer
>>> +     13,   // enumeration
>>> +     12,   // ordered list
>>> +     15    // password
>>> +};
>>> +
>>> +#define get_instance_id(type)                                                        \
>>> +static int get_##type##_instance_id(struct kobject *kobj)                    \
>>> +{                                                                            \
>>> +     int i; \
>>> +                                                             \
>>> +     for (i = 0; i <= bioscfg_drv.type##_instances_count; i++) { \
>>> +             if (!(strcmp(kobj->name, bioscfg_drv.type##_data[i].attribute_name))) \
>>> +                     return i;                                               \
>>> +     }                                                                       \
>>> +     return -EIO;                                                            \
>>> +}
>>> +
>>> +#define get_instance_id_for_attribute(type)                  \
>>> +static int get_instance_id_for_##type(char *attr_name)               \
>>> +{                                                                            \
>>> +     int i;                                                                  \
>>> +                                                                             \
>>> +     for (i = 0; i < bioscfg_drv.type##_instances_count; i++) {              \
>>> +             if (strcmp(bioscfg_drv.type##_data[i].attribute_name, attr_name) == 0)                                          \
>>> +                     return i;                                               \
>>> +     }                                                                       \
>>> +     return -EIO;                                                            \
>>> +}
>>> +
>>> +#define attribute_s_property_show(name, type)                                        \
>>> +static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,        \
>>> +                        char *buf)                                           \
>>> +{                                                                            \
>>> +     int i = get_##type##_instance_id(kobj);                                 \
>>> +     if (i >= 0)                                                             \
>>> +             return sprintf(buf, "%s\n", bioscfg_drv.type##_data[i].name);   \
>>> +     return 0;                                                               \
>>> +}
>>> +/* There is no need to keep track of default and current values
>>> + * separately
>>> + */
>>> +#define attribute_s_default_property_show(name, type, new_name)                      \
>>> +static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,        \
>>> +                        char *buf)                                           \
>>> +{                                                                            \
>>> +     int i = get_##type##_instance_id(kobj);                                 \
>>> +     if (i >= 0)                                                             \
>>> +             return sprintf(buf, "%s\n", bioscfg_drv.type##_data[i].new_name);       \
>>> +     return 0;                                                               \
>>> +}
>>> +
>>> +#define attribute_n_default_property_show(name, type, new_name)                      \
>>> +static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,        \
>>> +                        char *buf)                                           \
>>> +{                                                                            \
>>> +     int i = get_##type##_instance_id(kobj);                                 \
>>> +     if (i >= 0)                                                             \
>>> +             return sprintf(buf, "%d\n", bioscfg_drv.type##_data[i].new_name); \
>>> +     return 0;                                                               \
>>> +}
>>> +
>>> +#define attribute_n_property_show(name, type)                                        \
>>> +static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,        \
>>> +                        char *buf)                                           \
>>> +{                                                                            \
>>> +     int i = get_##type##_instance_id(kobj);                                 \
>>> +     if (i >= 0)                                                             \
>>> +             return sprintf(buf, "%d\n", bioscfg_drv.type##_data[i].name);   \
>>> +     return 0;                                                               \
>>> +}
>>> +
>>> +
>>> +#define attribute_property_store(curr_val, type)                             \
>>> +static ssize_t curr_val##_store(struct kobject *kobj,                                \
>>> +                             struct kobj_attribute *attr,                    \
>>> +                             const char *buf, size_t count)                  \
>>> +{                                                                            \
>>> +     char *p = NULL;                                                         \
>>> +     char *attr_value = NULL;                                                \
>>> +     char *attr_name = NULL;                                                 \
>>> +     int i;                                                                  \
>>> +     int ret = -EIO;                                                         \
>>> +                                                                             \
>>> +     attr_name = kstrdup(kobj->name, GFP_KERNEL);                            \
>>> +     if (!attr_name)                                                         \
>>> +             return -ENOMEM;                                                 \
>>> +                                                                             \
>>> +     attr_value = kstrdup(buf, GFP_KERNEL);                                  \
>>> +     if (!attr_value)                                                        \
>>> +             return -ENOMEM;                                                 \
>>> +                                                                             \
>>> +     p = memchr(attr_value, '\n', count);                                    \
>>> +     if (p != NULL)                                                          \
>>> +             *p = '\0';                                                      \
>>> +                                                                             \
>>> +     i = get_##type##_instance_id(kobj);                                     \
>>> +     if (i >= 0)                                                             \
>>> +             ret = validate_##type##_input(i, attr_value);                   \
>>> +     if (!ret)                                                               \
>>> +             ret = hp_set_attribute(attr_name, attr_value);                  \
>>> +     if (!ret)                                                               \
>>> +             update_##type##_value(i);                                       \
>>> +                                                                             \
>>> +     clear_all_passwords();                                                  \
>>> +     kfree(attr_name);                                                       \
>>> +     kfree(attr_value);                                                      \
>>> +                                                                             \
>>> +     return ret ? ret : count;                                               \
>>> +}
>>> +
>>> +#define attribute_spm_n_property_show(name, type)                            \
>>> +static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
>>> +{                                                                    \
>>> +     return sprintf(buf, "%d\n", bioscfg_drv.type##_data.name);\
>>> +}
>>> +
>>> +#define attribute_spm_s_property_show(name, type)                            \
>>> +static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
>>> +{                                                                    \
>>> +     return sprintf(buf, "%s\n", bioscfg_drv.type##_data.name);              \
>>> +}
>>> +
>>> +#define check_property_type(attr, prop, valuetype)\
>>> +     (attr##_obj[prop].type != valuetype)
>>> +
>>> +#define HPWMI_BINATTR_RW(_group, _name, _size)       \
>>> +static struct bin_attribute _group##_##_name =       \
>>> +__BIN_ATTR(_name, 0444 | 0200, _group##_##_name##_read, _group##_##_name##_write, _size)
>>> +
>>> +/*
>>> + * Prototypes
>>> + */
>>> +union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
>>> +int get_instance_count(const char *guid_string);
>>> +void strlcpy_attr(char *dest, char *src);
>>> +
>>> +/* String attributes */
>>> +int populate_string_buffer_data(union acpi_object *str_obj,
>>> +                      int instance_id,
>>> +                      struct kobject *attr_name_kobj);
>>> +int populate_string_elements_from_buffer(union acpi_object *string_obj,
>>> +                                      int instance_id,
>>> +                                      enum hp_wmi_data_type type);
>>> +int alloc_string_data(void);
>>> +void exit_string_attributes(void);
>>> +int populate_string_package_data(union acpi_object *str_obj,
>>> +                              int instance_id,
>>> +                              struct kobject *attr_name_kobj);
>>> +int populate_string_elements_from_package(union acpi_object *str_obj,
>>> +                                               int instance_id,
>>> +                                               enum hp_wmi_data_type type);
>>> +
>>> +/* Integer attributes */
>>> +int populate_integer_buffer_data(union acpi_object *integer_obj,
>>> +                       int instance_id,
>>> +                       struct kobject *attr_name_kobj);
>>> +int populate_integer_elements_from_buffer(union acpi_object *integer_obj,
>>> +                                       int instance_id,
>>> +                                       enum hp_wmi_data_type type);
>>> +int alloc_integer_data(void);
>>> +void exit_integer_attributes(void);
>>> +int populate_integer_package_data(union acpi_object *integer_obj,
>>> +                               int instance_id,
>>> +                               struct kobject *attr_name_kobj);
>>> +int populate_integer_elements_from_package(union acpi_object *integer_obj,
>>> +                                               int instance_id,
>>> +                                               enum hp_wmi_data_type type);
>>> +
>>> +/* Enumeration attributes */
>>> +int populate_enumeration_buffer_data(union acpi_object *enum_obj,
>>> +                           int instance_id,
>>> +                           struct kobject *attr_name_kobj);
>>> +int populate_enumeration_elements_from_buffer(union acpi_object *enum_obj,
>>> +                                           int instance_id,
>>> +                                           enum hp_wmi_data_type type);
>>> +int alloc_enumeration_data(void);
>>> +void exit_enumeration_attributes(void);
>>> +int populate_enumeration_package_data(union acpi_object *enum_obj,
>>> +                                   int instance_id,
>>> +                                   struct kobject *attr_name_kobj);
>>> +int populate_enumeration_elements_from_package(union acpi_object *enum_obj,
>>> +                                            int instance_id,
>>> +                                            enum hp_wmi_data_type type);
>>> +
>>> +/* Ordered list */
>>> +int populate_ordered_list_buffer_data(union acpi_object *order_obj, int instance_id,
>>> +                                   struct kobject *attr_name_kobj);
>>> +int populate_ordered_list_elements_from_buffer(union acpi_object *order_obj,
>>> +                                            int instance_id,
>>> +                                            enum hp_wmi_data_type
>>> +                                            type);
>>> +int alloc_ordered_list_data(void);
>>> +void exit_ordered_list_attributes(void);
>>> +int populate_ordered_list_package_data(union acpi_object *order_obj,
>>> +                                    int instance_id,
>>> +                                    struct kobject *attr_name_kobj);
>>> +int populate_ordered_list_elements_from_package(union acpi_object *order_obj,
>>> +                                             int instance_id,
>>> +                                             enum hp_wmi_data_type type);
>>> +
>>> +/* Password authentication attributes */
>>> +int populate_password_buffer_data(union acpi_object *password_obj,
>>> +                        int instance_id,
>>> +                        struct kobject *attr_name_kobj);
>>> +int populate_password_elements_from_buffer(union acpi_object *password_obj,
>>> +                                        int instance_id,
>>> +                                        enum hp_wmi_data_type type);
>>> +int populate_password_package_data(union acpi_object *password_obj, int instance_id,
>>> +                                struct kobject *attr_name_kobj);
>>> +int populate_password_elements_from_package(union acpi_object *password_obj,
>>> +                                        int instance_id,
>>> +                                         enum hp_wmi_data_type type);
>>> +int alloc_password_data(void);
>>> +int alloc_secure_platform_data(void);
>>> +void exit_password_attributes(void);
>>> +void exit_secure_platform_attributes(void);
>>> +int populate_secure_platform_data(struct kobject *attr_name_kobj);
>>> +int password_is_set(const char *auth);
>>> +int check_spm_is_enabled(void);
>>> +int wmi_error_and_message(int error_code, char *message);
>>> +int hp_wmi_set_bios_setting(void *input_buffer, int input_size);
>>> +int hp_wmi_perform_query(int query, enum hp_wmi_command command,
>>> +                             void *buffer, int insize, int outsize);
>>> +
>>> +/* Sure Start attributes */
>>> +void exit_sure_start_attributes(void);
>>> +int populate_sure_start_data(struct kobject *attr_name_kobj);
>>> +
>>> +/* Sure Admin Attributes */
>>> +void exit_sure_admin_attributes(void);
>>> +int populate_sure_admin_data(struct kobject *attr_name_kobj);
>>> +int hp_set_attribute(const char *a_name, const char *a_value);
>>> +int hp_set_attribute_with_payload(const char *a_name,
>>> +                               const char *a_value,
>>> +                               const char *auth_payload);
>>> +int update_attribute_value(char *attr_name, char *attr_value);
>>> +int hp_bios_settings_fill_buffer(void);
>>> +int hp_bios_settings_free_buffer(void);
>>> +int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
>>> +                                        int *alloc_size);
>>> +int append_read_string_attributes(char *buf, int alloc_size,
>>> +                                     int instance,
>>> +                                     enum hp_wmi_data_type type);
>>> +int append_read_integer_attributes(char *buf, int alloc_size,
>>> +                                      int instance,
>>> +                                      enum hp_wmi_data_type type);
>>> +int append_read_enumeration_attributes(char *buf, int alloc_size,
>>> +                                          int instance,
>>> +                                          enum hp_wmi_data_type type);
>>> +int append_read_ordered_list_attributes(char *buf, int alloc_size,
>>> +                                           int instance,
>>> +                                           enum hp_wmi_data_type type);
>>> +int append_read_password_attributes(char *buf, int alloc_size,
>>> +                                      int instance,
>>> +                                      enum hp_wmi_data_type type);
>>> +int append_read_settings(enum hp_wmi_data_type type, char **buf,
>>> +                           int *buf_size, int *alloc_size);
>>> +int append_read_attributes(char **buf, int alloc_size,
>>> +                              int instance, enum hp_wmi_data_type type);
>>> +int set_bios_defaults(u8 defType);
>>> +int get_password_instance_for_type(const char *name);
>>> +int clear_all_passwords(void);
>>> +int clear_passwords(const int instance);
>>> +void exit_bios_attr_set_interface(void);
>>> +int init_bios_attr_set_interface(void);
>>> +size_t calculate_string_buffer(const char *str);
>>> +size_t calculate_security_buffer(const char *authentication);
>>> +void populate_security_buffer(u16 *buffer, const char *authentication);
>>> +ssize_t populate_string_buffer(u16 *buffer, size_t buffer_len, const char *str);
>>> +int set_new_password(const char *password_type, const char *new_password);
>>> +int init_bios_attr_pass_interface(void);
>>> +void exit_bios_attr_pass_interface(void);
>>> +void *ascii_to_utf16_unicode(u16 *p, const u8 *str);
>>> +int get_integer_from_buffer(int **buffer, int *integer);
>>> +int get_string_from_buffer(u16 **buffer, char **str);
>>> +int convert_hexstr_to_str(char **hex, int input_len, char **str, int *len);
>>> +int convert_hexstr_to_int(char *str, int *int_value);
>>> +inline int encode_outsize_for_pvsz(int outsize);
>>> +
>>> +#endif
>>> diff --git a/drivers/platform/x86/hp/enum-attributes.c b/drivers/platform/x86/hp/enum-attributes.c
>>> new file mode 100644
>>> index 000000000000..6ec02b61857c
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/enum-attributes.c
>>> @@ -0,0 +1,504 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to enumeration type attributes under
>>> + * BIOS Enumeration GUID for use with hp-bioscfg driver.
>>> + *
>>> + *  Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#include "bioscfg.h"
>>> +
>>> +get_instance_id(enumeration);
>>> +
>>> +static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     int instance_id = get_enumeration_instance_id(kobj);
>>> +     union acpi_object *obj = NULL;
>>> +     ssize_t ret;
>>> +
>>> +     if (instance_id < 0)
>>> +             return -EIO;
>>> +
>>> +     /* need to use specific instance_id and guid combination to get right data */
>>> +     obj = get_wmiobj_pointer(instance_id, HP_WMI_BIOS_ENUMERATION_GUID);
>>> +     if (!obj)
>>> +             return -EIO;
>>> +
>>> +     ret = snprintf(buf, PAGE_SIZE, "%s\n",
>>> +                    bioscfg_drv.enumeration_data[instance_id].current_value);
>>> +
>>> +     kfree(obj);
>>> +     return ret;
>>> +}
>>> +
>>> +
>>> +/*
>>> + * validate_enumeration_input() -
>>> + * Validate input of current_value against possible values
>>> + *
>>> + * @instance_id: The instance on which input is validated
>>> + * @buf: Input value
>>> + */
>>> +static int validate_enumeration_input(int instance_id, const char *buf)
>>> +{
>>> +     char *options = NULL;
>>> +     char *p;
>>> +     int ret = 0;
>>> +     int found = 0;
>>> +
>>> +     options = kstrdup(bioscfg_drv.enumeration_data[instance_id].possible_values,
>>> +                       GFP_KERNEL);
>>> +
>>> +     if (!options) {
>>> +             ret = -ENOMEM;
>>> +             goto exit_validate_enum_input;
>>> +     }
>>> +
>>> +     /* Is it a read only attribute */
>>> +     if (bioscfg_drv.enumeration_data[instance_id].is_readonly) {
>>> +             ret = -EIO;
>>> +             goto exit_validate_enum_input;
>>> +     }
>>> +
>>> +     while ((p = strsep(&options, ";")) != NULL) {
>>> +             if (!*p)
>>> +                     continue;
>>> +
>>> +             if (!strcasecmp(p, buf)) {
>>> +                     found = 1;
>>> +                     break;
>>> +             }
>>> +     }
>>> +
>>> +     if (!found) {
>>> +             ret = -EINVAL;
>>> +             goto exit_validate_enum_input;
>>> +     }
>>> +
>>> +     strscpy(bioscfg_drv.enumeration_data[instance_id].new_value,
>>> +             buf,
>>> +             sizeof(bioscfg_drv.enumeration_data[instance_id].new_value));
>>> +
>>> +exit_validate_enum_input:
>>> +     kfree(options);
>>> +     return ret;
>>> +}
>>> +
>>> +static void update_enumeration_value(int instance_id)
>>> +{
>>> +     strscpy(bioscfg_drv.enumeration_data[instance_id].current_value,
>>> +             bioscfg_drv.enumeration_data[instance_id].new_value,
>>> +             sizeof(bioscfg_drv.enumeration_data[instance_id].current_value));
>>> +}
>>> +
>>> +
>>> +attribute_s_property_show(display_name_language_code, enumeration);
>>> +static struct kobj_attribute enumeration_display_langcode =
>>> +             __ATTR_RO(display_name_language_code);
>>> +
>>> +attribute_s_property_show(display_name, enumeration);
>>> +static struct kobj_attribute  enumeration_display_name =
>>> +             __ATTR_RO(display_name);
>>> +
>>> +attribute_property_store(current_value, enumeration);
>>> +static struct kobj_attribute enumeration_current_val =
>>> +     __ATTR_RW_MODE(current_value, 0600);
>>> +
>>> +attribute_s_property_show(possible_values, enumeration);
>>> +static struct kobj_attribute  enumeration_poss_val =
>>> +             __ATTR_RO(possible_values);
>>> +
>>> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "enumeration\n");
>>> +}
>>> +static struct kobj_attribute enumeration_type =
>>> +             __ATTR_RO(type);
>>> +
>>> +static struct attribute *enumeration_attrs[] = {
>>> +     &enumeration_display_langcode.attr,
>>> +     &enumeration_display_name.attr,
>>> +     &enumeration_current_val.attr,
>>> +     &enumeration_poss_val.attr,
>>> +     &enumeration_type.attr,
>>> +     NULL,
>>> +};
>>> +
>>> +static const struct attribute_group enumeration_attr_group = {
>>> +     .attrs = enumeration_attrs,
>>> +};
>>> +
>>> +int alloc_enumeration_data(void)
>>> +{
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.enumeration_instances_count =
>>> +             get_instance_count(HP_WMI_BIOS_ENUMERATION_GUID);
>>> +
>>> +     bioscfg_drv.enumeration_data = kcalloc(bioscfg_drv.enumeration_instances_count,
>>> +                                     sizeof(struct enumeration_data), GFP_KERNEL);
>>> +     if (!bioscfg_drv.enumeration_data) {
>>> +             bioscfg_drv.enumeration_instances_count = 0;
>>> +             ret = -ENOMEM;
>>> +     }
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * populate_enumeration_package_data() -
>>> + * Populate all properties of an instance under enumeration attribute
>>> + *
>>> + * @enum_obj: ACPI object with enumeration data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + */
>>> +int populate_enumeration_package_data(union acpi_object *enum_obj, int instance_id,
>>> +                     struct kobject *attr_name_kobj)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int str_len;
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.enumeration_data[instance_id].type = HPWMI_ENUMERATION_TYPE;
>>> +     bioscfg_drv.enumeration_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +
>>> +     ret = convert_hexstr_to_str(&(enum_obj[NAME].string.pointer),
>>> +                                 enum_obj[NAME].string.length,
>>> +                                 &str_value, &str_len);
>>> +     if (ACPI_FAILURE(ret)) {
>>> +             pr_warn("Failed to populate enumeration package data. Error [0%0x]\n", ret);
>>> +             kfree(str_value);
>>> +             return ret;
>>> +     }
>>> +
>>> +     strscpy(bioscfg_drv.enumeration_data[instance_id].attribute_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.enumeration_data[instance_id].attribute_name));
>>> +
>>> +     strscpy(bioscfg_drv.enumeration_data[instance_id].display_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.enumeration_data[instance_id].display_name));
>>> +
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +
>>> +     populate_enumeration_elements_from_package(enum_obj, instance_id, HPWMI_ENUMERATION_TYPE);
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
>>> +}
>>> +
>>> +int populate_enumeration_elements_from_package(union acpi_object *enum_obj,
>>> +                                        int instance_id,
>>> +                                        enum hp_wmi_data_type type)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int value_len;
>>> +     int status = 0;
>>> +     u32 size = 0;
>>> +     u32 int_value;
>>> +     int elem = 0;
>>> +     int reqs;
>>> +     int eloc;
>>> +     int pos_values;
>>> +
>>> +     strscpy(bioscfg_drv.enumeration_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.enumeration_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1, eloc = 1; elem < hp_wmi_elements_count[type]; elem++, eloc++) {
>>> +
>>> +             switch (enum_obj[elem].type) {
>>> +             case ACPI_TYPE_STRING:
>>> +
>>> +                     if (PREREQUISITES != elem && ENUM_POSSIBLE_VALUES != elem) {
>>> +                             status = convert_hexstr_to_str(&enum_obj[elem].string.pointer,
>>> +                                                            enum_obj[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                     }
>>> +                     break;
>>> +             case ACPI_TYPE_INTEGER:
>>> +                     int_value = (u32)enum_obj[elem].integer.value;
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Unsupported object type [%d]\n", enum_obj[elem].type);
>>> +                     continue;
>>> +             }
>>> +
>>> +             /* stop if extra counter is greater than total number
>>> +              * of elements for enumeration type
>>> +              */
>>> +             if (eloc == hp_wmi_elements_count[type])
>>> +                     goto exit_enumeration_package;
>>> +
>>> +             /* Assign appropriate element value to corresponding field*/
>>> +             switch (eloc) {
>>> +             case VALUE:
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.enumeration_data[instance_id].path, str_value,
>>> +                             sizeof(bioscfg_drv.enumeration_data[instance_id].path));
>>> +                     break;
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.enumeration_data[instance_id].is_readonly = int_value;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.enumeration_data[instance_id].display_in_ui = int_value;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.enumeration_data[instance_id].requires_physical_presence = int_value;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.enumeration_data[instance_id].sequence = int_value;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.enumeration_data[instance_id].prerequisitesize = int_value;
>>> +                     if (int_value > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +                     /*
>>> +                      * prerequisites element is omitted when
>>> +                      * prerequisitesSize value is zero.
>>> +                      */
>>> +                     if (int_value == 0)
>>> +                             eloc++;
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.enumeration_data[instance_id].prerequisitesize;
>>> +
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = convert_hexstr_to_str(&enum_obj[elem].string.pointer,
>>> +                                                            enum_obj[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     break;
>>> +
>>> +                             strlcat(bioscfg_drv.enumeration_data[instance_id].prerequisites,
>>> +                                     str_value,
>>> +                                     sizeof(bioscfg_drv.enumeration_data[instance_id].prerequisites));
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.enumeration_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.enumeration_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str_value);
>>> +                             str_value = NULL;
>>> +                     }
>>> +                     break;
>>> +
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.enumeration_data[instance_id].security_level = int_value;
>>> +                     break;
>>> +
>>> +             case ENUM_CURRENT_VALUE:
>>> +                     strscpy(bioscfg_drv.enumeration_data[instance_id].current_value,
>>> +                             str_value, sizeof(bioscfg_drv.enumeration_data[instance_id].current_value));
>>> +                     break;
>>> +             case ENUM_SIZE:
>>> +                     bioscfg_drv.enumeration_data[instance_id].size = int_value;
>>> +                     break;
>>> +             case ENUM_POSSIBLE_VALUES:
>>> +                     size = bioscfg_drv.enumeration_data[instance_id].size;
>>> +                     for (pos_values = 0; pos_values < size; pos_values++) {
>>> +                             status = convert_hexstr_to_str(&enum_obj[elem + pos_values].string.pointer,
>>> +                                                            enum_obj[elem  + pos_values].string.length,
>>> +                                                            &str_value, &value_len);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     break;
>>> +
>>> +                             strlcat(bioscfg_drv.enumeration_data[instance_id].possible_values,
>>> +                                     str_value,
>>> +                                     sizeof(bioscfg_drv.enumeration_data[instance_id].possible_values));
>>> +                             if (pos_values < (size - 1))
>>> +                                     strlcat(bioscfg_drv.enumeration_data[instance_id].possible_values, ";",
>>> +                                             sizeof(bioscfg_drv.enumeration_data[instance_id].possible_values));
>>> +                             kfree(str_value);
>>> +                             str_value = NULL;
>>> +                     }
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Enumeration attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +
>>> +             kfree(str_value);
>>> +             str_value = NULL;
>>> +     }
>>> +
>>> +exit_enumeration_package:
>>> +             kfree(str_value);
>>> +             str_value = NULL;
>>> +     return 0;
>>> +}
>>> +
>>> +/*
>>> + * populate_enumeration_buffer_data() -
>>> + * Populate all properties of an instance under enumeration attribute
>>> + *
>>> + * @enum_obj: ACPI object with enumeration data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + * @enumeration_property_count: Total properties count under enumeration type
>>> + */
>>> +int populate_enumeration_buffer_data(union acpi_object *enum_obj, int instance_id,
>>> +                           struct kobject *attr_name_kobj)
>>> +{
>>> +
>>> +     bioscfg_drv.enumeration_data[instance_id].type = HPWMI_ENUMERATION_TYPE;
>>> +     bioscfg_drv.enumeration_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +     strscpy(bioscfg_drv.enumeration_data[instance_id].attribute_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.enumeration_data[instance_id].attribute_name));
>>> +     strscpy(bioscfg_drv.enumeration_data[instance_id].display_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.enumeration_data[instance_id].display_name));
>>> +
>>> +     /* Populate enumeration elements */
>>> +     populate_enumeration_elements_from_buffer(enum_obj, instance_id, HPWMI_ENUMERATION_TYPE);
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
>>> +}
>>> +
>>> +int populate_enumeration_elements_from_buffer(union acpi_object *enum_obj,
>>> +                                           int instance_id,
>>> +                                           enum hp_wmi_data_type type)
>>> +{
>>> +     int status;
>>> +     char *str = NULL;
>>> +     int elem;
>>> +     int reqs;
>>> +     int integer;
>>> +     int size = 0;
>>> +     int values;
>>> +
>>> +     elem = 0;
>>> +
>>> +     strscpy(bioscfg_drv.enumeration_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.enumeration_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1; elem < 3; elem++) {
>>> +
>>> +             status = get_string_from_buffer((u16 **)&enum_obj->buffer.pointer, &str);
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +             case VALUE:
>>> +                     /* Skip 'Value' since 'CurrentValue' is reported. */
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.enumeration_data[instance_id].path,
>>> +                             str, sizeof(bioscfg_drv.enumeration_data[instance_id].path));
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Enumeration attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +
>>> +     for (elem = 3; elem < hp_wmi_elements_count[type]; elem++) {
>>> +             if (PREREQUISITES != elem && ENUM_CURRENT_VALUE != elem && ENUM_POSSIBLE_VALUES != elem)
>>> +                     status = get_integer_from_buffer((int **)&enum_obj->buffer.pointer, (int *)&integer);
>>> +
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +             switch (elem) {
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.enumeration_data[instance_id].is_readonly = integer;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.enumeration_data[instance_id].display_in_ui = integer;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.enumeration_data[instance_id].requires_physical_presence = integer;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.enumeration_data[instance_id].sequence = integer;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.enumeration_data[instance_id].prerequisitesize = integer;
>>> +                     if (integer > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.enumeration_data[instance_id].prerequisitesize;
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = get_string_from_buffer((u16 **)&enum_obj->buffer.pointer, &str);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.enumeration_data[instance_id].prerequisites,
>>> +                                     str,
>>> +                                     sizeof(bioscfg_drv.enumeration_data[instance_id].prerequisites));
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.enumeration_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.enumeration_data[instance_id].prerequisites));
>>> +                             kfree(str);
>>> +                             str = NULL;
>>> +                     }
>>> +                     break;
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.enumeration_data[instance_id].security_level = integer;
>>> +                     break;
>>> +             case ENUM_CURRENT_VALUE:
>>> +                     status = get_string_from_buffer((u16 **)&enum_obj->buffer.pointer, &str);
>>> +                     strscpy(bioscfg_drv.enumeration_data[instance_id].current_value,
>>> +                             str,
>>> +                             sizeof(bioscfg_drv.enumeration_data[instance_id].current_value));
>>> +                     break;
>>> +             case ENUM_SIZE:
>>> +                     bioscfg_drv.enumeration_data[instance_id].size = integer;
>>> +                     break;
>>> +             case ENUM_POSSIBLE_VALUES:
>>> +                     size = bioscfg_drv.enumeration_data[instance_id].size;
>>> +                     for (values = 0; values < size; values++) {
>>> +                             status = get_string_from_buffer((u16 **)&enum_obj->buffer.pointer, &str);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.enumeration_data[instance_id].possible_values,
>>> +                                     str,
>>> +                                     sizeof(bioscfg_drv.enumeration_data[instance_id].possible_values));
>>> +                             if (values != (size - 1))
>>> +                                     strlcat(bioscfg_drv.enumeration_data[instance_id].possible_values, ";",
>>> +                                             sizeof(bioscfg_drv.enumeration_data[instance_id].possible_values));
>>> +                             kfree(str);
>>> +                             str = NULL;
>>> +                     }
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Enumeration attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +     kfree(str);
>>> +     str = NULL;
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +/**
>>> + * exit_enumeration_attributes() - Clear all attribute data
>>> + *
>>> + * Clears all data allocated for this group of attributes
>>> + */
>>> +void exit_enumeration_attributes(void)
>>> +{
>>> +     int instance_id;
>>> +
>>> +     for (instance_id = 0; instance_id < bioscfg_drv.enumeration_instances_count; instance_id++) {
>>> +             if (bioscfg_drv.enumeration_data[instance_id].attr_name_kobj)
>>> +                     sysfs_remove_group(bioscfg_drv.enumeration_data[instance_id].attr_name_kobj,
>>> +                                                             &enumeration_attr_group);
>>> +     }
>>> +     bioscfg_drv.enumeration_instances_count = 0;
>>> +
>>> +     kfree(bioscfg_drv.enumeration_data);
>>> +     bioscfg_drv.enumeration_data = NULL;
>>> +}
>>> diff --git a/drivers/platform/x86/hp/int-attributes.c b/drivers/platform/x86/hp/int-attributes.c
>>> new file mode 100644
>>> index 000000000000..9a49a528fd9e
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/int-attributes.c
>>> @@ -0,0 +1,461 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to integer type attributes under
>>> + * BIOS Enumeration GUID for use with hp-bioscfg driver.
>>> + *
>>> + *  Copyright (c) 2022 Hewlett-Packard Inc.
>>> + */
>>> +
>>> +#include "bioscfg.h"
>>> +
>>> +get_instance_id(integer);
>>> +
>>> +static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     int instance_id = get_integer_instance_id(kobj);
>>> +     union acpi_object *obj = NULL;
>>> +     ssize_t ret;
>>> +
>>> +     if (instance_id < 0)
>>> +             return instance_id;
>>> +
>>> +     /* need to use specific instance_id and guid combination to get right data */
>>> +     obj = get_wmiobj_pointer(instance_id, HP_WMI_BIOS_INTEGER_GUID);
>>> +     if (!obj) {
>>> +             ret = -EIO;
>>> +             goto current_value_show_out;
>>> +     }
>>> +
>>> +     ret = snprintf(buf, PAGE_SIZE, "%d\n",  bioscfg_drv.integer_data[instance_id].current_value);
>>> +
>>> +current_value_show_out:
>>> +     kfree(obj);
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * 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
>>> + */
>>> +static int validate_integer_input(int instance_id, char *buf)
>>> +{
>>> +     int in_val;
>>> +     int ret;
>>> +
>>> +     ret = kstrtoint(buf, 10, &in_val);
>>> +
>>> +     /* BIOS treats it as a read only attribute */
>>> +     if (bioscfg_drv.integer_data[instance_id].is_readonly)
>>> +             return -EIO;
>>> +
>>> +     if (in_val < bioscfg_drv.integer_data[instance_id].lower_bound ||
>>> +                     in_val > bioscfg_drv.integer_data[instance_id].upper_bound)
>>> +             return -EINVAL;
>>> +
>>> +     bioscfg_drv.integer_data[instance_id].new_value = in_val;
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static void update_integer_value(int instance_id)
>>> +{
>>> +     bioscfg_drv.integer_data[instance_id].current_value =
>>> +             bioscfg_drv.integer_data[instance_id].new_value;
>>> +}
>>> +
>>> +attribute_s_property_show(display_name_language_code, integer);
>>> +static struct kobj_attribute integer_display_langcode =
>>> +     __ATTR_RO(display_name_language_code);
>>> +
>>> +attribute_s_property_show(display_name, integer);
>>> +static struct kobj_attribute integer_display_name =
>>> +     __ATTR_RO(display_name);
>>> +
>>> +attribute_property_store(current_value, integer);
>>> +static struct kobj_attribute integer_current_val =
>>> +     __ATTR_RW_MODE(current_value, 0600);
>>> +
>>> +attribute_n_property_show(lower_bound, integer);
>>> +static struct kobj_attribute integer_lower_bound =
>>> +     __ATTR_RO(lower_bound);
>>> +
>>> +attribute_n_property_show(upper_bound, integer);
>>> +static struct kobj_attribute integer_upper_bound =
>>> +     __ATTR_RO(upper_bound);
>>> +
>>> +attribute_n_property_show(scalar_increment, integer);
>>> +static struct kobj_attribute integer_scalar_increment =
>>> +     __ATTR_RO(scalar_increment);
>>> +
>>> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "integer\n");
>>> +}
>>> +static struct kobj_attribute integer_type =
>>> +     __ATTR_RO(type);
>>> +
>>> +static struct attribute *integer_attrs[] = {
>>> +     &integer_display_langcode.attr,
>>> +     &integer_display_name.attr,
>>> +     &integer_current_val.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_integer_data(void)
>>> +{
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.integer_instances_count = get_instance_count(HP_WMI_BIOS_INTEGER_GUID);
>>> +     bioscfg_drv.integer_data = kcalloc(bioscfg_drv.integer_instances_count,
>>> +                                     sizeof(struct integer_data), GFP_KERNEL);
>>> +     if (!bioscfg_drv.integer_data) {
>>> +             bioscfg_drv.integer_instances_count = 0;
>>> +             ret = -ENOMEM;
>>> +     }
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * populate_int_data() -
>>> + * Populate all properties of an instance under integer attribute
>>> + *
>>> + * @elements: ACPI object with integer data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + */
>>> +int populate_integer_package_data(union acpi_object *elements, int instance_id,
>>> +                     struct kobject *attr_name_kobj)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int str_len;
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.integer_data[instance_id].type = HPWMI_INTEGER_TYPE;
>>> +     bioscfg_drv.integer_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +
>>> +     ret = convert_hexstr_to_str(&(elements[NAME].string.pointer),
>>> +                                    elements[NAME].string.length,
>>> +                                    &str_value, &str_len);
>>> +     if (ACPI_FAILURE(ret)) {
>>> +             kfree(str_value);
>>> +             return ret;
>>> +     }
>>> +
>>> +     strscpy(bioscfg_drv.integer_data[instance_id].attribute_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.integer_data[instance_id].attribute_name));
>>> +     strscpy(bioscfg_drv.integer_data[instance_id].display_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.integer_data[instance_id].display_name));
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +
>>> +     populate_integer_elements_from_package(elements, instance_id, HPWMI_INTEGER_TYPE);
>>> +     return sysfs_create_group(attr_name_kobj, &integer_attr_group);
>>> +}
>>> +
>>> +int populate_integer_elements_from_package(union acpi_object *elements,
>>> +                                        int instance_id,
>>> +                                        enum hp_wmi_data_type type)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int value_len;
>>> +     int status = 0;
>>> +     u32 size = 0;
>>> +     u32 int_value;
>>> +     int elem = 0;
>>> +     int reqs;
>>> +     int eloc;
>>> +
>>> +     if (!elements)
>>> +             return -EINVAL;
>>> +
>>> +     strscpy(bioscfg_drv.integer_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.integer_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1, eloc = 1; elem < hp_wmi_elements_count[type]; elem++, eloc++) {
>>> +
>>> +             switch (elements[elem].type) {
>>> +             case ACPI_TYPE_STRING:
>>> +
>>> +                     if (elem != PREREQUISITES) {
>>> +                             status = convert_hexstr_to_str(&elements[elem].string.pointer,
>>> +                                                            elements[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +                     }
>>> +                     break;
>>> +             case ACPI_TYPE_INTEGER:
>>> +                     int_value = (u32)elements[elem].integer.value;
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Unsupported object type [%d]\n", elements[elem].type);
>>> +                     continue;
>>> +             }
>>> +             /*
>>> +              * Stop if extra counter is greater than total number
>>> +              * of elements for integer type.
>>> +              */
>>> +             if (eloc == hp_wmi_elements_count[type])
>>> +                     goto exit_integer_package;
>>> +
>>> +             /* Assign appropriate element value to corresponding field*/
>>> +             switch (eloc) {
>>> +             case VALUE:
>>> +                     status = kstrtoint(str_value, 10, &int_value);
>>> +                     if (status)
>>> +                             continue;
>>> +
>>> +                     bioscfg_drv.integer_data[instance_id].current_value = int_value;
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.integer_data[instance_id].path, str_value,
>>> +                             sizeof(bioscfg_drv.integer_data[instance_id].path));
>>> +                     break;
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.integer_data[instance_id].is_readonly = int_value;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.integer_data[instance_id].display_in_ui = int_value;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.integer_data[instance_id].requires_physical_presence = int_value;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.integer_data[instance_id].sequence = int_value;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.integer_data[instance_id].prerequisitesize = int_value;
>>> +
>>> +                     if (int_value > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +                     /*
>>> +                      * prerequisites element is omitted when
>>> +                      * prerequisitesSize value is zero.
>>> +                      */
>>> +                     if (int_value == 0)
>>> +                             eloc++;
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.integer_data[instance_id].prerequisitesize;
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = convert_hexstr_to_str(&elements[elem].string.pointer,
>>> +                                                            elements[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.integer_data[instance_id].prerequisites,
>>> +                                     str_value,
>>> +                                     sizeof(bioscfg_drv.integer_data[instance_id].prerequisites));
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.integer_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.integer_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str_value);
>>> +                             str_value = NULL;
>>> +                     }
>>> +                     break;
>>> +
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.integer_data[instance_id].security_level = int_value;
>>> +                     break;
>>> +             case INT_LOWER_BOUND:
>>> +                     bioscfg_drv.integer_data[instance_id].lower_bound = int_value;
>>> +                     break;
>>> +             case INT_UPPER_BOUND:
>>> +                     bioscfg_drv.integer_data[instance_id].upper_bound = int_value;
>>> +                     break;
>>> +             case INT_SCALAR_INCREMENT:
>>> +                     bioscfg_drv.integer_data[instance_id].scalar_increment = int_value;
>>> +                     break;
>>> +
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Integer attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str_value);
>>> +             str_value = NULL;
>>> +     }
>>> +exit_integer_package:
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +     return 0;
>>> +}
>>> +
>>> +
>>> +/*
>>> + * populate_integer_buffer_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_integer_buffer_data(union acpi_object *integer_obj, int instance_id,
>>> +                     struct kobject *attr_name_kobj)
>>> +{
>>> +     bioscfg_drv.integer_data[instance_id].type = HPWMI_INTEGER_TYPE;
>>> +     bioscfg_drv.integer_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +
>>> +     strscpy(bioscfg_drv.integer_data[instance_id].attribute_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.integer_data[instance_id].attribute_name));
>>> +
>>> +     strscpy(bioscfg_drv.integer_data[instance_id].display_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.integer_data[instance_id].display_name));
>>> +
>>> +     /* Populate integer elements */
>>> +     populate_integer_elements_from_buffer(integer_obj, instance_id, HPWMI_INTEGER_TYPE);
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &integer_attr_group);
>>> +}
>>> +
>>> +int populate_integer_elements_from_buffer(union acpi_object *integer_obj,
>>> +                                       int instance_id, enum hp_wmi_data_type type)
>>> +{
>>> +     int status;
>>> +     char *str = NULL;
>>> +     int elem;
>>> +     int reqs;
>>> +     int integer;
>>> +     int size = 0;
>>> +     int ret;
>>> +
>>> +     elem = 0;
>>> +     strscpy(bioscfg_drv.integer_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.integer_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1; elem < 3; elem++) {
>>> +
>>> +             status = get_string_from_buffer((u16 **)&integer_obj->buffer.pointer, &str);
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +             case VALUE:
>>> +                     ret = kstrtoint(str, 10, &integer);
>>> +                     if (ret)
>>> +                             continue;
>>> +
>>> +                     bioscfg_drv.integer_data[instance_id].current_value = integer;
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.integer_data[instance_id].path, str,
>>> +                             sizeof(bioscfg_drv.integer_data[instance_id].path));
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Integer attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +
>>> +     for (elem = 3; elem < hp_wmi_elements_count[type]; elem++) {
>>> +
>>> +             if (elem != PREREQUISITES)
>>> +                     status = get_integer_from_buffer((int **)&integer_obj->buffer.pointer, (int *)&integer);
>>> +
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.integer_data[instance_id].is_readonly = integer;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.integer_data[instance_id].display_in_ui = integer;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.integer_data[instance_id].requires_physical_presence = integer;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.integer_data[instance_id].sequence = integer;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.integer_data[instance_id].prerequisitesize = integer;
>>> +                     size = integer;
>>> +                     if (size > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = get_string_from_buffer((u16 **)&integer_obj->buffer.pointer, &str);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.integer_data[instance_id].prerequisites,
>>> +                                     str,
>>> +                                     sizeof(bioscfg_drv.integer_data[instance_id].prerequisites));
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.integer_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.integer_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str);
>>> +                             str = NULL;
>>> +                     }
>>> +                     break;
>>> +
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.integer_data[instance_id].security_level = integer;
>>> +                     break;
>>> +             case INT_LOWER_BOUND:
>>> +                     bioscfg_drv.integer_data[instance_id].lower_bound = integer;
>>> +                     break;
>>> +             case INT_UPPER_BOUND:
>>> +                     bioscfg_drv.integer_data[instance_id].upper_bound = integer;
>>> +                     break;
>>> +             case INT_SCALAR_INCREMENT:
>>> +                     bioscfg_drv.integer_data[instance_id].scalar_increment = integer;
>>> +                     break;
>>> +
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Integer attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +     return 0;
>>> +}
>>> +
>>> +/*
>>> + * exit_integer_attributes() - Clear all attribute data
>>> + *
>>> + * Clears all data allocated for this group of attributes
>>> + */
>>> +void exit_integer_attributes(void)
>>> +{
>>> +     int instance_id;
>>> +
>>> +     for (instance_id = 0; instance_id < bioscfg_drv.integer_instances_count; instance_id++) {
>>> +             if (bioscfg_drv.integer_data[instance_id].attr_name_kobj)
>>> +                     sysfs_remove_group(bioscfg_drv.integer_data[instance_id].attr_name_kobj,
>>> +                                                             &integer_attr_group);
>>> +     }
>>> +     bioscfg_drv.integer_instances_count = 0;
>>> +
>>> +     kfree(bioscfg_drv.integer_data);
>>> +     bioscfg_drv.integer_data = NULL;
>>> +}
>>> diff --git a/drivers/platform/x86/hp/ordered-attributes.c b/drivers/platform/x86/hp/ordered-attributes.c
>>> new file mode 100644
>>> index 000000000000..a66d7f0b34d2
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/ordered-attributes.c
>>> @@ -0,0 +1,568 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to ordered list type attributes under
>>> + * BIOS ORDERED LIST GUID for use with hp-bioscfg driver.
>>> + *
>>> + *  Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#include "bioscfg.h"
>>> +
>>> +get_instance_id(ordered_list);
>>> +
>>> +static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     int instance_id = get_ordered_list_instance_id(kobj);
>>> +     union acpi_object *obj = NULL;
>>> +     ssize_t ret;
>>> +
>>> +     if (instance_id < 0)
>>> +             return -EIO;
>>> +
>>> +     /* need to use specific instance_id and guid combination to get right data */
>>> +     obj = get_wmiobj_pointer(instance_id, HP_WMI_BIOS_ORDERED_LIST_GUID);
>>> +     if (!obj)
>>> +             return -EIO;
>>> +
>>> +     ret = snprintf(buf, PAGE_SIZE, "%s\n",
>>> +                    bioscfg_drv.ordered_list_data[instance_id].current_value);
>>> +
>>> +     kfree(obj);
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * validate_ordered_list_value -
>>> + * Validate input of current_value against possible values
>>> + *
>>> + * @instance_id: The instance on which input is validated
>>> + * @buf: Input value
>>> + */
>>> +static int validate_ordered_list_values(int instance_id, const char *buf)
>>> +{
>>> +     char *options = NULL;
>>> +     char *p;
>>> +     int ret = 0;
>>> +     int found = 0;
>>> +     char *new_values = NULL;
>>> +     char *value;
>>> +     int elem;
>>> +     int elem_found = 0;
>>> +
>>> +     options = kstrdup(bioscfg_drv.ordered_list_data[instance_id].elements,
>>> +                              GFP_KERNEL);
>>> +     new_values = kstrdup(buf, GFP_KERNEL);
>>> +
>>> +     if (!options || !new_values) {
>>> +             ret = -ENOMEM;
>>> +             goto validate_ordered_list_value_exit;
>>> +     }
>>> +
>>> +     /* Is it a read only attribute */
>>> +     if (bioscfg_drv.ordered_list_data[instance_id].is_readonly) {
>>> +             ret = -EIO;
>>> +             goto validate_ordered_list_value_exit;
>>> +     }
>>> +
>>> +     /*
>>> +      * Changes to ordered list values require checking that new
>>> +      * values are found in the list of elements.
>>> +      */
>>> +     for (elem = 0; elem < bioscfg_drv.ordered_list_data[instance_id].size; elem++) {
>>> +
>>> +             value = strsep(&new_values, ",");
>>> +             if (value != NULL) {
>>> +                     if (!*value)
>>> +                             continue;
>>> +                     elem_found++;
>>> +             }
>>> +
>>> +             while ((p = strsep(&options, ";")) != NULL) {
>>> +                     if (!*p)
>>> +                             continue;
>>> +
>>> +                     if (!strcasecmp(p, value)) {
>>> +                             found = 1;
>>> +                             break;
>>> +                     }
>>> +             }
>>> +
>>> +             if (!found) {
>>> +                     pr_warn("\"%s\" is not a valid ordered list element\n", value);
>>> +                     ret = -EINVAL;
>>> +                     goto validate_ordered_list_value_exit;
>>> +             }
>>> +     }
>>> +
>>> +     if (elem_found == bioscfg_drv.ordered_list_data[instance_id].size) {
>>> +             pr_warn("Number of new values is not equal to number of ordered list elements (%d)\n",
>>> +                     bioscfg_drv.ordered_list_data[instance_id].size);
>>> +             ret = -EINVAL;
>>> +             goto validate_ordered_list_value_exit;
>>> +     }
>>> +
>>> +validate_ordered_list_value_exit:
>>> +     kfree(options);
>>> +     kfree(new_values);
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * validate_ordered_input() -
>>> + * Validate input of current_value against possible values
>>> + *
>>> + * @instance_id: The instance on which input is validated
>>> + * @buf: Input value
>>> + */
>>> +static int validate_ordered_list_input(int instance_id, const char *buf)
>>> +{
>>> +     int ret = 0;
>>> +
>>> +     ret = validate_ordered_list_values(instance_id, buf);
>>> +     if (ret < 0) {
>>> +             ret = -EINVAL;
>>> +             goto validate_ordered_list_exit;
>>> +     }
>>> +
>>> +     strscpy(bioscfg_drv.ordered_list_data[instance_id].new_value,
>>> +             buf,
>>> +             sizeof(bioscfg_drv.ordered_list_data[instance_id].new_value));
>>> +
>>> +validate_ordered_list_exit:
>>> +     return ret;
>>> +}
>>> +
>>> +static void update_ordered_list_value(int instance_id)
>>> +{
>>> +     strscpy(bioscfg_drv.ordered_list_data[instance_id].current_value,
>>> +             bioscfg_drv.ordered_list_data[instance_id].new_value,
>>> +             sizeof(bioscfg_drv.ordered_list_data[instance_id].current_value));
>>> +}
>>> +
>>> +attribute_s_property_show(display_name_language_code, ordered_list);
>>> +static struct kobj_attribute ordered_list_display_langcode =
>>> +             __ATTR_RO(display_name_language_code);
>>> +
>>> +attribute_s_property_show(display_name, ordered_list);
>>> +static struct kobj_attribute ordered_list_display_name =
>>> +             __ATTR_RO(display_name);
>>> +
>>> +attribute_property_store(current_value, ordered_list);
>>> +static struct kobj_attribute ordered_list_current_val =
>>> +             __ATTR_RW_MODE(current_value, 0600);
>>> +
>>> +attribute_s_property_show(elements, ordered_list);
>>> +static struct kobj_attribute ordered_list_elements_val =
>>> +             __ATTR_RO(elements);
>>> +
>>> +attribute_n_property_show(size, ordered_list);
>>> +static struct kobj_attribute ordered_list_size_val =
>>> +             __ATTR_RO(size);
>>> +
>>> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "ordered-list\n");
>>> +}
>>> +static struct kobj_attribute ordered_list_type =
>>> +             __ATTR_RO(type);
>>> +
>>> +static struct attribute *ordered_list_attrs[] = {
>>> +     &ordered_list_display_langcode.attr,
>>> +     &ordered_list_display_name.attr,
>>> +     &ordered_list_current_val.attr,
>>> +     &ordered_list_elements_val.attr,
>>> +     &ordered_list_size_val.attr,
>>> +     &ordered_list_type.attr,
>>> +     NULL,
>>> +};
>>> +
>>> +static const struct attribute_group ordered_list_attr_group = {
>>> +     .attrs = ordered_list_attrs,
>>> +};
>>> +
>>> +int alloc_ordered_list_data(void)
>>> +{
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.ordered_list_instances_count =
>>> +             get_instance_count(HP_WMI_BIOS_ORDERED_LIST_GUID);
>>> +     bioscfg_drv.ordered_list_data = kcalloc(bioscfg_drv.ordered_list_instances_count,
>>> +                                     sizeof(struct ordered_list_data), GFP_KERNEL);
>>> +     if (!bioscfg_drv.ordered_list_data) {
>>> +             bioscfg_drv.ordered_list_instances_count = 0;
>>> +             ret = -ENOMEM;
>>> +     }
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * populate_ordered_list_package_data() -
>>> + * Populate all properties of an instance under ordered_list attribute
>>> + *
>>> + * @order_obj: ACPI object with ordered_list data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + */
>>> +int populate_ordered_list_package_data(union acpi_object *order_obj, int instance_id,
>>> +                     struct kobject *attr_name_kobj)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int str_len;
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.ordered_list_data[instance_id].type = HPWMI_ORDERED_LIST_TYPE;
>>> +     bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +     ret = convert_hexstr_to_str(&(order_obj[NAME].string.pointer),
>>> +                                    order_obj[NAME].string.length,
>>> +                                    &str_value, &str_len);
>>> +
>>> +     if (ACPI_FAILURE(ret)) {
>>> +             kfree(str_value);
>>> +             return ret;
>>> +     }
>>> +
>>> +     strscpy(bioscfg_drv.ordered_list_data[instance_id].attribute_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.ordered_list_data[instance_id].attribute_name));
>>> +     strscpy(bioscfg_drv.ordered_list_data[instance_id].display_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.ordered_list_data[instance_id].display_name));
>>> +
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +
>>> +     populate_ordered_list_elements_from_package(order_obj, instance_id, HPWMI_ORDERED_LIST_TYPE);
>>> +     return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group);
>>> +}
>>> +
>>> +int populate_ordered_list_elements_from_package(union acpi_object *order_obj,
>>> +                                        int instance_id,
>>> +                                        enum hp_wmi_data_type type)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int value_len;
>>> +     int status = 0;
>>> +     u32 size = 0;
>>> +     u32 int_value;
>>> +     int elem = 0;
>>> +     int reqs;
>>> +     int eloc;
>>> +     char *tmpstr = NULL;
>>> +     char *part_tmp = NULL;
>>> +     int tmp_len = 0;
>>> +     char *part = NULL;
>>> +
>>> +     strscpy(bioscfg_drv.ordered_list_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.ordered_list_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1, eloc = 1; elem < hp_wmi_elements_count[type]; elem++, eloc++) {
>>> +
>>> +             switch (order_obj[elem].type) {
>>> +             case ACPI_TYPE_STRING:
>>> +
>>> +                     if (elem != PREREQUISITES) {
>>> +                             status = convert_hexstr_to_str(&order_obj[elem].string.pointer,
>>> +                                                            order_obj[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                     }
>>> +                     break;
>>> +             case ACPI_TYPE_INTEGER:
>>> +                     int_value = (u32)order_obj[elem].integer.value;
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Unsupported object type [%d]\n", order_obj[elem].type);
>>> +                     continue;
>>> +             }
>>> +
>>> +             /*
>>> +              * Stop if extra counter is greater than total number
>>> +              * of elements for ordered list type
>>> +              */
>>> +             if (eloc == hp_wmi_elements_count[type])
>>> +                     goto exit_ordered_list_package;
>>> +
>>> +
>>> +             /* Assign appropriate element value to corresponding field*/
>>> +             switch (eloc) {
>>> +             case VALUE:
>>> +                     strscpy(bioscfg_drv.ordered_list_data[instance_id].current_value,
>>> +                             str_value, sizeof(bioscfg_drv.ordered_list_data[instance_id].current_value));
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.ordered_list_data[instance_id].path, str_value,
>>> +                             sizeof(bioscfg_drv.ordered_list_data[instance_id].path));
>>> +                     break;
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].is_readonly = int_value;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].display_in_ui = int_value;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].requires_physical_presence = int_value;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].sequence = int_value;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].prerequisitesize = int_value;
>>> +                     if (int_value > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +                     /*
>>> +                      * prerequisites element is omitted when
>>> +                      * prerequisitesSize value is zero.
>>> +                      */
>>> +                     if (int_value == 0)
>>> +                             eloc++;
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.ordered_list_data[instance_id].prerequisitesize;
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = convert_hexstr_to_str(&order_obj[elem].string.pointer,
>>> +                                                            order_obj[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.ordered_list_data[instance_id].prerequisites,
>>> +                                     str_value,
>>> +                                     sizeof(bioscfg_drv.ordered_list_data[instance_id].prerequisites));
>>> +
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.ordered_list_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.ordered_list_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str_value);
>>> +                             str_value = NULL;
>>> +                     }
>>> +                     break;
>>> +
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].security_level = int_value;
>>> +                     break;
>>> +
>>> +             case ORD_LIST_SIZE:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].size = int_value;
>>> +                     break;
>>> +             case ORD_LIST_ELEMENTS:
>>> +                     size = bioscfg_drv.ordered_list_data[instance_id].size;
>>> +
>>> +                     /*
>>> +                      * Ordered list data is stored in hex and comma separated format
>>> +                      * Convert the data and split it to show each element
>>> +                      */
>>> +                     status = convert_hexstr_to_str(&str_value, value_len, &tmpstr, &tmp_len);
>>> +                     if (ACPI_FAILURE(status))
>>> +                             goto exit_ordered_list_package;
>>> +
>>> +                     part_tmp = tmpstr;
>>> +                     part = strsep(&part_tmp, ",");
>>> +                     if (!part)
>>> +                             strscpy(bioscfg_drv.ordered_list_data[instance_id].elements,
>>> +                                     tmpstr, sizeof(bioscfg_drv.ordered_list_data[instance_id].elements));
>>> +
>>> +                     while (part) {
>>> +                             strlcat(bioscfg_drv.ordered_list_data[instance_id].elements,
>>> +                                     part, sizeof(bioscfg_drv.ordered_list_data[instance_id].elements));
>>> +
>>> +                             part = strsep(&part_tmp, ",");
>>> +                             if (part)
>>> +                                     strlcat(bioscfg_drv.ordered_list_data[instance_id].elements, ";",
>>> +                                             sizeof(bioscfg_drv.ordered_list_data[instance_id].elements));
>>> +                     }
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Ordered_List attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(tmpstr);
>>> +             tmpstr = NULL;
>>> +             kfree(str_value);
>>> +             str_value = NULL;
>>> +     }
>>> +
>>> +exit_ordered_list_package:
>>> +     kfree(tmpstr);
>>> +     tmpstr = NULL;
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +     return 0;
>>> +}
>>> +
>>> +/*
>>> + * populate_ordered_list_data() - Populate all properties of an
>>> + * instance under ordered list attribute
>>> + *
>>> + * @order_obj: ACPI object with enumeration data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + * @enum_property_count: Total properties count under ordered list type
>>> + */
>>> +int populate_ordered_list_buffer_data(union acpi_object *order_obj, int instance_id,
>>> +                     struct kobject *attr_name_kobj)
>>> +{
>>> +
>>> +     bioscfg_drv.ordered_list_data[instance_id].type = HPWMI_ORDERED_LIST_TYPE;
>>> +     bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +
>>> +     strscpy(bioscfg_drv.ordered_list_data[instance_id].attribute_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.ordered_list_data[instance_id].attribute_name));
>>> +     strscpy(bioscfg_drv.ordered_list_data[instance_id].display_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.ordered_list_data[instance_id].display_name));
>>> +
>>> +     /* Populate ordered list elements */
>>> +     populate_ordered_list_elements_from_buffer(order_obj, instance_id, HPWMI_ORDERED_LIST_TYPE);
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group);
>>> +}
>>> +
>>> +int populate_ordered_list_elements_from_buffer(union acpi_object *order_obj,
>>> +                                            int instance_id, enum hp_wmi_data_type type)
>>> +{
>>> +     int status;
>>> +     char *str = NULL;
>>> +     int elem;
>>> +     int reqs;
>>> +     int integer;
>>> +     int size = 0;
>>> +     int values;
>>> +
>>> +     elem = 0;
>>> +     strscpy(bioscfg_drv.ordered_list_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.ordered_list_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1; elem < 3; elem++) {
>>> +
>>> +             status = get_string_from_buffer((u16 **)&order_obj->buffer.pointer, &str);
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +             case VALUE:
>>> +                     strscpy(bioscfg_drv.ordered_list_data[instance_id].current_value,
>>> +                             str, sizeof(bioscfg_drv.ordered_list_data[instance_id].current_value));
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.ordered_list_data[instance_id].path, str,
>>> +                             sizeof(bioscfg_drv.ordered_list_data[instance_id].path));
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Ordered list attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +     for (elem = 3; elem < hp_wmi_elements_count[type]; elem++) {
>>> +
>>> +             if (elem != PREREQUISITES && elem != ORD_LIST_ELEMENTS)
>>> +                     status = get_integer_from_buffer((int **)&order_obj->buffer.pointer, (int *)&integer);
>>> +
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].is_readonly = integer;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].display_in_ui = integer;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].requires_physical_presence = integer;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].sequence = integer;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].prerequisitesize = integer;
>>> +                     if (integer > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.ordered_list_data[instance_id].prerequisitesize;
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = get_string_from_buffer((u16 **)&order_obj->buffer.pointer, &str);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.ordered_list_data[instance_id].prerequisites,
>>> +                                     str,
>>> +                                     sizeof(bioscfg_drv.ordered_list_data[instance_id].prerequisites));
>>> +
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.ordered_list_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.ordered_list_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str);
>>> +                             str = NULL;
>>> +                     }
>>> +                     break;
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].security_level = integer;
>>> +                     break;
>>> +             case ORD_LIST_SIZE:
>>> +                     bioscfg_drv.ordered_list_data[instance_id].size = integer;
>>> +                     break;
>>> +             case ORD_LIST_ELEMENTS:
>>> +                     size = bioscfg_drv.ordered_list_data[instance_id].size;
>>> +                     for (values = 0; values < size; values++) {
>>> +                             status = get_string_from_buffer((u16 **)&order_obj->buffer.pointer, &str);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.ordered_list_data[instance_id].elements,
>>> +                                     str,
>>> +                                     sizeof(bioscfg_drv.ordered_list_data[instance_id].elements));
>>> +
>>> +                             if (values != (size - 1))
>>> +                                     strlcat(bioscfg_drv.ordered_list_data[instance_id].elements, ";",
>>> +                                             sizeof(bioscfg_drv.ordered_list_data[instance_id].elements));
>>> +
>>> +                             kfree(str);
>>> +                             str = NULL;
>>> +                     }
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Ordered list attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +     kfree(str);
>>> +     str = NULL;
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +
>>> +/*
>>> + * exit_ordered_list_attributes() - Clear all attribute data
>>> + *
>>> + * Clears all data allocated for this group of attributes
>>> + */
>>> +void exit_ordered_list_attributes(void)
>>> +{
>>> +     int instance_id;
>>> +
>>> +     for (instance_id = 0; instance_id < bioscfg_drv.ordered_list_instances_count; instance_id++) {
>>> +             if (bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj)
>>> +                     sysfs_remove_group(bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj,
>>> +                                                             &ordered_list_attr_group);
>>> +     }
>>> +     bioscfg_drv.ordered_list_instances_count = 0;
>>> +
>>> +     kfree(bioscfg_drv.ordered_list_data);
>>> +     bioscfg_drv.ordered_list_data = NULL;
>>> +}
>>> diff --git a/drivers/platform/x86/hp/passwdattr-interface.c b/drivers/platform/x86/hp/passwdattr-interface.c
>>> new file mode 100644
>>> index 000000000000..ecba2994563c
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/passwdattr-interface.c
>>> @@ -0,0 +1,50 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to SET password methods under
>>> + * HP_WMI_SET_BIOS_SETTING_GUID for use with hp-bioscfg driver.
>>> + *
>>> + * Copyright (c) 2022 Hewlett-Packard Inc.
>>> + */
>>> +
>>> +#include <linux/wmi.h>
>>> +#include "bioscfg.h"
>>> +
>>> +static int bios_attr_pass_interface_probe(struct wmi_device *wdev, const void *context)
>>> +{
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     bioscfg_drv.password_attr_wdev = wdev;
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +     return 0;
>>> +}
>>> +
>>> +static void bios_attr_pass_interface_remove(struct wmi_device *wdev)
>>> +{
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     bioscfg_drv.password_attr_wdev = NULL;
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +}
>>> +
>>> +static const struct wmi_device_id bios_attr_pass_interface_id_table[] = {
>>> +     { .guid_string = HP_WMI_SET_BIOS_SETTING_GUID },
>>> +     { },
>>> +};
>>> +static struct wmi_driver bios_attr_pass_interface_driver = {
>>> +     .driver = {
>>> +             .name = DRIVER_NAME"-password"
>>> +     },
>>> +     .probe = bios_attr_pass_interface_probe,
>>> +     .remove = bios_attr_pass_interface_remove,
>>> +     .id_table = bios_attr_pass_interface_id_table,
>>> +};
>>> +
>>> +int init_bios_attr_pass_interface(void)
>>> +{
>>> +     return wmi_driver_register(&bios_attr_pass_interface_driver);
>>> +}
>>> +
>>> +void exit_bios_attr_pass_interface(void)
>>> +{
>>> +     wmi_driver_unregister(&bios_attr_pass_interface_driver);
>>> +}
>>> +
>>> +MODULE_DEVICE_TABLE(wmi, bios_attr_pass_interface_id_table);
>>> diff --git a/drivers/platform/x86/hp/passwdobj-attributes.c b/drivers/platform/x86/hp/passwdobj-attributes.c
>>> new file mode 100644
>>> index 000000000000..75d2f2c1e0e3
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/passwdobj-attributes.c
>>> @@ -0,0 +1,640 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to password object type attributes under
>>> + * BIOS PASSWORD for use with hp-bioscfg driver.
>>> + *
>>> + *  Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#include "bioscfg.h"
>>> +#include <asm-generic/posix_types.h>
>>> +
>>> +get_instance_id(password);
>>> +
>>> +int clear_passwords(const int instance)
>>> +{
>>> +     if (!bioscfg_drv.password_data[instance].is_enabled)
>>> +             return 0;
>>> +
>>> +     memset(bioscfg_drv.password_data[instance].current_password,
>>> +            0, sizeof(bioscfg_drv.password_data[instance].current_password));
>>> +     memset(bioscfg_drv.password_data[instance].new_password,
>>> +            0, sizeof(bioscfg_drv.password_data[instance].new_password));
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +int clear_all_passwords(void)
>>> +{
>>> +     int instance;
>>> +
>>> +     for (instance = 0; instance < bioscfg_drv.password_instances_count; instance++)
>>> +             clear_passwords(instance);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +int get_password_instance_for_type(const char *name)
>>> +{
>>> +     int count = bioscfg_drv.password_instances_count;
>>> +     int instance;
>>> +
>>> +     for (instance = 0; instance < count; instance++) {
>>> +             if (strcmp(bioscfg_drv.password_data[instance].display_name, name) == 0)
>>> +                     return instance;
>>> +     }
>>> +     return -EINVAL;
>>> +}
>>> +
>>> +int validate_password_input(int instance_id, const char *buf)
>>> +{
>>> +     int length;
>>> +
>>> +     length = strlen(buf);
>>> +     if (buf[length-1] == '\n')
>>> +             length--;
>>> +
>>> +     if (length > MAX_PASSWD_SIZE)
>>> +             return INVALID_BIOS_AUTH;
>>> +
>>> +     if (bioscfg_drv.password_data[instance_id].min_password_length > length ||
>>> +         bioscfg_drv.password_data[instance_id].max_password_length < length)
>>> +             return INVALID_BIOS_AUTH;
>>> +     return SUCCESS;
>>> +}
>>> +
>>> +int password_is_set(const char *name)
>>> +{
>>> +     int id;
>>> +
>>> +     id = get_password_instance_for_type(name);
>>> +     if (id < 0)
>>> +             return 0;
>>> +
>>> +     return bioscfg_drv.password_data[id].is_enabled;
>>> +}
>>> +
>>> +attribute_n_property_show(is_enabled, password);
>>> +static struct kobj_attribute password_is_password_set = __ATTR_RO(is_enabled);
>>> +
>>> +static ssize_t current_password_store(struct kobject *kobj,
>>> +                                   struct kobj_attribute *attr,
>>> +                                   const char *buf, size_t count)
>>> +{
>>> +     char *p, *buf_cp;
>>> +     int id, ret = 0;
>>> +
>>> +     buf_cp = kstrdup(buf, GFP_KERNEL);
>>> +     if (!buf_cp) {
>>> +             ret = -ENOMEM;
>>> +             goto exit_current_password;
>>> +     }
>>> +
>>> +     p = memchr(buf_cp, '\n', count);
>>> +
>>> +     if (p != NULL)
>>> +             *p = '\0';
>>> +
>>> +     id = get_password_instance_id(kobj);
>>> +
>>> +     if (id >= 0)
>>> +             ret = validate_password_input(id, buf_cp);
>>> +
>>> +     if (!ret)
>>> +             strscpy(bioscfg_drv.password_data[id].current_password,
>>> +                     buf_cp,
>>> +                     sizeof(bioscfg_drv.password_data[id].current_password));
>>> +
>>> +exit_current_password:
>>> +     kfree(buf_cp);
>>> +     return ret ? ret : count;
>>> +}
>>> +static struct kobj_attribute password_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, *buf_cp = NULL;
>>> +     int id, ret = -EIO;
>>> +
>>> +     buf_cp = kstrdup(buf, GFP_KERNEL);
>>> +     if (!buf_cp) {
>>> +             ret = -ENOMEM;
>>> +             goto exit_new_password;
>>> +     }
>>> +
>>> +     p = memchr(buf_cp, '\n', count);
>>> +
>>> +     if (p != NULL)
>>> +             *p = '\0';
>>> +
>>> +     id = get_password_instance_id(kobj);
>>> +
>>> +     if (id >= 0)
>>> +             ret = validate_password_input(id, buf_cp);
>>> +
>>> +     if (!ret)
>>> +             strscpy(bioscfg_drv.password_data[id].new_password,
>>> +                     buf_cp,
>>> +                     sizeof(bioscfg_drv.password_data[id].new_password));
>>> +
>>> +     if (!ret)
>>> +             ret = hp_set_attribute(kobj->name, buf_cp);
>>> +
>>> +exit_new_password:
>>> +     /*
>>> +      * Regardless of the results both new and current passwords
>>> +      * will be set to zero and avoid security issues
>>> +      */
>>> +     clear_passwords(id);
>>> +
>>> +     kfree(buf_cp);
>>> +     return ret ? ret : count;
>>> +}
>>> +
>>> +static struct kobj_attribute password_new_password = __ATTR_WO(new_password);
>>> +
>>> +
>>> +attribute_n_property_show(min_password_length, password);
>>> +static struct kobj_attribute password_min_password_length = __ATTR_RO(min_password_length);
>>> +
>>> +attribute_n_property_show(max_password_length, password);
>>> +static struct kobj_attribute password_max_password_length = __ATTR_RO(max_password_length);
>>> +
>>> +static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     if (strcmp(kobj->name, SETUP_PASSWD) == 0)
>>> +             return sprintf(buf, "%s\n", role_type[BIOS_ADMIN]);
>>> +
>>> +     if (strcmp(kobj->name, POWER_ON_PASSWD) == 0)
>>> +             return sprintf(buf,  "%s\n", role_type[POWER_ON]);
>>> +
>>> +     return -EIO;
>>> +}
>>> +static struct kobj_attribute password_role = __ATTR_RO(role);
>>> +
>>> +static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                        char *buf)
>>> +{
>>> +     int i = get_password_instance_id(kobj);
>>> +
>>> +     if (i < 0)
>>> +             return i;
>>> +
>>> +     if (bioscfg_drv.password_data[i].mechanism != PASSWORD)
>>> +             return -EINVAL;
>>> +
>>> +     return sprintf(buf, "%s\n",
>>> +                    passwd_mechanism_types[bioscfg_drv.password_data[i].mechanism]);
>>> +}
>>> +static struct kobj_attribute password_mechanism = __ATTR_RO(mechanism);
>>> +
>>> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "password\n");
>>> +}
>>> +static struct kobj_attribute password_type = __ATTR_RO(type);
>>> +
>>> +attribute_s_property_show(display_name, password);
>>> +static struct kobj_attribute password_display_name =
>>> +             __ATTR_RO(display_name);
>>> +
>>> +attribute_s_property_show(display_name_language_code, password);
>>> +static struct kobj_attribute password_display_langcode =
>>> +             __ATTR_RO(display_name_language_code);
>>> +
>>> +attribute_s_property_show(supported_encoding,  password);
>>> +static struct kobj_attribute password_encoding =
>>> +             __ATTR_RO(supported_encoding);
>>> +
>>> +attribute_n_property_show(encoding_size,  password);
>>> +static struct kobj_attribute password_encoding_size =
>>> +             __ATTR_RO(encoding_size);
>>> +
>>> +static struct attribute *password_attrs[] = {
>>> +     &password_is_password_set.attr,
>>> +     &password_min_password_length.attr,
>>> +     &password_max_password_length.attr,
>>> +     &password_current_password.attr,
>>> +     &password_new_password.attr,
>>> +     &password_role.attr,
>>> +     &password_mechanism.attr,
>>> +     &password_type.attr,
>>> +     &password_display_name.attr,
>>> +     &password_display_langcode.attr,
>>> +     &password_encoding.attr,
>>> +     &password_encoding_size.attr,
>>> +     NULL,
>>> +};
>>> +
>>> +static const struct attribute_group bios_password_attr_group = {
>>> +     .attrs = password_attrs,
>>> +};
>>> +
>>> +static const struct attribute_group system_password_attr_group = {
>>> +     .attrs = password_attrs,
>>> +};
>>> +
>>> +int alloc_password_data(void)
>>> +{
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.password_instances_count = get_instance_count(HP_WMI_BIOS_PASSWORD_GUID);
>>> +     bioscfg_drv.password_data = kcalloc(bioscfg_drv.password_instances_count,
>>> +                                         sizeof(struct password_data), GFP_KERNEL);
>>> +     if (!bioscfg_drv.password_data) {
>>> +             bioscfg_drv.password_instances_count = 0;
>>> +             ret = -ENOMEM;
>>> +     }
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * populate_password_package_data -
>>> + *   Populate all properties for an instance under password attribute
>>> + *
>>> + * @password_obj: ACPI object with password data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + */
>>> +int populate_password_package_data(union acpi_object *password_obj, int instance_id,
>>> +                                struct kobject *attr_name_kobj)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int str_len;
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.password_data[instance_id].type = HPWMI_PASSWORD_TYPE;
>>> +     bioscfg_drv.password_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +
>>> +     ret = convert_hexstr_to_str(&(password_obj[NAME].string.pointer),
>>> +                                 password_obj[NAME].string.length,
>>> +                                 &str_value, &str_len);
>>> +
>>> +     if (ACPI_FAILURE(ret)) {
>>> +             kfree(str_value);
>>> +             return ret;
>>> +     }
>>> +
>>> +     strscpy(bioscfg_drv.password_data[instance_id].attribute_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.password_data[instance_id].attribute_name));
>>> +     strscpy(bioscfg_drv.password_data[instance_id].display_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.password_data[instance_id].display_name));
>>> +
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +
>>> +     populate_password_elements_from_package(password_obj, instance_id, HPWMI_PASSWORD_TYPE);
>>> +
>>> +     if (strcmp(attr_name_kobj->name, "Setup Password") == 0) {
>>> +             /* Save  system authentication instance for easy access */
>>> +             return sysfs_create_group(attr_name_kobj, &bios_password_attr_group);
>>> +     }
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &system_password_attr_group);
>>> +}
>>> +
>>> +int populate_password_elements_from_package(union acpi_object *password_obj,
>>> +                                        int instance_id,
>>> +                                        enum hp_wmi_data_type type)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int value_len;
>>> +     int status = 0;
>>> +     u32 size = 0;
>>> +     u32 int_value;
>>> +     int elem = 0;
>>> +     int reqs;
>>> +     int eloc;
>>> +     int pos_values;
>>> +
>>> +     strscpy(bioscfg_drv.password_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.password_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1, eloc = 1; elem < hp_wmi_elements_count[type]; elem++, eloc++) {
>>> +
>>> +             switch (password_obj[elem].type) {
>>> +             case ACPI_TYPE_STRING:
>>> +
>>> +                     if (PREREQUISITES != elem && ENUM_POSSIBLE_VALUES != elem) {
>>> +                             status = convert_hexstr_to_str(&password_obj[elem].string.pointer,
>>> +                                                            password_obj[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                     }
>>> +                     break;
>>> +             case ACPI_TYPE_INTEGER:
>>> +                     int_value = (u32)password_obj[elem].integer.value;
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Unsupported object type [%d]\n", password_obj[elem].type);
>>> +                     continue;
>>> +             }
>>> +
>>> +             /* stop if extra counter is greater than total number
>>> +              * of elements for password type
>>> +              */
>>> +             if (eloc == hp_wmi_elements_count[type])
>>> +                     goto exit_password_package;
>>> +
>>> +             /* Assign appropriate element value to corresponding field*/
>>> +             switch (eloc) {
>>> +             case VALUE:
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.password_data[instance_id].path, str_value,
>>> +                             sizeof(bioscfg_drv.password_data[instance_id].path));
>>> +                     break;
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.password_data[instance_id].is_readonly = int_value;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.password_data[instance_id].display_in_ui = int_value;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.password_data[instance_id].requires_physical_presence = int_value;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.password_data[instance_id].sequence = int_value;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.password_data[instance_id].prerequisitesize = int_value;
>>> +                     if (int_value > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +                     /*
>>> +                      * prerequisites element is omitted when
>>> +                      * prerequisitesSize value is zero.
>>> +                      */
>>> +                     if (int_value == 0)
>>> +                             eloc++;
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.password_data[instance_id].prerequisitesize;
>>> +
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = convert_hexstr_to_str(&password_obj[elem].string.pointer,
>>> +                                                            password_obj[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     break;
>>> +
>>> +                             strlcat(bioscfg_drv.password_data[instance_id].prerequisites,
>>> +                                     str_value,
>>> +                                     sizeof(bioscfg_drv.password_data[instance_id].prerequisites));
>>> +
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.password_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.password_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str_value);
>>> +                             str_value = NULL;
>>> +                     }
>>> +                     break;
>>> +
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.password_data[instance_id].security_level = int_value;
>>> +                     break;
>>> +
>>> +             case PSWD_MIN_LENGTH:
>>> +                     bioscfg_drv.password_data[instance_id].min_password_length = int_value;
>>> +                     break;
>>> +             case PSWD_MAX_LENGTH:
>>> +                     bioscfg_drv.password_data[instance_id].max_password_length = int_value;
>>> +                     break;
>>> +             case PSWD_SIZE:
>>> +                     bioscfg_drv.password_data[instance_id].encoding_size = int_value;
>>> +                     break;
>>> +             case PSWD_SUPPORTED_ENCODING:
>>> +                     size = bioscfg_drv.password_data[instance_id].encoding_size;
>>> +                     for (pos_values = 0; pos_values < size; pos_values++) {
>>> +                             status = convert_hexstr_to_str(&password_obj[elem + pos_values].string.pointer,
>>> +                                                            password_obj[elem  + pos_values].string.length,
>>> +                                                            &str_value, &value_len);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     break;
>>> +
>>> +                             strlcat(bioscfg_drv.password_data[instance_id].supported_encoding,
>>> +                                     str_value,
>>> +                                     sizeof(bioscfg_drv.password_data[instance_id].supported_encoding));
>>> +
>>> +                             if (pos_values < (size - 1))
>>> +                                     strlcat(bioscfg_drv.password_data[instance_id].supported_encoding, ";",
>>> +                                             sizeof(bioscfg_drv.password_data[instance_id].supported_encoding));
>>> +                             kfree(str_value);
>>> +                             str_value = NULL;
>>> +                     }
>>> +                     break;
>>> +             case PSWD_IS_SET:
>>> +                     bioscfg_drv.password_data[instance_id].is_enabled = int_value;
>>> +                     break;
>>> +
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Password attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str_value);
>>> +             str_value = NULL;
>>> +     }
>>> +
>>> +exit_password_package:
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +     return 0;
>>> +}
>>> +
>>> +/*
>>> + * populate_password_buffer_data -
>>> + * Populate all properties for an instance under password object attribute
>>> + *
>>> + * @password_obj: ACPI object with password object data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + */
>>> +int populate_password_buffer_data(union acpi_object *password_obj, int instance_id,
>>> +                        struct kobject *attr_name_kobj)
>>> +{
>>> +     bioscfg_drv.password_data[instance_id].type = HPWMI_PASSWORD_TYPE;
>>> +     bioscfg_drv.password_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +
>>> +     strscpy(bioscfg_drv.password_data[instance_id].attribute_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.password_data[instance_id].attribute_name));
>>> +     strscpy(bioscfg_drv.password_data[instance_id].display_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.password_data[instance_id].display_name));
>>> +
>>> +     /* Populate Password attributes */
>>> +     populate_password_elements_from_buffer(password_obj, instance_id, HPWMI_PASSWORD_TYPE);
>>> +     if (strcmp(attr_name_kobj->name, "Setup Password") == 0)
>>> +             return sysfs_create_group(attr_name_kobj, &bios_password_attr_group);
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &system_password_attr_group);
>>> +}
>>> +
>>> +int populate_password_elements_from_buffer(union acpi_object *password_obj,
>>> +                                        int instance_id,
>>> +                                        enum hp_wmi_data_type type)
>>> +{
>>> +     int status;
>>> +     char *str = NULL;
>>> +     int elem;
>>> +     int reqs;
>>> +     int integer;
>>> +     int size = 0;
>>> +     int values;
>>> +
>>> +     elem = 0;
>>> +     strscpy(bioscfg_drv.password_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.password_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1; elem < 3; elem++) {
>>> +
>>> +             status = get_string_from_buffer((u16 **)&password_obj->buffer.pointer, &str);
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +             case VALUE:
>>> +                     strscpy(bioscfg_drv.password_data[instance_id].current_password,
>>> +                             str, sizeof(bioscfg_drv.password_data[instance_id].current_password));
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.password_data[instance_id].path, str,
>>> +                             sizeof(bioscfg_drv.password_data[instance_id].path));
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Password  attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +
>>> +     for (elem = 3; elem < hp_wmi_elements_count[type]; elem++) {
>>> +
>>> +             if (elem != PREREQUISITES  && elem != PSWD_SUPPORTED_ENCODING)
>>> +                     status = get_integer_from_buffer((int **)&password_obj->buffer.pointer, (int *)&integer);
>>> +
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.password_data[instance_id].is_readonly = integer;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.password_data[instance_id].display_in_ui = integer;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.password_data[instance_id].requires_physical_presence = integer;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.password_data[instance_id].sequence = integer;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.password_data[instance_id].prerequisitesize = integer;
>>> +                     if (integer > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.password_data[instance_id].prerequisitesize;
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = get_string_from_buffer((u16 **)&password_obj->buffer.pointer, &str);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.password_data[instance_id].prerequisites,
>>> +                                     str,
>>> +                                     sizeof(bioscfg_drv.password_data[instance_id].prerequisites));
>>> +
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.password_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.password_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str);
>>> +                             str = NULL;
>>> +                     }
>>> +                     break;
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.password_data[instance_id].security_level = integer;
>>> +                     break;
>>> +
>>> +             case PSWD_MIN_LENGTH:
>>> +                     bioscfg_drv.password_data[instance_id].min_password_length = integer;
>>> +                     break;
>>> +             case PSWD_MAX_LENGTH:
>>> +                     bioscfg_drv.password_data[instance_id].max_password_length = integer;
>>> +                     break;
>>> +             case PSWD_SIZE:
>>> +                     bioscfg_drv.password_data[instance_id].encoding_size = integer;
>>> +                     break;
>>> +             case PSWD_SUPPORTED_ENCODING:
>>> +                     size = bioscfg_drv.password_data[instance_id].encoding_size;
>>> +                     for (values = 0; values < size; values++) {
>>> +                             status = get_string_from_buffer((u16 **)&password_obj->buffer.pointer, &str);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.password_data[instance_id].supported_encoding,
>>> +                                     str,
>>> +                                     sizeof(bioscfg_drv.password_data[instance_id].supported_encoding));
>>> +
>>> +                             if (values != (size - 1))
>>> +                                     strlcat(bioscfg_drv.password_data[instance_id].supported_encoding, ";",
>>> +                                             sizeof(bioscfg_drv.password_data[instance_id].supported_encoding));
>>> +
>>> +                             kfree(str);
>>> +                             str = NULL;
>>> +                     }
>>> +                     break;
>>> +             case PSWD_IS_SET:
>>> +                     bioscfg_drv.password_data[instance_id].is_enabled = integer;
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in Password  attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +     kfree(str);
>>> +     str = NULL;
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +/*
>>> + * exit_password_attributes() - Clear all attribute data
>>> + *
>>> + * Clears all data allocated for this group of attributes
>>> + */
>>> +void exit_password_attributes(void)
>>> +{
>>> +     int instance_id;
>>> +
>>> +     for (instance_id = 0; instance_id < bioscfg_drv.password_instances_count; instance_id++) {
>>> +             if (bioscfg_drv.password_data[instance_id].attr_name_kobj) {
>>> +                     if (strcmp(bioscfg_drv.password_data[instance_id].attr_name_kobj->name, SETUP_PASSWD) == 0)
>>> +                             sysfs_remove_group(bioscfg_drv.password_data[instance_id].attr_name_kobj,
>>> +                                                             &bios_password_attr_group);
>>> +                     else
>>> +                             sysfs_remove_group(bioscfg_drv.password_data[instance_id].attr_name_kobj,
>>> +                                                             &system_password_attr_group);
>>> +             }
>>> +     }
>>> +     bioscfg_drv.password_instances_count = 0;
>>> +     kfree(bioscfg_drv.password_data);
>>> +     bioscfg_drv.password_data = NULL;
>>> +}
>>> diff --git a/drivers/platform/x86/hp/spmobj-attributes.c b/drivers/platform/x86/hp/spmobj-attributes.c
>>> new file mode 100644
>>> index 000000000000..631fdbd05be9
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/spmobj-attributes.c
>>> @@ -0,0 +1,408 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to secure platform management object type
>>> + * attributes under BIOS PASSWORD for use with hp-bioscfg driver
>>> + *
>>> + *  Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#include "bioscfg.h"
>>> +
>>> +#define MAX_KEK_BLOB_SIZE    4160
>>> +#define MAX_SK_BLOB_SIZE     516
>>> +
>>> +enum spm_states_values {
>>> +     NOT_PROVISIONED          = 0x00,
>>> +     PROVISIONED              = 0x01,
>>> +     PROVISIONING_IN_PROGRESS = 0x02
>>> +};
>>> +
>>> +static const char * const spm_state_types[] = {
>>> +     "not provisioned",
>>> +     "provisioned",
>>> +     "provisioning in progress"};
>>> +
>>> +
>>> +int check_spm_is_enabled(void)
>>> +{
>>> +     /* do we need to check the admin password is also configured */
>>> +     return bioscfg_drv.spm_data.is_enabled;
>>> +}
>>> +
>>> +/*
>>> + * calculate_security_buffer() - determines size of security buffer
>>> + * for authentication scheme
>>> + *
>>> + * @authentication: the authentication content
>>> + *
>>> + * Currently only supported type is Admin password
>>> + */
>>> +size_t calculate_security_buffer(const char *authentication)
>>> +{
>>> +     int size;
>>> +
>>> +     if (authentication != NULL && strlen(authentication) > 0) {
>>> +             size =  (sizeof(u16) + (strlen(authentication) * sizeof(u16)) +
>>> +                     + (strlen(UTF_PREFIX) * sizeof(u16)));
>>> +             return size;
>>> +     }
>>> +
>>> +     size  = sizeof(u16) * 2;
>>> +     return size;
>>> +}
>>> +
>>> +/*
>>> + * 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(u16 *buffer, const char *authentication)
>>> +{
>>> +     u16 *auth = buffer;
>>> +     char *strprefix = NULL;
>>> +
>>> +     if (strncmp(authentication, BEAM_PREFIX, strlen(BEAM_PREFIX)) == 0) {
>>> +             /*
>>> +              * BEAM_PREFIX is append to buffer when a signature
>>> +              * is provided and Sure Admin is enabled in BIOS
>>> +              */
>>> +             // BEAM_PREFIX found, convert part to unicode
>>> +             auth = ascii_to_utf16_unicode(auth, authentication);
>>> +     } else {
>>> +             /*
>>> +              * UTF-16 prefix is append to the * buffer when a BIOS
>>> +              * admin password is configured in BIOS
>>> +              */
>>> +
>>> +             // append UTF_PREFIX to part and then convert it to unicode
>>> +             strprefix = kasprintf(GFP_KERNEL, "%s%s", UTF_PREFIX, authentication);
>>> +             if (!strprefix)
>>> +                     goto out_populate_security_buffer;
>>> +
>>> +             auth = ascii_to_utf16_unicode(auth, strprefix);
>>> +     }
>>> +out_populate_security_buffer:
>>> +
>>> +     kfree(strprefix);
>>> +     strprefix = NULL;
>>> +}
>>> +
>>> +ssize_t update_spm_state(void)
>>> +{
>>> +     int ret;
>>> +     struct secureplatform_provisioning_data *data = NULL;
>>> +
>>> +     data = kmalloc(sizeof(struct secureplatform_provisioning_data), GFP_KERNEL);
>>> +     if (!data) {
>>> +             ret = -ENOMEM;
>>> +             goto spm_state_exit;
>>> +     }
>>> +
>>> +     ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_GET_STATE,
>>> +                                    HPWMI_SECUREPLATFORM, data, 0,
>>> +                                    sizeof(struct secureplatform_provisioning_data));
>>> +     if (ret < 0)
>>> +             goto spm_state_exit;
>>> +
>>> +     bioscfg_drv.spm_data.mechanism = data->state;
>>> +     if (bioscfg_drv.spm_data.mechanism)
>>> +             bioscfg_drv.spm_data.is_enabled = 1;
>>> +
>>> +spm_state_exit:
>>> +     kfree(data);
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * statusbin - Reports SPM status in binary format
>>> + *
>>> + * @kobj:  Pointer to a kernel object of things that show up as
>>> + *      directory in the sysfs filesystem.
>>> + * @attr:  Pointer to list of attributes for the operation
>>> + * @buf:   Pointer to buffer
>>> + *
>>> + * Returns number of bytes read on success.  Otherwise,
>>> + *         an HP WMI query specific error code (which is positive)
>>> + *         -ENODEV if the query was not successful at all
>>> + *
>>> + */
>>> +ssize_t statusbin(struct kobject *kobj,
>>> +                   struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_GET_STATE,
>>> +                                    HPWMI_SECUREPLATFORM, buf, 0,
>>> +                                    sizeof(struct secureplatform_provisioning_data));
>>> +
>>> +     return ret ? -ENODEV : sizeof(struct secureplatform_provisioning_data);
>>> +}
>>> +
>>> +ssize_t statusbin_show(struct kobject *kobj,
>>> +                        struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     int ret;
>>> +     struct secureplatform_provisioning_data *data = NULL;
>>> +
>>> +     data = kmalloc(sizeof(struct secureplatform_provisioning_data), GFP_KERNEL);
>>> +     if (!data) {
>>> +             ret = -ENOMEM;
>>> +             goto statusbin_show_exit;
>>> +     }
>>> +
>>> +     ret = statusbin(kobj, attr, (char *)data);
>>> +     if (ret < 0)
>>> +             goto statusbin_show_exit;
>>> +
>>> +     /* copy data to spm local structure */
>>> +     memcpy(buf, data, sizeof(struct secureplatform_provisioning_data));
>>> +
>>> +statusbin_show_exit:
>>> +     kfree(data);
>>> +
>>> +     return ret ? ret : strnlen(buf, PAGE_SIZE);
>>> +}
>>> +struct kobj_attribute password_spm_statusbin = __ATTR_RO(statusbin);
>>> +
>>> +/*
>>> + * status_show - Reads SPM status
>>> + *
>>> + * @kobj:  Pointer to a kernel object of things that show up as
>>> + *      directory in the sysfs filesystem.
>>> + * @attr:  Pointer to list of attributes for the operation
>>> + * @buf:   Pointer to buffer
>>> + *
>>> + * Returns number of bytes read on success.  Otherwise,
>>> + *         an HP WMI query specific error code (which is positive)
>>> + *         -ENODEV if the query was not successful at all
>>> + *         -ENOMEM if cannot allocate required memory size
>>> + *
>>> + */
>>> +ssize_t status_show(struct kobject *kobj, struct kobj_attribute
>>> +                     *attr, char *buf)
>>> +{
>>> +     int ret, i;
>>> +     struct secureplatform_provisioning_data *data = NULL;
>>> +
>>> +     data = kmalloc(sizeof(struct secureplatform_provisioning_data), GFP_KERNEL);
>>> +     if (!data) {
>>> +             ret = -ENOMEM;
>>> +             goto status_show_exit;
>>> +     }
>>> +
>>> +     ret = statusbin(kobj, attr, (char *)data);
>>> +     if (ret < 0)
>>> +             goto status_show_exit;
>>> +
>>> +     snprintf(buf, PAGE_SIZE, "%sState: %d\n", buf, data->state);
>>> +     snprintf(buf, PAGE_SIZE, "%sVersion: %d.%d\n", buf, data->version[0],
>>> +              data->version[1]);
>>> +
>>> +     /* state == 0 means secure platform management feature is not configured in BIOS. */
>>> +     if (data->state == 0)
>>> +             goto status_show_exit;
>>> +
>>> +     snprintf(buf, PAGE_SIZE, "%sNonce: %d\n", buf, data->nonce);
>>> +     snprintf(buf, PAGE_SIZE, "%sFeaturesInUse: %d\n", buf, data->features);
>>> +     snprintf(buf, PAGE_SIZE, "%sEndorsementKeyMod: {", buf);
>>> +
>>> +     for (i = 255; i >= 0; i--)
>>> +             snprintf(buf, PAGE_SIZE, "%s %u", buf, data->kek_mod[i]);
>>> +
>>> +     snprintf(buf, PAGE_SIZE, "%s }\n", buf);
>>> +     snprintf(buf, PAGE_SIZE, "%sSigningKeyMod: {", buf);
>>> +
>>> +     for (i = 255; i >= 0; i--)
>>> +             snprintf(buf, PAGE_SIZE, "%s %u", buf, data->sk_mod[i]);
>>> +     snprintf(buf, PAGE_SIZE, "%s }\n", buf);
>>> +
>>> +status_show_exit:
>>> +     kfree(data);
>>> +
>>> +     return strnlen(buf, PAGE_SIZE);
>>> +}
>>> +
>>> +struct kobj_attribute password_spm_status = __ATTR_RO(status);
>>> +
>>> +attribute_spm_n_property_show(is_enabled, spm);
>>> +static struct kobj_attribute password_spm_is_key_enabled = __ATTR_RO(is_enabled);
>>> +
>>> +
>>> +static ssize_t key_mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                        char *buf)
>>> +{
>>> +     int ret;
>>> +
>>> +     ret = snprintf(buf, PAGE_SIZE, "%s\n",
>>> +                    spm_mechanism_types[bioscfg_drv.spm_data.mechanism]);
>>> +     return ret;
>>> +}
>>> +static struct kobj_attribute password_spm_key_mechanism = __ATTR_RO(key_mechanism);
>>> +
>>> +static ssize_t sk_store(struct kobject *kobj,
>>> +                               struct kobj_attribute *attr,
>>> +                               const char *buf, size_t count)
>>> +{
>>> +     int ret;
>>> +     int length;
>>> +
>>> +     length = count;
>>> +     if (buf[length-1] == '\n')
>>> +             length--;
>>> +
>>> +     /* allocate space and copy current signing key */
>>> +     bioscfg_drv.spm_data.signing_key = kmalloc(length, GFP_KERNEL);
>>> +     if (!bioscfg_drv.spm_data.signing_key) {
>>> +             ret = -ENOMEM;
>>> +             goto exit_signing_key;
>>> +     }
>>> +
>>> +     memcpy(bioscfg_drv.spm_data.signing_key, buf, length);
>>> +     bioscfg_drv.spm_data.signing_key[length] = '\0';
>>> +
>>> +     /* submit signing key payload */
>>> +     ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_SK,
>>> +                                HPWMI_SECUREPLATFORM,
>>> +                                (void *)bioscfg_drv.spm_data.signing_key,
>>> +                                length, 0);
>>> +
>>> +     if (!ret) {
>>> +             bioscfg_drv.spm_data.mechanism = SIGNING_KEY;
>>> +             bioscfg_drv.pending_reboot = TRUE;
>>> +     }
>>> +
>>> +exit_signing_key:
>>> +     kfree(bioscfg_drv.spm_data.signing_key);
>>> +     bioscfg_drv.spm_data.signing_key = NULL;
>>> +
>>> +     return ret ? ret : count;
>>> +}
>>> +
>>> +static struct kobj_attribute password_spm_signing_key = __ATTR_WO(sk);
>>> +
>>> +static ssize_t kek_store(struct kobject *kobj,
>>> +                               struct kobj_attribute *attr,
>>> +                               const char *buf, size_t count)
>>> +{
>>> +     int ret;
>>> +     int length;
>>> +
>>> +     length = count;
>>> +     if (buf[length-1] == '\n')
>>> +             length--;
>>> +
>>> +     /* allocate space and copy current signing key */
>>> +     bioscfg_drv.spm_data.endorsement_key = kmalloc(length, GFP_KERNEL);
>>> +     if (!bioscfg_drv.spm_data.endorsement_key) {
>>> +             ret = -ENOMEM;
>>> +             goto exit_endorsement_key;
>>> +     }
>>> +
>>> +     memcpy(bioscfg_drv.spm_data.endorsement_key, buf, length);
>>> +     bioscfg_drv.spm_data.endorsement_key[length] = '\0';
>>> +
>>> +     ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
>>> +                                HPWMI_SECUREPLATFORM,
>>> +                                (void *)bioscfg_drv.spm_data.endorsement_key,
>>> +                                count, 0);
>>> +
>>> +     if (!ret) {
>>> +             bioscfg_drv.spm_data.mechanism = ENDORSEMENT_KEY;
>>> +             bioscfg_drv.pending_reboot = TRUE;
>>> +     }
>>> +
>>> +exit_endorsement_key:
>>> +     kfree(bioscfg_drv.spm_data.endorsement_key);
>>> +     bioscfg_drv.spm_data.endorsement_key = NULL;
>>> +
>>> +     return ret ? ret : count;
>>> +}
>>> +static struct kobj_attribute password_spm_endorsement_key = __ATTR_WO(kek);
>>> +
>>> +static ssize_t display_name_language_code_show(struct kobject *kobj,
>>> +                                            struct kobj_attribute *attr,
>>> +                                            char *buf)
>>> +{
>>> +     return sprintf(buf, "%s\n", LANG_CODE_STR);
>>> +}
>>> +
>>> +static struct kobj_attribute password_spm_display_langcode =
>>> +             __ATTR_RO(display_name_language_code);
>>> +
>>> +
>>> +static ssize_t display_name_show(struct kobject *kobj,
>>> +                              struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     return sprintf(buf, "%s\n", SPM_STR_DESC);
>>> +}
>>> +static struct kobj_attribute password_spm_display_name = __ATTR_RO(display_name);
>>> +
>>> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "secure-platform-management\n");
>>> +}
>>> +static struct kobj_attribute password_spm_type = __ATTR_RO(type);
>>> +
>>> +static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "%s\n", role_type[BIOS_SPM]);
>>> +}
>>> +static struct kobj_attribute password_spm_role = __ATTR_RO(role);
>>> +
>>> +static struct attribute *secure_platform_attrs[] = {
>>> +     &password_spm_display_name.attr,
>>> +     &password_spm_display_langcode.attr,
>>> +     &password_spm_is_key_enabled.attr,
>>> +     &password_spm_signing_key.attr,
>>> +     &password_spm_endorsement_key.attr,
>>> +     &password_spm_key_mechanism.attr,
>>> +     &password_spm_status.attr,
>>> +     &password_spm_statusbin.attr,
>>> +     &password_spm_type.attr,
>>> +     &password_spm_role.attr,
>>> +     NULL,
>>> +};
>>> +
>>> +static const struct attribute_group secure_platform_attr_group = {
>>> +     .attrs = secure_platform_attrs,
>>> +};
>>> +
>>> +void exit_secure_platform_attributes(void)
>>> +{
>>> +     /* remove secure platform sysfs entry and free key data*/
>>> +
>>> +     kfree(bioscfg_drv.spm_data.endorsement_key);
>>> +     bioscfg_drv.spm_data.endorsement_key = NULL;
>>> +
>>> +     kfree(bioscfg_drv.spm_data.signing_key);
>>> +     bioscfg_drv.spm_data.signing_key = NULL;
>>> +
>>> +     sysfs_remove_group(bioscfg_drv.spm_data.attr_name_kobj, &secure_platform_attr_group);
>>> +}
>>> +
>>> +int populate_secure_platform_data(struct kobject *attr_name_kobj)
>>> +{
>>> +     /* Populate data for Secure Platform Management */
>>> +     bioscfg_drv.spm_data.type = HPWMI_SECURE_PLATFORM_TYPE;
>>> +     bioscfg_drv.spm_data.attr_name_kobj = attr_name_kobj;
>>> +
>>> +     strscpy(bioscfg_drv.spm_data.attribute_name, SPM_STR,
>>> +             sizeof(bioscfg_drv.spm_data.attribute_name));
>>> +     strscpy(bioscfg_drv.spm_data.display_name, SPM_STR_DESC,
>>> +             sizeof(bioscfg_drv.spm_data.display_name));
>>> +
>>> +     bioscfg_drv.spm_data.is_enabled = 0;
>>> +     bioscfg_drv.spm_data.mechanism = 0;
>>> +     bioscfg_drv.pending_reboot = FALSE;
>>> +     update_spm_state();
>>> +
>>> +     bioscfg_drv.spm_data.endorsement_key = NULL;
>>> +     bioscfg_drv.spm_data.signing_key = NULL;
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &secure_platform_attr_group);
>>> +}
>>> diff --git a/drivers/platform/x86/hp/string-attributes.c b/drivers/platform/x86/hp/string-attributes.c
>>> new file mode 100644
>>> index 000000000000..c85688cfbccc
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/string-attributes.c
>>> @@ -0,0 +1,447 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to string type attributes under
>>> + * HP_WMI_BIOS_STRING_GUID for use with hp-bioscfg driver.
>>> + *
>>> + * Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#include "bioscfg.h"
>>> +
>>> +#define WMI_STRING_TYPE "HPBIOS_BIOSString"
>>> +
>>> +get_instance_id(string);
>>> +
>>> +static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     int instance_id = get_string_instance_id(kobj);
>>> +     union acpi_object *obj = NULL;
>>> +     ssize_t ret;
>>> +
>>> +     if (instance_id < 0)
>>> +             return -EIO;
>>> +
>>> +     /* need to use specific instance_id and guid combination to get right data */
>>> +     obj = get_wmiobj_pointer(instance_id, HP_WMI_BIOS_STRING_GUID);
>>> +     if (!obj)
>>> +             return -EIO;
>>> +
>>> +     ret = snprintf(buf, PAGE_SIZE, "%s\n",
>>> +                    bioscfg_drv.string_data[instance_id].current_value);
>>> +
>>> +     kfree(obj);
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * validate_string_input() -
>>> + * Validate input of current_value against min and max lengths
>>> + *
>>> + * @instance_id: The instance on which input is validated
>>> + * @buf: Input value
>>> + */
>>> +static int validate_string_input(int instance_id, const char *buf)
>>> +{
>>> +     int in_len = strlen(buf);
>>> +
>>> +     /* BIOS treats it as a read only attribute */
>>> +     if (bioscfg_drv.string_data[instance_id].is_readonly)
>>> +             return -EIO;
>>> +
>>> +     if ((in_len < bioscfg_drv.string_data[instance_id].min_length) ||
>>> +         (in_len > bioscfg_drv.string_data[instance_id].max_length))
>>> +             return -EINVAL;
>>> +
>>> +     strscpy(bioscfg_drv.string_data[instance_id].new_value,
>>> +             buf,
>>> +             sizeof(bioscfg_drv.string_data[instance_id].new_value));
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static void update_string_value(int instance_id)
>>> +{
>>> +     /* Write settings to BIOS */
>>> +     strscpy(bioscfg_drv.string_data[instance_id].current_value,
>>> +             bioscfg_drv.string_data[instance_id].new_value,
>>> +             sizeof(bioscfg_drv.string_data[instance_id].current_value));
>>> +}
>>> +
>>> +attribute_s_property_show(display_name_language_code, string);
>>> +static struct kobj_attribute string_display_langcode =
>>> +             __ATTR_RO(display_name_language_code);
>>> +
>>> +attribute_s_property_show(display_name, string);
>>> +static struct kobj_attribute string_display_name =
>>> +             __ATTR_RO(display_name);
>>> +
>>> +attribute_property_store(current_value, string);
>>> +static struct kobj_attribute string_current_val =
>>> +             __ATTR_RW_MODE(current_value, 0600);
>>> +
>>> +attribute_n_property_show(min_length, string);
>>> +static struct kobj_attribute string_min_length =
>>> +             __ATTR_RO(min_length);
>>> +
>>> +attribute_n_property_show(max_length, string);
>>> +static struct kobj_attribute string_max_length =
>>> +             __ATTR_RO(max_length);
>>> +
>>> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "string\n");
>>> +}
>>> +
>>> +static struct kobj_attribute string_type =
>>> +     __ATTR_RO(type);
>>> +
>>> +static struct attribute *string_attrs[] = {
>>> +     &string_display_langcode.attr,
>>> +     &string_display_name.attr,
>>> +     &string_current_val.attr,
>>> +     &string_min_length.attr,
>>> +     &string_max_length.attr,
>>> +     &string_type.attr,
>>> +     NULL
>>> +};
>>> +
>>> +static const struct attribute_group string_attr_group = {
>>> +     .attrs = string_attrs,
>>> +};
>>> +
>>> +int alloc_string_data(void)
>>> +{
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.string_instances_count = get_instance_count(HP_WMI_BIOS_STRING_GUID);
>>> +     bioscfg_drv.string_data = kcalloc(bioscfg_drv.string_instances_count,
>>> +                                     sizeof(struct string_data), GFP_KERNEL);
>>> +     if (!bioscfg_drv.string_data) {
>>> +             bioscfg_drv.string_instances_count = 0;
>>> +             ret = -ENOMEM;
>>> +     }
>>> +     return ret;
>>> +}
>>> +
>>> +/*
>>> + * populate_string_package_data() -
>>> + * Populate all properties of an instance under string attribute
>>> + *
>>> + * @elements: ACPI object with string data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + */
>>> +int populate_string_package_data(union acpi_object *elements, int instance_id,
>>> +                     struct kobject *attr_name_kobj)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int str_len;
>>> +     int ret = 0;
>>> +
>>> +     bioscfg_drv.string_data[instance_id].type = HPWMI_STRING_TYPE;
>>> +     bioscfg_drv.string_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +
>>> +     ret = convert_hexstr_to_str(&(elements[NAME].string.pointer),
>>> +                                    elements[NAME].string.length,
>>> +                                    &str_value, &str_len);
>>> +
>>> +     if (ACPI_FAILURE(ret)) {
>>> +             pr_warn("Failed to populate string package data. Error [0%0x]\n", ret);
>>> +             kfree(str_value);
>>> +             return ret;
>>> +     }
>>> +
>>> +     strscpy(bioscfg_drv.string_data[instance_id].attribute_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.string_data[instance_id].attribute_name));
>>> +
>>> +     strscpy(bioscfg_drv.string_data[instance_id].display_name,
>>> +             str_value,
>>> +             sizeof(bioscfg_drv.string_data[instance_id].display_name));
>>> +
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +
>>> +     populate_string_elements_from_package(elements, instance_id, HPWMI_STRING_TYPE);
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &string_attr_group);
>>> +}
>>> +
>>> +int populate_string_elements_from_package(union acpi_object *elements,
>>> +                                        int instance_id,
>>> +                                        enum hp_wmi_data_type type)
>>> +{
>>> +     char *str_value = NULL;
>>> +     int value_len;
>>> +     int status = 0;
>>> +     u32 size = 0;
>>> +     u32 int_value;
>>> +     int elem = 0;
>>> +     int reqs;
>>> +     int eloc;
>>> +
>>> +     if (!elements)
>>> +             return -EINVAL;
>>> +
>>> +     strscpy(bioscfg_drv.string_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.string_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1, eloc = 1; elem < hp_wmi_elements_count[type]; elem++, eloc++) {
>>> +
>>> +             switch (elements[elem].type) {
>>> +             case ACPI_TYPE_STRING:
>>> +
>>> +                     if (elem != PREREQUISITES) {
>>> +                             status = convert_hexstr_to_str(&elements[elem].string.pointer,
>>> +                                                            elements[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +                     }
>>> +                     break;
>>> +             case ACPI_TYPE_INTEGER:
>>> +                     int_value = (u32)elements[elem].integer.value;
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Unsupported object type [%d]\n", elements[elem].type);
>>> +                     continue;
>>> +             }
>>> +
>>> +             /*
>>> +              * Stop if extra counter is greater than total number
>>> +              * of elements for string type
>>> +              */
>>> +             if (eloc == hp_wmi_elements_count[type])
>>> +                     goto exit_string_package;
>>> +
>>> +             /* Assign appropriate element value to corresponding field*/
>>> +             switch (eloc) {
>>> +             case VALUE:
>>> +                     strscpy(bioscfg_drv.string_data[instance_id].current_value,
>>> +                             str_value, sizeof(bioscfg_drv.string_data[instance_id].current_value));
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.string_data[instance_id].path, str_value,
>>> +                             sizeof(bioscfg_drv.string_data[instance_id].path));
>>> +                     break;
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.string_data[instance_id].is_readonly = int_value;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.string_data[instance_id].display_in_ui = int_value;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.string_data[instance_id].requires_physical_presence = int_value;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.string_data[instance_id].sequence = int_value;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.string_data[instance_id].prerequisitesize = int_value;
>>> +                     if (size > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +
>>> +                     /*
>>> +                      * prerequisites element is omitted when
>>> +                      * prerequisitesSize value is zero.
>>> +                      */
>>> +                     if (int_value == 0)
>>> +                             eloc++;
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.string_data[instance_id].prerequisitesize;
>>> +
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = convert_hexstr_to_str(&elements[elem].string.pointer,
>>> +                                                            elements[elem].string.length,
>>> +                                                            &str_value, &value_len);
>>> +
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +                             pr_warn("Prerequisite String  value [%s]\n", str_value);
>>> +
>>> +                             strlcat(bioscfg_drv.string_data[instance_id].prerequisites,
>>> +                                     str_value,
>>> +                                     sizeof(bioscfg_drv.string_data[instance_id].prerequisites));
>>> +
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.string_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.string_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str_value);
>>> +                             str_value = NULL;
>>> +                     }
>>> +                     break;
>>> +
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.string_data[instance_id].security_level = int_value;
>>> +                     break;
>>> +             case STR_MIN_LENGTH:
>>> +                     bioscfg_drv.string_data[instance_id].min_length = int_value;
>>> +                     break;
>>> +             case STR_MAX_LENGTH:
>>> +                     bioscfg_drv.string_data[instance_id].max_length = int_value;
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in String attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str_value);
>>> +             str_value = NULL;
>>> +     }
>>> +exit_string_package:
>>> +     kfree(str_value);
>>> +     str_value = NULL;
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +/*
>>> + * populate_string_data() -
>>> + * Populate all properties of an instance under string attribute
>>> + *
>>> + * @string_obj: ACPI object with string data
>>> + * @instance_id: The instance to enumerate
>>> + * @attr_name_kobj: The parent kernel object
>>> + */
>>> +int populate_string_buffer_data(union acpi_object *string_obj, int instance_id, struct kobject *attr_name_kobj)
>>> +{
>>> +     bioscfg_drv.string_data[instance_id].type = HPWMI_STRING_TYPE;
>>> +     bioscfg_drv.string_data[instance_id].attr_name_kobj = attr_name_kobj;
>>> +     strscpy(bioscfg_drv.string_data[instance_id].attribute_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.string_data[instance_id].attribute_name));
>>> +
>>> +     strscpy(bioscfg_drv.string_data[instance_id].display_name,
>>> +             attr_name_kobj->name,
>>> +             sizeof(bioscfg_drv.string_data[instance_id].display_name));
>>> +     /* Populate string elements */
>>> +
>>> +     populate_string_elements_from_buffer(string_obj, instance_id, HPWMI_STRING_TYPE);
>>> +
>>> +     return sysfs_create_group(attr_name_kobj, &string_attr_group);
>>> +}
>>> +
>>> +int populate_string_elements_from_buffer(union acpi_object *string_obj, int instance_id, enum hp_wmi_data_type type)
>>> +{
>>> +     int status;
>>> +     char *str = NULL;
>>> +     int elem;
>>> +     int reqs;
>>> +     int int_value;
>>> +     int size = 0;
>>> +
>>> +     strscpy(bioscfg_drv.string_data[instance_id].display_name_language_code,
>>> +             LANG_CODE_STR,
>>> +             sizeof(bioscfg_drv.string_data[instance_id].display_name_language_code));
>>> +
>>> +     for (elem = 1; elem < 3; elem++) {
>>> +             status = get_string_from_buffer((u16 **)&string_obj->buffer.pointer, &str);
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +             case VALUE:
>>> +                     strscpy(bioscfg_drv.string_data[instance_id].current_value,
>>> +                             str, sizeof(bioscfg_drv.string_data[instance_id].current_value));
>>> +                     break;
>>> +             case PATH:
>>> +                     strscpy(bioscfg_drv.string_data[instance_id].path, str, sizeof(bioscfg_drv.string_data[instance_id].path));
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in String attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +
>>> +     for (elem = 3; elem < hp_wmi_elements_count[type]; elem++) {
>>> +
>>> +             if (elem != PREREQUISITES)
>>> +                     status = get_integer_from_buffer((int **)&string_obj->buffer.pointer, (int *)&int_value);
>>> +
>>> +             if (ACPI_FAILURE(status))
>>> +                     continue;
>>> +
>>> +             switch (elem) {
>>> +             case IS_READONLY:
>>> +                     bioscfg_drv.string_data[instance_id].is_readonly = int_value;
>>> +                     break;
>>> +             case DISPLAY_IN_UI:
>>> +                     bioscfg_drv.string_data[instance_id].display_in_ui = int_value;
>>> +                     break;
>>> +             case REQUIRES_PHYSICAL_PRESENCE:
>>> +                     bioscfg_drv.string_data[instance_id].requires_physical_presence = int_value;
>>> +                     break;
>>> +             case SEQUENCE:
>>> +                     bioscfg_drv.string_data[instance_id].sequence = int_value;
>>> +                     break;
>>> +             case PREREQUISITE_SIZE:
>>> +                     bioscfg_drv.string_data[instance_id].prerequisitesize = int_value;
>>> +                     if (int_value > 20)
>>> +                             pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
>>> +                     break;
>>> +             case PREREQUISITES:
>>> +                     size = bioscfg_drv.string_data[instance_id].prerequisitesize;
>>> +                     for (reqs = 0; reqs < size; reqs++) {
>>> +                             status = get_string_from_buffer((u16 **)&string_obj->buffer.pointer, &str);
>>> +                             if (ACPI_FAILURE(status))
>>> +                                     continue;
>>> +
>>> +                             strlcat(bioscfg_drv.string_data[instance_id].prerequisites,
>>> +                                     str,
>>> +                                     sizeof(bioscfg_drv.string_data[instance_id].prerequisites));
>>> +
>>> +                             if (reqs != (size - 1))
>>> +                                     strlcat(bioscfg_drv.string_data[instance_id].prerequisites, ";",
>>> +                                             sizeof(bioscfg_drv.string_data[instance_id].prerequisites));
>>> +
>>> +                             kfree(str);
>>> +                             str = NULL;
>>> +                     }
>>> +                     break;
>>> +             case SECURITY_LEVEL:
>>> +                     bioscfg_drv.string_data[instance_id].security_level = int_value;
>>> +                     break;
>>> +             case STR_MIN_LENGTH:
>>> +                     bioscfg_drv.string_data[instance_id].min_length = int_value;
>>> +                     break;
>>> +             case STR_MAX_LENGTH:
>>> +                     bioscfg_drv.string_data[instance_id].max_length = int_value;
>>> +                     break;
>>> +             default:
>>> +                     pr_warn("Invalid element: %d found in String attribute or data may be malformed\n", elem);
>>> +                     break;
>>> +             }
>>> +             kfree(str);
>>> +             str = NULL;
>>> +     }
>>> +     kfree(str);
>>> +     str = NULL;
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +/*
>>> + * exit_string_attributes() - Clear all attribute data
>>> + *
>>> + * Clears all data allocated for this group of attributes
>>> + */
>>> +void exit_string_attributes(void)
>>> +{
>>> +     int instance_id;
>>> +
>>> +     for (instance_id = 0; instance_id < bioscfg_drv.string_instances_count; instance_id++) {
>>> +             if (bioscfg_drv.string_data[instance_id].attr_name_kobj)
>>> +                     sysfs_remove_group(bioscfg_drv.string_data[instance_id].attr_name_kobj,
>>> +                                                             &string_attr_group);
>>> +     }
>>> +     bioscfg_drv.string_instances_count = 0;
>>> +
>>> +     kfree(bioscfg_drv.string_data);
>>> +     bioscfg_drv.string_data = NULL;
>>> +}
>>> diff --git a/drivers/platform/x86/hp/sureadmin-attributes.c b/drivers/platform/x86/hp/sureadmin-attributes.c
>>> new file mode 100644
>>> index 000000000000..dba5f94e8c9a
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/sureadmin-attributes.c
>>> @@ -0,0 +1,984 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to sure admin object type attributes under
>>> + * BIOS for use with hp-bioscfg driver
>>> + *
>>> + *  Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#include "bioscfg.h"
>>> +
>>> +static int bios_settings_size;
>>> +static int buf_alloc_size;
>>> +static char *bios_settings_buffer;
>>> +
>>> +const char *hp_wmi_classes[] = {
>>> +     "HPBIOS_BIOSString",
>>> +     "HPBIOS_BIOSInteger",
>>> +     "HPBIOS_BIOSEnumeration",
>>> +     "HPBIOS_BIOSOrderedList",
>>> +     "HPBIOS_BIOSPassword"
>>> +};
>>> +
>>> +get_instance_id_for_attribute(string);
>>> +get_instance_id_for_attribute(integer);
>>> +get_instance_id_for_attribute(enumeration);
>>> +get_instance_id_for_attribute(ordered_list);
>>> +
>>> +static ssize_t sure_admin_settings_write(struct file *filp, struct kobject *kobj,
>>> +                                      struct bin_attribute *attr,
>>> +                                      char *buf, loff_t off, size_t count)
>>> +{
>>> +     int status = 0;
>>> +     char *part = NULL;
>>> +     char *attr_name = NULL;
>>> +     char *attr_value = NULL;
>>> +     int part_len = 0;
>>> +     unsigned short *buffer = NULL;
>>> +     unsigned short *tmpstr = NULL;
>>> +     int buffer_size = (count + strlen(UTF_PREFIX)) * sizeof(unsigned short);
>>> +
>>> +     buffer = kmalloc(buffer_size, GFP_KERNEL);
>>> +     if (!buffer)
>>> +             return -ENOMEM;
>>> +
>>> +     tmpstr = buffer;
>>> +     part = strsep(&buf, ",");
>>> +     if (!part) {
>>> +             status = -EINVAL;
>>> +             goto exit_settings;
>>> +     }
>>> +     // Save attr_name
>>> +     attr_name = kmalloc(strlen(part) + 1, GFP_KERNEL);
>>> +     if (!attr_name) {
>>> +             status = -EINVAL;
>>> +             goto exit_settings;
>>> +     }
>>> +     strncpy(attr_name, part, strlen(part));
>>> +
>>> +     tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>>> +     part = strsep(&buf, ",");
>>> +     if (!part) {
>>> +             status = -EINVAL;
>>> +             goto exit_settings;
>>> +     }
>>> +
>>> +     part_len = strlen(part);
>>> +
>>> +     /* Add extra buffer space when encountering an empty string */
>>> +     if (!part_len) {
>>> +             buffer_size += sizeof(unsigned short);
>>> +             part_len += sizeof(unsigned short);
>>> +     }
>>> +
>>> +     // Save attr_value
>>> +     attr_value = kmalloc(part_len + 1, GFP_KERNEL);
>>> +     if (!attr_value) {
>>> +             status = -EINVAL;
>>> +             goto exit_settings;
>>> +     }
>>> +     strncpy(attr_value, part, part_len);
>>> +
>>> +     tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>>> +     part = strsep(&buf, ",");
>>> +     if (!part) {
>>> +             status = -EINVAL;
>>> +             goto exit_settings;
>>> +     }
>>> +     part_len = strlen(part) - 1;
>>> +     part[part_len] = '\0';
>>> +
>>> +     if (strncmp(part, BEAM_PREFIX, strlen(BEAM_PREFIX)) == 0) {
>>> +            /*
>>> +             * BEAM_PREFIX is append to buffer when a signature
>>> +             * is provided and Sure Admin is enabled in BIOS
>>> +             */
>>> +             // BEAM_PREFIX found, convert part to unicode
>>> +             tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>>> +             // decrease buffer size allocated initially for UTF_PREFIX
>>> +             buffer_size -= strlen(UTF_PREFIX) * sizeof(unsigned short);
>>> +     } else {
>>> +             /*
>>> +              * UTF-16 prefix is append to the * buffer when a BIOS
>>> +              * admin password is configured in BIOS
>>> +              */
>>> +
>>> +             // append UTF_PREFIX to part and then convert it to unicode
>>> +             part = kasprintf(GFP_KERNEL, "%s%s", UTF_PREFIX, part);
>>> +             if (!part)
>>> +                     goto exit_settings;
>>> +
>>> +             tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>>> +             kfree(part);
>>> +     }
>>> +
>>> +     part = strsep(&buf, ",");
>>> +     if (part) {
>>> +             status = -EINVAL;
>>> +             goto exit_settings;
>>> +     }
>>> +
>>> +     status = hp_wmi_set_bios_setting(buffer, buffer_size);
>>> +     if (ACPI_FAILURE(status)) {
>>> +             status = -EINVAL;
>>> +             goto exit_settings;
>>> +     }
>>> +
>>> +     if (attr_name == NULL)
>>> +             pr_warn("Name is null\n");
>>> +     if (attr_value == NULL)
>>> +             pr_warn("Value is null\n");
>>> +
>>> +     update_attribute_value(attr_name, attr_value);
>>> +
>>> +
>>> +exit_settings:
>>> +     kfree(buffer);
>>> +     kfree(attr_name);
>>> +     kfree(attr_value);
>>> +
>>> +     if (ACPI_SUCCESS(status))
>>> +             return count;
>>> +
>>> +     return status;
>>> +}
>>> +
>>> +int update_attribute_value(char *attr_name, char *attr_value)
>>> +{
>>> +     int instance = -EIO;
>>> +     int int_val;
>>> +     int ret;
>>> +
>>> +     if (!attr_name || !attr_value)
>>> +             return -EIO;
>>> +
>>> +     /* update value for the attribute */
>>> +     instance = get_instance_id_for_string(attr_name);
>>> +     if (instance >= 0) {
>>> +             strscpy(bioscfg_drv.string_data[instance].current_value,
>>> +                     attr_value,
>>> +                     sizeof(bioscfg_drv.string_data[instance].current_value));
>>> +             goto exit_update_attribute;
>>> +     }
>>> +
>>> +     instance = get_instance_id_for_integer(attr_name);
>>> +     if (instance >= 0) {
>>> +             ret = kstrtoint(attr_value, 10, &int_val);
>>> +             if (!ret)
>>> +                     bioscfg_drv.integer_data[instance].current_value = int_val;
>>> +             goto exit_update_attribute;
>>> +     }
>>> +
>>> +     instance = get_instance_id_for_enumeration(attr_name);
>>> +     if (instance >= 0) {
>>> +             strscpy(bioscfg_drv.enumeration_data[instance].current_value,
>>> +                     attr_value,
>>> +                     sizeof(bioscfg_drv.enumeration_data[instance].current_value));
>>> +             goto exit_update_attribute;
>>> +     }
>>> +     instance = get_instance_id_for_ordered_list(attr_name);
>>> +     if (instance >= 0)
>>> +             strscpy(bioscfg_drv.ordered_list_data[instance].current_value,
>>> +                     attr_value,
>>> +                     sizeof(bioscfg_drv.ordered_list_data[instance].current_value));
>>> +
>>> +exit_update_attribute:
>>> +     return instance;
>>> +}
>>> +
>>> +static ssize_t sure_admin_settings_read(struct file *filp, struct kobject *kobj,
>>> +                                     struct bin_attribute *attr, char *buf,
>>> +                                     loff_t off, size_t count)
>>> +{
>>> +     ssize_t ret;
>>> +
>>> +     /* clear the buffer when offset is pointing to the last position */
>>> +     if (off >= bios_settings_size && bios_settings_size > 0) {
>>> +             hp_bios_settings_free_buffer();
>>> +             return 0;
>>> +     }
>>> +
>>> +     /* clear the buffer whenever the read starts from the first position */
>>> +     if (off == 0 && bios_settings_size > 0)
>>> +             hp_bios_settings_free_buffer();
>>> +
>>> +     if (bios_settings_size == 0)
>>> +             hp_bios_settings_fill_buffer();
>>> +
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     ret = memory_read_from_buffer(buf, count, &off, bios_settings_buffer,
>>> +                                   bios_settings_size);
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
>>> +
>>> +static struct bin_attribute *sure_admin_binattrs[] = {
>>> +     &sure_admin_settings,
>>> +     NULL,
>>> +};
>>> +
>>> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "sure-admin\n");
>>> +}
>>> +static struct kobj_attribute sure_admin_type = __ATTR_RO(type);
>>> +
>>> +static ssize_t display_name_language_code_show(struct kobject *kobj,
>>> +                                            struct kobj_attribute *attr,
>>> +                                            char *buf)
>>> +{
>>> +     return sprintf(buf, "%s\n", LANG_CODE_STR);
>>> +}
>>> +
>>> +static struct kobj_attribute sure_admin_display_langcode =
>>> +             __ATTR_RO(display_name_language_code);
>>> +
>>> +
>>> +static ssize_t display_name_show(struct kobject *kobj,
>>> +                              struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     return sprintf(buf, "%s\n", SURE_ADMIN_DESC);
>>> +}
>>> +static struct kobj_attribute sure_admin_display_name = __ATTR_RO(display_name);
>>> +
>>> +static struct attribute *sure_admin_attrs[] = {
>>> +     &sure_admin_display_name.attr,
>>> +     &sure_admin_display_langcode.attr,
>>> +     &sure_admin_type.attr,
>>> +     NULL,
>>> +};
>>> +
>>> +static const struct attribute_group sure_admin_attr_group = {
>>> +     .attrs = sure_admin_attrs,
>>> +     .bin_attrs = sure_admin_binattrs,
>>> +};
>>> +
>>> +void exit_sure_admin_attributes(void)
>>> +{
>>> +     sysfs_remove_group(bioscfg_drv.sure_admin_attr_kobj, &sure_admin_attr_group);
>>> +}
>>> +
>>> +int populate_sure_admin_data(struct kobject *attr_name_kobj)
>>> +{
>>> +     bioscfg_drv.sure_admin_attr_kobj = attr_name_kobj;
>>> +     return sysfs_create_group(attr_name_kobj, &sure_admin_attr_group);
>>> +}
>>> +
>>> +int hp_bios_settings_fill_buffer(void)
>>> +{
>>> +     int status = 0;
>>> +     int initial_buffer_size = 20 * PAGE_SIZE;
>>> +
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     bios_settings_buffer = kmalloc(initial_buffer_size, GFP_KERNEL);
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +     if (!bios_settings_buffer)
>>> +             return -ENOMEM;
>>> +
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     buf_alloc_size = ksize(bios_settings_buffer);
>>> +     memset(bios_settings_buffer, 0x00, buf_alloc_size);
>>> +     bios_settings_size = snprintf(bios_settings_buffer,
>>> +                                     buf_alloc_size, "[\n");
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +
>>> +     status = append_read_settings(HPWMI_STRING_TYPE,
>>> +                                        &bios_settings_buffer,
>>> +                                        &bios_settings_size,
>>> +                                        &buf_alloc_size);
>>> +     if (ACPI_FAILURE(status))
>>> +             pr_err("error 0x%x occurred retrieving string instances\n", status);
>>> +
>>> +     status = append_read_settings(HPWMI_INTEGER_TYPE,
>>> +                                        &bios_settings_buffer,
>>> +                                        &bios_settings_size,
>>> +                                        &buf_alloc_size);
>>> +     if (ACPI_FAILURE(status))
>>> +             pr_err("error 0x%x occurred retrieving integer instances\n", status);
>>> +
>>> +     status = append_read_settings(HPWMI_ENUMERATION_TYPE,
>>> +                                        &bios_settings_buffer,
>>> +                                        &bios_settings_size,
>>> +                                        &buf_alloc_size);
>>> +     if (ACPI_FAILURE(status))
>>> +             pr_err("error 0x%x occurred retrieving enumeration instances\n", status);
>>> +
>>> +     status = append_read_settings(HPWMI_ORDERED_LIST_TYPE,
>>> +                                        &bios_settings_buffer,
>>> +                                        &bios_settings_size,
>>> +                                        &buf_alloc_size);
>>> +     if (ACPI_FAILURE(status))
>>> +             pr_err("error 0x%x occurred retrieving ordered list instances\n", status);
>>> +
>>> +     status = append_read_settings(HPWMI_PASSWORD_TYPE,
>>> +                                        &bios_settings_buffer,
>>> +                                        &bios_settings_size,
>>> +                                        &buf_alloc_size);
>>> +     if (ACPI_FAILURE(status))
>>> +             pr_err("error 0x%x occurred retrieving password list instances\n", status);
>>> +
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     /*
>>> +      * remove trailing comma
>>> +      */
>>> +     if (bios_settings_size >= 3) {
>>> +             if (bios_settings_buffer[bios_settings_size - 2] == ',')
>>> +                     bios_settings_buffer[bios_settings_size - 2] = ' ';
>>> +     }
>>> +     bios_settings_size = snprintf(bios_settings_buffer,
>>> +                                     buf_alloc_size, "%s]\n",
>>> +                                     bios_settings_buffer);
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +
>>> +     return bios_settings_size;
>>> +}
>>> +
>>> +int hp_bios_settings_free_buffer(void)
>>> +{
>>> +     mutex_lock(&bioscfg_drv.mutex);
>>> +     kfree(bios_settings_buffer);
>>> +     bios_settings_size = 0;
>>> +     buf_alloc_size = 0;
>>> +     mutex_unlock(&bioscfg_drv.mutex);
>>> +
>>> +     return 0;
>>> +}
>>> +int hp_bios_settings_realloc_buffer(char **buf, int *buf_size, int *alloc_size)
>>> +{
>>> +     int new_buffer_size;
>>> +     char *new_buf = NULL;
>>> +     int ret = 0;
>>> +
>>> +     if (*buf_size + PAGE_SIZE >= *alloc_size) {
>>> +             new_buffer_size = buf_alloc_size + 2 * PAGE_SIZE;
>>> +
>>> +             mutex_lock(&bioscfg_drv.mutex);
>>> +             new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
>>> +             mutex_unlock(&bioscfg_drv.mutex);
>>> +             if (new_buf) {
>>> +                     mutex_lock(&bioscfg_drv.mutex);
>>> +                     *buf = new_buf;
>>> +                     *alloc_size = ksize(new_buf);
>>> +                     mutex_unlock(&bioscfg_drv.mutex);
>>> +             } else {
>>> +                     hp_bios_settings_free_buffer();
>>> +                     ret = -ENOMEM;
>>> +             }
>>> +     }
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +int append_read_settings(enum hp_wmi_data_type type, char **buf,
>>> +                      int *buf_size, int *alloc_size)
>>> +{
>>> +     int ret = 0;
>>> +     int status = 0;
>>> +     int instance = 0;
>>> +     int instance_count = 0;
>>> +
>>> +     switch (type) {
>>> +     case HPWMI_STRING_TYPE:
>>> +             instance_count = bioscfg_drv.string_instances_count;
>>> +             break;
>>> +     case HPWMI_INTEGER_TYPE:
>>> +             instance_count = bioscfg_drv.integer_instances_count;
>>> +             break;
>>> +     case HPWMI_ENUMERATION_TYPE:
>>> +             instance_count = bioscfg_drv.enumeration_instances_count;
>>> +             break;
>>> +     case HPWMI_ORDERED_LIST_TYPE:
>>> +             instance_count = bioscfg_drv.ordered_list_instances_count;
>>> +             break;
>>> +     case HPWMI_PASSWORD_TYPE:
>>> +             instance_count = bioscfg_drv.password_instances_count;
>>> +             break;
>>> +     default:
>>> +             return -EINVAL;
>>> +     }
>>> +
>>> +     /*
>>> +      * Query all the instances
>>> +      */
>>> +     for (instance = 0; instance < instance_count; instance++) {
>>> +             mutex_lock(&bioscfg_drv.mutex);
>>> +             status = append_read_attributes(buf, *alloc_size,
>>> +                                                  instance, type);
>>> +             if (status > 0)
>>> +                     *buf_size = status;
>>> +
>>> +             mutex_unlock(&bioscfg_drv.mutex);
>>> +
>>> +             ret = hp_bios_settings_realloc_buffer(buf, buf_size,
>>> +                                                   alloc_size);
>>> +     }
>>> +     return ret;
>>> +}
>>> +
>>> +int append_read_attributes(char **buf, int alloc_size,
>>> +                        int instance, enum hp_wmi_data_type type)
>>> +{
>>> +     int status = 0;
>>> +
>>> +     switch (type) {
>>> +     case HPWMI_STRING_TYPE:
>>> +             status = append_read_string_attributes(*buf, alloc_size,
>>> +                                                    instance, type);
>>> +             break;
>>> +     case HPWMI_INTEGER_TYPE:
>>> +             status = append_read_integer_attributes(*buf, alloc_size,
>>> +                                                     instance, type);
>>> +             break;
>>> +     case HPWMI_ENUMERATION_TYPE:
>>> +             status = append_read_enumeration_attributes(*buf,
>>> +                                                         alloc_size,
>>> +                                                         instance, type);
>>> +             break;
>>> +     case HPWMI_ORDERED_LIST_TYPE:
>>> +             status = append_read_ordered_list_attributes(*buf,
>>> +                                                          alloc_size,
>>> +                                                          instance, type);
>>> +             break;
>>> +     case HPWMI_PASSWORD_TYPE:
>>> +             status = append_read_password_attributes(*buf,
>>> +                                                      alloc_size,
>>> +                                                      instance, type);
>>> +             break;
>>> +     default:
>>> +             status = -EINVAL;
>>> +             break;
>>> +     }
>>> +     return status;
>>> +}
>>> +
>>> +
>>> +int append_read_string_attributes(char *buf, int alloc_size,
>>> +                               int instance,
>>> +                               enum hp_wmi_data_type type)
>>> +{
>>> +     int buf_size;
>>> +     char *part_tmp = NULL;
>>> +     char *part = NULL;
>>> +
>>> +     if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf)
>>> +             return -EINVAL;
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s{\n", buf);
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Class\": \"%s\",\n",
>>> +                         buf, hp_wmi_classes[type]);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Name\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].display_name);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Value\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].current_value);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Path\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].path);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"IsReadOnly\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].is_readonly);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"DisplayInUI\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].display_in_ui);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"RequiresPhysicalPresence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].requires_physical_presence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Sequence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].sequence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"PrerequisiteSize\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].prerequisitesize);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Prerequisites\": [\n", buf);
>>> +
>>> +     if (bioscfg_drv.string_data[instance].prerequisitesize) {
>>> +             part_tmp = kstrdup(bioscfg_drv.string_data[instance].prerequisites,
>>> +                                GFP_KERNEL);
>>> +             part = strsep(&part_tmp, ";");
>>> +             while (part) {
>>> +                     buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part);
>>> +                     part = strsep(&part_tmp, ";");
>>> +                     if (part)
>>> +                             buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
>>> +                     else
>>> +                             buf_size = snprintf(buf, alloc_size, "%s\n", buf);
>>> +             }
>>> +             kfree(part_tmp);
>>> +             part_tmp = NULL;
>>> +     }
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>> +
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"SecurityLevel\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].security_level);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"MinLength\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].min_length);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"MaxLength\": %d\n",
>>> +                         buf,
>>> +                         bioscfg_drv.string_data[instance].max_length);
>>> +
>>> +     return snprintf(buf, alloc_size, "%s},\n", buf);
>>> +}
>>> +
>>> +
>>> +int append_read_integer_attributes(char *buf, int alloc_size,
>>> +                                int instance,
>>> +                                enum hp_wmi_data_type type)
>>> +{
>>> +     int buf_size;
>>> +     char *part_tmp = NULL;
>>> +     char *part = NULL;
>>> +
>>> +     if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf)
>>> +             return -EINVAL;
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s{\n", buf);
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Class\": \"%s\",\n",
>>> +                         buf, hp_wmi_classes[type]);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Name\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].display_name);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Value\": \"%d\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].current_value);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Path\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].path);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"IsReadOnly\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].is_readonly);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"DisplayInUI\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].display_in_ui);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"RequiresPhysicalPresence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].requires_physical_presence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Sequence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].sequence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"PrerequisiteSize\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].prerequisitesize);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Prerequisites\": [\n", buf);
>>> +
>>> +     if (bioscfg_drv.integer_data[instance].prerequisitesize) {
>>> +             part_tmp = kstrdup(bioscfg_drv.integer_data[instance].prerequisites,
>>> +                                GFP_KERNEL);
>>> +             part = strsep(&part_tmp, ";");
>>> +             while (part) {
>>> +                     buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part);
>>> +                     part = strsep(&part_tmp, ";");
>>> +                     if (part)
>>> +                             buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
>>> +                     else
>>> +                             buf_size = snprintf(buf, alloc_size, "%s\n", buf);
>>> +             }
>>> +             kfree(part_tmp);
>>> +             part_tmp = NULL;
>>> +     }
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"SecurityLevel\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].security_level);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"LowerBound\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].lower_bound);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"UpperBound\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].upper_bound);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"IntValue\": %d\n",
>>> +                         buf,
>>> +                         bioscfg_drv.integer_data[instance].scalar_increment);
>>> +
>>> +     return snprintf(buf, alloc_size, "%s},\n", buf);
>>> +}
>>> +
>>> +int append_read_enumeration_attributes(char *buf, int alloc_size,
>>> +                                    int instance,
>>> +                                    enum hp_wmi_data_type type)
>>> +{
>>> +     int buf_size;
>>> +     char *part_tmp = NULL;
>>> +     char *part = NULL;
>>> +
>>> +     if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf)
>>> +             return -EINVAL;
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s{\n", buf);
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Class\": \"%s\",\n",
>>> +                         buf, hp_wmi_classes[type]);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Name\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].display_name);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Path\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].path);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"IsReadOnly\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].is_readonly);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"DisplayInUI\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].display_in_ui);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"RequiresPhysicalPresence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].requires_physical_presence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Sequence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].sequence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"PrerequisiteSize\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].prerequisitesize);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Prerequisites\": [\n", buf);
>>> +
>>> +     if (bioscfg_drv.enumeration_data[instance].prerequisitesize) {
>>> +             part_tmp = kstrdup(bioscfg_drv.enumeration_data[instance].prerequisites,
>>> +                                GFP_KERNEL);
>>> +             part = strsep(&part_tmp, ";");
>>> +             while (part) {
>>> +                     buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part);
>>> +                     part = strsep(&part_tmp, ";");
>>> +                     if (part)
>>> +                             buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
>>> +                     else
>>> +                             buf_size = snprintf(buf, alloc_size, "%s\n", buf);
>>> +             }
>>> +             kfree(part_tmp);
>>> +             part_tmp = NULL;
>>> +     }
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"SecurityLevel\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].security_level);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Value\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].current_value);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Size\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.enumeration_data[instance].size);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\": [\n", buf);
>>> +
>>> +     if (bioscfg_drv.enumeration_data[instance].size) {
>>> +             part_tmp = kstrdup(bioscfg_drv.enumeration_data[instance].possible_values,
>>> +                                GFP_KERNEL);
>>> +             part = strsep(&part_tmp, ";");
>>> +             while (part) {
>>> +                     buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part);
>>> +                     part = strsep(&part_tmp, ";");
>>> +                     if (part)
>>> +                             buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
>>> +                     else
>>> +                             buf_size = snprintf(buf, alloc_size, "%s\n", buf);
>>> +             }
>>> +             kfree(part_tmp);
>>> +             part_tmp = NULL;
>>> +     }
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t]\n", buf);
>>> +
>>> +     return snprintf(buf, alloc_size, "%s},\n", buf);
>>> +}
>>> +
>>> +int append_read_ordered_list_attributes(char *buf, int alloc_size,
>>> +                                     int instance,
>>> +                                     enum hp_wmi_data_type type)
>>> +{
>>> +     int buf_size;
>>> +     char *part_tmp = NULL;
>>> +     char *part = NULL;
>>> +
>>> +     if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf)
>>> +             return -EINVAL;
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s{\n", buf);
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Class\": \"%s\",\n",
>>> +                         buf, hp_wmi_classes[type]);
>>> +
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Name\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].display_name);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Value\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].current_value);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Path\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].path);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"IsReadOnly\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].is_readonly);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"DisplayInUI\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].display_in_ui);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"RequiresPhysicalPresence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].requires_physical_presence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Sequence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].sequence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"PrerequisiteSize\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].prerequisitesize);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Prerequisites\": [\n", buf);
>>> +
>>> +     if (bioscfg_drv.ordered_list_data[instance].prerequisitesize) {
>>> +             part_tmp = kstrdup(bioscfg_drv.ordered_list_data[instance].prerequisites,
>>> +                                GFP_KERNEL);
>>> +             part = strsep(&part_tmp, ";");
>>> +             while (part) {
>>> +                     buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part);
>>> +                     part = strsep(&part_tmp, ";");
>>> +                     if (part)
>>> +                             buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
>>> +                     else
>>> +                             buf_size = snprintf(buf, alloc_size, "%s\n", buf);
>>> +             }
>>> +             kfree(part_tmp);
>>> +             part_tmp = NULL;
>>> +     }
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"SecurityLevel\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].security_level);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Size\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.ordered_list_data[instance].size);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n", buf);
>>> +
>>> +     if (bioscfg_drv.ordered_list_data[instance].size) {
>>> +             part_tmp = kstrdup(bioscfg_drv.ordered_list_data[instance].elements,
>>> +                                GFP_KERNEL);
>>> +             part = strsep(&part_tmp, ";");
>>> +             while (part) {
>>> +                     buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part);
>>> +                     part = strsep(&part_tmp, ";");
>>> +                     if (part)
>>> +                             buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
>>> +                     else
>>> +                             buf_size = snprintf(buf, alloc_size, "%s\n", buf);
>>> +             }
>>> +             kfree(part_tmp);
>>> +             part_tmp = NULL;
>>> +     }
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t]\n", buf);
>>> +
>>> +     return snprintf(buf, alloc_size, "%s},\n", buf);
>>> +}
>>> +
>>> +
>>> +int append_read_password_attributes(char *buf, int alloc_size,
>>> +                                 int instance,
>>> +                                 enum hp_wmi_data_type type)
>>> +{
>>> +     int buf_size;
>>> +     char *part_tmp = NULL;
>>> +     char *part = NULL;
>>> +
>>> +     if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf)
>>> +             return -EINVAL;
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s{\n", buf);
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Class\": \"%s\",\n",
>>> +                         buf, hp_wmi_classes[type]);
>>> +
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Name\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].display_name);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Value\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].current_password);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Path\": \"%s\",\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].path);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"IsReadOnly\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].is_readonly);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"DisplayInUI\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].display_in_ui);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"RequiresPhysicalPresence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].requires_physical_presence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Sequence\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].sequence);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"PrerequisiteSize\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].prerequisitesize);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"Prerequisites\": [\n", buf);
>>> +
>>> +     if (bioscfg_drv.password_data[instance].prerequisitesize) {
>>> +             part_tmp = kstrdup(bioscfg_drv.password_data[instance].prerequisites,
>>> +                                GFP_KERNEL);
>>> +             part = strsep(&part_tmp, ";");
>>> +             while (part) {
>>> +                     buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part);
>>> +                     part = strsep(&part_tmp, ";");
>>> +                     if (part)
>>> +                             buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
>>> +                     else
>>> +                             buf_size = snprintf(buf, alloc_size, "%s\n", buf);
>>> +             }
>>> +             kfree(part_tmp);
>>> +             part_tmp = NULL;
>>> +     }
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"SecurityLevel\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].security_level);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"MinLength\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].min_password_length);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"MaxLength\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].max_password_length);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"Size\": %d,\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].encoding_size);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t\"SupportedEncoding\": [\n", buf);
>>> +
>>> +     if (bioscfg_drv.password_data[instance].encoding_size) {
>>> +             part_tmp = kstrdup(bioscfg_drv.password_data[instance].supported_encoding,
>>> +                                GFP_KERNEL);
>>> +             part = strsep(&part_tmp, ";");
>>> +             while (part) {
>>> +                     buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part);
>>> +                     part = strsep(&part_tmp, ";");
>>> +                     if (part)
>>> +                             buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
>>> +                     else
>>> +                             buf_size = snprintf(buf, alloc_size, "%s\n", buf);
>>> +             }
>>> +             kfree(part_tmp);
>>> +             part_tmp = NULL;
>>> +     }
>>> +     buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>> +
>>> +     buf_size = snprintf(buf, alloc_size,
>>> +                         "%s\t\"IsSet\": %d\n",
>>> +                         buf,
>>> +                         bioscfg_drv.password_data[instance].is_enabled);
>>> +
>>> +     return snprintf(buf, alloc_size, "%s},\n", buf);
>>> +}
>>> diff --git a/drivers/platform/x86/hp/surestart-attributes.c b/drivers/platform/x86/hp/surestart-attributes.c
>>> new file mode 100644
>>> index 000000000000..41c5a549f2ca
>>> --- /dev/null
>>> +++ b/drivers/platform/x86/hp/surestart-attributes.c
>>> @@ -0,0 +1,145 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Functions corresponding to sure start object type attributes under
>>> + * BIOS for use with hp-bioscfg driver
>>> + *
>>> + *  Copyright (c) 2022 HP Development Company, L.P.
>>> + */
>>> +
>>> +#include "bioscfg.h"
>>> +#include <asm-generic/posix_types.h>
>>> +
>>> +#define LOG_MAX_ENTRIES      254
>>> +#define LOG_ENTRY_SIZE       16
>>> +
>>> +/*
>>> + * audit_log_entry_count_show - Reports the number of
>>> + *                           existing audit log entries available
>>> + *                           to be read
>>> + *
>>> + * @kobj:  Pointer to a kernel object of things that show up as directory
>>> + *      in the sysfs filesystem.
>>> + * @attr:  Pointer to list of attributes for the operation
>>> + * @buf:   Pointer to buffer
>>> + *
>>> + * Returns number of existing audit log entries available to be read,
>>> + *         audit log entry size, and maximum number of entries
>>> + *         supported. Otherwise, an HP WMI query specific error code
>>> + *         (which is negative)
>>> + *
>>> + *         [No of entries],[log entry size],[Max number of entries supported]
>>> + */
>>> +static ssize_t audit_log_entry_count_show(struct kobject *kobj,
>>> +                                       struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     int ret;
>>> +     u32 count = 0;
>>> +
>>> +     ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG_COUNT, HPWMI_SURESTART,
>>> +                                &count, 0, sizeof(count));
>>> +     if (ret < 0)
>>> +             return ret;
>>> +
>>> +     return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", count, LOG_ENTRY_SIZE, LOG_MAX_ENTRIES);
>>> +}
>>> +
>>> +/*
>>> + * audit_log_entries_show() - Return all entries found in log file
>>> + *
>>> + * @kobj:  Pointer to a kernel object of things that show up as
>>> + *      directory in the sysfs filesystem.
>>> + * @attr:  Pointer to list of attributes for the operation
>>> + * @buf:   Pointer to buffer
>>> + *
>>> + * Returns number of bytes needed to read all audit logs entries to be read.
>>> + *         Otherwise, an HP WMI query specific error code (which is negative)
>>> + *      -EFAULT if the audit logs size exceeds 4KB
>>> + *
>>> + */
>>> +static ssize_t audit_log_entries_show(struct kobject *kobj,
>>> +                                   struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     int ret;
>>> +     int i;
>>> +     u32 count = 0;
>>> +
>>> +     // Get the number of event logs
>>> +     ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG_COUNT, HPWMI_SURESTART,
>>> +                                &count, 1, 4);
>>> +
>>> +     /*
>>> +      * The show() api will not work if the audit logs ever go
>>> +      *  beyond 4KB
>>> +      */
>>> +     if (count * LOG_ENTRY_SIZE > PAGE_SIZE)
>>> +             return -EFAULT;
>>> +
>>> +     if (ret < 0)
>>> +             return ret;
>>> +
>>> +     /*
>>> +      * We are guaranteed the buffer is 4KB so today all the event
>>> +      * logs will fit
>>> +      */
>>> +     for (i = 0; ((i < count) & (ret >= 0)); i++) {
>>> +             *buf = (i + 1);
>>> +             ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG,
>>> +                                        HPWMI_SURESTART,
>>> +                                        buf, 1, 128);
>>> +             if (ret >= 0)
>>> +                     buf += LOG_ENTRY_SIZE;
>>> +     }
>>> +     return (count * LOG_ENTRY_SIZE);
>>> +}
>>> +
>>> +static struct kobj_attribute sure_start_audit_log_entry_count = __ATTR_RO(audit_log_entry_count);
>>> +struct kobj_attribute sure_start_audit_log_entries = __ATTR_RO(audit_log_entries);
>>> +
>>> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +                      char *buf)
>>> +{
>>> +     return sprintf(buf, "sure-start\n");
>>> +}
>>> +static struct kobj_attribute sure_start_type = __ATTR_RO(type);
>>> +
>>> +static ssize_t display_name_language_code_show(struct kobject *kobj,
>>> +                                            struct kobj_attribute *attr,
>>> +                                            char *buf)
>>> +{
>>> +     return sprintf(buf, "%s\n", LANG_CODE_STR);
>>> +}
>>> +
>>> +static struct kobj_attribute sure_start_display_langcode =
>>> +             __ATTR_RO(display_name_language_code);
>>> +
>>> +
>>> +static ssize_t display_name_show(struct kobject *kobj,
>>> +                              struct kobj_attribute *attr, char *buf)
>>> +{
>>> +     return sprintf(buf, "%s\n", SURE_START_DESC);
>>> +}
>>> +static struct kobj_attribute sure_start_display_name = __ATTR_RO(display_name);
>>> +
>>> +static struct attribute *sure_start_attrs[] = {
>>> +     &sure_start_display_name.attr,
>>> +     &sure_start_display_langcode.attr,
>>> +     &sure_start_audit_log_entry_count.attr,
>>> +     &sure_start_audit_log_entries.attr,
>>> +     &sure_start_type.attr,
>>> +     NULL,
>>> +};
>>> +
>>> +static const struct attribute_group sure_start_attr_group = {
>>> +     .attrs = sure_start_attrs,
>>> +};
>>> +
>>> +void exit_sure_start_attributes(void)
>>> +{
>>> +     sysfs_remove_group(bioscfg_drv.sure_start_attr_kobj, &sure_start_attr_group);
>>> +}
>>> +
>>> +int populate_sure_start_data(struct kobject *attr_name_kobj)
>>> +{
>>> +     bioscfg_drv.sure_start_attr_kobj = attr_name_kobj;
>>> +     return sysfs_create_group(attr_name_kobj, &sure_start_attr_group);
>>> +}
>>


  reply	other threads:[~2022-10-10 21:31 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-10 16:23 [PATCH v1 0/1] Introduction of HP-BIOSCFG driver Jorge Lopez
2022-10-10 16:23 ` [PATCH v1 1/1] " Jorge Lopez
2022-10-10 16:57   ` Limonciello, Mario
2022-10-10 21:26     ` Jorge Lopez
2022-10-10 21:31       ` Limonciello, Mario [this message]
2022-10-11 14:53         ` Jorge Lopez
2022-10-17 13:18         ` Jorge Lopez
2022-10-17 14:11           ` Jorge Lopez
2022-10-17 14:29             ` Limonciello, Mario
2022-10-17 14:36               ` Hans de Goede
2022-10-17 15:20                 ` Jorge Lopez
2022-10-17 15:37                   ` Hans de Goede
2022-10-17 16:03                     ` Limonciello, Mario

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d88e15ba-9e3f-310d-118b-7ccb2fbe1ca9@amd.com \
    --to=mario.limonciello@amd.com \
    --cc=hdegoede@redhat.com \
    --cc=jorgealtxwork@gmail.com \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox