All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jorge Lopez <jorgealtxwork@gmail.com>
To: "Limonciello, Mario" <Mario.Limonciello@amd.com>
Cc: Hans de Goede <hdegoede@redhat.com>,
	"platform-driver-x86@vger.kernel.org" 
	<platform-driver-x86@vger.kernel.org>
Subject: Re: [PATCH v1 5/6] Sure Admin Security Feature
Date: Thu, 7 Apr 2022 15:57:20 -0500	[thread overview]
Message-ID: <CAOOmCE9ewPqT0ph1miO17_3yAoknQ+KrZHrrG1E2kL5cynN5BA@mail.gmail.com> (raw)
In-Reply-To: <BL1PR12MB51572C0DA95007271012B6AAE2E69@BL1PR12MB5157.namprd12.prod.outlook.com>

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

  reply	other threads:[~2022-04-07 20:57 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=CAOOmCE9ewPqT0ph1miO17_3yAoknQ+KrZHrrG1E2kL5cynN5BA@mail.gmail.com \
    --to=jorgealtxwork@gmail.com \
    --cc=Mario.Limonciello@amd.com \
    --cc=hdegoede@redhat.com \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is 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.