diff options
Diffstat (limited to 'drivers/platform/x86/think-lmi.c')
| -rw-r--r-- | drivers/platform/x86/think-lmi.c | 65 | 
1 files changed, 55 insertions, 10 deletions
diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index 1138f770149d..52d1ce8dfe44 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -14,6 +14,7 @@  #include <linux/acpi.h>  #include <linux/errno.h>  #include <linux/fs.h> +#include <linux/mutex.h>  #include <linux/string.h>  #include <linux/types.h>  #include <linux/dmi.h> @@ -168,11 +169,11 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support");   */  #define LENOVO_CERT_THUMBPRINT_GUID "C59119ED-1C0D-4806-A8E9-59AA318176C4" -#define TLMI_POP_PWD (1 << 0) -#define TLMI_PAP_PWD (1 << 1) -#define TLMI_HDD_PWD (1 << 2) -#define TLMI_SYS_PWD (1 << 3) -#define TLMI_CERT    (1 << 7) +#define TLMI_POP_PWD BIT(0) /* Supervisor */ +#define TLMI_PAP_PWD BIT(1) /* Power-on */ +#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */ +#define TLMI_SMP_PWD BIT(6) /* System Management */ +#define TLMI_CERT    BIT(7) /* Certificate Based */  #define to_tlmi_pwd_setting(kobj)  container_of(kobj, struct tlmi_pwd_setting, kobj)  #define to_tlmi_attr_setting(kobj)  container_of(kobj, struct tlmi_attr_setting, kobj) @@ -195,6 +196,7 @@ static const char * const level_options[] = {  };  static struct think_lmi tlmi_priv;  static struct class *fw_attr_class; +static DEFINE_MUTEX(tlmi_mutex);  /* ------ Utility functions ------------*/  /* Strip out CR if one is present */ @@ -437,6 +439,9 @@ static ssize_t new_password_store(struct kobject *kobj,  	/* Strip out CR if one is present, setting password won't work if it is present */  	strip_cr(new_pwd); +	/* Use lock in case multiple WMI operations needed */ +	mutex_lock(&tlmi_mutex); +  	pwdlen = strlen(new_pwd);  	/* pwdlen == 0 is allowed to clear the password */  	if (pwdlen && ((pwdlen < setting->minlen) || (pwdlen > setting->maxlen))) { @@ -456,9 +461,9 @@ static ssize_t new_password_store(struct kobject *kobj,  				sprintf(pwd_type, "mhdp%d", setting->index);  		} else if (setting == tlmi_priv.pwd_nvme) {  			if (setting->level == TLMI_LEVEL_USER) -				sprintf(pwd_type, "unvp%d", setting->index); +				sprintf(pwd_type, "udrp%d", setting->index);  			else -				sprintf(pwd_type, "mnvp%d", setting->index); +				sprintf(pwd_type, "adrp%d", setting->index);  		} else {  			sprintf(pwd_type, "%s", setting->pwd_type);  		} @@ -493,6 +498,7 @@ static ssize_t new_password_store(struct kobject *kobj,  		kfree(auth_str);  	}  out: +	mutex_unlock(&tlmi_mutex);  	kfree(new_pwd);  	return ret ?: count;  } @@ -879,6 +885,11 @@ static umode_t auth_attr_is_visible(struct kobject *kobj,  		return 0;  	} +	/* Don't display un-needed settings if opcode available */ +	if ((attr == &auth_encoding.attr || attr == &auth_kbdlang.attr) && +	    tlmi_priv.opcode_support) +		return 0; +  	return attr->mode;  } @@ -981,6 +992,9 @@ static ssize_t current_value_store(struct kobject *kobj,  	/* Strip out CR if one is present */  	strip_cr(new_setting); +	/* Use lock in case multiple WMI operations needed */ +	mutex_lock(&tlmi_mutex); +  	/* Check if certificate authentication is enabled and active */  	if (tlmi_priv.certificate_support && tlmi_priv.pwd_admin->cert_installed) {  		if (!tlmi_priv.pwd_admin->signature || !tlmi_priv.pwd_admin->save_signature) { @@ -1001,7 +1015,33 @@ static ssize_t current_value_store(struct kobject *kobj,  				tlmi_priv.pwd_admin->save_signature);  		if (ret)  			goto out; -	} else { /* Non certiifcate based authentication */ +	} else if (tlmi_priv.opcode_support) { +		/* +		 * If opcode support is present use that interface. +		 * Note - this sets the variable and then the password as separate +		 * WMI calls. Function tlmi_save_bios_settings will error if the +		 * password is incorrect. +		 */ +		set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->display_name, +				    new_setting); +		if (!set_str) { +			ret = -ENOMEM; +			goto out; +		} + +		ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTINGS_GUID, set_str); +		if (ret) +			goto out; + +		if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { +			ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", +						  tlmi_priv.pwd_admin->password); +			if (ret) +				goto out; +		} + +		ret = tlmi_save_bios_settings(""); +	} else { /* old non-opcode based authentication method (deprecated) */  		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, @@ -1039,6 +1079,7 @@ static ssize_t current_value_store(struct kobject *kobj,  		kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE);  	}  out: +	mutex_unlock(&tlmi_mutex);  	kfree(auth_str);  	kfree(set_str);  	kfree(new_setting); @@ -1483,11 +1524,11 @@ static int tlmi_analyze(void)  		tlmi_priv.pwd_power->valid = true;  	if (tlmi_priv.opcode_support) { -		tlmi_priv.pwd_system = tlmi_create_auth("sys", "system"); +		tlmi_priv.pwd_system = tlmi_create_auth("smp", "system");  		if (!tlmi_priv.pwd_system)  			goto fail_clear_attr; -		if (tlmi_priv.pwdcfg.core.password_state & TLMI_SYS_PWD) +		if (tlmi_priv.pwdcfg.core.password_state & TLMI_SMP_PWD)  			tlmi_priv.pwd_system->valid = true;  		tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd"); @@ -1498,6 +1539,10 @@ static int tlmi_analyze(void)  		if (!tlmi_priv.pwd_nvme)  			goto fail_clear_attr; +		/* Set default hdd/nvme index to 1 as there is no device 0 */ +		tlmi_priv.pwd_hdd->index = 1; +		tlmi_priv.pwd_nvme->index = 1; +  		if (tlmi_priv.pwdcfg.core.password_state & TLMI_HDD_PWD) {  			/* Check if PWD is configured and set index to first drive found */  			if (tlmi_priv.pwdcfg.ext.hdd_user_password ||  |