Commit f5bc0157 authored by Mark Pearson's avatar Mark Pearson Committed by Hans de Goede

platform/x86: think-lmi: add debug_cmd

Many Lenovo BIOS's support the ability to send a debug command which
is useful for debugging and testing unreleased or early features.

Adding support for this feature as a module parameter.
Signed-off-by: default avatarMark Pearson <markpearson@lenovo.com>
Link: https://lore.kernel.org/r/20210817001501.293501-1-markpearson@lenovo.comReviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent 45b6f75e
......@@ -272,3 +272,14 @@ Description:
Note that any changes to this attribute requires a reboot
for changes to take effect.
What: /sys/class/firmware-attributes/*/attributes/debug_cmd
Date: July 2021
KernelVersion: 5.14
Contact: Mark Pearson <markpearson@lenovo.com>
Description:
This write only attribute can be used to send debug commands to the BIOS.
This should only be used when recommended by the BIOS vendor. Vendors may
use it to enable extra debug attributes or BIOS features for testing purposes.
Note that any changes to this attribute requires a reboot for changes to take effect.
......@@ -20,6 +20,10 @@
#include "firmware_attributes_class.h"
#include "think-lmi.h"
static bool debug_support;
module_param(debug_support, bool, 0444);
MODULE_PARM_DESC(debug_support, "Enable debug command support");
/*
* Name:
* Lenovo_BiosSetting
......@@ -116,6 +120,14 @@
*/
#define LENOVO_GET_BIOS_SELECTIONS_GUID "7364651A-132F-4FE7-ADAA-40C6C7EE2E3B"
/*
* Name:
* Lenovo_DebugCmdGUID
* Description
* Debug entry GUID method for entering debug commands to the BIOS
*/
#define LENOVO_DEBUG_CMD_GUID "7FF47003-3B6C-4E5E-A227-E979824A85D1"
#define TLMI_POP_PWD (1 << 0)
#define TLMI_PAP_PWD (1 << 1)
#define to_tlmi_pwd_setting(kobj) container_of(kobj, struct tlmi_pwd_setting, kobj)
......@@ -660,6 +672,64 @@ static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *
static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
/* ---- Debug interface--------------------------------------------------------- */
static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
char *set_str = NULL, *new_setting = NULL;
char *auth_str = NULL;
char *p;
int ret;
if (!tlmi_priv.can_debug_cmd)
return -EOPNOTSUPP;
new_setting = kstrdup(buf, GFP_KERNEL);
if (!new_setting)
return -ENOMEM;
/* Strip out CR if one is present */
p = strchrnul(new_setting, '\n');
*p = '\0';
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
tlmi_priv.pwd_admin->password,
encoding_options[tlmi_priv.pwd_admin->encoding],
tlmi_priv.pwd_admin->kbdlang);
if (!auth_str) {
ret = -ENOMEM;
goto out;
}
}
if (auth_str)
set_str = kasprintf(GFP_KERNEL, "%s,%s", new_setting, auth_str);
else
set_str = kasprintf(GFP_KERNEL, "%s;", new_setting);
if (!set_str) {
ret = -ENOMEM;
goto out;
}
ret = tlmi_simple_call(LENOVO_DEBUG_CMD_GUID, set_str);
if (ret)
goto out;
if (!ret && !tlmi_priv.pending_changes) {
tlmi_priv.pending_changes = true;
/* let userland know it may need to check reboot pending again */
kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE);
}
out:
kfree(auth_str);
kfree(set_str);
kfree(new_setting);
return ret ?: count;
}
static struct kobj_attribute debug_cmd = __ATTR_WO(debug_cmd);
/* ---- Initialisation --------------------------------------------------------- */
static void tlmi_release_attr(void)
{
......@@ -673,6 +743,8 @@ static void tlmi_release_attr(void)
}
}
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr);
if (tlmi_priv.can_debug_cmd && debug_support)
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
kset_unregister(tlmi_priv.attribute_kset);
/* Authentication structures */
......@@ -737,6 +809,11 @@ static int tlmi_sysfs_init(void)
if (ret)
goto fail_create_attr;
if (tlmi_priv.can_debug_cmd && debug_support) {
ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
if (ret)
goto fail_create_attr;
}
/* Create authentication entries */
tlmi_priv.authentication_kset = kset_create_and_add("authentication", NULL,
&tlmi_priv.class_dev->kobj);
......@@ -793,6 +870,9 @@ static int tlmi_analyze(void)
if (wmi_has_guid(LENOVO_BIOS_PASSWORD_SETTINGS_GUID))
tlmi_priv.can_get_password_settings = true;
if (wmi_has_guid(LENOVO_DEBUG_CMD_GUID))
tlmi_priv.can_debug_cmd = true;
/*
* Try to find the number of valid settings of this machine
* and use it to create sysfs attributes.
......
......@@ -61,6 +61,7 @@ struct think_lmi {
bool can_set_bios_password;
bool can_get_password_settings;
bool pending_changes;
bool can_debug_cmd;
struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT];
struct device *class_dev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment