All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/6] HP WMI Security Features
@ 2022-04-04 20:36 Jorge Lopez
  2022-04-04 20:36 ` [PATCH v1 1/6] Correct code style related issues in hp-wmi Jorge Lopez
                   ` (5 more replies)
  0 siblings, 6 replies; 25+ messages in thread
From: Jorge Lopez @ 2022-04-04 20:36 UTC (permalink / raw)
  To: platform-driver-x86

These set of patches include new driver support of HP Security Features,
documentation, and other minor changes.

These changes include  documentation for three new security features
introduced in the hp-wmi driver. The security features include
Secure Platform, Management, Sure Admin, and Sure Start.
Each documentation section provides security feature description,
identifies sysfs directories, and files exposed by the driver.

Sure Admin allows the user to configure the system to use a Sure Admin
cryptographic signature-based authorization string that the BIOS will
use to verify authorization to modify the setting.
    
Sure Start provides advanced firmware protection and resiliency by
identifying and repairing unauthorized BIOS changes.  

Secure Platform Management (SPM)  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.

Lastly, changes were introduced in preparation to submission of three
security features.  The addition of hp_wmi_groups will simplify the
integration of driver security features.
    

Jorge Lopez (6):
  Correct code style related issues in hp-wmi
  Update hp_wmi_group to simplify feature addition
  Secure Platform Management Security Feature
  Sure Start Security Feature
  Sure Admin Security Feature
  HP Security Features Documentation

 .../ABI/testing/sysfs-platform-hp-wmi         |   96 ++
 Documentation/admin-guide/hp_wmi.rst          |  141 ++
 Documentation/admin-guide/index.rst           |    1 +
 drivers/platform/x86/hp-wmi.c                 | 1298 ++++++++++++++++-
 4 files changed, 1535 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/sysfs-platform-hp-wmi
 create mode 100644 Documentation/admin-guide/hp_wmi.rst

-- 
2.25.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v1 1/6] Correct code style related issues in hp-wmi
  2022-04-04 20:36 [PATCH v1 0/6] HP WMI Security Features Jorge Lopez
@ 2022-04-04 20:36 ` Jorge Lopez
  2022-04-11 12:47   ` Hans de Goede
  2022-04-04 20:36 ` [PATCH v1 2/6] Update hp_wmi_group to simplify feature addition Jorge Lopez
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 25+ messages in thread
From: Jorge Lopez @ 2022-04-04 20:36 UTC (permalink / raw)
  To: platform-driver-x86

Update hp-wmi driver to address all code style issues reported
by checkpatch.pl script.

All changes were validated on a HP ZBook Workstation,
HP EliteBook x360, and HP EliteBook 850 G8 notebooks.

Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>

---
Based on the latest platform-drivers-x86.git/for-next

v1-0001-Update-hp_wmi_group-to-simplify-feature-addition patch was
broken in two separate patches.  This patch is patch 1 of 2
---
 drivers/platform/x86/hp-wmi.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 0e9a25b56e0e..667f94bba905 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -605,6 +605,7 @@ static int hp_wmi_rfkill2_refresh(void)
 	for (i = 0; i < rfkill2_count; i++) {
 		int num = rfkill2[i].num;
 		struct bios_rfkill2_device_state *devstate;
+
 		devstate = &state.device[num];
 
 		if (num >= state.count ||
@@ -625,6 +626,7 @@ static ssize_t display_show(struct device *dev, struct device_attribute *attr,
 			    char *buf)
 {
 	int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY);
+
 	if (value < 0)
 		return value;
 	return sprintf(buf, "%d\n", value);
@@ -634,6 +636,7 @@ static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr,
 			    char *buf)
 {
 	int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY);
+
 	if (value < 0)
 		return value;
 	return sprintf(buf, "%d\n", value);
@@ -643,6 +646,7 @@ static ssize_t als_show(struct device *dev, struct device_attribute *attr,
 			char *buf)
 {
 	int value = hp_wmi_read_int(HPWMI_ALS_QUERY);
+
 	if (value < 0)
 		return value;
 	return sprintf(buf, "%d\n", value);
@@ -652,6 +656,7 @@ static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
 			 char *buf)
 {
 	int value = hp_wmi_get_dock_state();
+
 	if (value < 0)
 		return value;
 	return sprintf(buf, "%d\n", value);
@@ -661,6 +666,7 @@ static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
 	int value = hp_wmi_get_tablet_mode();
+
 	if (value < 0)
 		return value;
 	return sprintf(buf, "%d\n", value);
@@ -671,6 +677,7 @@ static ssize_t postcode_show(struct device *dev, struct device_attribute *attr,
 {
 	/* Get the POST error code of previous boot failure. */
 	int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY);
+
 	if (value < 0)
 		return value;
 	return sprintf(buf, "0x%x\n", value);
@@ -1013,6 +1020,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
 		struct rfkill *rfkill;
 		enum rfkill_type type;
 		char *name;
+
 		switch (state.device[i].radio_type) {
 		case HPWMI_WIFI:
 			type = RFKILL_TYPE_WLAN;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v1 2/6] Update hp_wmi_group to simplify feature addition
  2022-04-04 20:36 [PATCH v1 0/6] HP WMI Security Features Jorge Lopez
  2022-04-04 20:36 ` [PATCH v1 1/6] Correct code style related issues in hp-wmi Jorge Lopez
@ 2022-04-04 20:36 ` Jorge Lopez
  2022-04-04 20:36 ` [PATCH v1 3/6] Secure Platform Management Security Feature Jorge Lopez
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 25+ messages in thread
From: Jorge Lopez @ 2022-04-04 20:36 UTC (permalink / raw)
  To: platform-driver-x86

Introduction of hp_wmi_groups to simplify the integration of driver
security features with sysfs.

All changes were validated on a HP ZBook Workstation,
HP EliteBook x360, and HP EliteBook 850 G8 notebooks.

Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>

---
Based on the latest platform-drivers-x86.git/for-next

v1-0001-Update-hp_wmi_group-to-simplify-feature-addition patch was
broken in two separate patches.  This patch is patch 2 of 2
---
 drivers/platform/x86/hp-wmi.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 667f94bba905..0c7d863b8aab 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -740,7 +740,15 @@ static struct attribute *hp_wmi_attrs[] = {
 	&dev_attr_postcode.attr,
 	NULL,
 };
-ATTRIBUTE_GROUPS(hp_wmi);
+
+static const struct attribute_group hp_wmi_group = {
+	.attrs = hp_wmi_attrs,
+};
+
+static const struct attribute_group *hp_wmi_groups[] = {
+	&hp_wmi_group,
+	NULL,
+};
 
 static void hp_wmi_notify(u32 value, void *context)
 {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v1 3/6] Secure Platform Management Security Feature
  2022-04-04 20:36 [PATCH v1 0/6] HP WMI Security Features Jorge Lopez
  2022-04-04 20:36 ` [PATCH v1 1/6] Correct code style related issues in hp-wmi Jorge Lopez
  2022-04-04 20:36 ` [PATCH v1 2/6] Update hp_wmi_group to simplify feature addition Jorge Lopez
@ 2022-04-04 20:36 ` Jorge Lopez
  2022-04-04 20:36 ` [PATCH v1 4/6] Sure Start " Jorge Lopez
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 25+ messages in thread
From: Jorge Lopez @ 2022-04-04 20:36 UTC (permalink / raw)
  To: platform-driver-x86

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.

The private key is used by system management utilities to sign
payloads containing configuration changes.  The BIOS on a target
system uses the associated public key to verify the integrity of the
payload and apply the changes.

At the end of the PC’s lifecycle a signed deprovisioning command
restores the factory default state.

KEK Certificate (KEK) and Signing Key (SK) get provisioned, and status
can be read either as text from the status file or binary from
statusbin.

	/sys/devices/platform/hp-wmi/spm/kek
	/sys/devices/platform/hp-wmi/spm/sk
	/sys/devices/platform/hp-wmi/spm/status
	/sys/devices/platform/hp-wmi/spm/statusbin

'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.

'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.

This feature requires "Update hp_wmi_group to simplify feature
addition" patch.

All changes were validated on a HP ZBook Workstation, HP EliteBook
x360, and HP EliteBook 850 G8 notebooks.

Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>

---
Based on the latest platform-drivers-x86.git/for-next
---
 drivers/platform/x86/hp-wmi.c | 195 ++++++++++++++++++++++++++++++++++
 1 file changed, 195 insertions(+)

diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 0c7d863b8aab..139dc079c1fa 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -120,6 +120,12 @@ enum hp_wmi_commandtype {
 	HPWMI_THERMAL_PROFILE_QUERY	= 0x4c,
 };
 
+enum hp_wmi_spm_commandtype {
+	HPWMI_SECUREPLATFORM_GET_STATE = 0x10,
+	HPWMI_SECUREPLATFORM_SET_KEK	= 0x11,
+	HPWMI_SECUREPLATFORM_SET_SK	= 0x12,
+};
+
 enum hp_wmi_gm_commandtype {
 	HPWMI_FAN_SPEED_GET_QUERY = 0x11,
 	HPWMI_SET_PERFORMANCE_MODE = 0x1A,
@@ -133,6 +139,7 @@ enum hp_wmi_command {
 	HPWMI_WRITE	= 0x02,
 	HPWMI_ODM	= 0x03,
 	HPWMI_GM	= 0x20008,
+	HPWMI_SECUREPLATFORM = 0x20010,
 };
 
 enum hp_wmi_hardware_mask {
@@ -193,6 +200,20 @@ struct bios_rfkill2_device_state {
 	u8 unknown[4];
 };
 
+#pragma pack(1)
+struct secureplatform_provisioning_data {
+	u8 state;
+	u8 version[2];
+	u8 reserved1;
+	u32 features;
+	u32 nonce;
+	u8 reserved2[28];
+	u8 sk_mod[256];
+	u8 kek_mod[256];
+};
+
+#pragma pack()
+
 /* 7 devices fit into the 128 byte buffer */
 #define HPWMI_MAX_RFKILL2_DEVICES	7
 
@@ -724,6 +745,179 @@ static ssize_t postcode_store(struct device *dev, struct device_attribute *attr,
 	return count;
 }
 
+/* Secure Platform Management (SPM) */
+
+/*
+ * spm_statusbin_show - 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
+ *
+ */
+static ssize_t spm_statusbin_show(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);
+}
+
+/*
+ * spm_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
+ *
+ */
+static ssize_t spm_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)
+		return -ENOMEM;
+
+	ret = spm_statusbin_show(kobj, attr, (char *)data);
+	if (ret < 0) {
+		kfree(data);
+		return ret;
+	}
+
+	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 secureplatform 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);
+}
+
+/*
+ * spm_kek_store:
+ *
+ * Function 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.
+ *
+ * @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
+ * @count: buffer size in bytes
+ *
+ * Returns number of bytes written on success.  Otherwise
+ *         an HP WMI query specific error code (which is positive)
+ *         -EINVAL if the query was not successful at all
+ *
+ */
+static ssize_t spm_kek_store(struct kobject *kobj,
+			     struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
+				       HPWMI_SECUREPLATFORM, (void *)buf, count, 0);
+	return ret ? -EINVAL : count;
+}
+
+/*
+ * spm_sk_store:
+ *
+ * Function 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.
+ *
+ * @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
+ * @count: buffer size in bytes
+ *
+ * Returns number of bytes written on success.  Otherwise
+ *         an HP WMI query specific error code (which is positive)
+ *         -EINVAL if the query was not successful at all
+ *
+ */
+static ssize_t spm_sk_store(struct kobject *kobj,
+			     struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_SK,
+				       HPWMI_SECUREPLATFORM, (void *)buf, count, 0);
+	return ret ? -EINVAL : count;
+}
+
+
+#define HPWMI_ATTR_RO(_group, _name)	\
+static struct kobj_attribute _group##_##_name =	\
+__ATTR(_name, 0444, _group##_##_name##_show, NULL)
+
+#define HPWMI_BINATTR_RO(_group, _name, _size)	\
+static struct bin_attribute _group##_##_name =	\
+__BIN_ATTR(_name, 0444, _group##_##_name##_read, NULL, _size)
+
+#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)
+
+#define HPWMI_ATTR_WO(_group, _name, _command)	\
+static struct kobj_attribute _group##_##_name =	\
+__ATTR(_name, 0400 | 0200, NULL, _group##_##_name##_store)
+
+HPWMI_ATTR_RO(spm, status);
+HPWMI_ATTR_RO(spm, statusbin);
+HPWMI_ATTR_WO(spm, kek, HPWMI_SECUREPLATFORM_SET_KEK);
+HPWMI_ATTR_WO(spm, sk, HPWMI_SECUREPLATFORM_SET_SK);
+
+static struct attribute *spm_attrs[] = {
+	&spm_status.attr,
+	&spm_statusbin.attr,
+	&spm_kek.attr,
+	&spm_sk.attr,
+	NULL,
+};
+
+struct kobject *spm_kobj;
+
+static const struct attribute_group spm_group = {
+	.name = "spm",
+	.attrs = spm_attrs,
+};
+
 static DEVICE_ATTR_RO(display);
 static DEVICE_ATTR_RO(hddtemp);
 static DEVICE_ATTR_RW(als);
@@ -747,6 +941,7 @@ static const struct attribute_group hp_wmi_group = {
 
 static const struct attribute_group *hp_wmi_groups[] = {
 	&hp_wmi_group,
+	&spm_group,
 	NULL,
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v1 4/6] Sure Start Security Feature
  2022-04-04 20:36 [PATCH v1 0/6] HP WMI Security Features Jorge Lopez
                   ` (2 preceding siblings ...)
  2022-04-04 20:36 ` [PATCH v1 3/6] Secure Platform Management Security Feature Jorge Lopez
@ 2022-04-04 20:36 ` Jorge Lopez
  2022-04-04 22:05   ` Limonciello, Mario
  2022-04-04 20:36 ` [PATCH v1 5/6] Sure Admin " Jorge Lopez
  2022-04-04 20:36 ` [PATCH v1 6/6] HP Security Features Documentation Jorge Lopez
  5 siblings, 1 reply; 25+ messages in thread
From: Jorge Lopez @ 2022-04-04 20:36 UTC (permalink / raw)
  To: platform-driver-x86

Sure Start provides advanced firmware protection and resiliency by
identifying and repairing unauthorized BIOS changes.  It maintains an
audit log of these events and other important system configuration
changes.  The following sysfs entries can be used to read the contents
of the audit log.

      /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count
      /sys/devices/platform/hp-wmi/sure_start/audit_log_entries

'audit_log_entry_count' is a read-only file that returns the number of
existing audit log events available to be read

'audit_log_entries' is a read-only file that returns the events in the
log

This feature requires "Update hp_wmi_group to simplify feature
addition" patch.

All changes were validated on a HP ZBook Workstation,
HP EliteBook x360, and HP EliteBook 850 G8 notebooks.

Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>

---
Based on the latest platform-drivers-x86.git/for-next
---
 drivers/platform/x86/hp-wmi.c | 108 ++++++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)

diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 139dc079c1fa..918e3eaf1b67 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -126,6 +126,11 @@ enum hp_wmi_spm_commandtype {
 	HPWMI_SECUREPLATFORM_SET_SK	= 0x12,
 };
 
+enum hp_wmi_surestart_commandtype {
+	HPWMI_SURESTART_GET_LOG_COUNT	= 0x01,
+	HPWMI_SURESTART_GET_LOG	= 0x02,
+};
+
 enum hp_wmi_gm_commandtype {
 	HPWMI_FAN_SPEED_GET_QUERY = 0x11,
 	HPWMI_SET_PERFORMANCE_MODE = 0x1A,
@@ -138,6 +143,7 @@ enum hp_wmi_command {
 	HPWMI_READ	= 0x01,
 	HPWMI_WRITE	= 0x02,
 	HPWMI_ODM	= 0x03,
+	HPWMI_SURESTART = 0x20006,
 	HPWMI_GM	= 0x20008,
 	HPWMI_SECUREPLATFORM = 0x20010,
 };
@@ -851,6 +857,7 @@ static ssize_t spm_kek_store(struct kobject *kobj,
 {
 	int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
 				       HPWMI_SECUREPLATFORM, (void *)buf, count, 0);
+
 	return ret ? -EINVAL : count;
 }
 
@@ -918,6 +925,106 @@ static const struct attribute_group spm_group = {
 	.attrs = spm_attrs,
 };
 
+/* Sure Start functions */
+
+#define LOG_MAX_ENTRIES	254
+#define LOG_ENTRY_SIZE	16
+
+/*
+ * sure_start_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 sure_start_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);
+}
+
+/*
+ * sure_start_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 sure_start_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);
+}
+
+HPWMI_ATTR_RO(sure_start, audit_log_entry_count);
+HPWMI_ATTR_RO(sure_start, audit_log_entries);
+
+static struct attribute *sure_start_attrs[] = {
+	&sure_start_audit_log_entry_count.attr,
+	&sure_start_audit_log_entries.attr,
+	NULL,
+};
+
+static const struct attribute_group sure_start_group = {
+	.name = "sure_start",
+	.attrs = sure_start_attrs,
+};
+
 static DEVICE_ATTR_RO(display);
 static DEVICE_ATTR_RO(hddtemp);
 static DEVICE_ATTR_RW(als);
@@ -942,6 +1049,7 @@ static const struct attribute_group hp_wmi_group = {
 static const struct attribute_group *hp_wmi_groups[] = {
 	&hp_wmi_group,
 	&spm_group,
+	&sure_start_group,
 	NULL,
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-04 20:36 [PATCH v1 0/6] HP WMI Security Features Jorge Lopez
                   ` (3 preceding siblings ...)
  2022-04-04 20:36 ` [PATCH v1 4/6] Sure Start " Jorge Lopez
@ 2022-04-04 20:36 ` Jorge Lopez
  2022-04-04 21:59   ` Limonciello, Mario
  2022-04-04 20:36 ` [PATCH v1 6/6] HP Security Features Documentation Jorge Lopez
  5 siblings, 1 reply; 25+ messages in thread
From: Jorge Lopez @ 2022-04-04 20:36 UTC (permalink / raw)
  To: platform-driver-x86

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. Behind the scenes, Sure Admin uses Secure Platform
Management (SPM) and WMI

'settings' is a file associated with Sure Admin. BIOS settings can be
read or written through the Sure Admin settings file in sysfs

	/sys/devices/platform/hp-wmi/sure_admin/settings

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"
		]
	}

This feature requires "Update hp_wmi_group to simplify feature
addition" patch.

All changes were validated on a HP ZBook Workstation,
HP EliteBook x360, and HP EliteBook 850 G8 notebooks.

Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>

---
Based on the latest platform-drivers-x86.git/for-next
---
 drivers/platform/x86/hp-wmi.c | 977 ++++++++++++++++++++++++++++++++++
 1 file changed, 977 insertions(+)

diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 918e3eaf1b67..b72ca18b77a6 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -27,6 +27,7 @@
 #include <linux/rfkill.h>
 #include <linux/string.h>
 #include <linux/dmi.h>
+#include <linux/nls.h>
 
 MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
 MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
@@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
 
 #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
 #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
+
 #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
 
+#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-6A1B8106F83C"
+#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-E293ADB9BF05"
+#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-4A3C09E75133"
+#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-7045CB4DA745"
+#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-015176049E2D"
+#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-C7CB9B4B8D5E"
+
 /* DMI board names of devices that should use the omen specific path for
  * thermal profiles.
  * This was obtained by taking a look in the windows omen command center
@@ -1025,6 +1034,973 @@ static const struct attribute_group sure_start_group = {
 	.attrs = sure_start_attrs,
 };
 
+
+static 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;
+	int  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));
+		ret = kstrtoint(tmp, 16, &ch);
+		if (ret) {
+			new_len = 0;
+			break;
+		}
+
+		if (ch == '\\')
+			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;
+	}
+
+	if (ret)
+		kfree(new_str);
+	return ret;
+}
+
+/*
+ * hp_wmi_get_setting_object() - Get an ACPI object by GUID and instance
+ *
+ * @guid:	GUID associated with the ACPI list of managed objects
+ * @instance:	Instance index to query on the ACPI list
+ * @obj:	The output ACPI object of type ACPI_TYPE_PACKAGE
+ *		or ACPI_TYPE_BUFFER (freed by the callee)
+ *
+ * Returns	zero on success.  Otherwise,an error inherited from
+ *		wmi_query_block(). It returns a obj by parameter if
+ *		the query returned object of type buffer or package,
+ *		otherwise, a null obj is returned.
+ *
+ * Note: obj should be freed by the callee once it is finished working with it
+ */
+static int hp_wmi_get_setting_object(char *guid, int instance,
+				union acpi_object **obj)
+{
+	struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL };
+	union acpi_object *tmp = NULL;
+	int ret;
+
+	ret = wmi_query_block(guid, instance, &output);
+	if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
+		tmp = output.pointer;
+		if (tmp->type == ACPI_TYPE_BUFFER || tmp->type == ACPI_TYPE_PACKAGE)
+			*obj = output.pointer;
+		else {
+			kfree(tmp);
+			*obj = NULL;
+		}
+	}
+
+	return ret;
+}
+
+
+static 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;
+
+	if (size == 0)
+		goto cleanup_exit;
+
+	for (i = 0; i < size; i++)
+		if (ptr[i] == '\\')
+			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);
+
+	if (escape == 0) {
+		ptr += (ptrlen / 2);
+		goto cleanup_exit;
+	}
+	/*
+	 * Convert escape characters only when found
+	 */
+	for (i = 0; i < size; i++) {
+		if (*ptr == '\\')
+			output[i++] = '\\';
+		output[i] = *ptr;
+		ptr++;
+	}
+
+cleanup_exit:
+	*buffer = ptr;
+	return 0;
+}
+
+static int get_integer_from_buffer(int **buffer, int *integer)
+{
+	int *ptr = PTR_ALIGN(*buffer, 4);
+	*integer = *(ptr++);
+	*buffer = ptr;
+	return 0;
+}
+
+
+// Sure Admin functions
+enum hp_wmi_data_type {
+	HPWMI_STRING_TYPE,
+	HPWMI_INTEGER_TYPE,
+	HPWMI_ENUMERATION_TYPE,
+	HPWMI_ORDEREDLIST_TYPE,
+	HPWMI_PASSWORD_TYPE,
+};
+
+#define HP_WMI_COMMON_ELEMENTS	\
+	"Name",	\
+	"Value",	\
+	"Path",	\
+	"IsReadOnly",	\
+	"DisplayInUI",	\
+	"RequiresPhysicalPresence",	\
+	"Sequence",	\
+	"PrerequisiteSize",	\
+	"SecurityLevel"
+
+const char *hp_wmi_string_elements[] = {
+	HP_WMI_COMMON_ELEMENTS,
+	"MinLength",
+	"MaxLength"
+};
+
+const char *hp_wmi_integer_elements[] = {
+	HP_WMI_COMMON_ELEMENTS,
+	"LowerBound",
+	"UpperBound",
+	"IntValue"
+};
+
+const char *hp_wmi_enumeration_elements[] = {
+	HP_WMI_COMMON_ELEMENTS,
+	"CurrentValue",
+	"Size"
+};
+
+const char *hp_wmi_orderedlist_elements[] = {
+	HP_WMI_COMMON_ELEMENTS,
+	"Size"
+};
+
+const char *hp_wmi_password_elements[] = {
+	HP_WMI_COMMON_ELEMENTS,
+	"MinLength",
+	"MaxLength",
+	"Size",
+	"SupportedEncoding",
+	"IsSet"
+};
+
+const char **hp_wmi_elements[] = {
+	hp_wmi_string_elements,
+	hp_wmi_integer_elements,
+	hp_wmi_enumeration_elements,
+	hp_wmi_orderedlist_elements,
+	hp_wmi_password_elements
+};
+
+const int hp_wmi_elements_count[] = {
+	ARRAY_SIZE(hp_wmi_string_elements),
+	ARRAY_SIZE(hp_wmi_integer_elements),
+	ARRAY_SIZE(hp_wmi_enumeration_elements),
+	ARRAY_SIZE(hp_wmi_orderedlist_elements),
+	ARRAY_SIZE(hp_wmi_password_elements)
+};
+
+const char *hp_wmi_classes[] = {
+	"HPBIOS_BIOSString",
+	"HPBIOS_BIOSInteger",
+	"HPBIOS_BIOSEnumeration",
+	"HPBIOS_BIOSOrderedList",
+	"HPBIOS_BIOSPassword"
+};
+
+static DEFINE_MUTEX(buf_mutex);
+static int settings_buffer_size;
+static int buf_alloc_size;
+static char *hp_bios_settings_buffer;
+
+
+static int append_package_elements_to_buffer(union acpi_object *obj,
+					     char *buf, int alloc_size, enum hp_wmi_data_type type)
+{
+	int i;
+	union acpi_object *pobj = NULL;
+	char *value = NULL;
+	int value_len;
+	char *tmpstr = NULL;
+	char *part_tmp = NULL;
+	int tmp_len = 0;
+	char *part = NULL;
+	int status = 0;
+	int size = 0;
+	int buf_size;
+
+	if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
+		return -EINVAL;
+
+	if (obj->type != ACPI_TYPE_PACKAGE)
+		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]);
+
+	for (i = 0; i < 3; i++) {
+		pobj = &(obj->package.elements[i]);
+		if (pobj->type == ACPI_TYPE_STRING) {
+			status = convert_hexstr_to_str(&pobj->string.pointer,
+						       pobj->string.length, &value, &value_len);
+			if (ACPI_FAILURE(status))
+				continue;
+			/*
+			 * Skip 'Value' (HP_WMI_COMMON_ELEMENTS) since
+			 * 'CurrentValue' is reported.
+			 */
+			if (type != HPWMI_ENUMERATION_TYPE || i != 1)
+				buf_size = snprintf(buf, alloc_size,
+						    "%s\t\"%s\": \"%s\",\n",
+						    buf,
+						    hp_wmi_elements[type][i], value);
+
+		}
+		kfree(value);
+		value = NULL;
+	}
+
+	for (i = 3; i < hp_wmi_elements_count[type]; i++) {
+		pobj = &(obj->package.elements[i]);
+
+		if (type == HPWMI_ENUMERATION_TYPE &&
+		    i == 9 &&
+		    pobj->type == ACPI_TYPE_STRING) {
+			/*
+			 * Report "CurrentValue" as "Value"
+			 */
+			status = convert_hexstr_to_str(&pobj->string.pointer,
+						       pobj->string.length,
+						       &value, &value_len);
+			if (ACPI_FAILURE(status))
+				continue;
+
+			buf_size = snprintf(buf, alloc_size,
+					    "%s\t\"Value\": \"%s\",\n",
+					    buf, value);
+			kfree(value);
+			value = NULL;
+
+		} else if (type == HPWMI_PASSWORD_TYPE &&
+			   i == 12 &&
+			   pobj->type == ACPI_TYPE_STRING) {
+			/*
+			 * Report list of "SupportEncoding"
+			 *
+			 *	"SupportedEncoding": [
+			 *		"utf-16"
+			 *	],
+			 *
+			 */
+
+			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
+					    buf, hp_wmi_elements[type][i]);
+			while (size--) {
+				pobj = &(obj->package.elements[i]);
+				status = convert_hexstr_to_str(&pobj->string.pointer,
+							       pobj->string.length,
+							       &value, &value_len);
+				if (ACPI_FAILURE(status))
+					continue;
+
+				if (size) {
+					buf_size = snprintf(buf, alloc_size,
+							    "%s\t\t\"%s\",\n", buf, value);
+					i++;
+				} else
+					buf_size = snprintf(buf, alloc_size,
+							    "%s\t\t\"%s\"\n", buf, value);
+
+				kfree(value);
+				value = NULL;
+
+			}
+			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
+			continue;
+
+		} else if (pobj->type == ACPI_TYPE_INTEGER) {
+			/*
+			 * Report "PrerequisiteSize" and "Size" values
+			 *	...
+			 *	"PrerequisiteSize": 1,
+			 *	...
+			 *	"Size": 2,
+			 *	...
+			 */
+			if (i == 7)
+				size = pobj->integer.value;
+			else if (type == HPWMI_ORDEREDLIST_TYPE && i == 9)
+				size = pobj->integer.value;
+			else if (type == HPWMI_ENUMERATION_TYPE && i == 10)
+				size = pobj->integer.value;
+			else if (type == HPWMI_PASSWORD_TYPE && i == 11)
+				size = pobj->integer.value;
+
+			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": %lld,\n", buf,
+					    hp_wmi_elements[type][i], pobj->integer.value);
+		}
+	}
+
+	if (type == HPWMI_ENUMERATION_TYPE) {
+		buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\": [\n", buf);
+		for (i = 0; i < size; i++) {
+			pobj = &(obj->package.elements[i + hp_wmi_elements_count[type]]);
+
+			status = convert_hexstr_to_str(&pobj->string.pointer,
+						       pobj->string.length,
+						       &value, &value_len);
+			if (ACPI_FAILURE(status))
+				break;
+
+			/*
+			 * Report list of "PossibleValues" of size
+			 * "Size"
+			 *	...
+			 *	"Size": 2,
+			 *	"PossibleValues": [
+			 *			"Disable",
+			 *			"Enable"]
+			 */
+			if (i == (size - 1))
+				buf_size = snprintf(buf, alloc_size,
+						    "%s\t\t\"%s\"\n", buf, value);
+			else
+				buf_size = snprintf(buf, alloc_size,
+						    "%s\t\t\"%s\",\n", buf, value);
+			kfree(value);
+			value = NULL;
+		}
+		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
+	}
+
+	if (type == HPWMI_ORDEREDLIST_TYPE) {
+		buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n", buf);
+		if (size <= 0)
+			goto finish_ordered_list;
+
+		pobj = &(obj->package.elements[hp_wmi_elements_count[type]]);
+		status = convert_hexstr_to_str(&pobj->string.pointer,
+					       pobj->string.length, &value, &value_len);
+		if (ACPI_FAILURE(status))
+			goto finish_ordered_list;
+
+		/*
+		 * 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(&value, value_len, &tmpstr, &tmp_len);
+		if (ACPI_FAILURE(status))
+			goto finish_ordered_list;
+
+		part_tmp = tmpstr;
+		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);
+		}
+	}
+
+finish_ordered_list:
+	if (type == HPWMI_ORDEREDLIST_TYPE)
+		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
+
+	/*
+	 * remove trailing comma
+	 */
+	if (buf_size > 3)
+		buf[buf_size - 2] = ' ';
+
+	kfree(tmpstr);
+	kfree(value);
+	return snprintf(buf, alloc_size, "%s},\n", buf);
+}
+
+static int append_buffer_elements_to_buffer(union acpi_object *obj,
+					    char *buf, int alloc_size, enum hp_wmi_data_type type)
+{
+	int buf_size;
+	int status;
+	char *str = NULL;
+	int i;
+	int j;
+	int integer;
+	int size = 0;
+
+	if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
+		return -EINVAL;
+
+	if (obj->type != ACPI_TYPE_BUFFER)
+		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]);
+
+	for (i = 0; i < 3; i++) {
+		status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str);
+		if (ACPI_SUCCESS(status)) {
+			/*
+			 * Skip 'Value' (HP_WMI_COMMON_ELEMENTS) since
+			 * 'CurrentValue' is reported.
+			 */
+			if (type != HPWMI_ENUMERATION_TYPE || i != 1)
+				buf_size = snprintf(buf, alloc_size,
+						    "%s\t\"%s\": \"%s\",\n",
+						    buf,
+						    hp_wmi_elements[type][i], str);
+		}
+		kfree(str);
+		str = NULL;
+
+	}
+
+	for (i = 3; i < hp_wmi_elements_count[type]; i++) {
+		if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
+			status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str);
+			if (ACPI_SUCCESS(status)) {
+				/*
+				 * Report "CurrentValue" as "Value"
+				 */
+				buf_size = snprintf(buf, alloc_size,
+						    "%s\t\"Value\": \"%s\",\n", buf, str);
+			}
+			kfree(str);
+			str = NULL;
+			continue;
+
+		} else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
+			/*
+			 * Report list of "SupportEncoding"
+			 *
+			 *	"SupportedEncoding": [
+			 *		"utf-16"
+			 *	],
+			 *
+			 */
+
+			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
+					    buf, hp_wmi_elements[type][i]);
+			for (j = 0; j < size; j++) {
+				status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str);
+				if (ACPI_SUCCESS(status)) {
+					if (j == size - 1)
+						buf_size = snprintf(buf, alloc_size,
+								    "%s\t\t\"%s\"\n", buf, str);
+					else
+						buf_size = snprintf(buf, alloc_size,
+								    "%s\t\t\"%s\",\n", buf, str);
+				}
+				kfree(str);
+				str = NULL;
+			}
+			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
+			continue;
+		}
+
+		size = 0;
+		status = get_integer_from_buffer((int **)&obj->buffer.pointer, &integer);
+		if (ACPI_SUCCESS(status)) {
+			/*
+			 * Report "PrerequisiteSize" and "Size" values
+			 *	...
+			 *	"PrerequisiteSize": 1,
+			 *	...
+			 *	"Size": 2,
+			 *	...
+			 */
+			if (i == 7)
+				size = integer;
+			else if (type == HPWMI_ENUMERATION_TYPE && i == 10)
+				size = integer;
+			else if (type == HPWMI_ORDEREDLIST_TYPE && i == 9)
+				size = integer;
+			else if (type == HPWMI_PASSWORD_TYPE && i == 11)
+				size = integer;
+
+			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": %d,\n", buf,
+					    hp_wmi_elements[type][i], integer);
+		}
+
+		if (size > 20)
+			pr_warn("%s exceeded the maximum number of elements supported or data may be malformed\n",
+				hp_wmi_elements[type][i]);
+
+		if (ACPI_SUCCESS(status) && i == 7) {
+			buf_size = snprintf(buf, alloc_size, "%s\t\"Prerequisites\": [\n", buf);
+			for (j = 0; j < size; j++) {
+				status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str);
+				if (ACPI_SUCCESS(status)) {
+					buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, str);
+
+					if (j == size - 1)
+						buf_size = snprintf(buf, alloc_size, "%s\n", buf);
+					else
+						buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
+
+				}
+				kfree(str);
+				str = NULL;
+			}
+			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
+		}
+	}
+
+	if (type == HPWMI_ENUMERATION_TYPE || type == HPWMI_ORDEREDLIST_TYPE) {
+		if (type == HPWMI_ENUMERATION_TYPE)
+			buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\": [\n", buf);
+		else
+			buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n", buf);
+
+		for (i = 0; i < size; i++) {
+			status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str);
+			if (ACPI_SUCCESS(status)) {
+				buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, str);
+
+				if (i == size - 1)
+					buf_size = snprintf(buf, alloc_size, "%s\n", buf);
+				else
+					buf_size = snprintf(buf, alloc_size, "%s,\n", buf);
+
+			}
+			kfree(str);
+			str = NULL;
+		}
+		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
+	}
+
+	/*
+	 * remove trailing comma
+	 */
+	if (buf_size > 3)
+		buf[buf_size - 2] = ' ';
+
+	return snprintf(buf, alloc_size, "%s},\n", buf);
+}
+
+static int hp_bios_settings_free_buffer(void)
+{
+	mutex_lock(&buf_mutex);
+	kfree(hp_bios_settings_buffer);
+	settings_buffer_size = 0;
+	buf_alloc_size = 0;
+	mutex_unlock(&buf_mutex);
+
+	return 0;
+}
+
+static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
+					   int *alloc_size,
+					   struct mutex *buf_mutex)
+{
+	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(buf_mutex);
+		new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
+		mutex_unlock(buf_mutex);
+		if (new_buf) {
+			mutex_lock(buf_mutex);
+			*buf = new_buf;
+			*alloc_size = ksize(new_buf);
+			mutex_unlock(buf_mutex);
+		} else {
+			hp_bios_settings_free_buffer();
+			ret = -ENOMEM;
+		}
+	}
+
+	return ret;
+}
+
+static int append_settings_to_buffer(char *guid, int type, char **buf,
+				     int *buf_size, int *alloc_size,
+				     struct mutex *buf_mutex)
+{
+	union acpi_object *obj = NULL;
+	int ret = 0;
+	int status = 0;
+	int instance = 0;
+
+	/*
+	 * Query all the instances until to receive a AE_BAD_PARAMETER
+	 */
+	do {
+		ret = hp_wmi_get_setting_object(guid, instance++, &obj);
+		if (ACPI_SUCCESS(ret) && obj != NULL) {
+			status = 0;
+			if (obj->type == ACPI_TYPE_PACKAGE) {
+				mutex_lock(buf_mutex);
+				status = append_package_elements_to_buffer(obj,
+							*buf, *alloc_size, type);
+				if (status > 0)
+					*buf_size = status;
+				mutex_unlock(buf_mutex);
+
+			} else if (obj->type == ACPI_TYPE_BUFFER) {
+				mutex_lock(buf_mutex);
+				status = append_buffer_elements_to_buffer(obj,
+							*buf, *alloc_size, type);
+				if (status > 0)
+					*buf_size = status;
+				mutex_unlock(buf_mutex);
+
+			} else
+				pr_warn("The retrieved object type(%d) is not supported yet\n",
+					obj->type);
+
+			ret = hp_bios_settings_realloc_buffer(buf, buf_size, alloc_size, buf_mutex);
+		}
+
+		kfree(obj);
+		obj = NULL;
+
+	} while (ACPI_SUCCESS(ret));
+
+	/*
+	 * AE_BAD_PARAMETER means the loop ended by exhaustion
+	 */
+	if (ret == AE_BAD_PARAMETER)
+		ret = 0;
+
+	return ret;
+}
+
+static int hp_bios_settings_fill_buffer(void)
+{
+	int status = 0;
+	int initial_buffer_size = 20 * PAGE_SIZE;
+
+	mutex_lock(&buf_mutex);
+	hp_bios_settings_buffer = kmalloc(initial_buffer_size, GFP_KERNEL);
+	mutex_unlock(&buf_mutex);
+	if (!hp_bios_settings_buffer)
+		return -ENOMEM;
+
+	mutex_lock(&buf_mutex);
+	buf_alloc_size = ksize(hp_bios_settings_buffer);
+	settings_buffer_size = snprintf(hp_bios_settings_buffer,
+					buf_alloc_size, "[\n");
+	mutex_unlock(&buf_mutex);
+
+	status = append_settings_to_buffer(HPWMI_STRING_GUID,
+		HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
+		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
+	if (ACPI_FAILURE(status))
+		pr_err("error 0x%x occurred retrieving string instances\n", status);
+
+	status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
+		HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
+		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
+	if (ACPI_FAILURE(status))
+		pr_err("error 0x%x occurred retrieving integer instances\n", status);
+
+	status = append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
+		HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
+		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
+	if (ACPI_FAILURE(status))
+		pr_err("error 0x%x occurred retrieving enumeration instances\n", status);
+
+	status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
+		HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
+		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
+	if (ACPI_FAILURE(status))
+		pr_err("error 0x%x occurred retrieving ordered list instances\n", status);
+
+	status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
+		HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
+		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
+	if (ACPI_FAILURE(status))
+		pr_err("error 0x%x occurred retrieving password list instances\n", status);
+
+	mutex_lock(&buf_mutex);
+	/*
+	 * remove trailing comma
+	 */
+	if (settings_buffer_size >= 3) {
+		if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
+			hp_bios_settings_buffer[settings_buffer_size - 2] = ' ';
+	}
+	settings_buffer_size = snprintf(hp_bios_settings_buffer,
+					buf_alloc_size, "%s]\n",
+					hp_bios_settings_buffer);
+	mutex_unlock(&buf_mutex);
+
+	return settings_buffer_size;
+}
+
+/*
+ * sure_admin_settings_read - Return a formatted file with settings
+ *                              and possible options read from BIOS
+ *
+ * @filp:  Pointer to file of settings read from BIOS
+ * @kobj:  Pointer to a kernel object of things that show up as directory in the sysfs filesystem.
+ * @attr:  Pointer to list of read attributes
+ * @buf:   Pointer to buffer
+ * @off:   File current offset
+ * @count: Buffer size
+ *
+ * Returns the count of unicode chars read if successful, otherwise
+ *		-ENOMEM unable to allocate memory
+ *		-EINVAL buffer not allocated or too small
+ *
+ */
+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 >= settings_buffer_size && settings_buffer_size > 0) {
+		hp_bios_settings_free_buffer();
+		return 0;
+	}
+
+	/* clear the buffer whenever the read starts from the first position */
+	if (off == 0 && settings_buffer_size > 0)
+		hp_bios_settings_free_buffer();
+
+	if (settings_buffer_size == 0)
+		hp_bios_settings_fill_buffer();
+
+	mutex_lock(&buf_mutex);
+	ret = memory_read_from_buffer(buf, count, &off, hp_bios_settings_buffer,
+				      settings_buffer_size);
+	mutex_unlock(&buf_mutex);
+
+	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
+ */
+static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
+{
+	int len = strlen(str);
+
+	/*
+	 * Add null character when reading an empty string
+	 */
+	if (len == 0) {
+		*p++ = 2;
+		*p++ = (u8)0x00;
+		return p;
+	}
+	*p++ = len * 2;
+	utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
+	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
+ */
+static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 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(HPWMI_SETBIOSSETTING_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;
+}
+
+/* Sure Admin Functions */
+
+#define UTF_PREFIX			((unsigned char *)"<utf-16/>")
+#define BEAM_PREFIX			((unsigned char *)"<BEAM/>")
+
+/*
+ * sure_admin_settings_write - Write the contents of a formatted file
+ *                               with settings and performs the logic
+ *                               to change any settings in BIOS.
+ *
+ * @filp:  Pointer to file of settings to be written to BIOS
+ * @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 write operation
+ * @buf:   Pointer to buffer
+ * @off:   File current offset
+ * @count: Buffer size
+ *
+ *
+ * Returns the count of unicode characters written to BIOS if successful, otherwise
+ *		-ENOMEM unable to allocate memory
+ *		-EINVAL buffer not allocated or too small
+ *
+ */
+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;
+	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 out_free;
+	}
+	tmpstr = ascii_to_utf16_unicode(tmpstr, part);
+	part = strsep(&buf, ",");
+	if (!part) {
+		status = -EINVAL;
+		goto out_free;
+	}
+
+	/* Add extra buffer space when encountering an empty string */
+	if (!strlen(part))
+		buffer_size += sizeof(unsigned short);
+	tmpstr = ascii_to_utf16_unicode(tmpstr, part);
+	part = strsep(&buf, ",");
+	if (!part) {
+		status = -EINVAL;
+		goto out_free;
+	}
+	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 out_free;
+
+		tmpstr = ascii_to_utf16_unicode(tmpstr, part);
+		kfree(part);
+	}
+
+	part = strsep(&buf, ",");
+	if (part) {
+		status = -EINVAL;
+		goto out_free;
+	}
+	status = hp_wmi_set_bios_setting(buffer, buffer_size);
+	if (ACPI_FAILURE(status))
+		status = -EINVAL;
+
+out_free:
+	kfree(buffer);
+	if (ACPI_SUCCESS(status))
+		return count;
+	return status;
+}
+
+HPWMI_BINATTR_RW(sure_admin, settings, 0);
+
+static struct bin_attribute *sure_admin_binattrs[] = {
+	&sure_admin_settings,
+	NULL,
+};
+
+static const struct attribute_group sure_admin_group = {
+	.name = "sure_admin",
+	.bin_attrs = sure_admin_binattrs,
+};
+
 static DEVICE_ATTR_RO(display);
 static DEVICE_ATTR_RO(hddtemp);
 static DEVICE_ATTR_RW(als);
@@ -1050,6 +2026,7 @@ static const struct attribute_group *hp_wmi_groups[] = {
 	&hp_wmi_group,
 	&spm_group,
 	&sure_start_group,
+	&sure_admin_group,
 	NULL,
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v1 6/6] HP Security Features Documentation
  2022-04-04 20:36 [PATCH v1 0/6] HP WMI Security Features Jorge Lopez
                   ` (4 preceding siblings ...)
  2022-04-04 20:36 ` [PATCH v1 5/6] Sure Admin " Jorge Lopez
@ 2022-04-04 20:36 ` Jorge Lopez
  5 siblings, 0 replies; 25+ messages in thread
From: Jorge Lopez @ 2022-04-04 20:36 UTC (permalink / raw)
  To: platform-driver-x86

Provide documentation for three new security features introduced in
the hp-wmi driver. The security features include Secure Platform
Management, Sure Admin, and Sure Start. Each documentation section
provides security feature description, identifies sysfs directories,
and files exposed by the driver.

Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>

---
Based on the latest platform-drivers-x86.git/for-next

This patch replaces and provides missing ABI/testing file in
v1-0001-HP-Security-Features-solutions-Documentation patch.

Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>

---
Based on the latest platform-drivers-x86.git/for-next
---
 .../ABI/testing/sysfs-platform-hp-wmi         |  96 ++++++++++++
 Documentation/admin-guide/hp_wmi.rst          | 141 ++++++++++++++++++
 Documentation/admin-guide/index.rst           |   1 +
 3 files changed, 238 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-platform-hp-wmi
 create mode 100644 Documentation/admin-guide/hp_wmi.rst

diff --git a/Documentation/ABI/testing/sysfs-platform-hp-wmi b/Documentation/ABI/testing/sysfs-platform-hp-wmi
new file mode 100644
index 000000000000..836b1cdbc260
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-hp-wmi
@@ -0,0 +1,96 @@
+
+What:		/sys/devices/platform/hp-wmi/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/devices/platform/hp-wmi/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/devices/platform/hp-wmi/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/devices/platform/hp-wmi/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/devices/platform/hp-wmi/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/devices/platform/hp-wmi/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/devices/platform/hp-wmi/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/Documentation/admin-guide/hp_wmi.rst b/Documentation/admin-guide/hp_wmi.rst
new file mode 100644
index 000000000000..4dcb416bbf08
--- /dev/null
+++ b/Documentation/admin-guide/hp_wmi.rst
@@ -0,0 +1,141 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================
+HP Inc. WMI driver (hp_wmi)
+===========================
+
+Purpose
+=======
+To document the use of the HP WMI driver to manage BIOS settings & security
+solutions on HP Inc.’s commercial platforms
+
+Scope
+=====
+This document discusses the functionality of the hp_wmi driver only.
+It does not cover the support needed from applications to configure the BIOS
+settings and enable the security features.
+
+Overview
+========
+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.
+
+The hp-wmi driver enables managing the BIOS settings and security solutions
+via sysfs, a virtual filesystem that can be used by usermode applications.
+
+When the driver loads, it creates the following directories and files in the
+/sys file system::
+
+	/sys/devices/platform/hp-wmi/spm/kek
+	/sys/devices/platform/hp-wmi/spm/sk
+	/sys/devices/platform/hp-wmi/spm/status
+	/sys/devices/platform/hp-wmi/spm/statusbin
+	/sys/devices/platform/hp-wmi/sure_admin/settings
+	/sys/devices/platform/hp-wmi/sure_start/audit_log_entries
+	/sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count
+
+If the driver is unloaded, all the allocated memory is freed and directories
+and files in the /sys file system removed.
+
+Secure Platform Management
+==========================
+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.
+
+The private key is used by system management utilities to sign payloads
+containing configuration changes.  The BIOS on a target system uses the
+associated public key to verify the integrity of the payload and apply the
+changes.
+
+At the end of the PC’s lifecycle a signed deprovisioning command restores
+the factory default state.
+
+KEK Certificate (KEK) and Signing Key (SK) get provisioned and status can
+be read either as text from the status file or binary from statusbin. ::
+
+	/sys/devices/platform/hp-wmi/spm/kek
+	/sys/devices/platform/hp-wmi/spm/sk
+	/sys/devices/platform/hp-wmi/spm/status
+	/sys/devices/platform/hp-wmi/spm/statusbin
+
+**status** is a read-only file that returns ASCII text reporting the
+following 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):
+
+**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.
+
+**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.
+
+Sure Admin
+==========
+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.
+Behind the scenes, Sure Admin uses Secure Platform Management (SPM) and WMI
+
+**settings** is a file associated with Sure Admin. BIOS settings can be read
+or written through the Sure Admin settings file in sysfs::
+
+	/sys/devices/platform/hp-wmi/sure_admin/settings
+
+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"
+		]
+	}
+
+Sure Start
+==========
+Sure Start provides advanced firmware protection and resiliency by identifying
+and repairing unauthorized BIOS changes.  It maintains an audit log of these
+events and other important system configuration changes.  The following sysfs
+entries can be used to read the contents of the audit log.
+
+**audit_log_entry_count** is a read-only file that returns the number of
+existing audit log events available to be read::
+
+	/sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count
+
+Reported data format::
+
+	[No of entries],[log entry size in bytes],[Max number of entries supported]
+
+
+**audit_log_entries** is a read-only file that returns the events in the log::
+
+	/sys/devices/platform/hp-wmi/sure_start/audit_log_entries
diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst
index 1bedab498104..58b9b0541cb5 100644
--- a/Documentation/admin-guide/index.rst
+++ b/Documentation/admin-guide/index.rst
@@ -86,6 +86,7 @@ configure specific aspects of kernel behavior to your liking.
    nfs/index
    gpio/index
    highuid
+   hp_wmi
    hw_random
    initrd
    iostats
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* RE: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-04 20:36 ` [PATCH v1 5/6] Sure Admin " Jorge Lopez
@ 2022-04-04 21:59   ` Limonciello, Mario
  2022-04-05 11:54     ` Hans de Goede
  0 siblings, 1 reply; 25+ messages in thread
From: Limonciello, Mario @ 2022-04-04 21:59 UTC (permalink / raw)
  To: Jorge Lopez, platform-driver-x86

[Public]



> -----Original Message-----
> From: Jorge Lopez <jorgealtxwork@gmail.com>
> Sent: Monday, April 4, 2022 15:36
> To: platform-driver-x86@vger.kernel.org
> Subject: [PATCH v1 5/6] Sure Admin Security Feature
> 
> 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. Behind the scenes, Sure Admin uses Secure Platform
> Management (SPM) and WMI
> 
> 'settings' is a file associated with Sure Admin. BIOS settings can be
> read or written through the Sure Admin settings file in sysfs
> 
> 	/sys/devices/platform/hp-wmi/sure_admin/settings
> 
> 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"
> 		]
> 	}
> 

This sounds like it has re-invented /sys/class/firmware-attributes.

Shouldn't you adopt that API?

> This feature requires "Update hp_wmi_group to simplify feature
> addition" patch.
> 
> All changes were validated on a HP ZBook Workstation,
> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> 
> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> 
> ---
> Based on the latest platform-drivers-x86.git/for-next
> ---
>  drivers/platform/x86/hp-wmi.c | 977
> ++++++++++++++++++++++++++++++++++
>  1 file changed, 977 insertions(+)
> 
> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
> index 918e3eaf1b67..b72ca18b77a6 100644
> --- a/drivers/platform/x86/hp-wmi.c
> +++ b/drivers/platform/x86/hp-wmi.c
> @@ -27,6 +27,7 @@
>  #include <linux/rfkill.h>
>  #include <linux/string.h>
>  #include <linux/dmi.h>
> +#include <linux/nls.h>
> 
>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-
> 3D44E2C707E4");
> 
>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
> +
>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
> 
> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-6A1B8106F83C"
> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
> E293ADB9BF05"
> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-
> 4A3C09E75133"
> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
> 7045CB4DA745"
> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
> 015176049E2D"
> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-
> C7CB9B4B8D5E"
> +
>  /* DMI board names of devices that should use the omen specific path for
>   * thermal profiles.
>   * This was obtained by taking a look in the windows omen command center
> @@ -1025,6 +1034,973 @@ static const struct attribute_group
> sure_start_group = {
>  	.attrs = sure_start_attrs,
>  };
> 
> +
> +static 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;
> +	int  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));
> +		ret = kstrtoint(tmp, 16, &ch);
> +		if (ret) {
> +			new_len = 0;
> +			break;
> +		}
> +
> +		if (ch == '\\')
> +			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;
> +	}
> +
> +	if (ret)
> +		kfree(new_str);
> +	return ret;
> +}
> +
> +/*
> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and instance
> + *
> + * @guid:	GUID associated with the ACPI list of managed objects
> + * @instance:	Instance index to query on the ACPI list
> + * @obj:	The output ACPI object of type ACPI_TYPE_PACKAGE
> + *		or ACPI_TYPE_BUFFER (freed by the callee)
> + *
> + * Returns	zero on success.  Otherwise,an error inherited from
> + *		wmi_query_block(). It returns a obj by parameter if
> + *		the query returned object of type buffer or package,
> + *		otherwise, a null obj is returned.
> + *
> + * Note: obj should be freed by the callee once it is finished working with it
> + */
> +static int hp_wmi_get_setting_object(char *guid, int instance,
> +				union acpi_object **obj)
> +{
> +	struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL
> };
> +	union acpi_object *tmp = NULL;
> +	int ret;
> +
> +	ret = wmi_query_block(guid, instance, &output);
> +	if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
> +		tmp = output.pointer;
> +		if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
> ACPI_TYPE_PACKAGE)
> +			*obj = output.pointer;
> +		else {
> +			kfree(tmp);
> +			*obj = NULL;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +
> +static 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;
> +
> +	if (size == 0)
> +		goto cleanup_exit;
> +
> +	for (i = 0; i < size; i++)
> +		if (ptr[i] == '\\')
> +			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);
> +
> +	if (escape == 0) {
> +		ptr += (ptrlen / 2);
> +		goto cleanup_exit;
> +	}
> +	/*
> +	 * Convert escape characters only when found
> +	 */
> +	for (i = 0; i < size; i++) {
> +		if (*ptr == '\\')
> +			output[i++] = '\\';
> +		output[i] = *ptr;
> +		ptr++;
> +	}
> +
> +cleanup_exit:
> +	*buffer = ptr;
> +	return 0;
> +}
> +
> +static int get_integer_from_buffer(int **buffer, int *integer)
> +{
> +	int *ptr = PTR_ALIGN(*buffer, 4);
> +	*integer = *(ptr++);
> +	*buffer = ptr;
> +	return 0;
> +}
> +
> +
> +// Sure Admin functions
> +enum hp_wmi_data_type {
> +	HPWMI_STRING_TYPE,
> +	HPWMI_INTEGER_TYPE,
> +	HPWMI_ENUMERATION_TYPE,
> +	HPWMI_ORDEREDLIST_TYPE,
> +	HPWMI_PASSWORD_TYPE,
> +};
> +
> +#define HP_WMI_COMMON_ELEMENTS	\
> +	"Name",	\
> +	"Value",	\
> +	"Path",	\
> +	"IsReadOnly",	\
> +	"DisplayInUI",	\
> +	"RequiresPhysicalPresence",	\
> +	"Sequence",	\
> +	"PrerequisiteSize",	\
> +	"SecurityLevel"
> +
> +const char *hp_wmi_string_elements[] = {
> +	HP_WMI_COMMON_ELEMENTS,
> +	"MinLength",
> +	"MaxLength"
> +};
> +
> +const char *hp_wmi_integer_elements[] = {
> +	HP_WMI_COMMON_ELEMENTS,
> +	"LowerBound",
> +	"UpperBound",
> +	"IntValue"
> +};
> +
> +const char *hp_wmi_enumeration_elements[] = {
> +	HP_WMI_COMMON_ELEMENTS,
> +	"CurrentValue",
> +	"Size"
> +};
> +
> +const char *hp_wmi_orderedlist_elements[] = {
> +	HP_WMI_COMMON_ELEMENTS,
> +	"Size"
> +};
> +
> +const char *hp_wmi_password_elements[] = {
> +	HP_WMI_COMMON_ELEMENTS,
> +	"MinLength",
> +	"MaxLength",
> +	"Size",
> +	"SupportedEncoding",
> +	"IsSet"
> +};
> +
> +const char **hp_wmi_elements[] = {
> +	hp_wmi_string_elements,
> +	hp_wmi_integer_elements,
> +	hp_wmi_enumeration_elements,
> +	hp_wmi_orderedlist_elements,
> +	hp_wmi_password_elements
> +};
> +
> +const int hp_wmi_elements_count[] = {
> +	ARRAY_SIZE(hp_wmi_string_elements),
> +	ARRAY_SIZE(hp_wmi_integer_elements),
> +	ARRAY_SIZE(hp_wmi_enumeration_elements),
> +	ARRAY_SIZE(hp_wmi_orderedlist_elements),
> +	ARRAY_SIZE(hp_wmi_password_elements)
> +};
> +
> +const char *hp_wmi_classes[] = {
> +	"HPBIOS_BIOSString",
> +	"HPBIOS_BIOSInteger",
> +	"HPBIOS_BIOSEnumeration",
> +	"HPBIOS_BIOSOrderedList",
> +	"HPBIOS_BIOSPassword"
> +};
> +
> +static DEFINE_MUTEX(buf_mutex);
> +static int settings_buffer_size;
> +static int buf_alloc_size;
> +static char *hp_bios_settings_buffer;
> +
> +
> +static int append_package_elements_to_buffer(union acpi_object *obj,
> +					     char *buf, int alloc_size, enum
> hp_wmi_data_type type)
> +{
> +	int i;
> +	union acpi_object *pobj = NULL;
> +	char *value = NULL;
> +	int value_len;
> +	char *tmpstr = NULL;
> +	char *part_tmp = NULL;
> +	int tmp_len = 0;
> +	char *part = NULL;
> +	int status = 0;
> +	int size = 0;
> +	int buf_size;
> +
> +	if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> +		return -EINVAL;
> +
> +	if (obj->type != ACPI_TYPE_PACKAGE)
> +		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]);
> +
> +	for (i = 0; i < 3; i++) {
> +		pobj = &(obj->package.elements[i]);
> +		if (pobj->type == ACPI_TYPE_STRING) {
> +			status = convert_hexstr_to_str(&pobj-
> >string.pointer,
> +						       pobj->string.length,
> &value, &value_len);
> +			if (ACPI_FAILURE(status))
> +				continue;
> +			/*
> +			 * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> since
> +			 * 'CurrentValue' is reported.
> +			 */
> +			if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> +				buf_size = snprintf(buf, alloc_size,
> +						    "%s\t\"%s\": \"%s\",\n",
> +						    buf,
> +
> hp_wmi_elements[type][i], value);
> +
> +		}
> +		kfree(value);
> +		value = NULL;
> +	}
> +
> +	for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> +		pobj = &(obj->package.elements[i]);
> +
> +		if (type == HPWMI_ENUMERATION_TYPE &&
> +		    i == 9 &&
> +		    pobj->type == ACPI_TYPE_STRING) {
> +			/*
> +			 * Report "CurrentValue" as "Value"
> +			 */
> +			status = convert_hexstr_to_str(&pobj-
> >string.pointer,
> +						       pobj->string.length,
> +						       &value, &value_len);
> +			if (ACPI_FAILURE(status))
> +				continue;
> +
> +			buf_size = snprintf(buf, alloc_size,
> +					    "%s\t\"Value\": \"%s\",\n",
> +					    buf, value);
> +			kfree(value);
> +			value = NULL;
> +
> +		} else if (type == HPWMI_PASSWORD_TYPE &&
> +			   i == 12 &&
> +			   pobj->type == ACPI_TYPE_STRING) {
> +			/*
> +			 * Report list of "SupportEncoding"
> +			 *
> +			 *	"SupportedEncoding": [
> +			 *		"utf-16"
> +			 *	],
> +			 *
> +			 */
> +
> +			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> +					    buf, hp_wmi_elements[type][i]);
> +			while (size--) {
> +				pobj = &(obj->package.elements[i]);
> +				status = convert_hexstr_to_str(&pobj-
> >string.pointer,
> +							       pobj-
> >string.length,
> +							       &value,
> &value_len);
> +				if (ACPI_FAILURE(status))
> +					continue;
> +
> +				if (size) {
> +					buf_size = snprintf(buf, alloc_size,
> +							    "%s\t\t\"%s\",\n",
> buf, value);
> +					i++;
> +				} else
> +					buf_size = snprintf(buf, alloc_size,
> +							    "%s\t\t\"%s\"\n",
> buf, value);
> +
> +				kfree(value);
> +				value = NULL;
> +
> +			}
> +			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> +			continue;
> +
> +		} else if (pobj->type == ACPI_TYPE_INTEGER) {
> +			/*
> +			 * Report "PrerequisiteSize" and "Size" values
> +			 *	...
> +			 *	"PrerequisiteSize": 1,
> +			 *	...
> +			 *	"Size": 2,
> +			 *	...
> +			 */
> +			if (i == 7)
> +				size = pobj->integer.value;
> +			else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> 9)
> +				size = pobj->integer.value;
> +			else if (type == HPWMI_ENUMERATION_TYPE && i
> == 10)
> +				size = pobj->integer.value;
> +			else if (type == HPWMI_PASSWORD_TYPE && i ==
> 11)
> +				size = pobj->integer.value;
> +
> +			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> %lld,\n", buf,
> +					    hp_wmi_elements[type][i], pobj-
> >integer.value);
> +		}
> +	}
> +
> +	if (type == HPWMI_ENUMERATION_TYPE) {
> +		buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
> [\n", buf);
> +		for (i = 0; i < size; i++) {
> +			pobj = &(obj->package.elements[i +
> hp_wmi_elements_count[type]]);
> +
> +			status = convert_hexstr_to_str(&pobj-
> >string.pointer,
> +						       pobj->string.length,
> +						       &value, &value_len);
> +			if (ACPI_FAILURE(status))
> +				break;
> +
> +			/*
> +			 * Report list of "PossibleValues" of size
> +			 * "Size"
> +			 *	...
> +			 *	"Size": 2,
> +			 *	"PossibleValues": [
> +			 *			"Disable",
> +			 *			"Enable"]
> +			 */
> +			if (i == (size - 1))
> +				buf_size = snprintf(buf, alloc_size,
> +						    "%s\t\t\"%s\"\n", buf,
> value);
> +			else
> +				buf_size = snprintf(buf, alloc_size,
> +						    "%s\t\t\"%s\",\n", buf,
> value);
> +			kfree(value);
> +			value = NULL;
> +		}
> +		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> +	}
> +
> +	if (type == HPWMI_ORDEREDLIST_TYPE) {
> +		buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
> buf);
> +		if (size <= 0)
> +			goto finish_ordered_list;
> +
> +		pobj = &(obj-
> >package.elements[hp_wmi_elements_count[type]]);
> +		status = convert_hexstr_to_str(&pobj->string.pointer,
> +					       pobj->string.length, &value,
> &value_len);
> +		if (ACPI_FAILURE(status))
> +			goto finish_ordered_list;
> +
> +		/*
> +		 * 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(&value, value_len, &tmpstr,
> &tmp_len);
> +		if (ACPI_FAILURE(status))
> +			goto finish_ordered_list;
> +
> +		part_tmp = tmpstr;
> +		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);
> +		}
> +	}
> +
> +finish_ordered_list:
> +	if (type == HPWMI_ORDEREDLIST_TYPE)
> +		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> +
> +	/*
> +	 * remove trailing comma
> +	 */
> +	if (buf_size > 3)
> +		buf[buf_size - 2] = ' ';
> +
> +	kfree(tmpstr);
> +	kfree(value);
> +	return snprintf(buf, alloc_size, "%s},\n", buf);
> +}
> +
> +static int append_buffer_elements_to_buffer(union acpi_object *obj,
> +					    char *buf, int alloc_size, enum
> hp_wmi_data_type type)
> +{
> +	int buf_size;
> +	int status;
> +	char *str = NULL;
> +	int i;
> +	int j;
> +	int integer;
> +	int size = 0;
> +
> +	if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> +		return -EINVAL;
> +
> +	if (obj->type != ACPI_TYPE_BUFFER)
> +		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]);
> +
> +	for (i = 0; i < 3; i++) {
> +		status = get_string_from_buffer((u16 **)&obj-
> >buffer.pointer, &str);
> +		if (ACPI_SUCCESS(status)) {
> +			/*
> +			 * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> since
> +			 * 'CurrentValue' is reported.
> +			 */
> +			if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> +				buf_size = snprintf(buf, alloc_size,
> +						    "%s\t\"%s\": \"%s\",\n",
> +						    buf,
> +
> hp_wmi_elements[type][i], str);
> +		}
> +		kfree(str);
> +		str = NULL;
> +
> +	}
> +
> +	for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> +		if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
> +			status = get_string_from_buffer((u16 **)&obj-
> >buffer.pointer, &str);
> +			if (ACPI_SUCCESS(status)) {
> +				/*
> +				 * Report "CurrentValue" as "Value"
> +				 */
> +				buf_size = snprintf(buf, alloc_size,
> +						    "%s\t\"Value\": \"%s\",\n",
> buf, str);
> +			}
> +			kfree(str);
> +			str = NULL;
> +			continue;
> +
> +		} else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
> +			/*
> +			 * Report list of "SupportEncoding"
> +			 *
> +			 *	"SupportedEncoding": [
> +			 *		"utf-16"
> +			 *	],
> +			 *
> +			 */
> +
> +			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> +					    buf, hp_wmi_elements[type][i]);
> +			for (j = 0; j < size; j++) {
> +				status = get_string_from_buffer((u16
> **)&obj->buffer.pointer, &str);
> +				if (ACPI_SUCCESS(status)) {
> +					if (j == size - 1)
> +						buf_size = snprintf(buf,
> alloc_size,
> +
> "%s\t\t\"%s\"\n", buf, str);
> +					else
> +						buf_size = snprintf(buf,
> alloc_size,
> +
> "%s\t\t\"%s\",\n", buf, str);
> +				}
> +				kfree(str);
> +				str = NULL;
> +			}
> +			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> +			continue;
> +		}
> +
> +		size = 0;
> +		status = get_integer_from_buffer((int **)&obj-
> >buffer.pointer, &integer);
> +		if (ACPI_SUCCESS(status)) {
> +			/*
> +			 * Report "PrerequisiteSize" and "Size" values
> +			 *	...
> +			 *	"PrerequisiteSize": 1,
> +			 *	...
> +			 *	"Size": 2,
> +			 *	...
> +			 */
> +			if (i == 7)
> +				size = integer;
> +			else if (type == HPWMI_ENUMERATION_TYPE && i
> == 10)
> +				size = integer;
> +			else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> 9)
> +				size = integer;
> +			else if (type == HPWMI_PASSWORD_TYPE && i ==
> 11)
> +				size = integer;
> +
> +			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> %d,\n", buf,
> +					    hp_wmi_elements[type][i],
> integer);
> +		}
> +
> +		if (size > 20)
> +			pr_warn("%s exceeded the maximum number of
> elements supported or data may be malformed\n",
> +				hp_wmi_elements[type][i]);
> +
> +		if (ACPI_SUCCESS(status) && i == 7) {
> +			buf_size = snprintf(buf, alloc_size,
> "%s\t\"Prerequisites\": [\n", buf);
> +			for (j = 0; j < size; j++) {
> +				status = get_string_from_buffer((u16
> **)&obj->buffer.pointer, &str);
> +				if (ACPI_SUCCESS(status)) {
> +					buf_size = snprintf(buf, alloc_size,
> "%s\t\t\"%s\"", buf, str);
> +
> +					if (j == size - 1)
> +						buf_size = snprintf(buf,
> alloc_size, "%s\n", buf);
> +					else
> +						buf_size = snprintf(buf,
> alloc_size, "%s,\n", buf);
> +
> +				}
> +				kfree(str);
> +				str = NULL;
> +			}
> +			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> +		}
> +	}
> +
> +	if (type == HPWMI_ENUMERATION_TYPE || type ==
> HPWMI_ORDEREDLIST_TYPE) {
> +		if (type == HPWMI_ENUMERATION_TYPE)
> +			buf_size = snprintf(buf, alloc_size,
> "%s\t\"PossibleValues\": [\n", buf);
> +		else
> +			buf_size = snprintf(buf, alloc_size,
> "%s\t\"Elements\": [\n", buf);
> +
> +		for (i = 0; i < size; i++) {
> +			status = get_string_from_buffer((u16 **)&obj-
> >buffer.pointer, &str);
> +			if (ACPI_SUCCESS(status)) {
> +				buf_size = snprintf(buf, alloc_size,
> "%s\t\t\"%s\"", buf, str);
> +
> +				if (i == size - 1)
> +					buf_size = snprintf(buf, alloc_size,
> "%s\n", buf);
> +				else
> +					buf_size = snprintf(buf, alloc_size,
> "%s,\n", buf);
> +
> +			}
> +			kfree(str);
> +			str = NULL;
> +		}
> +		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> +	}
> +
> +	/*
> +	 * remove trailing comma
> +	 */
> +	if (buf_size > 3)
> +		buf[buf_size - 2] = ' ';
> +
> +	return snprintf(buf, alloc_size, "%s},\n", buf);
> +}
> +
> +static int hp_bios_settings_free_buffer(void)
> +{
> +	mutex_lock(&buf_mutex);
> +	kfree(hp_bios_settings_buffer);
> +	settings_buffer_size = 0;
> +	buf_alloc_size = 0;
> +	mutex_unlock(&buf_mutex);
> +
> +	return 0;
> +}
> +
> +static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
> +					   int *alloc_size,
> +					   struct mutex *buf_mutex)
> +{
> +	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(buf_mutex);
> +		new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
> +		mutex_unlock(buf_mutex);
> +		if (new_buf) {
> +			mutex_lock(buf_mutex);
> +			*buf = new_buf;
> +			*alloc_size = ksize(new_buf);
> +			mutex_unlock(buf_mutex);
> +		} else {
> +			hp_bios_settings_free_buffer();
> +			ret = -ENOMEM;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int append_settings_to_buffer(char *guid, int type, char **buf,
> +				     int *buf_size, int *alloc_size,
> +				     struct mutex *buf_mutex)
> +{
> +	union acpi_object *obj = NULL;
> +	int ret = 0;
> +	int status = 0;
> +	int instance = 0;
> +
> +	/*
> +	 * Query all the instances until to receive a AE_BAD_PARAMETER
> +	 */
> +	do {
> +		ret = hp_wmi_get_setting_object(guid, instance++, &obj);
> +		if (ACPI_SUCCESS(ret) && obj != NULL) {
> +			status = 0;
> +			if (obj->type == ACPI_TYPE_PACKAGE) {
> +				mutex_lock(buf_mutex);
> +				status =
> append_package_elements_to_buffer(obj,
> +							*buf, *alloc_size,
> type);
> +				if (status > 0)
> +					*buf_size = status;
> +				mutex_unlock(buf_mutex);
> +
> +			} else if (obj->type == ACPI_TYPE_BUFFER) {
> +				mutex_lock(buf_mutex);
> +				status =
> append_buffer_elements_to_buffer(obj,
> +							*buf, *alloc_size,
> type);
> +				if (status > 0)
> +					*buf_size = status;
> +				mutex_unlock(buf_mutex);
> +
> +			} else
> +				pr_warn("The retrieved object type(%d) is
> not supported yet\n",
> +					obj->type);
> +
> +			ret = hp_bios_settings_realloc_buffer(buf, buf_size,
> alloc_size, buf_mutex);
> +		}
> +
> +		kfree(obj);
> +		obj = NULL;
> +
> +	} while (ACPI_SUCCESS(ret));
> +
> +	/*
> +	 * AE_BAD_PARAMETER means the loop ended by exhaustion
> +	 */
> +	if (ret == AE_BAD_PARAMETER)
> +		ret = 0;
> +
> +	return ret;
> +}
> +
> +static int hp_bios_settings_fill_buffer(void)
> +{
> +	int status = 0;
> +	int initial_buffer_size = 20 * PAGE_SIZE;
> +
> +	mutex_lock(&buf_mutex);
> +	hp_bios_settings_buffer = kmalloc(initial_buffer_size, GFP_KERNEL);
> +	mutex_unlock(&buf_mutex);
> +	if (!hp_bios_settings_buffer)
> +		return -ENOMEM;
> +
> +	mutex_lock(&buf_mutex);
> +	buf_alloc_size = ksize(hp_bios_settings_buffer);
> +	settings_buffer_size = snprintf(hp_bios_settings_buffer,
> +					buf_alloc_size, "[\n");
> +	mutex_unlock(&buf_mutex);
> +
> +	status = append_settings_to_buffer(HPWMI_STRING_GUID,
> +		HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
> +	if (ACPI_FAILURE(status))
> +		pr_err("error 0x%x occurred retrieving string instances\n",
> status);
> +
> +	status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
> +		HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
> +	if (ACPI_FAILURE(status))
> +		pr_err("error 0x%x occurred retrieving integer instances\n",
> status);
> +
> +	status = append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
> +		HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
> +	if (ACPI_FAILURE(status))
> +		pr_err("error 0x%x occurred retrieving enumeration
> instances\n", status);
> +
> +	status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
> +		HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
> +	if (ACPI_FAILURE(status))
> +		pr_err("error 0x%x occurred retrieving ordered list
> instances\n", status);
> +
> +	status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
> +		HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
> +	if (ACPI_FAILURE(status))
> +		pr_err("error 0x%x occurred retrieving password list
> instances\n", status);
> +
> +	mutex_lock(&buf_mutex);
> +	/*
> +	 * remove trailing comma
> +	 */
> +	if (settings_buffer_size >= 3) {
> +		if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
> +			hp_bios_settings_buffer[settings_buffer_size - 2] = '
> ';
> +	}
> +	settings_buffer_size = snprintf(hp_bios_settings_buffer,
> +					buf_alloc_size, "%s]\n",
> +					hp_bios_settings_buffer);
> +	mutex_unlock(&buf_mutex);
> +
> +	return settings_buffer_size;
> +}
> +
> +/*
> + * sure_admin_settings_read - Return a formatted file with settings
> + *                              and possible options read from BIOS
> + *
> + * @filp:  Pointer to file of settings read from BIOS
> + * @kobj:  Pointer to a kernel object of things that show up as directory in
> the sysfs filesystem.
> + * @attr:  Pointer to list of read attributes
> + * @buf:   Pointer to buffer
> + * @off:   File current offset
> + * @count: Buffer size
> + *
> + * Returns the count of unicode chars read if successful, otherwise
> + *		-ENOMEM unable to allocate memory
> + *		-EINVAL buffer not allocated or too small
> + *
> + */
> +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 >= settings_buffer_size && settings_buffer_size > 0) {
> +		hp_bios_settings_free_buffer();
> +		return 0;
> +	}
> +
> +	/* clear the buffer whenever the read starts from the first position
> */
> +	if (off == 0 && settings_buffer_size > 0)
> +		hp_bios_settings_free_buffer();
> +
> +	if (settings_buffer_size == 0)
> +		hp_bios_settings_fill_buffer();
> +
> +	mutex_lock(&buf_mutex);
> +	ret = memory_read_from_buffer(buf, count, &off,
> hp_bios_settings_buffer,
> +				      settings_buffer_size);
> +	mutex_unlock(&buf_mutex);
> +
> +	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
> + */
> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
> +{
> +	int len = strlen(str);
> +
> +	/*
> +	 * Add null character when reading an empty string
> +	 */
> +	if (len == 0) {
> +		*p++ = 2;
> +		*p++ = (u8)0x00;
> +		return p;
> +	}
> +	*p++ = len * 2;
> +	utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
> +	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
> + */
> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 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(HPWMI_SETBIOSSETTING_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;
> +}
> +
> +/* Sure Admin Functions */
> +
> +#define UTF_PREFIX			((unsigned char *)"<utf-16/>")
> +#define BEAM_PREFIX			((unsigned char
> *)"<BEAM/>")
> +
> +/*
> + * sure_admin_settings_write - Write the contents of a formatted file
> + *                               with settings and performs the logic
> + *                               to change any settings in BIOS.
> + *
> + * @filp:  Pointer to file of settings to be written to BIOS
> + * @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 write operation
> + * @buf:   Pointer to buffer
> + * @off:   File current offset
> + * @count: Buffer size
> + *
> + *
> + * Returns the count of unicode characters written to BIOS if successful,
> otherwise
> + *		-ENOMEM unable to allocate memory
> + *		-EINVAL buffer not allocated or too small
> + *
> + */
> +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;
> +	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 out_free;
> +	}
> +	tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> +	part = strsep(&buf, ",");
> +	if (!part) {
> +		status = -EINVAL;
> +		goto out_free;
> +	}
> +
> +	/* Add extra buffer space when encountering an empty string */
> +	if (!strlen(part))
> +		buffer_size += sizeof(unsigned short);
> +	tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> +	part = strsep(&buf, ",");
> +	if (!part) {
> +		status = -EINVAL;
> +		goto out_free;
> +	}
> +	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 out_free;
> +
> +		tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> +		kfree(part);
> +	}
> +
> +	part = strsep(&buf, ",");
> +	if (part) {
> +		status = -EINVAL;
> +		goto out_free;
> +	}
> +	status = hp_wmi_set_bios_setting(buffer, buffer_size);
> +	if (ACPI_FAILURE(status))
> +		status = -EINVAL;
> +
> +out_free:
> +	kfree(buffer);
> +	if (ACPI_SUCCESS(status))
> +		return count;
> +	return status;
> +}
> +
> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
> +
> +static struct bin_attribute *sure_admin_binattrs[] = {
> +	&sure_admin_settings,
> +	NULL,
> +};
> +
> +static const struct attribute_group sure_admin_group = {
> +	.name = "sure_admin",
> +	.bin_attrs = sure_admin_binattrs,
> +};
> +
>  static DEVICE_ATTR_RO(display);
>  static DEVICE_ATTR_RO(hddtemp);
>  static DEVICE_ATTR_RW(als);
> @@ -1050,6 +2026,7 @@ static const struct attribute_group
> *hp_wmi_groups[] = {
>  	&hp_wmi_group,
>  	&spm_group,
>  	&sure_start_group,
> +	&sure_admin_group,
>  	NULL,
>  };
> 
> --
> 2.25.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v1 4/6] Sure Start Security Feature
  2022-04-04 20:36 ` [PATCH v1 4/6] Sure Start " Jorge Lopez
@ 2022-04-04 22:05   ` Limonciello, Mario
  2022-04-05 16:56     ` Jorge Lopez
  0 siblings, 1 reply; 25+ messages in thread
From: Limonciello, Mario @ 2022-04-04 22:05 UTC (permalink / raw)
  To: Jorge Lopez, platform-driver-x86

[Public]



> -----Original Message-----
> From: Jorge Lopez <jorgealtxwork@gmail.com>
> Sent: Monday, April 4, 2022 15:36
> To: platform-driver-x86@vger.kernel.org
> Subject: [PATCH v1 4/6] Sure Start Security Feature
> 
> Sure Start provides advanced firmware protection and resiliency by
> identifying and repairing unauthorized BIOS changes.  It maintains an
> audit log of these events and other important system configuration
> changes.  The following sysfs entries can be used to read the contents
> of the audit log.
> 
>       /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count
>       /sys/devices/platform/hp-wmi/sure_start/audit_log_entries
> 
> 'audit_log_entry_count' is a read-only file that returns the number of
> existing audit log events available to be read
> 
> 'audit_log_entries' is a read-only file that returns the events in the
> log
> 
> This feature requires "Update hp_wmi_group to simplify feature
> addition" patch.
> 
> All changes were validated on a HP ZBook Workstation,
> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> 
> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> 
> ---
> Based on the latest platform-drivers-x86.git/for-next
> ---
>  drivers/platform/x86/hp-wmi.c | 108
> ++++++++++++++++++++++++++++++++++
>  1 file changed, 108 insertions(+)
> 
> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
> index 139dc079c1fa..918e3eaf1b67 100644
> --- a/drivers/platform/x86/hp-wmi.c
> +++ b/drivers/platform/x86/hp-wmi.c
> @@ -126,6 +126,11 @@ enum hp_wmi_spm_commandtype {
>  	HPWMI_SECUREPLATFORM_SET_SK	= 0x12,
>  };
> 
> +enum hp_wmi_surestart_commandtype {
> +	HPWMI_SURESTART_GET_LOG_COUNT	= 0x01,
> +	HPWMI_SURESTART_GET_LOG	= 0x02,
> +};
> +
>  enum hp_wmi_gm_commandtype {
>  	HPWMI_FAN_SPEED_GET_QUERY = 0x11,
>  	HPWMI_SET_PERFORMANCE_MODE = 0x1A,
> @@ -138,6 +143,7 @@ enum hp_wmi_command {
>  	HPWMI_READ	= 0x01,
>  	HPWMI_WRITE	= 0x02,
>  	HPWMI_ODM	= 0x03,
> +	HPWMI_SURESTART = 0x20006,
>  	HPWMI_GM	= 0x20008,
>  	HPWMI_SECUREPLATFORM = 0x20010,
>  };
> @@ -851,6 +857,7 @@ static ssize_t spm_kek_store(struct kobject *kobj,
>  {
>  	int ret =
> hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
>  				       HPWMI_SECUREPLATFORM, (void *)buf,
> count, 0);
> +
>  	return ret ? -EINVAL : count;
>  }
> 
> @@ -918,6 +925,106 @@ static const struct attribute_group spm_group = {
>  	.attrs = spm_attrs,
>  };
> 
> +/* Sure Start functions */
> +
> +#define LOG_MAX_ENTRIES	254
> +#define LOG_ENTRY_SIZE	16
> +
> +/*
> + * sure_start_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 sure_start_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);
> +}
> +
> +/*
> + * sure_start_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 sure_start_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;

This is an interface that will be there forever, what are realistic numbers and sizes after a long time?
I have an AMD HP laptop that is only been used a few months and checked the size like this:
dd if=audit_log_entries of=/tmp/entries

I notice that the copied file is 224 bytes.  Does that grow linearly?  A few years and I'll be at 4k?
If so, then maybe this should be designed as a different interface.

Also, the log is readable by anybody.  Should this be root only?

> +
> +	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);
> +}
> +
> +HPWMI_ATTR_RO(sure_start, audit_log_entry_count);
> +HPWMI_ATTR_RO(sure_start, audit_log_entries);
> +
> +static struct attribute *sure_start_attrs[] = {
> +	&sure_start_audit_log_entry_count.attr,
> +	&sure_start_audit_log_entries.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group sure_start_group = {
> +	.name = "sure_start",
> +	.attrs = sure_start_attrs,
> +};
> +
>  static DEVICE_ATTR_RO(display);
>  static DEVICE_ATTR_RO(hddtemp);
>  static DEVICE_ATTR_RW(als);
> @@ -942,6 +1049,7 @@ static const struct attribute_group hp_wmi_group =
> {
>  static const struct attribute_group *hp_wmi_groups[] = {
>  	&hp_wmi_group,
>  	&spm_group,
> +	&sure_start_group,
>  	NULL,
>  };
> 
> --
> 2.25.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-04 21:59   ` Limonciello, Mario
@ 2022-04-05 11:54     ` Hans de Goede
  2022-04-05 16:52       ` Jorge Lopez
  0 siblings, 1 reply; 25+ messages in thread
From: Hans de Goede @ 2022-04-05 11:54 UTC (permalink / raw)
  To: Limonciello, Mario, Jorge Lopez, platform-driver-x86

Hi,

On 4/4/22 23:59, Limonciello, Mario wrote:
> [Public]
> 
> 
> 
>> -----Original Message-----
>> From: Jorge Lopez <jorgealtxwork@gmail.com>
>> Sent: Monday, April 4, 2022 15:36
>> To: platform-driver-x86@vger.kernel.org
>> Subject: [PATCH v1 5/6] Sure Admin Security Feature
>>
>> 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. Behind the scenes, Sure Admin uses Secure Platform
>> Management (SPM) and WMI
>>
>> 'settings' is a file associated with Sure Admin. BIOS settings can be
>> read or written through the Sure Admin settings file in sysfs
>>
>> 	/sys/devices/platform/hp-wmi/sure_admin/settings
>>
>> 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"
>> 		]
>> 	}
>>
> 
> This sounds like it has re-invented /sys/class/firmware-attributes.
> 
> Shouldn't you adopt that API?

I fully agree. Jorge as I already indicated in our off-list
conversation when you initially started working on this
feature, we already have a standardized API for querying/changing
BIOS settings from within Linux:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/ABI/testing/sysfs-class-firmware-attributes

and any new code (such as this patch) which implements BIOS
setting changing MUST follow this standardized API (extending
it where necessary).

I'm sorry but this patch is not acceptable in its current form,
it needs to be *completely rewritten* to implement:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/ABI/testing/sysfs-class-firmware-attributes

See:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/platform/x86/dell/dell-wmi-sysman
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/platform/x86/think-lmi.c

for example code / for 2 drivers from other vendors already
implementing this.

The same applies to the:

"[PATCH v1 3/6] Secure Platform Management Security Feature"

this needs to be implemented as
a /sys/class/firmware-attributes/*/authentication/
authentication method, see for example these Lenovo specific
addition to the /sys/class/firmware-attributes/*/authentication/
userspace API for similar functionality on Lenovo Think* devices:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=06384573a3e8335ac6797577e545c33dbf91b490

I'll merge patches 1-2 sometime this week since those are
fine and it will be good to have those "out of the way",
but the rest of the series will need to be rewritten
taken the above comments into account.

Regards,

Hans










> 
>> This feature requires "Update hp_wmi_group to simplify feature
>> addition" patch.
>>
>> All changes were validated on a HP ZBook Workstation,
>> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
>>
>> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
>>
>> ---
>> Based on the latest platform-drivers-x86.git/for-next
>> ---
>>  drivers/platform/x86/hp-wmi.c | 977
>> ++++++++++++++++++++++++++++++++++
>>  1 file changed, 977 insertions(+)
>>
>> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
>> index 918e3eaf1b67..b72ca18b77a6 100644
>> --- a/drivers/platform/x86/hp-wmi.c
>> +++ b/drivers/platform/x86/hp-wmi.c
>> @@ -27,6 +27,7 @@
>>  #include <linux/rfkill.h>
>>  #include <linux/string.h>
>>  #include <linux/dmi.h>
>> +#include <linux/nls.h>
>>
>>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
>>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
>> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-
>> 3D44E2C707E4");
>>
>>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
>>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
>> +
>>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
>>
>> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-6A1B8106F83C"
>> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
>> E293ADB9BF05"
>> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-
>> 4A3C09E75133"
>> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
>> 7045CB4DA745"
>> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
>> 015176049E2D"
>> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-
>> C7CB9B4B8D5E"
>> +
>>  /* DMI board names of devices that should use the omen specific path for
>>   * thermal profiles.
>>   * This was obtained by taking a look in the windows omen command center
>> @@ -1025,6 +1034,973 @@ static const struct attribute_group
>> sure_start_group = {
>>  	.attrs = sure_start_attrs,
>>  };
>>
>> +
>> +static 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;
>> +	int  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));
>> +		ret = kstrtoint(tmp, 16, &ch);
>> +		if (ret) {
>> +			new_len = 0;
>> +			break;
>> +		}
>> +
>> +		if (ch == '\\')
>> +			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;
>> +	}
>> +
>> +	if (ret)
>> +		kfree(new_str);
>> +	return ret;
>> +}
>> +
>> +/*
>> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and instance
>> + *
>> + * @guid:	GUID associated with the ACPI list of managed objects
>> + * @instance:	Instance index to query on the ACPI list
>> + * @obj:	The output ACPI object of type ACPI_TYPE_PACKAGE
>> + *		or ACPI_TYPE_BUFFER (freed by the callee)
>> + *
>> + * Returns	zero on success.  Otherwise,an error inherited from
>> + *		wmi_query_block(). It returns a obj by parameter if
>> + *		the query returned object of type buffer or package,
>> + *		otherwise, a null obj is returned.
>> + *
>> + * Note: obj should be freed by the callee once it is finished working with it
>> + */
>> +static int hp_wmi_get_setting_object(char *guid, int instance,
>> +				union acpi_object **obj)
>> +{
>> +	struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL
>> };
>> +	union acpi_object *tmp = NULL;
>> +	int ret;
>> +
>> +	ret = wmi_query_block(guid, instance, &output);
>> +	if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
>> +		tmp = output.pointer;
>> +		if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
>> ACPI_TYPE_PACKAGE)
>> +			*obj = output.pointer;
>> +		else {
>> +			kfree(tmp);
>> +			*obj = NULL;
>> +		}
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +
>> +static 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;
>> +
>> +	if (size == 0)
>> +		goto cleanup_exit;
>> +
>> +	for (i = 0; i < size; i++)
>> +		if (ptr[i] == '\\')
>> +			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);
>> +
>> +	if (escape == 0) {
>> +		ptr += (ptrlen / 2);
>> +		goto cleanup_exit;
>> +	}
>> +	/*
>> +	 * Convert escape characters only when found
>> +	 */
>> +	for (i = 0; i < size; i++) {
>> +		if (*ptr == '\\')
>> +			output[i++] = '\\';
>> +		output[i] = *ptr;
>> +		ptr++;
>> +	}
>> +
>> +cleanup_exit:
>> +	*buffer = ptr;
>> +	return 0;
>> +}
>> +
>> +static int get_integer_from_buffer(int **buffer, int *integer)
>> +{
>> +	int *ptr = PTR_ALIGN(*buffer, 4);
>> +	*integer = *(ptr++);
>> +	*buffer = ptr;
>> +	return 0;
>> +}
>> +
>> +
>> +// Sure Admin functions
>> +enum hp_wmi_data_type {
>> +	HPWMI_STRING_TYPE,
>> +	HPWMI_INTEGER_TYPE,
>> +	HPWMI_ENUMERATION_TYPE,
>> +	HPWMI_ORDEREDLIST_TYPE,
>> +	HPWMI_PASSWORD_TYPE,
>> +};
>> +
>> +#define HP_WMI_COMMON_ELEMENTS	\
>> +	"Name",	\
>> +	"Value",	\
>> +	"Path",	\
>> +	"IsReadOnly",	\
>> +	"DisplayInUI",	\
>> +	"RequiresPhysicalPresence",	\
>> +	"Sequence",	\
>> +	"PrerequisiteSize",	\
>> +	"SecurityLevel"
>> +
>> +const char *hp_wmi_string_elements[] = {
>> +	HP_WMI_COMMON_ELEMENTS,
>> +	"MinLength",
>> +	"MaxLength"
>> +};
>> +
>> +const char *hp_wmi_integer_elements[] = {
>> +	HP_WMI_COMMON_ELEMENTS,
>> +	"LowerBound",
>> +	"UpperBound",
>> +	"IntValue"
>> +};
>> +
>> +const char *hp_wmi_enumeration_elements[] = {
>> +	HP_WMI_COMMON_ELEMENTS,
>> +	"CurrentValue",
>> +	"Size"
>> +};
>> +
>> +const char *hp_wmi_orderedlist_elements[] = {
>> +	HP_WMI_COMMON_ELEMENTS,
>> +	"Size"
>> +};
>> +
>> +const char *hp_wmi_password_elements[] = {
>> +	HP_WMI_COMMON_ELEMENTS,
>> +	"MinLength",
>> +	"MaxLength",
>> +	"Size",
>> +	"SupportedEncoding",
>> +	"IsSet"
>> +};
>> +
>> +const char **hp_wmi_elements[] = {
>> +	hp_wmi_string_elements,
>> +	hp_wmi_integer_elements,
>> +	hp_wmi_enumeration_elements,
>> +	hp_wmi_orderedlist_elements,
>> +	hp_wmi_password_elements
>> +};
>> +
>> +const int hp_wmi_elements_count[] = {
>> +	ARRAY_SIZE(hp_wmi_string_elements),
>> +	ARRAY_SIZE(hp_wmi_integer_elements),
>> +	ARRAY_SIZE(hp_wmi_enumeration_elements),
>> +	ARRAY_SIZE(hp_wmi_orderedlist_elements),
>> +	ARRAY_SIZE(hp_wmi_password_elements)
>> +};
>> +
>> +const char *hp_wmi_classes[] = {
>> +	"HPBIOS_BIOSString",
>> +	"HPBIOS_BIOSInteger",
>> +	"HPBIOS_BIOSEnumeration",
>> +	"HPBIOS_BIOSOrderedList",
>> +	"HPBIOS_BIOSPassword"
>> +};
>> +
>> +static DEFINE_MUTEX(buf_mutex);
>> +static int settings_buffer_size;
>> +static int buf_alloc_size;
>> +static char *hp_bios_settings_buffer;
>> +
>> +
>> +static int append_package_elements_to_buffer(union acpi_object *obj,
>> +					     char *buf, int alloc_size, enum
>> hp_wmi_data_type type)
>> +{
>> +	int i;
>> +	union acpi_object *pobj = NULL;
>> +	char *value = NULL;
>> +	int value_len;
>> +	char *tmpstr = NULL;
>> +	char *part_tmp = NULL;
>> +	int tmp_len = 0;
>> +	char *part = NULL;
>> +	int status = 0;
>> +	int size = 0;
>> +	int buf_size;
>> +
>> +	if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
>> +		return -EINVAL;
>> +
>> +	if (obj->type != ACPI_TYPE_PACKAGE)
>> +		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]);
>> +
>> +	for (i = 0; i < 3; i++) {
>> +		pobj = &(obj->package.elements[i]);
>> +		if (pobj->type == ACPI_TYPE_STRING) {
>> +			status = convert_hexstr_to_str(&pobj-
>>> string.pointer,
>> +						       pobj->string.length,
>> &value, &value_len);
>> +			if (ACPI_FAILURE(status))
>> +				continue;
>> +			/*
>> +			 * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
>> since
>> +			 * 'CurrentValue' is reported.
>> +			 */
>> +			if (type != HPWMI_ENUMERATION_TYPE || i != 1)
>> +				buf_size = snprintf(buf, alloc_size,
>> +						    "%s\t\"%s\": \"%s\",\n",
>> +						    buf,
>> +
>> hp_wmi_elements[type][i], value);
>> +
>> +		}
>> +		kfree(value);
>> +		value = NULL;
>> +	}
>> +
>> +	for (i = 3; i < hp_wmi_elements_count[type]; i++) {
>> +		pobj = &(obj->package.elements[i]);
>> +
>> +		if (type == HPWMI_ENUMERATION_TYPE &&
>> +		    i == 9 &&
>> +		    pobj->type == ACPI_TYPE_STRING) {
>> +			/*
>> +			 * Report "CurrentValue" as "Value"
>> +			 */
>> +			status = convert_hexstr_to_str(&pobj-
>>> string.pointer,
>> +						       pobj->string.length,
>> +						       &value, &value_len);
>> +			if (ACPI_FAILURE(status))
>> +				continue;
>> +
>> +			buf_size = snprintf(buf, alloc_size,
>> +					    "%s\t\"Value\": \"%s\",\n",
>> +					    buf, value);
>> +			kfree(value);
>> +			value = NULL;
>> +
>> +		} else if (type == HPWMI_PASSWORD_TYPE &&
>> +			   i == 12 &&
>> +			   pobj->type == ACPI_TYPE_STRING) {
>> +			/*
>> +			 * Report list of "SupportEncoding"
>> +			 *
>> +			 *	"SupportedEncoding": [
>> +			 *		"utf-16"
>> +			 *	],
>> +			 *
>> +			 */
>> +
>> +			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
>> +					    buf, hp_wmi_elements[type][i]);
>> +			while (size--) {
>> +				pobj = &(obj->package.elements[i]);
>> +				status = convert_hexstr_to_str(&pobj-
>>> string.pointer,
>> +							       pobj-
>>> string.length,
>> +							       &value,
>> &value_len);
>> +				if (ACPI_FAILURE(status))
>> +					continue;
>> +
>> +				if (size) {
>> +					buf_size = snprintf(buf, alloc_size,
>> +							    "%s\t\t\"%s\",\n",
>> buf, value);
>> +					i++;
>> +				} else
>> +					buf_size = snprintf(buf, alloc_size,
>> +							    "%s\t\t\"%s\"\n",
>> buf, value);
>> +
>> +				kfree(value);
>> +				value = NULL;
>> +
>> +			}
>> +			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>> +			continue;
>> +
>> +		} else if (pobj->type == ACPI_TYPE_INTEGER) {
>> +			/*
>> +			 * Report "PrerequisiteSize" and "Size" values
>> +			 *	...
>> +			 *	"PrerequisiteSize": 1,
>> +			 *	...
>> +			 *	"Size": 2,
>> +			 *	...
>> +			 */
>> +			if (i == 7)
>> +				size = pobj->integer.value;
>> +			else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
>> 9)
>> +				size = pobj->integer.value;
>> +			else if (type == HPWMI_ENUMERATION_TYPE && i
>> == 10)
>> +				size = pobj->integer.value;
>> +			else if (type == HPWMI_PASSWORD_TYPE && i ==
>> 11)
>> +				size = pobj->integer.value;
>> +
>> +			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
>> %lld,\n", buf,
>> +					    hp_wmi_elements[type][i], pobj-
>>> integer.value);
>> +		}
>> +	}
>> +
>> +	if (type == HPWMI_ENUMERATION_TYPE) {
>> +		buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
>> [\n", buf);
>> +		for (i = 0; i < size; i++) {
>> +			pobj = &(obj->package.elements[i +
>> hp_wmi_elements_count[type]]);
>> +
>> +			status = convert_hexstr_to_str(&pobj-
>>> string.pointer,
>> +						       pobj->string.length,
>> +						       &value, &value_len);
>> +			if (ACPI_FAILURE(status))
>> +				break;
>> +
>> +			/*
>> +			 * Report list of "PossibleValues" of size
>> +			 * "Size"
>> +			 *	...
>> +			 *	"Size": 2,
>> +			 *	"PossibleValues": [
>> +			 *			"Disable",
>> +			 *			"Enable"]
>> +			 */
>> +			if (i == (size - 1))
>> +				buf_size = snprintf(buf, alloc_size,
>> +						    "%s\t\t\"%s\"\n", buf,
>> value);
>> +			else
>> +				buf_size = snprintf(buf, alloc_size,
>> +						    "%s\t\t\"%s\",\n", buf,
>> value);
>> +			kfree(value);
>> +			value = NULL;
>> +		}
>> +		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>> +	}
>> +
>> +	if (type == HPWMI_ORDEREDLIST_TYPE) {
>> +		buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
>> buf);
>> +		if (size <= 0)
>> +			goto finish_ordered_list;
>> +
>> +		pobj = &(obj-
>>> package.elements[hp_wmi_elements_count[type]]);
>> +		status = convert_hexstr_to_str(&pobj->string.pointer,
>> +					       pobj->string.length, &value,
>> &value_len);
>> +		if (ACPI_FAILURE(status))
>> +			goto finish_ordered_list;
>> +
>> +		/*
>> +		 * 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(&value, value_len, &tmpstr,
>> &tmp_len);
>> +		if (ACPI_FAILURE(status))
>> +			goto finish_ordered_list;
>> +
>> +		part_tmp = tmpstr;
>> +		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);
>> +		}
>> +	}
>> +
>> +finish_ordered_list:
>> +	if (type == HPWMI_ORDEREDLIST_TYPE)
>> +		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>> +
>> +	/*
>> +	 * remove trailing comma
>> +	 */
>> +	if (buf_size > 3)
>> +		buf[buf_size - 2] = ' ';
>> +
>> +	kfree(tmpstr);
>> +	kfree(value);
>> +	return snprintf(buf, alloc_size, "%s},\n", buf);
>> +}
>> +
>> +static int append_buffer_elements_to_buffer(union acpi_object *obj,
>> +					    char *buf, int alloc_size, enum
>> hp_wmi_data_type type)
>> +{
>> +	int buf_size;
>> +	int status;
>> +	char *str = NULL;
>> +	int i;
>> +	int j;
>> +	int integer;
>> +	int size = 0;
>> +
>> +	if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
>> +		return -EINVAL;
>> +
>> +	if (obj->type != ACPI_TYPE_BUFFER)
>> +		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]);
>> +
>> +	for (i = 0; i < 3; i++) {
>> +		status = get_string_from_buffer((u16 **)&obj-
>>> buffer.pointer, &str);
>> +		if (ACPI_SUCCESS(status)) {
>> +			/*
>> +			 * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
>> since
>> +			 * 'CurrentValue' is reported.
>> +			 */
>> +			if (type != HPWMI_ENUMERATION_TYPE || i != 1)
>> +				buf_size = snprintf(buf, alloc_size,
>> +						    "%s\t\"%s\": \"%s\",\n",
>> +						    buf,
>> +
>> hp_wmi_elements[type][i], str);
>> +		}
>> +		kfree(str);
>> +		str = NULL;
>> +
>> +	}
>> +
>> +	for (i = 3; i < hp_wmi_elements_count[type]; i++) {
>> +		if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
>> +			status = get_string_from_buffer((u16 **)&obj-
>>> buffer.pointer, &str);
>> +			if (ACPI_SUCCESS(status)) {
>> +				/*
>> +				 * Report "CurrentValue" as "Value"
>> +				 */
>> +				buf_size = snprintf(buf, alloc_size,
>> +						    "%s\t\"Value\": \"%s\",\n",
>> buf, str);
>> +			}
>> +			kfree(str);
>> +			str = NULL;
>> +			continue;
>> +
>> +		} else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
>> +			/*
>> +			 * Report list of "SupportEncoding"
>> +			 *
>> +			 *	"SupportedEncoding": [
>> +			 *		"utf-16"
>> +			 *	],
>> +			 *
>> +			 */
>> +
>> +			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
>> +					    buf, hp_wmi_elements[type][i]);
>> +			for (j = 0; j < size; j++) {
>> +				status = get_string_from_buffer((u16
>> **)&obj->buffer.pointer, &str);
>> +				if (ACPI_SUCCESS(status)) {
>> +					if (j == size - 1)
>> +						buf_size = snprintf(buf,
>> alloc_size,
>> +
>> "%s\t\t\"%s\"\n", buf, str);
>> +					else
>> +						buf_size = snprintf(buf,
>> alloc_size,
>> +
>> "%s\t\t\"%s\",\n", buf, str);
>> +				}
>> +				kfree(str);
>> +				str = NULL;
>> +			}
>> +			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>> +			continue;
>> +		}
>> +
>> +		size = 0;
>> +		status = get_integer_from_buffer((int **)&obj-
>>> buffer.pointer, &integer);
>> +		if (ACPI_SUCCESS(status)) {
>> +			/*
>> +			 * Report "PrerequisiteSize" and "Size" values
>> +			 *	...
>> +			 *	"PrerequisiteSize": 1,
>> +			 *	...
>> +			 *	"Size": 2,
>> +			 *	...
>> +			 */
>> +			if (i == 7)
>> +				size = integer;
>> +			else if (type == HPWMI_ENUMERATION_TYPE && i
>> == 10)
>> +				size = integer;
>> +			else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
>> 9)
>> +				size = integer;
>> +			else if (type == HPWMI_PASSWORD_TYPE && i ==
>> 11)
>> +				size = integer;
>> +
>> +			buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
>> %d,\n", buf,
>> +					    hp_wmi_elements[type][i],
>> integer);
>> +		}
>> +
>> +		if (size > 20)
>> +			pr_warn("%s exceeded the maximum number of
>> elements supported or data may be malformed\n",
>> +				hp_wmi_elements[type][i]);
>> +
>> +		if (ACPI_SUCCESS(status) && i == 7) {
>> +			buf_size = snprintf(buf, alloc_size,
>> "%s\t\"Prerequisites\": [\n", buf);
>> +			for (j = 0; j < size; j++) {
>> +				status = get_string_from_buffer((u16
>> **)&obj->buffer.pointer, &str);
>> +				if (ACPI_SUCCESS(status)) {
>> +					buf_size = snprintf(buf, alloc_size,
>> "%s\t\t\"%s\"", buf, str);
>> +
>> +					if (j == size - 1)
>> +						buf_size = snprintf(buf,
>> alloc_size, "%s\n", buf);
>> +					else
>> +						buf_size = snprintf(buf,
>> alloc_size, "%s,\n", buf);
>> +
>> +				}
>> +				kfree(str);
>> +				str = NULL;
>> +			}
>> +			buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>> +		}
>> +	}
>> +
>> +	if (type == HPWMI_ENUMERATION_TYPE || type ==
>> HPWMI_ORDEREDLIST_TYPE) {
>> +		if (type == HPWMI_ENUMERATION_TYPE)
>> +			buf_size = snprintf(buf, alloc_size,
>> "%s\t\"PossibleValues\": [\n", buf);
>> +		else
>> +			buf_size = snprintf(buf, alloc_size,
>> "%s\t\"Elements\": [\n", buf);
>> +
>> +		for (i = 0; i < size; i++) {
>> +			status = get_string_from_buffer((u16 **)&obj-
>>> buffer.pointer, &str);
>> +			if (ACPI_SUCCESS(status)) {
>> +				buf_size = snprintf(buf, alloc_size,
>> "%s\t\t\"%s\"", buf, str);
>> +
>> +				if (i == size - 1)
>> +					buf_size = snprintf(buf, alloc_size,
>> "%s\n", buf);
>> +				else
>> +					buf_size = snprintf(buf, alloc_size,
>> "%s,\n", buf);
>> +
>> +			}
>> +			kfree(str);
>> +			str = NULL;
>> +		}
>> +		buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>> +	}
>> +
>> +	/*
>> +	 * remove trailing comma
>> +	 */
>> +	if (buf_size > 3)
>> +		buf[buf_size - 2] = ' ';
>> +
>> +	return snprintf(buf, alloc_size, "%s},\n", buf);
>> +}
>> +
>> +static int hp_bios_settings_free_buffer(void)
>> +{
>> +	mutex_lock(&buf_mutex);
>> +	kfree(hp_bios_settings_buffer);
>> +	settings_buffer_size = 0;
>> +	buf_alloc_size = 0;
>> +	mutex_unlock(&buf_mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
>> +					   int *alloc_size,
>> +					   struct mutex *buf_mutex)
>> +{
>> +	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(buf_mutex);
>> +		new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
>> +		mutex_unlock(buf_mutex);
>> +		if (new_buf) {
>> +			mutex_lock(buf_mutex);
>> +			*buf = new_buf;
>> +			*alloc_size = ksize(new_buf);
>> +			mutex_unlock(buf_mutex);
>> +		} else {
>> +			hp_bios_settings_free_buffer();
>> +			ret = -ENOMEM;
>> +		}
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int append_settings_to_buffer(char *guid, int type, char **buf,
>> +				     int *buf_size, int *alloc_size,
>> +				     struct mutex *buf_mutex)
>> +{
>> +	union acpi_object *obj = NULL;
>> +	int ret = 0;
>> +	int status = 0;
>> +	int instance = 0;
>> +
>> +	/*
>> +	 * Query all the instances until to receive a AE_BAD_PARAMETER
>> +	 */
>> +	do {
>> +		ret = hp_wmi_get_setting_object(guid, instance++, &obj);
>> +		if (ACPI_SUCCESS(ret) && obj != NULL) {
>> +			status = 0;
>> +			if (obj->type == ACPI_TYPE_PACKAGE) {
>> +				mutex_lock(buf_mutex);
>> +				status =
>> append_package_elements_to_buffer(obj,
>> +							*buf, *alloc_size,
>> type);
>> +				if (status > 0)
>> +					*buf_size = status;
>> +				mutex_unlock(buf_mutex);
>> +
>> +			} else if (obj->type == ACPI_TYPE_BUFFER) {
>> +				mutex_lock(buf_mutex);
>> +				status =
>> append_buffer_elements_to_buffer(obj,
>> +							*buf, *alloc_size,
>> type);
>> +				if (status > 0)
>> +					*buf_size = status;
>> +				mutex_unlock(buf_mutex);
>> +
>> +			} else
>> +				pr_warn("The retrieved object type(%d) is
>> not supported yet\n",
>> +					obj->type);
>> +
>> +			ret = hp_bios_settings_realloc_buffer(buf, buf_size,
>> alloc_size, buf_mutex);
>> +		}
>> +
>> +		kfree(obj);
>> +		obj = NULL;
>> +
>> +	} while (ACPI_SUCCESS(ret));
>> +
>> +	/*
>> +	 * AE_BAD_PARAMETER means the loop ended by exhaustion
>> +	 */
>> +	if (ret == AE_BAD_PARAMETER)
>> +		ret = 0;
>> +
>> +	return ret;
>> +}
>> +
>> +static int hp_bios_settings_fill_buffer(void)
>> +{
>> +	int status = 0;
>> +	int initial_buffer_size = 20 * PAGE_SIZE;
>> +
>> +	mutex_lock(&buf_mutex);
>> +	hp_bios_settings_buffer = kmalloc(initial_buffer_size, GFP_KERNEL);
>> +	mutex_unlock(&buf_mutex);
>> +	if (!hp_bios_settings_buffer)
>> +		return -ENOMEM;
>> +
>> +	mutex_lock(&buf_mutex);
>> +	buf_alloc_size = ksize(hp_bios_settings_buffer);
>> +	settings_buffer_size = snprintf(hp_bios_settings_buffer,
>> +					buf_alloc_size, "[\n");
>> +	mutex_unlock(&buf_mutex);
>> +
>> +	status = append_settings_to_buffer(HPWMI_STRING_GUID,
>> +		HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
>> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
>> +	if (ACPI_FAILURE(status))
>> +		pr_err("error 0x%x occurred retrieving string instances\n",
>> status);
>> +
>> +	status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
>> +		HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
>> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
>> +	if (ACPI_FAILURE(status))
>> +		pr_err("error 0x%x occurred retrieving integer instances\n",
>> status);
>> +
>> +	status = append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
>> +		HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
>> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
>> +	if (ACPI_FAILURE(status))
>> +		pr_err("error 0x%x occurred retrieving enumeration
>> instances\n", status);
>> +
>> +	status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
>> +		HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
>> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
>> +	if (ACPI_FAILURE(status))
>> +		pr_err("error 0x%x occurred retrieving ordered list
>> instances\n", status);
>> +
>> +	status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
>> +		HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
>> +		&settings_buffer_size, &buf_alloc_size, &buf_mutex);
>> +	if (ACPI_FAILURE(status))
>> +		pr_err("error 0x%x occurred retrieving password list
>> instances\n", status);
>> +
>> +	mutex_lock(&buf_mutex);
>> +	/*
>> +	 * remove trailing comma
>> +	 */
>> +	if (settings_buffer_size >= 3) {
>> +		if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
>> +			hp_bios_settings_buffer[settings_buffer_size - 2] = '
>> ';
>> +	}
>> +	settings_buffer_size = snprintf(hp_bios_settings_buffer,
>> +					buf_alloc_size, "%s]\n",
>> +					hp_bios_settings_buffer);
>> +	mutex_unlock(&buf_mutex);
>> +
>> +	return settings_buffer_size;
>> +}
>> +
>> +/*
>> + * sure_admin_settings_read - Return a formatted file with settings
>> + *                              and possible options read from BIOS
>> + *
>> + * @filp:  Pointer to file of settings read from BIOS
>> + * @kobj:  Pointer to a kernel object of things that show up as directory in
>> the sysfs filesystem.
>> + * @attr:  Pointer to list of read attributes
>> + * @buf:   Pointer to buffer
>> + * @off:   File current offset
>> + * @count: Buffer size
>> + *
>> + * Returns the count of unicode chars read if successful, otherwise
>> + *		-ENOMEM unable to allocate memory
>> + *		-EINVAL buffer not allocated or too small
>> + *
>> + */
>> +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 >= settings_buffer_size && settings_buffer_size > 0) {
>> +		hp_bios_settings_free_buffer();
>> +		return 0;
>> +	}
>> +
>> +	/* clear the buffer whenever the read starts from the first position
>> */
>> +	if (off == 0 && settings_buffer_size > 0)
>> +		hp_bios_settings_free_buffer();
>> +
>> +	if (settings_buffer_size == 0)
>> +		hp_bios_settings_fill_buffer();
>> +
>> +	mutex_lock(&buf_mutex);
>> +	ret = memory_read_from_buffer(buf, count, &off,
>> hp_bios_settings_buffer,
>> +				      settings_buffer_size);
>> +	mutex_unlock(&buf_mutex);
>> +
>> +	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
>> + */
>> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
>> +{
>> +	int len = strlen(str);
>> +
>> +	/*
>> +	 * Add null character when reading an empty string
>> +	 */
>> +	if (len == 0) {
>> +		*p++ = 2;
>> +		*p++ = (u8)0x00;
>> +		return p;
>> +	}
>> +	*p++ = len * 2;
>> +	utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
>> +	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
>> + */
>> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 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(HPWMI_SETBIOSSETTING_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;
>> +}
>> +
>> +/* Sure Admin Functions */
>> +
>> +#define UTF_PREFIX			((unsigned char *)"<utf-16/>")
>> +#define BEAM_PREFIX			((unsigned char
>> *)"<BEAM/>")
>> +
>> +/*
>> + * sure_admin_settings_write - Write the contents of a formatted file
>> + *                               with settings and performs the logic
>> + *                               to change any settings in BIOS.
>> + *
>> + * @filp:  Pointer to file of settings to be written to BIOS
>> + * @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 write operation
>> + * @buf:   Pointer to buffer
>> + * @off:   File current offset
>> + * @count: Buffer size
>> + *
>> + *
>> + * Returns the count of unicode characters written to BIOS if successful,
>> otherwise
>> + *		-ENOMEM unable to allocate memory
>> + *		-EINVAL buffer not allocated or too small
>> + *
>> + */
>> +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;
>> +	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 out_free;
>> +	}
>> +	tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>> +	part = strsep(&buf, ",");
>> +	if (!part) {
>> +		status = -EINVAL;
>> +		goto out_free;
>> +	}
>> +
>> +	/* Add extra buffer space when encountering an empty string */
>> +	if (!strlen(part))
>> +		buffer_size += sizeof(unsigned short);
>> +	tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>> +	part = strsep(&buf, ",");
>> +	if (!part) {
>> +		status = -EINVAL;
>> +		goto out_free;
>> +	}
>> +	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 out_free;
>> +
>> +		tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>> +		kfree(part);
>> +	}
>> +
>> +	part = strsep(&buf, ",");
>> +	if (part) {
>> +		status = -EINVAL;
>> +		goto out_free;
>> +	}
>> +	status = hp_wmi_set_bios_setting(buffer, buffer_size);
>> +	if (ACPI_FAILURE(status))
>> +		status = -EINVAL;
>> +
>> +out_free:
>> +	kfree(buffer);
>> +	if (ACPI_SUCCESS(status))
>> +		return count;
>> +	return status;
>> +}
>> +
>> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
>> +
>> +static struct bin_attribute *sure_admin_binattrs[] = {
>> +	&sure_admin_settings,
>> +	NULL,
>> +};
>> +
>> +static const struct attribute_group sure_admin_group = {
>> +	.name = "sure_admin",
>> +	.bin_attrs = sure_admin_binattrs,
>> +};
>> +
>>  static DEVICE_ATTR_RO(display);
>>  static DEVICE_ATTR_RO(hddtemp);
>>  static DEVICE_ATTR_RW(als);
>> @@ -1050,6 +2026,7 @@ static const struct attribute_group
>> *hp_wmi_groups[] = {
>>  	&hp_wmi_group,
>>  	&spm_group,
>>  	&sure_start_group,
>> +	&sure_admin_group,
>>  	NULL,
>>  };
>>
>> --
>> 2.25.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-05 11:54     ` Hans de Goede
@ 2022-04-05 16:52       ` Jorge Lopez
  2022-04-05 17:13         ` Limonciello, Mario
  0 siblings, 1 reply; 25+ messages in thread
From: Jorge Lopez @ 2022-04-05 16:52 UTC (permalink / raw)
  To: Hans de Goede; +Cc: Limonciello, Mario, platform-driver-x86

[-- Attachment #1: Type: text/plain, Size: 47194 bytes --]

Hi Hans,

On Tue, Apr 5, 2022 at 6:54 AM Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 4/4/22 23:59, Limonciello, Mario wrote:
> > [Public]
> >
> >
> >
> >> -----Original Message-----
> >> From: Jorge Lopez <jorgealtxwork@gmail.com>
> >> Sent: Monday, April 4, 2022 15:36
> >> To: platform-driver-x86@vger.kernel.org
> >> Subject: [PATCH v1 5/6] Sure Admin Security Feature
> >>
> >> 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. Behind the scenes, Sure Admin uses Secure Platform
> >> Management (SPM) and WMI
> >>
> >> 'settings' is a file associated with Sure Admin. BIOS settings can be
> >> read or written through the Sure Admin settings file in sysfs
> >>
> >>      /sys/devices/platform/hp-wmi/sure_admin/settings
> >>
> >> 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"
> >>              ]
> >>      }
> >>
> >
> > This sounds like it has re-invented /sys/class/firmware-attributes.
> >
> > Shouldn't you adopt that API?
>
> I fully agree. Jorge as I already indicated in our off-list
> conversation when you initially started working on this
> feature, we already have a standardized API for querying/changing
> BIOS settings from within Linux:
>

I agree that changing the BIOS settings from within Linux could
utilize the new methodology,  I will need to look closely at the
requirements before I can proceed to make the changes.
Keep in mind authentication of the values is done by BIOS.  No Linux
process validates any data name, value, or auth token; only BIOS.  All
data written to the sysfs file is not validated, it is just forward to
BIOS.  See spm_kek_store and spm_sk_store functions.
One point I must make clear when updating BIOS settings.  any  NOT
read-only BIOS settings can be changed by the application at any time.
   This list of settings changes from one system to another.

I am in disagreement with reading the settings.  hp-wmi does not read
one value at a time. It reads all values exposed by BIOS.  See
attached sample output.
The method for how all BIOS settings are reported needs to match the
method how Windows products do it.  It is a requirement to start
migrating customers from Windows to Linux while minimizing how BIOS
data is reported.

I will investigate the new API and bring it to the team's attention.

> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/ABI/testing/sysfs-class-firmware-attributes
>
> and any new code (such as this patch) which implements BIOS
> setting changing MUST follow this standardized API (extending
> it where necessary).
>
> I'm sorry but this patch is not acceptable in its current form,
> it needs to be *completely rewritten* to implement:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/ABI/testing/sysfs-class-firmware-attributes
>
> See:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/platform/x86/dell/dell-wmi-sysman
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/platform/x86/think-lmi.c
>
> for example code / for 2 drivers from other vendors already
> implementing this.
>
> The same applies to the:
>
> "[PATCH v1 3/6] Secure Platform Management Security Feature"
>
> this needs to be implemented as
> a /sys/class/firmware-attributes/*/authentication/
> authentication method, see for example these Lenovo specific
> addition to the /sys/class/firmware-attributes/*/authentication/
> userspace API for similar functionality on Lenovo Think* devices:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=06384573a3e8335ac6797577e545c33dbf91b490
>
> I'll merge patches 1-2 sometime this week since those are
> fine and it will be good to have those "out of the way",
> but the rest of the series will need to be rewritten
> taken the above comments into account.

v1-0003-Sure-Start-Security-Feature.patch  reports the number of audit
logs available and reports them when read.    it does not read/write
BIOS settings hence it does not fall within the same category as
patches v1-0002-Secure-Platform-Management-Security-Feature.patch and
v1-0004-Sure-Admin-Security-Feature.patch
Do you agree?

>
> Regards,
>
> Hans
>
>
>
>
>
>
>
>
>
>
> >
> >> This feature requires "Update hp_wmi_group to simplify feature
> >> addition" patch.
> >>
> >> All changes were validated on a HP ZBook Workstation,
> >> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> >>
> >> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> >>
> >> ---
> >> Based on the latest platform-drivers-x86.git/for-next
> >> ---
> >>  drivers/platform/x86/hp-wmi.c | 977
> >> ++++++++++++++++++++++++++++++++++
> >>  1 file changed, 977 insertions(+)
> >>
> >> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
> >> index 918e3eaf1b67..b72ca18b77a6 100644
> >> --- a/drivers/platform/x86/hp-wmi.c
> >> +++ b/drivers/platform/x86/hp-wmi.c
> >> @@ -27,6 +27,7 @@
> >>  #include <linux/rfkill.h>
> >>  #include <linux/string.h>
> >>  #include <linux/dmi.h>
> >> +#include <linux/nls.h>
> >>
> >>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
> >>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
> >> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-
> >> 3D44E2C707E4");
> >>
> >>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
> >>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
> >> +
> >>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
> >>
> >> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-6A1B8106F83C"
> >> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
> >> E293ADB9BF05"
> >> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-
> >> 4A3C09E75133"
> >> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
> >> 7045CB4DA745"
> >> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
> >> 015176049E2D"
> >> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-
> >> C7CB9B4B8D5E"
> >> +
> >>  /* DMI board names of devices that should use the omen specific path for
> >>   * thermal profiles.
> >>   * This was obtained by taking a look in the windows omen command center
> >> @@ -1025,6 +1034,973 @@ static const struct attribute_group
> >> sure_start_group = {
> >>      .attrs = sure_start_attrs,
> >>  };
> >>
> >> +
> >> +static 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;
> >> +    int  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));
> >> +            ret = kstrtoint(tmp, 16, &ch);
> >> +            if (ret) {
> >> +                    new_len = 0;
> >> +                    break;
> >> +            }
> >> +
> >> +            if (ch == '\\')
> >> +                    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;
> >> +    }
> >> +
> >> +    if (ret)
> >> +            kfree(new_str);
> >> +    return ret;
> >> +}
> >> +
> >> +/*
> >> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and instance
> >> + *
> >> + * @guid:   GUID associated with the ACPI list of managed objects
> >> + * @instance:       Instance index to query on the ACPI list
> >> + * @obj:    The output ACPI object of type ACPI_TYPE_PACKAGE
> >> + *          or ACPI_TYPE_BUFFER (freed by the callee)
> >> + *
> >> + * Returns  zero on success.  Otherwise,an error inherited from
> >> + *          wmi_query_block(). It returns a obj by parameter if
> >> + *          the query returned object of type buffer or package,
> >> + *          otherwise, a null obj is returned.
> >> + *
> >> + * Note: obj should be freed by the callee once it is finished working with it
> >> + */
> >> +static int hp_wmi_get_setting_object(char *guid, int instance,
> >> +                            union acpi_object **obj)
> >> +{
> >> +    struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL
> >> };
> >> +    union acpi_object *tmp = NULL;
> >> +    int ret;
> >> +
> >> +    ret = wmi_query_block(guid, instance, &output);
> >> +    if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
> >> +            tmp = output.pointer;
> >> +            if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
> >> ACPI_TYPE_PACKAGE)
> >> +                    *obj = output.pointer;
> >> +            else {
> >> +                    kfree(tmp);
> >> +                    *obj = NULL;
> >> +            }
> >> +    }
> >> +
> >> +    return ret;
> >> +}
> >> +
> >> +
> >> +static 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;
> >> +
> >> +    if (size == 0)
> >> +            goto cleanup_exit;
> >> +
> >> +    for (i = 0; i < size; i++)
> >> +            if (ptr[i] == '\\')
> >> +                    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);
> >> +
> >> +    if (escape == 0) {
> >> +            ptr += (ptrlen / 2);
> >> +            goto cleanup_exit;
> >> +    }
> >> +    /*
> >> +     * Convert escape characters only when found
> >> +     */
> >> +    for (i = 0; i < size; i++) {
> >> +            if (*ptr == '\\')
> >> +                    output[i++] = '\\';
> >> +            output[i] = *ptr;
> >> +            ptr++;
> >> +    }
> >> +
> >> +cleanup_exit:
> >> +    *buffer = ptr;
> >> +    return 0;
> >> +}
> >> +
> >> +static int get_integer_from_buffer(int **buffer, int *integer)
> >> +{
> >> +    int *ptr = PTR_ALIGN(*buffer, 4);
> >> +    *integer = *(ptr++);
> >> +    *buffer = ptr;
> >> +    return 0;
> >> +}
> >> +
> >> +
> >> +// Sure Admin functions
> >> +enum hp_wmi_data_type {
> >> +    HPWMI_STRING_TYPE,
> >> +    HPWMI_INTEGER_TYPE,
> >> +    HPWMI_ENUMERATION_TYPE,
> >> +    HPWMI_ORDEREDLIST_TYPE,
> >> +    HPWMI_PASSWORD_TYPE,
> >> +};
> >> +
> >> +#define HP_WMI_COMMON_ELEMENTS      \
> >> +    "Name", \
> >> +    "Value",        \
> >> +    "Path", \
> >> +    "IsReadOnly",   \
> >> +    "DisplayInUI",  \
> >> +    "RequiresPhysicalPresence",     \
> >> +    "Sequence",     \
> >> +    "PrerequisiteSize",     \
> >> +    "SecurityLevel"
> >> +
> >> +const char *hp_wmi_string_elements[] = {
> >> +    HP_WMI_COMMON_ELEMENTS,
> >> +    "MinLength",
> >> +    "MaxLength"
> >> +};
> >> +
> >> +const char *hp_wmi_integer_elements[] = {
> >> +    HP_WMI_COMMON_ELEMENTS,
> >> +    "LowerBound",
> >> +    "UpperBound",
> >> +    "IntValue"
> >> +};
> >> +
> >> +const char *hp_wmi_enumeration_elements[] = {
> >> +    HP_WMI_COMMON_ELEMENTS,
> >> +    "CurrentValue",
> >> +    "Size"
> >> +};
> >> +
> >> +const char *hp_wmi_orderedlist_elements[] = {
> >> +    HP_WMI_COMMON_ELEMENTS,
> >> +    "Size"
> >> +};
> >> +
> >> +const char *hp_wmi_password_elements[] = {
> >> +    HP_WMI_COMMON_ELEMENTS,
> >> +    "MinLength",
> >> +    "MaxLength",
> >> +    "Size",
> >> +    "SupportedEncoding",
> >> +    "IsSet"
> >> +};
> >> +
> >> +const char **hp_wmi_elements[] = {
> >> +    hp_wmi_string_elements,
> >> +    hp_wmi_integer_elements,
> >> +    hp_wmi_enumeration_elements,
> >> +    hp_wmi_orderedlist_elements,
> >> +    hp_wmi_password_elements
> >> +};
> >> +
> >> +const int hp_wmi_elements_count[] = {
> >> +    ARRAY_SIZE(hp_wmi_string_elements),
> >> +    ARRAY_SIZE(hp_wmi_integer_elements),
> >> +    ARRAY_SIZE(hp_wmi_enumeration_elements),
> >> +    ARRAY_SIZE(hp_wmi_orderedlist_elements),
> >> +    ARRAY_SIZE(hp_wmi_password_elements)
> >> +};
> >> +
> >> +const char *hp_wmi_classes[] = {
> >> +    "HPBIOS_BIOSString",
> >> +    "HPBIOS_BIOSInteger",
> >> +    "HPBIOS_BIOSEnumeration",
> >> +    "HPBIOS_BIOSOrderedList",
> >> +    "HPBIOS_BIOSPassword"
> >> +};
> >> +
> >> +static DEFINE_MUTEX(buf_mutex);
> >> +static int settings_buffer_size;
> >> +static int buf_alloc_size;
> >> +static char *hp_bios_settings_buffer;
> >> +
> >> +
> >> +static int append_package_elements_to_buffer(union acpi_object *obj,
> >> +                                         char *buf, int alloc_size, enum
> >> hp_wmi_data_type type)
> >> +{
> >> +    int i;
> >> +    union acpi_object *pobj = NULL;
> >> +    char *value = NULL;
> >> +    int value_len;
> >> +    char *tmpstr = NULL;
> >> +    char *part_tmp = NULL;
> >> +    int tmp_len = 0;
> >> +    char *part = NULL;
> >> +    int status = 0;
> >> +    int size = 0;
> >> +    int buf_size;
> >> +
> >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> >> +            return -EINVAL;
> >> +
> >> +    if (obj->type != ACPI_TYPE_PACKAGE)
> >> +            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]);
> >> +
> >> +    for (i = 0; i < 3; i++) {
> >> +            pobj = &(obj->package.elements[i]);
> >> +            if (pobj->type == ACPI_TYPE_STRING) {
> >> +                    status = convert_hexstr_to_str(&pobj-
> >>> string.pointer,
> >> +                                                   pobj->string.length,
> >> &value, &value_len);
> >> +                    if (ACPI_FAILURE(status))
> >> +                            continue;
> >> +                    /*
> >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> >> since
> >> +                     * 'CurrentValue' is reported.
> >> +                     */
> >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> >> +                            buf_size = snprintf(buf, alloc_size,
> >> +                                                "%s\t\"%s\": \"%s\",\n",
> >> +                                                buf,
> >> +
> >> hp_wmi_elements[type][i], value);
> >> +
> >> +            }
> >> +            kfree(value);
> >> +            value = NULL;
> >> +    }
> >> +
> >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> >> +            pobj = &(obj->package.elements[i]);
> >> +
> >> +            if (type == HPWMI_ENUMERATION_TYPE &&
> >> +                i == 9 &&
> >> +                pobj->type == ACPI_TYPE_STRING) {
> >> +                    /*
> >> +                     * Report "CurrentValue" as "Value"
> >> +                     */
> >> +                    status = convert_hexstr_to_str(&pobj-
> >>> string.pointer,
> >> +                                                   pobj->string.length,
> >> +                                                   &value, &value_len);
> >> +                    if (ACPI_FAILURE(status))
> >> +                            continue;
> >> +
> >> +                    buf_size = snprintf(buf, alloc_size,
> >> +                                        "%s\t\"Value\": \"%s\",\n",
> >> +                                        buf, value);
> >> +                    kfree(value);
> >> +                    value = NULL;
> >> +
> >> +            } else if (type == HPWMI_PASSWORD_TYPE &&
> >> +                       i == 12 &&
> >> +                       pobj->type == ACPI_TYPE_STRING) {
> >> +                    /*
> >> +                     * Report list of "SupportEncoding"
> >> +                     *
> >> +                     *      "SupportedEncoding": [
> >> +                     *              "utf-16"
> >> +                     *      ],
> >> +                     *
> >> +                     */
> >> +
> >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> >> +                                        buf, hp_wmi_elements[type][i]);
> >> +                    while (size--) {
> >> +                            pobj = &(obj->package.elements[i]);
> >> +                            status = convert_hexstr_to_str(&pobj-
> >>> string.pointer,
> >> +                                                           pobj-
> >>> string.length,
> >> +                                                           &value,
> >> &value_len);
> >> +                            if (ACPI_FAILURE(status))
> >> +                                    continue;
> >> +
> >> +                            if (size) {
> >> +                                    buf_size = snprintf(buf, alloc_size,
> >> +                                                        "%s\t\t\"%s\",\n",
> >> buf, value);
> >> +                                    i++;
> >> +                            } else
> >> +                                    buf_size = snprintf(buf, alloc_size,
> >> +                                                        "%s\t\t\"%s\"\n",
> >> buf, value);
> >> +
> >> +                            kfree(value);
> >> +                            value = NULL;
> >> +
> >> +                    }
> >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >> +                    continue;
> >> +
> >> +            } else if (pobj->type == ACPI_TYPE_INTEGER) {
> >> +                    /*
> >> +                     * Report "PrerequisiteSize" and "Size" values
> >> +                     *      ...
> >> +                     *      "PrerequisiteSize": 1,
> >> +                     *      ...
> >> +                     *      "Size": 2,
> >> +                     *      ...
> >> +                     */
> >> +                    if (i == 7)
> >> +                            size = pobj->integer.value;
> >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> >> 9)
> >> +                            size = pobj->integer.value;
> >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> >> == 10)
> >> +                            size = pobj->integer.value;
> >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> >> 11)
> >> +                            size = pobj->integer.value;
> >> +
> >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> >> %lld,\n", buf,
> >> +                                        hp_wmi_elements[type][i], pobj-
> >>> integer.value);
> >> +            }
> >> +    }
> >> +
> >> +    if (type == HPWMI_ENUMERATION_TYPE) {
> >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
> >> [\n", buf);
> >> +            for (i = 0; i < size; i++) {
> >> +                    pobj = &(obj->package.elements[i +
> >> hp_wmi_elements_count[type]]);
> >> +
> >> +                    status = convert_hexstr_to_str(&pobj-
> >>> string.pointer,
> >> +                                                   pobj->string.length,
> >> +                                                   &value, &value_len);
> >> +                    if (ACPI_FAILURE(status))
> >> +                            break;
> >> +
> >> +                    /*
> >> +                     * Report list of "PossibleValues" of size
> >> +                     * "Size"
> >> +                     *      ...
> >> +                     *      "Size": 2,
> >> +                     *      "PossibleValues": [
> >> +                     *                      "Disable",
> >> +                     *                      "Enable"]
> >> +                     */
> >> +                    if (i == (size - 1))
> >> +                            buf_size = snprintf(buf, alloc_size,
> >> +                                                "%s\t\t\"%s\"\n", buf,
> >> value);
> >> +                    else
> >> +                            buf_size = snprintf(buf, alloc_size,
> >> +                                                "%s\t\t\"%s\",\n", buf,
> >> value);
> >> +                    kfree(value);
> >> +                    value = NULL;
> >> +            }
> >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >> +    }
> >> +
> >> +    if (type == HPWMI_ORDEREDLIST_TYPE) {
> >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
> >> buf);
> >> +            if (size <= 0)
> >> +                    goto finish_ordered_list;
> >> +
> >> +            pobj = &(obj-
> >>> package.elements[hp_wmi_elements_count[type]]);
> >> +            status = convert_hexstr_to_str(&pobj->string.pointer,
> >> +                                           pobj->string.length, &value,
> >> &value_len);
> >> +            if (ACPI_FAILURE(status))
> >> +                    goto finish_ordered_list;
> >> +
> >> +            /*
> >> +             * 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(&value, value_len, &tmpstr,
> >> &tmp_len);
> >> +            if (ACPI_FAILURE(status))
> >> +                    goto finish_ordered_list;
> >> +
> >> +            part_tmp = tmpstr;
> >> +            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);
> >> +            }
> >> +    }
> >> +
> >> +finish_ordered_list:
> >> +    if (type == HPWMI_ORDEREDLIST_TYPE)
> >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >> +
> >> +    /*
> >> +     * remove trailing comma
> >> +     */
> >> +    if (buf_size > 3)
> >> +            buf[buf_size - 2] = ' ';
> >> +
> >> +    kfree(tmpstr);
> >> +    kfree(value);
> >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> >> +}
> >> +
> >> +static int append_buffer_elements_to_buffer(union acpi_object *obj,
> >> +                                        char *buf, int alloc_size, enum
> >> hp_wmi_data_type type)
> >> +{
> >> +    int buf_size;
> >> +    int status;
> >> +    char *str = NULL;
> >> +    int i;
> >> +    int j;
> >> +    int integer;
> >> +    int size = 0;
> >> +
> >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> >> +            return -EINVAL;
> >> +
> >> +    if (obj->type != ACPI_TYPE_BUFFER)
> >> +            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]);
> >> +
> >> +    for (i = 0; i < 3; i++) {
> >> +            status = get_string_from_buffer((u16 **)&obj-
> >>> buffer.pointer, &str);
> >> +            if (ACPI_SUCCESS(status)) {
> >> +                    /*
> >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> >> since
> >> +                     * 'CurrentValue' is reported.
> >> +                     */
> >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> >> +                            buf_size = snprintf(buf, alloc_size,
> >> +                                                "%s\t\"%s\": \"%s\",\n",
> >> +                                                buf,
> >> +
> >> hp_wmi_elements[type][i], str);
> >> +            }
> >> +            kfree(str);
> >> +            str = NULL;
> >> +
> >> +    }
> >> +
> >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> >> +            if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
> >> +                    status = get_string_from_buffer((u16 **)&obj-
> >>> buffer.pointer, &str);
> >> +                    if (ACPI_SUCCESS(status)) {
> >> +                            /*
> >> +                             * Report "CurrentValue" as "Value"
> >> +                             */
> >> +                            buf_size = snprintf(buf, alloc_size,
> >> +                                                "%s\t\"Value\": \"%s\",\n",
> >> buf, str);
> >> +                    }
> >> +                    kfree(str);
> >> +                    str = NULL;
> >> +                    continue;
> >> +
> >> +            } else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
> >> +                    /*
> >> +                     * Report list of "SupportEncoding"
> >> +                     *
> >> +                     *      "SupportedEncoding": [
> >> +                     *              "utf-16"
> >> +                     *      ],
> >> +                     *
> >> +                     */
> >> +
> >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> >> +                                        buf, hp_wmi_elements[type][i]);
> >> +                    for (j = 0; j < size; j++) {
> >> +                            status = get_string_from_buffer((u16
> >> **)&obj->buffer.pointer, &str);
> >> +                            if (ACPI_SUCCESS(status)) {
> >> +                                    if (j == size - 1)
> >> +                                            buf_size = snprintf(buf,
> >> alloc_size,
> >> +
> >> "%s\t\t\"%s\"\n", buf, str);
> >> +                                    else
> >> +                                            buf_size = snprintf(buf,
> >> alloc_size,
> >> +
> >> "%s\t\t\"%s\",\n", buf, str);
> >> +                            }
> >> +                            kfree(str);
> >> +                            str = NULL;
> >> +                    }
> >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >> +                    continue;
> >> +            }
> >> +
> >> +            size = 0;
> >> +            status = get_integer_from_buffer((int **)&obj-
> >>> buffer.pointer, &integer);
> >> +            if (ACPI_SUCCESS(status)) {
> >> +                    /*
> >> +                     * Report "PrerequisiteSize" and "Size" values
> >> +                     *      ...
> >> +                     *      "PrerequisiteSize": 1,
> >> +                     *      ...
> >> +                     *      "Size": 2,
> >> +                     *      ...
> >> +                     */
> >> +                    if (i == 7)
> >> +                            size = integer;
> >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> >> == 10)
> >> +                            size = integer;
> >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> >> 9)
> >> +                            size = integer;
> >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> >> 11)
> >> +                            size = integer;
> >> +
> >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> >> %d,\n", buf,
> >> +                                        hp_wmi_elements[type][i],
> >> integer);
> >> +            }
> >> +
> >> +            if (size > 20)
> >> +                    pr_warn("%s exceeded the maximum number of
> >> elements supported or data may be malformed\n",
> >> +                            hp_wmi_elements[type][i]);
> >> +
> >> +            if (ACPI_SUCCESS(status) && i == 7) {
> >> +                    buf_size = snprintf(buf, alloc_size,
> >> "%s\t\"Prerequisites\": [\n", buf);
> >> +                    for (j = 0; j < size; j++) {
> >> +                            status = get_string_from_buffer((u16
> >> **)&obj->buffer.pointer, &str);
> >> +                            if (ACPI_SUCCESS(status)) {
> >> +                                    buf_size = snprintf(buf, alloc_size,
> >> "%s\t\t\"%s\"", buf, str);
> >> +
> >> +                                    if (j == size - 1)
> >> +                                            buf_size = snprintf(buf,
> >> alloc_size, "%s\n", buf);
> >> +                                    else
> >> +                                            buf_size = snprintf(buf,
> >> alloc_size, "%s,\n", buf);
> >> +
> >> +                            }
> >> +                            kfree(str);
> >> +                            str = NULL;
> >> +                    }
> >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >> +            }
> >> +    }
> >> +
> >> +    if (type == HPWMI_ENUMERATION_TYPE || type ==
> >> HPWMI_ORDEREDLIST_TYPE) {
> >> +            if (type == HPWMI_ENUMERATION_TYPE)
> >> +                    buf_size = snprintf(buf, alloc_size,
> >> "%s\t\"PossibleValues\": [\n", buf);
> >> +            else
> >> +                    buf_size = snprintf(buf, alloc_size,
> >> "%s\t\"Elements\": [\n", buf);
> >> +
> >> +            for (i = 0; i < size; i++) {
> >> +                    status = get_string_from_buffer((u16 **)&obj-
> >>> buffer.pointer, &str);
> >> +                    if (ACPI_SUCCESS(status)) {
> >> +                            buf_size = snprintf(buf, alloc_size,
> >> "%s\t\t\"%s\"", buf, str);
> >> +
> >> +                            if (i == size - 1)
> >> +                                    buf_size = snprintf(buf, alloc_size,
> >> "%s\n", buf);
> >> +                            else
> >> +                                    buf_size = snprintf(buf, alloc_size,
> >> "%s,\n", buf);
> >> +
> >> +                    }
> >> +                    kfree(str);
> >> +                    str = NULL;
> >> +            }
> >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >> +    }
> >> +
> >> +    /*
> >> +     * remove trailing comma
> >> +     */
> >> +    if (buf_size > 3)
> >> +            buf[buf_size - 2] = ' ';
> >> +
> >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> >> +}
> >> +
> >> +static int hp_bios_settings_free_buffer(void)
> >> +{
> >> +    mutex_lock(&buf_mutex);
> >> +    kfree(hp_bios_settings_buffer);
> >> +    settings_buffer_size = 0;
> >> +    buf_alloc_size = 0;
> >> +    mutex_unlock(&buf_mutex);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
> >> +                                       int *alloc_size,
> >> +                                       struct mutex *buf_mutex)
> >> +{
> >> +    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(buf_mutex);
> >> +            new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
> >> +            mutex_unlock(buf_mutex);
> >> +            if (new_buf) {
> >> +                    mutex_lock(buf_mutex);
> >> +                    *buf = new_buf;
> >> +                    *alloc_size = ksize(new_buf);
> >> +                    mutex_unlock(buf_mutex);
> >> +            } else {
> >> +                    hp_bios_settings_free_buffer();
> >> +                    ret = -ENOMEM;
> >> +            }
> >> +    }
> >> +
> >> +    return ret;
> >> +}
> >> +
> >> +static int append_settings_to_buffer(char *guid, int type, char **buf,
> >> +                                 int *buf_size, int *alloc_size,
> >> +                                 struct mutex *buf_mutex)
> >> +{
> >> +    union acpi_object *obj = NULL;
> >> +    int ret = 0;
> >> +    int status = 0;
> >> +    int instance = 0;
> >> +
> >> +    /*
> >> +     * Query all the instances until to receive a AE_BAD_PARAMETER
> >> +     */
> >> +    do {
> >> +            ret = hp_wmi_get_setting_object(guid, instance++, &obj);
> >> +            if (ACPI_SUCCESS(ret) && obj != NULL) {
> >> +                    status = 0;
> >> +                    if (obj->type == ACPI_TYPE_PACKAGE) {
> >> +                            mutex_lock(buf_mutex);
> >> +                            status =
> >> append_package_elements_to_buffer(obj,
> >> +                                                    *buf, *alloc_size,
> >> type);
> >> +                            if (status > 0)
> >> +                                    *buf_size = status;
> >> +                            mutex_unlock(buf_mutex);
> >> +
> >> +                    } else if (obj->type == ACPI_TYPE_BUFFER) {
> >> +                            mutex_lock(buf_mutex);
> >> +                            status =
> >> append_buffer_elements_to_buffer(obj,
> >> +                                                    *buf, *alloc_size,
> >> type);
> >> +                            if (status > 0)
> >> +                                    *buf_size = status;
> >> +                            mutex_unlock(buf_mutex);
> >> +
> >> +                    } else
> >> +                            pr_warn("The retrieved object type(%d) is
> >> not supported yet\n",
> >> +                                    obj->type);
> >> +
> >> +                    ret = hp_bios_settings_realloc_buffer(buf, buf_size,
> >> alloc_size, buf_mutex);
> >> +            }
> >> +
> >> +            kfree(obj);
> >> +            obj = NULL;
> >> +
> >> +    } while (ACPI_SUCCESS(ret));
> >> +
> >> +    /*
> >> +     * AE_BAD_PARAMETER means the loop ended by exhaustion
> >> +     */
> >> +    if (ret == AE_BAD_PARAMETER)
> >> +            ret = 0;
> >> +
> >> +    return ret;
> >> +}
> >> +
> >> +static int hp_bios_settings_fill_buffer(void)
> >> +{
> >> +    int status = 0;
> >> +    int initial_buffer_size = 20 * PAGE_SIZE;
> >> +
> >> +    mutex_lock(&buf_mutex);
> >> +    hp_bios_settings_buffer = kmalloc(initial_buffer_size, GFP_KERNEL);
> >> +    mutex_unlock(&buf_mutex);
> >> +    if (!hp_bios_settings_buffer)
> >> +            return -ENOMEM;
> >> +
> >> +    mutex_lock(&buf_mutex);
> >> +    buf_alloc_size = ksize(hp_bios_settings_buffer);
> >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> >> +                                    buf_alloc_size, "[\n");
> >> +    mutex_unlock(&buf_mutex);
> >> +
> >> +    status = append_settings_to_buffer(HPWMI_STRING_GUID,
> >> +            HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
> >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >> +    if (ACPI_FAILURE(status))
> >> +            pr_err("error 0x%x occurred retrieving string instances\n",
> >> status);
> >> +
> >> +    status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
> >> +            HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
> >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >> +    if (ACPI_FAILURE(status))
> >> +            pr_err("error 0x%x occurred retrieving integer instances\n",
> >> status);
> >> +
> >> +    status = append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
> >> +            HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
> >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >> +    if (ACPI_FAILURE(status))
> >> +            pr_err("error 0x%x occurred retrieving enumeration
> >> instances\n", status);
> >> +
> >> +    status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
> >> +            HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
> >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >> +    if (ACPI_FAILURE(status))
> >> +            pr_err("error 0x%x occurred retrieving ordered list
> >> instances\n", status);
> >> +
> >> +    status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
> >> +            HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
> >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >> +    if (ACPI_FAILURE(status))
> >> +            pr_err("error 0x%x occurred retrieving password list
> >> instances\n", status);
> >> +
> >> +    mutex_lock(&buf_mutex);
> >> +    /*
> >> +     * remove trailing comma
> >> +     */
> >> +    if (settings_buffer_size >= 3) {
> >> +            if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
> >> +                    hp_bios_settings_buffer[settings_buffer_size - 2] = '
> >> ';
> >> +    }
> >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> >> +                                    buf_alloc_size, "%s]\n",
> >> +                                    hp_bios_settings_buffer);
> >> +    mutex_unlock(&buf_mutex);
> >> +
> >> +    return settings_buffer_size;
> >> +}
> >> +
> >> +/*
> >> + * sure_admin_settings_read - Return a formatted file with settings
> >> + *                              and possible options read from BIOS
> >> + *
> >> + * @filp:  Pointer to file of settings read from BIOS
> >> + * @kobj:  Pointer to a kernel object of things that show up as directory in
> >> the sysfs filesystem.
> >> + * @attr:  Pointer to list of read attributes
> >> + * @buf:   Pointer to buffer
> >> + * @off:   File current offset
> >> + * @count: Buffer size
> >> + *
> >> + * Returns the count of unicode chars read if successful, otherwise
> >> + *          -ENOMEM unable to allocate memory
> >> + *          -EINVAL buffer not allocated or too small
> >> + *
> >> + */
> >> +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 >= settings_buffer_size && settings_buffer_size > 0) {
> >> +            hp_bios_settings_free_buffer();
> >> +            return 0;
> >> +    }
> >> +
> >> +    /* clear the buffer whenever the read starts from the first position
> >> */
> >> +    if (off == 0 && settings_buffer_size > 0)
> >> +            hp_bios_settings_free_buffer();
> >> +
> >> +    if (settings_buffer_size == 0)
> >> +            hp_bios_settings_fill_buffer();
> >> +
> >> +    mutex_lock(&buf_mutex);
> >> +    ret = memory_read_from_buffer(buf, count, &off,
> >> hp_bios_settings_buffer,
> >> +                                  settings_buffer_size);
> >> +    mutex_unlock(&buf_mutex);
> >> +
> >> +    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
> >> + */
> >> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
> >> +{
> >> +    int len = strlen(str);
> >> +
> >> +    /*
> >> +     * Add null character when reading an empty string
> >> +     */
> >> +    if (len == 0) {
> >> +            *p++ = 2;
> >> +            *p++ = (u8)0x00;
> >> +            return p;
> >> +    }
> >> +    *p++ = len * 2;
> >> +    utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
> >> +    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
> >> + */
> >> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 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(HPWMI_SETBIOSSETTING_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;
> >> +}
> >> +
> >> +/* Sure Admin Functions */
> >> +
> >> +#define UTF_PREFIX                  ((unsigned char *)"<utf-16/>")
> >> +#define BEAM_PREFIX                 ((unsigned char
> >> *)"<BEAM/>")
> >> +
> >> +/*
> >> + * sure_admin_settings_write - Write the contents of a formatted file
> >> + *                               with settings and performs the logic
> >> + *                               to change any settings in BIOS.
> >> + *
> >> + * @filp:  Pointer to file of settings to be written to BIOS
> >> + * @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 write operation
> >> + * @buf:   Pointer to buffer
> >> + * @off:   File current offset
> >> + * @count: Buffer size
> >> + *
> >> + *
> >> + * Returns the count of unicode characters written to BIOS if successful,
> >> otherwise
> >> + *          -ENOMEM unable to allocate memory
> >> + *          -EINVAL buffer not allocated or too small
> >> + *
> >> + */
> >> +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;
> >> +    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 out_free;
> >> +    }
> >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> >> +    part = strsep(&buf, ",");
> >> +    if (!part) {
> >> +            status = -EINVAL;
> >> +            goto out_free;
> >> +    }
> >> +
> >> +    /* Add extra buffer space when encountering an empty string */
> >> +    if (!strlen(part))
> >> +            buffer_size += sizeof(unsigned short);
> >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> >> +    part = strsep(&buf, ",");
> >> +    if (!part) {
> >> +            status = -EINVAL;
> >> +            goto out_free;
> >> +    }
> >> +    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 out_free;
> >> +
> >> +            tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> >> +            kfree(part);
> >> +    }
> >> +
> >> +    part = strsep(&buf, ",");
> >> +    if (part) {
> >> +            status = -EINVAL;
> >> +            goto out_free;
> >> +    }
> >> +    status = hp_wmi_set_bios_setting(buffer, buffer_size);
> >> +    if (ACPI_FAILURE(status))
> >> +            status = -EINVAL;
> >> +
> >> +out_free:
> >> +    kfree(buffer);
> >> +    if (ACPI_SUCCESS(status))
> >> +            return count;
> >> +    return status;
> >> +}
> >> +
> >> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
> >> +
> >> +static struct bin_attribute *sure_admin_binattrs[] = {
> >> +    &sure_admin_settings,
> >> +    NULL,
> >> +};
> >> +
> >> +static const struct attribute_group sure_admin_group = {
> >> +    .name = "sure_admin",
> >> +    .bin_attrs = sure_admin_binattrs,
> >> +};
> >> +
> >>  static DEVICE_ATTR_RO(display);
> >>  static DEVICE_ATTR_RO(hddtemp);
> >>  static DEVICE_ATTR_RW(als);
> >> @@ -1050,6 +2026,7 @@ static const struct attribute_group
> >> *hp_wmi_groups[] = {
> >>      &hp_wmi_group,
> >>      &spm_group,
> >>      &sure_start_group,
> >> +    &sure_admin_group,
> >>      NULL,
> >>  };
> >>
> >> --
> >> 2.25.1
>

[-- Attachment #2: settings.log --]
[-- Type: application/octet-stream, Size: 104591 bytes --]

[
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Minimum BIOS Version",
	"Value": "00.00.00",
	"Path": "\\Main\\Update System BIOS",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 2020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 9 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Platform Management Key Endorsement Certificate",
	"Value": "",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 11000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"MinLength": 0,
	"MaxLength": 5745 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Platform Management Signing Key",
	"Value": "",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 11010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 689 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Platform Management Current State",
	"Value": "Not provisioned",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 11020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 50 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Platform Management Version",
	"Value": "1.00",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 11030,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 10 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Platform Management Usage Bitmask",
	"Value": "0x0000",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 11040,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 14 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Platform Management Key Endorsement Key",
	"Value": "",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 11060,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 344 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Enhanced BIOS Authentication Mode Local Access Key 1",
	"Value": "",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 13010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 645 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Enhanced BIOS Authentication Mode Version",
	"Value": "1.01",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 13005,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 11 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Embedded Storage for Recovery",
	"Value": "32 GB",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29100,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 120 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "HP Sure Run Current State",
	"Value": "Inactive",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 12000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 42 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "HP Cloud Managed State",
	"Value": "Enabled",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 12090,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 42 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Remote Device Management Status",
	"Value": "Enabled",
	"Path": "\\Security\\Security Configuration\\HP Find Lock Wipe",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 10000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 42 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Erase Hard Disk Serial Number",
	"Value": "",
	"Path": "\\Security\\Utilities\\Hard Drive Utilities",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 16060,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 20 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Erase Hard Disk Model Number",
	"Value": "",
	"Path": "\\Security\\Utilities\\Hard Drive Utilities",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 16061,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 40 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Erase Completion Date",
	"Value": "",
	"Path": "\\Security\\Utilities\\Hard Drive Utilities",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 16062,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 17 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Secure Erase Completion Status",
	"Value": "",
	"Path": "\\Security\\Utilities\\Hard Drive Utilities",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 16063,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 23 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Feature Byte",
	"Value": "3X476J6S6b7B7H7M7R7W7m7saBapaqauawb8bVbhcAd6dUdpdqfPfXguhKhWj4jhk8mEmwng.NH",
	"Path": "\\Main\\System Information\\System IDs",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 1230,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 249 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Build ID",
	"Value": "21WWSKAT6ar#SABA#DABA",
	"Path": "\\Main\\System Information\\System IDs",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 1235,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 55 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Agent Version",
	"Value": "0",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29040,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Image Version",
	"Value": "",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29060,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Driver Version",
	"Value": "",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29065,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Agent URL",
	"Value": "http://ftp.hp.com/pub/pcbios/CPR",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29025,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Agent Username",
	"Value": "",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29030,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Agent Provisioning Version",
	"Value": "0",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29035,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Image URL",
	"Value": "",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29045,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Image Username",
	"Value": "",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29050,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "OS Recovery Image Provisioning Version",
	"Value": "0",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29055,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Remote HP PC Hardware Diagnostics Custom Client Upload Url",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29881,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Remote HP PC Hardware Diagnostics Custom Client Download Url",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29883,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Remote HP PC Hardware Diagnostics Upload Server Username",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29888,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Remote HP PC Hardware Diagnostics Upload Server Password",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29889,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Remote HP PC Hardware Diagnostics Last Execution Time Stamp",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29887,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 256 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Update Address",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29805,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 255 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Proxy Address",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29852,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 255 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "DNS Addresses",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29854,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 255 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "IPv4 Address",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29856,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 255 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "IPv4 Subnet Mask",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29856,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 255 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "IPv4 Gateway",
	"Value": "",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29856,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 255 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Last Cover Removal and Count",
	"Value": "0 times",
	"Path": "\\Security\\Security Configuration\\Smart Cover",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 15050,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 78 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Camera Controller Firmware Version:",
	"Value": "Camera : 0015",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 323,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 99 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "HBMA Factory MAC Address",
	"Value": "F8-0D-AC-7F-AC-03",
	"Path": "\\Advanced",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21011,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 35 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "HBMA System MAC Address",
	"Value": "F8-0D-AC-7F-AC-03",
	"Path": "\\Advanced",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21012,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 35 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "HBMA Custom MAC Address",
	"Value": "00-00-00-00-00-00",
	"Path": "\\Advanced",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21013,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 35 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Intel(R) Thunderbolt Retimer FW version",
	"Value": "02.13.00.01",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 600,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 11,
	"MaxLength": 11 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Intel(R) Thunderbolt Retimer FW Model ID",
	"Value": "8720",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 603,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 4,
	"MaxLength": 4 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Batt_LTemp",
	"Value": "",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 1,
	"DisplayInUI": 0,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24072,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 16 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Product Name",
	"Value": "HP EliteBook x360 1040 G8 Notebook PC",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 10,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 60 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Serial Number",
	"Value": "CND0396WJC",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 190,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 32 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "SKU Number",
	"Value": "GPM4001#ABA",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 200,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 48 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Universally Unique Identifier (UUID)",
	"Value": "125484EB8C8F3048971F872FB4712BFE",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 210,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 32 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "UUID (standard format)",
	"Value": "EB845412-8F8C-4830-971F-872FB4712BFE",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 215,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 36 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Asset Tracking Number",
	"Value": "CND0396WJC",
	"Path": "\\Main\\System Information\\System IDs",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 1220,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 80 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Ownership Tag",
	"Value": "",
	"Path": "\\Main\\System Information\\System IDs",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 1225,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 80 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "System Board CT Number",
	"Value": "PXXXXA41UE9ZEN",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 250,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 14 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Product Family",
	"Value": "103C_5336AN HP EliteBook x360",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 260,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 48 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "MS Digital Marker",
	"Value": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 270,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 98 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "HP_Disk0MapForUefiBootOrder",
	"Value": "PciRoot(0x0)/Pci(0x1D,0x0)/Pci(0x0,0x0)/NVMe(0x1,62-4F-28-46-8B-44-1B-00)/HD(1,GPT,C95BAE9A-589F-4D55-9981-22873EB6CCF7,0x800,0x100000)/\\EFI\\ubuntu\\shimx64.efi\r\n\tPciRoot(0x0)/Pci(0x14,0x0)\r\n\tPciRoot(0x0)/Pci(0x1D,0x0)/Pci(0x0,0x0)/NVMe(0x1,62-4F-28-46-8B-44-1B-00)/HD(1,GPT,C95BAE9A-589F-4D55-9981-22873EB6CCF7,0x800,0x100000)/\\EFI\\ubuntu\\fwupdx64.efi\r\n\tPciRoot(0x0)/Pci(0x0,0x0)/IPv4(0.0.0.0,0x0,DHCP,0.0.0.0,0.0.0.0,0.0.0.0)\r\n\tPciRoot(0x0)/Pci(0x0,0x0)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000,0x0,Static,0000:0000:0000:0000:0000:0000:0000:0000,0x0,0000:0000:0000:0000:0000:0000:0000:0000)",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24120,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 1192 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Memory Size",
	"Value": "16384 MB",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 231,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 18 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "System BIOS Version",
	"Value": "T93 Ver. 01.08.00  01/13/2022",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 280,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 60 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "BIOS Build Version",
	"Value": "0001",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 281,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 10 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "ME Firmware Version",
	"Value": "15.0.35.1951",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 290,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 26 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "ME Firmware Mode",
	"Value": "Enable",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 291,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 14 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Audio Controller",
	"Value": "Realtek ALC3292",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 295,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 32 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Video BIOS Version",
	"Value": "Intel(R) GOP Driver [17.0.1055]",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 300,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 64 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Reference Code Revision",
	"Value": "A.0.5D.32",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 301,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 20 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Embedded Controller Firmware Version",
	"Value": "38.34.00",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 310,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 18 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Born On Date",
	"Value": "12/11/2020",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 330,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 22 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "System Board ID",
	"Value": "8720",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 340,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 10 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Type",
	"Value": "11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 30,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 94 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Speed",
	"Value": "3000 MHz",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 40,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 18 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Cores",
	"Value": "4",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 45,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 4 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Cache Size (L1/L2/L3)",
	"Value": "320 KB / 5 MB / 12 MB",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 50,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 44 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 MicroCode Revision",
	"Value": "9A",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 60,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 6 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Stepping",
	"Value": "1",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 70,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 4 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Bottom-OnBoard 1-1",
	"Value": "2 GB Micron",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 71,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 24 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Bottom-OnBoard 1-2",
	"Value": "2 GB Micron",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 72,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 24 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Bottom-OnBoard 2-1",
	"Value": "2 GB Micron",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 73,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 24 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Bottom-OnBoard 2-2",
	"Value": "2 GB Micron",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 74,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 24 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Bottom-OnBoard 3-1",
	"Value": "2 GB Micron",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 75,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 24 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Bottom-OnBoard 3-2",
	"Value": "2 GB Micron",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 76,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 24 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Bottom-OnBoard 4-1",
	"Value": "2 GB Micron",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 77,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 24 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "Processor 1 Bottom-OnBoard 4-2",
	"Value": "2 GB Micron",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 78,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 24 
},
{
	"Class": "HPBIOS_BIOSString",
	"Name": "TPM Specification Version",
	"Value": "2.0",
	"Path": "\\Security\\Security Configuration\\TPM Embedded Security",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 6001,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 0,
	"MaxLength": 8 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "Secure Platform Management Counter",
	"Value": "0",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 11050,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"LowerBound": 0,
	"UpperBound": -1,
	"IntValue": 0 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "Enhanced BIOS Authentication Mode Settings Anti-Replay Counter",
	"Value": "0",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 13020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"LowerBound": 0,
	"UpperBound": -1,
	"IntValue": 0 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "Enhanced BIOS Authentication Mode Actions Anti-Replay Counter",
	"Value": "0",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 13030,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"LowerBound": 0,
	"UpperBound": -1,
	"IntValue": 0 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "Remote HP PC Hardware Diagnostics Last Execution Status",
	"Value": "0",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29886,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"LowerBound": 0,
	"UpperBound": -1,
	"IntValue": 0 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "Password Minimum Length",
	"Value": "8",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5010,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"LowerBound": 4,
	"UpperBound": 32,
	"IntValue": 8 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "Data transfer timeout",
	"Value": "100",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29855,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"LowerBound": 1,
	"UpperBound": 65535,
	"IntValue": 100 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "BIOS Power-On Hour",
	"Value": "0",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23017,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"LowerBound": 0,
	"UpperBound": 23,
	"IntValue": 0 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "BIOS Power-On Minute",
	"Value": "0",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23018,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"LowerBound": 0,
	"UpperBound": 59,
	"IntValue": 0 
},
{
	"Class": "HPBIOS_BIOSInteger",
	"Name": "Disable Charging Port in sleep/off if battery below (%):",
	"Value": "10",
	"Path": "\\Advanced\\Port Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 27104,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"LowerBound": 10,
	"UpperBound": 100,
	"IntValue": 10 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "System Management Command",
	"Path": "\\Security\\Utilities\\System Management Command",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 18010,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Fast Boot",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "BIOS Rollback Policy",
	"Path": "\\Main\\Update System BIOS",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 2010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Unrestricted Rollback to older BIOS",
	"Size": 2,
	"PossibleValues": [
		"Unrestricted Rollback to older BIOS",
		"Restricted Rollback to older BIOS"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Audio Alerts During Boot",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24021,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Sure Start BIOS Settings Protection",
	"Path": "\\Security\\Security Configuration\\BIOS SureStart",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 7070,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 1,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Sure Start Secure Boot Keys Protection",
	"Path": "\\Security\\Security Configuration\\BIOS SureStart",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 7075,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 1,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Enhanced BIOS Authentication Mode",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 13000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Manufacturing Programming Mode",
	"Path": "\\",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 4001,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Lock",
	"Size": 2,
	"PossibleValues": [
		"Unlock",
		"Lock"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Permanent Disable Absolute Persistence Module Set Once",
	"Path": "\\Security\\Utilities",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 17010,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Absolute Persistence Module Current State",
	"Path": "\\Security\\Utilities",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 17020,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Inactive",
	"Size": 2,
	"PossibleValues": [
		"Inactive",
		"Active"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Startup Delay (sec.)",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "0",
	"Size": 13,
	"PossibleValues": [
		"0",
		"5",
		"10",
		"15",
		"20",
		"25",
		"30",
		"35",
		"40",
		"45",
		"50",
		"55",
		"60"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Native OS Firmware Update Service",
	"Path": "\\Main\\Update System BIOS",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 2008,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Permanently Disable HP Sure Run (Set Once)",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 12010,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 1,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "HP Cloud Managed",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 12070,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Permanently Disable HP Cloud Management (Set Once)",
	"Path": "\\Security\\Security Configuration\\HP Secure Platform Management",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 12080,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Remote Device Management",
	"Path": "\\Security\\Security Configuration\\HP Find Lock Wipe",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 10010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Permanently Disable Remote Device Management (Set Once)",
	"Path": "\\Security\\Security Configuration\\HP Find Lock Wipe",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 10020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "TPM Activation Policy",
	"Path": "\\Security\\Security Configuration\\TPM Embedded Security",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 6040,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Allow user to reject",
	"Size": 3,
	"PossibleValues": [
		"F1 to Boot",
		"Allow user to reject",
		"No prompts"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Sure Start Security Event Boot Notification",
	"Path": "\\Security\\Security Configuration\\BIOS SureStart",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 7090,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Require Acknowledgment",
	"Size": 2,
	"PossibleValues": [
		"Time out after 15 seconds",
		"Require Acknowledgment"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Ready BIOS for Device Guard Use",
	"Path": "\\Security\\Secure Boot Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 8070,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Do Nothing",
	"Size": 3,
	"PossibleValues": [
		"Do Nothing",
		"Configure on Next Boot",
		"Clear Configuration on Next Boot"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Physical Presence Interface",
	"Path": "\\Security\\Security Configuration\\Physical Presence Interface",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 14010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Force Cold Boot",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24150,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 3,
	"PossibleValues": [
		"Disable",
		"Enable",
		"Once"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Select Language",
	"Path": "\\Advanced\\Display Language",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 22010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "English",
	"Size": 15,
	"PossibleValues": [
		"English",
		"Deutsch",
		"Espanol",
		"Italiano",
		"Francais",
		"Japanese",
		"Portugues",
		"Dansk",
		"Svenska",
		"Nederlands",
		"Norsk",
		"Suomi",
		"Simplified Chinese",
		"Traditional Chinese",
		"Russian"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Select Keyboard Layout",
	"Path": "\\Advanced\\Display Language",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 22020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "English",
	"Size": 15,
	"PossibleValues": [
		"English",
		"Deutsch",
		"Espanol",
		"Italiano",
		"Francais",
		"Japanese",
		"Portugues",
		"Dansk",
		"Svenska",
		"Nederlands",
		"Norsk",
		"Suomi",
		"Simplified Chinese",
		"Traditional Chinese",
		"Russian"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Allow OPAL Hard Drive SID Authentication",
	"Path": "\\Security\\Utilities\\Hard Drive Utilities",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 16070,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "SureStart Development (Lab) Mode",
	"Path": "\\Security\\Security Configuration\\EC Production Mode",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 19000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "SureStart Production Mode",
	"Path": "\\Security\\Security Configuration\\EC Production Mode",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 19010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "USB Storage Boot",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24051,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Network (PXE) Boot",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24052,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "IPv6 during UEFI Boot",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24053,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSEnumeration WHERE Name='Network (PXE) Boot' AND CurrentValue = 'Enable'"
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Clear BIOS Event Log",
	"Path": "\\Main\\BIOS Event Log",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 3000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Don't Clear",
	"Size": 2,
	"PossibleValues": [
		"Don't Clear",
		"Clear"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "OS Recovery",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Recover OS from Network",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29005,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Recover OS after Boot Failure",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Prompt before Boot Failure Recovery",
	"Path": "\\Advanced\\HP Sure Recover",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29015,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Boot Sector (MBR/GPT) Recovery Policy",
	"Path": "\\Security\\Boot Sector (MBR/GPT) Recovery Policy",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Local user control",
	"Size": 2,
	"PossibleValues": [
		"Local user control",
		"Recover in event of corruption"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Remote HP PC Hardware Diagnostics Use Custom Download Url",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29882,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Remote HP PC Hardware Diagnostics Scheduled Execution Enabled",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29884,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Remote HP PC Hardware Diagnostics Execute On Next Boot",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29891,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Remote HP PC Hardware Diagnostics Scheduled Execution Frequency",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29885,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Weekly",
	"Size": 3,
	"PossibleValues": [
		"Daily",
		"Weekly",
		"Monthly"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Enhanced HP Firmware Runtime Intrusion Prevention and Detection",
	"Path": "\\Security\\Security Configuration\\BIOS SureStart",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 7080,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Sure Start Security Event Policy",
	"Path": "\\Security\\Security Configuration\\BIOS SureStart",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 7090,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Log Event and notify user",
	"Size": 3,
	"PossibleValues": [
		"Log Event Only",
		"Log Event and notify user",
		"Log Event and power off system"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "At least one symbol is required in Administrator and User passwords",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5020,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "At least one number is required in Administrator and User passwords",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5030,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "At least one upper case character is required in Administrator and User passwords",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5040,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "At least one lower case character is required in Administrator and User passwords",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5050,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Are spaces allowed in Administrator and User passwords?",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5060,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Allow User to Modify Power-on Password",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5061,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Change or Delete",
	"Size": 3,
	"PossibleValues": [
		"No",
		"Change Only",
		"Change or Delete"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Wake on LAN Power-on Password Policy",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5062,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Require Password",
	"Size": 2,
	"PossibleValues": [
		"Bypass Password",
		"Require Password"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Prompt for Admin authentication on F9 (Boot Menu)",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5070,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Prompt for Admin authentication on F11 (System Recovery)",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5080,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Prompt for Admin authentication on F12 (Network Boot)",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5090,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Prompt for Admin authentication on Capsule Update",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5100,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "BIOS Administrator visible at Power-on Authentication",
	"Path": "\\Security\\Administrator Tools\\Password Policies",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 5110,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Force Check on Reboot",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29806,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Update BIOS via Network",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29806,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Update Source",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29802,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "HP",
	"Size": 2,
	"PossibleValues": [
		"HP",
		"Custom"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Automatically Check for Updates",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29803,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Monthly",
	"Size": 3,
	"PossibleValues": [
		"Daily",
		"Weekly",
		"Monthly"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Automatic BIOS Update Setting",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29804,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 6,
	"PossibleValues": [
		"Disable",
		"Let user decide whether to install updates",
		"Install all updates automatically",
		"Install only important updates automatically",
		"Download and install normal BIOS updates automatically without prompts",
		"Download and install important BIOS updates automatically without prompts"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Use Proxy",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29850,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "IPv4 Configuration",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29856,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Automatic",
	"Size": 2,
	"PossibleValues": [
		"Automatic",
		"Manual"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "DNS Configuration",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29853,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Automatic",
	"Size": 2,
	"PossibleValues": [
		"Automatic",
		"Manual"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Force HTTP no-cache",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29857,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Force Default IP Configuration",
	"Path": "\\Advanced\\Configurations",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 29858,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Video Memory Size",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26310,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "64 MB",
	"Size": 4,
	"PossibleValues": [
		"64 MB",
		"128 MB",
		"256 MB",
		"512 MB"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Custom Logo",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 500,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Not Present",
	"Size": 2,
	"PossibleValues": [
		"Not Present",
		"Present"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Sunday",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Monday",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23011,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Tuesday",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23012,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Wednesday",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23013,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Thursday",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23014,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Friday",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23015,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Saturday",
	"Path": "\\Advanced\\Scheduled Power-On",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 23016,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Cover Removal Sensor",
	"Path": "\\Security\\Security Configuration\\Smart Cover",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 15020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Notify user"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Power Off Upon Cover Removal",
	"Path": "\\Security\\Security Configuration\\Smart Cover",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 15030,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSEnumeration WHERE Name='Cover Removal Sensor' AND CurrentValue != 'Disable'"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Clear TPM on boot after cover removal",
	"Path": "\\Security\\Security Configuration\\Smart Cover",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 15040,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSEnumeration WHERE Name='Cover Removal Sensor' AND CurrentValue != 'Disable'"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Audio Device",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Microphone",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26002,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Internal Speakers",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26003,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Headphone Output",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26004,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Runtime Power Management",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26003,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Extended Idle Power States",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26004,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Prompt on Fixed Storage Change",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24061,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Intel Dynamic Tuning",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 25030,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Power Slider Plus",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 25032,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Motion sensing cool mode",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 25033,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Configure Storage Controller for VMD",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 25016,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Sanitization Mode Countdown Timer",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 25100,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "120",
	"Size": 20,
	"PossibleValues": [
		"15",
		"30",
		"45",
		"60",
		"75",
		"90",
		"105",
		"120",
		"135",
		"150",
		"165",
		"180",
		"195",
		"210",
		"225",
		"240",
		"255",
		"270",
		"285",
		"300"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Pre-Sanitization Mode Countdown Timer",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 25101,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "3",
	"Size": 11,
	"PossibleValues": [
		"0",
		"1",
		"2",
		"3",
		"4",
		"5",
		"6",
		"7",
		"8",
		"9",
		"10"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "HP Application Driver",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 25100,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Left USB Ports",
	"Path": "\\Advanced\\Port Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 27120,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Right USB Ports",
	"Path": "\\Advanced\\Port Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 27121,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "USB Legacy Port Charging",
	"Path": "\\Advanced\\Port Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 27103,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "E-label",
	"Path": "\\Advanced\\E Label",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 30000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Not Present",
	"Size": 2,
	"PossibleValues": [
		"Not Present",
		"Present"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "NFC",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26011,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Integrated Camera",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Fingerprint Device",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26021,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Touch Device",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26022,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "HP Sure Shutter",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26025,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Camera Shutter stays in last known state",
	"Size": 2,
	"PossibleValues": [
		"Camera Shutter stays in last known state",
		"Camera Shutter closes on boot or resume"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Battery Safety Mode",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26023,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Bluetooth",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24900,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Wireless Network Device (WLAN)",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24901,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Mobile Network Device (WWAN) and GPS Combo Device",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24904,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "LAN / WLAN Auto Switching",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24906,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "LAN / WWAN Auto Switching",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24905,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "TILE Deactivate",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24913,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Host Based MAC Address",
	"Path": "\\Advanced",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 3,
	"PossibleValues": [
		"Disable",
		"System",
		"Custom"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Pre-boot HBMA Support",
	"Path": "\\Advanced",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21014,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Windows HBMA Support",
	"Path": "\\Advanced",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21015,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Single NIC Operation (Disable All Other NICs when HBMA is active on one NIC)",
	"Path": "\\Advanced",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21016,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "DMA Protection",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28056,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Pre-boot DMA protection",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28058,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "All PCIe Devices",
	"Size": 2,
	"PossibleValues": [
		"Thunderbolt Only",
		"All PCIe Devices"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Thunderbolt Type-C Ports",
	"Path": "\\Advanced\\Port Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 27301,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Thunderbolt Mode",
	"Path": "\\Advanced\\Port Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 27302,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Launch Hotkeys without Fn Keypress",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24204,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Auto",
	"Size": 3,
	"PossibleValues": [
		"Disable",
		"Enable",
		"Auto"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Swap Fn and Ctrl (Keys)",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24205,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Fast Charge",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24206,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "USB Type-C Connector System Software Interface (UCSI)",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24208,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Enable High Resolution mode when connected to a USB-C DP alt mode dock",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24209,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Special Keys mapped to Fn + keypress",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24210,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Swap Arrow Up/Down and Page Up/Down Function",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24211,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Power button delay to avoid accidental activation for system sleep or power down",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24212,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Automatic Travel Bag Detection",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24211,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Fan Always on while on AC Power",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24601,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Boost Converter",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24607,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Backlit keyboard timeout",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24608,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "15 secs.",
	"Size": 6,
	"PossibleValues": [
		"5 secs.",
		"15 secs.",
		"30 secs.",
		"1 min..",
		"5 mins.",
		"Never."
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Automatic Keyboard Backlit",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24609,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Force enable HP Sure View",
	"Path": "\\Advanced\\Built in Device",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24610,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Battery Health Manager",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26005,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Let HP manage my battery charging",
	"Size": 2,
	"PossibleValues": [
		"Maximize my battery health",
		"Let HP manage my battery charging"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "HP will balance your battery health and battery duration (read-only)",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26006,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enabled",
	"Size": 2,
	"PossibleValues": [
		"Enabled",
		"Enabled & Activated"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Adaptive Battery Optimizer",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 1,
	"DisplayInUI": 0,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26007,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Adaptive Battery Optimizer Status",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 1,
	"DisplayInUI": 0,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26008,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Not activated",
	"Size": 2,
	"PossibleValues": [
		"Not activated",
		"Activated"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Power On When AC Detected",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24001,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSEnumeration WHERE Name='Power Control' AND CurrentValue='Disable'"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Power On When Lid is Opened",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24002,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Disable Battery On Next Boot",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26008,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Do not disable",
	"Size": 2,
	"PossibleValues": [
		"Do not disable",
		"Next shut down"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Prompt on Battery Errors",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24071,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "USB Key Provisioning Support",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28051,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Unconfigure AMT on next boot",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28052,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Do Not Apply",
	"Size": 2,
	"PossibleValues": [
		"Do Not Apply",
		"Apply"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "SOL Terminal Emulation Mode",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28053,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "ANSI",
	"Size": 2,
	"PossibleValues": [
		"ANSI",
		"VT100"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Verbose Boot Messages",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28054,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Watchdog Timer",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28055,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "OS Watchdog Timer (min.)",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28056,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "5",
	"Size": 5,
	"PossibleValues": [
		"5",
		"10",
		"15",
		"20",
		"25"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "BIOS Watchdog Timer (min.)",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28057,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "5",
	"Size": 5,
	"PossibleValues": [
		"5",
		"10",
		"15",
		"20",
		"25"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "USB Redirection Support",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28059,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Show Unconfigure ME Confirmation Prompt",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28060,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "CIRA Timeout (min.)",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28062,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "1 min",
	"Size": 5,
	"PossibleValues": [
		"1 min",
		"2 mins",
		"3 mins",
		"4 mins",
		"Never"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Intel Active Management Technology (AMT)",
	"Path": "\\Advanced\\AMT Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28063,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Turbo-boost",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Hyperthreading",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28001,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Virtualization Technology (VTx)",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28003,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Virtualization Technology for Directed I/O (VTd)",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28004,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Trusted Execution Technology (TXT)",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28005,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Enhanced Hello Sign-in",
	"Path": "\\Advanced\\System Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28007,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Full encryption of main memory (DRAM)",
	"Path": "\\Advanced\\Tme Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 28000,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Power Control",
	"Path": "\\Advanced\\Device Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24205,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSEnumeration WHERE Name='Power ON When AC Detected' AND CurrentValue='Disable'"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Save Custom Defaults",
	"Path": "\\Main",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 65532,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Do not Save",
	"Size": 2,
	"PossibleValues": [
		"Do not Save",
		"Save"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Apply Custom Defaults and Exit",
	"Path": "\\Main",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 65533,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Apply Factory Defaults and Exit",
	"Path": "\\Main",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 65534,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Secure Boot",
	"Path": "\\Security\\Secure Boot Configuration",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 8010,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 1,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Import Custom Secure Boot keys",
	"Path": "\\Security\\Secure Boot Configuration",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 8020,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 1,
	"Value": "Do Nothing",
	"Size": 2,
	"PossibleValues": [
		"Do Nothing",
		"On next boot"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Clear Secure Boot keys",
	"Path": "\\Security\\Secure Boot Configuration",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 8030,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 1,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Reset Secure Boot keys to factory defaults",
	"Path": "\\Security\\Secure Boot Configuration",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 8040,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 1,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Enable MS UEFI CA key",
	"Path": "\\Security\\Secure Boot Configuration",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 8050,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Yes",
	"Size": 2,
	"PossibleValues": [
		"No",
		"Yes"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Custom Keys Image Verification State",
	"Path": "\\Security\\Secure Boot Configuration",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 8060,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "No Custom Keys",
	"Size": 3,
	"PossibleValues": [
		"No Custom Keys",
		"Fail",
		"Success"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Ready to disable MS UEFI CA Key",
	"Path": "\\Security\\Secure Boot Configuration",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 8055,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Ready",
	"Size": 2,
	"PossibleValues": [
		"Not Ready",
		"Ready"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Fingerprint Reset on Reboot",
	"Path": "\\Security\\Fingerprint Reset on Reboot",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 20010,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Verify Boot Block on every boot",
	"Path": "\\Security\\Security Configuration\\BIOS SureStart",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 7030,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Lock BIOS Version",
	"Path": "\\Main\\Update System BIOS",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 2005,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Dynamic Runtime Scanning of Boot Block",
	"Path": "\\Security\\Security Configuration\\BIOS SureStart",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 7060,
	"PrerequisiteSize": 1,
	"Prerequisites": [
		"SELECT * FROM HP_BIOSPassword WHERE Name='Setup Password' AND IsSet=1"
	],
	"SecurityLevel": 0,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "NumLock on at boot",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24040,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Wake On LAN",
	"Path": "\\Advanced\\Built-In Device Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 26001,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Boot to Hard Drive",
	"Size": 4,
	"PossibleValues": [
		"Disabled",
		"Boot to Network",
		"Boot to Hard Drive",
		"Boot to Normal Boot Order"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "TPM Device",
	"Path": "\\Security\\Security Configuration\\TPM Embedded Security",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 6010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "Available",
	"Size": 2,
	"PossibleValues": [
		"Hidden",
		"Available"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "TPM State",
	"Path": "\\Security\\Security Configuration\\TPM Embedded Security",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 6020,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "Enable",
	"Size": 2,
	"PossibleValues": [
		"Disable",
		"Enable"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Clear TPM",
	"Path": "\\Security\\Security Configuration\\TPM Embedded Security",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 6030,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 1,
	"Value": "No",
	"Size": 2,
	"PossibleValues": [
		"No",
		"On next boot"
	] 
},
{
	"Class": "HPBIOS_BIOSEnumeration",
	"Name": "Save/Restore GPT of System Hard Drive",
	"Path": "\\Security\\Utilities\\Hard Drive Utilities",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 16010,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Value": "Disabled",
	"Size": 2,
	"PossibleValues": [
		"Disabled",
		"Enabled"
	] 
},
{
	"Class": "HPBIOS_BIOSOrderedList",
	"Name": "USB Type-C Controller(s) Firmware Version:",
	"Value": "TPS65994 : 7.5.0",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 315,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Size": 1,
	"Elements": [
		"TPS65994 : 7.5.0"
	] 
},
{
	"Class": "HPBIOS_BIOSOrderedList",
	"Name": "HBMA Priority List",
	"Value": "USB NIC Dongle:HP External Adapter :0BDA_8153,USB NIC Dongle:HP USB-C Travel Dock :17E9_4352,USB NIC Dongle:HP USB Travel Dock :17E9_4351,USB NIC Dongle:HP 3005pr :17E9_430A,USB NIC Dongle:HP Universal pr :17E9_4327,Thunderbolt Dock:HP Elite Dock :14E4_1682:14E4_1682",
	"Path": "\\Advanced",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 21019,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Size": 6,
	"Elements": [
		"USB NIC Dongle:HP External Adapter :0BDA_8153",
		"USB NIC Dongle:HP USB-C Travel Dock :17E9_4352",
		"USB NIC Dongle:HP USB Travel Dock :17E9_4351",
		"USB NIC Dongle:HP 3005pr :17E9_430A",
		"USB NIC Dongle:HP Universal pr :17E9_4327",
		"Thunderbolt Dock:HP Elite Dock :14E4_1682:14E4_1682"
	] 
},
{
	"Class": "HPBIOS_BIOSOrderedList",
	"Name": "DriveLock Enabled Drives",
	"Value": "",
	"Path": "\\Security\\Utilities\\Hard Drive Utilities",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 16050,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Size": 0,
	"Elements": [
	] 
},
{
	"Class": "HPBIOS_BIOSOrderedList",
	"Name": "UEFI Boot Order",
	"Value": "HDD:M.2:1,HDD:USB:1,UNKNOWN:EXPANSION,NETWORK IPV4:EXPANSION:1,NETWORK IPV6:EXPANSION:1",
	"Path": "\\Advanced\\Boot Options",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 24111,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Size": 5,
	"Elements": [
		"HDD:M.2:1",
		"HDD:USB:1",
		"UNKNOWN:EXPANSION",
		"NETWORK IPV4:EXPANSION:1",
		"NETWORK IPV6:EXPANSION:1"
	] 
},
{
	"Class": "HPBIOS_BIOSOrderedList",
	"Name": "Storage Devices",
	"Value": "WDC PC SN730 SDBPNTY-512G-1006-20196A800563 (512 GB)",
	"Path": "\\Main\\System Information",
	"IsReadOnly": 1,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 0,
	"Sequence": 232,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"Size": 1,
	"Elements": [
		"WDC PC SN730 SDBPNTY-512G-1006-20196A800563 (512 GB)"
	] 
},
{
	"Class": "HPBIOS_BIOSPassword",
	"Name": "Setup Password",
	"Value": "",
	"Path": "\\Security",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 1,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 4,
	"MaxLength": 32,
	"Size": 1,
	"SupportedEncoding": [
		"utf-16"
	],
	"IsSet": 0 
},
{
	"Class": "HPBIOS_BIOSPassword",
	"Name": "Power-On Password",
	"Value": "",
	"Path": "\\Security",
	"IsReadOnly": 0,
	"DisplayInUI": 1,
	"RequiresPhysicalPresence": 1,
	"Sequence": 1,
	"PrerequisiteSize": 0,
	"Prerequisites": [
	],
	"SecurityLevel": 0,
	"MinLength": 4,
	"MaxLength": 32,
	"Size": 1,
	"SupportedEncoding": [
		"utf-16"
	],
	"IsSet": 0 
} 
]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 4/6] Sure Start Security Feature
  2022-04-04 22:05   ` Limonciello, Mario
@ 2022-04-05 16:56     ` Jorge Lopez
  2022-04-05 17:09       ` Limonciello, Mario
  0 siblings, 1 reply; 25+ messages in thread
From: Jorge Lopez @ 2022-04-05 16:56 UTC (permalink / raw)
  To: Limonciello, Mario; +Cc: platform-driver-x86

hi Mario,

On Mon, Apr 4, 2022 at 5:05 PM Limonciello, Mario
<Mario.Limonciello@amd.com> wrote:
>
> [Public]
>
>
>
> > -----Original Message-----
> > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > Sent: Monday, April 4, 2022 15:36
> > To: platform-driver-x86@vger.kernel.org
> > Subject: [PATCH v1 4/6] Sure Start Security Feature
> >
> > Sure Start provides advanced firmware protection and resiliency by
> > identifying and repairing unauthorized BIOS changes.  It maintains an
> > audit log of these events and other important system configuration
> > changes.  The following sysfs entries can be used to read the contents
> > of the audit log.
> >
> >       /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count
> >       /sys/devices/platform/hp-wmi/sure_start/audit_log_entries
> >
> > 'audit_log_entry_count' is a read-only file that returns the number of
> > existing audit log events available to be read
> >
> > 'audit_log_entries' is a read-only file that returns the events in the
> > log
> >
> > This feature requires "Update hp_wmi_group to simplify feature
> > addition" patch.
> >
> > All changes were validated on a HP ZBook Workstation,
> > HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> >
> > Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> >
> > ---
> > Based on the latest platform-drivers-x86.git/for-next
> > ---
> >  drivers/platform/x86/hp-wmi.c | 108
> > ++++++++++++++++++++++++++++++++++
> >  1 file changed, 108 insertions(+)
> >
> > diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
> > index 139dc079c1fa..918e3eaf1b67 100644
> > --- a/drivers/platform/x86/hp-wmi.c
> > +++ b/drivers/platform/x86/hp-wmi.c
> > @@ -126,6 +126,11 @@ enum hp_wmi_spm_commandtype {
> >       HPWMI_SECUREPLATFORM_SET_SK     = 0x12,
> >  };
> >
> > +enum hp_wmi_surestart_commandtype {
> > +     HPWMI_SURESTART_GET_LOG_COUNT   = 0x01,
> > +     HPWMI_SURESTART_GET_LOG = 0x02,
> > +};
> > +
> >  enum hp_wmi_gm_commandtype {
> >       HPWMI_FAN_SPEED_GET_QUERY = 0x11,
> >       HPWMI_SET_PERFORMANCE_MODE = 0x1A,
> > @@ -138,6 +143,7 @@ enum hp_wmi_command {
> >       HPWMI_READ      = 0x01,
> >       HPWMI_WRITE     = 0x02,
> >       HPWMI_ODM       = 0x03,
> > +     HPWMI_SURESTART = 0x20006,
> >       HPWMI_GM        = 0x20008,
> >       HPWMI_SECUREPLATFORM = 0x20010,
> >  };
> > @@ -851,6 +857,7 @@ static ssize_t spm_kek_store(struct kobject *kobj,
> >  {
> >       int ret =
> > hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
> >                                      HPWMI_SECUREPLATFORM, (void *)buf,
> > count, 0);
> > +
> >       return ret ? -EINVAL : count;
> >  }
> >
> > @@ -918,6 +925,106 @@ static const struct attribute_group spm_group = {
> >       .attrs = spm_attrs,
> >  };
> >
> > +/* Sure Start functions */
> > +
> > +#define LOG_MAX_ENTRIES      254
> > +#define LOG_ENTRY_SIZE       16
> > +
> > +/*
> > + * sure_start_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 sure_start_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);
> > +}
> > +
> > +/*
> > + * sure_start_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 sure_start_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;
>
> This is an interface that will be there forever, what are realistic numbers and sizes after a long time?
> I have an AMD HP laptop that is only been used a few months and checked the size like this:
> dd if=audit_log_entries of=/tmp/entries
>
The audit log will grow linearly and it is defined by BIOS.  The total
number of bytes ( audit log size times the max number of audit logs
supported by BIOS) is 4K.
The audit log size reports three values. Number of event logs, audit
log max size (16), and max of audit logs supported by BIOS (254).
(16*254 = 4K).
In your case, the total number of bytes for all audit logs available
is 224 bytes.  You can conclude, your system has 14 audit logs
available to be read  (224/16 = 14)

> If so, then maybe this should be designed as a different interface.
>
> Also, the log is readable by anybody.  Should this be root only?

No.  audit logs will be available to everyone.  The interpretation of
each audit event is done at the application level.

>
> > +
> > +     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);
> > +}
> > +
> > +HPWMI_ATTR_RO(sure_start, audit_log_entry_count);
> > +HPWMI_ATTR_RO(sure_start, audit_log_entries);
> > +
> > +static struct attribute *sure_start_attrs[] = {
> > +     &sure_start_audit_log_entry_count.attr,
> > +     &sure_start_audit_log_entries.attr,
> > +     NULL,
> > +};
> > +
> > +static const struct attribute_group sure_start_group = {
> > +     .name = "sure_start",
> > +     .attrs = sure_start_attrs,
> > +};
> > +
> >  static DEVICE_ATTR_RO(display);
> >  static DEVICE_ATTR_RO(hddtemp);
> >  static DEVICE_ATTR_RW(als);
> > @@ -942,6 +1049,7 @@ static const struct attribute_group hp_wmi_group =
> > {
> >  static const struct attribute_group *hp_wmi_groups[] = {
> >       &hp_wmi_group,
> >       &spm_group,
> > +     &sure_start_group,
> >       NULL,
> >  };
> >
> > --
> > 2.25.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v1 4/6] Sure Start Security Feature
  2022-04-05 16:56     ` Jorge Lopez
@ 2022-04-05 17:09       ` Limonciello, Mario
  2022-04-05 18:52         ` Jorge Lopez
  0 siblings, 1 reply; 25+ messages in thread
From: Limonciello, Mario @ 2022-04-05 17:09 UTC (permalink / raw)
  To: Jorge Lopez; +Cc: platform-driver-x86

[Public]



> -----Original Message-----
> From: Jorge Lopez <jorgealtxwork@gmail.com>
> Sent: Tuesday, April 5, 2022 11:56
> To: Limonciello, Mario <Mario.Limonciello@amd.com>
> Cc: platform-driver-x86@vger.kernel.org
> Subject: Re: [PATCH v1 4/6] Sure Start Security Feature
> 
> hi Mario,
> 
> On Mon, Apr 4, 2022 at 5:05 PM Limonciello, Mario
> <Mario.Limonciello@amd.com> wrote:
> >
> > [Public]
> >
> >
> >
> > > -----Original Message-----
> > > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > Sent: Monday, April 4, 2022 15:36
> > > To: platform-driver-x86@vger.kernel.org
> > > Subject: [PATCH v1 4/6] Sure Start Security Feature
> > >
> > > Sure Start provides advanced firmware protection and resiliency by
> > > identifying and repairing unauthorized BIOS changes.  It maintains an
> > > audit log of these events and other important system configuration
> > > changes.  The following sysfs entries can be used to read the contents
> > > of the audit log.
> > >
> > >       /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count
> > >       /sys/devices/platform/hp-wmi/sure_start/audit_log_entries
> > >
> > > 'audit_log_entry_count' is a read-only file that returns the number of
> > > existing audit log events available to be read
> > >
> > > 'audit_log_entries' is a read-only file that returns the events in the
> > > log
> > >
> > > This feature requires "Update hp_wmi_group to simplify feature
> > > addition" patch.
> > >
> > > All changes were validated on a HP ZBook Workstation,
> > > HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> > >
> > > Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> > >
> > > ---
> > > Based on the latest platform-drivers-x86.git/for-next
> > > ---
> > >  drivers/platform/x86/hp-wmi.c | 108
> > > ++++++++++++++++++++++++++++++++++
> > >  1 file changed, 108 insertions(+)
> > >
> > > diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-
> wmi.c
> > > index 139dc079c1fa..918e3eaf1b67 100644
> > > --- a/drivers/platform/x86/hp-wmi.c
> > > +++ b/drivers/platform/x86/hp-wmi.c
> > > @@ -126,6 +126,11 @@ enum hp_wmi_spm_commandtype {
> > >       HPWMI_SECUREPLATFORM_SET_SK     = 0x12,
> > >  };
> > >
> > > +enum hp_wmi_surestart_commandtype {
> > > +     HPWMI_SURESTART_GET_LOG_COUNT   = 0x01,
> > > +     HPWMI_SURESTART_GET_LOG = 0x02,
> > > +};
> > > +
> > >  enum hp_wmi_gm_commandtype {
> > >       HPWMI_FAN_SPEED_GET_QUERY = 0x11,
> > >       HPWMI_SET_PERFORMANCE_MODE = 0x1A,
> > > @@ -138,6 +143,7 @@ enum hp_wmi_command {
> > >       HPWMI_READ      = 0x01,
> > >       HPWMI_WRITE     = 0x02,
> > >       HPWMI_ODM       = 0x03,
> > > +     HPWMI_SURESTART = 0x20006,
> > >       HPWMI_GM        = 0x20008,
> > >       HPWMI_SECUREPLATFORM = 0x20010,
> > >  };
> > > @@ -851,6 +857,7 @@ static ssize_t spm_kek_store(struct kobject *kobj,
> > >  {
> > >       int ret =
> > > hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
> > >                                      HPWMI_SECUREPLATFORM, (void *)buf,
> > > count, 0);
> > > +
> > >       return ret ? -EINVAL : count;
> > >  }
> > >
> > > @@ -918,6 +925,106 @@ static const struct attribute_group spm_group =
> {
> > >       .attrs = spm_attrs,
> > >  };
> > >
> > > +/* Sure Start functions */
> > > +
> > > +#define LOG_MAX_ENTRIES      254
> > > +#define LOG_ENTRY_SIZE       16
> > > +
> > > +/*
> > > + * sure_start_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 sure_start_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);
> > > +}
> > > +
> > > +/*
> > > + * sure_start_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 sure_start_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;
> >
> > This is an interface that will be there forever, what are realistic numbers
> and sizes after a long time?
> > I have an AMD HP laptop that is only been used a few months and checked
> the size like this:
> > dd if=audit_log_entries of=/tmp/entries
> >
> The audit log will grow linearly and it is defined by BIOS.  The total
> number of bytes ( audit log size times the max number of audit logs
> supported by BIOS) is 4K.
> The audit log size reports three values. Number of event logs, audit
> log max size (16), and max of audit logs supported by BIOS (254).
> (16*254 = 4K).
> In your case, the total number of bytes for all audit logs available
> is 224 bytes.  You can conclude, your system has 14 audit logs
> available to be read  (224/16 = 14)

 But so if this is growing linearly what happens if BIOS ends up with
 more than 4k audit logs?  Can that happen?

If that happens  I can no longer access them from userspace right?

> 
> > If so, then maybe this should be designed as a different interface.
> >
> > Also, the log is readable by anybody.  Should this be root only?
> 
> No.  audit logs will be available to everyone.  The interpretation of
> each audit event is done at the application level.

Got it - thanks

> 
> >
> > > +
> > > +     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);
> > > +}
> > > +
> > > +HPWMI_ATTR_RO(sure_start, audit_log_entry_count);
> > > +HPWMI_ATTR_RO(sure_start, audit_log_entries);
> > > +
> > > +static struct attribute *sure_start_attrs[] = {
> > > +     &sure_start_audit_log_entry_count.attr,
> > > +     &sure_start_audit_log_entries.attr,
> > > +     NULL,
> > > +};
> > > +
> > > +static const struct attribute_group sure_start_group = {
> > > +     .name = "sure_start",
> > > +     .attrs = sure_start_attrs,
> > > +};
> > > +
> > >  static DEVICE_ATTR_RO(display);
> > >  static DEVICE_ATTR_RO(hddtemp);
> > >  static DEVICE_ATTR_RW(als);
> > > @@ -942,6 +1049,7 @@ static const struct attribute_group
> hp_wmi_group =
> > > {
> > >  static const struct attribute_group *hp_wmi_groups[] = {
> > >       &hp_wmi_group,
> > >       &spm_group,
> > > +     &sure_start_group,
> > >       NULL,
> > >  };
> > >
> > > --
> > > 2.25.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-05 16:52       ` Jorge Lopez
@ 2022-04-05 17:13         ` Limonciello, Mario
  2022-04-07 13:44           ` Jorge Lopez
  0 siblings, 1 reply; 25+ messages in thread
From: Limonciello, Mario @ 2022-04-05 17:13 UTC (permalink / raw)
  To: Jorge Lopez, Hans de Goede; +Cc: platform-driver-x86

[Public]



> -----Original Message-----
> From: Jorge Lopez <jorgealtxwork@gmail.com>
> Sent: Tuesday, April 5, 2022 11:52
> To: Hans de Goede <hdegoede@redhat.com>
> Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-driver-
> x86@vger.kernel.org
> Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> 
> Hi Hans,
> 
> On Tue, Apr 5, 2022 at 6:54 AM Hans de Goede <hdegoede@redhat.com>
> wrote:
> >
> > Hi,
> >
> > On 4/4/22 23:59, Limonciello, Mario wrote:
> > > [Public]
> > >
> > >
> > >
> > >> -----Original Message-----
> > >> From: Jorge Lopez <jorgealtxwork@gmail.com>
> > >> Sent: Monday, April 4, 2022 15:36
> > >> To: platform-driver-x86@vger.kernel.org
> > >> Subject: [PATCH v1 5/6] Sure Admin Security Feature
> > >>
> > >> 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. Behind the scenes, Sure Admin uses Secure
> Platform
> > >> Management (SPM) and WMI
> > >>
> > >> 'settings' is a file associated with Sure Admin. BIOS settings can be
> > >> read or written through the Sure Admin settings file in sysfs
> > >>
> > >>      /sys/devices/platform/hp-wmi/sure_admin/settings
> > >>
> > >> 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"
> > >>              ]
> > >>      }
> > >>
> > >
> > > This sounds like it has re-invented /sys/class/firmware-attributes.
> > >
> > > Shouldn't you adopt that API?
> >
> > I fully agree. Jorge as I already indicated in our off-list
> > conversation when you initially started working on this
> > feature, we already have a standardized API for querying/changing
> > BIOS settings from within Linux:
> >
> 
> I agree that changing the BIOS settings from within Linux could
> utilize the new methodology,  I will need to look closely at the
> requirements before I can proceed to make the changes.
> Keep in mind authentication of the values is done by BIOS.  No Linux
> process validates any data name, value, or auth token; only BIOS.  All
> data written to the sysfs file is not validated, it is just forward to
> BIOS.  See spm_kek_store and spm_sk_store functions.

That's fine, and it's a safer design to have BIOS validate it.

> One point I must make clear when updating BIOS settings.  any  NOT
> read-only BIOS settings can be changed by the application at any time.
>    This list of settings changes from one system to another.

Right.

> 
> I am in disagreement with reading the settings.  hp-wmi does not read
> one value at a time. It reads all values exposed by BIOS.  See
> attached sample output.

The settings can all be read at initialization time for the driver and cached
then.

> The method for how all BIOS settings are reported needs to match the
> method how Windows products do it.  It is a requirement to start
> migrating customers from Windows to Linux while minimizing how BIOS
> data is reported.

Because we have a standardized API in Linux for this, I think it's best to abstract
this behind a userspace application/script.  If they expect to see it in the format you
showed, the userspace application can take the data from Linux and package it that
way.

You'll have richer libraries and languages and tools to work from when doing this too.
It should make it a lot less painful.

> 
> I will investigate the new API and bring it to the team's attention.
> 
> >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> D&amp;reserved=0
> >
> > and any new code (such as this patch) which implements BIOS
> > setting changing MUST follow this standardized API (extending
> > it where necessary).
> >
> > I'm sorry but this patch is not acceptable in its current form,
> > it needs to be *completely rewritten* to implement:
> >
> >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> D&amp;reserved=0
> >
> > See:
> >
> >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fdell%2Fdell-wmi-
> sysman&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8f
> ea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> 7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> mp;sdata=z5jmH7ECYBeLcndQ2vfHaUuyE04Eaf1Lymh6BjnyJ%2Fk%3D&amp;r
> eserved=0
> >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fthink-
> lmi.c&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea
> 104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> 0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> sdata=5n6w9LEB2iWpj1cOQP6Ngz94AqP1Bu4vu8T0EdN%2FThU%3D&amp;re
> served=0
> >
> > for example code / for 2 drivers from other vendors already
> > implementing this.
> >
> > The same applies to the:
> >
> > "[PATCH v1 3/6] Secure Platform Management Security Feature"
> >
> > this needs to be implemented as
> > a /sys/class/firmware-attributes/*/authentication/
> > authentication method, see for example these Lenovo specific
> > addition to the /sys/class/firmware-attributes/*/authentication/
> > userspace API for similar functionality on Lenovo Think* devices:
> >
> >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> 2Fcommit%2F%3Fid%3D06384573a3e8335ac6797577e545c33dbf91b490&amp;
> data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea1040342827
> 08da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C63784
> 7743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLC
> JQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=eldS
> 4H3Z%2BAyL%2FG%2FO9W9rDGC37yh5sGgtUhpKdUAoSmA%3D&amp;reser
> ved=0
> >
> > I'll merge patches 1-2 sometime this week since those are
> > fine and it will be good to have those "out of the way",
> > but the rest of the series will need to be rewritten
> > taken the above comments into account.
> 
> v1-0003-Sure-Start-Security-Feature.patch  reports the number of audit
> logs available and reports them when read.    it does not read/write
> BIOS settings hence it does not fall within the same category as
> patches v1-0002-Secure-Platform-Management-Security-Feature.patch and
> v1-0004-Sure-Admin-Security-Feature.patch
> Do you agree?
> 
> >
> > Regards,
> >
> > Hans
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> > >
> > >> This feature requires "Update hp_wmi_group to simplify feature
> > >> addition" patch.
> > >>
> > >> All changes were validated on a HP ZBook Workstation,
> > >> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> > >>
> > >> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> > >>
> > >> ---
> > >> Based on the latest platform-drivers-x86.git/for-next
> > >> ---
> > >>  drivers/platform/x86/hp-wmi.c | 977
> > >> ++++++++++++++++++++++++++++++++++
> > >>  1 file changed, 977 insertions(+)
> > >>
> > >> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-
> wmi.c
> > >> index 918e3eaf1b67..b72ca18b77a6 100644
> > >> --- a/drivers/platform/x86/hp-wmi.c
> > >> +++ b/drivers/platform/x86/hp-wmi.c
> > >> @@ -27,6 +27,7 @@
> > >>  #include <linux/rfkill.h>
> > >>  #include <linux/string.h>
> > >>  #include <linux/dmi.h>
> > >> +#include <linux/nls.h>
> > >>
> > >>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
> > >>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
> > >> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-
> > >> 3D44E2C707E4");
> > >>
> > >>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-
> ACCDC67EF61C"
> > >>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-
> 3D44E2C707E4"
> > >> +
> > >>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
> > >>
> > >> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-
> 6A1B8106F83C"
> > >> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
> > >> E293ADB9BF05"
> > >> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-
> > >> 4A3C09E75133"
> > >> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
> > >> 7045CB4DA745"
> > >> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
> > >> 015176049E2D"
> > >> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-
> > >> C7CB9B4B8D5E"
> > >> +
> > >>  /* DMI board names of devices that should use the omen specific path
> for
> > >>   * thermal profiles.
> > >>   * This was obtained by taking a look in the windows omen command
> center
> > >> @@ -1025,6 +1034,973 @@ static const struct attribute_group
> > >> sure_start_group = {
> > >>      .attrs = sure_start_attrs,
> > >>  };
> > >>
> > >> +
> > >> +static 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;
> > >> +    int  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));
> > >> +            ret = kstrtoint(tmp, 16, &ch);
> > >> +            if (ret) {
> > >> +                    new_len = 0;
> > >> +                    break;
> > >> +            }
> > >> +
> > >> +            if (ch == '\\')
> > >> +                    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;
> > >> +    }
> > >> +
> > >> +    if (ret)
> > >> +            kfree(new_str);
> > >> +    return ret;
> > >> +}
> > >> +
> > >> +/*
> > >> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and
> instance
> > >> + *
> > >> + * @guid:   GUID associated with the ACPI list of managed objects
> > >> + * @instance:       Instance index to query on the ACPI list
> > >> + * @obj:    The output ACPI object of type ACPI_TYPE_PACKAGE
> > >> + *          or ACPI_TYPE_BUFFER (freed by the callee)
> > >> + *
> > >> + * Returns  zero on success.  Otherwise,an error inherited from
> > >> + *          wmi_query_block(). It returns a obj by parameter if
> > >> + *          the query returned object of type buffer or package,
> > >> + *          otherwise, a null obj is returned.
> > >> + *
> > >> + * Note: obj should be freed by the callee once it is finished working
> with it
> > >> + */
> > >> +static int hp_wmi_get_setting_object(char *guid, int instance,
> > >> +                            union acpi_object **obj)
> > >> +{
> > >> +    struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL
> > >> };
> > >> +    union acpi_object *tmp = NULL;
> > >> +    int ret;
> > >> +
> > >> +    ret = wmi_query_block(guid, instance, &output);
> > >> +    if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
> > >> +            tmp = output.pointer;
> > >> +            if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
> > >> ACPI_TYPE_PACKAGE)
> > >> +                    *obj = output.pointer;
> > >> +            else {
> > >> +                    kfree(tmp);
> > >> +                    *obj = NULL;
> > >> +            }
> > >> +    }
> > >> +
> > >> +    return ret;
> > >> +}
> > >> +
> > >> +
> > >> +static 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;
> > >> +
> > >> +    if (size == 0)
> > >> +            goto cleanup_exit;
> > >> +
> > >> +    for (i = 0; i < size; i++)
> > >> +            if (ptr[i] == '\\')
> > >> +                    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);
> > >> +
> > >> +    if (escape == 0) {
> > >> +            ptr += (ptrlen / 2);
> > >> +            goto cleanup_exit;
> > >> +    }
> > >> +    /*
> > >> +     * Convert escape characters only when found
> > >> +     */
> > >> +    for (i = 0; i < size; i++) {
> > >> +            if (*ptr == '\\')
> > >> +                    output[i++] = '\\';
> > >> +            output[i] = *ptr;
> > >> +            ptr++;
> > >> +    }
> > >> +
> > >> +cleanup_exit:
> > >> +    *buffer = ptr;
> > >> +    return 0;
> > >> +}
> > >> +
> > >> +static int get_integer_from_buffer(int **buffer, int *integer)
> > >> +{
> > >> +    int *ptr = PTR_ALIGN(*buffer, 4);
> > >> +    *integer = *(ptr++);
> > >> +    *buffer = ptr;
> > >> +    return 0;
> > >> +}
> > >> +
> > >> +
> > >> +// Sure Admin functions
> > >> +enum hp_wmi_data_type {
> > >> +    HPWMI_STRING_TYPE,
> > >> +    HPWMI_INTEGER_TYPE,
> > >> +    HPWMI_ENUMERATION_TYPE,
> > >> +    HPWMI_ORDEREDLIST_TYPE,
> > >> +    HPWMI_PASSWORD_TYPE,
> > >> +};
> > >> +
> > >> +#define HP_WMI_COMMON_ELEMENTS      \
> > >> +    "Name", \
> > >> +    "Value",        \
> > >> +    "Path", \
> > >> +    "IsReadOnly",   \
> > >> +    "DisplayInUI",  \
> > >> +    "RequiresPhysicalPresence",     \
> > >> +    "Sequence",     \
> > >> +    "PrerequisiteSize",     \
> > >> +    "SecurityLevel"
> > >> +
> > >> +const char *hp_wmi_string_elements[] = {
> > >> +    HP_WMI_COMMON_ELEMENTS,
> > >> +    "MinLength",
> > >> +    "MaxLength"
> > >> +};
> > >> +
> > >> +const char *hp_wmi_integer_elements[] = {
> > >> +    HP_WMI_COMMON_ELEMENTS,
> > >> +    "LowerBound",
> > >> +    "UpperBound",
> > >> +    "IntValue"
> > >> +};
> > >> +
> > >> +const char *hp_wmi_enumeration_elements[] = {
> > >> +    HP_WMI_COMMON_ELEMENTS,
> > >> +    "CurrentValue",
> > >> +    "Size"
> > >> +};
> > >> +
> > >> +const char *hp_wmi_orderedlist_elements[] = {
> > >> +    HP_WMI_COMMON_ELEMENTS,
> > >> +    "Size"
> > >> +};
> > >> +
> > >> +const char *hp_wmi_password_elements[] = {
> > >> +    HP_WMI_COMMON_ELEMENTS,
> > >> +    "MinLength",
> > >> +    "MaxLength",
> > >> +    "Size",
> > >> +    "SupportedEncoding",
> > >> +    "IsSet"
> > >> +};
> > >> +
> > >> +const char **hp_wmi_elements[] = {
> > >> +    hp_wmi_string_elements,
> > >> +    hp_wmi_integer_elements,
> > >> +    hp_wmi_enumeration_elements,
> > >> +    hp_wmi_orderedlist_elements,
> > >> +    hp_wmi_password_elements
> > >> +};
> > >> +
> > >> +const int hp_wmi_elements_count[] = {
> > >> +    ARRAY_SIZE(hp_wmi_string_elements),
> > >> +    ARRAY_SIZE(hp_wmi_integer_elements),
> > >> +    ARRAY_SIZE(hp_wmi_enumeration_elements),
> > >> +    ARRAY_SIZE(hp_wmi_orderedlist_elements),
> > >> +    ARRAY_SIZE(hp_wmi_password_elements)
> > >> +};
> > >> +
> > >> +const char *hp_wmi_classes[] = {
> > >> +    "HPBIOS_BIOSString",
> > >> +    "HPBIOS_BIOSInteger",
> > >> +    "HPBIOS_BIOSEnumeration",
> > >> +    "HPBIOS_BIOSOrderedList",
> > >> +    "HPBIOS_BIOSPassword"
> > >> +};
> > >> +
> > >> +static DEFINE_MUTEX(buf_mutex);
> > >> +static int settings_buffer_size;
> > >> +static int buf_alloc_size;
> > >> +static char *hp_bios_settings_buffer;
> > >> +
> > >> +
> > >> +static int append_package_elements_to_buffer(union acpi_object
> *obj,
> > >> +                                         char *buf, int alloc_size, enum
> > >> hp_wmi_data_type type)
> > >> +{
> > >> +    int i;
> > >> +    union acpi_object *pobj = NULL;
> > >> +    char *value = NULL;
> > >> +    int value_len;
> > >> +    char *tmpstr = NULL;
> > >> +    char *part_tmp = NULL;
> > >> +    int tmp_len = 0;
> > >> +    char *part = NULL;
> > >> +    int status = 0;
> > >> +    int size = 0;
> > >> +    int buf_size;
> > >> +
> > >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > >> +            return -EINVAL;
> > >> +
> > >> +    if (obj->type != ACPI_TYPE_PACKAGE)
> > >> +            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]);
> > >> +
> > >> +    for (i = 0; i < 3; i++) {
> > >> +            pobj = &(obj->package.elements[i]);
> > >> +            if (pobj->type == ACPI_TYPE_STRING) {
> > >> +                    status = convert_hexstr_to_str(&pobj-
> > >>> string.pointer,
> > >> +                                                   pobj->string.length,
> > >> &value, &value_len);
> > >> +                    if (ACPI_FAILURE(status))
> > >> +                            continue;
> > >> +                    /*
> > >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > >> since
> > >> +                     * 'CurrentValue' is reported.
> > >> +                     */
> > >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > >> +                            buf_size = snprintf(buf, alloc_size,
> > >> +                                                "%s\t\"%s\": \"%s\",\n",
> > >> +                                                buf,
> > >> +
> > >> hp_wmi_elements[type][i], value);
> > >> +
> > >> +            }
> > >> +            kfree(value);
> > >> +            value = NULL;
> > >> +    }
> > >> +
> > >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > >> +            pobj = &(obj->package.elements[i]);
> > >> +
> > >> +            if (type == HPWMI_ENUMERATION_TYPE &&
> > >> +                i == 9 &&
> > >> +                pobj->type == ACPI_TYPE_STRING) {
> > >> +                    /*
> > >> +                     * Report "CurrentValue" as "Value"
> > >> +                     */
> > >> +                    status = convert_hexstr_to_str(&pobj-
> > >>> string.pointer,
> > >> +                                                   pobj->string.length,
> > >> +                                                   &value, &value_len);
> > >> +                    if (ACPI_FAILURE(status))
> > >> +                            continue;
> > >> +
> > >> +                    buf_size = snprintf(buf, alloc_size,
> > >> +                                        "%s\t\"Value\": \"%s\",\n",
> > >> +                                        buf, value);
> > >> +                    kfree(value);
> > >> +                    value = NULL;
> > >> +
> > >> +            } else if (type == HPWMI_PASSWORD_TYPE &&
> > >> +                       i == 12 &&
> > >> +                       pobj->type == ACPI_TYPE_STRING) {
> > >> +                    /*
> > >> +                     * Report list of "SupportEncoding"
> > >> +                     *
> > >> +                     *      "SupportedEncoding": [
> > >> +                     *              "utf-16"
> > >> +                     *      ],
> > >> +                     *
> > >> +                     */
> > >> +
> > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > >> +                                        buf, hp_wmi_elements[type][i]);
> > >> +                    while (size--) {
> > >> +                            pobj = &(obj->package.elements[i]);
> > >> +                            status = convert_hexstr_to_str(&pobj-
> > >>> string.pointer,
> > >> +                                                           pobj-
> > >>> string.length,
> > >> +                                                           &value,
> > >> &value_len);
> > >> +                            if (ACPI_FAILURE(status))
> > >> +                                    continue;
> > >> +
> > >> +                            if (size) {
> > >> +                                    buf_size = snprintf(buf, alloc_size,
> > >> +                                                        "%s\t\t\"%s\",\n",
> > >> buf, value);
> > >> +                                    i++;
> > >> +                            } else
> > >> +                                    buf_size = snprintf(buf, alloc_size,
> > >> +                                                        "%s\t\t\"%s\"\n",
> > >> buf, value);
> > >> +
> > >> +                            kfree(value);
> > >> +                            value = NULL;
> > >> +
> > >> +                    }
> > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >> +                    continue;
> > >> +
> > >> +            } else if (pobj->type == ACPI_TYPE_INTEGER) {
> > >> +                    /*
> > >> +                     * Report "PrerequisiteSize" and "Size" values
> > >> +                     *      ...
> > >> +                     *      "PrerequisiteSize": 1,
> > >> +                     *      ...
> > >> +                     *      "Size": 2,
> > >> +                     *      ...
> > >> +                     */
> > >> +                    if (i == 7)
> > >> +                            size = pobj->integer.value;
> > >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > >> 9)
> > >> +                            size = pobj->integer.value;
> > >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > >> == 10)
> > >> +                            size = pobj->integer.value;
> > >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > >> 11)
> > >> +                            size = pobj->integer.value;
> > >> +
> > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > >> %lld,\n", buf,
> > >> +                                        hp_wmi_elements[type][i], pobj-
> > >>> integer.value);
> > >> +            }
> > >> +    }
> > >> +
> > >> +    if (type == HPWMI_ENUMERATION_TYPE) {
> > >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
> > >> [\n", buf);
> > >> +            for (i = 0; i < size; i++) {
> > >> +                    pobj = &(obj->package.elements[i +
> > >> hp_wmi_elements_count[type]]);
> > >> +
> > >> +                    status = convert_hexstr_to_str(&pobj-
> > >>> string.pointer,
> > >> +                                                   pobj->string.length,
> > >> +                                                   &value, &value_len);
> > >> +                    if (ACPI_FAILURE(status))
> > >> +                            break;
> > >> +
> > >> +                    /*
> > >> +                     * Report list of "PossibleValues" of size
> > >> +                     * "Size"
> > >> +                     *      ...
> > >> +                     *      "Size": 2,
> > >> +                     *      "PossibleValues": [
> > >> +                     *                      "Disable",
> > >> +                     *                      "Enable"]
> > >> +                     */
> > >> +                    if (i == (size - 1))
> > >> +                            buf_size = snprintf(buf, alloc_size,
> > >> +                                                "%s\t\t\"%s\"\n", buf,
> > >> value);
> > >> +                    else
> > >> +                            buf_size = snprintf(buf, alloc_size,
> > >> +                                                "%s\t\t\"%s\",\n", buf,
> > >> value);
> > >> +                    kfree(value);
> > >> +                    value = NULL;
> > >> +            }
> > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >> +    }
> > >> +
> > >> +    if (type == HPWMI_ORDEREDLIST_TYPE) {
> > >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
> > >> buf);
> > >> +            if (size <= 0)
> > >> +                    goto finish_ordered_list;
> > >> +
> > >> +            pobj = &(obj-
> > >>> package.elements[hp_wmi_elements_count[type]]);
> > >> +            status = convert_hexstr_to_str(&pobj->string.pointer,
> > >> +                                           pobj->string.length, &value,
> > >> &value_len);
> > >> +            if (ACPI_FAILURE(status))
> > >> +                    goto finish_ordered_list;
> > >> +
> > >> +            /*
> > >> +             * 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(&value, value_len, &tmpstr,
> > >> &tmp_len);
> > >> +            if (ACPI_FAILURE(status))
> > >> +                    goto finish_ordered_list;
> > >> +
> > >> +            part_tmp = tmpstr;
> > >> +            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);
> > >> +            }
> > >> +    }
> > >> +
> > >> +finish_ordered_list:
> > >> +    if (type == HPWMI_ORDEREDLIST_TYPE)
> > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >> +
> > >> +    /*
> > >> +     * remove trailing comma
> > >> +     */
> > >> +    if (buf_size > 3)
> > >> +            buf[buf_size - 2] = ' ';
> > >> +
> > >> +    kfree(tmpstr);
> > >> +    kfree(value);
> > >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > >> +}
> > >> +
> > >> +static int append_buffer_elements_to_buffer(union acpi_object *obj,
> > >> +                                        char *buf, int alloc_size, enum
> > >> hp_wmi_data_type type)
> > >> +{
> > >> +    int buf_size;
> > >> +    int status;
> > >> +    char *str = NULL;
> > >> +    int i;
> > >> +    int j;
> > >> +    int integer;
> > >> +    int size = 0;
> > >> +
> > >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > >> +            return -EINVAL;
> > >> +
> > >> +    if (obj->type != ACPI_TYPE_BUFFER)
> > >> +            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]);
> > >> +
> > >> +    for (i = 0; i < 3; i++) {
> > >> +            status = get_string_from_buffer((u16 **)&obj-
> > >>> buffer.pointer, &str);
> > >> +            if (ACPI_SUCCESS(status)) {
> > >> +                    /*
> > >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > >> since
> > >> +                     * 'CurrentValue' is reported.
> > >> +                     */
> > >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > >> +                            buf_size = snprintf(buf, alloc_size,
> > >> +                                                "%s\t\"%s\": \"%s\",\n",
> > >> +                                                buf,
> > >> +
> > >> hp_wmi_elements[type][i], str);
> > >> +            }
> > >> +            kfree(str);
> > >> +            str = NULL;
> > >> +
> > >> +    }
> > >> +
> > >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > >> +            if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
> > >> +                    status = get_string_from_buffer((u16 **)&obj-
> > >>> buffer.pointer, &str);
> > >> +                    if (ACPI_SUCCESS(status)) {
> > >> +                            /*
> > >> +                             * Report "CurrentValue" as "Value"
> > >> +                             */
> > >> +                            buf_size = snprintf(buf, alloc_size,
> > >> +                                                "%s\t\"Value\": \"%s\",\n",
> > >> buf, str);
> > >> +                    }
> > >> +                    kfree(str);
> > >> +                    str = NULL;
> > >> +                    continue;
> > >> +
> > >> +            } else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
> > >> +                    /*
> > >> +                     * Report list of "SupportEncoding"
> > >> +                     *
> > >> +                     *      "SupportedEncoding": [
> > >> +                     *              "utf-16"
> > >> +                     *      ],
> > >> +                     *
> > >> +                     */
> > >> +
> > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > >> +                                        buf, hp_wmi_elements[type][i]);
> > >> +                    for (j = 0; j < size; j++) {
> > >> +                            status = get_string_from_buffer((u16
> > >> **)&obj->buffer.pointer, &str);
> > >> +                            if (ACPI_SUCCESS(status)) {
> > >> +                                    if (j == size - 1)
> > >> +                                            buf_size = snprintf(buf,
> > >> alloc_size,
> > >> +
> > >> "%s\t\t\"%s\"\n", buf, str);
> > >> +                                    else
> > >> +                                            buf_size = snprintf(buf,
> > >> alloc_size,
> > >> +
> > >> "%s\t\t\"%s\",\n", buf, str);
> > >> +                            }
> > >> +                            kfree(str);
> > >> +                            str = NULL;
> > >> +                    }
> > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >> +                    continue;
> > >> +            }
> > >> +
> > >> +            size = 0;
> > >> +            status = get_integer_from_buffer((int **)&obj-
> > >>> buffer.pointer, &integer);
> > >> +            if (ACPI_SUCCESS(status)) {
> > >> +                    /*
> > >> +                     * Report "PrerequisiteSize" and "Size" values
> > >> +                     *      ...
> > >> +                     *      "PrerequisiteSize": 1,
> > >> +                     *      ...
> > >> +                     *      "Size": 2,
> > >> +                     *      ...
> > >> +                     */
> > >> +                    if (i == 7)
> > >> +                            size = integer;
> > >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > >> == 10)
> > >> +                            size = integer;
> > >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > >> 9)
> > >> +                            size = integer;
> > >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > >> 11)
> > >> +                            size = integer;
> > >> +
> > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > >> %d,\n", buf,
> > >> +                                        hp_wmi_elements[type][i],
> > >> integer);
> > >> +            }
> > >> +
> > >> +            if (size > 20)
> > >> +                    pr_warn("%s exceeded the maximum number of
> > >> elements supported or data may be malformed\n",
> > >> +                            hp_wmi_elements[type][i]);
> > >> +
> > >> +            if (ACPI_SUCCESS(status) && i == 7) {
> > >> +                    buf_size = snprintf(buf, alloc_size,
> > >> "%s\t\"Prerequisites\": [\n", buf);
> > >> +                    for (j = 0; j < size; j++) {
> > >> +                            status = get_string_from_buffer((u16
> > >> **)&obj->buffer.pointer, &str);
> > >> +                            if (ACPI_SUCCESS(status)) {
> > >> +                                    buf_size = snprintf(buf, alloc_size,
> > >> "%s\t\t\"%s\"", buf, str);
> > >> +
> > >> +                                    if (j == size - 1)
> > >> +                                            buf_size = snprintf(buf,
> > >> alloc_size, "%s\n", buf);
> > >> +                                    else
> > >> +                                            buf_size = snprintf(buf,
> > >> alloc_size, "%s,\n", buf);
> > >> +
> > >> +                            }
> > >> +                            kfree(str);
> > >> +                            str = NULL;
> > >> +                    }
> > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >> +            }
> > >> +    }
> > >> +
> > >> +    if (type == HPWMI_ENUMERATION_TYPE || type ==
> > >> HPWMI_ORDEREDLIST_TYPE) {
> > >> +            if (type == HPWMI_ENUMERATION_TYPE)
> > >> +                    buf_size = snprintf(buf, alloc_size,
> > >> "%s\t\"PossibleValues\": [\n", buf);
> > >> +            else
> > >> +                    buf_size = snprintf(buf, alloc_size,
> > >> "%s\t\"Elements\": [\n", buf);
> > >> +
> > >> +            for (i = 0; i < size; i++) {
> > >> +                    status = get_string_from_buffer((u16 **)&obj-
> > >>> buffer.pointer, &str);
> > >> +                    if (ACPI_SUCCESS(status)) {
> > >> +                            buf_size = snprintf(buf, alloc_size,
> > >> "%s\t\t\"%s\"", buf, str);
> > >> +
> > >> +                            if (i == size - 1)
> > >> +                                    buf_size = snprintf(buf, alloc_size,
> > >> "%s\n", buf);
> > >> +                            else
> > >> +                                    buf_size = snprintf(buf, alloc_size,
> > >> "%s,\n", buf);
> > >> +
> > >> +                    }
> > >> +                    kfree(str);
> > >> +                    str = NULL;
> > >> +            }
> > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >> +    }
> > >> +
> > >> +    /*
> > >> +     * remove trailing comma
> > >> +     */
> > >> +    if (buf_size > 3)
> > >> +            buf[buf_size - 2] = ' ';
> > >> +
> > >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > >> +}
> > >> +
> > >> +static int hp_bios_settings_free_buffer(void)
> > >> +{
> > >> +    mutex_lock(&buf_mutex);
> > >> +    kfree(hp_bios_settings_buffer);
> > >> +    settings_buffer_size = 0;
> > >> +    buf_alloc_size = 0;
> > >> +    mutex_unlock(&buf_mutex);
> > >> +
> > >> +    return 0;
> > >> +}
> > >> +
> > >> +static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
> > >> +                                       int *alloc_size,
> > >> +                                       struct mutex *buf_mutex)
> > >> +{
> > >> +    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(buf_mutex);
> > >> +            new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
> > >> +            mutex_unlock(buf_mutex);
> > >> +            if (new_buf) {
> > >> +                    mutex_lock(buf_mutex);
> > >> +                    *buf = new_buf;
> > >> +                    *alloc_size = ksize(new_buf);
> > >> +                    mutex_unlock(buf_mutex);
> > >> +            } else {
> > >> +                    hp_bios_settings_free_buffer();
> > >> +                    ret = -ENOMEM;
> > >> +            }
> > >> +    }
> > >> +
> > >> +    return ret;
> > >> +}
> > >> +
> > >> +static int append_settings_to_buffer(char *guid, int type, char **buf,
> > >> +                                 int *buf_size, int *alloc_size,
> > >> +                                 struct mutex *buf_mutex)
> > >> +{
> > >> +    union acpi_object *obj = NULL;
> > >> +    int ret = 0;
> > >> +    int status = 0;
> > >> +    int instance = 0;
> > >> +
> > >> +    /*
> > >> +     * Query all the instances until to receive a AE_BAD_PARAMETER
> > >> +     */
> > >> +    do {
> > >> +            ret = hp_wmi_get_setting_object(guid, instance++, &obj);
> > >> +            if (ACPI_SUCCESS(ret) && obj != NULL) {
> > >> +                    status = 0;
> > >> +                    if (obj->type == ACPI_TYPE_PACKAGE) {
> > >> +                            mutex_lock(buf_mutex);
> > >> +                            status =
> > >> append_package_elements_to_buffer(obj,
> > >> +                                                    *buf, *alloc_size,
> > >> type);
> > >> +                            if (status > 0)
> > >> +                                    *buf_size = status;
> > >> +                            mutex_unlock(buf_mutex);
> > >> +
> > >> +                    } else if (obj->type == ACPI_TYPE_BUFFER) {
> > >> +                            mutex_lock(buf_mutex);
> > >> +                            status =
> > >> append_buffer_elements_to_buffer(obj,
> > >> +                                                    *buf, *alloc_size,
> > >> type);
> > >> +                            if (status > 0)
> > >> +                                    *buf_size = status;
> > >> +                            mutex_unlock(buf_mutex);
> > >> +
> > >> +                    } else
> > >> +                            pr_warn("The retrieved object type(%d) is
> > >> not supported yet\n",
> > >> +                                    obj->type);
> > >> +
> > >> +                    ret = hp_bios_settings_realloc_buffer(buf, buf_size,
> > >> alloc_size, buf_mutex);
> > >> +            }
> > >> +
> > >> +            kfree(obj);
> > >> +            obj = NULL;
> > >> +
> > >> +    } while (ACPI_SUCCESS(ret));
> > >> +
> > >> +    /*
> > >> +     * AE_BAD_PARAMETER means the loop ended by exhaustion
> > >> +     */
> > >> +    if (ret == AE_BAD_PARAMETER)
> > >> +            ret = 0;
> > >> +
> > >> +    return ret;
> > >> +}
> > >> +
> > >> +static int hp_bios_settings_fill_buffer(void)
> > >> +{
> > >> +    int status = 0;
> > >> +    int initial_buffer_size = 20 * PAGE_SIZE;
> > >> +
> > >> +    mutex_lock(&buf_mutex);
> > >> +    hp_bios_settings_buffer = kmalloc(initial_buffer_size,
> GFP_KERNEL);
> > >> +    mutex_unlock(&buf_mutex);
> > >> +    if (!hp_bios_settings_buffer)
> > >> +            return -ENOMEM;
> > >> +
> > >> +    mutex_lock(&buf_mutex);
> > >> +    buf_alloc_size = ksize(hp_bios_settings_buffer);
> > >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > >> +                                    buf_alloc_size, "[\n");
> > >> +    mutex_unlock(&buf_mutex);
> > >> +
> > >> +    status = append_settings_to_buffer(HPWMI_STRING_GUID,
> > >> +            HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
> > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >> +    if (ACPI_FAILURE(status))
> > >> +            pr_err("error 0x%x occurred retrieving string instances\n",
> > >> status);
> > >> +
> > >> +    status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
> > >> +            HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
> > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >> +    if (ACPI_FAILURE(status))
> > >> +            pr_err("error 0x%x occurred retrieving integer instances\n",
> > >> status);
> > >> +
> > >> +    status =
> append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
> > >> +            HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
> > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >> +    if (ACPI_FAILURE(status))
> > >> +            pr_err("error 0x%x occurred retrieving enumeration
> > >> instances\n", status);
> > >> +
> > >> +    status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
> > >> +            HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
> > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >> +    if (ACPI_FAILURE(status))
> > >> +            pr_err("error 0x%x occurred retrieving ordered list
> > >> instances\n", status);
> > >> +
> > >> +    status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
> > >> +            HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
> > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >> +    if (ACPI_FAILURE(status))
> > >> +            pr_err("error 0x%x occurred retrieving password list
> > >> instances\n", status);
> > >> +
> > >> +    mutex_lock(&buf_mutex);
> > >> +    /*
> > >> +     * remove trailing comma
> > >> +     */
> > >> +    if (settings_buffer_size >= 3) {
> > >> +            if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
> > >> +                    hp_bios_settings_buffer[settings_buffer_size - 2] = '
> > >> ';
> > >> +    }
> > >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > >> +                                    buf_alloc_size, "%s]\n",
> > >> +                                    hp_bios_settings_buffer);
> > >> +    mutex_unlock(&buf_mutex);
> > >> +
> > >> +    return settings_buffer_size;
> > >> +}
> > >> +
> > >> +/*
> > >> + * sure_admin_settings_read - Return a formatted file with settings
> > >> + *                              and possible options read from BIOS
> > >> + *
> > >> + * @filp:  Pointer to file of settings read from BIOS
> > >> + * @kobj:  Pointer to a kernel object of things that show up as directory
> in
> > >> the sysfs filesystem.
> > >> + * @attr:  Pointer to list of read attributes
> > >> + * @buf:   Pointer to buffer
> > >> + * @off:   File current offset
> > >> + * @count: Buffer size
> > >> + *
> > >> + * Returns the count of unicode chars read if successful, otherwise
> > >> + *          -ENOMEM unable to allocate memory
> > >> + *          -EINVAL buffer not allocated or too small
> > >> + *
> > >> + */
> > >> +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 >= settings_buffer_size && settings_buffer_size > 0) {
> > >> +            hp_bios_settings_free_buffer();
> > >> +            return 0;
> > >> +    }
> > >> +
> > >> +    /* clear the buffer whenever the read starts from the first position
> > >> */
> > >> +    if (off == 0 && settings_buffer_size > 0)
> > >> +            hp_bios_settings_free_buffer();
> > >> +
> > >> +    if (settings_buffer_size == 0)
> > >> +            hp_bios_settings_fill_buffer();
> > >> +
> > >> +    mutex_lock(&buf_mutex);
> > >> +    ret = memory_read_from_buffer(buf, count, &off,
> > >> hp_bios_settings_buffer,
> > >> +                                  settings_buffer_size);
> > >> +    mutex_unlock(&buf_mutex);
> > >> +
> > >> +    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
> > >> + */
> > >> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
> > >> +{
> > >> +    int len = strlen(str);
> > >> +
> > >> +    /*
> > >> +     * Add null character when reading an empty string
> > >> +     */
> > >> +    if (len == 0) {
> > >> +            *p++ = 2;
> > >> +            *p++ = (u8)0x00;
> > >> +            return p;
> > >> +    }
> > >> +    *p++ = len * 2;
> > >> +    utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
> > >> +    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
> > >> + */
> > >> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 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(HPWMI_SETBIOSSETTING_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;
> > >> +}
> > >> +
> > >> +/* Sure Admin Functions */
> > >> +
> > >> +#define UTF_PREFIX                  ((unsigned char *)"<utf-16/>")
> > >> +#define BEAM_PREFIX                 ((unsigned char
> > >> *)"<BEAM/>")
> > >> +
> > >> +/*
> > >> + * sure_admin_settings_write - Write the contents of a formatted file
> > >> + *                               with settings and performs the logic
> > >> + *                               to change any settings in BIOS.
> > >> + *
> > >> + * @filp:  Pointer to file of settings to be written to BIOS
> > >> + * @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 write operation
> > >> + * @buf:   Pointer to buffer
> > >> + * @off:   File current offset
> > >> + * @count: Buffer size
> > >> + *
> > >> + *
> > >> + * Returns the count of unicode characters written to BIOS if
> successful,
> > >> otherwise
> > >> + *          -ENOMEM unable to allocate memory
> > >> + *          -EINVAL buffer not allocated or too small
> > >> + *
> > >> + */
> > >> +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;
> > >> +    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 out_free;
> > >> +    }
> > >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > >> +    part = strsep(&buf, ",");
> > >> +    if (!part) {
> > >> +            status = -EINVAL;
> > >> +            goto out_free;
> > >> +    }
> > >> +
> > >> +    /* Add extra buffer space when encountering an empty string */
> > >> +    if (!strlen(part))
> > >> +            buffer_size += sizeof(unsigned short);
> > >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > >> +    part = strsep(&buf, ",");
> > >> +    if (!part) {
> > >> +            status = -EINVAL;
> > >> +            goto out_free;
> > >> +    }
> > >> +    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 out_free;
> > >> +
> > >> +            tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > >> +            kfree(part);
> > >> +    }
> > >> +
> > >> +    part = strsep(&buf, ",");
> > >> +    if (part) {
> > >> +            status = -EINVAL;
> > >> +            goto out_free;
> > >> +    }
> > >> +    status = hp_wmi_set_bios_setting(buffer, buffer_size);
> > >> +    if (ACPI_FAILURE(status))
> > >> +            status = -EINVAL;
> > >> +
> > >> +out_free:
> > >> +    kfree(buffer);
> > >> +    if (ACPI_SUCCESS(status))
> > >> +            return count;
> > >> +    return status;
> > >> +}
> > >> +
> > >> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
> > >> +
> > >> +static struct bin_attribute *sure_admin_binattrs[] = {
> > >> +    &sure_admin_settings,
> > >> +    NULL,
> > >> +};
> > >> +
> > >> +static const struct attribute_group sure_admin_group = {
> > >> +    .name = "sure_admin",
> > >> +    .bin_attrs = sure_admin_binattrs,
> > >> +};
> > >> +
> > >>  static DEVICE_ATTR_RO(display);
> > >>  static DEVICE_ATTR_RO(hddtemp);
> > >>  static DEVICE_ATTR_RW(als);
> > >> @@ -1050,6 +2026,7 @@ static const struct attribute_group
> > >> *hp_wmi_groups[] = {
> > >>      &hp_wmi_group,
> > >>      &spm_group,
> > >>      &sure_start_group,
> > >> +    &sure_admin_group,
> > >>      NULL,
> > >>  };
> > >>
> > >> --
> > >> 2.25.1
> >

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 4/6] Sure Start Security Feature
  2022-04-05 17:09       ` Limonciello, Mario
@ 2022-04-05 18:52         ` Jorge Lopez
  2022-04-05 18:54           ` Limonciello, Mario
  0 siblings, 1 reply; 25+ messages in thread
From: Jorge Lopez @ 2022-04-05 18:52 UTC (permalink / raw)
  To: Limonciello, Mario; +Cc: platform-driver-x86

On Tue, Apr 5, 2022 at 12:09 PM Limonciello, Mario
<Mario.Limonciello@amd.com> wrote:
>
> [Public]
>
>
>
> > -----Original Message-----
> > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > Sent: Tuesday, April 5, 2022 11:56
> > To: Limonciello, Mario <Mario.Limonciello@amd.com>
> > Cc: platform-driver-x86@vger.kernel.org
> > Subject: Re: [PATCH v1 4/6] Sure Start Security Feature
> >
> > hi Mario,
> >
> > On Mon, Apr 4, 2022 at 5:05 PM Limonciello, Mario
> > <Mario.Limonciello@amd.com> wrote:
> > >
> > > [Public]
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > > Sent: Monday, April 4, 2022 15:36
> > > > To: platform-driver-x86@vger.kernel.org
> > > > Subject: [PATCH v1 4/6] Sure Start Security Feature
> > > >
> > > > Sure Start provides advanced firmware protection and resiliency by
> > > > identifying and repairing unauthorized BIOS changes.  It maintains an
> > > > audit log of these events and other important system configuration
> > > > changes.  The following sysfs entries can be used to read the contents
> > > > of the audit log.
> > > >
> > > >       /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count
> > > >       /sys/devices/platform/hp-wmi/sure_start/audit_log_entries
> > > >
> > > > 'audit_log_entry_count' is a read-only file that returns the number of
> > > > existing audit log events available to be read
> > > >
> > > > 'audit_log_entries' is a read-only file that returns the events in the
> > > > log
> > > >
> > > > This feature requires "Update hp_wmi_group to simplify feature
> > > > addition" patch.
> > > >
> > > > All changes were validated on a HP ZBook Workstation,
> > > > HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> > > >
> > > > Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> > > >
> > > > ---
> > > > Based on the latest platform-drivers-x86.git/for-next
> > > > ---
> > > >  drivers/platform/x86/hp-wmi.c | 108
> > > > ++++++++++++++++++++++++++++++++++
> > > >  1 file changed, 108 insertions(+)
> > > >
> > > > diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-
> > wmi.c
> > > > index 139dc079c1fa..918e3eaf1b67 100644
> > > > --- a/drivers/platform/x86/hp-wmi.c
> > > > +++ b/drivers/platform/x86/hp-wmi.c
> > > > @@ -126,6 +126,11 @@ enum hp_wmi_spm_commandtype {
> > > >       HPWMI_SECUREPLATFORM_SET_SK     = 0x12,
> > > >  };
> > > >
> > > > +enum hp_wmi_surestart_commandtype {
> > > > +     HPWMI_SURESTART_GET_LOG_COUNT   = 0x01,
> > > > +     HPWMI_SURESTART_GET_LOG = 0x02,
> > > > +};
> > > > +
> > > >  enum hp_wmi_gm_commandtype {
> > > >       HPWMI_FAN_SPEED_GET_QUERY = 0x11,
> > > >       HPWMI_SET_PERFORMANCE_MODE = 0x1A,
> > > > @@ -138,6 +143,7 @@ enum hp_wmi_command {
> > > >       HPWMI_READ      = 0x01,
> > > >       HPWMI_WRITE     = 0x02,
> > > >       HPWMI_ODM       = 0x03,
> > > > +     HPWMI_SURESTART = 0x20006,
> > > >       HPWMI_GM        = 0x20008,
> > > >       HPWMI_SECUREPLATFORM = 0x20010,
> > > >  };
> > > > @@ -851,6 +857,7 @@ static ssize_t spm_kek_store(struct kobject *kobj,
> > > >  {
> > > >       int ret =
> > > > hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
> > > >                                      HPWMI_SECUREPLATFORM, (void *)buf,
> > > > count, 0);
> > > > +
> > > >       return ret ? -EINVAL : count;
> > > >  }
> > > >
> > > > @@ -918,6 +925,106 @@ static const struct attribute_group spm_group =
> > {
> > > >       .attrs = spm_attrs,
> > > >  };
> > > >
> > > > +/* Sure Start functions */
> > > > +
> > > > +#define LOG_MAX_ENTRIES      254
> > > > +#define LOG_ENTRY_SIZE       16
> > > > +
> > > > +/*
> > > > + * sure_start_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 sure_start_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);
> > > > +}
> > > > +
> > > > +/*
> > > > + * sure_start_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 sure_start_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;
> > >
> > > This is an interface that will be there forever, what are realistic numbers
> > and sizes after a long time?
> > > I have an AMD HP laptop that is only been used a few months and checked
> > the size like this:
> > > dd if=audit_log_entries of=/tmp/entries
> > >
> > The audit log will grow linearly and it is defined by BIOS.  The total
> > number of bytes ( audit log size times the max number of audit logs
> > supported by BIOS) is 4K.
> > The audit log size reports three values. Number of event logs, audit
> > log max size (16), and max of audit logs supported by BIOS (254).
> > (16*254 = 4K).
> > In your case, the total number of bytes for all audit logs available
> > is 224 bytes.  You can conclude, your system has 14 audit logs
> > available to be read  (224/16 = 14)
>
>  But so if this is growing linearly what happens if BIOS ends up with
>  more than 4k audit logs?  Can that happen?

BIOS limits the max total audit log size to 4k.  BIOS will discard the
oldest and maintain the max 4k size.

>
> If that happens  I can no longer access them from userspace right?

If it happens, the driver will return an error and  no audit logs will
be accessible from userspace..

>
> >
> > > If so, then maybe this should be designed as a different interface.
> > >
> > > Also, the log is readable by anybody.  Should this be root only?
> >
> > No.  audit logs will be available to everyone.  The interpretation of
> > each audit event is done at the application level.
>
> Got it - thanks
>
> >
> > >
> > > > +
> > > > +     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);
> > > > +}
> > > > +
> > > > +HPWMI_ATTR_RO(sure_start, audit_log_entry_count);
> > > > +HPWMI_ATTR_RO(sure_start, audit_log_entries);
> > > > +
> > > > +static struct attribute *sure_start_attrs[] = {
> > > > +     &sure_start_audit_log_entry_count.attr,
> > > > +     &sure_start_audit_log_entries.attr,
> > > > +     NULL,
> > > > +};
> > > > +
> > > > +static const struct attribute_group sure_start_group = {
> > > > +     .name = "sure_start",
> > > > +     .attrs = sure_start_attrs,
> > > > +};
> > > > +
> > > >  static DEVICE_ATTR_RO(display);
> > > >  static DEVICE_ATTR_RO(hddtemp);
> > > >  static DEVICE_ATTR_RW(als);
> > > > @@ -942,6 +1049,7 @@ static const struct attribute_group
> > hp_wmi_group =
> > > > {
> > > >  static const struct attribute_group *hp_wmi_groups[] = {
> > > >       &hp_wmi_group,
> > > >       &spm_group,
> > > > +     &sure_start_group,
> > > >       NULL,
> > > >  };
> > > >
> > > > --
> > > > 2.25.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v1 4/6] Sure Start Security Feature
  2022-04-05 18:52         ` Jorge Lopez
@ 2022-04-05 18:54           ` Limonciello, Mario
  0 siblings, 0 replies; 25+ messages in thread
From: Limonciello, Mario @ 2022-04-05 18:54 UTC (permalink / raw)
  To: Jorge Lopez; +Cc: platform-driver-x86

[Public]



> -----Original Message-----
> From: Jorge Lopez <jorgealtxwork@gmail.com>
> Sent: Tuesday, April 5, 2022 13:52
> To: Limonciello, Mario <Mario.Limonciello@amd.com>
> Cc: platform-driver-x86@vger.kernel.org
> Subject: Re: [PATCH v1 4/6] Sure Start Security Feature
> 
> On Tue, Apr 5, 2022 at 12:09 PM Limonciello, Mario
> <Mario.Limonciello@amd.com> wrote:
> >
> > [Public]
> >
> >
> >
> > > -----Original Message-----
> > > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > Sent: Tuesday, April 5, 2022 11:56
> > > To: Limonciello, Mario <Mario.Limonciello@amd.com>
> > > Cc: platform-driver-x86@vger.kernel.org
> > > Subject: Re: [PATCH v1 4/6] Sure Start Security Feature
> > >
> > > hi Mario,
> > >
> > > On Mon, Apr 4, 2022 at 5:05 PM Limonciello, Mario
> > > <Mario.Limonciello@amd.com> wrote:
> > > >
> > > > [Public]
> > > >
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > > > Sent: Monday, April 4, 2022 15:36
> > > > > To: platform-driver-x86@vger.kernel.org
> > > > > Subject: [PATCH v1 4/6] Sure Start Security Feature
> > > > >
> > > > > Sure Start provides advanced firmware protection and resiliency by
> > > > > identifying and repairing unauthorized BIOS changes.  It maintains an
> > > > > audit log of these events and other important system configuration
> > > > > changes.  The following sysfs entries can be used to read the contents
> > > > > of the audit log.
> > > > >
> > > > >       /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count
> > > > >       /sys/devices/platform/hp-wmi/sure_start/audit_log_entries
> > > > >
> > > > > 'audit_log_entry_count' is a read-only file that returns the number of
> > > > > existing audit log events available to be read
> > > > >
> > > > > 'audit_log_entries' is a read-only file that returns the events in the
> > > > > log
> > > > >
> > > > > This feature requires "Update hp_wmi_group to simplify feature
> > > > > addition" patch.
> > > > >
> > > > > All changes were validated on a HP ZBook Workstation,
> > > > > HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> > > > >
> > > > > Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> > > > >
> > > > > ---
> > > > > Based on the latest platform-drivers-x86.git/for-next
> > > > > ---
> > > > >  drivers/platform/x86/hp-wmi.c | 108
> > > > > ++++++++++++++++++++++++++++++++++
> > > > >  1 file changed, 108 insertions(+)
> > > > >
> > > > > diff --git a/drivers/platform/x86/hp-wmi.c
> b/drivers/platform/x86/hp-
> > > wmi.c
> > > > > index 139dc079c1fa..918e3eaf1b67 100644
> > > > > --- a/drivers/platform/x86/hp-wmi.c
> > > > > +++ b/drivers/platform/x86/hp-wmi.c
> > > > > @@ -126,6 +126,11 @@ enum hp_wmi_spm_commandtype {
> > > > >       HPWMI_SECUREPLATFORM_SET_SK     = 0x12,
> > > > >  };
> > > > >
> > > > > +enum hp_wmi_surestart_commandtype {
> > > > > +     HPWMI_SURESTART_GET_LOG_COUNT   = 0x01,
> > > > > +     HPWMI_SURESTART_GET_LOG = 0x02,
> > > > > +};
> > > > > +
> > > > >  enum hp_wmi_gm_commandtype {
> > > > >       HPWMI_FAN_SPEED_GET_QUERY = 0x11,
> > > > >       HPWMI_SET_PERFORMANCE_MODE = 0x1A,
> > > > > @@ -138,6 +143,7 @@ enum hp_wmi_command {
> > > > >       HPWMI_READ      = 0x01,
> > > > >       HPWMI_WRITE     = 0x02,
> > > > >       HPWMI_ODM       = 0x03,
> > > > > +     HPWMI_SURESTART = 0x20006,
> > > > >       HPWMI_GM        = 0x20008,
> > > > >       HPWMI_SECUREPLATFORM = 0x20010,
> > > > >  };
> > > > > @@ -851,6 +857,7 @@ static ssize_t spm_kek_store(struct kobject
> *kobj,
> > > > >  {
> > > > >       int ret =
> > > > > hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
> > > > >                                      HPWMI_SECUREPLATFORM, (void *)buf,
> > > > > count, 0);
> > > > > +
> > > > >       return ret ? -EINVAL : count;
> > > > >  }
> > > > >
> > > > > @@ -918,6 +925,106 @@ static const struct attribute_group
> spm_group =
> > > {
> > > > >       .attrs = spm_attrs,
> > > > >  };
> > > > >
> > > > > +/* Sure Start functions */
> > > > > +
> > > > > +#define LOG_MAX_ENTRIES      254
> > > > > +#define LOG_ENTRY_SIZE       16
> > > > > +
> > > > > +/*
> > > > > + * sure_start_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 sure_start_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);
> > > > > +}
> > > > > +
> > > > > +/*
> > > > > + * sure_start_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 sure_start_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;
> > > >
> > > > This is an interface that will be there forever, what are realistic numbers
> > > and sizes after a long time?
> > > > I have an AMD HP laptop that is only been used a few months and
> checked
> > > the size like this:
> > > > dd if=audit_log_entries of=/tmp/entries
> > > >
> > > The audit log will grow linearly and it is defined by BIOS.  The total
> > > number of bytes ( audit log size times the max number of audit logs
> > > supported by BIOS) is 4K.
> > > The audit log size reports three values. Number of event logs, audit
> > > log max size (16), and max of audit logs supported by BIOS (254).
> > > (16*254 = 4K).
> > > In your case, the total number of bytes for all audit logs available
> > > is 224 bytes.  You can conclude, your system has 14 audit logs
> > > available to be read  (224/16 = 14)
> >
> >  But so if this is growing linearly what happens if BIOS ends up with
> >  more than 4k audit logs?  Can that happen?
> 
> BIOS limits the max total audit log size to 4k.  BIOS will discard the
> oldest and maintain the max 4k size.

That's great BIOS has a guarantee.  I think leaving a comment in a future
version of this patch will be helpful.

> 
> >
> > If that happens  I can no longer access them from userspace right?
> 
> If it happens, the driver will return an error and  no audit logs will
> be accessible from userspace..

It sounds unlikely if BIOS is enforcing 4k size and rolling the logs.  In this
circumstance maybe a pr_warn/pr_err on the overflow error return makes
sense so users know it's the BIOS is at fault though.

> 
> >
> > >
> > > > If so, then maybe this should be designed as a different interface.
> > > >
> > > > Also, the log is readable by anybody.  Should this be root only?
> > >
> > > No.  audit logs will be available to everyone.  The interpretation of
> > > each audit event is done at the application level.
> >
> > Got it - thanks
> >
> > >
> > > >
> > > > > +
> > > > > +     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);
> > > > > +}
> > > > > +
> > > > > +HPWMI_ATTR_RO(sure_start, audit_log_entry_count);
> > > > > +HPWMI_ATTR_RO(sure_start, audit_log_entries);
> > > > > +
> > > > > +static struct attribute *sure_start_attrs[] = {
> > > > > +     &sure_start_audit_log_entry_count.attr,
> > > > > +     &sure_start_audit_log_entries.attr,
> > > > > +     NULL,
> > > > > +};
> > > > > +
> > > > > +static const struct attribute_group sure_start_group = {
> > > > > +     .name = "sure_start",
> > > > > +     .attrs = sure_start_attrs,
> > > > > +};
> > > > > +
> > > > >  static DEVICE_ATTR_RO(display);
> > > > >  static DEVICE_ATTR_RO(hddtemp);
> > > > >  static DEVICE_ATTR_RW(als);
> > > > > @@ -942,6 +1049,7 @@ static const struct attribute_group
> > > hp_wmi_group =
> > > > > {
> > > > >  static const struct attribute_group *hp_wmi_groups[] = {
> > > > >       &hp_wmi_group,
> > > > >       &spm_group,
> > > > > +     &sure_start_group,
> > > > >       NULL,
> > > > >  };
> > > > >
> > > > > --
> > > > > 2.25.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-05 17:13         ` Limonciello, Mario
@ 2022-04-07 13:44           ` Jorge Lopez
  2022-04-07 19:17             ` Limonciello, Mario
  2022-04-08  9:21             ` Hans de Goede
  0 siblings, 2 replies; 25+ messages in thread
From: Jorge Lopez @ 2022-04-07 13:44 UTC (permalink / raw)
  To: Limonciello, Mario; +Cc: Hans de Goede, platform-driver-x86

Hans, Mario,

The code links make references to code that implements the new
interfaces but there’s
still code in the kernel that uses the old ones.  I do agree we should
be forward looking
and want to be good participants in the kernel development, but can’t
let our immediate
business needs be impacted with opportunities to enhance the driver to
take advantage
of the latest kernel features.

Rewriting those security features will impact customer business
datelines requiring
HP to provide private releases as the kernel version changes.   The
requested changes
will impact products in the market and HP ability to help customers to
migrate to Linux
from Windows products.

It is because of the immediate business needs, avoiding impacting our
customers/products,
and rewriting  enhancements to the driver that I need to propose an
interim solution.

My proposal is to introduce a read/write value accessible in the user
space to control how
the driver reports and handles BIOS settings and values.  The new
configuration features
will be gradually disabled  as they are converted to use the standardized API.
It is like the configuration flag used to overcome the tablet detection problem
introduced in the past.   The changes solely affect the HP WMI driver.
This option will help us
move forward for this release and give us time to make the necessary
changes to both
the driver and support applications.

Please let me know if this is a viable interim solution.

If it is not possible, I need to ask where the actual written
requirement is found so I can
include them in the business justification for changes and release
delays to management.


Regards,

Jorge Lopez


On Tue, Apr 5, 2022 at 12:13 PM Limonciello, Mario
<Mario.Limonciello@amd.com> wrote:
>
> [Public]
>
>
>
> > -----Original Message-----
> > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > Sent: Tuesday, April 5, 2022 11:52
> > To: Hans de Goede <hdegoede@redhat.com>
> > Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-driver-
> > x86@vger.kernel.org
> > Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> >
> > Hi Hans,
> >
> > On Tue, Apr 5, 2022 at 6:54 AM Hans de Goede <hdegoede@redhat.com>
> > wrote:
> > >
> > > Hi,
> > >
> > > On 4/4/22 23:59, Limonciello, Mario wrote:
> > > > [Public]
> > > >
> > > >
> > > >
> > > >> -----Original Message-----
> > > >> From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > >> Sent: Monday, April 4, 2022 15:36
> > > >> To: platform-driver-x86@vger.kernel.org
> > > >> Subject: [PATCH v1 5/6] Sure Admin Security Feature
> > > >>
> > > >> 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. Behind the scenes, Sure Admin uses Secure
> > Platform
> > > >> Management (SPM) and WMI
> > > >>
> > > >> 'settings' is a file associated with Sure Admin. BIOS settings can be
> > > >> read or written through the Sure Admin settings file in sysfs
> > > >>
> > > >>      /sys/devices/platform/hp-wmi/sure_admin/settings
> > > >>
> > > >> 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"
> > > >>              ]
> > > >>      }
> > > >>
> > > >
> > > > This sounds like it has re-invented /sys/class/firmware-attributes.
> > > >
> > > > Shouldn't you adopt that API?
> > >
> > > I fully agree. Jorge as I already indicated in our off-list
> > > conversation when you initially started working on this
> > > feature, we already have a standardized API for querying/changing
> > > BIOS settings from within Linux:
> > >
> >
> > I agree that changing the BIOS settings from within Linux could
> > utilize the new methodology,  I will need to look closely at the
> > requirements before I can proceed to make the changes.
> > Keep in mind authentication of the values is done by BIOS.  No Linux
> > process validates any data name, value, or auth token; only BIOS.  All
> > data written to the sysfs file is not validated, it is just forward to
> > BIOS.  See spm_kek_store and spm_sk_store functions.
>
> That's fine, and it's a safer design to have BIOS validate it.
>
> > One point I must make clear when updating BIOS settings.  any  NOT
> > read-only BIOS settings can be changed by the application at any time.
> >    This list of settings changes from one system to another.
>
> Right.
>
> >
> > I am in disagreement with reading the settings.  hp-wmi does not read
> > one value at a time. It reads all values exposed by BIOS.  See
> > attached sample output.
>
> The settings can all be read at initialization time for the driver and cached
> then.
>
> > The method for how all BIOS settings are reported needs to match the
> > method how Windows products do it.  It is a requirement to start
> > migrating customers from Windows to Linux while minimizing how BIOS
> > data is reported.
>
> Because we have a standardized API in Linux for this, I think it's best to abstract
> this behind a userspace application/script.  If they expect to see it in the format you
> showed, the userspace application can take the data from Linux and package it that
> way.
>
> You'll have richer libraries and languages and tools to work from when doing this too.
> It should make it a lot less painful.
>
> >
> > I will investigate the new API and bring it to the team's attention.
> >
> > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> > attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> > f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> > 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> > C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> > &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> > D&amp;reserved=0
> > >
> > > and any new code (such as this patch) which implements BIOS
> > > setting changing MUST follow this standardized API (extending
> > > it where necessary).
> > >
> > > I'm sorry but this patch is not acceptable in its current form,
> > > it needs to be *completely rewritten* to implement:
> > >
> > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> > attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> > f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> > 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> > C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> > &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> > D&amp;reserved=0
> > >
> > > See:
> > >
> > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fdell%2Fdell-wmi-
> > sysman&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8f
> > ea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> > 7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> > wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> > mp;sdata=z5jmH7ECYBeLcndQ2vfHaUuyE04Eaf1Lymh6BjnyJ%2Fk%3D&amp;r
> > eserved=0
> > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fthink-
> > lmi.c&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea
> > 104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > 0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > sdata=5n6w9LEB2iWpj1cOQP6Ngz94AqP1Bu4vu8T0EdN%2FThU%3D&amp;re
> > served=0
> > >
> > > for example code / for 2 drivers from other vendors already
> > > implementing this.
> > >
> > > The same applies to the:
> > >
> > > "[PATCH v1 3/6] Secure Platform Management Security Feature"
> > >
> > > this needs to be implemented as
> > > a /sys/class/firmware-attributes/*/authentication/
> > > authentication method, see for example these Lenovo specific
> > > addition to the /sys/class/firmware-attributes/*/authentication/
> > > userspace API for similar functionality on Lenovo Think* devices:
> > >
> > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > 2Fcommit%2F%3Fid%3D06384573a3e8335ac6797577e545c33dbf91b490&amp;
> > data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea1040342827
> > 08da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C63784
> > 7743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLC
> > JQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=eldS
> > 4H3Z%2BAyL%2FG%2FO9W9rDGC37yh5sGgtUhpKdUAoSmA%3D&amp;reser
> > ved=0
> > >
> > > I'll merge patches 1-2 sometime this week since those are
> > > fine and it will be good to have those "out of the way",
> > > but the rest of the series will need to be rewritten
> > > taken the above comments into account.
> >
> > v1-0003-Sure-Start-Security-Feature.patch  reports the number of audit
> > logs available and reports them when read.    it does not read/write
> > BIOS settings hence it does not fall within the same category as
> > patches v1-0002-Secure-Platform-Management-Security-Feature.patch and
> > v1-0004-Sure-Admin-Security-Feature.patch
> > Do you agree?
> >
> > >
> > > Regards,
> > >
> > > Hans
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > > >
> > > >> This feature requires "Update hp_wmi_group to simplify feature
> > > >> addition" patch.
> > > >>
> > > >> All changes were validated on a HP ZBook Workstation,
> > > >> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> > > >>
> > > >> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> > > >>
> > > >> ---
> > > >> Based on the latest platform-drivers-x86.git/for-next
> > > >> ---
> > > >>  drivers/platform/x86/hp-wmi.c | 977
> > > >> ++++++++++++++++++++++++++++++++++
> > > >>  1 file changed, 977 insertions(+)
> > > >>
> > > >> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-
> > wmi.c
> > > >> index 918e3eaf1b67..b72ca18b77a6 100644
> > > >> --- a/drivers/platform/x86/hp-wmi.c
> > > >> +++ b/drivers/platform/x86/hp-wmi.c
> > > >> @@ -27,6 +27,7 @@
> > > >>  #include <linux/rfkill.h>
> > > >>  #include <linux/string.h>
> > > >>  #include <linux/dmi.h>
> > > >> +#include <linux/nls.h>
> > > >>
> > > >>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
> > > >>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
> > > >> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-
> > > >> 3D44E2C707E4");
> > > >>
> > > >>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-
> > ACCDC67EF61C"
> > > >>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-
> > 3D44E2C707E4"
> > > >> +
> > > >>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
> > > >>
> > > >> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-
> > 6A1B8106F83C"
> > > >> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
> > > >> E293ADB9BF05"
> > > >> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-
> > > >> 4A3C09E75133"
> > > >> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
> > > >> 7045CB4DA745"
> > > >> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
> > > >> 015176049E2D"
> > > >> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-
> > > >> C7CB9B4B8D5E"
> > > >> +
> > > >>  /* DMI board names of devices that should use the omen specific path
> > for
> > > >>   * thermal profiles.
> > > >>   * This was obtained by taking a look in the windows omen command
> > center
> > > >> @@ -1025,6 +1034,973 @@ static const struct attribute_group
> > > >> sure_start_group = {
> > > >>      .attrs = sure_start_attrs,
> > > >>  };
> > > >>
> > > >> +
> > > >> +static 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;
> > > >> +    int  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));
> > > >> +            ret = kstrtoint(tmp, 16, &ch);
> > > >> +            if (ret) {
> > > >> +                    new_len = 0;
> > > >> +                    break;
> > > >> +            }
> > > >> +
> > > >> +            if (ch == '\\')
> > > >> +                    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;
> > > >> +    }
> > > >> +
> > > >> +    if (ret)
> > > >> +            kfree(new_str);
> > > >> +    return ret;
> > > >> +}
> > > >> +
> > > >> +/*
> > > >> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and
> > instance
> > > >> + *
> > > >> + * @guid:   GUID associated with the ACPI list of managed objects
> > > >> + * @instance:       Instance index to query on the ACPI list
> > > >> + * @obj:    The output ACPI object of type ACPI_TYPE_PACKAGE
> > > >> + *          or ACPI_TYPE_BUFFER (freed by the callee)
> > > >> + *
> > > >> + * Returns  zero on success.  Otherwise,an error inherited from
> > > >> + *          wmi_query_block(). It returns a obj by parameter if
> > > >> + *          the query returned object of type buffer or package,
> > > >> + *          otherwise, a null obj is returned.
> > > >> + *
> > > >> + * Note: obj should be freed by the callee once it is finished working
> > with it
> > > >> + */
> > > >> +static int hp_wmi_get_setting_object(char *guid, int instance,
> > > >> +                            union acpi_object **obj)
> > > >> +{
> > > >> +    struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL
> > > >> };
> > > >> +    union acpi_object *tmp = NULL;
> > > >> +    int ret;
> > > >> +
> > > >> +    ret = wmi_query_block(guid, instance, &output);
> > > >> +    if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
> > > >> +            tmp = output.pointer;
> > > >> +            if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
> > > >> ACPI_TYPE_PACKAGE)
> > > >> +                    *obj = output.pointer;
> > > >> +            else {
> > > >> +                    kfree(tmp);
> > > >> +                    *obj = NULL;
> > > >> +            }
> > > >> +    }
> > > >> +
> > > >> +    return ret;
> > > >> +}
> > > >> +
> > > >> +
> > > >> +static 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;
> > > >> +
> > > >> +    if (size == 0)
> > > >> +            goto cleanup_exit;
> > > >> +
> > > >> +    for (i = 0; i < size; i++)
> > > >> +            if (ptr[i] == '\\')
> > > >> +                    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);
> > > >> +
> > > >> +    if (escape == 0) {
> > > >> +            ptr += (ptrlen / 2);
> > > >> +            goto cleanup_exit;
> > > >> +    }
> > > >> +    /*
> > > >> +     * Convert escape characters only when found
> > > >> +     */
> > > >> +    for (i = 0; i < size; i++) {
> > > >> +            if (*ptr == '\\')
> > > >> +                    output[i++] = '\\';
> > > >> +            output[i] = *ptr;
> > > >> +            ptr++;
> > > >> +    }
> > > >> +
> > > >> +cleanup_exit:
> > > >> +    *buffer = ptr;
> > > >> +    return 0;
> > > >> +}
> > > >> +
> > > >> +static int get_integer_from_buffer(int **buffer, int *integer)
> > > >> +{
> > > >> +    int *ptr = PTR_ALIGN(*buffer, 4);
> > > >> +    *integer = *(ptr++);
> > > >> +    *buffer = ptr;
> > > >> +    return 0;
> > > >> +}
> > > >> +
> > > >> +
> > > >> +// Sure Admin functions
> > > >> +enum hp_wmi_data_type {
> > > >> +    HPWMI_STRING_TYPE,
> > > >> +    HPWMI_INTEGER_TYPE,
> > > >> +    HPWMI_ENUMERATION_TYPE,
> > > >> +    HPWMI_ORDEREDLIST_TYPE,
> > > >> +    HPWMI_PASSWORD_TYPE,
> > > >> +};
> > > >> +
> > > >> +#define HP_WMI_COMMON_ELEMENTS      \
> > > >> +    "Name", \
> > > >> +    "Value",        \
> > > >> +    "Path", \
> > > >> +    "IsReadOnly",   \
> > > >> +    "DisplayInUI",  \
> > > >> +    "RequiresPhysicalPresence",     \
> > > >> +    "Sequence",     \
> > > >> +    "PrerequisiteSize",     \
> > > >> +    "SecurityLevel"
> > > >> +
> > > >> +const char *hp_wmi_string_elements[] = {
> > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > >> +    "MinLength",
> > > >> +    "MaxLength"
> > > >> +};
> > > >> +
> > > >> +const char *hp_wmi_integer_elements[] = {
> > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > >> +    "LowerBound",
> > > >> +    "UpperBound",
> > > >> +    "IntValue"
> > > >> +};
> > > >> +
> > > >> +const char *hp_wmi_enumeration_elements[] = {
> > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > >> +    "CurrentValue",
> > > >> +    "Size"
> > > >> +};
> > > >> +
> > > >> +const char *hp_wmi_orderedlist_elements[] = {
> > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > >> +    "Size"
> > > >> +};
> > > >> +
> > > >> +const char *hp_wmi_password_elements[] = {
> > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > >> +    "MinLength",
> > > >> +    "MaxLength",
> > > >> +    "Size",
> > > >> +    "SupportedEncoding",
> > > >> +    "IsSet"
> > > >> +};
> > > >> +
> > > >> +const char **hp_wmi_elements[] = {
> > > >> +    hp_wmi_string_elements,
> > > >> +    hp_wmi_integer_elements,
> > > >> +    hp_wmi_enumeration_elements,
> > > >> +    hp_wmi_orderedlist_elements,
> > > >> +    hp_wmi_password_elements
> > > >> +};
> > > >> +
> > > >> +const int hp_wmi_elements_count[] = {
> > > >> +    ARRAY_SIZE(hp_wmi_string_elements),
> > > >> +    ARRAY_SIZE(hp_wmi_integer_elements),
> > > >> +    ARRAY_SIZE(hp_wmi_enumeration_elements),
> > > >> +    ARRAY_SIZE(hp_wmi_orderedlist_elements),
> > > >> +    ARRAY_SIZE(hp_wmi_password_elements)
> > > >> +};
> > > >> +
> > > >> +const char *hp_wmi_classes[] = {
> > > >> +    "HPBIOS_BIOSString",
> > > >> +    "HPBIOS_BIOSInteger",
> > > >> +    "HPBIOS_BIOSEnumeration",
> > > >> +    "HPBIOS_BIOSOrderedList",
> > > >> +    "HPBIOS_BIOSPassword"
> > > >> +};
> > > >> +
> > > >> +static DEFINE_MUTEX(buf_mutex);
> > > >> +static int settings_buffer_size;
> > > >> +static int buf_alloc_size;
> > > >> +static char *hp_bios_settings_buffer;
> > > >> +
> > > >> +
> > > >> +static int append_package_elements_to_buffer(union acpi_object
> > *obj,
> > > >> +                                         char *buf, int alloc_size, enum
> > > >> hp_wmi_data_type type)
> > > >> +{
> > > >> +    int i;
> > > >> +    union acpi_object *pobj = NULL;
> > > >> +    char *value = NULL;
> > > >> +    int value_len;
> > > >> +    char *tmpstr = NULL;
> > > >> +    char *part_tmp = NULL;
> > > >> +    int tmp_len = 0;
> > > >> +    char *part = NULL;
> > > >> +    int status = 0;
> > > >> +    int size = 0;
> > > >> +    int buf_size;
> > > >> +
> > > >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > > >> +            return -EINVAL;
> > > >> +
> > > >> +    if (obj->type != ACPI_TYPE_PACKAGE)
> > > >> +            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]);
> > > >> +
> > > >> +    for (i = 0; i < 3; i++) {
> > > >> +            pobj = &(obj->package.elements[i]);
> > > >> +            if (pobj->type == ACPI_TYPE_STRING) {
> > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > >>> string.pointer,
> > > >> +                                                   pobj->string.length,
> > > >> &value, &value_len);
> > > >> +                    if (ACPI_FAILURE(status))
> > > >> +                            continue;
> > > >> +                    /*
> > > >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > > >> since
> > > >> +                     * 'CurrentValue' is reported.
> > > >> +                     */
> > > >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > >> +                                                "%s\t\"%s\": \"%s\",\n",
> > > >> +                                                buf,
> > > >> +
> > > >> hp_wmi_elements[type][i], value);
> > > >> +
> > > >> +            }
> > > >> +            kfree(value);
> > > >> +            value = NULL;
> > > >> +    }
> > > >> +
> > > >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > > >> +            pobj = &(obj->package.elements[i]);
> > > >> +
> > > >> +            if (type == HPWMI_ENUMERATION_TYPE &&
> > > >> +                i == 9 &&
> > > >> +                pobj->type == ACPI_TYPE_STRING) {
> > > >> +                    /*
> > > >> +                     * Report "CurrentValue" as "Value"
> > > >> +                     */
> > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > >>> string.pointer,
> > > >> +                                                   pobj->string.length,
> > > >> +                                                   &value, &value_len);
> > > >> +                    if (ACPI_FAILURE(status))
> > > >> +                            continue;
> > > >> +
> > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > >> +                                        "%s\t\"Value\": \"%s\",\n",
> > > >> +                                        buf, value);
> > > >> +                    kfree(value);
> > > >> +                    value = NULL;
> > > >> +
> > > >> +            } else if (type == HPWMI_PASSWORD_TYPE &&
> > > >> +                       i == 12 &&
> > > >> +                       pobj->type == ACPI_TYPE_STRING) {
> > > >> +                    /*
> > > >> +                     * Report list of "SupportEncoding"
> > > >> +                     *
> > > >> +                     *      "SupportedEncoding": [
> > > >> +                     *              "utf-16"
> > > >> +                     *      ],
> > > >> +                     *
> > > >> +                     */
> > > >> +
> > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > > >> +                                        buf, hp_wmi_elements[type][i]);
> > > >> +                    while (size--) {
> > > >> +                            pobj = &(obj->package.elements[i]);
> > > >> +                            status = convert_hexstr_to_str(&pobj-
> > > >>> string.pointer,
> > > >> +                                                           pobj-
> > > >>> string.length,
> > > >> +                                                           &value,
> > > >> &value_len);
> > > >> +                            if (ACPI_FAILURE(status))
> > > >> +                                    continue;
> > > >> +
> > > >> +                            if (size) {
> > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > >> +                                                        "%s\t\t\"%s\",\n",
> > > >> buf, value);
> > > >> +                                    i++;
> > > >> +                            } else
> > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > >> +                                                        "%s\t\t\"%s\"\n",
> > > >> buf, value);
> > > >> +
> > > >> +                            kfree(value);
> > > >> +                            value = NULL;
> > > >> +
> > > >> +                    }
> > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > >> +                    continue;
> > > >> +
> > > >> +            } else if (pobj->type == ACPI_TYPE_INTEGER) {
> > > >> +                    /*
> > > >> +                     * Report "PrerequisiteSize" and "Size" values
> > > >> +                     *      ...
> > > >> +                     *      "PrerequisiteSize": 1,
> > > >> +                     *      ...
> > > >> +                     *      "Size": 2,
> > > >> +                     *      ...
> > > >> +                     */
> > > >> +                    if (i == 7)
> > > >> +                            size = pobj->integer.value;
> > > >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > > >> 9)
> > > >> +                            size = pobj->integer.value;
> > > >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > > >> == 10)
> > > >> +                            size = pobj->integer.value;
> > > >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > > >> 11)
> > > >> +                            size = pobj->integer.value;
> > > >> +
> > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > > >> %lld,\n", buf,
> > > >> +                                        hp_wmi_elements[type][i], pobj-
> > > >>> integer.value);
> > > >> +            }
> > > >> +    }
> > > >> +
> > > >> +    if (type == HPWMI_ENUMERATION_TYPE) {
> > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
> > > >> [\n", buf);
> > > >> +            for (i = 0; i < size; i++) {
> > > >> +                    pobj = &(obj->package.elements[i +
> > > >> hp_wmi_elements_count[type]]);
> > > >> +
> > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > >>> string.pointer,
> > > >> +                                                   pobj->string.length,
> > > >> +                                                   &value, &value_len);
> > > >> +                    if (ACPI_FAILURE(status))
> > > >> +                            break;
> > > >> +
> > > >> +                    /*
> > > >> +                     * Report list of "PossibleValues" of size
> > > >> +                     * "Size"
> > > >> +                     *      ...
> > > >> +                     *      "Size": 2,
> > > >> +                     *      "PossibleValues": [
> > > >> +                     *                      "Disable",
> > > >> +                     *                      "Enable"]
> > > >> +                     */
> > > >> +                    if (i == (size - 1))
> > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > >> +                                                "%s\t\t\"%s\"\n", buf,
> > > >> value);
> > > >> +                    else
> > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > >> +                                                "%s\t\t\"%s\",\n", buf,
> > > >> value);
> > > >> +                    kfree(value);
> > > >> +                    value = NULL;
> > > >> +            }
> > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > >> +    }
> > > >> +
> > > >> +    if (type == HPWMI_ORDEREDLIST_TYPE) {
> > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
> > > >> buf);
> > > >> +            if (size <= 0)
> > > >> +                    goto finish_ordered_list;
> > > >> +
> > > >> +            pobj = &(obj-
> > > >>> package.elements[hp_wmi_elements_count[type]]);
> > > >> +            status = convert_hexstr_to_str(&pobj->string.pointer,
> > > >> +                                           pobj->string.length, &value,
> > > >> &value_len);
> > > >> +            if (ACPI_FAILURE(status))
> > > >> +                    goto finish_ordered_list;
> > > >> +
> > > >> +            /*
> > > >> +             * 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(&value, value_len, &tmpstr,
> > > >> &tmp_len);
> > > >> +            if (ACPI_FAILURE(status))
> > > >> +                    goto finish_ordered_list;
> > > >> +
> > > >> +            part_tmp = tmpstr;
> > > >> +            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);
> > > >> +            }
> > > >> +    }
> > > >> +
> > > >> +finish_ordered_list:
> > > >> +    if (type == HPWMI_ORDEREDLIST_TYPE)
> > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > >> +
> > > >> +    /*
> > > >> +     * remove trailing comma
> > > >> +     */
> > > >> +    if (buf_size > 3)
> > > >> +            buf[buf_size - 2] = ' ';
> > > >> +
> > > >> +    kfree(tmpstr);
> > > >> +    kfree(value);
> > > >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > > >> +}
> > > >> +
> > > >> +static int append_buffer_elements_to_buffer(union acpi_object *obj,
> > > >> +                                        char *buf, int alloc_size, enum
> > > >> hp_wmi_data_type type)
> > > >> +{
> > > >> +    int buf_size;
> > > >> +    int status;
> > > >> +    char *str = NULL;
> > > >> +    int i;
> > > >> +    int j;
> > > >> +    int integer;
> > > >> +    int size = 0;
> > > >> +
> > > >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > > >> +            return -EINVAL;
> > > >> +
> > > >> +    if (obj->type != ACPI_TYPE_BUFFER)
> > > >> +            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]);
> > > >> +
> > > >> +    for (i = 0; i < 3; i++) {
> > > >> +            status = get_string_from_buffer((u16 **)&obj-
> > > >>> buffer.pointer, &str);
> > > >> +            if (ACPI_SUCCESS(status)) {
> > > >> +                    /*
> > > >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > > >> since
> > > >> +                     * 'CurrentValue' is reported.
> > > >> +                     */
> > > >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > >> +                                                "%s\t\"%s\": \"%s\",\n",
> > > >> +                                                buf,
> > > >> +
> > > >> hp_wmi_elements[type][i], str);
> > > >> +            }
> > > >> +            kfree(str);
> > > >> +            str = NULL;
> > > >> +
> > > >> +    }
> > > >> +
> > > >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > > >> +            if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
> > > >> +                    status = get_string_from_buffer((u16 **)&obj-
> > > >>> buffer.pointer, &str);
> > > >> +                    if (ACPI_SUCCESS(status)) {
> > > >> +                            /*
> > > >> +                             * Report "CurrentValue" as "Value"
> > > >> +                             */
> > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > >> +                                                "%s\t\"Value\": \"%s\",\n",
> > > >> buf, str);
> > > >> +                    }
> > > >> +                    kfree(str);
> > > >> +                    str = NULL;
> > > >> +                    continue;
> > > >> +
> > > >> +            } else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
> > > >> +                    /*
> > > >> +                     * Report list of "SupportEncoding"
> > > >> +                     *
> > > >> +                     *      "SupportedEncoding": [
> > > >> +                     *              "utf-16"
> > > >> +                     *      ],
> > > >> +                     *
> > > >> +                     */
> > > >> +
> > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > > >> +                                        buf, hp_wmi_elements[type][i]);
> > > >> +                    for (j = 0; j < size; j++) {
> > > >> +                            status = get_string_from_buffer((u16
> > > >> **)&obj->buffer.pointer, &str);
> > > >> +                            if (ACPI_SUCCESS(status)) {
> > > >> +                                    if (j == size - 1)
> > > >> +                                            buf_size = snprintf(buf,
> > > >> alloc_size,
> > > >> +
> > > >> "%s\t\t\"%s\"\n", buf, str);
> > > >> +                                    else
> > > >> +                                            buf_size = snprintf(buf,
> > > >> alloc_size,
> > > >> +
> > > >> "%s\t\t\"%s\",\n", buf, str);
> > > >> +                            }
> > > >> +                            kfree(str);
> > > >> +                            str = NULL;
> > > >> +                    }
> > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > >> +                    continue;
> > > >> +            }
> > > >> +
> > > >> +            size = 0;
> > > >> +            status = get_integer_from_buffer((int **)&obj-
> > > >>> buffer.pointer, &integer);
> > > >> +            if (ACPI_SUCCESS(status)) {
> > > >> +                    /*
> > > >> +                     * Report "PrerequisiteSize" and "Size" values
> > > >> +                     *      ...
> > > >> +                     *      "PrerequisiteSize": 1,
> > > >> +                     *      ...
> > > >> +                     *      "Size": 2,
> > > >> +                     *      ...
> > > >> +                     */
> > > >> +                    if (i == 7)
> > > >> +                            size = integer;
> > > >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > > >> == 10)
> > > >> +                            size = integer;
> > > >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > > >> 9)
> > > >> +                            size = integer;
> > > >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > > >> 11)
> > > >> +                            size = integer;
> > > >> +
> > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > > >> %d,\n", buf,
> > > >> +                                        hp_wmi_elements[type][i],
> > > >> integer);
> > > >> +            }
> > > >> +
> > > >> +            if (size > 20)
> > > >> +                    pr_warn("%s exceeded the maximum number of
> > > >> elements supported or data may be malformed\n",
> > > >> +                            hp_wmi_elements[type][i]);
> > > >> +
> > > >> +            if (ACPI_SUCCESS(status) && i == 7) {
> > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > >> "%s\t\"Prerequisites\": [\n", buf);
> > > >> +                    for (j = 0; j < size; j++) {
> > > >> +                            status = get_string_from_buffer((u16
> > > >> **)&obj->buffer.pointer, &str);
> > > >> +                            if (ACPI_SUCCESS(status)) {
> > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > >> "%s\t\t\"%s\"", buf, str);
> > > >> +
> > > >> +                                    if (j == size - 1)
> > > >> +                                            buf_size = snprintf(buf,
> > > >> alloc_size, "%s\n", buf);
> > > >> +                                    else
> > > >> +                                            buf_size = snprintf(buf,
> > > >> alloc_size, "%s,\n", buf);
> > > >> +
> > > >> +                            }
> > > >> +                            kfree(str);
> > > >> +                            str = NULL;
> > > >> +                    }
> > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > >> +            }
> > > >> +    }
> > > >> +
> > > >> +    if (type == HPWMI_ENUMERATION_TYPE || type ==
> > > >> HPWMI_ORDEREDLIST_TYPE) {
> > > >> +            if (type == HPWMI_ENUMERATION_TYPE)
> > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > >> "%s\t\"PossibleValues\": [\n", buf);
> > > >> +            else
> > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > >> "%s\t\"Elements\": [\n", buf);
> > > >> +
> > > >> +            for (i = 0; i < size; i++) {
> > > >> +                    status = get_string_from_buffer((u16 **)&obj-
> > > >>> buffer.pointer, &str);
> > > >> +                    if (ACPI_SUCCESS(status)) {
> > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > >> "%s\t\t\"%s\"", buf, str);
> > > >> +
> > > >> +                            if (i == size - 1)
> > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > >> "%s\n", buf);
> > > >> +                            else
> > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > >> "%s,\n", buf);
> > > >> +
> > > >> +                    }
> > > >> +                    kfree(str);
> > > >> +                    str = NULL;
> > > >> +            }
> > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > >> +    }
> > > >> +
> > > >> +    /*
> > > >> +     * remove trailing comma
> > > >> +     */
> > > >> +    if (buf_size > 3)
> > > >> +            buf[buf_size - 2] = ' ';
> > > >> +
> > > >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > > >> +}
> > > >> +
> > > >> +static int hp_bios_settings_free_buffer(void)
> > > >> +{
> > > >> +    mutex_lock(&buf_mutex);
> > > >> +    kfree(hp_bios_settings_buffer);
> > > >> +    settings_buffer_size = 0;
> > > >> +    buf_alloc_size = 0;
> > > >> +    mutex_unlock(&buf_mutex);
> > > >> +
> > > >> +    return 0;
> > > >> +}
> > > >> +
> > > >> +static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
> > > >> +                                       int *alloc_size,
> > > >> +                                       struct mutex *buf_mutex)
> > > >> +{
> > > >> +    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(buf_mutex);
> > > >> +            new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
> > > >> +            mutex_unlock(buf_mutex);
> > > >> +            if (new_buf) {
> > > >> +                    mutex_lock(buf_mutex);
> > > >> +                    *buf = new_buf;
> > > >> +                    *alloc_size = ksize(new_buf);
> > > >> +                    mutex_unlock(buf_mutex);
> > > >> +            } else {
> > > >> +                    hp_bios_settings_free_buffer();
> > > >> +                    ret = -ENOMEM;
> > > >> +            }
> > > >> +    }
> > > >> +
> > > >> +    return ret;
> > > >> +}
> > > >> +
> > > >> +static int append_settings_to_buffer(char *guid, int type, char **buf,
> > > >> +                                 int *buf_size, int *alloc_size,
> > > >> +                                 struct mutex *buf_mutex)
> > > >> +{
> > > >> +    union acpi_object *obj = NULL;
> > > >> +    int ret = 0;
> > > >> +    int status = 0;
> > > >> +    int instance = 0;
> > > >> +
> > > >> +    /*
> > > >> +     * Query all the instances until to receive a AE_BAD_PARAMETER
> > > >> +     */
> > > >> +    do {
> > > >> +            ret = hp_wmi_get_setting_object(guid, instance++, &obj);
> > > >> +            if (ACPI_SUCCESS(ret) && obj != NULL) {
> > > >> +                    status = 0;
> > > >> +                    if (obj->type == ACPI_TYPE_PACKAGE) {
> > > >> +                            mutex_lock(buf_mutex);
> > > >> +                            status =
> > > >> append_package_elements_to_buffer(obj,
> > > >> +                                                    *buf, *alloc_size,
> > > >> type);
> > > >> +                            if (status > 0)
> > > >> +                                    *buf_size = status;
> > > >> +                            mutex_unlock(buf_mutex);
> > > >> +
> > > >> +                    } else if (obj->type == ACPI_TYPE_BUFFER) {
> > > >> +                            mutex_lock(buf_mutex);
> > > >> +                            status =
> > > >> append_buffer_elements_to_buffer(obj,
> > > >> +                                                    *buf, *alloc_size,
> > > >> type);
> > > >> +                            if (status > 0)
> > > >> +                                    *buf_size = status;
> > > >> +                            mutex_unlock(buf_mutex);
> > > >> +
> > > >> +                    } else
> > > >> +                            pr_warn("The retrieved object type(%d) is
> > > >> not supported yet\n",
> > > >> +                                    obj->type);
> > > >> +
> > > >> +                    ret = hp_bios_settings_realloc_buffer(buf, buf_size,
> > > >> alloc_size, buf_mutex);
> > > >> +            }
> > > >> +
> > > >> +            kfree(obj);
> > > >> +            obj = NULL;
> > > >> +
> > > >> +    } while (ACPI_SUCCESS(ret));
> > > >> +
> > > >> +    /*
> > > >> +     * AE_BAD_PARAMETER means the loop ended by exhaustion
> > > >> +     */
> > > >> +    if (ret == AE_BAD_PARAMETER)
> > > >> +            ret = 0;
> > > >> +
> > > >> +    return ret;
> > > >> +}
> > > >> +
> > > >> +static int hp_bios_settings_fill_buffer(void)
> > > >> +{
> > > >> +    int status = 0;
> > > >> +    int initial_buffer_size = 20 * PAGE_SIZE;
> > > >> +
> > > >> +    mutex_lock(&buf_mutex);
> > > >> +    hp_bios_settings_buffer = kmalloc(initial_buffer_size,
> > GFP_KERNEL);
> > > >> +    mutex_unlock(&buf_mutex);
> > > >> +    if (!hp_bios_settings_buffer)
> > > >> +            return -ENOMEM;
> > > >> +
> > > >> +    mutex_lock(&buf_mutex);
> > > >> +    buf_alloc_size = ksize(hp_bios_settings_buffer);
> > > >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > > >> +                                    buf_alloc_size, "[\n");
> > > >> +    mutex_unlock(&buf_mutex);
> > > >> +
> > > >> +    status = append_settings_to_buffer(HPWMI_STRING_GUID,
> > > >> +            HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
> > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > >> +    if (ACPI_FAILURE(status))
> > > >> +            pr_err("error 0x%x occurred retrieving string instances\n",
> > > >> status);
> > > >> +
> > > >> +    status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
> > > >> +            HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
> > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > >> +    if (ACPI_FAILURE(status))
> > > >> +            pr_err("error 0x%x occurred retrieving integer instances\n",
> > > >> status);
> > > >> +
> > > >> +    status =
> > append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
> > > >> +            HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
> > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > >> +    if (ACPI_FAILURE(status))
> > > >> +            pr_err("error 0x%x occurred retrieving enumeration
> > > >> instances\n", status);
> > > >> +
> > > >> +    status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
> > > >> +            HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
> > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > >> +    if (ACPI_FAILURE(status))
> > > >> +            pr_err("error 0x%x occurred retrieving ordered list
> > > >> instances\n", status);
> > > >> +
> > > >> +    status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
> > > >> +            HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
> > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > >> +    if (ACPI_FAILURE(status))
> > > >> +            pr_err("error 0x%x occurred retrieving password list
> > > >> instances\n", status);
> > > >> +
> > > >> +    mutex_lock(&buf_mutex);
> > > >> +    /*
> > > >> +     * remove trailing comma
> > > >> +     */
> > > >> +    if (settings_buffer_size >= 3) {
> > > >> +            if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
> > > >> +                    hp_bios_settings_buffer[settings_buffer_size - 2] = '
> > > >> ';
> > > >> +    }
> > > >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > > >> +                                    buf_alloc_size, "%s]\n",
> > > >> +                                    hp_bios_settings_buffer);
> > > >> +    mutex_unlock(&buf_mutex);
> > > >> +
> > > >> +    return settings_buffer_size;
> > > >> +}
> > > >> +
> > > >> +/*
> > > >> + * sure_admin_settings_read - Return a formatted file with settings
> > > >> + *                              and possible options read from BIOS
> > > >> + *
> > > >> + * @filp:  Pointer to file of settings read from BIOS
> > > >> + * @kobj:  Pointer to a kernel object of things that show up as directory
> > in
> > > >> the sysfs filesystem.
> > > >> + * @attr:  Pointer to list of read attributes
> > > >> + * @buf:   Pointer to buffer
> > > >> + * @off:   File current offset
> > > >> + * @count: Buffer size
> > > >> + *
> > > >> + * Returns the count of unicode chars read if successful, otherwise
> > > >> + *          -ENOMEM unable to allocate memory
> > > >> + *          -EINVAL buffer not allocated or too small
> > > >> + *
> > > >> + */
> > > >> +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 >= settings_buffer_size && settings_buffer_size > 0) {
> > > >> +            hp_bios_settings_free_buffer();
> > > >> +            return 0;
> > > >> +    }
> > > >> +
> > > >> +    /* clear the buffer whenever the read starts from the first position
> > > >> */
> > > >> +    if (off == 0 && settings_buffer_size > 0)
> > > >> +            hp_bios_settings_free_buffer();
> > > >> +
> > > >> +    if (settings_buffer_size == 0)
> > > >> +            hp_bios_settings_fill_buffer();
> > > >> +
> > > >> +    mutex_lock(&buf_mutex);
> > > >> +    ret = memory_read_from_buffer(buf, count, &off,
> > > >> hp_bios_settings_buffer,
> > > >> +                                  settings_buffer_size);
> > > >> +    mutex_unlock(&buf_mutex);
> > > >> +
> > > >> +    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
> > > >> + */
> > > >> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
> > > >> +{
> > > >> +    int len = strlen(str);
> > > >> +
> > > >> +    /*
> > > >> +     * Add null character when reading an empty string
> > > >> +     */
> > > >> +    if (len == 0) {
> > > >> +            *p++ = 2;
> > > >> +            *p++ = (u8)0x00;
> > > >> +            return p;
> > > >> +    }
> > > >> +    *p++ = len * 2;
> > > >> +    utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
> > > >> +    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
> > > >> + */
> > > >> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 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(HPWMI_SETBIOSSETTING_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;
> > > >> +}
> > > >> +
> > > >> +/* Sure Admin Functions */
> > > >> +
> > > >> +#define UTF_PREFIX                  ((unsigned char *)"<utf-16/>")
> > > >> +#define BEAM_PREFIX                 ((unsigned char
> > > >> *)"<BEAM/>")
> > > >> +
> > > >> +/*
> > > >> + * sure_admin_settings_write - Write the contents of a formatted file
> > > >> + *                               with settings and performs the logic
> > > >> + *                               to change any settings in BIOS.
> > > >> + *
> > > >> + * @filp:  Pointer to file of settings to be written to BIOS
> > > >> + * @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 write operation
> > > >> + * @buf:   Pointer to buffer
> > > >> + * @off:   File current offset
> > > >> + * @count: Buffer size
> > > >> + *
> > > >> + *
> > > >> + * Returns the count of unicode characters written to BIOS if
> > successful,
> > > >> otherwise
> > > >> + *          -ENOMEM unable to allocate memory
> > > >> + *          -EINVAL buffer not allocated or too small
> > > >> + *
> > > >> + */
> > > >> +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;
> > > >> +    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 out_free;
> > > >> +    }
> > > >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > >> +    part = strsep(&buf, ",");
> > > >> +    if (!part) {
> > > >> +            status = -EINVAL;
> > > >> +            goto out_free;
> > > >> +    }
> > > >> +
> > > >> +    /* Add extra buffer space when encountering an empty string */
> > > >> +    if (!strlen(part))
> > > >> +            buffer_size += sizeof(unsigned short);
> > > >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > >> +    part = strsep(&buf, ",");
> > > >> +    if (!part) {
> > > >> +            status = -EINVAL;
> > > >> +            goto out_free;
> > > >> +    }
> > > >> +    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 out_free;
> > > >> +
> > > >> +            tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > >> +            kfree(part);
> > > >> +    }
> > > >> +
> > > >> +    part = strsep(&buf, ",");
> > > >> +    if (part) {
> > > >> +            status = -EINVAL;
> > > >> +            goto out_free;
> > > >> +    }
> > > >> +    status = hp_wmi_set_bios_setting(buffer, buffer_size);
> > > >> +    if (ACPI_FAILURE(status))
> > > >> +            status = -EINVAL;
> > > >> +
> > > >> +out_free:
> > > >> +    kfree(buffer);
> > > >> +    if (ACPI_SUCCESS(status))
> > > >> +            return count;
> > > >> +    return status;
> > > >> +}
> > > >> +
> > > >> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
> > > >> +
> > > >> +static struct bin_attribute *sure_admin_binattrs[] = {
> > > >> +    &sure_admin_settings,
> > > >> +    NULL,
> > > >> +};
> > > >> +
> > > >> +static const struct attribute_group sure_admin_group = {
> > > >> +    .name = "sure_admin",
> > > >> +    .bin_attrs = sure_admin_binattrs,
> > > >> +};
> > > >> +
> > > >>  static DEVICE_ATTR_RO(display);
> > > >>  static DEVICE_ATTR_RO(hddtemp);
> > > >>  static DEVICE_ATTR_RW(als);
> > > >> @@ -1050,6 +2026,7 @@ static const struct attribute_group
> > > >> *hp_wmi_groups[] = {
> > > >>      &hp_wmi_group,
> > > >>      &spm_group,
> > > >>      &sure_start_group,
> > > >> +    &sure_admin_group,
> > > >>      NULL,
> > > >>  };
> > > >>
> > > >> --
> > > >> 2.25.1
> > >

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-07 13:44           ` Jorge Lopez
@ 2022-04-07 19:17             ` Limonciello, Mario
  2022-04-07 20:57               ` Jorge Lopez
  2022-04-08  9:21             ` Hans de Goede
  1 sibling, 1 reply; 25+ messages in thread
From: Limonciello, Mario @ 2022-04-07 19:17 UTC (permalink / raw)
  To: Jorge Lopez; +Cc: Hans de Goede, platform-driver-x86

[Public]

> -----Original Message-----
> From: Jorge Lopez <jorgealtxwork@gmail.com>
> Sent: Thursday, April 7, 2022 08:45
> To: Limonciello, Mario <Mario.Limonciello@amd.com>
> Cc: Hans de Goede <hdegoede@redhat.com>; platform-driver-
> x86@vger.kernel.org
> Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> 
> Hans, Mario,
> 
> The code links make references to code that implements the new
> interfaces but there’s
> still code in the kernel that uses the old ones.  I do agree we should
> be forward looking
> and want to be good participants in the kernel development, but can’t
> let our immediate
> business needs be impacted with opportunities to enhance the driver to
> take advantage
> of the latest kernel features.
> 

Keep in mind that from an upstream kernel perspective this driver is "new".
There is no requirements from the upstream perspective to
keep your old interfaces in place from when it was out of tree.

Requirements like this start when the driver is in tree.
https://www.kernel.org/doc/html/latest/admin-guide/abi-stable.html

> Rewriting those security features will impact customer business
> datelines requiring
> HP to provide private releases as the kernel version changes.   The
> requested changes
> will impact products in the market and HP ability to help customers to
> migrate to Linux
> from Windows products.
> 
> It is because of the immediate business needs, avoiding impacting our
> customers/products,
> and rewriting  enhancements to the driver that I need to propose an
> interim solution.

Right, get it upstream and it's less work, of course 😊

> 
> My proposal is to introduce a read/write value accessible in the user
> space to control how
> the driver reports and handles BIOS settings and values.  The new
> configuration features
> will be gradually disabled  as they are converted to use the standardized API.
> It is like the configuration flag used to overcome the tablet detection
> problem
> introduced in the past.   The changes solely affect the HP WMI driver.
> This option will help us
> move forward for this release and give us time to make the necessary
> changes to both
> the driver and support applications.
> 
> Please let me know if this is a viable interim solution.
> 
> If it is not possible, I need to ask where the actual written
> requirement is found so I can
> include them in the business justification for changes and release
> delays to management.
> 

From an upstream subsystem maintainer perspective Hans will want you to do
everything you can to get it correct the first time.  If you don't; what impetus do
you have to fix it later?  You would have an interface that "works" and meets
your business needs but no guarantee it ever would standardize.

I do get where you're coming from though and you obviously have customers that
value your existing interface.  So let me entertain this thought process a little bit,
Hans feel free to disagree with me.

If there is a compatibility mode to let it work similar to how it worked "out
of tree" I don't think this should be something that you turn on/off dynamically
at runtime.  It is a lot of code, you introduce complexity of sysfs files coming and
going and racing with userspace and worse this eventually this would all be dead code.
I think it's better to have a KConfig option that would enable this dead code.

Also I think a better place for such a file that we would all know is going to eventually
go away is debugfs.  There is no guarantee for files and interfaces in debugfs to stay
around.  You can point applications at using the sysfs file today with your out of tree
driver there until the standardized interface support is made available.
Something like CONFIG_HP_WMI_DEBUGFS_SETTINGS.  Then you can keep it in there
as long as you want, distros and users can decide if they want to use it.  When you're
confident enough that all the applications that previously used the out of tree module
are migrated to the modern interface tear away that debugfs option as a future patch.

> 
> Regards,
> 
> Jorge Lopez
> 
> 
> On Tue, Apr 5, 2022 at 12:13 PM Limonciello, Mario
> <Mario.Limonciello@amd.com> wrote:
> >
> > [Public]
> >
> >
> >
> > > -----Original Message-----
> > > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > Sent: Tuesday, April 5, 2022 11:52
> > > To: Hans de Goede <hdegoede@redhat.com>
> > > Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-driver-
> > > x86@vger.kernel.org
> > > Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> > >
> > > Hi Hans,
> > >
> > > On Tue, Apr 5, 2022 at 6:54 AM Hans de Goede
> <hdegoede@redhat.com>
> > > wrote:
> > > >
> > > > Hi,
> > > >
> > > > On 4/4/22 23:59, Limonciello, Mario wrote:
> > > > > [Public]
> > > > >
> > > > >
> > > > >
> > > > >> -----Original Message-----
> > > > >> From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > > >> Sent: Monday, April 4, 2022 15:36
> > > > >> To: platform-driver-x86@vger.kernel.org
> > > > >> Subject: [PATCH v1 5/6] Sure Admin Security Feature
> > > > >>
> > > > >> 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. Behind the scenes, Sure Admin uses Secure
> > > Platform
> > > > >> Management (SPM) and WMI
> > > > >>
> > > > >> 'settings' is a file associated with Sure Admin. BIOS settings can be
> > > > >> read or written through the Sure Admin settings file in sysfs
> > > > >>
> > > > >>      /sys/devices/platform/hp-wmi/sure_admin/settings
> > > > >>
> > > > >> 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"
> > > > >>              ]
> > > > >>      }
> > > > >>
> > > > >
> > > > > This sounds like it has re-invented /sys/class/firmware-attributes.
> > > > >
> > > > > Shouldn't you adopt that API?
> > > >
> > > > I fully agree. Jorge as I already indicated in our off-list
> > > > conversation when you initially started working on this
> > > > feature, we already have a standardized API for querying/changing
> > > > BIOS settings from within Linux:
> > > >
> > >
> > > I agree that changing the BIOS settings from within Linux could
> > > utilize the new methodology,  I will need to look closely at the
> > > requirements before I can proceed to make the changes.
> > > Keep in mind authentication of the values is done by BIOS.  No Linux
> > > process validates any data name, value, or auth token; only BIOS.  All
> > > data written to the sysfs file is not validated, it is just forward to
> > > BIOS.  See spm_kek_store and spm_sk_store functions.
> >
> > That's fine, and it's a safer design to have BIOS validate it.
> >
> > > One point I must make clear when updating BIOS settings.  any  NOT
> > > read-only BIOS settings can be changed by the application at any time.
> > >    This list of settings changes from one system to another.
> >
> > Right.
> >
> > >
> > > I am in disagreement with reading the settings.  hp-wmi does not read
> > > one value at a time. It reads all values exposed by BIOS.  See
> > > attached sample output.
> >
> > The settings can all be read at initialization time for the driver and cached
> > then.
> >
> > > The method for how all BIOS settings are reported needs to match the
> > > method how Windows products do it.  It is a requirement to start
> > > migrating customers from Windows to Linux while minimizing how BIOS
> > > data is reported.
> >
> > Because we have a standardized API in Linux for this, I think it's best to
> abstract
> > this behind a userspace application/script.  If they expect to see it in the
> format you
> > showed, the userspace application can take the data from Linux and
> package it that
> > way.
> >
> > You'll have richer libraries and languages and tools to work from when
> doing this too.
> > It should make it a lot less painful.
> >
> > >
> > > I will investigate the new API and bring it to the team's attention.
> > >
> > > >
> > >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> served=0
> > >
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> > >
> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> > >
> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> > >
> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> > >
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> > >
> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> > > D&amp;reserved=0
> > > >
> > > > and any new code (such as this patch) which implements BIOS
> > > > setting changing MUST follow this standardized API (extending
> > > > it where necessary).
> > > >
> > > > I'm sorry but this patch is not acceptable in its current form,
> > > > it needs to be *completely rewritten* to implement:
> > > >
> > > >
> > >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> served=0
> > >
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> > >
> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> > >
> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> > >
> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> > >
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> > >
> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> > > D&amp;reserved=0
> > > >
> > > > See:
> > > >
> > > >
> > >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> served=0
> > >
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fdell%2Fdell-wmi-
> > >
> sysman&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8f
> > >
> ea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> > >
> 7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> > >
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> > >
> mp;sdata=z5jmH7ECYBeLcndQ2vfHaUuyE04Eaf1Lymh6BjnyJ%2Fk%3D&amp;r
> > > eserved=0
> > > >
> > >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> served=0
> > >
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fthink-
> > >
> lmi.c&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea
> > >
> 104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > >
> 0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > >
> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > >
> sdata=5n6w9LEB2iWpj1cOQP6Ngz94AqP1Bu4vu8T0EdN%2FThU%3D&amp;re
> > > served=0
> > > >
> > > > for example code / for 2 drivers from other vendors already
> > > > implementing this.
> > > >
> > > > The same applies to the:
> > > >
> > > > "[PATCH v1 3/6] Secure Platform Management Security Feature"
> > > >
> > > > this needs to be implemented as
> > > > a /sys/class/firmware-attributes/*/authentication/
> > > > authentication method, see for example these Lenovo specific
> > > > addition to the /sys/class/firmware-attributes/*/authentication/
> > > > userspace API for similar functionality on Lenovo Think* devices:
> > > >
> > > >
> > >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> served=0
> > >
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > >
> 2Fcommit%2F%3Fid%3D06384573a3e8335ac6797577e545c33dbf91b490&amp;
> > >
> data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea1040342827
> > >
> 08da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C63784
> > >
> 7743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLC
> > >
> JQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=eldS
> > >
> 4H3Z%2BAyL%2FG%2FO9W9rDGC37yh5sGgtUhpKdUAoSmA%3D&amp;reser
> > > ved=0
> > > >
> > > > I'll merge patches 1-2 sometime this week since those are
> > > > fine and it will be good to have those "out of the way",
> > > > but the rest of the series will need to be rewritten
> > > > taken the above comments into account.
> > >
> > > v1-0003-Sure-Start-Security-Feature.patch  reports the number of audit
> > > logs available and reports them when read.    it does not read/write
> > > BIOS settings hence it does not fall within the same category as
> > > patches v1-0002-Secure-Platform-Management-Security-Feature.patch
> and
> > > v1-0004-Sure-Admin-Security-Feature.patch
> > > Do you agree?
> > >
> > > >
> > > > Regards,
> > > >
> > > > Hans
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > >
> > > > >
> > > > >> This feature requires "Update hp_wmi_group to simplify feature
> > > > >> addition" patch.
> > > > >>
> > > > >> All changes were validated on a HP ZBook Workstation,
> > > > >> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> > > > >>
> > > > >> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> > > > >>
> > > > >> ---
> > > > >> Based on the latest platform-drivers-x86.git/for-next
> > > > >> ---
> > > > >>  drivers/platform/x86/hp-wmi.c | 977
> > > > >> ++++++++++++++++++++++++++++++++++
> > > > >>  1 file changed, 977 insertions(+)
> > > > >>
> > > > >> diff --git a/drivers/platform/x86/hp-wmi.c
> b/drivers/platform/x86/hp-
> > > wmi.c
> > > > >> index 918e3eaf1b67..b72ca18b77a6 100644
> > > > >> --- a/drivers/platform/x86/hp-wmi.c
> > > > >> +++ b/drivers/platform/x86/hp-wmi.c
> > > > >> @@ -27,6 +27,7 @@
> > > > >>  #include <linux/rfkill.h>
> > > > >>  #include <linux/string.h>
> > > > >>  #include <linux/dmi.h>
> > > > >> +#include <linux/nls.h>
> > > > >>
> > > > >>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
> > > > >>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
> > > > >> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-
> BE91-
> > > > >> 3D44E2C707E4");
> > > > >>
> > > > >>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-
> > > ACCDC67EF61C"
> > > > >>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-
> > > 3D44E2C707E4"
> > > > >> +
> > > > >>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
> > > > >>
> > > > >> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-
> > > 6A1B8106F83C"
> > > > >> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
> > > > >> E293ADB9BF05"
> > > > >> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-
> B8FE-
> > > > >> 4A3C09E75133"
> > > > >> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
> > > > >> 7045CB4DA745"
> > > > >> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
> > > > >> 015176049E2D"
> > > > >> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-
> 951D-
> > > > >> C7CB9B4B8D5E"
> > > > >> +
> > > > >>  /* DMI board names of devices that should use the omen specific
> path
> > > for
> > > > >>   * thermal profiles.
> > > > >>   * This was obtained by taking a look in the windows omen
> command
> > > center
> > > > >> @@ -1025,6 +1034,973 @@ static const struct attribute_group
> > > > >> sure_start_group = {
> > > > >>      .attrs = sure_start_attrs,
> > > > >>  };
> > > > >>
> > > > >> +
> > > > >> +static 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;
> > > > >> +    int  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));
> > > > >> +            ret = kstrtoint(tmp, 16, &ch);
> > > > >> +            if (ret) {
> > > > >> +                    new_len = 0;
> > > > >> +                    break;
> > > > >> +            }
> > > > >> +
> > > > >> +            if (ch == '\\')
> > > > >> +                    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;
> > > > >> +    }
> > > > >> +
> > > > >> +    if (ret)
> > > > >> +            kfree(new_str);
> > > > >> +    return ret;
> > > > >> +}
> > > > >> +
> > > > >> +/*
> > > > >> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and
> > > instance
> > > > >> + *
> > > > >> + * @guid:   GUID associated with the ACPI list of managed objects
> > > > >> + * @instance:       Instance index to query on the ACPI list
> > > > >> + * @obj:    The output ACPI object of type ACPI_TYPE_PACKAGE
> > > > >> + *          or ACPI_TYPE_BUFFER (freed by the callee)
> > > > >> + *
> > > > >> + * Returns  zero on success.  Otherwise,an error inherited from
> > > > >> + *          wmi_query_block(). It returns a obj by parameter if
> > > > >> + *          the query returned object of type buffer or package,
> > > > >> + *          otherwise, a null obj is returned.
> > > > >> + *
> > > > >> + * Note: obj should be freed by the callee once it is finished
> working
> > > with it
> > > > >> + */
> > > > >> +static int hp_wmi_get_setting_object(char *guid, int instance,
> > > > >> +                            union acpi_object **obj)
> > > > >> +{
> > > > >> +    struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER,
> NULL
> > > > >> };
> > > > >> +    union acpi_object *tmp = NULL;
> > > > >> +    int ret;
> > > > >> +
> > > > >> +    ret = wmi_query_block(guid, instance, &output);
> > > > >> +    if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
> > > > >> +            tmp = output.pointer;
> > > > >> +            if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
> > > > >> ACPI_TYPE_PACKAGE)
> > > > >> +                    *obj = output.pointer;
> > > > >> +            else {
> > > > >> +                    kfree(tmp);
> > > > >> +                    *obj = NULL;
> > > > >> +            }
> > > > >> +    }
> > > > >> +
> > > > >> +    return ret;
> > > > >> +}
> > > > >> +
> > > > >> +
> > > > >> +static 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;
> > > > >> +
> > > > >> +    if (size == 0)
> > > > >> +            goto cleanup_exit;
> > > > >> +
> > > > >> +    for (i = 0; i < size; i++)
> > > > >> +            if (ptr[i] == '\\')
> > > > >> +                    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);
> > > > >> +
> > > > >> +    if (escape == 0) {
> > > > >> +            ptr += (ptrlen / 2);
> > > > >> +            goto cleanup_exit;
> > > > >> +    }
> > > > >> +    /*
> > > > >> +     * Convert escape characters only when found
> > > > >> +     */
> > > > >> +    for (i = 0; i < size; i++) {
> > > > >> +            if (*ptr == '\\')
> > > > >> +                    output[i++] = '\\';
> > > > >> +            output[i] = *ptr;
> > > > >> +            ptr++;
> > > > >> +    }
> > > > >> +
> > > > >> +cleanup_exit:
> > > > >> +    *buffer = ptr;
> > > > >> +    return 0;
> > > > >> +}
> > > > >> +
> > > > >> +static int get_integer_from_buffer(int **buffer, int *integer)
> > > > >> +{
> > > > >> +    int *ptr = PTR_ALIGN(*buffer, 4);
> > > > >> +    *integer = *(ptr++);
> > > > >> +    *buffer = ptr;
> > > > >> +    return 0;
> > > > >> +}
> > > > >> +
> > > > >> +
> > > > >> +// Sure Admin functions
> > > > >> +enum hp_wmi_data_type {
> > > > >> +    HPWMI_STRING_TYPE,
> > > > >> +    HPWMI_INTEGER_TYPE,
> > > > >> +    HPWMI_ENUMERATION_TYPE,
> > > > >> +    HPWMI_ORDEREDLIST_TYPE,
> > > > >> +    HPWMI_PASSWORD_TYPE,
> > > > >> +};
> > > > >> +
> > > > >> +#define HP_WMI_COMMON_ELEMENTS      \
> > > > >> +    "Name", \
> > > > >> +    "Value",        \
> > > > >> +    "Path", \
> > > > >> +    "IsReadOnly",   \
> > > > >> +    "DisplayInUI",  \
> > > > >> +    "RequiresPhysicalPresence",     \
> > > > >> +    "Sequence",     \
> > > > >> +    "PrerequisiteSize",     \
> > > > >> +    "SecurityLevel"
> > > > >> +
> > > > >> +const char *hp_wmi_string_elements[] = {
> > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > >> +    "MinLength",
> > > > >> +    "MaxLength"
> > > > >> +};
> > > > >> +
> > > > >> +const char *hp_wmi_integer_elements[] = {
> > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > >> +    "LowerBound",
> > > > >> +    "UpperBound",
> > > > >> +    "IntValue"
> > > > >> +};
> > > > >> +
> > > > >> +const char *hp_wmi_enumeration_elements[] = {
> > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > >> +    "CurrentValue",
> > > > >> +    "Size"
> > > > >> +};
> > > > >> +
> > > > >> +const char *hp_wmi_orderedlist_elements[] = {
> > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > >> +    "Size"
> > > > >> +};
> > > > >> +
> > > > >> +const char *hp_wmi_password_elements[] = {
> > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > >> +    "MinLength",
> > > > >> +    "MaxLength",
> > > > >> +    "Size",
> > > > >> +    "SupportedEncoding",
> > > > >> +    "IsSet"
> > > > >> +};
> > > > >> +
> > > > >> +const char **hp_wmi_elements[] = {
> > > > >> +    hp_wmi_string_elements,
> > > > >> +    hp_wmi_integer_elements,
> > > > >> +    hp_wmi_enumeration_elements,
> > > > >> +    hp_wmi_orderedlist_elements,
> > > > >> +    hp_wmi_password_elements
> > > > >> +};
> > > > >> +
> > > > >> +const int hp_wmi_elements_count[] = {
> > > > >> +    ARRAY_SIZE(hp_wmi_string_elements),
> > > > >> +    ARRAY_SIZE(hp_wmi_integer_elements),
> > > > >> +    ARRAY_SIZE(hp_wmi_enumeration_elements),
> > > > >> +    ARRAY_SIZE(hp_wmi_orderedlist_elements),
> > > > >> +    ARRAY_SIZE(hp_wmi_password_elements)
> > > > >> +};
> > > > >> +
> > > > >> +const char *hp_wmi_classes[] = {
> > > > >> +    "HPBIOS_BIOSString",
> > > > >> +    "HPBIOS_BIOSInteger",
> > > > >> +    "HPBIOS_BIOSEnumeration",
> > > > >> +    "HPBIOS_BIOSOrderedList",
> > > > >> +    "HPBIOS_BIOSPassword"
> > > > >> +};
> > > > >> +
> > > > >> +static DEFINE_MUTEX(buf_mutex);
> > > > >> +static int settings_buffer_size;
> > > > >> +static int buf_alloc_size;
> > > > >> +static char *hp_bios_settings_buffer;
> > > > >> +
> > > > >> +
> > > > >> +static int append_package_elements_to_buffer(union acpi_object
> > > *obj,
> > > > >> +                                         char *buf, int alloc_size, enum
> > > > >> hp_wmi_data_type type)
> > > > >> +{
> > > > >> +    int i;
> > > > >> +    union acpi_object *pobj = NULL;
> > > > >> +    char *value = NULL;
> > > > >> +    int value_len;
> > > > >> +    char *tmpstr = NULL;
> > > > >> +    char *part_tmp = NULL;
> > > > >> +    int tmp_len = 0;
> > > > >> +    char *part = NULL;
> > > > >> +    int status = 0;
> > > > >> +    int size = 0;
> > > > >> +    int buf_size;
> > > > >> +
> > > > >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > > > >> +            return -EINVAL;
> > > > >> +
> > > > >> +    if (obj->type != ACPI_TYPE_PACKAGE)
> > > > >> +            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]);
> > > > >> +
> > > > >> +    for (i = 0; i < 3; i++) {
> > > > >> +            pobj = &(obj->package.elements[i]);
> > > > >> +            if (pobj->type == ACPI_TYPE_STRING) {
> > > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > > >>> string.pointer,
> > > > >> +                                                   pobj->string.length,
> > > > >> &value, &value_len);
> > > > >> +                    if (ACPI_FAILURE(status))
> > > > >> +                            continue;
> > > > >> +                    /*
> > > > >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > > > >> since
> > > > >> +                     * 'CurrentValue' is reported.
> > > > >> +                     */
> > > > >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > >> +                                                "%s\t\"%s\": \"%s\",\n",
> > > > >> +                                                buf,
> > > > >> +
> > > > >> hp_wmi_elements[type][i], value);
> > > > >> +
> > > > >> +            }
> > > > >> +            kfree(value);
> > > > >> +            value = NULL;
> > > > >> +    }
> > > > >> +
> > > > >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > > > >> +            pobj = &(obj->package.elements[i]);
> > > > >> +
> > > > >> +            if (type == HPWMI_ENUMERATION_TYPE &&
> > > > >> +                i == 9 &&
> > > > >> +                pobj->type == ACPI_TYPE_STRING) {
> > > > >> +                    /*
> > > > >> +                     * Report "CurrentValue" as "Value"
> > > > >> +                     */
> > > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > > >>> string.pointer,
> > > > >> +                                                   pobj->string.length,
> > > > >> +                                                   &value, &value_len);
> > > > >> +                    if (ACPI_FAILURE(status))
> > > > >> +                            continue;
> > > > >> +
> > > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > > >> +                                        "%s\t\"Value\": \"%s\",\n",
> > > > >> +                                        buf, value);
> > > > >> +                    kfree(value);
> > > > >> +                    value = NULL;
> > > > >> +
> > > > >> +            } else if (type == HPWMI_PASSWORD_TYPE &&
> > > > >> +                       i == 12 &&
> > > > >> +                       pobj->type == ACPI_TYPE_STRING) {
> > > > >> +                    /*
> > > > >> +                     * Report list of "SupportEncoding"
> > > > >> +                     *
> > > > >> +                     *      "SupportedEncoding": [
> > > > >> +                     *              "utf-16"
> > > > >> +                     *      ],
> > > > >> +                     *
> > > > >> +                     */
> > > > >> +
> > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > > > >> +                                        buf, hp_wmi_elements[type][i]);
> > > > >> +                    while (size--) {
> > > > >> +                            pobj = &(obj->package.elements[i]);
> > > > >> +                            status = convert_hexstr_to_str(&pobj-
> > > > >>> string.pointer,
> > > > >> +                                                           pobj-
> > > > >>> string.length,
> > > > >> +                                                           &value,
> > > > >> &value_len);
> > > > >> +                            if (ACPI_FAILURE(status))
> > > > >> +                                    continue;
> > > > >> +
> > > > >> +                            if (size) {
> > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > >> +                                                        "%s\t\t\"%s\",\n",
> > > > >> buf, value);
> > > > >> +                                    i++;
> > > > >> +                            } else
> > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > >> +                                                        "%s\t\t\"%s\"\n",
> > > > >> buf, value);
> > > > >> +
> > > > >> +                            kfree(value);
> > > > >> +                            value = NULL;
> > > > >> +
> > > > >> +                    }
> > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > >> +                    continue;
> > > > >> +
> > > > >> +            } else if (pobj->type == ACPI_TYPE_INTEGER) {
> > > > >> +                    /*
> > > > >> +                     * Report "PrerequisiteSize" and "Size" values
> > > > >> +                     *      ...
> > > > >> +                     *      "PrerequisiteSize": 1,
> > > > >> +                     *      ...
> > > > >> +                     *      "Size": 2,
> > > > >> +                     *      ...
> > > > >> +                     */
> > > > >> +                    if (i == 7)
> > > > >> +                            size = pobj->integer.value;
> > > > >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > > > >> 9)
> > > > >> +                            size = pobj->integer.value;
> > > > >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > > > >> == 10)
> > > > >> +                            size = pobj->integer.value;
> > > > >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > > > >> 11)
> > > > >> +                            size = pobj->integer.value;
> > > > >> +
> > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > > > >> %lld,\n", buf,
> > > > >> +                                        hp_wmi_elements[type][i], pobj-
> > > > >>> integer.value);
> > > > >> +            }
> > > > >> +    }
> > > > >> +
> > > > >> +    if (type == HPWMI_ENUMERATION_TYPE) {
> > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
> > > > >> [\n", buf);
> > > > >> +            for (i = 0; i < size; i++) {
> > > > >> +                    pobj = &(obj->package.elements[i +
> > > > >> hp_wmi_elements_count[type]]);
> > > > >> +
> > > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > > >>> string.pointer,
> > > > >> +                                                   pobj->string.length,
> > > > >> +                                                   &value, &value_len);
> > > > >> +                    if (ACPI_FAILURE(status))
> > > > >> +                            break;
> > > > >> +
> > > > >> +                    /*
> > > > >> +                     * Report list of "PossibleValues" of size
> > > > >> +                     * "Size"
> > > > >> +                     *      ...
> > > > >> +                     *      "Size": 2,
> > > > >> +                     *      "PossibleValues": [
> > > > >> +                     *                      "Disable",
> > > > >> +                     *                      "Enable"]
> > > > >> +                     */
> > > > >> +                    if (i == (size - 1))
> > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > >> +                                                "%s\t\t\"%s\"\n", buf,
> > > > >> value);
> > > > >> +                    else
> > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > >> +                                                "%s\t\t\"%s\",\n", buf,
> > > > >> value);
> > > > >> +                    kfree(value);
> > > > >> +                    value = NULL;
> > > > >> +            }
> > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > >> +    }
> > > > >> +
> > > > >> +    if (type == HPWMI_ORDEREDLIST_TYPE) {
> > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
> > > > >> buf);
> > > > >> +            if (size <= 0)
> > > > >> +                    goto finish_ordered_list;
> > > > >> +
> > > > >> +            pobj = &(obj-
> > > > >>> package.elements[hp_wmi_elements_count[type]]);
> > > > >> +            status = convert_hexstr_to_str(&pobj->string.pointer,
> > > > >> +                                           pobj->string.length, &value,
> > > > >> &value_len);
> > > > >> +            if (ACPI_FAILURE(status))
> > > > >> +                    goto finish_ordered_list;
> > > > >> +
> > > > >> +            /*
> > > > >> +             * 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(&value, value_len, &tmpstr,
> > > > >> &tmp_len);
> > > > >> +            if (ACPI_FAILURE(status))
> > > > >> +                    goto finish_ordered_list;
> > > > >> +
> > > > >> +            part_tmp = tmpstr;
> > > > >> +            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);
> > > > >> +            }
> > > > >> +    }
> > > > >> +
> > > > >> +finish_ordered_list:
> > > > >> +    if (type == HPWMI_ORDEREDLIST_TYPE)
> > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > >> +
> > > > >> +    /*
> > > > >> +     * remove trailing comma
> > > > >> +     */
> > > > >> +    if (buf_size > 3)
> > > > >> +            buf[buf_size - 2] = ' ';
> > > > >> +
> > > > >> +    kfree(tmpstr);
> > > > >> +    kfree(value);
> > > > >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > > > >> +}
> > > > >> +
> > > > >> +static int append_buffer_elements_to_buffer(union acpi_object
> *obj,
> > > > >> +                                        char *buf, int alloc_size, enum
> > > > >> hp_wmi_data_type type)
> > > > >> +{
> > > > >> +    int buf_size;
> > > > >> +    int status;
> > > > >> +    char *str = NULL;
> > > > >> +    int i;
> > > > >> +    int j;
> > > > >> +    int integer;
> > > > >> +    int size = 0;
> > > > >> +
> > > > >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > > > >> +            return -EINVAL;
> > > > >> +
> > > > >> +    if (obj->type != ACPI_TYPE_BUFFER)
> > > > >> +            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]);
> > > > >> +
> > > > >> +    for (i = 0; i < 3; i++) {
> > > > >> +            status = get_string_from_buffer((u16 **)&obj-
> > > > >>> buffer.pointer, &str);
> > > > >> +            if (ACPI_SUCCESS(status)) {
> > > > >> +                    /*
> > > > >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > > > >> since
> > > > >> +                     * 'CurrentValue' is reported.
> > > > >> +                     */
> > > > >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > >> +                                                "%s\t\"%s\": \"%s\",\n",
> > > > >> +                                                buf,
> > > > >> +
> > > > >> hp_wmi_elements[type][i], str);
> > > > >> +            }
> > > > >> +            kfree(str);
> > > > >> +            str = NULL;
> > > > >> +
> > > > >> +    }
> > > > >> +
> > > > >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > > > >> +            if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
> > > > >> +                    status = get_string_from_buffer((u16 **)&obj-
> > > > >>> buffer.pointer, &str);
> > > > >> +                    if (ACPI_SUCCESS(status)) {
> > > > >> +                            /*
> > > > >> +                             * Report "CurrentValue" as "Value"
> > > > >> +                             */
> > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > >> +                                                "%s\t\"Value\": \"%s\",\n",
> > > > >> buf, str);
> > > > >> +                    }
> > > > >> +                    kfree(str);
> > > > >> +                    str = NULL;
> > > > >> +                    continue;
> > > > >> +
> > > > >> +            } else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
> > > > >> +                    /*
> > > > >> +                     * Report list of "SupportEncoding"
> > > > >> +                     *
> > > > >> +                     *      "SupportedEncoding": [
> > > > >> +                     *              "utf-16"
> > > > >> +                     *      ],
> > > > >> +                     *
> > > > >> +                     */
> > > > >> +
> > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > > > >> +                                        buf, hp_wmi_elements[type][i]);
> > > > >> +                    for (j = 0; j < size; j++) {
> > > > >> +                            status = get_string_from_buffer((u16
> > > > >> **)&obj->buffer.pointer, &str);
> > > > >> +                            if (ACPI_SUCCESS(status)) {
> > > > >> +                                    if (j == size - 1)
> > > > >> +                                            buf_size = snprintf(buf,
> > > > >> alloc_size,
> > > > >> +
> > > > >> "%s\t\t\"%s\"\n", buf, str);
> > > > >> +                                    else
> > > > >> +                                            buf_size = snprintf(buf,
> > > > >> alloc_size,
> > > > >> +
> > > > >> "%s\t\t\"%s\",\n", buf, str);
> > > > >> +                            }
> > > > >> +                            kfree(str);
> > > > >> +                            str = NULL;
> > > > >> +                    }
> > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > >> +                    continue;
> > > > >> +            }
> > > > >> +
> > > > >> +            size = 0;
> > > > >> +            status = get_integer_from_buffer((int **)&obj-
> > > > >>> buffer.pointer, &integer);
> > > > >> +            if (ACPI_SUCCESS(status)) {
> > > > >> +                    /*
> > > > >> +                     * Report "PrerequisiteSize" and "Size" values
> > > > >> +                     *      ...
> > > > >> +                     *      "PrerequisiteSize": 1,
> > > > >> +                     *      ...
> > > > >> +                     *      "Size": 2,
> > > > >> +                     *      ...
> > > > >> +                     */
> > > > >> +                    if (i == 7)
> > > > >> +                            size = integer;
> > > > >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > > > >> == 10)
> > > > >> +                            size = integer;
> > > > >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > > > >> 9)
> > > > >> +                            size = integer;
> > > > >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > > > >> 11)
> > > > >> +                            size = integer;
> > > > >> +
> > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > > > >> %d,\n", buf,
> > > > >> +                                        hp_wmi_elements[type][i],
> > > > >> integer);
> > > > >> +            }
> > > > >> +
> > > > >> +            if (size > 20)
> > > > >> +                    pr_warn("%s exceeded the maximum number of
> > > > >> elements supported or data may be malformed\n",
> > > > >> +                            hp_wmi_elements[type][i]);
> > > > >> +
> > > > >> +            if (ACPI_SUCCESS(status) && i == 7) {
> > > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > > >> "%s\t\"Prerequisites\": [\n", buf);
> > > > >> +                    for (j = 0; j < size; j++) {
> > > > >> +                            status = get_string_from_buffer((u16
> > > > >> **)&obj->buffer.pointer, &str);
> > > > >> +                            if (ACPI_SUCCESS(status)) {
> > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > >> "%s\t\t\"%s\"", buf, str);
> > > > >> +
> > > > >> +                                    if (j == size - 1)
> > > > >> +                                            buf_size = snprintf(buf,
> > > > >> alloc_size, "%s\n", buf);
> > > > >> +                                    else
> > > > >> +                                            buf_size = snprintf(buf,
> > > > >> alloc_size, "%s,\n", buf);
> > > > >> +
> > > > >> +                            }
> > > > >> +                            kfree(str);
> > > > >> +                            str = NULL;
> > > > >> +                    }
> > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > >> +            }
> > > > >> +    }
> > > > >> +
> > > > >> +    if (type == HPWMI_ENUMERATION_TYPE || type ==
> > > > >> HPWMI_ORDEREDLIST_TYPE) {
> > > > >> +            if (type == HPWMI_ENUMERATION_TYPE)
> > > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > > >> "%s\t\"PossibleValues\": [\n", buf);
> > > > >> +            else
> > > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > > >> "%s\t\"Elements\": [\n", buf);
> > > > >> +
> > > > >> +            for (i = 0; i < size; i++) {
> > > > >> +                    status = get_string_from_buffer((u16 **)&obj-
> > > > >>> buffer.pointer, &str);
> > > > >> +                    if (ACPI_SUCCESS(status)) {
> > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > >> "%s\t\t\"%s\"", buf, str);
> > > > >> +
> > > > >> +                            if (i == size - 1)
> > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > >> "%s\n", buf);
> > > > >> +                            else
> > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > >> "%s,\n", buf);
> > > > >> +
> > > > >> +                    }
> > > > >> +                    kfree(str);
> > > > >> +                    str = NULL;
> > > > >> +            }
> > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > >> +    }
> > > > >> +
> > > > >> +    /*
> > > > >> +     * remove trailing comma
> > > > >> +     */
> > > > >> +    if (buf_size > 3)
> > > > >> +            buf[buf_size - 2] = ' ';
> > > > >> +
> > > > >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > > > >> +}
> > > > >> +
> > > > >> +static int hp_bios_settings_free_buffer(void)
> > > > >> +{
> > > > >> +    mutex_lock(&buf_mutex);
> > > > >> +    kfree(hp_bios_settings_buffer);
> > > > >> +    settings_buffer_size = 0;
> > > > >> +    buf_alloc_size = 0;
> > > > >> +    mutex_unlock(&buf_mutex);
> > > > >> +
> > > > >> +    return 0;
> > > > >> +}
> > > > >> +
> > > > >> +static int hp_bios_settings_realloc_buffer(char **buf, int
> *buf_size,
> > > > >> +                                       int *alloc_size,
> > > > >> +                                       struct mutex *buf_mutex)
> > > > >> +{
> > > > >> +    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(buf_mutex);
> > > > >> +            new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
> > > > >> +            mutex_unlock(buf_mutex);
> > > > >> +            if (new_buf) {
> > > > >> +                    mutex_lock(buf_mutex);
> > > > >> +                    *buf = new_buf;
> > > > >> +                    *alloc_size = ksize(new_buf);
> > > > >> +                    mutex_unlock(buf_mutex);
> > > > >> +            } else {
> > > > >> +                    hp_bios_settings_free_buffer();
> > > > >> +                    ret = -ENOMEM;
> > > > >> +            }
> > > > >> +    }
> > > > >> +
> > > > >> +    return ret;
> > > > >> +}
> > > > >> +
> > > > >> +static int append_settings_to_buffer(char *guid, int type, char
> **buf,
> > > > >> +                                 int *buf_size, int *alloc_size,
> > > > >> +                                 struct mutex *buf_mutex)
> > > > >> +{
> > > > >> +    union acpi_object *obj = NULL;
> > > > >> +    int ret = 0;
> > > > >> +    int status = 0;
> > > > >> +    int instance = 0;
> > > > >> +
> > > > >> +    /*
> > > > >> +     * Query all the instances until to receive a AE_BAD_PARAMETER
> > > > >> +     */
> > > > >> +    do {
> > > > >> +            ret = hp_wmi_get_setting_object(guid, instance++, &obj);
> > > > >> +            if (ACPI_SUCCESS(ret) && obj != NULL) {
> > > > >> +                    status = 0;
> > > > >> +                    if (obj->type == ACPI_TYPE_PACKAGE) {
> > > > >> +                            mutex_lock(buf_mutex);
> > > > >> +                            status =
> > > > >> append_package_elements_to_buffer(obj,
> > > > >> +                                                    *buf, *alloc_size,
> > > > >> type);
> > > > >> +                            if (status > 0)
> > > > >> +                                    *buf_size = status;
> > > > >> +                            mutex_unlock(buf_mutex);
> > > > >> +
> > > > >> +                    } else if (obj->type == ACPI_TYPE_BUFFER) {
> > > > >> +                            mutex_lock(buf_mutex);
> > > > >> +                            status =
> > > > >> append_buffer_elements_to_buffer(obj,
> > > > >> +                                                    *buf, *alloc_size,
> > > > >> type);
> > > > >> +                            if (status > 0)
> > > > >> +                                    *buf_size = status;
> > > > >> +                            mutex_unlock(buf_mutex);
> > > > >> +
> > > > >> +                    } else
> > > > >> +                            pr_warn("The retrieved object type(%d) is
> > > > >> not supported yet\n",
> > > > >> +                                    obj->type);
> > > > >> +
> > > > >> +                    ret = hp_bios_settings_realloc_buffer(buf, buf_size,
> > > > >> alloc_size, buf_mutex);
> > > > >> +            }
> > > > >> +
> > > > >> +            kfree(obj);
> > > > >> +            obj = NULL;
> > > > >> +
> > > > >> +    } while (ACPI_SUCCESS(ret));
> > > > >> +
> > > > >> +    /*
> > > > >> +     * AE_BAD_PARAMETER means the loop ended by exhaustion
> > > > >> +     */
> > > > >> +    if (ret == AE_BAD_PARAMETER)
> > > > >> +            ret = 0;
> > > > >> +
> > > > >> +    return ret;
> > > > >> +}
> > > > >> +
> > > > >> +static int hp_bios_settings_fill_buffer(void)
> > > > >> +{
> > > > >> +    int status = 0;
> > > > >> +    int initial_buffer_size = 20 * PAGE_SIZE;
> > > > >> +
> > > > >> +    mutex_lock(&buf_mutex);
> > > > >> +    hp_bios_settings_buffer = kmalloc(initial_buffer_size,
> > > GFP_KERNEL);
> > > > >> +    mutex_unlock(&buf_mutex);
> > > > >> +    if (!hp_bios_settings_buffer)
> > > > >> +            return -ENOMEM;
> > > > >> +
> > > > >> +    mutex_lock(&buf_mutex);
> > > > >> +    buf_alloc_size = ksize(hp_bios_settings_buffer);
> > > > >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > > > >> +                                    buf_alloc_size, "[\n");
> > > > >> +    mutex_unlock(&buf_mutex);
> > > > >> +
> > > > >> +    status = append_settings_to_buffer(HPWMI_STRING_GUID,
> > > > >> +            HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
> > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > >> +    if (ACPI_FAILURE(status))
> > > > >> +            pr_err("error 0x%x occurred retrieving string instances\n",
> > > > >> status);
> > > > >> +
> > > > >> +    status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
> > > > >> +            HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
> > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > >> +    if (ACPI_FAILURE(status))
> > > > >> +            pr_err("error 0x%x occurred retrieving integer instances\n",
> > > > >> status);
> > > > >> +
> > > > >> +    status =
> > > append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
> > > > >> +            HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
> > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > >> +    if (ACPI_FAILURE(status))
> > > > >> +            pr_err("error 0x%x occurred retrieving enumeration
> > > > >> instances\n", status);
> > > > >> +
> > > > >> +    status =
> append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
> > > > >> +            HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
> > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > >> +    if (ACPI_FAILURE(status))
> > > > >> +            pr_err("error 0x%x occurred retrieving ordered list
> > > > >> instances\n", status);
> > > > >> +
> > > > >> +    status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
> > > > >> +            HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
> > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > >> +    if (ACPI_FAILURE(status))
> > > > >> +            pr_err("error 0x%x occurred retrieving password list
> > > > >> instances\n", status);
> > > > >> +
> > > > >> +    mutex_lock(&buf_mutex);
> > > > >> +    /*
> > > > >> +     * remove trailing comma
> > > > >> +     */
> > > > >> +    if (settings_buffer_size >= 3) {
> > > > >> +            if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
> > > > >> +                    hp_bios_settings_buffer[settings_buffer_size - 2] = '
> > > > >> ';
> > > > >> +    }
> > > > >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > > > >> +                                    buf_alloc_size, "%s]\n",
> > > > >> +                                    hp_bios_settings_buffer);
> > > > >> +    mutex_unlock(&buf_mutex);
> > > > >> +
> > > > >> +    return settings_buffer_size;
> > > > >> +}
> > > > >> +
> > > > >> +/*
> > > > >> + * sure_admin_settings_read - Return a formatted file with
> settings
> > > > >> + *                              and possible options read from BIOS
> > > > >> + *
> > > > >> + * @filp:  Pointer to file of settings read from BIOS
> > > > >> + * @kobj:  Pointer to a kernel object of things that show up as
> directory
> > > in
> > > > >> the sysfs filesystem.
> > > > >> + * @attr:  Pointer to list of read attributes
> > > > >> + * @buf:   Pointer to buffer
> > > > >> + * @off:   File current offset
> > > > >> + * @count: Buffer size
> > > > >> + *
> > > > >> + * Returns the count of unicode chars read if successful, otherwise
> > > > >> + *          -ENOMEM unable to allocate memory
> > > > >> + *          -EINVAL buffer not allocated or too small
> > > > >> + *
> > > > >> + */
> > > > >> +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 >= settings_buffer_size && settings_buffer_size > 0) {
> > > > >> +            hp_bios_settings_free_buffer();
> > > > >> +            return 0;
> > > > >> +    }
> > > > >> +
> > > > >> +    /* clear the buffer whenever the read starts from the first
> position
> > > > >> */
> > > > >> +    if (off == 0 && settings_buffer_size > 0)
> > > > >> +            hp_bios_settings_free_buffer();
> > > > >> +
> > > > >> +    if (settings_buffer_size == 0)
> > > > >> +            hp_bios_settings_fill_buffer();
> > > > >> +
> > > > >> +    mutex_lock(&buf_mutex);
> > > > >> +    ret = memory_read_from_buffer(buf, count, &off,
> > > > >> hp_bios_settings_buffer,
> > > > >> +                                  settings_buffer_size);
> > > > >> +    mutex_unlock(&buf_mutex);
> > > > >> +
> > > > >> +    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
> > > > >> + */
> > > > >> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
> > > > >> +{
> > > > >> +    int len = strlen(str);
> > > > >> +
> > > > >> +    /*
> > > > >> +     * Add null character when reading an empty string
> > > > >> +     */
> > > > >> +    if (len == 0) {
> > > > >> +            *p++ = 2;
> > > > >> +            *p++ = (u8)0x00;
> > > > >> +            return p;
> > > > >> +    }
> > > > >> +    *p++ = len * 2;
> > > > >> +    utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
> > > > >> +    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
> > > > >> + */
> > > > >> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32
> 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(HPWMI_SETBIOSSETTING_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;
> > > > >> +}
> > > > >> +
> > > > >> +/* Sure Admin Functions */
> > > > >> +
> > > > >> +#define UTF_PREFIX                  ((unsigned char *)"<utf-16/>")
> > > > >> +#define BEAM_PREFIX                 ((unsigned char
> > > > >> *)"<BEAM/>")
> > > > >> +
> > > > >> +/*
> > > > >> + * sure_admin_settings_write - Write the contents of a formatted
> file
> > > > >> + *                               with settings and performs the logic
> > > > >> + *                               to change any settings in BIOS.
> > > > >> + *
> > > > >> + * @filp:  Pointer to file of settings to be written to BIOS
> > > > >> + * @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 write operation
> > > > >> + * @buf:   Pointer to buffer
> > > > >> + * @off:   File current offset
> > > > >> + * @count: Buffer size
> > > > >> + *
> > > > >> + *
> > > > >> + * Returns the count of unicode characters written to BIOS if
> > > successful,
> > > > >> otherwise
> > > > >> + *          -ENOMEM unable to allocate memory
> > > > >> + *          -EINVAL buffer not allocated or too small
> > > > >> + *
> > > > >> + */
> > > > >> +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;
> > > > >> +    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 out_free;
> > > > >> +    }
> > > > >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > > >> +    part = strsep(&buf, ",");
> > > > >> +    if (!part) {
> > > > >> +            status = -EINVAL;
> > > > >> +            goto out_free;
> > > > >> +    }
> > > > >> +
> > > > >> +    /* Add extra buffer space when encountering an empty string */
> > > > >> +    if (!strlen(part))
> > > > >> +            buffer_size += sizeof(unsigned short);
> > > > >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > > >> +    part = strsep(&buf, ",");
> > > > >> +    if (!part) {
> > > > >> +            status = -EINVAL;
> > > > >> +            goto out_free;
> > > > >> +    }
> > > > >> +    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 out_free;
> > > > >> +
> > > > >> +            tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > > >> +            kfree(part);
> > > > >> +    }
> > > > >> +
> > > > >> +    part = strsep(&buf, ",");
> > > > >> +    if (part) {
> > > > >> +            status = -EINVAL;
> > > > >> +            goto out_free;
> > > > >> +    }
> > > > >> +    status = hp_wmi_set_bios_setting(buffer, buffer_size);
> > > > >> +    if (ACPI_FAILURE(status))
> > > > >> +            status = -EINVAL;
> > > > >> +
> > > > >> +out_free:
> > > > >> +    kfree(buffer);
> > > > >> +    if (ACPI_SUCCESS(status))
> > > > >> +            return count;
> > > > >> +    return status;
> > > > >> +}
> > > > >> +
> > > > >> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
> > > > >> +
> > > > >> +static struct bin_attribute *sure_admin_binattrs[] = {
> > > > >> +    &sure_admin_settings,
> > > > >> +    NULL,
> > > > >> +};
> > > > >> +
> > > > >> +static const struct attribute_group sure_admin_group = {
> > > > >> +    .name = "sure_admin",
> > > > >> +    .bin_attrs = sure_admin_binattrs,
> > > > >> +};
> > > > >> +
> > > > >>  static DEVICE_ATTR_RO(display);
> > > > >>  static DEVICE_ATTR_RO(hddtemp);
> > > > >>  static DEVICE_ATTR_RW(als);
> > > > >> @@ -1050,6 +2026,7 @@ static const struct attribute_group
> > > > >> *hp_wmi_groups[] = {
> > > > >>      &hp_wmi_group,
> > > > >>      &spm_group,
> > > > >>      &sure_start_group,
> > > > >> +    &sure_admin_group,
> > > > >>      NULL,
> > > > >>  };
> > > > >>
> > > > >> --
> > > > >> 2.25.1
> > > >

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-07 19:17             ` Limonciello, Mario
@ 2022-04-07 20:57               ` Jorge Lopez
  0 siblings, 0 replies; 25+ messages in thread
From: Jorge Lopez @ 2022-04-07 20:57 UTC (permalink / raw)
  To: Limonciello, Mario; +Cc: Hans de Goede, platform-driver-x86

On Thu, Apr 7, 2022 at 2:17 PM Limonciello, Mario
<Mario.Limonciello@amd.com> wrote:
>
> [Public]
>
> > -----Original Message-----
> > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > Sent: Thursday, April 7, 2022 08:45
> > To: Limonciello, Mario <Mario.Limonciello@amd.com>
> > Cc: Hans de Goede <hdegoede@redhat.com>; platform-driver-
> > x86@vger.kernel.org
> > Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> >
> > Hans, Mario,
> >
> > The code links make references to code that implements the new
> > interfaces but there’s
> > still code in the kernel that uses the old ones.  I do agree we should
> > be forward looking
> > and want to be good participants in the kernel development, but can’t
> > let our immediate
> > business needs be impacted with opportunities to enhance the driver to
> > take advantage
> > of the latest kernel features.
> >
>
> Keep in mind that from an upstream kernel perspective this driver is "new".
> There is no requirements from the upstream perspective to
> keep your old interfaces in place from when it was out of tree.
>
> Requirements like this start when the driver is in tree.
> https://www.kernel.org/doc/html/latest/admin-guide/abi-stable.html
>
Thank you for the link and explanation regarding the kernel
perspective for the state of the driver.

> > Rewriting those security features will impact customer business
> > datelines requiring
> > HP to provide private releases as the kernel version changes.   The
> > requested changes
> > will impact products in the market and HP ability to help customers to
> > migrate to Linux
> > from Windows products.
> >
> > It is because of the immediate business needs, avoiding impacting our
> > customers/products,
> > and rewriting  enhancements to the driver that I need to propose an
> > interim solution.
>
> Right, get it upstream and it's less work, of course 😊

Indeed that is our goal.
>
> >
> > My proposal is to introduce a read/write value accessible in the user
> > space to control how
> > the driver reports and handles BIOS settings and values.  The new
> > configuration features
> > will be gradually disabled  as they are converted to use the standardized API.
> > It is like the configuration flag used to overcome the tablet detection
> > problem
> > introduced in the past.   The changes solely affect the HP WMI driver.
> > This option will help us
> > move forward for this release and give us time to make the necessary
> > changes to both
> > the driver and support applications.
> >
> > Please let me know if this is a viable interim solution.
> >
> > If it is not possible, I need to ask where the actual written
> > requirement is found so I can
> > include them in the business justification for changes and release
> > delays to management.
> >
>
> From an upstream subsystem maintainer perspective Hans will want you to do
> everything you can to get it correct the first time.  If you don't; what impetus do
> you have to fix it later?  You would have an interface that "works" and meets
> your business needs but no guarantee it ever would standardize.
>
> I do get where you're coming from though and you obviously have customers that
> value your existing interface.  So let me entertain this thought process a little bit,
> Hans feel free to disagree with me.
>
> If there is a compatibility mode to let it work similar to how it worked "out
> of tree" I don't think this should be something that you turn on/off dynamically
> at runtime.  It is a lot of code, you introduce complexity of sysfs files coming and
> going and racing with userspace and worse this eventually this would all be dead code.
> I think it's better to have a KConfig option that would enable this dead code.
>
> Also I think a better place for such a file that we would all know is going to eventually
> go away is debugfs.  There is no guarantee for files and interfaces in debugfs to stay
> around.  You can point applications at using the sysfs file today with your out of tree
> driver there until the standardized interface support is made available.
> Something like CONFIG_HP_WMI_DEBUGFS_SETTINGS.  Then you can keep it in there
> as long as you want, distros and users can decide if they want to use it.  When you're
> confident enough that all the applications that previously used the out of tree module
> are migrated to the modern interface tear away that debugfs option as a future patch.
>

I agree with both your comments and Hans request. .  Hans is correct
in requesting the driver to use the latest standards and be correct
the first time,  I am working with the security architect on a
timeline to made the requested changes and submit a new review.
Is there are a site where the kernel schedules are published?  This
information will help us  align better in the future and setup the
correct speciation.


> >
> > Regards,
> >
> > Jorge Lopez
> >
> >
> > On Tue, Apr 5, 2022 at 12:13 PM Limonciello, Mario
> > <Mario.Limonciello@amd.com> wrote:
> > >
> > > [Public]
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > > Sent: Tuesday, April 5, 2022 11:52
> > > > To: Hans de Goede <hdegoede@redhat.com>
> > > > Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-driver-
> > > > x86@vger.kernel.org
> > > > Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> > > >
> > > > Hi Hans,
> > > >
> > > > On Tue, Apr 5, 2022 at 6:54 AM Hans de Goede
> > <hdegoede@redhat.com>
> > > > wrote:
> > > > >
> > > > > Hi,
> > > > >
> > > > > On 4/4/22 23:59, Limonciello, Mario wrote:
> > > > > > [Public]
> > > > > >
> > > > > >
> > > > > >
> > > > > >> -----Original Message-----
> > > > > >> From: Jorge Lopez <jorgealtxwork@gmail.com>
> > > > > >> Sent: Monday, April 4, 2022 15:36
> > > > > >> To: platform-driver-x86@vger.kernel.org
> > > > > >> Subject: [PATCH v1 5/6] Sure Admin Security Feature
> > > > > >>
> > > > > >> 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. Behind the scenes, Sure Admin uses Secure
> > > > Platform
> > > > > >> Management (SPM) and WMI
> > > > > >>
> > > > > >> 'settings' is a file associated with Sure Admin. BIOS settings can be
> > > > > >> read or written through the Sure Admin settings file in sysfs
> > > > > >>
> > > > > >>      /sys/devices/platform/hp-wmi/sure_admin/settings
> > > > > >>
> > > > > >> 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"
> > > > > >>              ]
> > > > > >>      }
> > > > > >>
> > > > > >
> > > > > > This sounds like it has re-invented /sys/class/firmware-attributes.
> > > > > >
> > > > > > Shouldn't you adopt that API?
> > > > >
> > > > > I fully agree. Jorge as I already indicated in our off-list
> > > > > conversation when you initially started working on this
> > > > > feature, we already have a standardized API for querying/changing
> > > > > BIOS settings from within Linux:
> > > > >
> > > >
> > > > I agree that changing the BIOS settings from within Linux could
> > > > utilize the new methodology,  I will need to look closely at the
> > > > requirements before I can proceed to make the changes.
> > > > Keep in mind authentication of the values is done by BIOS.  No Linux
> > > > process validates any data name, value, or auth token; only BIOS.  All
> > > > data written to the sysfs file is not validated, it is just forward to
> > > > BIOS.  See spm_kek_store and spm_sk_store functions.
> > >
> > > That's fine, and it's a safer design to have BIOS validate it.
> > >
> > > > One point I must make clear when updating BIOS settings.  any  NOT
> > > > read-only BIOS settings can be changed by the application at any time.
> > > >    This list of settings changes from one system to another.
> > >
> > > Right.
> > >
> > > >
> > > > I am in disagreement with reading the settings.  hp-wmi does not read
> > > > one value at a time. It reads all values exposed by BIOS.  See
> > > > attached sample output.
> > >
> > > The settings can all be read at initialization time for the driver and cached
> > > then.
> > >
> > > > The method for how all BIOS settings are reported needs to match the
> > > > method how Windows products do it.  It is a requirement to start
> > > > migrating customers from Windows to Linux while minimizing how BIOS
> > > > data is reported.
> > >
> > > Because we have a standardized API in Linux for this, I think it's best to
> > abstract
> > > this behind a userspace application/script.  If they expect to see it in the
> > format you
> > > showed, the userspace application can take the data from Linux and
> > package it that
> > > way.
> > >
> > > You'll have richer libraries and languages and tools to work from when
> > doing this too.
> > > It should make it a lot less painful.
> > >
> > > >
> > > > I will investigate the new API and bring it to the team's attention.
> > > >
> > > > >
> > > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> > b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> > served=0
> > > >
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > > 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> > > >
> > attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> > > >
> > f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> > > >
> > 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> > > >
> > C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> > > >
> > &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> > > > D&amp;reserved=0
> > > > >
> > > > > and any new code (such as this patch) which implements BIOS
> > > > > setting changing MUST follow this standardized API (extending
> > > > > it where necessary).
> > > > >
> > > > > I'm sorry but this patch is not acceptable in its current form,
> > > > > it needs to be *completely rewritten* to implement:
> > > > >
> > > > >
> > > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> > b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> > served=0
> > > >
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > > 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> > > >
> > attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> > > >
> > f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> > > >
> > 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> > > >
> > C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> > > >
> > &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> > > > D&amp;reserved=0
> > > > >
> > > > > See:
> > > > >
> > > > >
> > > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> > b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> > served=0
> > > >
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > > 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fdell%2Fdell-wmi-
> > > >
> > sysman&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8f
> > > >
> > ea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> > > >
> > 7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> > > >
> > wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> > > >
> > mp;sdata=z5jmH7ECYBeLcndQ2vfHaUuyE04Eaf1Lymh6BjnyJ%2Fk%3D&amp;r
> > > > eserved=0
> > > > >
> > > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> > b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> > served=0
> > > >
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > > 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fthink-
> > > >
> > lmi.c&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea
> > > >
> > 104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > > >
> > 0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > > >
> > AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > > >
> > sdata=5n6w9LEB2iWpj1cOQP6Ngz94AqP1Bu4vu8T0EdN%2FThU%3D&amp;re
> > > > served=0
> > > > >
> > > > > for example code / for 2 drivers from other vendors already
> > > > > implementing this.
> > > > >
> > > > > The same applies to the:
> > > > >
> > > > > "[PATCH v1 3/6] Secure Platform Management Security Feature"
> > > > >
> > > > > this needs to be implemented as
> > > > > a /sys/class/firmware-attributes/*/authentication/
> > > > > authentication method, see for example these Lenovo specific
> > > > > addition to the /sys/class/firmware-attributes/*/authentication/
> > > > > userspace API for similar functionality on Lenovo Think* devices:
> > > > >
> > > > >
> > > >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> > %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cfbde7b4dbc
> > b44386a58408da189cc91d%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > 0%7C637849358937251820%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > sdata=oZGg9YneMO6luJPU0FN8CsxfBzfh9zizgm1EM%2BLCIdM%3D&amp;re
> > served=0
> > > >
> > ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > > >
> > 2Fcommit%2F%3Fid%3D06384573a3e8335ac6797577e545c33dbf91b490&amp;
> > > >
> > data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea1040342827
> > > >
> > 08da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C63784
> > > >
> > 7743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLC
> > > >
> > JQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=eldS
> > > >
> > 4H3Z%2BAyL%2FG%2FO9W9rDGC37yh5sGgtUhpKdUAoSmA%3D&amp;reser
> > > > ved=0
> > > > >
> > > > > I'll merge patches 1-2 sometime this week since those are
> > > > > fine and it will be good to have those "out of the way",
> > > > > but the rest of the series will need to be rewritten
> > > > > taken the above comments into account.
> > > >
> > > > v1-0003-Sure-Start-Security-Feature.patch  reports the number of audit
> > > > logs available and reports them when read.    it does not read/write
> > > > BIOS settings hence it does not fall within the same category as
> > > > patches v1-0002-Secure-Platform-Management-Security-Feature.patch
> > and
> > > > v1-0004-Sure-Admin-Security-Feature.patch
> > > > Do you agree?
> > > >
> > > > >
> > > > > Regards,
> > > > >
> > > > > Hans
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > > >
> > > > > >> This feature requires "Update hp_wmi_group to simplify feature
> > > > > >> addition" patch.
> > > > > >>
> > > > > >> All changes were validated on a HP ZBook Workstation,
> > > > > >> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> > > > > >>
> > > > > >> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> > > > > >>
> > > > > >> ---
> > > > > >> Based on the latest platform-drivers-x86.git/for-next
> > > > > >> ---
> > > > > >>  drivers/platform/x86/hp-wmi.c | 977
> > > > > >> ++++++++++++++++++++++++++++++++++
> > > > > >>  1 file changed, 977 insertions(+)
> > > > > >>
> > > > > >> diff --git a/drivers/platform/x86/hp-wmi.c
> > b/drivers/platform/x86/hp-
> > > > wmi.c
> > > > > >> index 918e3eaf1b67..b72ca18b77a6 100644
> > > > > >> --- a/drivers/platform/x86/hp-wmi.c
> > > > > >> +++ b/drivers/platform/x86/hp-wmi.c
> > > > > >> @@ -27,6 +27,7 @@
> > > > > >>  #include <linux/rfkill.h>
> > > > > >>  #include <linux/string.h>
> > > > > >>  #include <linux/dmi.h>
> > > > > >> +#include <linux/nls.h>
> > > > > >>
> > > > > >>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
> > > > > >>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
> > > > > >> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-
> > BE91-
> > > > > >> 3D44E2C707E4");
> > > > > >>
> > > > > >>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-
> > > > ACCDC67EF61C"
> > > > > >>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-
> > > > 3D44E2C707E4"
> > > > > >> +
> > > > > >>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
> > > > > >>
> > > > > >> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-
> > > > 6A1B8106F83C"
> > > > > >> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
> > > > > >> E293ADB9BF05"
> > > > > >> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-
> > B8FE-
> > > > > >> 4A3C09E75133"
> > > > > >> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
> > > > > >> 7045CB4DA745"
> > > > > >> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
> > > > > >> 015176049E2D"
> > > > > >> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-
> > 951D-
> > > > > >> C7CB9B4B8D5E"
> > > > > >> +
> > > > > >>  /* DMI board names of devices that should use the omen specific
> > path
> > > > for
> > > > > >>   * thermal profiles.
> > > > > >>   * This was obtained by taking a look in the windows omen
> > command
> > > > center
> > > > > >> @@ -1025,6 +1034,973 @@ static const struct attribute_group
> > > > > >> sure_start_group = {
> > > > > >>      .attrs = sure_start_attrs,
> > > > > >>  };
> > > > > >>
> > > > > >> +
> > > > > >> +static 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;
> > > > > >> +    int  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));
> > > > > >> +            ret = kstrtoint(tmp, 16, &ch);
> > > > > >> +            if (ret) {
> > > > > >> +                    new_len = 0;
> > > > > >> +                    break;
> > > > > >> +            }
> > > > > >> +
> > > > > >> +            if (ch == '\\')
> > > > > >> +                    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;
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    if (ret)
> > > > > >> +            kfree(new_str);
> > > > > >> +    return ret;
> > > > > >> +}
> > > > > >> +
> > > > > >> +/*
> > > > > >> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and
> > > > instance
> > > > > >> + *
> > > > > >> + * @guid:   GUID associated with the ACPI list of managed objects
> > > > > >> + * @instance:       Instance index to query on the ACPI list
> > > > > >> + * @obj:    The output ACPI object of type ACPI_TYPE_PACKAGE
> > > > > >> + *          or ACPI_TYPE_BUFFER (freed by the callee)
> > > > > >> + *
> > > > > >> + * Returns  zero on success.  Otherwise,an error inherited from
> > > > > >> + *          wmi_query_block(). It returns a obj by parameter if
> > > > > >> + *          the query returned object of type buffer or package,
> > > > > >> + *          otherwise, a null obj is returned.
> > > > > >> + *
> > > > > >> + * Note: obj should be freed by the callee once it is finished
> > working
> > > > with it
> > > > > >> + */
> > > > > >> +static int hp_wmi_get_setting_object(char *guid, int instance,
> > > > > >> +                            union acpi_object **obj)
> > > > > >> +{
> > > > > >> +    struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER,
> > NULL
> > > > > >> };
> > > > > >> +    union acpi_object *tmp = NULL;
> > > > > >> +    int ret;
> > > > > >> +
> > > > > >> +    ret = wmi_query_block(guid, instance, &output);
> > > > > >> +    if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
> > > > > >> +            tmp = output.pointer;
> > > > > >> +            if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
> > > > > >> ACPI_TYPE_PACKAGE)
> > > > > >> +                    *obj = output.pointer;
> > > > > >> +            else {
> > > > > >> +                    kfree(tmp);
> > > > > >> +                    *obj = NULL;
> > > > > >> +            }
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    return ret;
> > > > > >> +}
> > > > > >> +
> > > > > >> +
> > > > > >> +static 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;
> > > > > >> +
> > > > > >> +    if (size == 0)
> > > > > >> +            goto cleanup_exit;
> > > > > >> +
> > > > > >> +    for (i = 0; i < size; i++)
> > > > > >> +            if (ptr[i] == '\\')
> > > > > >> +                    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);
> > > > > >> +
> > > > > >> +    if (escape == 0) {
> > > > > >> +            ptr += (ptrlen / 2);
> > > > > >> +            goto cleanup_exit;
> > > > > >> +    }
> > > > > >> +    /*
> > > > > >> +     * Convert escape characters only when found
> > > > > >> +     */
> > > > > >> +    for (i = 0; i < size; i++) {
> > > > > >> +            if (*ptr == '\\')
> > > > > >> +                    output[i++] = '\\';
> > > > > >> +            output[i] = *ptr;
> > > > > >> +            ptr++;
> > > > > >> +    }
> > > > > >> +
> > > > > >> +cleanup_exit:
> > > > > >> +    *buffer = ptr;
> > > > > >> +    return 0;
> > > > > >> +}
> > > > > >> +
> > > > > >> +static int get_integer_from_buffer(int **buffer, int *integer)
> > > > > >> +{
> > > > > >> +    int *ptr = PTR_ALIGN(*buffer, 4);
> > > > > >> +    *integer = *(ptr++);
> > > > > >> +    *buffer = ptr;
> > > > > >> +    return 0;
> > > > > >> +}
> > > > > >> +
> > > > > >> +
> > > > > >> +// Sure Admin functions
> > > > > >> +enum hp_wmi_data_type {
> > > > > >> +    HPWMI_STRING_TYPE,
> > > > > >> +    HPWMI_INTEGER_TYPE,
> > > > > >> +    HPWMI_ENUMERATION_TYPE,
> > > > > >> +    HPWMI_ORDEREDLIST_TYPE,
> > > > > >> +    HPWMI_PASSWORD_TYPE,
> > > > > >> +};
> > > > > >> +
> > > > > >> +#define HP_WMI_COMMON_ELEMENTS      \
> > > > > >> +    "Name", \
> > > > > >> +    "Value",        \
> > > > > >> +    "Path", \
> > > > > >> +    "IsReadOnly",   \
> > > > > >> +    "DisplayInUI",  \
> > > > > >> +    "RequiresPhysicalPresence",     \
> > > > > >> +    "Sequence",     \
> > > > > >> +    "PrerequisiteSize",     \
> > > > > >> +    "SecurityLevel"
> > > > > >> +
> > > > > >> +const char *hp_wmi_string_elements[] = {
> > > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > > >> +    "MinLength",
> > > > > >> +    "MaxLength"
> > > > > >> +};
> > > > > >> +
> > > > > >> +const char *hp_wmi_integer_elements[] = {
> > > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > > >> +    "LowerBound",
> > > > > >> +    "UpperBound",
> > > > > >> +    "IntValue"
> > > > > >> +};
> > > > > >> +
> > > > > >> +const char *hp_wmi_enumeration_elements[] = {
> > > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > > >> +    "CurrentValue",
> > > > > >> +    "Size"
> > > > > >> +};
> > > > > >> +
> > > > > >> +const char *hp_wmi_orderedlist_elements[] = {
> > > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > > >> +    "Size"
> > > > > >> +};
> > > > > >> +
> > > > > >> +const char *hp_wmi_password_elements[] = {
> > > > > >> +    HP_WMI_COMMON_ELEMENTS,
> > > > > >> +    "MinLength",
> > > > > >> +    "MaxLength",
> > > > > >> +    "Size",
> > > > > >> +    "SupportedEncoding",
> > > > > >> +    "IsSet"
> > > > > >> +};
> > > > > >> +
> > > > > >> +const char **hp_wmi_elements[] = {
> > > > > >> +    hp_wmi_string_elements,
> > > > > >> +    hp_wmi_integer_elements,
> > > > > >> +    hp_wmi_enumeration_elements,
> > > > > >> +    hp_wmi_orderedlist_elements,
> > > > > >> +    hp_wmi_password_elements
> > > > > >> +};
> > > > > >> +
> > > > > >> +const int hp_wmi_elements_count[] = {
> > > > > >> +    ARRAY_SIZE(hp_wmi_string_elements),
> > > > > >> +    ARRAY_SIZE(hp_wmi_integer_elements),
> > > > > >> +    ARRAY_SIZE(hp_wmi_enumeration_elements),
> > > > > >> +    ARRAY_SIZE(hp_wmi_orderedlist_elements),
> > > > > >> +    ARRAY_SIZE(hp_wmi_password_elements)
> > > > > >> +};
> > > > > >> +
> > > > > >> +const char *hp_wmi_classes[] = {
> > > > > >> +    "HPBIOS_BIOSString",
> > > > > >> +    "HPBIOS_BIOSInteger",
> > > > > >> +    "HPBIOS_BIOSEnumeration",
> > > > > >> +    "HPBIOS_BIOSOrderedList",
> > > > > >> +    "HPBIOS_BIOSPassword"
> > > > > >> +};
> > > > > >> +
> > > > > >> +static DEFINE_MUTEX(buf_mutex);
> > > > > >> +static int settings_buffer_size;
> > > > > >> +static int buf_alloc_size;
> > > > > >> +static char *hp_bios_settings_buffer;
> > > > > >> +
> > > > > >> +
> > > > > >> +static int append_package_elements_to_buffer(union acpi_object
> > > > *obj,
> > > > > >> +                                         char *buf, int alloc_size, enum
> > > > > >> hp_wmi_data_type type)
> > > > > >> +{
> > > > > >> +    int i;
> > > > > >> +    union acpi_object *pobj = NULL;
> > > > > >> +    char *value = NULL;
> > > > > >> +    int value_len;
> > > > > >> +    char *tmpstr = NULL;
> > > > > >> +    char *part_tmp = NULL;
> > > > > >> +    int tmp_len = 0;
> > > > > >> +    char *part = NULL;
> > > > > >> +    int status = 0;
> > > > > >> +    int size = 0;
> > > > > >> +    int buf_size;
> > > > > >> +
> > > > > >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > > > > >> +            return -EINVAL;
> > > > > >> +
> > > > > >> +    if (obj->type != ACPI_TYPE_PACKAGE)
> > > > > >> +            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]);
> > > > > >> +
> > > > > >> +    for (i = 0; i < 3; i++) {
> > > > > >> +            pobj = &(obj->package.elements[i]);
> > > > > >> +            if (pobj->type == ACPI_TYPE_STRING) {
> > > > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > > > >>> string.pointer,
> > > > > >> +                                                   pobj->string.length,
> > > > > >> &value, &value_len);
> > > > > >> +                    if (ACPI_FAILURE(status))
> > > > > >> +                            continue;
> > > > > >> +                    /*
> > > > > >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > > > > >> since
> > > > > >> +                     * 'CurrentValue' is reported.
> > > > > >> +                     */
> > > > > >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > > >> +                                                "%s\t\"%s\": \"%s\",\n",
> > > > > >> +                                                buf,
> > > > > >> +
> > > > > >> hp_wmi_elements[type][i], value);
> > > > > >> +
> > > > > >> +            }
> > > > > >> +            kfree(value);
> > > > > >> +            value = NULL;
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > > > > >> +            pobj = &(obj->package.elements[i]);
> > > > > >> +
> > > > > >> +            if (type == HPWMI_ENUMERATION_TYPE &&
> > > > > >> +                i == 9 &&
> > > > > >> +                pobj->type == ACPI_TYPE_STRING) {
> > > > > >> +                    /*
> > > > > >> +                     * Report "CurrentValue" as "Value"
> > > > > >> +                     */
> > > > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > > > >>> string.pointer,
> > > > > >> +                                                   pobj->string.length,
> > > > > >> +                                                   &value, &value_len);
> > > > > >> +                    if (ACPI_FAILURE(status))
> > > > > >> +                            continue;
> > > > > >> +
> > > > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > > > >> +                                        "%s\t\"Value\": \"%s\",\n",
> > > > > >> +                                        buf, value);
> > > > > >> +                    kfree(value);
> > > > > >> +                    value = NULL;
> > > > > >> +
> > > > > >> +            } else if (type == HPWMI_PASSWORD_TYPE &&
> > > > > >> +                       i == 12 &&
> > > > > >> +                       pobj->type == ACPI_TYPE_STRING) {
> > > > > >> +                    /*
> > > > > >> +                     * Report list of "SupportEncoding"
> > > > > >> +                     *
> > > > > >> +                     *      "SupportedEncoding": [
> > > > > >> +                     *              "utf-16"
> > > > > >> +                     *      ],
> > > > > >> +                     *
> > > > > >> +                     */
> > > > > >> +
> > > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > > > > >> +                                        buf, hp_wmi_elements[type][i]);
> > > > > >> +                    while (size--) {
> > > > > >> +                            pobj = &(obj->package.elements[i]);
> > > > > >> +                            status = convert_hexstr_to_str(&pobj-
> > > > > >>> string.pointer,
> > > > > >> +                                                           pobj-
> > > > > >>> string.length,
> > > > > >> +                                                           &value,
> > > > > >> &value_len);
> > > > > >> +                            if (ACPI_FAILURE(status))
> > > > > >> +                                    continue;
> > > > > >> +
> > > > > >> +                            if (size) {
> > > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > > >> +                                                        "%s\t\t\"%s\",\n",
> > > > > >> buf, value);
> > > > > >> +                                    i++;
> > > > > >> +                            } else
> > > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > > >> +                                                        "%s\t\t\"%s\"\n",
> > > > > >> buf, value);
> > > > > >> +
> > > > > >> +                            kfree(value);
> > > > > >> +                            value = NULL;
> > > > > >> +
> > > > > >> +                    }
> > > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > > >> +                    continue;
> > > > > >> +
> > > > > >> +            } else if (pobj->type == ACPI_TYPE_INTEGER) {
> > > > > >> +                    /*
> > > > > >> +                     * Report "PrerequisiteSize" and "Size" values
> > > > > >> +                     *      ...
> > > > > >> +                     *      "PrerequisiteSize": 1,
> > > > > >> +                     *      ...
> > > > > >> +                     *      "Size": 2,
> > > > > >> +                     *      ...
> > > > > >> +                     */
> > > > > >> +                    if (i == 7)
> > > > > >> +                            size = pobj->integer.value;
> > > > > >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > > > > >> 9)
> > > > > >> +                            size = pobj->integer.value;
> > > > > >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > > > > >> == 10)
> > > > > >> +                            size = pobj->integer.value;
> > > > > >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > > > > >> 11)
> > > > > >> +                            size = pobj->integer.value;
> > > > > >> +
> > > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > > > > >> %lld,\n", buf,
> > > > > >> +                                        hp_wmi_elements[type][i], pobj-
> > > > > >>> integer.value);
> > > > > >> +            }
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    if (type == HPWMI_ENUMERATION_TYPE) {
> > > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
> > > > > >> [\n", buf);
> > > > > >> +            for (i = 0; i < size; i++) {
> > > > > >> +                    pobj = &(obj->package.elements[i +
> > > > > >> hp_wmi_elements_count[type]]);
> > > > > >> +
> > > > > >> +                    status = convert_hexstr_to_str(&pobj-
> > > > > >>> string.pointer,
> > > > > >> +                                                   pobj->string.length,
> > > > > >> +                                                   &value, &value_len);
> > > > > >> +                    if (ACPI_FAILURE(status))
> > > > > >> +                            break;
> > > > > >> +
> > > > > >> +                    /*
> > > > > >> +                     * Report list of "PossibleValues" of size
> > > > > >> +                     * "Size"
> > > > > >> +                     *      ...
> > > > > >> +                     *      "Size": 2,
> > > > > >> +                     *      "PossibleValues": [
> > > > > >> +                     *                      "Disable",
> > > > > >> +                     *                      "Enable"]
> > > > > >> +                     */
> > > > > >> +                    if (i == (size - 1))
> > > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > > >> +                                                "%s\t\t\"%s\"\n", buf,
> > > > > >> value);
> > > > > >> +                    else
> > > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > > >> +                                                "%s\t\t\"%s\",\n", buf,
> > > > > >> value);
> > > > > >> +                    kfree(value);
> > > > > >> +                    value = NULL;
> > > > > >> +            }
> > > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    if (type == HPWMI_ORDEREDLIST_TYPE) {
> > > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
> > > > > >> buf);
> > > > > >> +            if (size <= 0)
> > > > > >> +                    goto finish_ordered_list;
> > > > > >> +
> > > > > >> +            pobj = &(obj-
> > > > > >>> package.elements[hp_wmi_elements_count[type]]);
> > > > > >> +            status = convert_hexstr_to_str(&pobj->string.pointer,
> > > > > >> +                                           pobj->string.length, &value,
> > > > > >> &value_len);
> > > > > >> +            if (ACPI_FAILURE(status))
> > > > > >> +                    goto finish_ordered_list;
> > > > > >> +
> > > > > >> +            /*
> > > > > >> +             * 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(&value, value_len, &tmpstr,
> > > > > >> &tmp_len);
> > > > > >> +            if (ACPI_FAILURE(status))
> > > > > >> +                    goto finish_ordered_list;
> > > > > >> +
> > > > > >> +            part_tmp = tmpstr;
> > > > > >> +            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);
> > > > > >> +            }
> > > > > >> +    }
> > > > > >> +
> > > > > >> +finish_ordered_list:
> > > > > >> +    if (type == HPWMI_ORDEREDLIST_TYPE)
> > > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > > >> +
> > > > > >> +    /*
> > > > > >> +     * remove trailing comma
> > > > > >> +     */
> > > > > >> +    if (buf_size > 3)
> > > > > >> +            buf[buf_size - 2] = ' ';
> > > > > >> +
> > > > > >> +    kfree(tmpstr);
> > > > > >> +    kfree(value);
> > > > > >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > > > > >> +}
> > > > > >> +
> > > > > >> +static int append_buffer_elements_to_buffer(union acpi_object
> > *obj,
> > > > > >> +                                        char *buf, int alloc_size, enum
> > > > > >> hp_wmi_data_type type)
> > > > > >> +{
> > > > > >> +    int buf_size;
> > > > > >> +    int status;
> > > > > >> +    char *str = NULL;
> > > > > >> +    int i;
> > > > > >> +    int j;
> > > > > >> +    int integer;
> > > > > >> +    int size = 0;
> > > > > >> +
> > > > > >> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > > > > >> +            return -EINVAL;
> > > > > >> +
> > > > > >> +    if (obj->type != ACPI_TYPE_BUFFER)
> > > > > >> +            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]);
> > > > > >> +
> > > > > >> +    for (i = 0; i < 3; i++) {
> > > > > >> +            status = get_string_from_buffer((u16 **)&obj-
> > > > > >>> buffer.pointer, &str);
> > > > > >> +            if (ACPI_SUCCESS(status)) {
> > > > > >> +                    /*
> > > > > >> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > > > > >> since
> > > > > >> +                     * 'CurrentValue' is reported.
> > > > > >> +                     */
> > > > > >> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > > >> +                                                "%s\t\"%s\": \"%s\",\n",
> > > > > >> +                                                buf,
> > > > > >> +
> > > > > >> hp_wmi_elements[type][i], str);
> > > > > >> +            }
> > > > > >> +            kfree(str);
> > > > > >> +            str = NULL;
> > > > > >> +
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > > > > >> +            if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
> > > > > >> +                    status = get_string_from_buffer((u16 **)&obj-
> > > > > >>> buffer.pointer, &str);
> > > > > >> +                    if (ACPI_SUCCESS(status)) {
> > > > > >> +                            /*
> > > > > >> +                             * Report "CurrentValue" as "Value"
> > > > > >> +                             */
> > > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > > >> +                                                "%s\t\"Value\": \"%s\",\n",
> > > > > >> buf, str);
> > > > > >> +                    }
> > > > > >> +                    kfree(str);
> > > > > >> +                    str = NULL;
> > > > > >> +                    continue;
> > > > > >> +
> > > > > >> +            } else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
> > > > > >> +                    /*
> > > > > >> +                     * Report list of "SupportEncoding"
> > > > > >> +                     *
> > > > > >> +                     *      "SupportedEncoding": [
> > > > > >> +                     *              "utf-16"
> > > > > >> +                     *      ],
> > > > > >> +                     *
> > > > > >> +                     */
> > > > > >> +
> > > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > > > > >> +                                        buf, hp_wmi_elements[type][i]);
> > > > > >> +                    for (j = 0; j < size; j++) {
> > > > > >> +                            status = get_string_from_buffer((u16
> > > > > >> **)&obj->buffer.pointer, &str);
> > > > > >> +                            if (ACPI_SUCCESS(status)) {
> > > > > >> +                                    if (j == size - 1)
> > > > > >> +                                            buf_size = snprintf(buf,
> > > > > >> alloc_size,
> > > > > >> +
> > > > > >> "%s\t\t\"%s\"\n", buf, str);
> > > > > >> +                                    else
> > > > > >> +                                            buf_size = snprintf(buf,
> > > > > >> alloc_size,
> > > > > >> +
> > > > > >> "%s\t\t\"%s\",\n", buf, str);
> > > > > >> +                            }
> > > > > >> +                            kfree(str);
> > > > > >> +                            str = NULL;
> > > > > >> +                    }
> > > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > > >> +                    continue;
> > > > > >> +            }
> > > > > >> +
> > > > > >> +            size = 0;
> > > > > >> +            status = get_integer_from_buffer((int **)&obj-
> > > > > >>> buffer.pointer, &integer);
> > > > > >> +            if (ACPI_SUCCESS(status)) {
> > > > > >> +                    /*
> > > > > >> +                     * Report "PrerequisiteSize" and "Size" values
> > > > > >> +                     *      ...
> > > > > >> +                     *      "PrerequisiteSize": 1,
> > > > > >> +                     *      ...
> > > > > >> +                     *      "Size": 2,
> > > > > >> +                     *      ...
> > > > > >> +                     */
> > > > > >> +                    if (i == 7)
> > > > > >> +                            size = integer;
> > > > > >> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > > > > >> == 10)
> > > > > >> +                            size = integer;
> > > > > >> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > > > > >> 9)
> > > > > >> +                            size = integer;
> > > > > >> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > > > > >> 11)
> > > > > >> +                            size = integer;
> > > > > >> +
> > > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > > > > >> %d,\n", buf,
> > > > > >> +                                        hp_wmi_elements[type][i],
> > > > > >> integer);
> > > > > >> +            }
> > > > > >> +
> > > > > >> +            if (size > 20)
> > > > > >> +                    pr_warn("%s exceeded the maximum number of
> > > > > >> elements supported or data may be malformed\n",
> > > > > >> +                            hp_wmi_elements[type][i]);
> > > > > >> +
> > > > > >> +            if (ACPI_SUCCESS(status) && i == 7) {
> > > > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > > > >> "%s\t\"Prerequisites\": [\n", buf);
> > > > > >> +                    for (j = 0; j < size; j++) {
> > > > > >> +                            status = get_string_from_buffer((u16
> > > > > >> **)&obj->buffer.pointer, &str);
> > > > > >> +                            if (ACPI_SUCCESS(status)) {
> > > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > > >> "%s\t\t\"%s\"", buf, str);
> > > > > >> +
> > > > > >> +                                    if (j == size - 1)
> > > > > >> +                                            buf_size = snprintf(buf,
> > > > > >> alloc_size, "%s\n", buf);
> > > > > >> +                                    else
> > > > > >> +                                            buf_size = snprintf(buf,
> > > > > >> alloc_size, "%s,\n", buf);
> > > > > >> +
> > > > > >> +                            }
> > > > > >> +                            kfree(str);
> > > > > >> +                            str = NULL;
> > > > > >> +                    }
> > > > > >> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > > >> +            }
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    if (type == HPWMI_ENUMERATION_TYPE || type ==
> > > > > >> HPWMI_ORDEREDLIST_TYPE) {
> > > > > >> +            if (type == HPWMI_ENUMERATION_TYPE)
> > > > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > > > >> "%s\t\"PossibleValues\": [\n", buf);
> > > > > >> +            else
> > > > > >> +                    buf_size = snprintf(buf, alloc_size,
> > > > > >> "%s\t\"Elements\": [\n", buf);
> > > > > >> +
> > > > > >> +            for (i = 0; i < size; i++) {
> > > > > >> +                    status = get_string_from_buffer((u16 **)&obj-
> > > > > >>> buffer.pointer, &str);
> > > > > >> +                    if (ACPI_SUCCESS(status)) {
> > > > > >> +                            buf_size = snprintf(buf, alloc_size,
> > > > > >> "%s\t\t\"%s\"", buf, str);
> > > > > >> +
> > > > > >> +                            if (i == size - 1)
> > > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > > >> "%s\n", buf);
> > > > > >> +                            else
> > > > > >> +                                    buf_size = snprintf(buf, alloc_size,
> > > > > >> "%s,\n", buf);
> > > > > >> +
> > > > > >> +                    }
> > > > > >> +                    kfree(str);
> > > > > >> +                    str = NULL;
> > > > > >> +            }
> > > > > >> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    /*
> > > > > >> +     * remove trailing comma
> > > > > >> +     */
> > > > > >> +    if (buf_size > 3)
> > > > > >> +            buf[buf_size - 2] = ' ';
> > > > > >> +
> > > > > >> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > > > > >> +}
> > > > > >> +
> > > > > >> +static int hp_bios_settings_free_buffer(void)
> > > > > >> +{
> > > > > >> +    mutex_lock(&buf_mutex);
> > > > > >> +    kfree(hp_bios_settings_buffer);
> > > > > >> +    settings_buffer_size = 0;
> > > > > >> +    buf_alloc_size = 0;
> > > > > >> +    mutex_unlock(&buf_mutex);
> > > > > >> +
> > > > > >> +    return 0;
> > > > > >> +}
> > > > > >> +
> > > > > >> +static int hp_bios_settings_realloc_buffer(char **buf, int
> > *buf_size,
> > > > > >> +                                       int *alloc_size,
> > > > > >> +                                       struct mutex *buf_mutex)
> > > > > >> +{
> > > > > >> +    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(buf_mutex);
> > > > > >> +            new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
> > > > > >> +            mutex_unlock(buf_mutex);
> > > > > >> +            if (new_buf) {
> > > > > >> +                    mutex_lock(buf_mutex);
> > > > > >> +                    *buf = new_buf;
> > > > > >> +                    *alloc_size = ksize(new_buf);
> > > > > >> +                    mutex_unlock(buf_mutex);
> > > > > >> +            } else {
> > > > > >> +                    hp_bios_settings_free_buffer();
> > > > > >> +                    ret = -ENOMEM;
> > > > > >> +            }
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    return ret;
> > > > > >> +}
> > > > > >> +
> > > > > >> +static int append_settings_to_buffer(char *guid, int type, char
> > **buf,
> > > > > >> +                                 int *buf_size, int *alloc_size,
> > > > > >> +                                 struct mutex *buf_mutex)
> > > > > >> +{
> > > > > >> +    union acpi_object *obj = NULL;
> > > > > >> +    int ret = 0;
> > > > > >> +    int status = 0;
> > > > > >> +    int instance = 0;
> > > > > >> +
> > > > > >> +    /*
> > > > > >> +     * Query all the instances until to receive a AE_BAD_PARAMETER
> > > > > >> +     */
> > > > > >> +    do {
> > > > > >> +            ret = hp_wmi_get_setting_object(guid, instance++, &obj);
> > > > > >> +            if (ACPI_SUCCESS(ret) && obj != NULL) {
> > > > > >> +                    status = 0;
> > > > > >> +                    if (obj->type == ACPI_TYPE_PACKAGE) {
> > > > > >> +                            mutex_lock(buf_mutex);
> > > > > >> +                            status =
> > > > > >> append_package_elements_to_buffer(obj,
> > > > > >> +                                                    *buf, *alloc_size,
> > > > > >> type);
> > > > > >> +                            if (status > 0)
> > > > > >> +                                    *buf_size = status;
> > > > > >> +                            mutex_unlock(buf_mutex);
> > > > > >> +
> > > > > >> +                    } else if (obj->type == ACPI_TYPE_BUFFER) {
> > > > > >> +                            mutex_lock(buf_mutex);
> > > > > >> +                            status =
> > > > > >> append_buffer_elements_to_buffer(obj,
> > > > > >> +                                                    *buf, *alloc_size,
> > > > > >> type);
> > > > > >> +                            if (status > 0)
> > > > > >> +                                    *buf_size = status;
> > > > > >> +                            mutex_unlock(buf_mutex);
> > > > > >> +
> > > > > >> +                    } else
> > > > > >> +                            pr_warn("The retrieved object type(%d) is
> > > > > >> not supported yet\n",
> > > > > >> +                                    obj->type);
> > > > > >> +
> > > > > >> +                    ret = hp_bios_settings_realloc_buffer(buf, buf_size,
> > > > > >> alloc_size, buf_mutex);
> > > > > >> +            }
> > > > > >> +
> > > > > >> +            kfree(obj);
> > > > > >> +            obj = NULL;
> > > > > >> +
> > > > > >> +    } while (ACPI_SUCCESS(ret));
> > > > > >> +
> > > > > >> +    /*
> > > > > >> +     * AE_BAD_PARAMETER means the loop ended by exhaustion
> > > > > >> +     */
> > > > > >> +    if (ret == AE_BAD_PARAMETER)
> > > > > >> +            ret = 0;
> > > > > >> +
> > > > > >> +    return ret;
> > > > > >> +}
> > > > > >> +
> > > > > >> +static int hp_bios_settings_fill_buffer(void)
> > > > > >> +{
> > > > > >> +    int status = 0;
> > > > > >> +    int initial_buffer_size = 20 * PAGE_SIZE;
> > > > > >> +
> > > > > >> +    mutex_lock(&buf_mutex);
> > > > > >> +    hp_bios_settings_buffer = kmalloc(initial_buffer_size,
> > > > GFP_KERNEL);
> > > > > >> +    mutex_unlock(&buf_mutex);
> > > > > >> +    if (!hp_bios_settings_buffer)
> > > > > >> +            return -ENOMEM;
> > > > > >> +
> > > > > >> +    mutex_lock(&buf_mutex);
> > > > > >> +    buf_alloc_size = ksize(hp_bios_settings_buffer);
> > > > > >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > > > > >> +                                    buf_alloc_size, "[\n");
> > > > > >> +    mutex_unlock(&buf_mutex);
> > > > > >> +
> > > > > >> +    status = append_settings_to_buffer(HPWMI_STRING_GUID,
> > > > > >> +            HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
> > > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > > >> +    if (ACPI_FAILURE(status))
> > > > > >> +            pr_err("error 0x%x occurred retrieving string instances\n",
> > > > > >> status);
> > > > > >> +
> > > > > >> +    status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
> > > > > >> +            HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
> > > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > > >> +    if (ACPI_FAILURE(status))
> > > > > >> +            pr_err("error 0x%x occurred retrieving integer instances\n",
> > > > > >> status);
> > > > > >> +
> > > > > >> +    status =
> > > > append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
> > > > > >> +            HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
> > > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > > >> +    if (ACPI_FAILURE(status))
> > > > > >> +            pr_err("error 0x%x occurred retrieving enumeration
> > > > > >> instances\n", status);
> > > > > >> +
> > > > > >> +    status =
> > append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
> > > > > >> +            HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
> > > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > > >> +    if (ACPI_FAILURE(status))
> > > > > >> +            pr_err("error 0x%x occurred retrieving ordered list
> > > > > >> instances\n", status);
> > > > > >> +
> > > > > >> +    status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
> > > > > >> +            HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
> > > > > >> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > > > > >> +    if (ACPI_FAILURE(status))
> > > > > >> +            pr_err("error 0x%x occurred retrieving password list
> > > > > >> instances\n", status);
> > > > > >> +
> > > > > >> +    mutex_lock(&buf_mutex);
> > > > > >> +    /*
> > > > > >> +     * remove trailing comma
> > > > > >> +     */
> > > > > >> +    if (settings_buffer_size >= 3) {
> > > > > >> +            if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
> > > > > >> +                    hp_bios_settings_buffer[settings_buffer_size - 2] = '
> > > > > >> ';
> > > > > >> +    }
> > > > > >> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > > > > >> +                                    buf_alloc_size, "%s]\n",
> > > > > >> +                                    hp_bios_settings_buffer);
> > > > > >> +    mutex_unlock(&buf_mutex);
> > > > > >> +
> > > > > >> +    return settings_buffer_size;
> > > > > >> +}
> > > > > >> +
> > > > > >> +/*
> > > > > >> + * sure_admin_settings_read - Return a formatted file with
> > settings
> > > > > >> + *                              and possible options read from BIOS
> > > > > >> + *
> > > > > >> + * @filp:  Pointer to file of settings read from BIOS
> > > > > >> + * @kobj:  Pointer to a kernel object of things that show up as
> > directory
> > > > in
> > > > > >> the sysfs filesystem.
> > > > > >> + * @attr:  Pointer to list of read attributes
> > > > > >> + * @buf:   Pointer to buffer
> > > > > >> + * @off:   File current offset
> > > > > >> + * @count: Buffer size
> > > > > >> + *
> > > > > >> + * Returns the count of unicode chars read if successful, otherwise
> > > > > >> + *          -ENOMEM unable to allocate memory
> > > > > >> + *          -EINVAL buffer not allocated or too small
> > > > > >> + *
> > > > > >> + */
> > > > > >> +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 >= settings_buffer_size && settings_buffer_size > 0) {
> > > > > >> +            hp_bios_settings_free_buffer();
> > > > > >> +            return 0;
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    /* clear the buffer whenever the read starts from the first
> > position
> > > > > >> */
> > > > > >> +    if (off == 0 && settings_buffer_size > 0)
> > > > > >> +            hp_bios_settings_free_buffer();
> > > > > >> +
> > > > > >> +    if (settings_buffer_size == 0)
> > > > > >> +            hp_bios_settings_fill_buffer();
> > > > > >> +
> > > > > >> +    mutex_lock(&buf_mutex);
> > > > > >> +    ret = memory_read_from_buffer(buf, count, &off,
> > > > > >> hp_bios_settings_buffer,
> > > > > >> +                                  settings_buffer_size);
> > > > > >> +    mutex_unlock(&buf_mutex);
> > > > > >> +
> > > > > >> +    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
> > > > > >> + */
> > > > > >> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
> > > > > >> +{
> > > > > >> +    int len = strlen(str);
> > > > > >> +
> > > > > >> +    /*
> > > > > >> +     * Add null character when reading an empty string
> > > > > >> +     */
> > > > > >> +    if (len == 0) {
> > > > > >> +            *p++ = 2;
> > > > > >> +            *p++ = (u8)0x00;
> > > > > >> +            return p;
> > > > > >> +    }
> > > > > >> +    *p++ = len * 2;
> > > > > >> +    utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
> > > > > >> +    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
> > > > > >> + */
> > > > > >> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32
> > 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(HPWMI_SETBIOSSETTING_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;
> > > > > >> +}
> > > > > >> +
> > > > > >> +/* Sure Admin Functions */
> > > > > >> +
> > > > > >> +#define UTF_PREFIX                  ((unsigned char *)"<utf-16/>")
> > > > > >> +#define BEAM_PREFIX                 ((unsigned char
> > > > > >> *)"<BEAM/>")
> > > > > >> +
> > > > > >> +/*
> > > > > >> + * sure_admin_settings_write - Write the contents of a formatted
> > file
> > > > > >> + *                               with settings and performs the logic
> > > > > >> + *                               to change any settings in BIOS.
> > > > > >> + *
> > > > > >> + * @filp:  Pointer to file of settings to be written to BIOS
> > > > > >> + * @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 write operation
> > > > > >> + * @buf:   Pointer to buffer
> > > > > >> + * @off:   File current offset
> > > > > >> + * @count: Buffer size
> > > > > >> + *
> > > > > >> + *
> > > > > >> + * Returns the count of unicode characters written to BIOS if
> > > > successful,
> > > > > >> otherwise
> > > > > >> + *          -ENOMEM unable to allocate memory
> > > > > >> + *          -EINVAL buffer not allocated or too small
> > > > > >> + *
> > > > > >> + */
> > > > > >> +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;
> > > > > >> +    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 out_free;
> > > > > >> +    }
> > > > > >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > > > >> +    part = strsep(&buf, ",");
> > > > > >> +    if (!part) {
> > > > > >> +            status = -EINVAL;
> > > > > >> +            goto out_free;
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    /* Add extra buffer space when encountering an empty string */
> > > > > >> +    if (!strlen(part))
> > > > > >> +            buffer_size += sizeof(unsigned short);
> > > > > >> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > > > >> +    part = strsep(&buf, ",");
> > > > > >> +    if (!part) {
> > > > > >> +            status = -EINVAL;
> > > > > >> +            goto out_free;
> > > > > >> +    }
> > > > > >> +    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 out_free;
> > > > > >> +
> > > > > >> +            tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > > > > >> +            kfree(part);
> > > > > >> +    }
> > > > > >> +
> > > > > >> +    part = strsep(&buf, ",");
> > > > > >> +    if (part) {
> > > > > >> +            status = -EINVAL;
> > > > > >> +            goto out_free;
> > > > > >> +    }
> > > > > >> +    status = hp_wmi_set_bios_setting(buffer, buffer_size);
> > > > > >> +    if (ACPI_FAILURE(status))
> > > > > >> +            status = -EINVAL;
> > > > > >> +
> > > > > >> +out_free:
> > > > > >> +    kfree(buffer);
> > > > > >> +    if (ACPI_SUCCESS(status))
> > > > > >> +            return count;
> > > > > >> +    return status;
> > > > > >> +}
> > > > > >> +
> > > > > >> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
> > > > > >> +
> > > > > >> +static struct bin_attribute *sure_admin_binattrs[] = {
> > > > > >> +    &sure_admin_settings,
> > > > > >> +    NULL,
> > > > > >> +};
> > > > > >> +
> > > > > >> +static const struct attribute_group sure_admin_group = {
> > > > > >> +    .name = "sure_admin",
> > > > > >> +    .bin_attrs = sure_admin_binattrs,
> > > > > >> +};
> > > > > >> +
> > > > > >>  static DEVICE_ATTR_RO(display);
> > > > > >>  static DEVICE_ATTR_RO(hddtemp);
> > > > > >>  static DEVICE_ATTR_RW(als);
> > > > > >> @@ -1050,6 +2026,7 @@ static const struct attribute_group
> > > > > >> *hp_wmi_groups[] = {
> > > > > >>      &hp_wmi_group,
> > > > > >>      &spm_group,
> > > > > >>      &sure_start_group,
> > > > > >> +    &sure_admin_group,
> > > > > >>      NULL,
> > > > > >>  };
> > > > > >>
> > > > > >> --
> > > > > >> 2.25.1
> > > > >

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-07 13:44           ` Jorge Lopez
  2022-04-07 19:17             ` Limonciello, Mario
@ 2022-04-08  9:21             ` Hans de Goede
  2022-04-08 14:46               ` Jorge Lopez
  1 sibling, 1 reply; 25+ messages in thread
From: Hans de Goede @ 2022-04-08  9:21 UTC (permalink / raw)
  To: Jorge Lopez, Limonciello, Mario; +Cc: platform-driver-x86

Hi Jorge,

On 4/7/22 15:44, Jorge Lopez wrote:
> Hans, Mario,
> 
> The code links make references to code that implements the new
> interfaces but there’s
> still code in the kernel that uses the old ones.

I'm not sure what you mean with "uses the old ones" there never
has been any kernel drivers for changing BIOS settings before
the dell and lenovo drivers were merged.

Sure there are generic mechanisms like chardev-s and ioctls which
are used for a whole bunch of things. But AFAIK there never was
an API specifically for changing BIOS settings before.

> I do agree we should
> be forward looking
> and want to be good participants in the kernel development, but can’t
> let our immediate
> business needs be impacted with opportunities to enhance the driver to
> take advantage
> of the latest kernel features.
> 
> Rewriting those security features will impact customer business
> datelines requiring
> HP to provide private releases as the kernel version changes.   The
> requested changes
> will impact products in the market and HP ability to help customers to
> migrate to Linux
> from Windows products.

This sounds like you are saying that you are already shipping
a version of the driver with the non-standard API to customers.
Shipping code to customers before even proposing it upstream is
HP own choice and the results of that as such are HP's
responsibility.

You cannot just say we are already shipping this so we need
the upstream kernel to support this non standard API, that is
not how upstream kernel development works.

I realize that HP is new to working directly with the upstream kernel
community and I realize that being told that the API which you are
already using cannot be used for upstreaming your driver is not what
you want to hear.

But that does not change that I cannot accept a driver which does not
implement the standard API which the upstream kernel community has
agreed upon for this functionality.

Or as Mario very elegantly put it:

'Keep in mind that from an upstream kernel perspective this driver is "new".
There is no requirements from the upstream perspective to
keep your old interfaces in place from when it was out of tree.'

> It is because of the immediate business needs, avoiding impacting our
> customers/products,
> and rewriting  enhancements to the driver that I need to propose an
> interim solution.
> 
> My proposal is to introduce a read/write value accessible in the user
> space to control how
> the driver reports and handles BIOS settings and values.  The new
> configuration features
> will be gradually disabled  as they are converted to use the standardized API.
> It is like the configuration flag used to overcome the tablet detection problem
> introduced in the past.   The changes solely affect the HP WMI driver.
> This option will help us
> move forward for this release and give us time to make the necessary
> changes to both
> the driver and support applications.
> 
> Please let me know if this is a viable interim solution.

First of all to be very clear, any code going upstream must support
the standard API:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/ABI/testing/sysfs-class-firmware-attributes

from day one. I'm not really enthusiastic about the concept of also
supporting the API which you have been using out of tree so far, but
I guess that Mario's suggestion to offer a Kconfig option which
when enabled offers this API under debugfs might be an acceptible
compromise. I would need to see the actual code for that though to
see if this is acceptable.

And there would need to be a clear cut-of date document after which
the code to support the old API will be removed.

> If it is not possible, I need to ask where the actual written
> requirement is found so I can
> include them in the business justification for changes and release
> delays to management.

I'm not sure if this is written down somewhere, but certainly
you will agree that if you were submitting a driver for a soundcard
that that should use the existing ALSA userspace API for sound so
that it would just work with the existing userspace sound support.

This is the same. If an existing standardized userspace API exists
for a certain functionality then that userspace API _must_ be used,
AFAIK this is not explictly written down anywhere because it is just
very much common sense.

Regards,

Hans






> On Tue, Apr 5, 2022 at 12:13 PM Limonciello, Mario
> <Mario.Limonciello@amd.com> wrote:
>>
>> [Public]
>>
>>
>>
>>> -----Original Message-----
>>> From: Jorge Lopez <jorgealtxwork@gmail.com>
>>> Sent: Tuesday, April 5, 2022 11:52
>>> To: Hans de Goede <hdegoede@redhat.com>
>>> Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-driver-
>>> x86@vger.kernel.org
>>> Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
>>>
>>> Hi Hans,
>>>
>>> On Tue, Apr 5, 2022 at 6:54 AM Hans de Goede <hdegoede@redhat.com>
>>> wrote:
>>>>
>>>> Hi,
>>>>
>>>> On 4/4/22 23:59, Limonciello, Mario wrote:
>>>>> [Public]
>>>>>
>>>>>
>>>>>
>>>>>> -----Original Message-----
>>>>>> From: Jorge Lopez <jorgealtxwork@gmail.com>
>>>>>> Sent: Monday, April 4, 2022 15:36
>>>>>> To: platform-driver-x86@vger.kernel.org
>>>>>> Subject: [PATCH v1 5/6] Sure Admin Security Feature
>>>>>>
>>>>>> 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. Behind the scenes, Sure Admin uses Secure
>>> Platform
>>>>>> Management (SPM) and WMI
>>>>>>
>>>>>> 'settings' is a file associated with Sure Admin. BIOS settings can be
>>>>>> read or written through the Sure Admin settings file in sysfs
>>>>>>
>>>>>>      /sys/devices/platform/hp-wmi/sure_admin/settings
>>>>>>
>>>>>> 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"
>>>>>>              ]
>>>>>>      }
>>>>>>
>>>>>
>>>>> This sounds like it has re-invented /sys/class/firmware-attributes.
>>>>>
>>>>> Shouldn't you adopt that API?
>>>>
>>>> I fully agree. Jorge as I already indicated in our off-list
>>>> conversation when you initially started working on this
>>>> feature, we already have a standardized API for querying/changing
>>>> BIOS settings from within Linux:
>>>>
>>>
>>> I agree that changing the BIOS settings from within Linux could
>>> utilize the new methodology,  I will need to look closely at the
>>> requirements before I can proceed to make the changes.
>>> Keep in mind authentication of the values is done by BIOS.  No Linux
>>> process validates any data name, value, or auth token; only BIOS.  All
>>> data written to the sysfs file is not validated, it is just forward to
>>> BIOS.  See spm_kek_store and spm_sk_store functions.
>>
>> That's fine, and it's a safer design to have BIOS validate it.
>>
>>> One point I must make clear when updating BIOS settings.  any  NOT
>>> read-only BIOS settings can be changed by the application at any time.
>>>    This list of settings changes from one system to another.
>>
>> Right.
>>
>>>
>>> I am in disagreement with reading the settings.  hp-wmi does not read
>>> one value at a time. It reads all values exposed by BIOS.  See
>>> attached sample output.
>>
>> The settings can all be read at initialization time for the driver and cached
>> then.
>>
>>> The method for how all BIOS settings are reported needs to match the
>>> method how Windows products do it.  It is a requirement to start
>>> migrating customers from Windows to Linux while minimizing how BIOS
>>> data is reported.
>>
>> Because we have a standardized API in Linux for this, I think it's best to abstract
>> this behind a userspace application/script.  If they expect to see it in the format you
>> showed, the userspace application can take the data from Linux and package it that
>> way.
>>
>> You'll have richer libraries and languages and tools to work from when doing this too.
>> It should make it a lot less painful.
>>
>>>
>>> I will investigate the new API and bring it to the team's attention.
>>>
>>>>
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
>>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
>>> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
>>> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
>>> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
>>> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
>>> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
>>> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
>>> D&amp;reserved=0
>>>>
>>>> and any new code (such as this patch) which implements BIOS
>>>> setting changing MUST follow this standardized API (extending
>>>> it where necessary).
>>>>
>>>> I'm sorry but this patch is not acceptable in its current form,
>>>> it needs to be *completely rewritten* to implement:
>>>>
>>>>
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
>>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
>>> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
>>> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
>>> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
>>> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
>>> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
>>> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
>>> D&amp;reserved=0
>>>>
>>>> See:
>>>>
>>>>
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
>>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
>>> 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fdell%2Fdell-wmi-
>>> sysman&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8f
>>> ea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%
>>> 7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
>>> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
>>> mp;sdata=z5jmH7ECYBeLcndQ2vfHaUuyE04Eaf1Lymh6BjnyJ%2Fk%3D&amp;r
>>> eserved=0
>>>>
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
>>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
>>> 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fthink-
>>> lmi.c&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea
>>> 104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
>>> 0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
>>> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
>>> sdata=5n6w9LEB2iWpj1cOQP6Ngz94AqP1Bu4vu8T0EdN%2FThU%3D&amp;re
>>> served=0
>>>>
>>>> for example code / for 2 drivers from other vendors already
>>>> implementing this.
>>>>
>>>> The same applies to the:
>>>>
>>>> "[PATCH v1 3/6] Secure Platform Management Security Feature"
>>>>
>>>> this needs to be implemented as
>>>> a /sys/class/firmware-attributes/*/authentication/
>>>> authentication method, see for example these Lenovo specific
>>>> addition to the /sys/class/firmware-attributes/*/authentication/
>>>> userspace API for similar functionality on Lenovo Think* devices:
>>>>
>>>>
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
>>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
>>> 2Fcommit%2F%3Fid%3D06384573a3e8335ac6797577e545c33dbf91b490&amp;
>>> data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea1040342827
>>> 08da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C63784
>>> 7743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLC
>>> JQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=eldS
>>> 4H3Z%2BAyL%2FG%2FO9W9rDGC37yh5sGgtUhpKdUAoSmA%3D&amp;reser
>>> ved=0
>>>>
>>>> I'll merge patches 1-2 sometime this week since those are
>>>> fine and it will be good to have those "out of the way",
>>>> but the rest of the series will need to be rewritten
>>>> taken the above comments into account.
>>>
>>> v1-0003-Sure-Start-Security-Feature.patch  reports the number of audit
>>> logs available and reports them when read.    it does not read/write
>>> BIOS settings hence it does not fall within the same category as
>>> patches v1-0002-Secure-Platform-Management-Security-Feature.patch and
>>> v1-0004-Sure-Admin-Security-Feature.patch
>>> Do you agree?
>>>
>>>>
>>>> Regards,
>>>>
>>>> Hans
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>>
>>>>>> This feature requires "Update hp_wmi_group to simplify feature
>>>>>> addition" patch.
>>>>>>
>>>>>> All changes were validated on a HP ZBook Workstation,
>>>>>> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
>>>>>>
>>>>>> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
>>>>>>
>>>>>> ---
>>>>>> Based on the latest platform-drivers-x86.git/for-next
>>>>>> ---
>>>>>>  drivers/platform/x86/hp-wmi.c | 977
>>>>>> ++++++++++++++++++++++++++++++++++
>>>>>>  1 file changed, 977 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-
>>> wmi.c
>>>>>> index 918e3eaf1b67..b72ca18b77a6 100644
>>>>>> --- a/drivers/platform/x86/hp-wmi.c
>>>>>> +++ b/drivers/platform/x86/hp-wmi.c
>>>>>> @@ -27,6 +27,7 @@
>>>>>>  #include <linux/rfkill.h>
>>>>>>  #include <linux/string.h>
>>>>>>  #include <linux/dmi.h>
>>>>>> +#include <linux/nls.h>
>>>>>>
>>>>>>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
>>>>>>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
>>>>>> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-
>>>>>> 3D44E2C707E4");
>>>>>>
>>>>>>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-
>>> ACCDC67EF61C"
>>>>>>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-
>>> 3D44E2C707E4"
>>>>>> +
>>>>>>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
>>>>>>
>>>>>> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-
>>> 6A1B8106F83C"
>>>>>> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
>>>>>> E293ADB9BF05"
>>>>>> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-
>>>>>> 4A3C09E75133"
>>>>>> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
>>>>>> 7045CB4DA745"
>>>>>> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
>>>>>> 015176049E2D"
>>>>>> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-
>>>>>> C7CB9B4B8D5E"
>>>>>> +
>>>>>>  /* DMI board names of devices that should use the omen specific path
>>> for
>>>>>>   * thermal profiles.
>>>>>>   * This was obtained by taking a look in the windows omen command
>>> center
>>>>>> @@ -1025,6 +1034,973 @@ static const struct attribute_group
>>>>>> sure_start_group = {
>>>>>>      .attrs = sure_start_attrs,
>>>>>>  };
>>>>>>
>>>>>> +
>>>>>> +static 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;
>>>>>> +    int  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));
>>>>>> +            ret = kstrtoint(tmp, 16, &ch);
>>>>>> +            if (ret) {
>>>>>> +                    new_len = 0;
>>>>>> +                    break;
>>>>>> +            }
>>>>>> +
>>>>>> +            if (ch == '\\')
>>>>>> +                    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;
>>>>>> +    }
>>>>>> +
>>>>>> +    if (ret)
>>>>>> +            kfree(new_str);
>>>>>> +    return ret;
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and
>>> instance
>>>>>> + *
>>>>>> + * @guid:   GUID associated with the ACPI list of managed objects
>>>>>> + * @instance:       Instance index to query on the ACPI list
>>>>>> + * @obj:    The output ACPI object of type ACPI_TYPE_PACKAGE
>>>>>> + *          or ACPI_TYPE_BUFFER (freed by the callee)
>>>>>> + *
>>>>>> + * Returns  zero on success.  Otherwise,an error inherited from
>>>>>> + *          wmi_query_block(). It returns a obj by parameter if
>>>>>> + *          the query returned object of type buffer or package,
>>>>>> + *          otherwise, a null obj is returned.
>>>>>> + *
>>>>>> + * Note: obj should be freed by the callee once it is finished working
>>> with it
>>>>>> + */
>>>>>> +static int hp_wmi_get_setting_object(char *guid, int instance,
>>>>>> +                            union acpi_object **obj)
>>>>>> +{
>>>>>> +    struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL
>>>>>> };
>>>>>> +    union acpi_object *tmp = NULL;
>>>>>> +    int ret;
>>>>>> +
>>>>>> +    ret = wmi_query_block(guid, instance, &output);
>>>>>> +    if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
>>>>>> +            tmp = output.pointer;
>>>>>> +            if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
>>>>>> ACPI_TYPE_PACKAGE)
>>>>>> +                    *obj = output.pointer;
>>>>>> +            else {
>>>>>> +                    kfree(tmp);
>>>>>> +                    *obj = NULL;
>>>>>> +            }
>>>>>> +    }
>>>>>> +
>>>>>> +    return ret;
>>>>>> +}
>>>>>> +
>>>>>> +
>>>>>> +static 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;
>>>>>> +
>>>>>> +    if (size == 0)
>>>>>> +            goto cleanup_exit;
>>>>>> +
>>>>>> +    for (i = 0; i < size; i++)
>>>>>> +            if (ptr[i] == '\\')
>>>>>> +                    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);
>>>>>> +
>>>>>> +    if (escape == 0) {
>>>>>> +            ptr += (ptrlen / 2);
>>>>>> +            goto cleanup_exit;
>>>>>> +    }
>>>>>> +    /*
>>>>>> +     * Convert escape characters only when found
>>>>>> +     */
>>>>>> +    for (i = 0; i < size; i++) {
>>>>>> +            if (*ptr == '\\')
>>>>>> +                    output[i++] = '\\';
>>>>>> +            output[i] = *ptr;
>>>>>> +            ptr++;
>>>>>> +    }
>>>>>> +
>>>>>> +cleanup_exit:
>>>>>> +    *buffer = ptr;
>>>>>> +    return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int get_integer_from_buffer(int **buffer, int *integer)
>>>>>> +{
>>>>>> +    int *ptr = PTR_ALIGN(*buffer, 4);
>>>>>> +    *integer = *(ptr++);
>>>>>> +    *buffer = ptr;
>>>>>> +    return 0;
>>>>>> +}
>>>>>> +
>>>>>> +
>>>>>> +// Sure Admin functions
>>>>>> +enum hp_wmi_data_type {
>>>>>> +    HPWMI_STRING_TYPE,
>>>>>> +    HPWMI_INTEGER_TYPE,
>>>>>> +    HPWMI_ENUMERATION_TYPE,
>>>>>> +    HPWMI_ORDEREDLIST_TYPE,
>>>>>> +    HPWMI_PASSWORD_TYPE,
>>>>>> +};
>>>>>> +
>>>>>> +#define HP_WMI_COMMON_ELEMENTS      \
>>>>>> +    "Name", \
>>>>>> +    "Value",        \
>>>>>> +    "Path", \
>>>>>> +    "IsReadOnly",   \
>>>>>> +    "DisplayInUI",  \
>>>>>> +    "RequiresPhysicalPresence",     \
>>>>>> +    "Sequence",     \
>>>>>> +    "PrerequisiteSize",     \
>>>>>> +    "SecurityLevel"
>>>>>> +
>>>>>> +const char *hp_wmi_string_elements[] = {
>>>>>> +    HP_WMI_COMMON_ELEMENTS,
>>>>>> +    "MinLength",
>>>>>> +    "MaxLength"
>>>>>> +};
>>>>>> +
>>>>>> +const char *hp_wmi_integer_elements[] = {
>>>>>> +    HP_WMI_COMMON_ELEMENTS,
>>>>>> +    "LowerBound",
>>>>>> +    "UpperBound",
>>>>>> +    "IntValue"
>>>>>> +};
>>>>>> +
>>>>>> +const char *hp_wmi_enumeration_elements[] = {
>>>>>> +    HP_WMI_COMMON_ELEMENTS,
>>>>>> +    "CurrentValue",
>>>>>> +    "Size"
>>>>>> +};
>>>>>> +
>>>>>> +const char *hp_wmi_orderedlist_elements[] = {
>>>>>> +    HP_WMI_COMMON_ELEMENTS,
>>>>>> +    "Size"
>>>>>> +};
>>>>>> +
>>>>>> +const char *hp_wmi_password_elements[] = {
>>>>>> +    HP_WMI_COMMON_ELEMENTS,
>>>>>> +    "MinLength",
>>>>>> +    "MaxLength",
>>>>>> +    "Size",
>>>>>> +    "SupportedEncoding",
>>>>>> +    "IsSet"
>>>>>> +};
>>>>>> +
>>>>>> +const char **hp_wmi_elements[] = {
>>>>>> +    hp_wmi_string_elements,
>>>>>> +    hp_wmi_integer_elements,
>>>>>> +    hp_wmi_enumeration_elements,
>>>>>> +    hp_wmi_orderedlist_elements,
>>>>>> +    hp_wmi_password_elements
>>>>>> +};
>>>>>> +
>>>>>> +const int hp_wmi_elements_count[] = {
>>>>>> +    ARRAY_SIZE(hp_wmi_string_elements),
>>>>>> +    ARRAY_SIZE(hp_wmi_integer_elements),
>>>>>> +    ARRAY_SIZE(hp_wmi_enumeration_elements),
>>>>>> +    ARRAY_SIZE(hp_wmi_orderedlist_elements),
>>>>>> +    ARRAY_SIZE(hp_wmi_password_elements)
>>>>>> +};
>>>>>> +
>>>>>> +const char *hp_wmi_classes[] = {
>>>>>> +    "HPBIOS_BIOSString",
>>>>>> +    "HPBIOS_BIOSInteger",
>>>>>> +    "HPBIOS_BIOSEnumeration",
>>>>>> +    "HPBIOS_BIOSOrderedList",
>>>>>> +    "HPBIOS_BIOSPassword"
>>>>>> +};
>>>>>> +
>>>>>> +static DEFINE_MUTEX(buf_mutex);
>>>>>> +static int settings_buffer_size;
>>>>>> +static int buf_alloc_size;
>>>>>> +static char *hp_bios_settings_buffer;
>>>>>> +
>>>>>> +
>>>>>> +static int append_package_elements_to_buffer(union acpi_object
>>> *obj,
>>>>>> +                                         char *buf, int alloc_size, enum
>>>>>> hp_wmi_data_type type)
>>>>>> +{
>>>>>> +    int i;
>>>>>> +    union acpi_object *pobj = NULL;
>>>>>> +    char *value = NULL;
>>>>>> +    int value_len;
>>>>>> +    char *tmpstr = NULL;
>>>>>> +    char *part_tmp = NULL;
>>>>>> +    int tmp_len = 0;
>>>>>> +    char *part = NULL;
>>>>>> +    int status = 0;
>>>>>> +    int size = 0;
>>>>>> +    int buf_size;
>>>>>> +
>>>>>> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
>>>>>> +            return -EINVAL;
>>>>>> +
>>>>>> +    if (obj->type != ACPI_TYPE_PACKAGE)
>>>>>> +            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]);
>>>>>> +
>>>>>> +    for (i = 0; i < 3; i++) {
>>>>>> +            pobj = &(obj->package.elements[i]);
>>>>>> +            if (pobj->type == ACPI_TYPE_STRING) {
>>>>>> +                    status = convert_hexstr_to_str(&pobj-
>>>>>>> string.pointer,
>>>>>> +                                                   pobj->string.length,
>>>>>> &value, &value_len);
>>>>>> +                    if (ACPI_FAILURE(status))
>>>>>> +                            continue;
>>>>>> +                    /*
>>>>>> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
>>>>>> since
>>>>>> +                     * 'CurrentValue' is reported.
>>>>>> +                     */
>>>>>> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
>>>>>> +                            buf_size = snprintf(buf, alloc_size,
>>>>>> +                                                "%s\t\"%s\": \"%s\",\n",
>>>>>> +                                                buf,
>>>>>> +
>>>>>> hp_wmi_elements[type][i], value);
>>>>>> +
>>>>>> +            }
>>>>>> +            kfree(value);
>>>>>> +            value = NULL;
>>>>>> +    }
>>>>>> +
>>>>>> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
>>>>>> +            pobj = &(obj->package.elements[i]);
>>>>>> +
>>>>>> +            if (type == HPWMI_ENUMERATION_TYPE &&
>>>>>> +                i == 9 &&
>>>>>> +                pobj->type == ACPI_TYPE_STRING) {
>>>>>> +                    /*
>>>>>> +                     * Report "CurrentValue" as "Value"
>>>>>> +                     */
>>>>>> +                    status = convert_hexstr_to_str(&pobj-
>>>>>>> string.pointer,
>>>>>> +                                                   pobj->string.length,
>>>>>> +                                                   &value, &value_len);
>>>>>> +                    if (ACPI_FAILURE(status))
>>>>>> +                            continue;
>>>>>> +
>>>>>> +                    buf_size = snprintf(buf, alloc_size,
>>>>>> +                                        "%s\t\"Value\": \"%s\",\n",
>>>>>> +                                        buf, value);
>>>>>> +                    kfree(value);
>>>>>> +                    value = NULL;
>>>>>> +
>>>>>> +            } else if (type == HPWMI_PASSWORD_TYPE &&
>>>>>> +                       i == 12 &&
>>>>>> +                       pobj->type == ACPI_TYPE_STRING) {
>>>>>> +                    /*
>>>>>> +                     * Report list of "SupportEncoding"
>>>>>> +                     *
>>>>>> +                     *      "SupportedEncoding": [
>>>>>> +                     *              "utf-16"
>>>>>> +                     *      ],
>>>>>> +                     *
>>>>>> +                     */
>>>>>> +
>>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
>>>>>> +                                        buf, hp_wmi_elements[type][i]);
>>>>>> +                    while (size--) {
>>>>>> +                            pobj = &(obj->package.elements[i]);
>>>>>> +                            status = convert_hexstr_to_str(&pobj-
>>>>>>> string.pointer,
>>>>>> +                                                           pobj-
>>>>>>> string.length,
>>>>>> +                                                           &value,
>>>>>> &value_len);
>>>>>> +                            if (ACPI_FAILURE(status))
>>>>>> +                                    continue;
>>>>>> +
>>>>>> +                            if (size) {
>>>>>> +                                    buf_size = snprintf(buf, alloc_size,
>>>>>> +                                                        "%s\t\t\"%s\",\n",
>>>>>> buf, value);
>>>>>> +                                    i++;
>>>>>> +                            } else
>>>>>> +                                    buf_size = snprintf(buf, alloc_size,
>>>>>> +                                                        "%s\t\t\"%s\"\n",
>>>>>> buf, value);
>>>>>> +
>>>>>> +                            kfree(value);
>>>>>> +                            value = NULL;
>>>>>> +
>>>>>> +                    }
>>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>>>>> +                    continue;
>>>>>> +
>>>>>> +            } else if (pobj->type == ACPI_TYPE_INTEGER) {
>>>>>> +                    /*
>>>>>> +                     * Report "PrerequisiteSize" and "Size" values
>>>>>> +                     *      ...
>>>>>> +                     *      "PrerequisiteSize": 1,
>>>>>> +                     *      ...
>>>>>> +                     *      "Size": 2,
>>>>>> +                     *      ...
>>>>>> +                     */
>>>>>> +                    if (i == 7)
>>>>>> +                            size = pobj->integer.value;
>>>>>> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
>>>>>> 9)
>>>>>> +                            size = pobj->integer.value;
>>>>>> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
>>>>>> == 10)
>>>>>> +                            size = pobj->integer.value;
>>>>>> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
>>>>>> 11)
>>>>>> +                            size = pobj->integer.value;
>>>>>> +
>>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
>>>>>> %lld,\n", buf,
>>>>>> +                                        hp_wmi_elements[type][i], pobj-
>>>>>>> integer.value);
>>>>>> +            }
>>>>>> +    }
>>>>>> +
>>>>>> +    if (type == HPWMI_ENUMERATION_TYPE) {
>>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
>>>>>> [\n", buf);
>>>>>> +            for (i = 0; i < size; i++) {
>>>>>> +                    pobj = &(obj->package.elements[i +
>>>>>> hp_wmi_elements_count[type]]);
>>>>>> +
>>>>>> +                    status = convert_hexstr_to_str(&pobj-
>>>>>>> string.pointer,
>>>>>> +                                                   pobj->string.length,
>>>>>> +                                                   &value, &value_len);
>>>>>> +                    if (ACPI_FAILURE(status))
>>>>>> +                            break;
>>>>>> +
>>>>>> +                    /*
>>>>>> +                     * Report list of "PossibleValues" of size
>>>>>> +                     * "Size"
>>>>>> +                     *      ...
>>>>>> +                     *      "Size": 2,
>>>>>> +                     *      "PossibleValues": [
>>>>>> +                     *                      "Disable",
>>>>>> +                     *                      "Enable"]
>>>>>> +                     */
>>>>>> +                    if (i == (size - 1))
>>>>>> +                            buf_size = snprintf(buf, alloc_size,
>>>>>> +                                                "%s\t\t\"%s\"\n", buf,
>>>>>> value);
>>>>>> +                    else
>>>>>> +                            buf_size = snprintf(buf, alloc_size,
>>>>>> +                                                "%s\t\t\"%s\",\n", buf,
>>>>>> value);
>>>>>> +                    kfree(value);
>>>>>> +                    value = NULL;
>>>>>> +            }
>>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>>>>> +    }
>>>>>> +
>>>>>> +    if (type == HPWMI_ORDEREDLIST_TYPE) {
>>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
>>>>>> buf);
>>>>>> +            if (size <= 0)
>>>>>> +                    goto finish_ordered_list;
>>>>>> +
>>>>>> +            pobj = &(obj-
>>>>>>> package.elements[hp_wmi_elements_count[type]]);
>>>>>> +            status = convert_hexstr_to_str(&pobj->string.pointer,
>>>>>> +                                           pobj->string.length, &value,
>>>>>> &value_len);
>>>>>> +            if (ACPI_FAILURE(status))
>>>>>> +                    goto finish_ordered_list;
>>>>>> +
>>>>>> +            /*
>>>>>> +             * 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(&value, value_len, &tmpstr,
>>>>>> &tmp_len);
>>>>>> +            if (ACPI_FAILURE(status))
>>>>>> +                    goto finish_ordered_list;
>>>>>> +
>>>>>> +            part_tmp = tmpstr;
>>>>>> +            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);
>>>>>> +            }
>>>>>> +    }
>>>>>> +
>>>>>> +finish_ordered_list:
>>>>>> +    if (type == HPWMI_ORDEREDLIST_TYPE)
>>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>>>>> +
>>>>>> +    /*
>>>>>> +     * remove trailing comma
>>>>>> +     */
>>>>>> +    if (buf_size > 3)
>>>>>> +            buf[buf_size - 2] = ' ';
>>>>>> +
>>>>>> +    kfree(tmpstr);
>>>>>> +    kfree(value);
>>>>>> +    return snprintf(buf, alloc_size, "%s},\n", buf);
>>>>>> +}
>>>>>> +
>>>>>> +static int append_buffer_elements_to_buffer(union acpi_object *obj,
>>>>>> +                                        char *buf, int alloc_size, enum
>>>>>> hp_wmi_data_type type)
>>>>>> +{
>>>>>> +    int buf_size;
>>>>>> +    int status;
>>>>>> +    char *str = NULL;
>>>>>> +    int i;
>>>>>> +    int j;
>>>>>> +    int integer;
>>>>>> +    int size = 0;
>>>>>> +
>>>>>> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
>>>>>> +            return -EINVAL;
>>>>>> +
>>>>>> +    if (obj->type != ACPI_TYPE_BUFFER)
>>>>>> +            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]);
>>>>>> +
>>>>>> +    for (i = 0; i < 3; i++) {
>>>>>> +            status = get_string_from_buffer((u16 **)&obj-
>>>>>>> buffer.pointer, &str);
>>>>>> +            if (ACPI_SUCCESS(status)) {
>>>>>> +                    /*
>>>>>> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
>>>>>> since
>>>>>> +                     * 'CurrentValue' is reported.
>>>>>> +                     */
>>>>>> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
>>>>>> +                            buf_size = snprintf(buf, alloc_size,
>>>>>> +                                                "%s\t\"%s\": \"%s\",\n",
>>>>>> +                                                buf,
>>>>>> +
>>>>>> hp_wmi_elements[type][i], str);
>>>>>> +            }
>>>>>> +            kfree(str);
>>>>>> +            str = NULL;
>>>>>> +
>>>>>> +    }
>>>>>> +
>>>>>> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
>>>>>> +            if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
>>>>>> +                    status = get_string_from_buffer((u16 **)&obj-
>>>>>>> buffer.pointer, &str);
>>>>>> +                    if (ACPI_SUCCESS(status)) {
>>>>>> +                            /*
>>>>>> +                             * Report "CurrentValue" as "Value"
>>>>>> +                             */
>>>>>> +                            buf_size = snprintf(buf, alloc_size,
>>>>>> +                                                "%s\t\"Value\": \"%s\",\n",
>>>>>> buf, str);
>>>>>> +                    }
>>>>>> +                    kfree(str);
>>>>>> +                    str = NULL;
>>>>>> +                    continue;
>>>>>> +
>>>>>> +            } else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
>>>>>> +                    /*
>>>>>> +                     * Report list of "SupportEncoding"
>>>>>> +                     *
>>>>>> +                     *      "SupportedEncoding": [
>>>>>> +                     *              "utf-16"
>>>>>> +                     *      ],
>>>>>> +                     *
>>>>>> +                     */
>>>>>> +
>>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
>>>>>> +                                        buf, hp_wmi_elements[type][i]);
>>>>>> +                    for (j = 0; j < size; j++) {
>>>>>> +                            status = get_string_from_buffer((u16
>>>>>> **)&obj->buffer.pointer, &str);
>>>>>> +                            if (ACPI_SUCCESS(status)) {
>>>>>> +                                    if (j == size - 1)
>>>>>> +                                            buf_size = snprintf(buf,
>>>>>> alloc_size,
>>>>>> +
>>>>>> "%s\t\t\"%s\"\n", buf, str);
>>>>>> +                                    else
>>>>>> +                                            buf_size = snprintf(buf,
>>>>>> alloc_size,
>>>>>> +
>>>>>> "%s\t\t\"%s\",\n", buf, str);
>>>>>> +                            }
>>>>>> +                            kfree(str);
>>>>>> +                            str = NULL;
>>>>>> +                    }
>>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>>>>> +                    continue;
>>>>>> +            }
>>>>>> +
>>>>>> +            size = 0;
>>>>>> +            status = get_integer_from_buffer((int **)&obj-
>>>>>>> buffer.pointer, &integer);
>>>>>> +            if (ACPI_SUCCESS(status)) {
>>>>>> +                    /*
>>>>>> +                     * Report "PrerequisiteSize" and "Size" values
>>>>>> +                     *      ...
>>>>>> +                     *      "PrerequisiteSize": 1,
>>>>>> +                     *      ...
>>>>>> +                     *      "Size": 2,
>>>>>> +                     *      ...
>>>>>> +                     */
>>>>>> +                    if (i == 7)
>>>>>> +                            size = integer;
>>>>>> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
>>>>>> == 10)
>>>>>> +                            size = integer;
>>>>>> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
>>>>>> 9)
>>>>>> +                            size = integer;
>>>>>> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
>>>>>> 11)
>>>>>> +                            size = integer;
>>>>>> +
>>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
>>>>>> %d,\n", buf,
>>>>>> +                                        hp_wmi_elements[type][i],
>>>>>> integer);
>>>>>> +            }
>>>>>> +
>>>>>> +            if (size > 20)
>>>>>> +                    pr_warn("%s exceeded the maximum number of
>>>>>> elements supported or data may be malformed\n",
>>>>>> +                            hp_wmi_elements[type][i]);
>>>>>> +
>>>>>> +            if (ACPI_SUCCESS(status) && i == 7) {
>>>>>> +                    buf_size = snprintf(buf, alloc_size,
>>>>>> "%s\t\"Prerequisites\": [\n", buf);
>>>>>> +                    for (j = 0; j < size; j++) {
>>>>>> +                            status = get_string_from_buffer((u16
>>>>>> **)&obj->buffer.pointer, &str);
>>>>>> +                            if (ACPI_SUCCESS(status)) {
>>>>>> +                                    buf_size = snprintf(buf, alloc_size,
>>>>>> "%s\t\t\"%s\"", buf, str);
>>>>>> +
>>>>>> +                                    if (j == size - 1)
>>>>>> +                                            buf_size = snprintf(buf,
>>>>>> alloc_size, "%s\n", buf);
>>>>>> +                                    else
>>>>>> +                                            buf_size = snprintf(buf,
>>>>>> alloc_size, "%s,\n", buf);
>>>>>> +
>>>>>> +                            }
>>>>>> +                            kfree(str);
>>>>>> +                            str = NULL;
>>>>>> +                    }
>>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>>>>> +            }
>>>>>> +    }
>>>>>> +
>>>>>> +    if (type == HPWMI_ENUMERATION_TYPE || type ==
>>>>>> HPWMI_ORDEREDLIST_TYPE) {
>>>>>> +            if (type == HPWMI_ENUMERATION_TYPE)
>>>>>> +                    buf_size = snprintf(buf, alloc_size,
>>>>>> "%s\t\"PossibleValues\": [\n", buf);
>>>>>> +            else
>>>>>> +                    buf_size = snprintf(buf, alloc_size,
>>>>>> "%s\t\"Elements\": [\n", buf);
>>>>>> +
>>>>>> +            for (i = 0; i < size; i++) {
>>>>>> +                    status = get_string_from_buffer((u16 **)&obj-
>>>>>>> buffer.pointer, &str);
>>>>>> +                    if (ACPI_SUCCESS(status)) {
>>>>>> +                            buf_size = snprintf(buf, alloc_size,
>>>>>> "%s\t\t\"%s\"", buf, str);
>>>>>> +
>>>>>> +                            if (i == size - 1)
>>>>>> +                                    buf_size = snprintf(buf, alloc_size,
>>>>>> "%s\n", buf);
>>>>>> +                            else
>>>>>> +                                    buf_size = snprintf(buf, alloc_size,
>>>>>> "%s,\n", buf);
>>>>>> +
>>>>>> +                    }
>>>>>> +                    kfree(str);
>>>>>> +                    str = NULL;
>>>>>> +            }
>>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
>>>>>> +    }
>>>>>> +
>>>>>> +    /*
>>>>>> +     * remove trailing comma
>>>>>> +     */
>>>>>> +    if (buf_size > 3)
>>>>>> +            buf[buf_size - 2] = ' ';
>>>>>> +
>>>>>> +    return snprintf(buf, alloc_size, "%s},\n", buf);
>>>>>> +}
>>>>>> +
>>>>>> +static int hp_bios_settings_free_buffer(void)
>>>>>> +{
>>>>>> +    mutex_lock(&buf_mutex);
>>>>>> +    kfree(hp_bios_settings_buffer);
>>>>>> +    settings_buffer_size = 0;
>>>>>> +    buf_alloc_size = 0;
>>>>>> +    mutex_unlock(&buf_mutex);
>>>>>> +
>>>>>> +    return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
>>>>>> +                                       int *alloc_size,
>>>>>> +                                       struct mutex *buf_mutex)
>>>>>> +{
>>>>>> +    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(buf_mutex);
>>>>>> +            new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
>>>>>> +            mutex_unlock(buf_mutex);
>>>>>> +            if (new_buf) {
>>>>>> +                    mutex_lock(buf_mutex);
>>>>>> +                    *buf = new_buf;
>>>>>> +                    *alloc_size = ksize(new_buf);
>>>>>> +                    mutex_unlock(buf_mutex);
>>>>>> +            } else {
>>>>>> +                    hp_bios_settings_free_buffer();
>>>>>> +                    ret = -ENOMEM;
>>>>>> +            }
>>>>>> +    }
>>>>>> +
>>>>>> +    return ret;
>>>>>> +}
>>>>>> +
>>>>>> +static int append_settings_to_buffer(char *guid, int type, char **buf,
>>>>>> +                                 int *buf_size, int *alloc_size,
>>>>>> +                                 struct mutex *buf_mutex)
>>>>>> +{
>>>>>> +    union acpi_object *obj = NULL;
>>>>>> +    int ret = 0;
>>>>>> +    int status = 0;
>>>>>> +    int instance = 0;
>>>>>> +
>>>>>> +    /*
>>>>>> +     * Query all the instances until to receive a AE_BAD_PARAMETER
>>>>>> +     */
>>>>>> +    do {
>>>>>> +            ret = hp_wmi_get_setting_object(guid, instance++, &obj);
>>>>>> +            if (ACPI_SUCCESS(ret) && obj != NULL) {
>>>>>> +                    status = 0;
>>>>>> +                    if (obj->type == ACPI_TYPE_PACKAGE) {
>>>>>> +                            mutex_lock(buf_mutex);
>>>>>> +                            status =
>>>>>> append_package_elements_to_buffer(obj,
>>>>>> +                                                    *buf, *alloc_size,
>>>>>> type);
>>>>>> +                            if (status > 0)
>>>>>> +                                    *buf_size = status;
>>>>>> +                            mutex_unlock(buf_mutex);
>>>>>> +
>>>>>> +                    } else if (obj->type == ACPI_TYPE_BUFFER) {
>>>>>> +                            mutex_lock(buf_mutex);
>>>>>> +                            status =
>>>>>> append_buffer_elements_to_buffer(obj,
>>>>>> +                                                    *buf, *alloc_size,
>>>>>> type);
>>>>>> +                            if (status > 0)
>>>>>> +                                    *buf_size = status;
>>>>>> +                            mutex_unlock(buf_mutex);
>>>>>> +
>>>>>> +                    } else
>>>>>> +                            pr_warn("The retrieved object type(%d) is
>>>>>> not supported yet\n",
>>>>>> +                                    obj->type);
>>>>>> +
>>>>>> +                    ret = hp_bios_settings_realloc_buffer(buf, buf_size,
>>>>>> alloc_size, buf_mutex);
>>>>>> +            }
>>>>>> +
>>>>>> +            kfree(obj);
>>>>>> +            obj = NULL;
>>>>>> +
>>>>>> +    } while (ACPI_SUCCESS(ret));
>>>>>> +
>>>>>> +    /*
>>>>>> +     * AE_BAD_PARAMETER means the loop ended by exhaustion
>>>>>> +     */
>>>>>> +    if (ret == AE_BAD_PARAMETER)
>>>>>> +            ret = 0;
>>>>>> +
>>>>>> +    return ret;
>>>>>> +}
>>>>>> +
>>>>>> +static int hp_bios_settings_fill_buffer(void)
>>>>>> +{
>>>>>> +    int status = 0;
>>>>>> +    int initial_buffer_size = 20 * PAGE_SIZE;
>>>>>> +
>>>>>> +    mutex_lock(&buf_mutex);
>>>>>> +    hp_bios_settings_buffer = kmalloc(initial_buffer_size,
>>> GFP_KERNEL);
>>>>>> +    mutex_unlock(&buf_mutex);
>>>>>> +    if (!hp_bios_settings_buffer)
>>>>>> +            return -ENOMEM;
>>>>>> +
>>>>>> +    mutex_lock(&buf_mutex);
>>>>>> +    buf_alloc_size = ksize(hp_bios_settings_buffer);
>>>>>> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
>>>>>> +                                    buf_alloc_size, "[\n");
>>>>>> +    mutex_unlock(&buf_mutex);
>>>>>> +
>>>>>> +    status = append_settings_to_buffer(HPWMI_STRING_GUID,
>>>>>> +            HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
>>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
>>>>>> +    if (ACPI_FAILURE(status))
>>>>>> +            pr_err("error 0x%x occurred retrieving string instances\n",
>>>>>> status);
>>>>>> +
>>>>>> +    status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
>>>>>> +            HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
>>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
>>>>>> +    if (ACPI_FAILURE(status))
>>>>>> +            pr_err("error 0x%x occurred retrieving integer instances\n",
>>>>>> status);
>>>>>> +
>>>>>> +    status =
>>> append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
>>>>>> +            HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
>>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
>>>>>> +    if (ACPI_FAILURE(status))
>>>>>> +            pr_err("error 0x%x occurred retrieving enumeration
>>>>>> instances\n", status);
>>>>>> +
>>>>>> +    status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
>>>>>> +            HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
>>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
>>>>>> +    if (ACPI_FAILURE(status))
>>>>>> +            pr_err("error 0x%x occurred retrieving ordered list
>>>>>> instances\n", status);
>>>>>> +
>>>>>> +    status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
>>>>>> +            HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
>>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
>>>>>> +    if (ACPI_FAILURE(status))
>>>>>> +            pr_err("error 0x%x occurred retrieving password list
>>>>>> instances\n", status);
>>>>>> +
>>>>>> +    mutex_lock(&buf_mutex);
>>>>>> +    /*
>>>>>> +     * remove trailing comma
>>>>>> +     */
>>>>>> +    if (settings_buffer_size >= 3) {
>>>>>> +            if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
>>>>>> +                    hp_bios_settings_buffer[settings_buffer_size - 2] = '
>>>>>> ';
>>>>>> +    }
>>>>>> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
>>>>>> +                                    buf_alloc_size, "%s]\n",
>>>>>> +                                    hp_bios_settings_buffer);
>>>>>> +    mutex_unlock(&buf_mutex);
>>>>>> +
>>>>>> +    return settings_buffer_size;
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * sure_admin_settings_read - Return a formatted file with settings
>>>>>> + *                              and possible options read from BIOS
>>>>>> + *
>>>>>> + * @filp:  Pointer to file of settings read from BIOS
>>>>>> + * @kobj:  Pointer to a kernel object of things that show up as directory
>>> in
>>>>>> the sysfs filesystem.
>>>>>> + * @attr:  Pointer to list of read attributes
>>>>>> + * @buf:   Pointer to buffer
>>>>>> + * @off:   File current offset
>>>>>> + * @count: Buffer size
>>>>>> + *
>>>>>> + * Returns the count of unicode chars read if successful, otherwise
>>>>>> + *          -ENOMEM unable to allocate memory
>>>>>> + *          -EINVAL buffer not allocated or too small
>>>>>> + *
>>>>>> + */
>>>>>> +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 >= settings_buffer_size && settings_buffer_size > 0) {
>>>>>> +            hp_bios_settings_free_buffer();
>>>>>> +            return 0;
>>>>>> +    }
>>>>>> +
>>>>>> +    /* clear the buffer whenever the read starts from the first position
>>>>>> */
>>>>>> +    if (off == 0 && settings_buffer_size > 0)
>>>>>> +            hp_bios_settings_free_buffer();
>>>>>> +
>>>>>> +    if (settings_buffer_size == 0)
>>>>>> +            hp_bios_settings_fill_buffer();
>>>>>> +
>>>>>> +    mutex_lock(&buf_mutex);
>>>>>> +    ret = memory_read_from_buffer(buf, count, &off,
>>>>>> hp_bios_settings_buffer,
>>>>>> +                                  settings_buffer_size);
>>>>>> +    mutex_unlock(&buf_mutex);
>>>>>> +
>>>>>> +    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
>>>>>> + */
>>>>>> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
>>>>>> +{
>>>>>> +    int len = strlen(str);
>>>>>> +
>>>>>> +    /*
>>>>>> +     * Add null character when reading an empty string
>>>>>> +     */
>>>>>> +    if (len == 0) {
>>>>>> +            *p++ = 2;
>>>>>> +            *p++ = (u8)0x00;
>>>>>> +            return p;
>>>>>> +    }
>>>>>> +    *p++ = len * 2;
>>>>>> +    utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
>>>>>> +    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
>>>>>> + */
>>>>>> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 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(HPWMI_SETBIOSSETTING_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;
>>>>>> +}
>>>>>> +
>>>>>> +/* Sure Admin Functions */
>>>>>> +
>>>>>> +#define UTF_PREFIX                  ((unsigned char *)"<utf-16/>")
>>>>>> +#define BEAM_PREFIX                 ((unsigned char
>>>>>> *)"<BEAM/>")
>>>>>> +
>>>>>> +/*
>>>>>> + * sure_admin_settings_write - Write the contents of a formatted file
>>>>>> + *                               with settings and performs the logic
>>>>>> + *                               to change any settings in BIOS.
>>>>>> + *
>>>>>> + * @filp:  Pointer to file of settings to be written to BIOS
>>>>>> + * @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 write operation
>>>>>> + * @buf:   Pointer to buffer
>>>>>> + * @off:   File current offset
>>>>>> + * @count: Buffer size
>>>>>> + *
>>>>>> + *
>>>>>> + * Returns the count of unicode characters written to BIOS if
>>> successful,
>>>>>> otherwise
>>>>>> + *          -ENOMEM unable to allocate memory
>>>>>> + *          -EINVAL buffer not allocated or too small
>>>>>> + *
>>>>>> + */
>>>>>> +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;
>>>>>> +    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 out_free;
>>>>>> +    }
>>>>>> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>>>>>> +    part = strsep(&buf, ",");
>>>>>> +    if (!part) {
>>>>>> +            status = -EINVAL;
>>>>>> +            goto out_free;
>>>>>> +    }
>>>>>> +
>>>>>> +    /* Add extra buffer space when encountering an empty string */
>>>>>> +    if (!strlen(part))
>>>>>> +            buffer_size += sizeof(unsigned short);
>>>>>> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>>>>>> +    part = strsep(&buf, ",");
>>>>>> +    if (!part) {
>>>>>> +            status = -EINVAL;
>>>>>> +            goto out_free;
>>>>>> +    }
>>>>>> +    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 out_free;
>>>>>> +
>>>>>> +            tmpstr = ascii_to_utf16_unicode(tmpstr, part);
>>>>>> +            kfree(part);
>>>>>> +    }
>>>>>> +
>>>>>> +    part = strsep(&buf, ",");
>>>>>> +    if (part) {
>>>>>> +            status = -EINVAL;
>>>>>> +            goto out_free;
>>>>>> +    }
>>>>>> +    status = hp_wmi_set_bios_setting(buffer, buffer_size);
>>>>>> +    if (ACPI_FAILURE(status))
>>>>>> +            status = -EINVAL;
>>>>>> +
>>>>>> +out_free:
>>>>>> +    kfree(buffer);
>>>>>> +    if (ACPI_SUCCESS(status))
>>>>>> +            return count;
>>>>>> +    return status;
>>>>>> +}
>>>>>> +
>>>>>> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
>>>>>> +
>>>>>> +static struct bin_attribute *sure_admin_binattrs[] = {
>>>>>> +    &sure_admin_settings,
>>>>>> +    NULL,
>>>>>> +};
>>>>>> +
>>>>>> +static const struct attribute_group sure_admin_group = {
>>>>>> +    .name = "sure_admin",
>>>>>> +    .bin_attrs = sure_admin_binattrs,
>>>>>> +};
>>>>>> +
>>>>>>  static DEVICE_ATTR_RO(display);
>>>>>>  static DEVICE_ATTR_RO(hddtemp);
>>>>>>  static DEVICE_ATTR_RW(als);
>>>>>> @@ -1050,6 +2026,7 @@ static const struct attribute_group
>>>>>> *hp_wmi_groups[] = {
>>>>>>      &hp_wmi_group,
>>>>>>      &spm_group,
>>>>>>      &sure_start_group,
>>>>>> +    &sure_admin_group,
>>>>>>      NULL,
>>>>>>  };
>>>>>>
>>>>>> --
>>>>>> 2.25.1
>>>>
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-08  9:21             ` Hans de Goede
@ 2022-04-08 14:46               ` Jorge Lopez
  2022-04-08 14:54                 ` Limonciello, Mario
  0 siblings, 1 reply; 25+ messages in thread
From: Jorge Lopez @ 2022-04-08 14:46 UTC (permalink / raw)
  To: Hans de Goede; +Cc: Limonciello, Mario, platform-driver-x86

On Fri, Apr 8, 2022 at 4:21 AM Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi Jorge,
>
> On 4/7/22 15:44, Jorge Lopez wrote:
> > Hans, Mario,
> >
> > The code links make references to code that implements the new
> > interfaces but there’s
> > still code in the kernel that uses the old ones.
>
> I'm not sure what you mean with "uses the old ones" there never
> has been any kernel drivers for changing BIOS settings before
> the dell and lenovo drivers were merged.

"uses the old ones" statement means that there are drivers on the tree
that change BIOS settings without having to convert to the new
standards.  hp-wmi remained unsupported for many years so I can
understand why the security features need to use the standardized API.

>
> Sure there are generic mechanisms like chardev-s and ioctls which
> are used for a whole bunch of things. But AFAIK there never was
> an API specifically for changing BIOS settings before.
>
> > I do agree we should
> > be forward looking
> > and want to be good participants in the kernel development, but can’t
> > let our immediate
> > business needs be impacted with opportunities to enhance the driver to
> > take advantage
> > of the latest kernel features.
> >
> > Rewriting those security features will impact customer business
> > datelines requiring
> > HP to provide private releases as the kernel version changes.   The
> > requested changes
> > will impact products in the market and HP ability to help customers to
> > migrate to Linux
> > from Windows products.
>
> This sounds like you are saying that you are already shipping
> a version of the driver with the non-standard API to customers.
> Shipping code to customers before even proposing it upstream is
> HP own choice and the results of that as such are HP's
> responsibility.
>
The products shipped to customers are Windows products and customers
are accustomed to how the data is reported and set.  The goal for the
new security features in Linux is to help those customers migrate to
Linux with little or no change to their scripts/tools.

> You cannot just say we are already shipping this so we need
> the upstream kernel to support this non standard API, that is
> not how upstream kernel development works.
>
> I realize that HP is new to working directly with the upstream kernel
> community and I realize that being told that the API which you are
> already using cannot be used for upstreaming your driver is not what
> you want to hear.
>
> But that does not change that I cannot accept a driver which does not
> implement the standard API which the upstream kernel community has
> agreed upon for this functionality.
>
> Or as Mario very elegantly put it:
>
> 'Keep in mind that from an upstream kernel perspective this driver is "new".
> There is no requirements from the upstream perspective to
> keep your old interfaces in place from when it was out of tree.'
>
> > It is because of the immediate business needs, avoiding impacting our
> > customers/products,
> > and rewriting  enhancements to the driver that I need to propose an
> > interim solution.
> >
> > My proposal is to introduce a read/write value accessible in the user
> > space to control how
> > the driver reports and handles BIOS settings and values.  The new
> > configuration features
> > will be gradually disabled  as they are converted to use the standardized API.
> > It is like the configuration flag used to overcome the tablet detection problem
> > introduced in the past.   The changes solely affect the HP WMI driver.
> > This option will help us
> > move forward for this release and give us time to make the necessary
> > changes to both
> > the driver and support applications.
> >
> > Please let me know if this is a viable interim solution.
>
> First of all to be very clear, any code going upstream must support
> the standard API:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/ABI/testing/sysfs-class-firmware-attributes
>
> from day one. I'm not really enthusiastic about the concept of also
> supporting the API which you have been using out of tree so far, but
> I guess that Mario's suggestion to offer a Kconfig option which
> when enabled offers this API under debugfs might be an acceptible
> compromise. I would need to see the actual code for that though to
> see if this is acceptable.
>
> And there would need to be a clear cut-of date document after which
> the code to support the old API will be removed.
>
> > If it is not possible, I need to ask where the actual written
> > requirement is found so I can
> > include them in the business justification for changes and release
> > delays to management.
>
> I'm not sure if this is written down somewhere, but certainly
> you will agree that if you were submitting a driver for a soundcard
> that that should use the existing ALSA userspace API for sound so
> that it would just work with the existing userspace sound support.
>
> This is the same. If an existing standardized userspace API exists
> for a certain functionality then that userspace API _must_ be used,
> AFAIK this is not explictly written down anywhere because it is just
> very much common sense.

I completely agree with your comments and request for the driver to
implement the standardized API.  hp-wmi remained unsupported for many
years so I can understand why the security features need to use the
standardized API.  I am having conversations with other teams on how
to move forward with the standard API and how the data is handled and
reported.   We will submit a new set of patches utilizing the new
standard at a later time.   Would it be accurate to state that any
extensions to the standardized API model are acceptable, Correct?

Regards,

Jorge
>
> Regards,
>
> Hans
>
>
>
>
>
>
> > On Tue, Apr 5, 2022 at 12:13 PM Limonciello, Mario
> > <Mario.Limonciello@amd.com> wrote:
> >>
> >> [Public]
> >>
> >>
> >>
> >>> -----Original Message-----
> >>> From: Jorge Lopez <jorgealtxwork@gmail.com>
> >>> Sent: Tuesday, April 5, 2022 11:52
> >>> To: Hans de Goede <hdegoede@redhat.com>
> >>> Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-driver-
> >>> x86@vger.kernel.org
> >>> Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> >>>
> >>> Hi Hans,
> >>>
> >>> On Tue, Apr 5, 2022 at 6:54 AM Hans de Goede <hdegoede@redhat.com>
> >>> wrote:
> >>>>
> >>>> Hi,
> >>>>
> >>>> On 4/4/22 23:59, Limonciello, Mario wrote:
> >>>>> [Public]
> >>>>>
> >>>>>
> >>>>>
> >>>>>> -----Original Message-----
> >>>>>> From: Jorge Lopez <jorgealtxwork@gmail.com>
> >>>>>> Sent: Monday, April 4, 2022 15:36
> >>>>>> To: platform-driver-x86@vger.kernel.org
> >>>>>> Subject: [PATCH v1 5/6] Sure Admin Security Feature
> >>>>>>
> >>>>>> 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. Behind the scenes, Sure Admin uses Secure
> >>> Platform
> >>>>>> Management (SPM) and WMI
> >>>>>>
> >>>>>> 'settings' is a file associated with Sure Admin. BIOS settings can be
> >>>>>> read or written through the Sure Admin settings file in sysfs
> >>>>>>
> >>>>>>      /sys/devices/platform/hp-wmi/sure_admin/settings
> >>>>>>
> >>>>>> 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"
> >>>>>>              ]
> >>>>>>      }
> >>>>>>
> >>>>>
> >>>>> This sounds like it has re-invented /sys/class/firmware-attributes.
> >>>>>
> >>>>> Shouldn't you adopt that API?
> >>>>
> >>>> I fully agree. Jorge as I already indicated in our off-list
> >>>> conversation when you initially started working on this
> >>>> feature, we already have a standardized API for querying/changing
> >>>> BIOS settings from within Linux:
> >>>>
> >>>
> >>> I agree that changing the BIOS settings from within Linux could
> >>> utilize the new methodology,  I will need to look closely at the
> >>> requirements before I can proceed to make the changes.
> >>> Keep in mind authentication of the values is done by BIOS.  No Linux
> >>> process validates any data name, value, or auth token; only BIOS.  All
> >>> data written to the sysfs file is not validated, it is just forward to
> >>> BIOS.  See spm_kek_store and spm_sk_store functions.
> >>
> >> That's fine, and it's a safer design to have BIOS validate it.
> >>
> >>> One point I must make clear when updating BIOS settings.  any  NOT
> >>> read-only BIOS settings can be changed by the application at any time.
> >>>    This list of settings changes from one system to another.
> >>
> >> Right.
> >>
> >>>
> >>> I am in disagreement with reading the settings.  hp-wmi does not read
> >>> one value at a time. It reads all values exposed by BIOS.  See
> >>> attached sample output.
> >>
> >> The settings can all be read at initialization time for the driver and cached
> >> then.
> >>
> >>> The method for how all BIOS settings are reported needs to match the
> >>> method how Windows products do it.  It is a requirement to start
> >>> migrating customers from Windows to Linux while minimizing how BIOS
> >>> data is reported.
> >>
> >> Because we have a standardized API in Linux for this, I think it's best to abstract
> >> this behind a userspace application/script.  If they expect to see it in the format you
> >> showed, the userspace application can take the data from Linux and package it that
> >> way.
> >>
> >> You'll have richer libraries and languages and tools to work from when doing this too.
> >> It should make it a lot less painful.
> >>
> >>>
> >>> I will investigate the new API and bring it to the team's attention.
> >>>
> >>>>
> >>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> >>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> >>> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> >>> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> >>> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> >>> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> >>> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> >>> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> >>> D&amp;reserved=0
> >>>>
> >>>> and any new code (such as this patch) which implements BIOS
> >>>> setting changing MUST follow this standardized API (extending
> >>>> it where necessary).
> >>>>
> >>>> I'm sorry but this patch is not acceptable in its current form,
> >>>> it needs to be *completely rewritten* to implement:
> >>>>
> >>>>
> >>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> >>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> >>> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> >>> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> >>> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> >>> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> >>> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> >>> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> >>> D&amp;reserved=0
> >>>>
> >>>> See:
> >>>>
> >>>>
> >>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> >>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> >>> 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fdell%2Fdell-wmi-
> >>> sysman&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8f
> >>> ea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> >>> 7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> >>> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> >>> mp;sdata=z5jmH7ECYBeLcndQ2vfHaUuyE04Eaf1Lymh6BjnyJ%2Fk%3D&amp;r
> >>> eserved=0
> >>>>
> >>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> >>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> >>> 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fthink-
> >>> lmi.c&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea
> >>> 104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> >>> 0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> >>> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> >>> sdata=5n6w9LEB2iWpj1cOQP6Ngz94AqP1Bu4vu8T0EdN%2FThU%3D&amp;re
> >>> served=0
> >>>>
> >>>> for example code / for 2 drivers from other vendors already
> >>>> implementing this.
> >>>>
> >>>> The same applies to the:
> >>>>
> >>>> "[PATCH v1 3/6] Secure Platform Management Security Feature"
> >>>>
> >>>> this needs to be implemented as
> >>>> a /sys/class/firmware-attributes/*/authentication/
> >>>> authentication method, see for example these Lenovo specific
> >>>> addition to the /sys/class/firmware-attributes/*/authentication/
> >>>> userspace API for similar functionality on Lenovo Think* devices:
> >>>>
> >>>>
> >>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> >>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> >>> 2Fcommit%2F%3Fid%3D06384573a3e8335ac6797577e545c33dbf91b490&amp;
> >>> data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea1040342827
> >>> 08da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C63784
> >>> 7743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLC
> >>> JQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=eldS
> >>> 4H3Z%2BAyL%2FG%2FO9W9rDGC37yh5sGgtUhpKdUAoSmA%3D&amp;reser
> >>> ved=0
> >>>>
> >>>> I'll merge patches 1-2 sometime this week since those are
> >>>> fine and it will be good to have those "out of the way",
> >>>> but the rest of the series will need to be rewritten
> >>>> taken the above comments into account.
> >>>
> >>> v1-0003-Sure-Start-Security-Feature.patch  reports the number of audit
> >>> logs available and reports them when read.    it does not read/write
> >>> BIOS settings hence it does not fall within the same category as
> >>> patches v1-0002-Secure-Platform-Management-Security-Feature.patch and
> >>> v1-0004-Sure-Admin-Security-Feature.patch
> >>> Do you agree?
> >>>
> >>>>
> >>>> Regards,
> >>>>
> >>>> Hans
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>
> >>>>>> This feature requires "Update hp_wmi_group to simplify feature
> >>>>>> addition" patch.
> >>>>>>
> >>>>>> All changes were validated on a HP ZBook Workstation,
> >>>>>> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> >>>>>>
> >>>>>> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> >>>>>>
> >>>>>> ---
> >>>>>> Based on the latest platform-drivers-x86.git/for-next
> >>>>>> ---
> >>>>>>  drivers/platform/x86/hp-wmi.c | 977
> >>>>>> ++++++++++++++++++++++++++++++++++
> >>>>>>  1 file changed, 977 insertions(+)
> >>>>>>
> >>>>>> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-
> >>> wmi.c
> >>>>>> index 918e3eaf1b67..b72ca18b77a6 100644
> >>>>>> --- a/drivers/platform/x86/hp-wmi.c
> >>>>>> +++ b/drivers/platform/x86/hp-wmi.c
> >>>>>> @@ -27,6 +27,7 @@
> >>>>>>  #include <linux/rfkill.h>
> >>>>>>  #include <linux/string.h>
> >>>>>>  #include <linux/dmi.h>
> >>>>>> +#include <linux/nls.h>
> >>>>>>
> >>>>>>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
> >>>>>>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
> >>>>>> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-
> >>>>>> 3D44E2C707E4");
> >>>>>>
> >>>>>>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-
> >>> ACCDC67EF61C"
> >>>>>>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-
> >>> 3D44E2C707E4"
> >>>>>> +
> >>>>>>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
> >>>>>>
> >>>>>> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-
> >>> 6A1B8106F83C"
> >>>>>> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
> >>>>>> E293ADB9BF05"
> >>>>>> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-
> >>>>>> 4A3C09E75133"
> >>>>>> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-
> >>>>>> 7045CB4DA745"
> >>>>>> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
> >>>>>> 015176049E2D"
> >>>>>> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-
> >>>>>> C7CB9B4B8D5E"
> >>>>>> +
> >>>>>>  /* DMI board names of devices that should use the omen specific path
> >>> for
> >>>>>>   * thermal profiles.
> >>>>>>   * This was obtained by taking a look in the windows omen command
> >>> center
> >>>>>> @@ -1025,6 +1034,973 @@ static const struct attribute_group
> >>>>>> sure_start_group = {
> >>>>>>      .attrs = sure_start_attrs,
> >>>>>>  };
> >>>>>>
> >>>>>> +
> >>>>>> +static 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;
> >>>>>> +    int  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));
> >>>>>> +            ret = kstrtoint(tmp, 16, &ch);
> >>>>>> +            if (ret) {
> >>>>>> +                    new_len = 0;
> >>>>>> +                    break;
> >>>>>> +            }
> >>>>>> +
> >>>>>> +            if (ch == '\\')
> >>>>>> +                    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;
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    if (ret)
> >>>>>> +            kfree(new_str);
> >>>>>> +    return ret;
> >>>>>> +}
> >>>>>> +
> >>>>>> +/*
> >>>>>> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and
> >>> instance
> >>>>>> + *
> >>>>>> + * @guid:   GUID associated with the ACPI list of managed objects
> >>>>>> + * @instance:       Instance index to query on the ACPI list
> >>>>>> + * @obj:    The output ACPI object of type ACPI_TYPE_PACKAGE
> >>>>>> + *          or ACPI_TYPE_BUFFER (freed by the callee)
> >>>>>> + *
> >>>>>> + * Returns  zero on success.  Otherwise,an error inherited from
> >>>>>> + *          wmi_query_block(). It returns a obj by parameter if
> >>>>>> + *          the query returned object of type buffer or package,
> >>>>>> + *          otherwise, a null obj is returned.
> >>>>>> + *
> >>>>>> + * Note: obj should be freed by the callee once it is finished working
> >>> with it
> >>>>>> + */
> >>>>>> +static int hp_wmi_get_setting_object(char *guid, int instance,
> >>>>>> +                            union acpi_object **obj)
> >>>>>> +{
> >>>>>> +    struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL
> >>>>>> };
> >>>>>> +    union acpi_object *tmp = NULL;
> >>>>>> +    int ret;
> >>>>>> +
> >>>>>> +    ret = wmi_query_block(guid, instance, &output);
> >>>>>> +    if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
> >>>>>> +            tmp = output.pointer;
> >>>>>> +            if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
> >>>>>> ACPI_TYPE_PACKAGE)
> >>>>>> +                    *obj = output.pointer;
> >>>>>> +            else {
> >>>>>> +                    kfree(tmp);
> >>>>>> +                    *obj = NULL;
> >>>>>> +            }
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    return ret;
> >>>>>> +}
> >>>>>> +
> >>>>>> +
> >>>>>> +static 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;
> >>>>>> +
> >>>>>> +    if (size == 0)
> >>>>>> +            goto cleanup_exit;
> >>>>>> +
> >>>>>> +    for (i = 0; i < size; i++)
> >>>>>> +            if (ptr[i] == '\\')
> >>>>>> +                    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);
> >>>>>> +
> >>>>>> +    if (escape == 0) {
> >>>>>> +            ptr += (ptrlen / 2);
> >>>>>> +            goto cleanup_exit;
> >>>>>> +    }
> >>>>>> +    /*
> >>>>>> +     * Convert escape characters only when found
> >>>>>> +     */
> >>>>>> +    for (i = 0; i < size; i++) {
> >>>>>> +            if (*ptr == '\\')
> >>>>>> +                    output[i++] = '\\';
> >>>>>> +            output[i] = *ptr;
> >>>>>> +            ptr++;
> >>>>>> +    }
> >>>>>> +
> >>>>>> +cleanup_exit:
> >>>>>> +    *buffer = ptr;
> >>>>>> +    return 0;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int get_integer_from_buffer(int **buffer, int *integer)
> >>>>>> +{
> >>>>>> +    int *ptr = PTR_ALIGN(*buffer, 4);
> >>>>>> +    *integer = *(ptr++);
> >>>>>> +    *buffer = ptr;
> >>>>>> +    return 0;
> >>>>>> +}
> >>>>>> +
> >>>>>> +
> >>>>>> +// Sure Admin functions
> >>>>>> +enum hp_wmi_data_type {
> >>>>>> +    HPWMI_STRING_TYPE,
> >>>>>> +    HPWMI_INTEGER_TYPE,
> >>>>>> +    HPWMI_ENUMERATION_TYPE,
> >>>>>> +    HPWMI_ORDEREDLIST_TYPE,
> >>>>>> +    HPWMI_PASSWORD_TYPE,
> >>>>>> +};
> >>>>>> +
> >>>>>> +#define HP_WMI_COMMON_ELEMENTS      \
> >>>>>> +    "Name", \
> >>>>>> +    "Value",        \
> >>>>>> +    "Path", \
> >>>>>> +    "IsReadOnly",   \
> >>>>>> +    "DisplayInUI",  \
> >>>>>> +    "RequiresPhysicalPresence",     \
> >>>>>> +    "Sequence",     \
> >>>>>> +    "PrerequisiteSize",     \
> >>>>>> +    "SecurityLevel"
> >>>>>> +
> >>>>>> +const char *hp_wmi_string_elements[] = {
> >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> >>>>>> +    "MinLength",
> >>>>>> +    "MaxLength"
> >>>>>> +};
> >>>>>> +
> >>>>>> +const char *hp_wmi_integer_elements[] = {
> >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> >>>>>> +    "LowerBound",
> >>>>>> +    "UpperBound",
> >>>>>> +    "IntValue"
> >>>>>> +};
> >>>>>> +
> >>>>>> +const char *hp_wmi_enumeration_elements[] = {
> >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> >>>>>> +    "CurrentValue",
> >>>>>> +    "Size"
> >>>>>> +};
> >>>>>> +
> >>>>>> +const char *hp_wmi_orderedlist_elements[] = {
> >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> >>>>>> +    "Size"
> >>>>>> +};
> >>>>>> +
> >>>>>> +const char *hp_wmi_password_elements[] = {
> >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> >>>>>> +    "MinLength",
> >>>>>> +    "MaxLength",
> >>>>>> +    "Size",
> >>>>>> +    "SupportedEncoding",
> >>>>>> +    "IsSet"
> >>>>>> +};
> >>>>>> +
> >>>>>> +const char **hp_wmi_elements[] = {
> >>>>>> +    hp_wmi_string_elements,
> >>>>>> +    hp_wmi_integer_elements,
> >>>>>> +    hp_wmi_enumeration_elements,
> >>>>>> +    hp_wmi_orderedlist_elements,
> >>>>>> +    hp_wmi_password_elements
> >>>>>> +};
> >>>>>> +
> >>>>>> +const int hp_wmi_elements_count[] = {
> >>>>>> +    ARRAY_SIZE(hp_wmi_string_elements),
> >>>>>> +    ARRAY_SIZE(hp_wmi_integer_elements),
> >>>>>> +    ARRAY_SIZE(hp_wmi_enumeration_elements),
> >>>>>> +    ARRAY_SIZE(hp_wmi_orderedlist_elements),
> >>>>>> +    ARRAY_SIZE(hp_wmi_password_elements)
> >>>>>> +};
> >>>>>> +
> >>>>>> +const char *hp_wmi_classes[] = {
> >>>>>> +    "HPBIOS_BIOSString",
> >>>>>> +    "HPBIOS_BIOSInteger",
> >>>>>> +    "HPBIOS_BIOSEnumeration",
> >>>>>> +    "HPBIOS_BIOSOrderedList",
> >>>>>> +    "HPBIOS_BIOSPassword"
> >>>>>> +};
> >>>>>> +
> >>>>>> +static DEFINE_MUTEX(buf_mutex);
> >>>>>> +static int settings_buffer_size;
> >>>>>> +static int buf_alloc_size;
> >>>>>> +static char *hp_bios_settings_buffer;
> >>>>>> +
> >>>>>> +
> >>>>>> +static int append_package_elements_to_buffer(union acpi_object
> >>> *obj,
> >>>>>> +                                         char *buf, int alloc_size, enum
> >>>>>> hp_wmi_data_type type)
> >>>>>> +{
> >>>>>> +    int i;
> >>>>>> +    union acpi_object *pobj = NULL;
> >>>>>> +    char *value = NULL;
> >>>>>> +    int value_len;
> >>>>>> +    char *tmpstr = NULL;
> >>>>>> +    char *part_tmp = NULL;
> >>>>>> +    int tmp_len = 0;
> >>>>>> +    char *part = NULL;
> >>>>>> +    int status = 0;
> >>>>>> +    int size = 0;
> >>>>>> +    int buf_size;
> >>>>>> +
> >>>>>> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> >>>>>> +            return -EINVAL;
> >>>>>> +
> >>>>>> +    if (obj->type != ACPI_TYPE_PACKAGE)
> >>>>>> +            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]);
> >>>>>> +
> >>>>>> +    for (i = 0; i < 3; i++) {
> >>>>>> +            pobj = &(obj->package.elements[i]);
> >>>>>> +            if (pobj->type == ACPI_TYPE_STRING) {
> >>>>>> +                    status = convert_hexstr_to_str(&pobj-
> >>>>>>> string.pointer,
> >>>>>> +                                                   pobj->string.length,
> >>>>>> &value, &value_len);
> >>>>>> +                    if (ACPI_FAILURE(status))
> >>>>>> +                            continue;
> >>>>>> +                    /*
> >>>>>> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> >>>>>> since
> >>>>>> +                     * 'CurrentValue' is reported.
> >>>>>> +                     */
> >>>>>> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> >>>>>> +                                                "%s\t\"%s\": \"%s\",\n",
> >>>>>> +                                                buf,
> >>>>>> +
> >>>>>> hp_wmi_elements[type][i], value);
> >>>>>> +
> >>>>>> +            }
> >>>>>> +            kfree(value);
> >>>>>> +            value = NULL;
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> >>>>>> +            pobj = &(obj->package.elements[i]);
> >>>>>> +
> >>>>>> +            if (type == HPWMI_ENUMERATION_TYPE &&
> >>>>>> +                i == 9 &&
> >>>>>> +                pobj->type == ACPI_TYPE_STRING) {
> >>>>>> +                    /*
> >>>>>> +                     * Report "CurrentValue" as "Value"
> >>>>>> +                     */
> >>>>>> +                    status = convert_hexstr_to_str(&pobj-
> >>>>>>> string.pointer,
> >>>>>> +                                                   pobj->string.length,
> >>>>>> +                                                   &value, &value_len);
> >>>>>> +                    if (ACPI_FAILURE(status))
> >>>>>> +                            continue;
> >>>>>> +
> >>>>>> +                    buf_size = snprintf(buf, alloc_size,
> >>>>>> +                                        "%s\t\"Value\": \"%s\",\n",
> >>>>>> +                                        buf, value);
> >>>>>> +                    kfree(value);
> >>>>>> +                    value = NULL;
> >>>>>> +
> >>>>>> +            } else if (type == HPWMI_PASSWORD_TYPE &&
> >>>>>> +                       i == 12 &&
> >>>>>> +                       pobj->type == ACPI_TYPE_STRING) {
> >>>>>> +                    /*
> >>>>>> +                     * Report list of "SupportEncoding"
> >>>>>> +                     *
> >>>>>> +                     *      "SupportedEncoding": [
> >>>>>> +                     *              "utf-16"
> >>>>>> +                     *      ],
> >>>>>> +                     *
> >>>>>> +                     */
> >>>>>> +
> >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> >>>>>> +                                        buf, hp_wmi_elements[type][i]);
> >>>>>> +                    while (size--) {
> >>>>>> +                            pobj = &(obj->package.elements[i]);
> >>>>>> +                            status = convert_hexstr_to_str(&pobj-
> >>>>>>> string.pointer,
> >>>>>> +                                                           pobj-
> >>>>>>> string.length,
> >>>>>> +                                                           &value,
> >>>>>> &value_len);
> >>>>>> +                            if (ACPI_FAILURE(status))
> >>>>>> +                                    continue;
> >>>>>> +
> >>>>>> +                            if (size) {
> >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> >>>>>> +                                                        "%s\t\t\"%s\",\n",
> >>>>>> buf, value);
> >>>>>> +                                    i++;
> >>>>>> +                            } else
> >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> >>>>>> +                                                        "%s\t\t\"%s\"\n",
> >>>>>> buf, value);
> >>>>>> +
> >>>>>> +                            kfree(value);
> >>>>>> +                            value = NULL;
> >>>>>> +
> >>>>>> +                    }
> >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >>>>>> +                    continue;
> >>>>>> +
> >>>>>> +            } else if (pobj->type == ACPI_TYPE_INTEGER) {
> >>>>>> +                    /*
> >>>>>> +                     * Report "PrerequisiteSize" and "Size" values
> >>>>>> +                     *      ...
> >>>>>> +                     *      "PrerequisiteSize": 1,
> >>>>>> +                     *      ...
> >>>>>> +                     *      "Size": 2,
> >>>>>> +                     *      ...
> >>>>>> +                     */
> >>>>>> +                    if (i == 7)
> >>>>>> +                            size = pobj->integer.value;
> >>>>>> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> >>>>>> 9)
> >>>>>> +                            size = pobj->integer.value;
> >>>>>> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> >>>>>> == 10)
> >>>>>> +                            size = pobj->integer.value;
> >>>>>> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> >>>>>> 11)
> >>>>>> +                            size = pobj->integer.value;
> >>>>>> +
> >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> >>>>>> %lld,\n", buf,
> >>>>>> +                                        hp_wmi_elements[type][i], pobj-
> >>>>>>> integer.value);
> >>>>>> +            }
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    if (type == HPWMI_ENUMERATION_TYPE) {
> >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\":
> >>>>>> [\n", buf);
> >>>>>> +            for (i = 0; i < size; i++) {
> >>>>>> +                    pobj = &(obj->package.elements[i +
> >>>>>> hp_wmi_elements_count[type]]);
> >>>>>> +
> >>>>>> +                    status = convert_hexstr_to_str(&pobj-
> >>>>>>> string.pointer,
> >>>>>> +                                                   pobj->string.length,
> >>>>>> +                                                   &value, &value_len);
> >>>>>> +                    if (ACPI_FAILURE(status))
> >>>>>> +                            break;
> >>>>>> +
> >>>>>> +                    /*
> >>>>>> +                     * Report list of "PossibleValues" of size
> >>>>>> +                     * "Size"
> >>>>>> +                     *      ...
> >>>>>> +                     *      "Size": 2,
> >>>>>> +                     *      "PossibleValues": [
> >>>>>> +                     *                      "Disable",
> >>>>>> +                     *                      "Enable"]
> >>>>>> +                     */
> >>>>>> +                    if (i == (size - 1))
> >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> >>>>>> +                                                "%s\t\t\"%s\"\n", buf,
> >>>>>> value);
> >>>>>> +                    else
> >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> >>>>>> +                                                "%s\t\t\"%s\",\n", buf,
> >>>>>> value);
> >>>>>> +                    kfree(value);
> >>>>>> +                    value = NULL;
> >>>>>> +            }
> >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    if (type == HPWMI_ORDEREDLIST_TYPE) {
> >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
> >>>>>> buf);
> >>>>>> +            if (size <= 0)
> >>>>>> +                    goto finish_ordered_list;
> >>>>>> +
> >>>>>> +            pobj = &(obj-
> >>>>>>> package.elements[hp_wmi_elements_count[type]]);
> >>>>>> +            status = convert_hexstr_to_str(&pobj->string.pointer,
> >>>>>> +                                           pobj->string.length, &value,
> >>>>>> &value_len);
> >>>>>> +            if (ACPI_FAILURE(status))
> >>>>>> +                    goto finish_ordered_list;
> >>>>>> +
> >>>>>> +            /*
> >>>>>> +             * 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(&value, value_len, &tmpstr,
> >>>>>> &tmp_len);
> >>>>>> +            if (ACPI_FAILURE(status))
> >>>>>> +                    goto finish_ordered_list;
> >>>>>> +
> >>>>>> +            part_tmp = tmpstr;
> >>>>>> +            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);
> >>>>>> +            }
> >>>>>> +    }
> >>>>>> +
> >>>>>> +finish_ordered_list:
> >>>>>> +    if (type == HPWMI_ORDEREDLIST_TYPE)
> >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >>>>>> +
> >>>>>> +    /*
> >>>>>> +     * remove trailing comma
> >>>>>> +     */
> >>>>>> +    if (buf_size > 3)
> >>>>>> +            buf[buf_size - 2] = ' ';
> >>>>>> +
> >>>>>> +    kfree(tmpstr);
> >>>>>> +    kfree(value);
> >>>>>> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int append_buffer_elements_to_buffer(union acpi_object *obj,
> >>>>>> +                                        char *buf, int alloc_size, enum
> >>>>>> hp_wmi_data_type type)
> >>>>>> +{
> >>>>>> +    int buf_size;
> >>>>>> +    int status;
> >>>>>> +    char *str = NULL;
> >>>>>> +    int i;
> >>>>>> +    int j;
> >>>>>> +    int integer;
> >>>>>> +    int size = 0;
> >>>>>> +
> >>>>>> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> >>>>>> +            return -EINVAL;
> >>>>>> +
> >>>>>> +    if (obj->type != ACPI_TYPE_BUFFER)
> >>>>>> +            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]);
> >>>>>> +
> >>>>>> +    for (i = 0; i < 3; i++) {
> >>>>>> +            status = get_string_from_buffer((u16 **)&obj-
> >>>>>>> buffer.pointer, &str);
> >>>>>> +            if (ACPI_SUCCESS(status)) {
> >>>>>> +                    /*
> >>>>>> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> >>>>>> since
> >>>>>> +                     * 'CurrentValue' is reported.
> >>>>>> +                     */
> >>>>>> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> >>>>>> +                                                "%s\t\"%s\": \"%s\",\n",
> >>>>>> +                                                buf,
> >>>>>> +
> >>>>>> hp_wmi_elements[type][i], str);
> >>>>>> +            }
> >>>>>> +            kfree(str);
> >>>>>> +            str = NULL;
> >>>>>> +
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> >>>>>> +            if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
> >>>>>> +                    status = get_string_from_buffer((u16 **)&obj-
> >>>>>>> buffer.pointer, &str);
> >>>>>> +                    if (ACPI_SUCCESS(status)) {
> >>>>>> +                            /*
> >>>>>> +                             * Report "CurrentValue" as "Value"
> >>>>>> +                             */
> >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> >>>>>> +                                                "%s\t\"Value\": \"%s\",\n",
> >>>>>> buf, str);
> >>>>>> +                    }
> >>>>>> +                    kfree(str);
> >>>>>> +                    str = NULL;
> >>>>>> +                    continue;
> >>>>>> +
> >>>>>> +            } else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
> >>>>>> +                    /*
> >>>>>> +                     * Report list of "SupportEncoding"
> >>>>>> +                     *
> >>>>>> +                     *      "SupportedEncoding": [
> >>>>>> +                     *              "utf-16"
> >>>>>> +                     *      ],
> >>>>>> +                     *
> >>>>>> +                     */
> >>>>>> +
> >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> >>>>>> +                                        buf, hp_wmi_elements[type][i]);
> >>>>>> +                    for (j = 0; j < size; j++) {
> >>>>>> +                            status = get_string_from_buffer((u16
> >>>>>> **)&obj->buffer.pointer, &str);
> >>>>>> +                            if (ACPI_SUCCESS(status)) {
> >>>>>> +                                    if (j == size - 1)
> >>>>>> +                                            buf_size = snprintf(buf,
> >>>>>> alloc_size,
> >>>>>> +
> >>>>>> "%s\t\t\"%s\"\n", buf, str);
> >>>>>> +                                    else
> >>>>>> +                                            buf_size = snprintf(buf,
> >>>>>> alloc_size,
> >>>>>> +
> >>>>>> "%s\t\t\"%s\",\n", buf, str);
> >>>>>> +                            }
> >>>>>> +                            kfree(str);
> >>>>>> +                            str = NULL;
> >>>>>> +                    }
> >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >>>>>> +                    continue;
> >>>>>> +            }
> >>>>>> +
> >>>>>> +            size = 0;
> >>>>>> +            status = get_integer_from_buffer((int **)&obj-
> >>>>>>> buffer.pointer, &integer);
> >>>>>> +            if (ACPI_SUCCESS(status)) {
> >>>>>> +                    /*
> >>>>>> +                     * Report "PrerequisiteSize" and "Size" values
> >>>>>> +                     *      ...
> >>>>>> +                     *      "PrerequisiteSize": 1,
> >>>>>> +                     *      ...
> >>>>>> +                     *      "Size": 2,
> >>>>>> +                     *      ...
> >>>>>> +                     */
> >>>>>> +                    if (i == 7)
> >>>>>> +                            size = integer;
> >>>>>> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> >>>>>> == 10)
> >>>>>> +                            size = integer;
> >>>>>> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> >>>>>> 9)
> >>>>>> +                            size = integer;
> >>>>>> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> >>>>>> 11)
> >>>>>> +                            size = integer;
> >>>>>> +
> >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> >>>>>> %d,\n", buf,
> >>>>>> +                                        hp_wmi_elements[type][i],
> >>>>>> integer);
> >>>>>> +            }
> >>>>>> +
> >>>>>> +            if (size > 20)
> >>>>>> +                    pr_warn("%s exceeded the maximum number of
> >>>>>> elements supported or data may be malformed\n",
> >>>>>> +                            hp_wmi_elements[type][i]);
> >>>>>> +
> >>>>>> +            if (ACPI_SUCCESS(status) && i == 7) {
> >>>>>> +                    buf_size = snprintf(buf, alloc_size,
> >>>>>> "%s\t\"Prerequisites\": [\n", buf);
> >>>>>> +                    for (j = 0; j < size; j++) {
> >>>>>> +                            status = get_string_from_buffer((u16
> >>>>>> **)&obj->buffer.pointer, &str);
> >>>>>> +                            if (ACPI_SUCCESS(status)) {
> >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> >>>>>> "%s\t\t\"%s\"", buf, str);
> >>>>>> +
> >>>>>> +                                    if (j == size - 1)
> >>>>>> +                                            buf_size = snprintf(buf,
> >>>>>> alloc_size, "%s\n", buf);
> >>>>>> +                                    else
> >>>>>> +                                            buf_size = snprintf(buf,
> >>>>>> alloc_size, "%s,\n", buf);
> >>>>>> +
> >>>>>> +                            }
> >>>>>> +                            kfree(str);
> >>>>>> +                            str = NULL;
> >>>>>> +                    }
> >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >>>>>> +            }
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    if (type == HPWMI_ENUMERATION_TYPE || type ==
> >>>>>> HPWMI_ORDEREDLIST_TYPE) {
> >>>>>> +            if (type == HPWMI_ENUMERATION_TYPE)
> >>>>>> +                    buf_size = snprintf(buf, alloc_size,
> >>>>>> "%s\t\"PossibleValues\": [\n", buf);
> >>>>>> +            else
> >>>>>> +                    buf_size = snprintf(buf, alloc_size,
> >>>>>> "%s\t\"Elements\": [\n", buf);
> >>>>>> +
> >>>>>> +            for (i = 0; i < size; i++) {
> >>>>>> +                    status = get_string_from_buffer((u16 **)&obj-
> >>>>>>> buffer.pointer, &str);
> >>>>>> +                    if (ACPI_SUCCESS(status)) {
> >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> >>>>>> "%s\t\t\"%s\"", buf, str);
> >>>>>> +
> >>>>>> +                            if (i == size - 1)
> >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> >>>>>> "%s\n", buf);
> >>>>>> +                            else
> >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> >>>>>> "%s,\n", buf);
> >>>>>> +
> >>>>>> +                    }
> >>>>>> +                    kfree(str);
> >>>>>> +                    str = NULL;
> >>>>>> +            }
> >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    /*
> >>>>>> +     * remove trailing comma
> >>>>>> +     */
> >>>>>> +    if (buf_size > 3)
> >>>>>> +            buf[buf_size - 2] = ' ';
> >>>>>> +
> >>>>>> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int hp_bios_settings_free_buffer(void)
> >>>>>> +{
> >>>>>> +    mutex_lock(&buf_mutex);
> >>>>>> +    kfree(hp_bios_settings_buffer);
> >>>>>> +    settings_buffer_size = 0;
> >>>>>> +    buf_alloc_size = 0;
> >>>>>> +    mutex_unlock(&buf_mutex);
> >>>>>> +
> >>>>>> +    return 0;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size,
> >>>>>> +                                       int *alloc_size,
> >>>>>> +                                       struct mutex *buf_mutex)
> >>>>>> +{
> >>>>>> +    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(buf_mutex);
> >>>>>> +            new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
> >>>>>> +            mutex_unlock(buf_mutex);
> >>>>>> +            if (new_buf) {
> >>>>>> +                    mutex_lock(buf_mutex);
> >>>>>> +                    *buf = new_buf;
> >>>>>> +                    *alloc_size = ksize(new_buf);
> >>>>>> +                    mutex_unlock(buf_mutex);
> >>>>>> +            } else {
> >>>>>> +                    hp_bios_settings_free_buffer();
> >>>>>> +                    ret = -ENOMEM;
> >>>>>> +            }
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    return ret;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int append_settings_to_buffer(char *guid, int type, char **buf,
> >>>>>> +                                 int *buf_size, int *alloc_size,
> >>>>>> +                                 struct mutex *buf_mutex)
> >>>>>> +{
> >>>>>> +    union acpi_object *obj = NULL;
> >>>>>> +    int ret = 0;
> >>>>>> +    int status = 0;
> >>>>>> +    int instance = 0;
> >>>>>> +
> >>>>>> +    /*
> >>>>>> +     * Query all the instances until to receive a AE_BAD_PARAMETER
> >>>>>> +     */
> >>>>>> +    do {
> >>>>>> +            ret = hp_wmi_get_setting_object(guid, instance++, &obj);
> >>>>>> +            if (ACPI_SUCCESS(ret) && obj != NULL) {
> >>>>>> +                    status = 0;
> >>>>>> +                    if (obj->type == ACPI_TYPE_PACKAGE) {
> >>>>>> +                            mutex_lock(buf_mutex);
> >>>>>> +                            status =
> >>>>>> append_package_elements_to_buffer(obj,
> >>>>>> +                                                    *buf, *alloc_size,
> >>>>>> type);
> >>>>>> +                            if (status > 0)
> >>>>>> +                                    *buf_size = status;
> >>>>>> +                            mutex_unlock(buf_mutex);
> >>>>>> +
> >>>>>> +                    } else if (obj->type == ACPI_TYPE_BUFFER) {
> >>>>>> +                            mutex_lock(buf_mutex);
> >>>>>> +                            status =
> >>>>>> append_buffer_elements_to_buffer(obj,
> >>>>>> +                                                    *buf, *alloc_size,
> >>>>>> type);
> >>>>>> +                            if (status > 0)
> >>>>>> +                                    *buf_size = status;
> >>>>>> +                            mutex_unlock(buf_mutex);
> >>>>>> +
> >>>>>> +                    } else
> >>>>>> +                            pr_warn("The retrieved object type(%d) is
> >>>>>> not supported yet\n",
> >>>>>> +                                    obj->type);
> >>>>>> +
> >>>>>> +                    ret = hp_bios_settings_realloc_buffer(buf, buf_size,
> >>>>>> alloc_size, buf_mutex);
> >>>>>> +            }
> >>>>>> +
> >>>>>> +            kfree(obj);
> >>>>>> +            obj = NULL;
> >>>>>> +
> >>>>>> +    } while (ACPI_SUCCESS(ret));
> >>>>>> +
> >>>>>> +    /*
> >>>>>> +     * AE_BAD_PARAMETER means the loop ended by exhaustion
> >>>>>> +     */
> >>>>>> +    if (ret == AE_BAD_PARAMETER)
> >>>>>> +            ret = 0;
> >>>>>> +
> >>>>>> +    return ret;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int hp_bios_settings_fill_buffer(void)
> >>>>>> +{
> >>>>>> +    int status = 0;
> >>>>>> +    int initial_buffer_size = 20 * PAGE_SIZE;
> >>>>>> +
> >>>>>> +    mutex_lock(&buf_mutex);
> >>>>>> +    hp_bios_settings_buffer = kmalloc(initial_buffer_size,
> >>> GFP_KERNEL);
> >>>>>> +    mutex_unlock(&buf_mutex);
> >>>>>> +    if (!hp_bios_settings_buffer)
> >>>>>> +            return -ENOMEM;
> >>>>>> +
> >>>>>> +    mutex_lock(&buf_mutex);
> >>>>>> +    buf_alloc_size = ksize(hp_bios_settings_buffer);
> >>>>>> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> >>>>>> +                                    buf_alloc_size, "[\n");
> >>>>>> +    mutex_unlock(&buf_mutex);
> >>>>>> +
> >>>>>> +    status = append_settings_to_buffer(HPWMI_STRING_GUID,
> >>>>>> +            HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
> >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >>>>>> +    if (ACPI_FAILURE(status))
> >>>>>> +            pr_err("error 0x%x occurred retrieving string instances\n",
> >>>>>> status);
> >>>>>> +
> >>>>>> +    status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
> >>>>>> +            HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
> >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >>>>>> +    if (ACPI_FAILURE(status))
> >>>>>> +            pr_err("error 0x%x occurred retrieving integer instances\n",
> >>>>>> status);
> >>>>>> +
> >>>>>> +    status =
> >>> append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
> >>>>>> +            HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
> >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >>>>>> +    if (ACPI_FAILURE(status))
> >>>>>> +            pr_err("error 0x%x occurred retrieving enumeration
> >>>>>> instances\n", status);
> >>>>>> +
> >>>>>> +    status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
> >>>>>> +            HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
> >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >>>>>> +    if (ACPI_FAILURE(status))
> >>>>>> +            pr_err("error 0x%x occurred retrieving ordered list
> >>>>>> instances\n", status);
> >>>>>> +
> >>>>>> +    status = append_settings_to_buffer(HPWMI_PASSWORD_GUID,
> >>>>>> +            HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
> >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> >>>>>> +    if (ACPI_FAILURE(status))
> >>>>>> +            pr_err("error 0x%x occurred retrieving password list
> >>>>>> instances\n", status);
> >>>>>> +
> >>>>>> +    mutex_lock(&buf_mutex);
> >>>>>> +    /*
> >>>>>> +     * remove trailing comma
> >>>>>> +     */
> >>>>>> +    if (settings_buffer_size >= 3) {
> >>>>>> +            if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
> >>>>>> +                    hp_bios_settings_buffer[settings_buffer_size - 2] = '
> >>>>>> ';
> >>>>>> +    }
> >>>>>> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> >>>>>> +                                    buf_alloc_size, "%s]\n",
> >>>>>> +                                    hp_bios_settings_buffer);
> >>>>>> +    mutex_unlock(&buf_mutex);
> >>>>>> +
> >>>>>> +    return settings_buffer_size;
> >>>>>> +}
> >>>>>> +
> >>>>>> +/*
> >>>>>> + * sure_admin_settings_read - Return a formatted file with settings
> >>>>>> + *                              and possible options read from BIOS
> >>>>>> + *
> >>>>>> + * @filp:  Pointer to file of settings read from BIOS
> >>>>>> + * @kobj:  Pointer to a kernel object of things that show up as directory
> >>> in
> >>>>>> the sysfs filesystem.
> >>>>>> + * @attr:  Pointer to list of read attributes
> >>>>>> + * @buf:   Pointer to buffer
> >>>>>> + * @off:   File current offset
> >>>>>> + * @count: Buffer size
> >>>>>> + *
> >>>>>> + * Returns the count of unicode chars read if successful, otherwise
> >>>>>> + *          -ENOMEM unable to allocate memory
> >>>>>> + *          -EINVAL buffer not allocated or too small
> >>>>>> + *
> >>>>>> + */
> >>>>>> +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 >= settings_buffer_size && settings_buffer_size > 0) {
> >>>>>> +            hp_bios_settings_free_buffer();
> >>>>>> +            return 0;
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    /* clear the buffer whenever the read starts from the first position
> >>>>>> */
> >>>>>> +    if (off == 0 && settings_buffer_size > 0)
> >>>>>> +            hp_bios_settings_free_buffer();
> >>>>>> +
> >>>>>> +    if (settings_buffer_size == 0)
> >>>>>> +            hp_bios_settings_fill_buffer();
> >>>>>> +
> >>>>>> +    mutex_lock(&buf_mutex);
> >>>>>> +    ret = memory_read_from_buffer(buf, count, &off,
> >>>>>> hp_bios_settings_buffer,
> >>>>>> +                                  settings_buffer_size);
> >>>>>> +    mutex_unlock(&buf_mutex);
> >>>>>> +
> >>>>>> +    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
> >>>>>> + */
> >>>>>> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
> >>>>>> +{
> >>>>>> +    int len = strlen(str);
> >>>>>> +
> >>>>>> +    /*
> >>>>>> +     * Add null character when reading an empty string
> >>>>>> +     */
> >>>>>> +    if (len == 0) {
> >>>>>> +            *p++ = 2;
> >>>>>> +            *p++ = (u8)0x00;
> >>>>>> +            return p;
> >>>>>> +    }
> >>>>>> +    *p++ = len * 2;
> >>>>>> +    utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
> >>>>>> +    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
> >>>>>> + */
> >>>>>> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 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(HPWMI_SETBIOSSETTING_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;
> >>>>>> +}
> >>>>>> +
> >>>>>> +/* Sure Admin Functions */
> >>>>>> +
> >>>>>> +#define UTF_PREFIX                  ((unsigned char *)"<utf-16/>")
> >>>>>> +#define BEAM_PREFIX                 ((unsigned char
> >>>>>> *)"<BEAM/>")
> >>>>>> +
> >>>>>> +/*
> >>>>>> + * sure_admin_settings_write - Write the contents of a formatted file
> >>>>>> + *                               with settings and performs the logic
> >>>>>> + *                               to change any settings in BIOS.
> >>>>>> + *
> >>>>>> + * @filp:  Pointer to file of settings to be written to BIOS
> >>>>>> + * @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 write operation
> >>>>>> + * @buf:   Pointer to buffer
> >>>>>> + * @off:   File current offset
> >>>>>> + * @count: Buffer size
> >>>>>> + *
> >>>>>> + *
> >>>>>> + * Returns the count of unicode characters written to BIOS if
> >>> successful,
> >>>>>> otherwise
> >>>>>> + *          -ENOMEM unable to allocate memory
> >>>>>> + *          -EINVAL buffer not allocated or too small
> >>>>>> + *
> >>>>>> + */
> >>>>>> +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;
> >>>>>> +    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 out_free;
> >>>>>> +    }
> >>>>>> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> >>>>>> +    part = strsep(&buf, ",");
> >>>>>> +    if (!part) {
> >>>>>> +            status = -EINVAL;
> >>>>>> +            goto out_free;
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    /* Add extra buffer space when encountering an empty string */
> >>>>>> +    if (!strlen(part))
> >>>>>> +            buffer_size += sizeof(unsigned short);
> >>>>>> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> >>>>>> +    part = strsep(&buf, ",");
> >>>>>> +    if (!part) {
> >>>>>> +            status = -EINVAL;
> >>>>>> +            goto out_free;
> >>>>>> +    }
> >>>>>> +    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 out_free;
> >>>>>> +
> >>>>>> +            tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> >>>>>> +            kfree(part);
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    part = strsep(&buf, ",");
> >>>>>> +    if (part) {
> >>>>>> +            status = -EINVAL;
> >>>>>> +            goto out_free;
> >>>>>> +    }
> >>>>>> +    status = hp_wmi_set_bios_setting(buffer, buffer_size);
> >>>>>> +    if (ACPI_FAILURE(status))
> >>>>>> +            status = -EINVAL;
> >>>>>> +
> >>>>>> +out_free:
> >>>>>> +    kfree(buffer);
> >>>>>> +    if (ACPI_SUCCESS(status))
> >>>>>> +            return count;
> >>>>>> +    return status;
> >>>>>> +}
> >>>>>> +
> >>>>>> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
> >>>>>> +
> >>>>>> +static struct bin_attribute *sure_admin_binattrs[] = {
> >>>>>> +    &sure_admin_settings,
> >>>>>> +    NULL,
> >>>>>> +};
> >>>>>> +
> >>>>>> +static const struct attribute_group sure_admin_group = {
> >>>>>> +    .name = "sure_admin",
> >>>>>> +    .bin_attrs = sure_admin_binattrs,
> >>>>>> +};
> >>>>>> +
> >>>>>>  static DEVICE_ATTR_RO(display);
> >>>>>>  static DEVICE_ATTR_RO(hddtemp);
> >>>>>>  static DEVICE_ATTR_RW(als);
> >>>>>> @@ -1050,6 +2026,7 @@ static const struct attribute_group
> >>>>>> *hp_wmi_groups[] = {
> >>>>>>      &hp_wmi_group,
> >>>>>>      &spm_group,
> >>>>>>      &sure_start_group,
> >>>>>> +    &sure_admin_group,
> >>>>>>      NULL,
> >>>>>>  };
> >>>>>>
> >>>>>> --
> >>>>>> 2.25.1
> >>>>
> >
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* RE: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-08 14:46               ` Jorge Lopez
@ 2022-04-08 14:54                 ` Limonciello, Mario
  2022-04-08 15:04                   ` Hans de Goede
  0 siblings, 1 reply; 25+ messages in thread
From: Limonciello, Mario @ 2022-04-08 14:54 UTC (permalink / raw)
  To: Jorge Lopez, Hans de Goede; +Cc: platform-driver-x86

[Public]



> -----Original Message-----
> From: Jorge Lopez <jorgealtxwork@gmail.com>
> Sent: Friday, April 8, 2022 09:47
> To: Hans de Goede <hdegoede@redhat.com>
> Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-driver-
> x86@vger.kernel.org
> Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> 
> On Fri, Apr 8, 2022 at 4:21 AM Hans de Goede <hdegoede@redhat.com>
> wrote:
> >
> > Hi Jorge,
> >
> > On 4/7/22 15:44, Jorge Lopez wrote:
> > > Hans, Mario,
> > >
> > > The code links make references to code that implements the new
> > > interfaces but there's
> > > still code in the kernel that uses the old ones.
> >
> > I'm not sure what you mean with "uses the old ones" there never
> > has been any kernel drivers for changing BIOS settings before
> > the dell and lenovo drivers were merged.
> 
> "uses the old ones" statement means that there are drivers on the tree
> that change BIOS settings without having to convert to the new
> standards.  hp-wmi remained unsupported for many years so I can
> understand why the security features need to use the standardized API.
> 
> >
> > Sure there are generic mechanisms like chardev-s and ioctls which
> > are used for a whole bunch of things. But AFAIK there never was
> > an API specifically for changing BIOS settings before.
> >
> > > I do agree we should
> > > be forward looking
> > > and want to be good participants in the kernel development, but can't
> > > let our immediate
> > > business needs be impacted with opportunities to enhance the driver to
> > > take advantage
> > > of the latest kernel features.
> > >
> > > Rewriting those security features will impact customer business
> > > datelines requiring
> > > HP to provide private releases as the kernel version changes.   The
> > > requested changes
> > > will impact products in the market and HP ability to help customers to
> > > migrate to Linux
> > > from Windows products.
> >
> > This sounds like you are saying that you are already shipping
> > a version of the driver with the non-standard API to customers.
> > Shipping code to customers before even proposing it upstream is
> > HP own choice and the results of that as such are HP's
> > responsibility.
> >
> The products shipped to customers are Windows products and customers
> are accustomed to how the data is reported and set.  The goal for the
> new security features in Linux is to help those customers migrate to
> Linux with little or no change to their scripts/tools.

I think if this is the situation then a userspace compatibility /conversion tool is
your better answer than a large compatibility layer in debugfs.

From the customer perspective they just need to see that JSON file in/out, right?
So you should be able to write a tool/script that parses all the attributes from
sysfs in a high level language and puts them into a JSON payload for their scripts
to work from.  Likewise it should be able to parse a JSON payload and deploy
all of that stuff into the standard API.

You can also explain in your documentation associates with such a tool/script
that it's using a standard API and if they want to use that API directly instead
of your compatibility tool they're welcome to do so.

> 
> > You cannot just say we are already shipping this so we need
> > the upstream kernel to support this non standard API, that is
> > not how upstream kernel development works.
> >
> > I realize that HP is new to working directly with the upstream kernel
> > community and I realize that being told that the API which you are
> > already using cannot be used for upstreaming your driver is not what
> > you want to hear.
> >
> > But that does not change that I cannot accept a driver which does not
> > implement the standard API which the upstream kernel community has
> > agreed upon for this functionality.
> >
> > Or as Mario very elegantly put it:
> >
> > 'Keep in mind that from an upstream kernel perspective this driver is
> "new".
> > There is no requirements from the upstream perspective to
> > keep your old interfaces in place from when it was out of tree.'
> >
> > > It is because of the immediate business needs, avoiding impacting our
> > > customers/products,
> > > and rewriting  enhancements to the driver that I need to propose an
> > > interim solution.
> > >
> > > My proposal is to introduce a read/write value accessible in the user
> > > space to control how
> > > the driver reports and handles BIOS settings and values.  The new
> > > configuration features
> > > will be gradually disabled  as they are converted to use the standardized
> API.
> > > It is like the configuration flag used to overcome the tablet detection
> problem
> > > introduced in the past.   The changes solely affect the HP WMI driver.
> > > This option will help us
> > > move forward for this release and give us time to make the necessary
> > > changes to both
> > > the driver and support applications.
> > >
> > > Please let me know if this is a viable interim solution.
> >
> > First of all to be very clear, any code going upstream must support
> > the standard API:
> >
> >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cb0dd9
> 6dde69d48c4e60c08da196ea2e1%7C3dd8961fe4884e608e11a82d994e183d%7
> C0%7C0%7C637850260243195656%7CUnknown%7CTWFpbGZsb3d8eyJWIjoi
> MC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C300
> 0&amp;sdata=HDIa3CmOAhty7ZtwAoKh5VveEGCC%2Fuq5E1rx0hWOHns%3
> D&amp;reserved=0
> >
> > from day one. I'm not really enthusiastic about the concept of also
> > supporting the API which you have been using out of tree so far, but
> > I guess that Mario's suggestion to offer a Kconfig option which
> > when enabled offers this API under debugfs might be an acceptible
> > compromise. I would need to see the actual code for that though to
> > see if this is acceptable.
> >
> > And there would need to be a clear cut-of date document after which
> > the code to support the old API will be removed.
> >
> > > If it is not possible, I need to ask where the actual written
> > > requirement is found so I can
> > > include them in the business justification for changes and release
> > > delays to management.
> >
> > I'm not sure if this is written down somewhere, but certainly
> > you will agree that if you were submitting a driver for a soundcard
> > that that should use the existing ALSA userspace API for sound so
> > that it would just work with the existing userspace sound support.
> >
> > This is the same. If an existing standardized userspace API exists
> > for a certain functionality then that userspace API _must_ be used,
> > AFAIK this is not explictly written down anywhere because it is just
> > very much common sense.
> 
> I completely agree with your comments and request for the driver to
> implement the standardized API.  hp-wmi remained unsupported for many
> years so I can understand why the security features need to use the
> standardized API.  I am having conversations with other teams on how
> to move forward with the standard API and how the data is handled and
> reported.   We will submit a new set of patches utilizing the new
> standard at a later time.   Would it be accurate to state that any
> extensions to the standardized API model are acceptable, Correct?
> 

That's correct.  Dell did the first driver, and then Lenovo did the second.
The majority of the features from the Dell driver applied to the Lenovo one
and any idiosyncrasies were introduced as new sysfs files or documented and
agreed different behaviors of others.

> Regards,
> 
> Jorge
> >
> > Regards,
> >
> > Hans
> >
> >
> >
> >
> >
> >
> > > On Tue, Apr 5, 2022 at 12:13 PM Limonciello, Mario
> > > <Mario.Limonciello@amd.com> wrote:
> > >>
> > >> [Public]
> > >>
> > >>
> > >>
> > >>> -----Original Message-----
> > >>> From: Jorge Lopez <jorgealtxwork@gmail.com>
> > >>> Sent: Tuesday, April 5, 2022 11:52
> > >>> To: Hans de Goede <hdegoede@redhat.com>
> > >>> Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-
> driver-
> > >>> x86@vger.kernel.org
> > >>> Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
> > >>>
> > >>> Hi Hans,
> > >>>
> > >>> On Tue, Apr 5, 2022 at 6:54 AM Hans de Goede
> <hdegoede@redhat.com>
> > >>> wrote:
> > >>>>
> > >>>> Hi,
> > >>>>
> > >>>> On 4/4/22 23:59, Limonciello, Mario wrote:
> > >>>>> [Public]
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>>>> -----Original Message-----
> > >>>>>> From: Jorge Lopez <jorgealtxwork@gmail.com>
> > >>>>>> Sent: Monday, April 4, 2022 15:36
> > >>>>>> To: platform-driver-x86@vger.kernel.org
> > >>>>>> Subject: [PATCH v1 5/6] Sure Admin Security Feature
> > >>>>>>
> > >>>>>> 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. Behind the scenes, Sure Admin uses Secure
> > >>> Platform
> > >>>>>> Management (SPM) and WMI
> > >>>>>>
> > >>>>>> 'settings' is a file associated with Sure Admin. BIOS settings can be
> > >>>>>> read or written through the Sure Admin settings file in sysfs
> > >>>>>>
> > >>>>>>      /sys/devices/platform/hp-wmi/sure_admin/settings
> > >>>>>>
> > >>>>>> 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"
> > >>>>>>              ]
> > >>>>>>      }
> > >>>>>>
> > >>>>>
> > >>>>> This sounds like it has re-invented /sys/class/firmware-attributes.
> > >>>>>
> > >>>>> Shouldn't you adopt that API?
> > >>>>
> > >>>> I fully agree. Jorge as I already indicated in our off-list
> > >>>> conversation when you initially started working on this
> > >>>> feature, we already have a standardized API for querying/changing
> > >>>> BIOS settings from within Linux:
> > >>>>
> > >>>
> > >>> I agree that changing the BIOS settings from within Linux could
> > >>> utilize the new methodology,  I will need to look closely at the
> > >>> requirements before I can proceed to make the changes.
> > >>> Keep in mind authentication of the values is done by BIOS.  No Linux
> > >>> process validates any data name, value, or auth token; only BIOS.  All
> > >>> data written to the sysfs file is not validated, it is just forward to
> > >>> BIOS.  See spm_kek_store and spm_sk_store functions.
> > >>
> > >> That's fine, and it's a safer design to have BIOS validate it.
> > >>
> > >>> One point I must make clear when updating BIOS settings.  any  NOT
> > >>> read-only BIOS settings can be changed by the application at any time.
> > >>>    This list of settings changes from one system to another.
> > >>
> > >> Right.
> > >>
> > >>>
> > >>> I am in disagreement with reading the settings.  hp-wmi does not read
> > >>> one value at a time. It reads all values exposed by BIOS.  See
> > >>> attached sample output.
> > >>
> > >> The settings can all be read at initialization time for the driver and
> cached
> > >> then.
> > >>
> > >>> The method for how all BIOS settings are reported needs to match the
> > >>> method how Windows products do it.  It is a requirement to start
> > >>> migrating customers from Windows to Linux while minimizing how
> BIOS
> > >>> data is reported.
> > >>
> > >> Because we have a standardized API in Linux for this, I think it's best to
> abstract
> > >> this behind a userspace application/script.  If they expect to see it in the
> format you
> > >> showed, the userspace application can take the data from Linux and
> package it that
> > >> way.
> > >>
> > >> You'll have richer libraries and languages and tools to work from when
> doing this too.
> > >> It should make it a lot less painful.
> > >>
> > >>>
> > >>> I will investigate the new API and bring it to the team's attention.
> > >>>
> > >>>>
> > >>>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cb0dd96dde
> 69d48c4e60c08da196ea2e1%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> 7C0%7C637850260243195656%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> mp;sdata=RDJFrHlrsTnb6mvH77dxXYRXclateWBOXLWnc6GQm3c%3D&amp;r
> eserved=0
> > >>>
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > >>> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> > >>>
> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> > >>>
> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> > >>>
> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> > >>>
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> > >>>
> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> > >>> D&amp;reserved=0
> > >>>>
> > >>>> and any new code (such as this patch) which implements BIOS
> > >>>> setting changing MUST follow this standardized API (extending
> > >>>> it where necessary).
> > >>>>
> > >>>> I'm sorry but this patch is not acceptable in its current form,
> > >>>> it needs to be *completely rewritten* to implement:
> > >>>>
> > >>>>
> > >>>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cb0dd96dde
> 69d48c4e60c08da196ea2e1%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> 7C0%7C637850260243195656%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> mp;sdata=RDJFrHlrsTnb6mvH77dxXYRXclateWBOXLWnc6GQm3c%3D&amp;r
> eserved=0
> > >>>
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > >>> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
> > >>>
> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12
> > >>>
> f8fea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C
> > >>>
> 0%7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiM
> > >>>
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000
> > >>>
> &amp;sdata=QhkFIYFCRXg1seDPb3qhk5qMkNQ%2B8AQXmHuke0YrWKc%3
> > >>> D&amp;reserved=0
> > >>>>
> > >>>> See:
> > >>>>
> > >>>>
> > >>>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cb0dd96dde
> 69d48c4e60c08da196ea2e1%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> 7C0%7C637850260243195656%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> mp;sdata=RDJFrHlrsTnb6mvH77dxXYRXclateWBOXLWnc6GQm3c%3D&amp;r
> eserved=0
> > >>>
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > >>> 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fdell%2Fdell-wmi-
> > >>>
> sysman&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8f
> > >>>
> ea104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> > >>>
> 7C0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> > >>>
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> > >>>
> mp;sdata=z5jmH7ECYBeLcndQ2vfHaUuyE04Eaf1Lymh6BjnyJ%2Fk%3D&amp;r
> > >>> eserved=0
> > >>>>
> > >>>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cb0dd96dde
> 69d48c4e60c08da196ea2e1%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> 7C0%7C637850260243195656%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> mp;sdata=RDJFrHlrsTnb6mvH77dxXYRXclateWBOXLWnc6GQm3c%3D&amp;r
> eserved=0
> > >>>
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > >>> 2Ftree%2Fdrivers%2Fplatform%2Fx86%2Fthink-
> > >>>
> lmi.c&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea
> > >>>
> 104034282708da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C
> > >>>
> 0%7C637847743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLj
> > >>>
> AwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;
> > >>>
> sdata=5n6w9LEB2iWpj1cOQP6Ngz94AqP1Bu4vu8T0EdN%2FThU%3D&amp;re
> > >>> served=0
> > >>>>
> > >>>> for example code / for 2 drivers from other vendors already
> > >>>> implementing this.
> > >>>>
> > >>>> The same applies to the:
> > >>>>
> > >>>> "[PATCH v1 3/6] Secure Platform Management Security Feature"
> > >>>>
> > >>>> this needs to be implemented as
> > >>>> a /sys/class/firmware-attributes/*/authentication/
> > >>>> authentication method, see for example these Lenovo specific
> > >>>> addition to the /sys/class/firmware-attributes/*/authentication/
> > >>>> userspace API for similar functionality on Lenovo Think* devices:
> > >>>>
> > >>>>
> > >>>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
> %2F&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cb0dd96dde
> 69d48c4e60c08da196ea2e1%7C3dd8961fe4884e608e11a82d994e183d%7C0%
> 7C0%7C637850260243195656%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&a
> mp;sdata=RDJFrHlrsTnb6mvH77dxXYRXclateWBOXLWnc6GQm3c%3D&amp;r
> eserved=0
> > >>>
> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
> > >>>
> 2Fcommit%2F%3Fid%3D06384573a3e8335ac6797577e545c33dbf91b490&amp;
> > >>>
> data=04%7C01%7CMario.Limonciello%40amd.com%7C43a12f8fea1040342827
> > >>>
> 08da1724a70c%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C63784
> > >>>
> 7743455947225%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLC
> > >>>
> JQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=eldS
> > >>>
> 4H3Z%2BAyL%2FG%2FO9W9rDGC37yh5sGgtUhpKdUAoSmA%3D&amp;reser
> > >>> ved=0
> > >>>>
> > >>>> I'll merge patches 1-2 sometime this week since those are
> > >>>> fine and it will be good to have those "out of the way",
> > >>>> but the rest of the series will need to be rewritten
> > >>>> taken the above comments into account.
> > >>>
> > >>> v1-0003-Sure-Start-Security-Feature.patch  reports the number of
> audit
> > >>> logs available and reports them when read.    it does not read/write
> > >>> BIOS settings hence it does not fall within the same category as
> > >>> patches v1-0002-Secure-Platform-Management-Security-
> Feature.patch and
> > >>> v1-0004-Sure-Admin-Security-Feature.patch
> > >>> Do you agree?
> > >>>
> > >>>>
> > >>>> Regards,
> > >>>>
> > >>>> Hans
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>>
> > >>>>>> This feature requires "Update hp_wmi_group to simplify feature
> > >>>>>> addition" patch.
> > >>>>>>
> > >>>>>> All changes were validated on a HP ZBook Workstation,
> > >>>>>> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> > >>>>>>
> > >>>>>> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
> > >>>>>>
> > >>>>>> ---
> > >>>>>> Based on the latest platform-drivers-x86.git/for-next
> > >>>>>> ---
> > >>>>>>  drivers/platform/x86/hp-wmi.c | 977
> > >>>>>> ++++++++++++++++++++++++++++++++++
> > >>>>>>  1 file changed, 977 insertions(+)
> > >>>>>>
> > >>>>>> diff --git a/drivers/platform/x86/hp-wmi.c
> b/drivers/platform/x86/hp-
> > >>> wmi.c
> > >>>>>> index 918e3eaf1b67..b72ca18b77a6 100644
> > >>>>>> --- a/drivers/platform/x86/hp-wmi.c
> > >>>>>> +++ b/drivers/platform/x86/hp-wmi.c
> > >>>>>> @@ -27,6 +27,7 @@
> > >>>>>>  #include <linux/rfkill.h>
> > >>>>>>  #include <linux/string.h>
> > >>>>>>  #include <linux/dmi.h>
> > >>>>>> +#include <linux/nls.h>
> > >>>>>>
> > >>>>>>  MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
> > >>>>>>  MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
> > >>>>>> @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-
> BE91-
> > >>>>>> 3D44E2C707E4");
> > >>>>>>
> > >>>>>>  #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-
> > >>> ACCDC67EF61C"
> > >>>>>>  #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-
> > >>> 3D44E2C707E4"
> > >>>>>> +
> > >>>>>>  #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
> > >>>>>>
> > >>>>>> +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-
> > >>> 6A1B8106F83C"
> > >>>>>> +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-
> > >>>>>> E293ADB9BF05"
> > >>>>>> +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-
> B8FE-
> > >>>>>> 4A3C09E75133"
> > >>>>>> +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-
> A0E0-
> > >>>>>> 7045CB4DA745"
> > >>>>>> +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-
> > >>>>>> 015176049E2D"
> > >>>>>> +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-
> 951D-
> > >>>>>> C7CB9B4B8D5E"
> > >>>>>> +
> > >>>>>>  /* DMI board names of devices that should use the omen specific
> path
> > >>> for
> > >>>>>>   * thermal profiles.
> > >>>>>>   * This was obtained by taking a look in the windows omen
> command
> > >>> center
> > >>>>>> @@ -1025,6 +1034,973 @@ static const struct attribute_group
> > >>>>>> sure_start_group = {
> > >>>>>>      .attrs = sure_start_attrs,
> > >>>>>>  };
> > >>>>>>
> > >>>>>> +
> > >>>>>> +static 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;
> > >>>>>> +    int  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));
> > >>>>>> +            ret = kstrtoint(tmp, 16, &ch);
> > >>>>>> +            if (ret) {
> > >>>>>> +                    new_len = 0;
> > >>>>>> +                    break;
> > >>>>>> +            }
> > >>>>>> +
> > >>>>>> +            if (ch == '\\')
> > >>>>>> +                    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;
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    if (ret)
> > >>>>>> +            kfree(new_str);
> > >>>>>> +    return ret;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +/*
> > >>>>>> + * hp_wmi_get_setting_object() - Get an ACPI object by GUID
> and
> > >>> instance
> > >>>>>> + *
> > >>>>>> + * @guid:   GUID associated with the ACPI list of managed objects
> > >>>>>> + * @instance:       Instance index to query on the ACPI list
> > >>>>>> + * @obj:    The output ACPI object of type ACPI_TYPE_PACKAGE
> > >>>>>> + *          or ACPI_TYPE_BUFFER (freed by the callee)
> > >>>>>> + *
> > >>>>>> + * Returns  zero on success.  Otherwise,an error inherited from
> > >>>>>> + *          wmi_query_block(). It returns a obj by parameter if
> > >>>>>> + *          the query returned object of type buffer or package,
> > >>>>>> + *          otherwise, a null obj is returned.
> > >>>>>> + *
> > >>>>>> + * Note: obj should be freed by the callee once it is finished
> working
> > >>> with it
> > >>>>>> + */
> > >>>>>> +static int hp_wmi_get_setting_object(char *guid, int instance,
> > >>>>>> +                            union acpi_object **obj)
> > >>>>>> +{
> > >>>>>> +    struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER,
> NULL
> > >>>>>> };
> > >>>>>> +    union acpi_object *tmp = NULL;
> > >>>>>> +    int ret;
> > >>>>>> +
> > >>>>>> +    ret = wmi_query_block(guid, instance, &output);
> > >>>>>> +    if (ACPI_SUCCESS(ret) && output.pointer != NULL) {
> > >>>>>> +            tmp = output.pointer;
> > >>>>>> +            if (tmp->type == ACPI_TYPE_BUFFER || tmp->type ==
> > >>>>>> ACPI_TYPE_PACKAGE)
> > >>>>>> +                    *obj = output.pointer;
> > >>>>>> +            else {
> > >>>>>> +                    kfree(tmp);
> > >>>>>> +                    *obj = NULL;
> > >>>>>> +            }
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    return ret;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +
> > >>>>>> +static 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;
> > >>>>>> +
> > >>>>>> +    if (size == 0)
> > >>>>>> +            goto cleanup_exit;
> > >>>>>> +
> > >>>>>> +    for (i = 0; i < size; i++)
> > >>>>>> +            if (ptr[i] == '\\')
> > >>>>>> +                    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);
> > >>>>>> +
> > >>>>>> +    if (escape == 0) {
> > >>>>>> +            ptr += (ptrlen / 2);
> > >>>>>> +            goto cleanup_exit;
> > >>>>>> +    }
> > >>>>>> +    /*
> > >>>>>> +     * Convert escape characters only when found
> > >>>>>> +     */
> > >>>>>> +    for (i = 0; i < size; i++) {
> > >>>>>> +            if (*ptr == '\\')
> > >>>>>> +                    output[i++] = '\\';
> > >>>>>> +            output[i] = *ptr;
> > >>>>>> +            ptr++;
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +cleanup_exit:
> > >>>>>> +    *buffer = ptr;
> > >>>>>> +    return 0;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +static int get_integer_from_buffer(int **buffer, int *integer)
> > >>>>>> +{
> > >>>>>> +    int *ptr = PTR_ALIGN(*buffer, 4);
> > >>>>>> +    *integer = *(ptr++);
> > >>>>>> +    *buffer = ptr;
> > >>>>>> +    return 0;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +
> > >>>>>> +// Sure Admin functions
> > >>>>>> +enum hp_wmi_data_type {
> > >>>>>> +    HPWMI_STRING_TYPE,
> > >>>>>> +    HPWMI_INTEGER_TYPE,
> > >>>>>> +    HPWMI_ENUMERATION_TYPE,
> > >>>>>> +    HPWMI_ORDEREDLIST_TYPE,
> > >>>>>> +    HPWMI_PASSWORD_TYPE,
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +#define HP_WMI_COMMON_ELEMENTS      \
> > >>>>>> +    "Name", \
> > >>>>>> +    "Value",        \
> > >>>>>> +    "Path", \
> > >>>>>> +    "IsReadOnly",   \
> > >>>>>> +    "DisplayInUI",  \
> > >>>>>> +    "RequiresPhysicalPresence",     \
> > >>>>>> +    "Sequence",     \
> > >>>>>> +    "PrerequisiteSize",     \
> > >>>>>> +    "SecurityLevel"
> > >>>>>> +
> > >>>>>> +const char *hp_wmi_string_elements[] = {
> > >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> > >>>>>> +    "MinLength",
> > >>>>>> +    "MaxLength"
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +const char *hp_wmi_integer_elements[] = {
> > >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> > >>>>>> +    "LowerBound",
> > >>>>>> +    "UpperBound",
> > >>>>>> +    "IntValue"
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +const char *hp_wmi_enumeration_elements[] = {
> > >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> > >>>>>> +    "CurrentValue",
> > >>>>>> +    "Size"
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +const char *hp_wmi_orderedlist_elements[] = {
> > >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> > >>>>>> +    "Size"
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +const char *hp_wmi_password_elements[] = {
> > >>>>>> +    HP_WMI_COMMON_ELEMENTS,
> > >>>>>> +    "MinLength",
> > >>>>>> +    "MaxLength",
> > >>>>>> +    "Size",
> > >>>>>> +    "SupportedEncoding",
> > >>>>>> +    "IsSet"
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +const char **hp_wmi_elements[] = {
> > >>>>>> +    hp_wmi_string_elements,
> > >>>>>> +    hp_wmi_integer_elements,
> > >>>>>> +    hp_wmi_enumeration_elements,
> > >>>>>> +    hp_wmi_orderedlist_elements,
> > >>>>>> +    hp_wmi_password_elements
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +const int hp_wmi_elements_count[] = {
> > >>>>>> +    ARRAY_SIZE(hp_wmi_string_elements),
> > >>>>>> +    ARRAY_SIZE(hp_wmi_integer_elements),
> > >>>>>> +    ARRAY_SIZE(hp_wmi_enumeration_elements),
> > >>>>>> +    ARRAY_SIZE(hp_wmi_orderedlist_elements),
> > >>>>>> +    ARRAY_SIZE(hp_wmi_password_elements)
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +const char *hp_wmi_classes[] = {
> > >>>>>> +    "HPBIOS_BIOSString",
> > >>>>>> +    "HPBIOS_BIOSInteger",
> > >>>>>> +    "HPBIOS_BIOSEnumeration",
> > >>>>>> +    "HPBIOS_BIOSOrderedList",
> > >>>>>> +    "HPBIOS_BIOSPassword"
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +static DEFINE_MUTEX(buf_mutex);
> > >>>>>> +static int settings_buffer_size;
> > >>>>>> +static int buf_alloc_size;
> > >>>>>> +static char *hp_bios_settings_buffer;
> > >>>>>> +
> > >>>>>> +
> > >>>>>> +static int append_package_elements_to_buffer(union
> acpi_object
> > >>> *obj,
> > >>>>>> +                                         char *buf, int alloc_size, enum
> > >>>>>> hp_wmi_data_type type)
> > >>>>>> +{
> > >>>>>> +    int i;
> > >>>>>> +    union acpi_object *pobj = NULL;
> > >>>>>> +    char *value = NULL;
> > >>>>>> +    int value_len;
> > >>>>>> +    char *tmpstr = NULL;
> > >>>>>> +    char *part_tmp = NULL;
> > >>>>>> +    int tmp_len = 0;
> > >>>>>> +    char *part = NULL;
> > >>>>>> +    int status = 0;
> > >>>>>> +    int size = 0;
> > >>>>>> +    int buf_size;
> > >>>>>> +
> > >>>>>> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > >>>>>> +            return -EINVAL;
> > >>>>>> +
> > >>>>>> +    if (obj->type != ACPI_TYPE_PACKAGE)
> > >>>>>> +            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]);
> > >>>>>> +
> > >>>>>> +    for (i = 0; i < 3; i++) {
> > >>>>>> +            pobj = &(obj->package.elements[i]);
> > >>>>>> +            if (pobj->type == ACPI_TYPE_STRING) {
> > >>>>>> +                    status = convert_hexstr_to_str(&pobj-
> > >>>>>>> string.pointer,
> > >>>>>> +                                                   pobj->string.length,
> > >>>>>> &value, &value_len);
> > >>>>>> +                    if (ACPI_FAILURE(status))
> > >>>>>> +                            continue;
> > >>>>>> +                    /*
> > >>>>>> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > >>>>>> since
> > >>>>>> +                     * 'CurrentValue' is reported.
> > >>>>>> +                     */
> > >>>>>> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> > >>>>>> +                                                "%s\t\"%s\": \"%s\",\n",
> > >>>>>> +                                                buf,
> > >>>>>> +
> > >>>>>> hp_wmi_elements[type][i], value);
> > >>>>>> +
> > >>>>>> +            }
> > >>>>>> +            kfree(value);
> > >>>>>> +            value = NULL;
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > >>>>>> +            pobj = &(obj->package.elements[i]);
> > >>>>>> +
> > >>>>>> +            if (type == HPWMI_ENUMERATION_TYPE &&
> > >>>>>> +                i == 9 &&
> > >>>>>> +                pobj->type == ACPI_TYPE_STRING) {
> > >>>>>> +                    /*
> > >>>>>> +                     * Report "CurrentValue" as "Value"
> > >>>>>> +                     */
> > >>>>>> +                    status = convert_hexstr_to_str(&pobj-
> > >>>>>>> string.pointer,
> > >>>>>> +                                                   pobj->string.length,
> > >>>>>> +                                                   &value, &value_len);
> > >>>>>> +                    if (ACPI_FAILURE(status))
> > >>>>>> +                            continue;
> > >>>>>> +
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> +                                        "%s\t\"Value\": \"%s\",\n",
> > >>>>>> +                                        buf, value);
> > >>>>>> +                    kfree(value);
> > >>>>>> +                    value = NULL;
> > >>>>>> +
> > >>>>>> +            } else if (type == HPWMI_PASSWORD_TYPE &&
> > >>>>>> +                       i == 12 &&
> > >>>>>> +                       pobj->type == ACPI_TYPE_STRING) {
> > >>>>>> +                    /*
> > >>>>>> +                     * Report list of "SupportEncoding"
> > >>>>>> +                     *
> > >>>>>> +                     *      "SupportedEncoding": [
> > >>>>>> +                     *              "utf-16"
> > >>>>>> +                     *      ],
> > >>>>>> +                     *
> > >>>>>> +                     */
> > >>>>>> +
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > >>>>>> +                                        buf, hp_wmi_elements[type][i]);
> > >>>>>> +                    while (size--) {
> > >>>>>> +                            pobj = &(obj->package.elements[i]);
> > >>>>>> +                            status = convert_hexstr_to_str(&pobj-
> > >>>>>>> string.pointer,
> > >>>>>> +                                                           pobj-
> > >>>>>>> string.length,
> > >>>>>> +                                                           &value,
> > >>>>>> &value_len);
> > >>>>>> +                            if (ACPI_FAILURE(status))
> > >>>>>> +                                    continue;
> > >>>>>> +
> > >>>>>> +                            if (size) {
> > >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> +                                                        "%s\t\t\"%s\",\n",
> > >>>>>> buf, value);
> > >>>>>> +                                    i++;
> > >>>>>> +                            } else
> > >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> +                                                        "%s\t\t\"%s\"\n",
> > >>>>>> buf, value);
> > >>>>>> +
> > >>>>>> +                            kfree(value);
> > >>>>>> +                            value = NULL;
> > >>>>>> +
> > >>>>>> +                    }
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >>>>>> +                    continue;
> > >>>>>> +
> > >>>>>> +            } else if (pobj->type == ACPI_TYPE_INTEGER) {
> > >>>>>> +                    /*
> > >>>>>> +                     * Report "PrerequisiteSize" and "Size" values
> > >>>>>> +                     *      ...
> > >>>>>> +                     *      "PrerequisiteSize": 1,
> > >>>>>> +                     *      ...
> > >>>>>> +                     *      "Size": 2,
> > >>>>>> +                     *      ...
> > >>>>>> +                     */
> > >>>>>> +                    if (i == 7)
> > >>>>>> +                            size = pobj->integer.value;
> > >>>>>> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > >>>>>> 9)
> > >>>>>> +                            size = pobj->integer.value;
> > >>>>>> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > >>>>>> == 10)
> > >>>>>> +                            size = pobj->integer.value;
> > >>>>>> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > >>>>>> 11)
> > >>>>>> +                            size = pobj->integer.value;
> > >>>>>> +
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > >>>>>> %lld,\n", buf,
> > >>>>>> +                                        hp_wmi_elements[type][i], pobj-
> > >>>>>>> integer.value);
> > >>>>>> +            }
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    if (type == HPWMI_ENUMERATION_TYPE) {
> > >>>>>> +            buf_size = snprintf(buf, alloc_size,
> "%s\t\"PossibleValues\":
> > >>>>>> [\n", buf);
> > >>>>>> +            for (i = 0; i < size; i++) {
> > >>>>>> +                    pobj = &(obj->package.elements[i +
> > >>>>>> hp_wmi_elements_count[type]]);
> > >>>>>> +
> > >>>>>> +                    status = convert_hexstr_to_str(&pobj-
> > >>>>>>> string.pointer,
> > >>>>>> +                                                   pobj->string.length,
> > >>>>>> +                                                   &value, &value_len);
> > >>>>>> +                    if (ACPI_FAILURE(status))
> > >>>>>> +                            break;
> > >>>>>> +
> > >>>>>> +                    /*
> > >>>>>> +                     * Report list of "PossibleValues" of size
> > >>>>>> +                     * "Size"
> > >>>>>> +                     *      ...
> > >>>>>> +                     *      "Size": 2,
> > >>>>>> +                     *      "PossibleValues": [
> > >>>>>> +                     *                      "Disable",
> > >>>>>> +                     *                      "Enable"]
> > >>>>>> +                     */
> > >>>>>> +                    if (i == (size - 1))
> > >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> > >>>>>> +                                                "%s\t\t\"%s\"\n", buf,
> > >>>>>> value);
> > >>>>>> +                    else
> > >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> > >>>>>> +                                                "%s\t\t\"%s\",\n", buf,
> > >>>>>> value);
> > >>>>>> +                    kfree(value);
> > >>>>>> +                    value = NULL;
> > >>>>>> +            }
> > >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    if (type == HPWMI_ORDEREDLIST_TYPE) {
> > >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n",
> > >>>>>> buf);
> > >>>>>> +            if (size <= 0)
> > >>>>>> +                    goto finish_ordered_list;
> > >>>>>> +
> > >>>>>> +            pobj = &(obj-
> > >>>>>>> package.elements[hp_wmi_elements_count[type]]);
> > >>>>>> +            status = convert_hexstr_to_str(&pobj->string.pointer,
> > >>>>>> +                                           pobj->string.length, &value,
> > >>>>>> &value_len);
> > >>>>>> +            if (ACPI_FAILURE(status))
> > >>>>>> +                    goto finish_ordered_list;
> > >>>>>> +
> > >>>>>> +            /*
> > >>>>>> +             * 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(&value, value_len,
> &tmpstr,
> > >>>>>> &tmp_len);
> > >>>>>> +            if (ACPI_FAILURE(status))
> > >>>>>> +                    goto finish_ordered_list;
> > >>>>>> +
> > >>>>>> +            part_tmp = tmpstr;
> > >>>>>> +            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);
> > >>>>>> +            }
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +finish_ordered_list:
> > >>>>>> +    if (type == HPWMI_ORDEREDLIST_TYPE)
> > >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >>>>>> +
> > >>>>>> +    /*
> > >>>>>> +     * remove trailing comma
> > >>>>>> +     */
> > >>>>>> +    if (buf_size > 3)
> > >>>>>> +            buf[buf_size - 2] = ' ';
> > >>>>>> +
> > >>>>>> +    kfree(tmpstr);
> > >>>>>> +    kfree(value);
> > >>>>>> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +static int append_buffer_elements_to_buffer(union acpi_object
> *obj,
> > >>>>>> +                                        char *buf, int alloc_size, enum
> > >>>>>> hp_wmi_data_type type)
> > >>>>>> +{
> > >>>>>> +    int buf_size;
> > >>>>>> +    int status;
> > >>>>>> +    char *str = NULL;
> > >>>>>> +    int i;
> > >>>>>> +    int j;
> > >>>>>> +    int integer;
> > >>>>>> +    int size = 0;
> > >>>>>> +
> > >>>>>> +    if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj)
> > >>>>>> +            return -EINVAL;
> > >>>>>> +
> > >>>>>> +    if (obj->type != ACPI_TYPE_BUFFER)
> > >>>>>> +            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]);
> > >>>>>> +
> > >>>>>> +    for (i = 0; i < 3; i++) {
> > >>>>>> +            status = get_string_from_buffer((u16 **)&obj-
> > >>>>>>> buffer.pointer, &str);
> > >>>>>> +            if (ACPI_SUCCESS(status)) {
> > >>>>>> +                    /*
> > >>>>>> +                     * Skip 'Value' (HP_WMI_COMMON_ELEMENTS)
> > >>>>>> since
> > >>>>>> +                     * 'CurrentValue' is reported.
> > >>>>>> +                     */
> > >>>>>> +                    if (type != HPWMI_ENUMERATION_TYPE || i != 1)
> > >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> > >>>>>> +                                                "%s\t\"%s\": \"%s\",\n",
> > >>>>>> +                                                buf,
> > >>>>>> +
> > >>>>>> hp_wmi_elements[type][i], str);
> > >>>>>> +            }
> > >>>>>> +            kfree(str);
> > >>>>>> +            str = NULL;
> > >>>>>> +
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    for (i = 3; i < hp_wmi_elements_count[type]; i++) {
> > >>>>>> +            if (type == HPWMI_ENUMERATION_TYPE && i == 9) {
> > >>>>>> +                    status = get_string_from_buffer((u16 **)&obj-
> > >>>>>>> buffer.pointer, &str);
> > >>>>>> +                    if (ACPI_SUCCESS(status)) {
> > >>>>>> +                            /*
> > >>>>>> +                             * Report "CurrentValue" as "Value"
> > >>>>>> +                             */
> > >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> > >>>>>> +                                                "%s\t\"Value\": \"%s\",\n",
> > >>>>>> buf, str);
> > >>>>>> +                    }
> > >>>>>> +                    kfree(str);
> > >>>>>> +                    str = NULL;
> > >>>>>> +                    continue;
> > >>>>>> +
> > >>>>>> +            } else if (type == HPWMI_PASSWORD_TYPE && i == 12) {
> > >>>>>> +                    /*
> > >>>>>> +                     * Report list of "SupportEncoding"
> > >>>>>> +                     *
> > >>>>>> +                     *      "SupportedEncoding": [
> > >>>>>> +                     *              "utf-16"
> > >>>>>> +                     *      ],
> > >>>>>> +                     *
> > >>>>>> +                     */
> > >>>>>> +
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n",
> > >>>>>> +                                        buf, hp_wmi_elements[type][i]);
> > >>>>>> +                    for (j = 0; j < size; j++) {
> > >>>>>> +                            status = get_string_from_buffer((u16
> > >>>>>> **)&obj->buffer.pointer, &str);
> > >>>>>> +                            if (ACPI_SUCCESS(status)) {
> > >>>>>> +                                    if (j == size - 1)
> > >>>>>> +                                            buf_size = snprintf(buf,
> > >>>>>> alloc_size,
> > >>>>>> +
> > >>>>>> "%s\t\t\"%s\"\n", buf, str);
> > >>>>>> +                                    else
> > >>>>>> +                                            buf_size = snprintf(buf,
> > >>>>>> alloc_size,
> > >>>>>> +
> > >>>>>> "%s\t\t\"%s\",\n", buf, str);
> > >>>>>> +                            }
> > >>>>>> +                            kfree(str);
> > >>>>>> +                            str = NULL;
> > >>>>>> +                    }
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >>>>>> +                    continue;
> > >>>>>> +            }
> > >>>>>> +
> > >>>>>> +            size = 0;
> > >>>>>> +            status = get_integer_from_buffer((int **)&obj-
> > >>>>>>> buffer.pointer, &integer);
> > >>>>>> +            if (ACPI_SUCCESS(status)) {
> > >>>>>> +                    /*
> > >>>>>> +                     * Report "PrerequisiteSize" and "Size" values
> > >>>>>> +                     *      ...
> > >>>>>> +                     *      "PrerequisiteSize": 1,
> > >>>>>> +                     *      ...
> > >>>>>> +                     *      "Size": 2,
> > >>>>>> +                     *      ...
> > >>>>>> +                     */
> > >>>>>> +                    if (i == 7)
> > >>>>>> +                            size = integer;
> > >>>>>> +                    else if (type == HPWMI_ENUMERATION_TYPE && i
> > >>>>>> == 10)
> > >>>>>> +                            size = integer;
> > >>>>>> +                    else if (type == HPWMI_ORDEREDLIST_TYPE && i ==
> > >>>>>> 9)
> > >>>>>> +                            size = integer;
> > >>>>>> +                    else if (type == HPWMI_PASSWORD_TYPE && i ==
> > >>>>>> 11)
> > >>>>>> +                            size = integer;
> > >>>>>> +
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t\"%s\":
> > >>>>>> %d,\n", buf,
> > >>>>>> +                                        hp_wmi_elements[type][i],
> > >>>>>> integer);
> > >>>>>> +            }
> > >>>>>> +
> > >>>>>> +            if (size > 20)
> > >>>>>> +                    pr_warn("%s exceeded the maximum number of
> > >>>>>> elements supported or data may be malformed\n",
> > >>>>>> +                            hp_wmi_elements[type][i]);
> > >>>>>> +
> > >>>>>> +            if (ACPI_SUCCESS(status) && i == 7) {
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> "%s\t\"Prerequisites\": [\n", buf);
> > >>>>>> +                    for (j = 0; j < size; j++) {
> > >>>>>> +                            status = get_string_from_buffer((u16
> > >>>>>> **)&obj->buffer.pointer, &str);
> > >>>>>> +                            if (ACPI_SUCCESS(status)) {
> > >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> "%s\t\t\"%s\"", buf, str);
> > >>>>>> +
> > >>>>>> +                                    if (j == size - 1)
> > >>>>>> +                                            buf_size = snprintf(buf,
> > >>>>>> alloc_size, "%s\n", buf);
> > >>>>>> +                                    else
> > >>>>>> +                                            buf_size = snprintf(buf,
> > >>>>>> alloc_size, "%s,\n", buf);
> > >>>>>> +
> > >>>>>> +                            }
> > >>>>>> +                            kfree(str);
> > >>>>>> +                            str = NULL;
> > >>>>>> +                    }
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >>>>>> +            }
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    if (type == HPWMI_ENUMERATION_TYPE || type ==
> > >>>>>> HPWMI_ORDEREDLIST_TYPE) {
> > >>>>>> +            if (type == HPWMI_ENUMERATION_TYPE)
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> "%s\t\"PossibleValues\": [\n", buf);
> > >>>>>> +            else
> > >>>>>> +                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> "%s\t\"Elements\": [\n", buf);
> > >>>>>> +
> > >>>>>> +            for (i = 0; i < size; i++) {
> > >>>>>> +                    status = get_string_from_buffer((u16 **)&obj-
> > >>>>>>> buffer.pointer, &str);
> > >>>>>> +                    if (ACPI_SUCCESS(status)) {
> > >>>>>> +                            buf_size = snprintf(buf, alloc_size,
> > >>>>>> "%s\t\t\"%s\"", buf, str);
> > >>>>>> +
> > >>>>>> +                            if (i == size - 1)
> > >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> "%s\n", buf);
> > >>>>>> +                            else
> > >>>>>> +                                    buf_size = snprintf(buf, alloc_size,
> > >>>>>> "%s,\n", buf);
> > >>>>>> +
> > >>>>>> +                    }
> > >>>>>> +                    kfree(str);
> > >>>>>> +                    str = NULL;
> > >>>>>> +            }
> > >>>>>> +            buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf);
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    /*
> > >>>>>> +     * remove trailing comma
> > >>>>>> +     */
> > >>>>>> +    if (buf_size > 3)
> > >>>>>> +            buf[buf_size - 2] = ' ';
> > >>>>>> +
> > >>>>>> +    return snprintf(buf, alloc_size, "%s},\n", buf);
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +static int hp_bios_settings_free_buffer(void)
> > >>>>>> +{
> > >>>>>> +    mutex_lock(&buf_mutex);
> > >>>>>> +    kfree(hp_bios_settings_buffer);
> > >>>>>> +    settings_buffer_size = 0;
> > >>>>>> +    buf_alloc_size = 0;
> > >>>>>> +    mutex_unlock(&buf_mutex);
> > >>>>>> +
> > >>>>>> +    return 0;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +static int hp_bios_settings_realloc_buffer(char **buf, int
> *buf_size,
> > >>>>>> +                                       int *alloc_size,
> > >>>>>> +                                       struct mutex *buf_mutex)
> > >>>>>> +{
> > >>>>>> +    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(buf_mutex);
> > >>>>>> +            new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL);
> > >>>>>> +            mutex_unlock(buf_mutex);
> > >>>>>> +            if (new_buf) {
> > >>>>>> +                    mutex_lock(buf_mutex);
> > >>>>>> +                    *buf = new_buf;
> > >>>>>> +                    *alloc_size = ksize(new_buf);
> > >>>>>> +                    mutex_unlock(buf_mutex);
> > >>>>>> +            } else {
> > >>>>>> +                    hp_bios_settings_free_buffer();
> > >>>>>> +                    ret = -ENOMEM;
> > >>>>>> +            }
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    return ret;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +static int append_settings_to_buffer(char *guid, int type, char
> **buf,
> > >>>>>> +                                 int *buf_size, int *alloc_size,
> > >>>>>> +                                 struct mutex *buf_mutex)
> > >>>>>> +{
> > >>>>>> +    union acpi_object *obj = NULL;
> > >>>>>> +    int ret = 0;
> > >>>>>> +    int status = 0;
> > >>>>>> +    int instance = 0;
> > >>>>>> +
> > >>>>>> +    /*
> > >>>>>> +     * Query all the instances until to receive a
> AE_BAD_PARAMETER
> > >>>>>> +     */
> > >>>>>> +    do {
> > >>>>>> +            ret = hp_wmi_get_setting_object(guid, instance++, &obj);
> > >>>>>> +            if (ACPI_SUCCESS(ret) && obj != NULL) {
> > >>>>>> +                    status = 0;
> > >>>>>> +                    if (obj->type == ACPI_TYPE_PACKAGE) {
> > >>>>>> +                            mutex_lock(buf_mutex);
> > >>>>>> +                            status =
> > >>>>>> append_package_elements_to_buffer(obj,
> > >>>>>> +                                                    *buf, *alloc_size,
> > >>>>>> type);
> > >>>>>> +                            if (status > 0)
> > >>>>>> +                                    *buf_size = status;
> > >>>>>> +                            mutex_unlock(buf_mutex);
> > >>>>>> +
> > >>>>>> +                    } else if (obj->type == ACPI_TYPE_BUFFER) {
> > >>>>>> +                            mutex_lock(buf_mutex);
> > >>>>>> +                            status =
> > >>>>>> append_buffer_elements_to_buffer(obj,
> > >>>>>> +                                                    *buf, *alloc_size,
> > >>>>>> type);
> > >>>>>> +                            if (status > 0)
> > >>>>>> +                                    *buf_size = status;
> > >>>>>> +                            mutex_unlock(buf_mutex);
> > >>>>>> +
> > >>>>>> +                    } else
> > >>>>>> +                            pr_warn("The retrieved object type(%d) is
> > >>>>>> not supported yet\n",
> > >>>>>> +                                    obj->type);
> > >>>>>> +
> > >>>>>> +                    ret = hp_bios_settings_realloc_buffer(buf, buf_size,
> > >>>>>> alloc_size, buf_mutex);
> > >>>>>> +            }
> > >>>>>> +
> > >>>>>> +            kfree(obj);
> > >>>>>> +            obj = NULL;
> > >>>>>> +
> > >>>>>> +    } while (ACPI_SUCCESS(ret));
> > >>>>>> +
> > >>>>>> +    /*
> > >>>>>> +     * AE_BAD_PARAMETER means the loop ended by exhaustion
> > >>>>>> +     */
> > >>>>>> +    if (ret == AE_BAD_PARAMETER)
> > >>>>>> +            ret = 0;
> > >>>>>> +
> > >>>>>> +    return ret;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +static int hp_bios_settings_fill_buffer(void)
> > >>>>>> +{
> > >>>>>> +    int status = 0;
> > >>>>>> +    int initial_buffer_size = 20 * PAGE_SIZE;
> > >>>>>> +
> > >>>>>> +    mutex_lock(&buf_mutex);
> > >>>>>> +    hp_bios_settings_buffer = kmalloc(initial_buffer_size,
> > >>> GFP_KERNEL);
> > >>>>>> +    mutex_unlock(&buf_mutex);
> > >>>>>> +    if (!hp_bios_settings_buffer)
> > >>>>>> +            return -ENOMEM;
> > >>>>>> +
> > >>>>>> +    mutex_lock(&buf_mutex);
> > >>>>>> +    buf_alloc_size = ksize(hp_bios_settings_buffer);
> > >>>>>> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > >>>>>> +                                    buf_alloc_size, "[\n");
> > >>>>>> +    mutex_unlock(&buf_mutex);
> > >>>>>> +
> > >>>>>> +    status = append_settings_to_buffer(HPWMI_STRING_GUID,
> > >>>>>> +            HPWMI_STRING_TYPE, &hp_bios_settings_buffer,
> > >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >>>>>> +    if (ACPI_FAILURE(status))
> > >>>>>> +            pr_err("error 0x%x occurred retrieving string instances\n",
> > >>>>>> status);
> > >>>>>> +
> > >>>>>> +    status = append_settings_to_buffer(HPWMI_INTEGER_GUID,
> > >>>>>> +            HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer,
> > >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >>>>>> +    if (ACPI_FAILURE(status))
> > >>>>>> +            pr_err("error 0x%x occurred retrieving integer
> instances\n",
> > >>>>>> status);
> > >>>>>> +
> > >>>>>> +    status =
> > >>> append_settings_to_buffer(HPWMI_ENUMERATION_GUID,
> > >>>>>> +            HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer,
> > >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >>>>>> +    if (ACPI_FAILURE(status))
> > >>>>>> +            pr_err("error 0x%x occurred retrieving enumeration
> > >>>>>> instances\n", status);
> > >>>>>> +
> > >>>>>> +    status =
> append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID,
> > >>>>>> +            HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer,
> > >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >>>>>> +    if (ACPI_FAILURE(status))
> > >>>>>> +            pr_err("error 0x%x occurred retrieving ordered list
> > >>>>>> instances\n", status);
> > >>>>>> +
> > >>>>>> +    status =
> append_settings_to_buffer(HPWMI_PASSWORD_GUID,
> > >>>>>> +            HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer,
> > >>>>>> +            &settings_buffer_size, &buf_alloc_size, &buf_mutex);
> > >>>>>> +    if (ACPI_FAILURE(status))
> > >>>>>> +            pr_err("error 0x%x occurred retrieving password list
> > >>>>>> instances\n", status);
> > >>>>>> +
> > >>>>>> +    mutex_lock(&buf_mutex);
> > >>>>>> +    /*
> > >>>>>> +     * remove trailing comma
> > >>>>>> +     */
> > >>>>>> +    if (settings_buffer_size >= 3) {
> > >>>>>> +            if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',')
> > >>>>>> +                    hp_bios_settings_buffer[settings_buffer_size - 2] = '
> > >>>>>> ';
> > >>>>>> +    }
> > >>>>>> +    settings_buffer_size = snprintf(hp_bios_settings_buffer,
> > >>>>>> +                                    buf_alloc_size, "%s]\n",
> > >>>>>> +                                    hp_bios_settings_buffer);
> > >>>>>> +    mutex_unlock(&buf_mutex);
> > >>>>>> +
> > >>>>>> +    return settings_buffer_size;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +/*
> > >>>>>> + * sure_admin_settings_read - Return a formatted file with
> settings
> > >>>>>> + *                              and possible options read from BIOS
> > >>>>>> + *
> > >>>>>> + * @filp:  Pointer to file of settings read from BIOS
> > >>>>>> + * @kobj:  Pointer to a kernel object of things that show up as
> directory
> > >>> in
> > >>>>>> the sysfs filesystem.
> > >>>>>> + * @attr:  Pointer to list of read attributes
> > >>>>>> + * @buf:   Pointer to buffer
> > >>>>>> + * @off:   File current offset
> > >>>>>> + * @count: Buffer size
> > >>>>>> + *
> > >>>>>> + * Returns the count of unicode chars read if successful,
> otherwise
> > >>>>>> + *          -ENOMEM unable to allocate memory
> > >>>>>> + *          -EINVAL buffer not allocated or too small
> > >>>>>> + *
> > >>>>>> + */
> > >>>>>> +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 >= settings_buffer_size && settings_buffer_size > 0) {
> > >>>>>> +            hp_bios_settings_free_buffer();
> > >>>>>> +            return 0;
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    /* clear the buffer whenever the read starts from the first
> position
> > >>>>>> */
> > >>>>>> +    if (off == 0 && settings_buffer_size > 0)
> > >>>>>> +            hp_bios_settings_free_buffer();
> > >>>>>> +
> > >>>>>> +    if (settings_buffer_size == 0)
> > >>>>>> +            hp_bios_settings_fill_buffer();
> > >>>>>> +
> > >>>>>> +    mutex_lock(&buf_mutex);
> > >>>>>> +    ret = memory_read_from_buffer(buf, count, &off,
> > >>>>>> hp_bios_settings_buffer,
> > >>>>>> +                                  settings_buffer_size);
> > >>>>>> +    mutex_unlock(&buf_mutex);
> > >>>>>> +
> > >>>>>> +    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
> > >>>>>> + */
> > >>>>>> +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str)
> > >>>>>> +{
> > >>>>>> +    int len = strlen(str);
> > >>>>>> +
> > >>>>>> +    /*
> > >>>>>> +     * Add null character when reading an empty string
> > >>>>>> +     */
> > >>>>>> +    if (len == 0) {
> > >>>>>> +            *p++ = 2;
> > >>>>>> +            *p++ = (u8)0x00;
> > >>>>>> +            return p;
> > >>>>>> +    }
> > >>>>>> +    *p++ = len * 2;
> > >>>>>> +    utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len);
> > >>>>>> +    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
> > >>>>>> + */
> > >>>>>> +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32
> 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(HPWMI_SETBIOSSETTING_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;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +/* Sure Admin Functions */
> > >>>>>> +
> > >>>>>> +#define UTF_PREFIX                  ((unsigned char *)"<utf-16/>")
> > >>>>>> +#define BEAM_PREFIX                 ((unsigned char
> > >>>>>> *)"<BEAM/>")
> > >>>>>> +
> > >>>>>> +/*
> > >>>>>> + * sure_admin_settings_write - Write the contents of a
> formatted file
> > >>>>>> + *                               with settings and performs the logic
> > >>>>>> + *                               to change any settings in BIOS.
> > >>>>>> + *
> > >>>>>> + * @filp:  Pointer to file of settings to be written to BIOS
> > >>>>>> + * @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 write operation
> > >>>>>> + * @buf:   Pointer to buffer
> > >>>>>> + * @off:   File current offset
> > >>>>>> + * @count: Buffer size
> > >>>>>> + *
> > >>>>>> + *
> > >>>>>> + * Returns the count of unicode characters written to BIOS if
> > >>> successful,
> > >>>>>> otherwise
> > >>>>>> + *          -ENOMEM unable to allocate memory
> > >>>>>> + *          -EINVAL buffer not allocated or too small
> > >>>>>> + *
> > >>>>>> + */
> > >>>>>> +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;
> > >>>>>> +    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 out_free;
> > >>>>>> +    }
> > >>>>>> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > >>>>>> +    part = strsep(&buf, ",");
> > >>>>>> +    if (!part) {
> > >>>>>> +            status = -EINVAL;
> > >>>>>> +            goto out_free;
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    /* Add extra buffer space when encountering an empty string
> */
> > >>>>>> +    if (!strlen(part))
> > >>>>>> +            buffer_size += sizeof(unsigned short);
> > >>>>>> +    tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > >>>>>> +    part = strsep(&buf, ",");
> > >>>>>> +    if (!part) {
> > >>>>>> +            status = -EINVAL;
> > >>>>>> +            goto out_free;
> > >>>>>> +    }
> > >>>>>> +    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 out_free;
> > >>>>>> +
> > >>>>>> +            tmpstr = ascii_to_utf16_unicode(tmpstr, part);
> > >>>>>> +            kfree(part);
> > >>>>>> +    }
> > >>>>>> +
> > >>>>>> +    part = strsep(&buf, ",");
> > >>>>>> +    if (part) {
> > >>>>>> +            status = -EINVAL;
> > >>>>>> +            goto out_free;
> > >>>>>> +    }
> > >>>>>> +    status = hp_wmi_set_bios_setting(buffer, buffer_size);
> > >>>>>> +    if (ACPI_FAILURE(status))
> > >>>>>> +            status = -EINVAL;
> > >>>>>> +
> > >>>>>> +out_free:
> > >>>>>> +    kfree(buffer);
> > >>>>>> +    if (ACPI_SUCCESS(status))
> > >>>>>> +            return count;
> > >>>>>> +    return status;
> > >>>>>> +}
> > >>>>>> +
> > >>>>>> +HPWMI_BINATTR_RW(sure_admin, settings, 0);
> > >>>>>> +
> > >>>>>> +static struct bin_attribute *sure_admin_binattrs[] = {
> > >>>>>> +    &sure_admin_settings,
> > >>>>>> +    NULL,
> > >>>>>> +};
> > >>>>>> +
> > >>>>>> +static const struct attribute_group sure_admin_group = {
> > >>>>>> +    .name = "sure_admin",
> > >>>>>> +    .bin_attrs = sure_admin_binattrs,
> > >>>>>> +};
> > >>>>>> +
> > >>>>>>  static DEVICE_ATTR_RO(display);
> > >>>>>>  static DEVICE_ATTR_RO(hddtemp);
> > >>>>>>  static DEVICE_ATTR_RW(als);
> > >>>>>> @@ -1050,6 +2026,7 @@ static const struct attribute_group
> > >>>>>> *hp_wmi_groups[] = {
> > >>>>>>      &hp_wmi_group,
> > >>>>>>      &spm_group,
> > >>>>>>      &sure_start_group,
> > >>>>>> +    &sure_admin_group,
> > >>>>>>      NULL,
> > >>>>>>  };
> > >>>>>>
> > >>>>>> --
> > >>>>>> 2.25.1
> > >>>>
> > >
> >

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 5/6] Sure Admin Security Feature
  2022-04-08 14:54                 ` Limonciello, Mario
@ 2022-04-08 15:04                   ` Hans de Goede
  0 siblings, 0 replies; 25+ messages in thread
From: Hans de Goede @ 2022-04-08 15:04 UTC (permalink / raw)
  To: Limonciello, Mario, Jorge Lopez; +Cc: platform-driver-x86

Hi,

On 4/8/22 16:54, Limonciello, Mario wrote:
> [Public]
> 
> 
> 
>> -----Original Message-----
>> From: Jorge Lopez <jorgealtxwork@gmail.com>
>> Sent: Friday, April 8, 2022 09:47
>> To: Hans de Goede <hdegoede@redhat.com>
>> Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; platform-driver-
>> x86@vger.kernel.org
>> Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
>>
>> On Fri, Apr 8, 2022 at 4:21 AM Hans de Goede <hdegoede@redhat.com>
>> wrote:
>>>
>>> Hi Jorge,
>>>
>>> On 4/7/22 15:44, Jorge Lopez wrote:
>>>> Hans, Mario,
>>>>
>>>> The code links make references to code that implements the new
>>>> interfaces but there's
>>>> still code in the kernel that uses the old ones.
>>>
>>> I'm not sure what you mean with "uses the old ones" there never
>>> has been any kernel drivers for changing BIOS settings before
>>> the dell and lenovo drivers were merged.
>>
>> "uses the old ones" statement means that there are drivers on the tree
>> that change BIOS settings without having to convert to the new
>> standards.  hp-wmi remained unsupported for many years so I can
>> understand why the security features need to use the standardized API.
>>
>>>
>>> Sure there are generic mechanisms like chardev-s and ioctls which
>>> are used for a whole bunch of things. But AFAIK there never was
>>> an API specifically for changing BIOS settings before.
>>>
>>>> I do agree we should
>>>> be forward looking
>>>> and want to be good participants in the kernel development, but can't
>>>> let our immediate
>>>> business needs be impacted with opportunities to enhance the driver to
>>>> take advantage
>>>> of the latest kernel features.
>>>>
>>>> Rewriting those security features will impact customer business
>>>> datelines requiring
>>>> HP to provide private releases as the kernel version changes.   The
>>>> requested changes
>>>> will impact products in the market and HP ability to help customers to
>>>> migrate to Linux
>>>> from Windows products.
>>>
>>> This sounds like you are saying that you are already shipping
>>> a version of the driver with the non-standard API to customers.
>>> Shipping code to customers before even proposing it upstream is
>>> HP own choice and the results of that as such are HP's
>>> responsibility.
>>>
>> The products shipped to customers are Windows products and customers
>> are accustomed to how the data is reported and set.  The goal for the
>> new security features in Linux is to help those customers migrate to
>> Linux with little or no change to their scripts/tools.
> 
> I think if this is the situation then a userspace compatibility /conversion tool is
> your better answer than a large compatibility layer in debugfs.
> 
> From the customer perspective they just need to see that JSON file in/out, right?
> So you should be able to write a tool/script that parses all the attributes from
> sysfs in a high level language and puts them into a JSON payload for their scripts
> to work from.  Likewise it should be able to parse a JSON payload and deploy
> all of that stuff into the standard API.

Big +1 from me for this proposal, I agree that having some userspace tool
to work with Windows compatible json files would be best here.


> 
> You can also explain in your documentation associates with such a tool/script
> that it's using a standard API and if they want to use that API directly instead
> of your compatibility tool they're welcome to do so.
> 
>>
>>> You cannot just say we are already shipping this so we need
>>> the upstream kernel to support this non standard API, that is
>>> not how upstream kernel development works.
>>>
>>> I realize that HP is new to working directly with the upstream kernel
>>> community and I realize that being told that the API which you are
>>> already using cannot be used for upstreaming your driver is not what
>>> you want to hear.
>>>
>>> But that does not change that I cannot accept a driver which does not
>>> implement the standard API which the upstream kernel community has
>>> agreed upon for this functionality.
>>>
>>> Or as Mario very elegantly put it:
>>>
>>> 'Keep in mind that from an upstream kernel perspective this driver is
>> "new".
>>> There is no requirements from the upstream perspective to
>>> keep your old interfaces in place from when it was out of tree.'
>>>
>>>> It is because of the immediate business needs, avoiding impacting our
>>>> customers/products,
>>>> and rewriting  enhancements to the driver that I need to propose an
>>>> interim solution.
>>>>
>>>> My proposal is to introduce a read/write value accessible in the user
>>>> space to control how
>>>> the driver reports and handles BIOS settings and values.  The new
>>>> configuration features
>>>> will be gradually disabled  as they are converted to use the standardized
>> API.
>>>> It is like the configuration flag used to overcome the tablet detection
>> problem
>>>> introduced in the past.   The changes solely affect the HP WMI driver.
>>>> This option will help us
>>>> move forward for this release and give us time to make the necessary
>>>> changes to both
>>>> the driver and support applications.
>>>>
>>>> Please let me know if this is a viable interim solution.
>>>
>>> First of all to be very clear, any code going upstream must support
>>> the standard API:
>>>
>>>
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.k
>> ernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%
>> 2Ftree%2FDocumentation%2FABI%2Ftesting%2Fsysfs-class-firmware-
>> attributes&amp;data=04%7C01%7CMario.Limonciello%40amd.com%7Cb0dd9
>> 6dde69d48c4e60c08da196ea2e1%7C3dd8961fe4884e608e11a82d994e183d%7
>> C0%7C0%7C637850260243195656%7CUnknown%7CTWFpbGZsb3d8eyJWIjoi
>> MC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C300
>> 0&amp;sdata=HDIa3CmOAhty7ZtwAoKh5VveEGCC%2Fuq5E1rx0hWOHns%3
>> D&amp;reserved=0
>>>
>>> from day one. I'm not really enthusiastic about the concept of also
>>> supporting the API which you have been using out of tree so far, but
>>> I guess that Mario's suggestion to offer a Kconfig option which
>>> when enabled offers this API under debugfs might be an acceptible
>>> compromise. I would need to see the actual code for that though to
>>> see if this is acceptable.
>>>
>>> And there would need to be a clear cut-of date document after which
>>> the code to support the old API will be removed.
>>>
>>>> If it is not possible, I need to ask where the actual written
>>>> requirement is found so I can
>>>> include them in the business justification for changes and release
>>>> delays to management.
>>>
>>> I'm not sure if this is written down somewhere, but certainly
>>> you will agree that if you were submitting a driver for a soundcard
>>> that that should use the existing ALSA userspace API for sound so
>>> that it would just work with the existing userspace sound support.
>>>
>>> This is the same. If an existing standardized userspace API exists
>>> for a certain functionality then that userspace API _must_ be used,
>>> AFAIK this is not explictly written down anywhere because it is just
>>> very much common sense.
>>
>> I completely agree with your comments and request for the driver to
>> implement the standardized API.  hp-wmi remained unsupported for many
>> years so I can understand why the security features need to use the
>> standardized API.  I am having conversations with other teams on how
>> to move forward with the standard API and how the data is handled and
>> reported.   We will submit a new set of patches utilizing the new
>> standard at a later time.   Would it be accurate to state that any
>> extensions to the standardized API model are acceptable, Correct?
>>
> 
> That's correct.  Dell did the first driver, and then Lenovo did the second.
> The majority of the features from the Dell driver applied to the Lenovo one
> and any idiosyncrasies were introduced as new sysfs files or documented and
> agreed different behaviors of others.

Again +1 / I agree where possible please try to fit things in the standardized
API, but as you can see from both the Dell and Lenovo sections in the API docs,
vendor extensions are allowed.

Regards,

Hans


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 1/6] Correct code style related issues in hp-wmi
  2022-04-04 20:36 ` [PATCH v1 1/6] Correct code style related issues in hp-wmi Jorge Lopez
@ 2022-04-11 12:47   ` Hans de Goede
  2022-04-11 14:00     ` Jorge Lopez
  0 siblings, 1 reply; 25+ messages in thread
From: Hans de Goede @ 2022-04-11 12:47 UTC (permalink / raw)
  To: Jorge Lopez, platform-driver-x86

Hi,

On 4/4/22 22:36, Jorge Lopez wrote:
> Update hp-wmi driver to address all code style issues reported
> by checkpatch.pl script.
> 
> All changes were validated on a HP ZBook Workstation,
> HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> 
> Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>

Thank you for your patch, I've applied this patch to my review-hans 
branch:
https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans

Note it will show up in my review-hans branch once I've pushed my
local branch there, which might take a while.

Once I've run some tests on this branch the patches there will be
added to the platform-drivers-x86/for-next branch and eventually
will be included in the pdx86 pull-request to Linus for the next
merge-window.

Regards,

Hans

p.s.

Note I've decided to not merge the "Update hp_wmi_group to simplify
feature addition" patch for now, since this may turn out to not
be necessary when you change things to use the firmware-atrributes
class.



> ---
> Based on the latest platform-drivers-x86.git/for-next
> 
> v1-0001-Update-hp_wmi_group-to-simplify-feature-addition patch was
> broken in two separate patches.  This patch is patch 1 of 2
> ---
>  drivers/platform/x86/hp-wmi.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
> index 0e9a25b56e0e..667f94bba905 100644
> --- a/drivers/platform/x86/hp-wmi.c
> +++ b/drivers/platform/x86/hp-wmi.c
> @@ -605,6 +605,7 @@ static int hp_wmi_rfkill2_refresh(void)
>  	for (i = 0; i < rfkill2_count; i++) {
>  		int num = rfkill2[i].num;
>  		struct bios_rfkill2_device_state *devstate;
> +
>  		devstate = &state.device[num];
>  
>  		if (num >= state.count ||
> @@ -625,6 +626,7 @@ static ssize_t display_show(struct device *dev, struct device_attribute *attr,
>  			    char *buf)
>  {
>  	int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY);
> +
>  	if (value < 0)
>  		return value;
>  	return sprintf(buf, "%d\n", value);
> @@ -634,6 +636,7 @@ static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr,
>  			    char *buf)
>  {
>  	int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY);
> +
>  	if (value < 0)
>  		return value;
>  	return sprintf(buf, "%d\n", value);
> @@ -643,6 +646,7 @@ static ssize_t als_show(struct device *dev, struct device_attribute *attr,
>  			char *buf)
>  {
>  	int value = hp_wmi_read_int(HPWMI_ALS_QUERY);
> +
>  	if (value < 0)
>  		return value;
>  	return sprintf(buf, "%d\n", value);
> @@ -652,6 +656,7 @@ static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
>  			 char *buf)
>  {
>  	int value = hp_wmi_get_dock_state();
> +
>  	if (value < 0)
>  		return value;
>  	return sprintf(buf, "%d\n", value);
> @@ -661,6 +666,7 @@ static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,
>  			   char *buf)
>  {
>  	int value = hp_wmi_get_tablet_mode();
> +
>  	if (value < 0)
>  		return value;
>  	return sprintf(buf, "%d\n", value);
> @@ -671,6 +677,7 @@ static ssize_t postcode_show(struct device *dev, struct device_attribute *attr,
>  {
>  	/* Get the POST error code of previous boot failure. */
>  	int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY);
> +
>  	if (value < 0)
>  		return value;
>  	return sprintf(buf, "0x%x\n", value);
> @@ -1013,6 +1020,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
>  		struct rfkill *rfkill;
>  		enum rfkill_type type;
>  		char *name;
> +
>  		switch (state.device[i].radio_type) {
>  		case HPWMI_WIFI:
>  			type = RFKILL_TYPE_WLAN;


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v1 1/6] Correct code style related issues in hp-wmi
  2022-04-11 12:47   ` Hans de Goede
@ 2022-04-11 14:00     ` Jorge Lopez
  0 siblings, 0 replies; 25+ messages in thread
From: Jorge Lopez @ 2022-04-11 14:00 UTC (permalink / raw)
  To: Hans de Goede; +Cc: platform-driver-x86

On Mon, Apr 11, 2022 at 7:47 AM Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 4/4/22 22:36, Jorge Lopez wrote:
> > Update hp-wmi driver to address all code style issues reported
> > by checkpatch.pl script.
> >
> > All changes were validated on a HP ZBook Workstation,
> > HP EliteBook x360, and HP EliteBook 850 G8 notebooks.
> >
> > Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
>
> Thank you for your patch, I've applied this patch to my review-hans
> branch:
> https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans
>
> Note it will show up in my review-hans branch once I've pushed my
> local branch there, which might take a while.
>
> Once I've run some tests on this branch the patches there will be
> added to the platform-drivers-x86/for-next branch and eventually
> will be included in the pdx86 pull-request to Linus for the next
> merge-window.
>
> Regards,
>
> Hans
>
> p.s.
>
> Note I've decided to not merge the "Update hp_wmi_group to simplify
> feature addition" patch for now, since this may turn out to not
> be necessary when you change things to use the firmware-atrributes
> class.
>

Thank you.   I will reach out if I have questions about some of the
fields and possible backwards compatibility issues.
>
>
> > ---
> > Based on the latest platform-drivers-x86.git/for-next
> >
> > v1-0001-Update-hp_wmi_group-to-simplify-feature-addition patch was
> > broken in two separate patches.  This patch is patch 1 of 2
> > ---
> >  drivers/platform/x86/hp-wmi.c | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> >
> > diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
> > index 0e9a25b56e0e..667f94bba905 100644
> > --- a/drivers/platform/x86/hp-wmi.c
> > +++ b/drivers/platform/x86/hp-wmi.c
> > @@ -605,6 +605,7 @@ static int hp_wmi_rfkill2_refresh(void)
> >       for (i = 0; i < rfkill2_count; i++) {
> >               int num = rfkill2[i].num;
> >               struct bios_rfkill2_device_state *devstate;
> > +
> >               devstate = &state.device[num];
> >
> >               if (num >= state.count ||
> > @@ -625,6 +626,7 @@ static ssize_t display_show(struct device *dev, struct device_attribute *attr,
> >                           char *buf)
> >  {
> >       int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY);
> > +
> >       if (value < 0)
> >               return value;
> >       return sprintf(buf, "%d\n", value);
> > @@ -634,6 +636,7 @@ static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr,
> >                           char *buf)
> >  {
> >       int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY);
> > +
> >       if (value < 0)
> >               return value;
> >       return sprintf(buf, "%d\n", value);
> > @@ -643,6 +646,7 @@ static ssize_t als_show(struct device *dev, struct device_attribute *attr,
> >                       char *buf)
> >  {
> >       int value = hp_wmi_read_int(HPWMI_ALS_QUERY);
> > +
> >       if (value < 0)
> >               return value;
> >       return sprintf(buf, "%d\n", value);
> > @@ -652,6 +656,7 @@ static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
> >                        char *buf)
> >  {
> >       int value = hp_wmi_get_dock_state();
> > +
> >       if (value < 0)
> >               return value;
> >       return sprintf(buf, "%d\n", value);
> > @@ -661,6 +666,7 @@ static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,
> >                          char *buf)
> >  {
> >       int value = hp_wmi_get_tablet_mode();
> > +
> >       if (value < 0)
> >               return value;
> >       return sprintf(buf, "%d\n", value);
> > @@ -671,6 +677,7 @@ static ssize_t postcode_show(struct device *dev, struct device_attribute *attr,
> >  {
> >       /* Get the POST error code of previous boot failure. */
> >       int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY);
> > +
> >       if (value < 0)
> >               return value;
> >       return sprintf(buf, "0x%x\n", value);
> > @@ -1013,6 +1020,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
> >               struct rfkill *rfkill;
> >               enum rfkill_type type;
> >               char *name;
> > +
> >               switch (state.device[i].radio_type) {
> >               case HPWMI_WIFI:
> >                       type = RFKILL_TYPE_WLAN;
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2022-04-11 14:00 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-04 20:36 [PATCH v1 0/6] HP WMI Security Features Jorge Lopez
2022-04-04 20:36 ` [PATCH v1 1/6] Correct code style related issues in hp-wmi Jorge Lopez
2022-04-11 12:47   ` Hans de Goede
2022-04-11 14:00     ` Jorge Lopez
2022-04-04 20:36 ` [PATCH v1 2/6] Update hp_wmi_group to simplify feature addition Jorge Lopez
2022-04-04 20:36 ` [PATCH v1 3/6] Secure Platform Management Security Feature Jorge Lopez
2022-04-04 20:36 ` [PATCH v1 4/6] Sure Start " Jorge Lopez
2022-04-04 22:05   ` Limonciello, Mario
2022-04-05 16:56     ` Jorge Lopez
2022-04-05 17:09       ` Limonciello, Mario
2022-04-05 18:52         ` Jorge Lopez
2022-04-05 18:54           ` Limonciello, Mario
2022-04-04 20:36 ` [PATCH v1 5/6] Sure Admin " Jorge Lopez
2022-04-04 21:59   ` Limonciello, Mario
2022-04-05 11:54     ` Hans de Goede
2022-04-05 16:52       ` Jorge Lopez
2022-04-05 17:13         ` Limonciello, Mario
2022-04-07 13:44           ` Jorge Lopez
2022-04-07 19:17             ` Limonciello, Mario
2022-04-07 20:57               ` Jorge Lopez
2022-04-08  9:21             ` Hans de Goede
2022-04-08 14:46               ` Jorge Lopez
2022-04-08 14:54                 ` Limonciello, Mario
2022-04-08 15:04                   ` Hans de Goede
2022-04-04 20:36 ` [PATCH v1 6/6] HP Security Features Documentation Jorge Lopez

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.