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