Re: [PATCH v1 1/1] Introduction of HP-BIOSCFG driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



''Hi Mario,

Please see comments to previous source comments.

On Mon, Oct 17, 2022 at 8:18 AM Jorge Lopez <jorgealtxwork@xxxxxxxxx> wrote:
>
> Hi Mario,
>
> On Mon, Oct 10, 2022 at 4:31 PM Limonciello, Mario
> <mario.limonciello@xxxxxxx> wrote:
> >
> > On 10/10/2022 16:26, Jorge Lopez wrote:
> > > Hi Mario,
> > >
> > > On Mon, Oct 10, 2022 at 11:57 AM Limonciello, Mario
> > > <mario.limonciello@xxxxxxx> 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.
>
> Submitted the recommended changes for review in v2
>
> >
> > >>
> > >> 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.
> >
>
> There is not a reliable mechanism to programmatically determine which
> BIOS settings require a reboot to be updated.  The v2 changes
> leverages “RequiredPhysicalPresence” reported value to set
> pending_reboot.
>
> > >
> > >> 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.
>
> Submitted a patch to improve the friendly display name for
> few numbers of attributes associated with ‘Schedule Power-ON.’  BIOS
> assign names such ‘Tuesday’ to an attribute. The name is correct, but
> it is not descriptive enough for the user.  Under those
> conditions a portion of the path data value is appended to the attribute
> name to create a user-friendly display name.
>
> For instance, the attribute name is ‘Tuesday,’ and the display name
> value is ‘Schedule Power-ON – Tuesday’
>
>
> >
> > >
> > >> 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@xxxxxx>
> > >>>
> > >>> ---
> > >>> 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.

The requested information will be added in v3

> > >>
> > >>> +
> > >>> +             "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@xxxxxx>
> > >>> +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@xxxxxx>
> > >>> +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@xxxxxx>
> > >>> +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@xxxxxx>
> > >>> +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@xxxxxx>
> > >>> +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@xxxxxx>
> > >>> +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@xxxxxx>
> > >>> +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.

The other drivers named HP-WMI and HP_ACCEL  were written by third
party members and not by HP.   It is for this reason and because of
the number of files, only hp-bioscfg was placed in a separate
directory.   Let me know If my reasoning is not valid enough  and I
will keep the files in a separate directory and move the selection to
the main list.    In addition, Moving  HP-WMI and HP_ACCEL drivers
from x86 directories fall outside of the scope of these changes,
Correct?

> > >>
> > >>> +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:

The build process was tested with the latest  drivers/platform/x86
from branch for-next.
Nonetheless, I will investigate.

> > >>
> > >> --- 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@xxxxxx>");
> > >>> +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?

P21 stands for "Project 21" and part of Hardware Enforced Persistency
security feature.
Project 21 will be more confusing while P21 is a common term used in
HP security products.

> > >>
> > >>> +     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?

Displaying the meaning of HEP will make the message less friendly.
HEP stands for 'Hardware Enforced Persistency".

> > >>
> > >>> +     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);
> > >>> +}
> > >>
> >




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux