@@ -985,6 +985,13 @@ static ssize_t current_value_store(struct kobject *kobj,
985985 if (!tlmi_priv .can_set_bios_settings )
986986 return - EOPNOTSUPP ;
987987
988+ /*
989+ * If we are using bulk saves a reboot should be done once save has
990+ * been called
991+ */
992+ if (tlmi_priv .save_mode == TLMI_SAVE_BULK && tlmi_priv .reboot_required )
993+ return - EPERM ;
994+
988995 new_setting = kstrdup (buf , GFP_KERNEL );
989996 if (!new_setting )
990997 return - ENOMEM ;
@@ -1011,10 +1018,11 @@ static ssize_t current_value_store(struct kobject *kobj,
10111018 ret = tlmi_simple_call (LENOVO_SET_BIOS_SETTING_CERT_GUID , set_str );
10121019 if (ret )
10131020 goto out ;
1014- ret = tlmi_simple_call (LENOVO_SAVE_BIOS_SETTING_CERT_GUID ,
1015- tlmi_priv .pwd_admin -> save_signature );
1016- if (ret )
1017- goto out ;
1021+ if (tlmi_priv .save_mode == TLMI_SAVE_BULK )
1022+ tlmi_priv .save_required = true;
1023+ else
1024+ ret = tlmi_simple_call (LENOVO_SAVE_BIOS_SETTING_CERT_GUID ,
1025+ tlmi_priv .pwd_admin -> save_signature );
10181026 } else if (tlmi_priv .opcode_support ) {
10191027 /*
10201028 * If opcode support is present use that interface.
@@ -1033,14 +1041,17 @@ static ssize_t current_value_store(struct kobject *kobj,
10331041 if (ret )
10341042 goto out ;
10351043
1036- if (tlmi_priv .pwd_admin -> valid && tlmi_priv .pwd_admin -> password [0 ]) {
1037- ret = tlmi_opcode_setting ("WmiOpcodePasswordAdmin" ,
1038- tlmi_priv .pwd_admin -> password );
1039- if (ret )
1040- goto out ;
1044+ if (tlmi_priv .save_mode == TLMI_SAVE_BULK ) {
1045+ tlmi_priv .save_required = true;
1046+ } else {
1047+ if (tlmi_priv .pwd_admin -> valid && tlmi_priv .pwd_admin -> password [0 ]) {
1048+ ret = tlmi_opcode_setting ("WmiOpcodePasswordAdmin" ,
1049+ tlmi_priv .pwd_admin -> password );
1050+ if (ret )
1051+ goto out ;
1052+ }
1053+ ret = tlmi_save_bios_settings ("" );
10411054 }
1042-
1043- ret = tlmi_save_bios_settings ("" );
10441055 } else { /* old non-opcode based authentication method (deprecated) */
10451056 if (tlmi_priv .pwd_admin -> valid && tlmi_priv .pwd_admin -> password [0 ]) {
10461057 auth_str = kasprintf (GFP_KERNEL , "%s,%s,%s;" ,
@@ -1068,10 +1079,14 @@ static ssize_t current_value_store(struct kobject *kobj,
10681079 if (ret )
10691080 goto out ;
10701081
1071- if (auth_str )
1072- ret = tlmi_save_bios_settings (auth_str );
1073- else
1074- ret = tlmi_save_bios_settings ("" );
1082+ if (tlmi_priv .save_mode == TLMI_SAVE_BULK ) {
1083+ tlmi_priv .save_required = true;
1084+ } else {
1085+ if (auth_str )
1086+ ret = tlmi_save_bios_settings (auth_str );
1087+ else
1088+ ret = tlmi_save_bios_settings ("" );
1089+ }
10751090 }
10761091 if (!ret && !tlmi_priv .pending_changes ) {
10771092 tlmi_priv .pending_changes = true;
@@ -1152,6 +1167,107 @@ static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *
11521167
11531168static struct kobj_attribute pending_reboot = __ATTR_RO (pending_reboot );
11541169
1170+ static const char * const save_mode_strings [] = {
1171+ [TLMI_SAVE_SINGLE ] = "single" ,
1172+ [TLMI_SAVE_BULK ] = "bulk" ,
1173+ [TLMI_SAVE_SAVE ] = "save"
1174+ };
1175+
1176+ static ssize_t save_settings_show (struct kobject * kobj , struct kobj_attribute * attr ,
1177+ char * buf )
1178+ {
1179+ /* Check that setting is valid */
1180+ if (WARN_ON (tlmi_priv .save_mode < TLMI_SAVE_SINGLE ||
1181+ tlmi_priv .save_mode > TLMI_SAVE_BULK ))
1182+ return - EIO ;
1183+ return sysfs_emit (buf , "%s\n" , save_mode_strings [tlmi_priv .save_mode ]);
1184+ }
1185+
1186+ static ssize_t save_settings_store (struct kobject * kobj , struct kobj_attribute * attr ,
1187+ const char * buf , size_t count )
1188+ {
1189+ char * auth_str = NULL ;
1190+ int ret = 0 ;
1191+ int cmd ;
1192+
1193+ cmd = sysfs_match_string (save_mode_strings , buf );
1194+ if (cmd < 0 )
1195+ return cmd ;
1196+
1197+ /* Use lock in case multiple WMI operations needed */
1198+ mutex_lock (& tlmi_mutex );
1199+
1200+ switch (cmd ) {
1201+ case TLMI_SAVE_SINGLE :
1202+ case TLMI_SAVE_BULK :
1203+ tlmi_priv .save_mode = cmd ;
1204+ goto out ;
1205+ case TLMI_SAVE_SAVE :
1206+ /* Check if supported*/
1207+ if (!tlmi_priv .can_set_bios_settings ||
1208+ tlmi_priv .save_mode == TLMI_SAVE_SINGLE ) {
1209+ ret = - EOPNOTSUPP ;
1210+ goto out ;
1211+ }
1212+ /* Check there is actually something to save */
1213+ if (!tlmi_priv .save_required ) {
1214+ ret = - ENOENT ;
1215+ goto out ;
1216+ }
1217+ /* Check if certificate authentication is enabled and active */
1218+ if (tlmi_priv .certificate_support && tlmi_priv .pwd_admin -> cert_installed ) {
1219+ if (!tlmi_priv .pwd_admin -> signature ||
1220+ !tlmi_priv .pwd_admin -> save_signature ) {
1221+ ret = - EINVAL ;
1222+ goto out ;
1223+ }
1224+ ret = tlmi_simple_call (LENOVO_SAVE_BIOS_SETTING_CERT_GUID ,
1225+ tlmi_priv .pwd_admin -> save_signature );
1226+ if (ret )
1227+ goto out ;
1228+ } else if (tlmi_priv .opcode_support ) {
1229+ if (tlmi_priv .pwd_admin -> valid && tlmi_priv .pwd_admin -> password [0 ]) {
1230+ ret = tlmi_opcode_setting ("WmiOpcodePasswordAdmin" ,
1231+ tlmi_priv .pwd_admin -> password );
1232+ if (ret )
1233+ goto out ;
1234+ }
1235+ ret = tlmi_save_bios_settings ("" );
1236+ } else { /* old non-opcode based authentication method (deprecated) */
1237+ if (tlmi_priv .pwd_admin -> valid && tlmi_priv .pwd_admin -> password [0 ]) {
1238+ auth_str = kasprintf (GFP_KERNEL , "%s,%s,%s;" ,
1239+ tlmi_priv .pwd_admin -> password ,
1240+ encoding_options [tlmi_priv .pwd_admin -> encoding ],
1241+ tlmi_priv .pwd_admin -> kbdlang );
1242+ if (!auth_str ) {
1243+ ret = - ENOMEM ;
1244+ goto out ;
1245+ }
1246+ }
1247+
1248+ if (auth_str )
1249+ ret = tlmi_save_bios_settings (auth_str );
1250+ else
1251+ ret = tlmi_save_bios_settings ("" );
1252+ }
1253+ tlmi_priv .save_required = false;
1254+ tlmi_priv .reboot_required = true;
1255+
1256+ if (!ret && !tlmi_priv .pending_changes ) {
1257+ tlmi_priv .pending_changes = true;
1258+ /* let userland know it may need to check reboot pending again */
1259+ kobject_uevent (& tlmi_priv .class_dev -> kobj , KOBJ_CHANGE );
1260+ }
1261+ break ;
1262+ }
1263+ out :
1264+ mutex_unlock (& tlmi_mutex );
1265+ kfree (auth_str );
1266+ return ret ?: count ;
1267+ }
1268+
1269+ static struct kobj_attribute save_settings = __ATTR_RW (save_settings );
1270+
11551271/* ---- Debug interface--------------------------------------------------------- */
11561272static ssize_t debug_cmd_store (struct kobject * kobj , struct kobj_attribute * attr ,
11571273 const char * buf , size_t count )
@@ -1221,6 +1337,8 @@ static void tlmi_release_attr(void)
12211337 }
12221338 }
12231339 sysfs_remove_file (& tlmi_priv .attribute_kset -> kobj , & pending_reboot .attr );
1340+ sysfs_remove_file (& tlmi_priv .attribute_kset -> kobj , & save_settings .attr );
1341+
12241342 if (tlmi_priv .can_debug_cmd && debug_support )
12251343 sysfs_remove_file (& tlmi_priv .attribute_kset -> kobj , & debug_cmd .attr );
12261344
@@ -1302,6 +1420,10 @@ static int tlmi_sysfs_init(void)
13021420 if (ret )
13031421 goto fail_create_attr ;
13041422
1423+ ret = sysfs_create_file (& tlmi_priv .attribute_kset -> kobj , & save_settings .attr );
1424+ if (ret )
1425+ goto fail_create_attr ;
1426+
13051427 if (tlmi_priv .can_debug_cmd && debug_support ) {
13061428 ret = sysfs_create_file (& tlmi_priv .attribute_kset -> kobj , & debug_cmd .attr );
13071429 if (ret )
0 commit comments