From f5bc0157be9baf1e2f12fb53f1e392b955e1c57f Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Mon, 16 Aug 2021 20:15:01 -0400 Subject: 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: Mark Pearson Link: https://lore.kernel.org/r/20210817001501.293501-1-markpearson@lenovo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/think-lmi.c | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'drivers/platform/x86/think-lmi.c') diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index 6cfed4427fb0..9472aae72df2 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -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. -- cgit v1.2.3