/* * Name: BiosSetting * Description: Get item name and settings for current LMI instance. * Type: Query * Returns: "Item,Value" * Example: "WakeOnLAN,Enable"
*/ #define LENOVO_BIOS_SETTING_GUID "51F5230E-9677-46CD-A1CF-C0B23EE34DB7"
/* * Name: SetBiosSetting * Description: Change the BIOS setting to the desired value using the SetBiosSetting * class. To save the settings, use the SaveBiosSetting class. * BIOS settings and values are case sensitive. * After making changes to the BIOS settings, you must reboot the computer * before the changes will take effect. * Type: Method * Arguments: "Item,Value,Password,Encoding,KbdLang;" * Example: "WakeOnLAN,Disable,pa55w0rd,ascii,us;"
*/ #define LENOVO_SET_BIOS_SETTINGS_GUID "98479A64-33F5-4E33-A707-8E251EBBC3A1"
/* * Name: SaveBiosSettings * Description: Save any pending changes in settings. * Type: Method * Arguments: "Password,Encoding,KbdLang;" * Example: "pa55w0rd,ascii,us;"
*/ #define LENOVO_SAVE_BIOS_SETTINGS_GUID "6A4B54EF-A5ED-4D33-9455-B0D9B48DF4B3"
/* * Name: SetBiosPassword * Description: Change a specific password. * - BIOS settings cannot be changed at the same boot as power-on * passwords (POP) and hard disk passwords (HDP). If you want to change * BIOS settings and POP or HDP, you must reboot the system after changing * one of them. * - A password cannot be set using this method when one does not already * exist. Passwords can only be updated or cleared. * Type: Method * Arguments: "PasswordType,CurrentPassword,NewPassword,Encoding,KbdLang;" * Example: "pop,pa55w0rd,newpa55w0rd,ascii,us;”
*/ #define LENOVO_SET_BIOS_PASSWORD_GUID "2651D9FD-911C-4B69-B94E-D0DED5963BD7"
/* * Name: GetBiosSelections * Description: Return a list of valid settings for a given item. * Type: Method * Arguments: "Item" * Returns: "Value1,Value2,Value3,..." * Example: * -> "FlashOverLAN" * <- "Enabled,Disabled"
*/ #define LENOVO_GET_BIOS_SELECTIONS_GUID "7364651A-132F-4FE7-ADAA-40C6C7EE2E3B"
/* * Name: DebugCmd * Description: Debug entry method for entering debug commands to the BIOS
*/ #define LENOVO_DEBUG_CMD_GUID "7FF47003-3B6C-4E5E-A227-E979824A85D1"
/* * Name: OpcodeIF * Description: Opcode interface which provides the ability to set multiple * parameters and then trigger an action with a final command. * This is particularly useful for simplifying setting passwords. * With this support comes the ability to set System, HDD and NVMe * passwords. * This is currently available on ThinkCenter and ThinkStations platforms
*/ #define LENOVO_OPCODE_IF_GUID "DFDDEF2C-57D4-48ce-B196-0FB787D90836"
/* * Name: SetBiosCert * Description: Install BIOS certificate. * Type: Method * Arguments: "Certificate,Password" * You must reboot the computer before the changes will take effect.
*/ #define LENOVO_SET_BIOS_CERT_GUID "26861C9F-47E9-44C4-BD8B-DFE7FA2610FE"
/* * Name: UpdateBiosCert * Description: Update BIOS certificate. * Type: Method * Format: "Certificate,Signature" * You must reboot the computer before the changes will take effect.
*/ #define LENOVO_UPDATE_BIOS_CERT_GUID "9AA3180A-9750-41F7-B9F7-D5D3B1BAC3CE"
/* * Name: ClearBiosCert * Description: Uninstall BIOS certificate. * Type: Method * Format: "Serial,Signature" * You must reboot the computer before the changes will take effect.
*/ #define LENOVO_CLEAR_BIOS_CERT_GUID "B2BC39A7-78DD-4D71-B059-A510DEC44890" /* * Name: CertToPassword * Description: Switch from certificate to password authentication. * Type: Method * Format: "Password,Signature" * You must reboot the computer before the changes will take effect.
*/ #define LENOVO_CERT_TO_PASSWORD_GUID "0DE8590D-5510-4044-9621-77C227F5A70D"
/* Convert BIOS WMI error string to suitable error code */ staticint tlmi_errstr_to_err(constchar *errstr)
{ int i;
for (i = 0; i < sizeof(tlmi_errs)/sizeof(struct tlmi_err_codes); i++) { if (!strcmp(tlmi_errs[i].err_str, errstr)) return tlmi_errs[i].err_code;
} return -EPERM;
}
obj = output->pointer; if (!obj) return -ENOMEM; if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer) return -EIO;
return tlmi_errstr_to_err(obj->string.pointer);
}
/* Utility function to execute WMI call to BIOS */ staticint tlmi_simple_call(constchar *guid, constchar *arg)
{ conststruct acpi_buffer input = { strlen(arg), (char *)arg }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status; int i, err;
/* * Duplicated call required to match BIOS workaround for behavior * seen when WMI accessed via scripting on other OS.
*/ for (i = 0; i < 2; i++) { /* (re)initialize output buffer to default state */
output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL;
status = wmi_evaluate_method(guid, 0, 0, &input, &output); if (ACPI_FAILURE(status)) {
kfree(output.pointer); return -EIO;
}
err = tlmi_extract_error(&output);
kfree(output.pointer); if (err) return err;
} return 0;
}
/* Extract output string from WMI return value */ staticint tlmi_extract_output_string(union acpi_object *obj, char **string)
{ char *s;
if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer) return -EIO;
s = kstrdup(obj->string.pointer, GFP_KERNEL); if (!s) return -ENOMEM;
*string = s; return 0;
}
/* ------ Core interface functions ------------*/
/* Get password settings from BIOS */ staticint tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg)
{ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; constunion acpi_object *obj;
acpi_status status; int copy_size;
if (!tlmi_priv.can_get_password_settings) return -EOPNOTSUPP;
status = wmi_query_block(LENOVO_BIOS_PASSWORD_SETTINGS_GUID, 0,
&output); if (ACPI_FAILURE(status)) return -EIO;
obj = output.pointer; if (!obj) return -ENOMEM; if (obj->type != ACPI_TYPE_BUFFER || !obj->buffer.pointer) {
kfree(obj); return -EIO;
} /* * The size of thinkpad_wmi_pcfg on ThinkStation is larger than ThinkPad. * To make the driver compatible on different brands, we permit it to get * the data in below case. * Settings must have at minimum the core fields available
*/ if (obj->buffer.length < sizeof(struct tlmi_pwdcfg_core)) {
pr_warn("Unknown pwdcfg buffer length %d\n", obj->buffer.length);
kfree(obj); return -EIO;
}
pwdlen = strlen(buf); /* pwdlen == 0 is allowed to clear the password */ if (pwdlen && ((pwdlen < setting->minlen) || (pwdlen > setting->maxlen))) return -EINVAL;
strscpy(setting->password, buf, setting->maxlen); /* Strip out CR if one is present, setting password won't work if it is present */
strreplace(setting->password, '\n', '\0'); return count;
}
if (!tlmi_priv.can_set_bios_password) return -EOPNOTSUPP;
/* Strip out CR if one is present, setting password won't work if it is present */
new_pwd = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_pwd) return -ENOMEM;
/* 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))) {
ret = -EINVAL; goto out;
}
/* If opcode support is present use that interface */ if (tlmi_priv.opcode_support) { char pwd_type[8];
/* Special handling required for HDD and NVMe passwords */ if (setting == tlmi_priv.pwd_hdd) { if (setting->level == TLMI_LEVEL_USER)
sprintf(pwd_type, "uhdp%d", setting->index); else
sprintf(pwd_type, "mhdp%d", setting->index);
} elseif (setting == tlmi_priv.pwd_nvme) { if (setting->level == TLMI_LEVEL_USER)
sprintf(pwd_type, "udrp%d", setting->index); else
sprintf(pwd_type, "adrp%d", setting->index);
} else {
sprintf(pwd_type, "%s", setting->pwd_type);
}
ret = tlmi_opcode_setting("WmiOpcodePasswordType", pwd_type); if (ret) goto out;
/* * Note admin password is not always required if SMPControl enabled in BIOS, * So only set if it's configured. * Let BIOS figure it out - we'll get an error if operation is not permitted
*/ if (tlmi_priv.pwd_admin->pwd_enabled && strlen(tlmi_priv.pwd_admin->password)) {
ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
tlmi_priv.pwd_admin->password); if (ret) goto out;
}
ret = tlmi_opcode_setting("WmiOpcodePasswordCurrent01", setting->password); if (ret) goto out;
ret = tlmi_opcode_setting("WmiOpcodePasswordNew01", new_pwd); if (ret) goto out;
ret = tlmi_simple_call(LENOVO_OPCODE_IF_GUID, "WmiOpcodePasswordSetUpdate;");
} else { /* Format: 'PasswordType,CurrentPw,NewPw,Encoding,KbdLang;' */
auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s,%s,%s;",
setting->pwd_type, setting->password, new_pwd,
encoding_options[setting->encoding], setting->kbdlang); if (!auth_str) {
ret = -ENOMEM; goto out;
}
ret = tlmi_simple_call(LENOVO_SET_BIOS_PASSWORD_GUID, auth_str);
kfree(auth_str);
}
out:
mutex_unlock(&tlmi_mutex);
kfree(new_pwd); return ret ?: count;
}
if (!tlmi_priv.certificate_support) return -EOPNOTSUPP;
/* If empty then clear installed certificate */ if ((buf[0] == '\0') || (buf[0] == '\n')) { /* Clear installed certificate */ /* Check that signature is set */ if (!setting->signature || !setting->signature[0]) return -EACCES;
/* Format: 'serial#, signature' */
serial = dmi_get_system_info(DMI_PRODUCT_SERIAL); if (!serial) return -ENODEV;
auth_str = cert_command(setting, serial, setting->signature); if (!auth_str) return -ENOMEM;
ret = tlmi_simple_call(LENOVO_CLEAR_BIOS_CERT_GUID, auth_str);
kfree(auth_str);
return ret ?: count;
}
/* Strip out CR if one is present */
new_cert = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_cert) return -ENOMEM;
if (setting->cert_installed) { /* Certificate is installed so this is an update */
install_mode = TLMI_CERT_UPDATE; /* If admin account enabled - need to use its signature */ if (tlmi_priv.pwd_admin->pwd_enabled)
signature = tlmi_priv.pwd_admin->signature; else
signature = setting->signature;
} else { /* Cert install */ /* Check if SMC and SVC already installed */ if ((setting == tlmi_priv.pwd_system) && tlmi_priv.pwd_admin->cert_installed) { /* This gets treated as a cert update */
install_mode = TLMI_CERT_UPDATE;
signature = tlmi_priv.pwd_admin->signature;
} else { /* Regular cert install */
install_mode = TLMI_CERT_INSTALL;
signature = setting->signature;
}
}
if (install_mode == TLMI_CERT_UPDATE) { /* This is a certificate update */ if (!signature || !signature[0]) {
kfree(new_cert); return -EACCES;
}
guid = LENOVO_UPDATE_BIOS_CERT_GUID; /* Format: 'Certificate,Signature' */
auth_str = cert_command(setting, new_cert, signature);
} else { /* This is a fresh install */ /* To set admin cert, a password must be enabled */ if ((setting == tlmi_priv.pwd_admin) &&
(!setting->pwd_enabled || !setting->password[0])) {
kfree(new_cert); return -EACCES;
}
guid = LENOVO_SET_BIOS_CERT_GUID; /* Format: 'Certificate, password' */
auth_str = cert_command(setting, new_cert, setting->password);
}
kfree(new_cert); if (!auth_str) return -ENOMEM;
ret = tlmi_simple_call(guid, auth_str);
kfree(auth_str);
/* We only want to display level and index settings on HDD/NVMe */ if (attr == &auth_index.attr || attr == &auth_level.attr) { if ((setting == tlmi_priv.pwd_hdd) || (setting == tlmi_priv.pwd_nvme)) return attr->mode; return 0;
}
/* We only display certificates, if supported */ if (attr == &auth_certificate.attr ||
attr == &auth_signature.attr ||
attr == &auth_save_signature.attr ||
attr == &auth_cert_thumb.attr ||
attr == &auth_cert_to_password.attr) { if (tlmi_priv.certificate_support) { if (setting == tlmi_priv.pwd_admin) return attr->mode; if ((tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) &&
(setting == tlmi_priv.pwd_system)) return attr->mode;
} 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;
ret = tlmi_setting(setting->wdev, setting->index, &item); if (ret) return ret;
/* validate and split from `item,value` -> `value` */
value = strpbrk(item, ","); if (!value || value == item || !strlen(value + 1))
ret = -EINVAL; else { /* On Workstations remove the Options part after the value */
strreplace(value, ';', '\0');
ret = sysfs_emit(buf, "%s\n", value + 1);
}
kfree(item);
if (setting->possible_values) { /* Figure out what setting type is as BIOS does not return this */ if (strchr(setting->possible_values, ';')) return sysfs_emit(buf, "enumeration\n");
} /* Anything else is going to be a string */ return sysfs_emit(buf, "string\n");
}
if (!tlmi_priv.can_set_bios_settings) return -EOPNOTSUPP;
/* * If we are using bulk saves a reboot should be done once save has * been called
*/ if (tlmi_priv.save_mode == TLMI_SAVE_BULK && tlmi_priv.reboot_required) return -EPERM;
/* Strip out CR if one is present */
new_setting = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_setting) return -ENOMEM;
/* 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) {
ret = -EINVAL; goto out;
}
set_str = kasprintf(GFP_KERNEL, "%s,%s,%s", setting->name,
new_setting, tlmi_priv.pwd_admin->signature); if (!set_str) {
ret = -ENOMEM; goto out;
}
ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTING_CERT_GUID, set_str); if (ret) goto out; if (tlmi_priv.save_mode == TLMI_SAVE_BULK)
tlmi_priv.save_required = true; else
ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID,
tlmi_priv.pwd_admin->save_signature);
} elseif (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. * Workstation's require the opcode to be set before changing the * attribute.
*/ if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) {
ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
tlmi_priv.pwd_admin->password); if (ret) goto out;
}
set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->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.save_mode == TLMI_SAVE_BULK)
tlmi_priv.save_required = true; else
ret = tlmi_save_bios_settings("");
} else { /* old non-opcode based authentication method (deprecated) */ if (tlmi_priv.pwd_admin->pwd_enabled && 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,%s", setting->name,
new_setting, auth_str); else
set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->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.save_mode == TLMI_SAVE_BULK) {
tlmi_priv.save_required = true;
} else { if (auth_str)
ret = tlmi_save_bios_settings(auth_str); else
ret = tlmi_save_bios_settings("");
}
} 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:
mutex_unlock(&tlmi_mutex);
kfree(auth_str);
kfree(set_str);
kfree(new_setting); return ret ?: count;
}
/* We don't want to display possible_values attributes if not available */ if ((attr == &attr_possible_values.attr) && (!setting->possible_values)) return 0;
static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute *attr, constchar *buf, size_t count)
{ char *auth_str = NULL; int ret = 0; int cmd;
cmd = sysfs_match_string(save_mode_strings, buf); if (cmd < 0) return cmd;
/* Use lock in case multiple WMI operations needed */
mutex_lock(&tlmi_mutex);
switch (cmd) { case TLMI_SAVE_SINGLE: case TLMI_SAVE_BULK:
tlmi_priv.save_mode = cmd; goto out; case TLMI_SAVE_SAVE: /* Check if supported*/ if (!tlmi_priv.can_set_bios_settings ||
tlmi_priv.save_mode == TLMI_SAVE_SINGLE) {
ret = -EOPNOTSUPP; goto out;
} /* Check there is actually something to save */ if (!tlmi_priv.save_required) {
ret = -ENOENT; goto out;
} /* 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) {
ret = -EINVAL; goto out;
}
ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID,
tlmi_priv.pwd_admin->save_signature); if (ret) goto out;
} elseif (tlmi_priv.opcode_support) { if (tlmi_priv.pwd_admin->pwd_enabled && 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->pwd_enabled && 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)
ret = tlmi_save_bios_settings(auth_str); else
ret = tlmi_save_bios_settings("");
}
tlmi_priv.save_required = false;
tlmi_priv.reboot_required = true;
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);
} break;
}
out:
mutex_unlock(&tlmi_mutex);
kfree(auth_str); return ret ?: count;
}
/* Strip out CR if one is present */
new_setting = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_setting) return -ENOMEM;
if (tlmi_priv.pwd_admin->pwd_enabled && 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;
}
duplicate = kset_find_obj(attribute_kset, name); if (duplicate) {
pr_debug("Duplicate attribute name found - %s\n", name); /* kset_find_obj() returns a reference */
kobject_put(duplicate); return -EBUSY;
}
return 0;
}
staticint tlmi_sysfs_init(void)
{ int i, ret;
tlmi_priv.class_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0),
NULL, "%s", "thinklmi"); if (IS_ERR(tlmi_priv.class_dev)) {
ret = PTR_ERR(tlmi_priv.class_dev); goto fail_class_created;
}
tlmi_priv.attribute_kset = kset_create_and_add("attributes", NULL,
&tlmi_priv.class_dev->kobj); if (!tlmi_priv.attribute_kset) {
ret = -ENOMEM; goto fail_device_created;
}
tlmi_priv.authentication_kset = kset_create_and_add("authentication", NULL,
&tlmi_priv.class_dev->kobj); if (!tlmi_priv.authentication_kset) {
kset_unregister(tlmi_priv.attribute_kset);
ret = -ENOMEM; goto fail_device_created;
}
for (i = 0; i < TLMI_SETTINGS_COUNT; i++) { /* Check if index is a valid setting - skip if it isn't */ if (!tlmi_priv.setting[i]) continue;
/* check for duplicate or reserved values */ if (tlmi_validate_setting_name(tlmi_priv.attribute_kset,
tlmi_priv.setting[i]->display_name) < 0) {
kfree(tlmi_priv.setting[i]->possible_values);
kfree(tlmi_priv.setting[i]);
tlmi_priv.setting[i] = NULL; continue;
}
/* Build attribute */
tlmi_priv.setting[i]->kobj.kset = tlmi_priv.attribute_kset;
ret = kobject_init_and_add(&tlmi_priv.setting[i]->kobj, &tlmi_attr_setting_ktype,
NULL, "%s", tlmi_priv.setting[i]->display_name); if (ret) goto fail_create_attr;
}
ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr); if (ret) goto fail_create_attr;
ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &save_settings.attr); 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.pwd_admin->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_init_and_add(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "Admin"); if (ret) goto fail_create_attr;
tlmi_priv.pwd_power->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_init_and_add(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "Power-on"); if (ret) goto fail_create_attr;
if (tlmi_priv.opcode_support) {
tlmi_priv.pwd_system->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_init_and_add(&tlmi_priv.pwd_system->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "System"); if (ret) goto fail_create_attr;
tlmi_priv.pwd_hdd->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_init_and_add(&tlmi_priv.pwd_hdd->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "HDD"); if (ret) goto fail_create_attr;
tlmi_priv.pwd_nvme->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_init_and_add(&tlmi_priv.pwd_nvme->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "NVMe"); if (ret) goto fail_create_attr;
}
staticint tlmi_analyze(struct wmi_device *wdev)
{ int i, ret;
if (wmi_has_guid(LENOVO_SET_BIOS_SETTINGS_GUID) &&
wmi_has_guid(LENOVO_SAVE_BIOS_SETTINGS_GUID))
tlmi_priv.can_set_bios_settings = true;
if (wmi_has_guid(LENOVO_GET_BIOS_SELECTIONS_GUID))
tlmi_priv.can_get_bios_selections = true;
if (wmi_has_guid(LENOVO_SET_BIOS_PASSWORD_GUID))
tlmi_priv.can_set_bios_password = true;
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;
if (wmi_has_guid(LENOVO_OPCODE_IF_GUID))
tlmi_priv.opcode_support = true;
if (wmi_has_guid(LENOVO_SET_BIOS_CERT_GUID) &&
wmi_has_guid(LENOVO_SET_BIOS_SETTING_CERT_GUID) &&
wmi_has_guid(LENOVO_SAVE_BIOS_SETTING_CERT_GUID))
tlmi_priv.certificate_support = true;
/* * Try to find the number of valid settings of this machine * and use it to create sysfs attributes.
*/ for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) { struct tlmi_attr_setting *setting; char *item = NULL;
tlmi_priv.setting[i] = NULL;
ret = tlmi_setting(wdev, i, &item); if (ret) break; if (!item) break; if (!*item) {
kfree(item); continue;
}
/* Remove the value part */
strreplace(item, ',', '\0');
/* Create a setting entry */
setting = kzalloc(sizeof(*setting), GFP_KERNEL); if (!setting) {
ret = -ENOMEM;
kfree(item); goto fail_clear_attr;
}
setting->wdev = wdev;
setting->index = i;
strscpy(setting->name, item); /* It is not allowed to have '/' for file name. Convert it into '\'. */
strreplace(item, '/', '\\');
strscpy(setting->display_name, item);
/* If BIOS selections supported, load those */ if (tlmi_priv.can_get_bios_selections) {
ret = tlmi_get_bios_selections(setting->name,
&setting->possible_values); if (ret || !setting->possible_values)
pr_info("Error retrieving possible values for %d : %s\n",
i, setting->display_name);
} else { /* * Older Thinkstations don't support the bios_selections API. * Instead they store this as a [Optional:Option1,Option2] section of the * name string. * Try and pull that out if it's available.
*/ char *optitem, *optstart, *optend;
if (!tlmi_setting(setting->wdev, setting->index, &optitem)) {
optstart = strstr(optitem, "[Optional:"); if (optstart) {
optstart += strlen("[Optional:");
optend = strstr(optstart, "]"); if (optend)
setting->possible_values =
kstrndup(optstart, optend - optstart,
GFP_KERNEL);
}
kfree(optitem);
}
} /* * firmware-attributes requires that possible_values are separated by ';' but * Lenovo FW uses ','. Replace appropriately.
*/ if (setting->possible_values)
strreplace(setting->possible_values, ',', ';');
tlmi_priv.setting[i] = setting;
kfree(item);
}
/* Create password setting structure */
ret = tlmi_get_pwd_settings(&tlmi_priv.pwdcfg); if (ret) goto fail_clear_attr;
/* All failures below boil down to kmalloc failures */
ret = -ENOMEM;
tlmi_priv.pwd_admin = tlmi_create_auth("pap", "bios-admin"); if (!tlmi_priv.pwd_admin) goto fail_clear_attr;
if (tlmi_priv.pwdcfg.core.password_state & TLMI_PAP_PWD)
tlmi_priv.pwd_admin->pwd_enabled = true;
tlmi_priv.pwd_power = tlmi_create_auth("pop", "power-on"); if (!tlmi_priv.pwd_power) goto fail_clear_attr;
if (tlmi_priv.pwdcfg.core.password_state & TLMI_POP_PWD)
tlmi_priv.pwd_power->pwd_enabled = true;
if (tlmi_priv.opcode_support) {
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_SMP_PWD)
tlmi_priv.pwd_system->pwd_enabled = true;
tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd"); if (!tlmi_priv.pwd_hdd) goto fail_clear_attr;
tlmi_priv.pwd_nvme = tlmi_create_auth("nvm", "nvme"); 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 ||
tlmi_priv.pwdcfg.ext.hdd_master_password) {
tlmi_priv.pwd_hdd->pwd_enabled = true; if (tlmi_priv.pwdcfg.ext.hdd_master_password)
tlmi_priv.pwd_hdd->index =
ffs(tlmi_priv.pwdcfg.ext.hdd_master_password) - 1; else
tlmi_priv.pwd_hdd->index =
ffs(tlmi_priv.pwdcfg.ext.hdd_user_password) - 1;
} if (tlmi_priv.pwdcfg.ext.nvme_user_password ||
tlmi_priv.pwdcfg.ext.nvme_master_password) {
tlmi_priv.pwd_nvme->pwd_enabled = true; if (tlmi_priv.pwdcfg.ext.nvme_master_password)
tlmi_priv.pwd_nvme->index =
ffs(tlmi_priv.pwdcfg.ext.nvme_master_password) - 1; else
tlmi_priv.pwd_nvme->index =
ffs(tlmi_priv.pwdcfg.ext.nvme_user_password) - 1;
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.