ksmbd: fix race condition between tree conn lookup and disconnect
[platform/kernel/linux-starfive.git] / drivers / platform / x86 / hp / hp-bioscfg / bioscfg.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Common methods for use with hp-bioscfg driver
4  *
5  *  Copyright (c) 2022 HP Development Company, L.P.
6  */
7
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10 #include <linux/fs.h>
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/wmi.h>
14 #include "bioscfg.h"
15 #include "../../firmware_attributes_class.h"
16 #include <linux/nls.h>
17 #include <linux/errno.h>
18
19 MODULE_AUTHOR("Jorge Lopez <jorge.lopez2@hp.com>");
20 MODULE_DESCRIPTION("HP BIOS Configuration Driver");
21 MODULE_LICENSE("GPL");
22
23 struct bioscfg_priv bioscfg_drv = {
24         .mutex = __MUTEX_INITIALIZER(bioscfg_drv.mutex),
25 };
26
27 static struct class *fw_attr_class;
28
29 ssize_t display_name_language_code_show(struct kobject *kobj,
30                                         struct kobj_attribute *attr,
31                                         char *buf)
32 {
33         return sysfs_emit(buf, "%s\n", LANG_CODE_STR);
34 }
35
36 struct kobj_attribute common_display_langcode =
37         __ATTR_RO(display_name_language_code);
38
39 int hp_get_integer_from_buffer(u8 **buffer, u32 *buffer_size, u32 *integer)
40 {
41         int *ptr = PTR_ALIGN((int *)*buffer, sizeof(int));
42
43         /* Ensure there is enough space remaining to read the integer */
44         if (*buffer_size < sizeof(int))
45                 return -EINVAL;
46
47         *integer = *(ptr++);
48         *buffer = (u8 *)ptr;
49         *buffer_size -= sizeof(int);
50
51         return 0;
52 }
53
54 int hp_get_string_from_buffer(u8 **buffer, u32 *buffer_size, char *dst, u32 dst_size)
55 {
56         u16 *src = (u16 *)*buffer;
57         u16 src_size;
58
59         u16 size;
60         int i;
61         int conv_dst_size;
62
63         if (*buffer_size < sizeof(u16))
64                 return -EINVAL;
65
66         src_size = *(src++);
67         /* size value in u16 chars */
68         size = src_size / sizeof(u16);
69
70         /* Ensure there is enough space remaining to read and convert
71          * the string
72          */
73         if (*buffer_size < src_size)
74                 return -EINVAL;
75
76         for (i = 0; i < size; i++)
77                 if (src[i] == '\\' ||
78                     src[i] == '\r' ||
79                     src[i] == '\n' ||
80                     src[i] == '\t')
81                         size++;
82
83         /*
84          * Conversion is limited to destination string max number of
85          * bytes.
86          */
87         conv_dst_size = size;
88         if (size > dst_size)
89                 conv_dst_size = dst_size - 1;
90
91         /*
92          * convert from UTF-16 unicode to ASCII
93          */
94         utf16s_to_utf8s(src, src_size, UTF16_HOST_ENDIAN, dst, conv_dst_size);
95         dst[conv_dst_size] = 0;
96
97         for (i = 0; i < conv_dst_size; i++) {
98                 if (*src == '\\' ||
99                     *src == '\r' ||
100                     *src == '\n' ||
101                     *src == '\t') {
102                         dst[i++] = '\\';
103                         if (i == conv_dst_size)
104                                 break;
105                 }
106
107                 if (*src == '\r')
108                         dst[i] = 'r';
109                 else if (*src == '\n')
110                         dst[i] = 'n';
111                 else if (*src == '\t')
112                         dst[i] = 't';
113                 else if (*src == '"')
114                         dst[i] = '\'';
115                 else
116                         dst[i] = *src;
117                 src++;
118         }
119
120         *buffer = (u8 *)src;
121         *buffer_size -= size * sizeof(u16);
122
123         return size;
124 }
125
126 int hp_get_common_data_from_buffer(u8 **buffer_ptr, u32 *buffer_size,
127                                    struct common_data *common_data)
128 {
129         int ret = 0;
130         int reqs;
131
132         // PATH:
133         ret = hp_get_string_from_buffer(buffer_ptr, buffer_size, common_data->path,
134                                         sizeof(common_data->path));
135         if (ret < 0)
136                 goto common_exit;
137
138         // IS_READONLY:
139         ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
140                                          &common_data->is_readonly);
141         if (ret < 0)
142                 goto common_exit;
143
144         //DISPLAY_IN_UI:
145         ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
146                                          &common_data->display_in_ui);
147         if (ret < 0)
148                 goto common_exit;
149
150         // REQUIRES_PHYSICAL_PRESENCE:
151         ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
152                                          &common_data->requires_physical_presence);
153         if (ret < 0)
154                 goto common_exit;
155
156         // SEQUENCE:
157         ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
158                                          &common_data->sequence);
159         if (ret < 0)
160                 goto common_exit;
161
162         // PREREQUISITES_SIZE:
163         ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
164                                          &common_data->prerequisites_size);
165         if (ret < 0)
166                 goto common_exit;
167
168         if (common_data->prerequisites_size > MAX_PREREQUISITES_SIZE) {
169                 /* Report a message and limit prerequisite size to maximum value */
170                 pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
171                 common_data->prerequisites_size = MAX_PREREQUISITES_SIZE;
172         }
173
174         // PREREQUISITES:
175         for (reqs = 0; reqs < common_data->prerequisites_size; reqs++) {
176                 ret = hp_get_string_from_buffer(buffer_ptr, buffer_size,
177                                                 common_data->prerequisites[reqs],
178                                                 sizeof(common_data->prerequisites[reqs]));
179                 if (ret < 0)
180                         break;
181         }
182
183         // SECURITY_LEVEL:
184         ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size,
185                                          &common_data->security_level);
186
187 common_exit:
188         return ret;
189 }
190
191 int hp_enforce_single_line_input(char *buf, size_t count)
192 {
193         char *p;
194
195         p = memchr(buf, '\n', count);
196
197         if (p == buf + count - 1)
198                 *p = '\0'; /* strip trailing newline */
199         else if (p)
200                 return -EINVAL;  /* enforce single line input */
201
202         return 0;
203 }
204
205 /* Set pending reboot value and generate KOBJ_NAME event */
206 void hp_set_reboot_and_signal_event(void)
207 {
208         bioscfg_drv.pending_reboot = true;
209         kobject_uevent(&bioscfg_drv.class_dev->kobj, KOBJ_CHANGE);
210 }
211
212 /**
213  * hp_calculate_string_buffer() - determines size of string buffer for
214  * use with BIOS communication
215  *
216  * @str: the string to calculate based upon
217  */
218 size_t hp_calculate_string_buffer(const char *str)
219 {
220         size_t length = strlen(str);
221
222         /* BIOS expects 4 bytes when an empty string is found */
223         if (length == 0)
224                 return 4;
225
226         /* u16 length field + one UTF16 char for each input char */
227         return sizeof(u16) + strlen(str) * sizeof(u16);
228 }
229
230 int hp_wmi_error_and_message(int error_code)
231 {
232         char *error_msg = NULL;
233         int ret;
234
235         switch (error_code) {
236         case SUCCESS:
237                 error_msg = "Success";
238                 ret = 0;
239                 break;
240         case CMD_FAILED:
241                 error_msg = "Command failed";
242                 ret = -EINVAL;
243                 break;
244         case INVALID_SIGN:
245                 error_msg = "Invalid signature";
246                 ret = -EINVAL;
247                 break;
248         case INVALID_CMD_VALUE:
249                 error_msg = "Invalid command value/Feature not supported";
250                 ret = -EOPNOTSUPP;
251                 break;
252         case INVALID_CMD_TYPE:
253                 error_msg = "Invalid command type";
254                 ret = -EINVAL;
255                 break;
256         case INVALID_DATA_SIZE:
257                 error_msg = "Invalid data size";
258                 ret = -EINVAL;
259                 break;
260         case INVALID_CMD_PARAM:
261                 error_msg = "Invalid command parameter";
262                 ret = -EINVAL;
263                 break;
264         case ENCRYP_CMD_REQUIRED:
265                 error_msg = "Secure/encrypted command required";
266                 ret = -EACCES;
267                 break;
268         case NO_SECURE_SESSION:
269                 error_msg = "No secure session established";
270                 ret = -EACCES;
271                 break;
272         case SECURE_SESSION_FOUND:
273                 error_msg = "Secure session already established";
274                 ret = -EACCES;
275                 break;
276         case SECURE_SESSION_FAILED:
277                 error_msg = "Secure session failed";
278                 ret = -EIO;
279                 break;
280         case AUTH_FAILED:
281                 error_msg = "Other permission/Authentication failed";
282                 ret = -EACCES;
283                 break;
284         case INVALID_BIOS_AUTH:
285                 error_msg = "Invalid BIOS administrator password";
286                 ret = -EINVAL;
287                 break;
288         case NONCE_DID_NOT_MATCH:
289                 error_msg = "Nonce did not match";
290                 ret = -EINVAL;
291                 break;
292         case GENERIC_ERROR:
293                 error_msg = "Generic/Other error";
294                 ret = -EIO;
295                 break;
296         case BIOS_ADMIN_POLICY_NOT_MET:
297                 error_msg = "BIOS Admin password does not meet password policy requirements";
298                 ret = -EINVAL;
299                 break;
300         case BIOS_ADMIN_NOT_SET:
301                 error_msg = "BIOS Setup password is not set";
302                 ret = -EPERM;
303                 break;
304         case P21_NO_PROVISIONED:
305                 error_msg = "P21 is not provisioned";
306                 ret = -EPERM;
307                 break;
308         case P21_PROVISION_IN_PROGRESS:
309                 error_msg = "P21 is already provisioned or provisioning is in progress and a signing key has already been sent";
310                 ret = -EINPROGRESS;
311                 break;
312         case P21_IN_USE:
313                 error_msg = "P21 in use (cannot deprovision)";
314                 ret = -EPERM;
315                 break;
316         case HEP_NOT_ACTIVE:
317                 error_msg = "HEP not activated";
318                 ret = -EPERM;
319                 break;
320         case HEP_ALREADY_SET:
321                 error_msg = "HEP Transport already set";
322                 ret = -EINVAL;
323                 break;
324         case HEP_CHECK_STATE:
325                 error_msg = "Check the current HEP state";
326                 ret = -EINVAL;
327                 break;
328         default:
329                 error_msg = "Generic/Other error";
330                 ret = -EIO;
331                 break;
332         }
333
334         if (error_code)
335                 pr_warn_ratelimited("Returned error 0x%x, \"%s\"\n", error_code, error_msg);
336
337         return ret;
338 }
339
340 static ssize_t pending_reboot_show(struct kobject *kobj,
341                                    struct kobj_attribute *attr,
342                                    char *buf)
343 {
344         return sysfs_emit(buf, "%d\n", bioscfg_drv.pending_reboot);
345 }
346
347 static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
348
349 /*
350  * create_attributes_level_sysfs_files() - Creates pending_reboot attributes
351  */
352 static int create_attributes_level_sysfs_files(void)
353 {
354         return  sysfs_create_file(&bioscfg_drv.main_dir_kset->kobj,
355                                   &pending_reboot.attr);
356 }
357
358 static void attr_name_release(struct kobject *kobj)
359 {
360         kfree(kobj);
361 }
362
363 static const struct kobj_type attr_name_ktype = {
364         .release        = attr_name_release,
365         .sysfs_ops      = &kobj_sysfs_ops,
366 };
367
368 /**
369  * hp_get_wmiobj_pointer() - Get Content of WMI block for particular instance
370  *
371  * @instance_id: WMI instance ID
372  * @guid_string: WMI GUID (in str form)
373  *
374  * Fetches the content for WMI block (instance_id) under GUID (guid_string)
375  * Caller must kfree the return
376  */
377 union acpi_object *hp_get_wmiobj_pointer(int instance_id, const char *guid_string)
378 {
379         struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
380         acpi_status status;
381
382         status = wmi_query_block(guid_string, instance_id, &out);
383         return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
384 }
385
386 /**
387  * hp_get_instance_count() - Compute total number of instances under guid_string
388  *
389  * @guid_string: WMI GUID (in string form)
390  */
391 int hp_get_instance_count(const char *guid_string)
392 {
393         union acpi_object *wmi_obj = NULL;
394         int i = 0;
395
396         do {
397                 kfree(wmi_obj);
398                 wmi_obj = hp_get_wmiobj_pointer(i, guid_string);
399                 i++;
400         } while (wmi_obj);
401
402         return i - 1;
403 }
404
405 /**
406  * hp_alloc_attributes_data() - Allocate attributes data for a particular type
407  *
408  * @attr_type: Attribute type to allocate
409  */
410 static int hp_alloc_attributes_data(int attr_type)
411 {
412         switch (attr_type) {
413         case HPWMI_STRING_TYPE:
414                 return hp_alloc_string_data();
415
416         case HPWMI_INTEGER_TYPE:
417                 return hp_alloc_integer_data();
418
419         case HPWMI_ENUMERATION_TYPE:
420                 return hp_alloc_enumeration_data();
421
422         case HPWMI_ORDERED_LIST_TYPE:
423                 return hp_alloc_ordered_list_data();
424
425         case HPWMI_PASSWORD_TYPE:
426                 return hp_alloc_password_data();
427
428         default:
429                 return 0;
430         }
431 }
432
433 int hp_convert_hexstr_to_str(const char *input, u32 input_len, char **str, int *len)
434 {
435         int ret = 0;
436         int new_len = 0;
437         char tmp[] = "0x00";
438         char *new_str = NULL;
439         long  ch;
440         int i;
441
442         if (input_len <= 0 || !input || !str || !len)
443                 return -EINVAL;
444
445         *len = 0;
446         *str = NULL;
447
448         new_str = kmalloc(input_len, GFP_KERNEL);
449         if (!new_str)
450                 return -ENOMEM;
451
452         for (i = 0; i < input_len; i += 5) {
453                 strncpy(tmp, input + i, strlen(tmp));
454                 if (kstrtol(tmp, 16, &ch) == 0) {
455                         // escape char
456                         if (ch == '\\' ||
457                             ch == '\r' ||
458                             ch == '\n' || ch == '\t') {
459                                 if (ch == '\r')
460                                         ch = 'r';
461                                 else if (ch == '\n')
462                                         ch = 'n';
463                                 else if (ch == '\t')
464                                         ch = 't';
465                                 new_str[new_len++] = '\\';
466                         }
467                         new_str[new_len++] = ch;
468                         if (ch == '\0')
469                                 break;
470                 }
471         }
472
473         if (new_len) {
474                 new_str[new_len] = '\0';
475                 *str = krealloc(new_str, (new_len + 1) * sizeof(char),
476                                 GFP_KERNEL);
477                 if (*str)
478                         *len = new_len;
479                 else
480                         ret = -ENOMEM;
481         } else {
482                 ret = -EFAULT;
483         }
484
485         if (ret)
486                 kfree(new_str);
487         return ret;
488 }
489
490 /* map output size to the corresponding WMI method id */
491 int hp_encode_outsize_for_pvsz(int outsize)
492 {
493         if (outsize > 4096)
494                 return -EINVAL;
495         if (outsize > 1024)
496                 return 5;
497         if (outsize > 128)
498                 return 4;
499         if (outsize > 4)
500                 return 3;
501         if (outsize > 0)
502                 return 2;
503         return 1;
504 }
505
506 /*
507  * Update friendly display name for several attributes associated to
508  * 'Schedule Power-On'
509  */
510 void hp_friendly_user_name_update(char *path, const char *attr_name,
511                                   char *attr_display, int attr_size)
512 {
513         if (strstr(path, SCHEDULE_POWER_ON))
514                 snprintf(attr_display, attr_size, "%s - %s", SCHEDULE_POWER_ON, attr_name);
515         else
516                 strscpy(attr_display, attr_name, attr_size);
517 }
518
519 /**
520  * hp_update_attribute_permissions() - Update attributes permissions when
521  * isReadOnly value is 1
522  *
523  * @is_readonly:  bool value to indicate if it a readonly attribute.
524  * @current_val: kobj_attribute corresponding to attribute.
525  *
526  */
527 void hp_update_attribute_permissions(bool is_readonly, struct kobj_attribute *current_val)
528 {
529         current_val->attr.mode = is_readonly ? 0444 : 0644;
530 }
531
532 /**
533  * destroy_attribute_objs() - Free a kset of kobjects
534  * @kset: The kset to destroy
535  *
536  * Fress kobjects created for each attribute_name under attribute type kset
537  */
538 static void destroy_attribute_objs(struct kset *kset)
539 {
540         struct kobject *pos, *next;
541
542         list_for_each_entry_safe(pos, next, &kset->list, entry)
543                 kobject_put(pos);
544 }
545
546 /**
547  * release_attributes_data() - Clean-up all sysfs directories and files created
548  */
549 static void release_attributes_data(void)
550 {
551         mutex_lock(&bioscfg_drv.mutex);
552
553         hp_exit_string_attributes();
554         hp_exit_integer_attributes();
555         hp_exit_enumeration_attributes();
556         hp_exit_ordered_list_attributes();
557         hp_exit_password_attributes();
558         hp_exit_sure_start_attributes();
559         hp_exit_secure_platform_attributes();
560
561         if (bioscfg_drv.authentication_dir_kset) {
562                 destroy_attribute_objs(bioscfg_drv.authentication_dir_kset);
563                 kset_unregister(bioscfg_drv.authentication_dir_kset);
564                 bioscfg_drv.authentication_dir_kset = NULL;
565         }
566         if (bioscfg_drv.main_dir_kset) {
567                 sysfs_remove_file(&bioscfg_drv.main_dir_kset->kobj, &pending_reboot.attr);
568                 destroy_attribute_objs(bioscfg_drv.main_dir_kset);
569                 kset_unregister(bioscfg_drv.main_dir_kset);
570                 bioscfg_drv.main_dir_kset = NULL;
571         }
572         mutex_unlock(&bioscfg_drv.mutex);
573 }
574
575 /**
576  * hp_add_other_attributes() - Initialize HP custom attributes not
577  * reported by BIOS and required to support Secure Platform and Sure
578  * Start.
579  *
580  * @attr_type: Custom HP attribute not reported by BIOS
581  *
582  * Initialize all 2 types of attributes: Platform and Sure Start
583  * object.  Populates each attribute types respective properties
584  * under sysfs files.
585  *
586  * Returns zero(0) if successful. Otherwise, a negative value.
587  */
588 static int hp_add_other_attributes(int attr_type)
589 {
590         struct kobject *attr_name_kobj;
591         union acpi_object *obj = NULL;
592         int ret;
593         char *attr_name;
594
595         mutex_lock(&bioscfg_drv.mutex);
596
597         attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
598         if (!attr_name_kobj) {
599                 ret = -ENOMEM;
600                 goto err_other_attr_init;
601         }
602
603         /* Check if attribute type is supported */
604         switch (attr_type) {
605         case HPWMI_SECURE_PLATFORM_TYPE:
606                 attr_name_kobj->kset = bioscfg_drv.authentication_dir_kset;
607                 attr_name = SPM_STR;
608                 break;
609
610         case HPWMI_SURE_START_TYPE:
611                 attr_name_kobj->kset = bioscfg_drv.main_dir_kset;
612                 attr_name = SURE_START_STR;
613                 break;
614
615         default:
616                 pr_err("Error: Unknown attr_type: %d\n", attr_type);
617                 ret = -EINVAL;
618                 goto err_other_attr_init;
619         }
620
621         ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,
622                                    NULL, "%s", attr_name);
623         if (ret) {
624                 pr_err("Error encountered [%d]\n", ret);
625                 kobject_put(attr_name_kobj);
626                 goto err_other_attr_init;
627         }
628
629         /* Populate attribute data */
630         switch (attr_type) {
631         case HPWMI_SECURE_PLATFORM_TYPE:
632                 ret = hp_populate_secure_platform_data(attr_name_kobj);
633                 if (ret)
634                         goto err_other_attr_init;
635                 break;
636
637         case HPWMI_SURE_START_TYPE:
638                 ret = hp_populate_sure_start_data(attr_name_kobj);
639                 if (ret)
640                         goto err_other_attr_init;
641                 break;
642
643         default:
644                 ret = -EINVAL;
645                 goto err_other_attr_init;
646         }
647
648         mutex_unlock(&bioscfg_drv.mutex);
649         return 0;
650
651 err_other_attr_init:
652         mutex_unlock(&bioscfg_drv.mutex);
653         kfree(obj);
654         return ret;
655 }
656
657 static int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type,
658                                           union acpi_object *obj,
659                                           const char *guid, int min_elements,
660                                           int instance_id)
661 {
662         struct kobject *attr_name_kobj;
663         union acpi_object *elements;
664         struct kset *temp_kset;
665
666         char *str_value = NULL;
667         int str_len;
668         int ret = 0;
669
670         /* Take action appropriate to each ACPI TYPE */
671         if (obj->package.count < min_elements) {
672                 pr_err("ACPI-package does not have enough elements: %d < %d\n",
673                        obj->package.count, min_elements);
674                 goto pack_attr_exit;
675         }
676
677         elements = obj->package.elements;
678
679         /* sanity checking */
680         if (elements[NAME].type != ACPI_TYPE_STRING) {
681                 pr_debug("incorrect element type\n");
682                 goto pack_attr_exit;
683         }
684         if (strlen(elements[NAME].string.pointer) == 0) {
685                 pr_debug("empty attribute found\n");
686                 goto pack_attr_exit;
687         }
688
689         if (attr_type == HPWMI_PASSWORD_TYPE)
690                 temp_kset = bioscfg_drv.authentication_dir_kset;
691         else
692                 temp_kset = bioscfg_drv.main_dir_kset;
693
694         /* convert attribute name to string */
695         ret = hp_convert_hexstr_to_str(elements[NAME].string.pointer,
696                                        elements[NAME].string.length,
697                                        &str_value, &str_len);
698
699         if (ret) {
700                 pr_debug("Failed to populate integer package data. Error [0%0x]\n",
701                          ret);
702                 kfree(str_value);
703                 return ret;
704         }
705
706         /* All duplicate attributes found are ignored */
707         if (kset_find_obj(temp_kset, str_value)) {
708                 pr_debug("Duplicate attribute name found - %s\n", str_value);
709                 goto pack_attr_exit;
710         }
711
712         /* build attribute */
713         attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
714         if (!attr_name_kobj) {
715                 ret = -ENOMEM;
716                 goto pack_attr_exit;
717         }
718
719         attr_name_kobj->kset = temp_kset;
720
721         ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,
722                                    NULL, "%s", str_value);
723
724         if (ret) {
725                 kobject_put(attr_name_kobj);
726                 goto pack_attr_exit;
727         }
728
729         /* enumerate all of these attributes */
730         switch (attr_type) {
731         case HPWMI_STRING_TYPE:
732                 ret = hp_populate_string_package_data(elements,
733                                                       instance_id,
734                                                       attr_name_kobj);
735                 break;
736         case HPWMI_INTEGER_TYPE:
737                 ret = hp_populate_integer_package_data(elements,
738                                                        instance_id,
739                                                        attr_name_kobj);
740                 break;
741         case HPWMI_ENUMERATION_TYPE:
742                 ret = hp_populate_enumeration_package_data(elements,
743                                                            instance_id,
744                                                            attr_name_kobj);
745                 break;
746         case HPWMI_ORDERED_LIST_TYPE:
747                 ret = hp_populate_ordered_list_package_data(elements,
748                                                             instance_id,
749                                                             attr_name_kobj);
750                 break;
751         case HPWMI_PASSWORD_TYPE:
752                 ret = hp_populate_password_package_data(elements,
753                                                         instance_id,
754                                                         attr_name_kobj);
755                 break;
756         default:
757                 pr_debug("Unknown attribute type found: 0x%x\n", attr_type);
758                 break;
759         }
760
761 pack_attr_exit:
762         kfree(str_value);
763         return ret;
764 }
765
766 static int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type,
767                                          union acpi_object *obj,
768                                          const char *guid, int min_elements,
769                                          int instance_id)
770 {
771         struct kobject *attr_name_kobj;
772         struct kset *temp_kset;
773         char str[MAX_BUFF_SIZE];
774
775         char *temp_str = NULL;
776         char *str_value = NULL;
777         u8 *buffer_ptr = NULL;
778         int buffer_size;
779         int ret = 0;
780
781         buffer_size = obj->buffer.length;
782         buffer_ptr = obj->buffer.pointer;
783
784         ret = hp_get_string_from_buffer(&buffer_ptr,
785                                         &buffer_size, str, MAX_BUFF_SIZE);
786
787         if (ret < 0)
788                 goto buff_attr_exit;
789
790         if (attr_type == HPWMI_PASSWORD_TYPE ||
791             attr_type == HPWMI_SECURE_PLATFORM_TYPE)
792                 temp_kset = bioscfg_drv.authentication_dir_kset;
793         else
794                 temp_kset = bioscfg_drv.main_dir_kset;
795
796         /* All duplicate attributes found are ignored */
797         if (kset_find_obj(temp_kset, str)) {
798                 pr_debug("Duplicate attribute name found - %s\n", str);
799                 goto buff_attr_exit;
800         }
801
802         /* build attribute */
803         attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
804         if (!attr_name_kobj) {
805                 ret = -ENOMEM;
806                 goto buff_attr_exit;
807         }
808
809         attr_name_kobj->kset = temp_kset;
810
811         temp_str = str;
812         if (attr_type == HPWMI_SECURE_PLATFORM_TYPE)
813                 temp_str = "SPM";
814
815         ret = kobject_init_and_add(attr_name_kobj,
816                                    &attr_name_ktype, NULL, "%s", temp_str);
817         if (ret) {
818                 kobject_put(attr_name_kobj);
819                 goto buff_attr_exit;
820         }
821
822         /* enumerate all of these attributes */
823         switch (attr_type) {
824         case HPWMI_STRING_TYPE:
825                 ret = hp_populate_string_buffer_data(buffer_ptr,
826                                                      &buffer_size,
827                                                      instance_id,
828                                                      attr_name_kobj);
829                 break;
830         case HPWMI_INTEGER_TYPE:
831                 ret = hp_populate_integer_buffer_data(buffer_ptr,
832                                                       &buffer_size,
833                                                       instance_id,
834                                                       attr_name_kobj);
835                 break;
836         case HPWMI_ENUMERATION_TYPE:
837                 ret = hp_populate_enumeration_buffer_data(buffer_ptr,
838                                                           &buffer_size,
839                                                           instance_id,
840                                                           attr_name_kobj);
841                 break;
842         case HPWMI_ORDERED_LIST_TYPE:
843                 ret = hp_populate_ordered_list_buffer_data(buffer_ptr,
844                                                            &buffer_size,
845                                                            instance_id,
846                                                            attr_name_kobj);
847                 break;
848         case HPWMI_PASSWORD_TYPE:
849                 ret = hp_populate_password_buffer_data(buffer_ptr,
850                                                        &buffer_size,
851                                                        instance_id,
852                                                        attr_name_kobj);
853                 break;
854         default:
855                 pr_debug("Unknown attribute type found: 0x%x\n", attr_type);
856                 break;
857         }
858
859 buff_attr_exit:
860         kfree(str_value);
861         return ret;
862 }
863
864 /**
865  * hp_init_bios_attributes() - Initialize all attributes for a type
866  * @attr_type: The attribute type to initialize
867  * @guid: The WMI GUID associated with this type to initialize
868  *
869  * Initialize all 5 types of attributes: enumeration, integer,
870  * string, password, ordered list  object.  Populates each attribute types
871  * respective properties under sysfs files
872  */
873 static int hp_init_bios_attributes(enum hp_wmi_data_type attr_type, const char *guid)
874 {
875         union acpi_object *obj = NULL;
876         int min_elements;
877
878         /* instance_id needs to be reset for each type GUID
879          * also, instance IDs are unique within GUID but not across
880          */
881         int instance_id = 0;
882         int cur_instance_id = instance_id;
883         int ret = 0;
884
885         ret = hp_alloc_attributes_data(attr_type);
886         if (ret)
887                 return ret;
888
889         switch (attr_type) {
890         case HPWMI_STRING_TYPE:
891                 min_elements = STR_ELEM_CNT;
892                 break;
893         case HPWMI_INTEGER_TYPE:
894                 min_elements = INT_ELEM_CNT;
895                 break;
896         case HPWMI_ENUMERATION_TYPE:
897                 min_elements = ENUM_ELEM_CNT;
898                 break;
899         case HPWMI_ORDERED_LIST_TYPE:
900                 min_elements = ORD_ELEM_CNT;
901                 break;
902         case HPWMI_PASSWORD_TYPE:
903                 min_elements = PSWD_ELEM_CNT;
904                 break;
905         default:
906                 pr_err("Error: Unknown attr_type: %d\n", attr_type);
907                 return -EINVAL;
908         }
909
910         /* need to use specific instance_id and guid combination to get right data */
911         obj = hp_get_wmiobj_pointer(instance_id, guid);
912         if (!obj)
913                 return -ENODEV;
914
915         mutex_lock(&bioscfg_drv.mutex);
916         while (obj) {
917                 /* Take action appropriate to each ACPI TYPE */
918                 if (obj->type == ACPI_TYPE_PACKAGE) {
919                         ret = hp_init_bios_package_attribute(attr_type, obj,
920                                                              guid, min_elements,
921                                                              cur_instance_id);
922
923                 } else if (obj->type == ACPI_TYPE_BUFFER) {
924                         ret = hp_init_bios_buffer_attribute(attr_type, obj,
925                                                             guid, min_elements,
926                                                             cur_instance_id);
927
928                 } else {
929                         pr_err("Expected ACPI-package or buffer type, got: %d\n",
930                                obj->type);
931                         ret = -EIO;
932                         goto err_attr_init;
933                 }
934
935                 /*
936                  * Failure reported in one attribute must not
937                  * stop process of the remaining attribute values.
938                  */
939                 if (ret >= 0)
940                         cur_instance_id++;
941
942                 kfree(obj);
943                 instance_id++;
944                 obj = hp_get_wmiobj_pointer(instance_id, guid);
945         }
946
947 err_attr_init:
948         mutex_unlock(&bioscfg_drv.mutex);
949         kfree(obj);
950         return ret;
951 }
952
953 static int __init hp_init(void)
954 {
955         int ret;
956         int hp_bios_capable = wmi_has_guid(HP_WMI_BIOS_GUID);
957         int set_bios_settings = wmi_has_guid(HP_WMI_SET_BIOS_SETTING_GUID);
958
959         if (!hp_bios_capable) {
960                 pr_err("Unable to run on non-HP system\n");
961                 return -ENODEV;
962         }
963
964         if (!set_bios_settings) {
965                 pr_err("Unable to set BIOS settings on HP systems\n");
966                 return -ENODEV;
967         }
968
969         ret = hp_init_attr_set_interface();
970         if (ret)
971                 return ret;
972
973         ret = fw_attributes_class_get(&fw_attr_class);
974         if (ret)
975                 goto err_unregister_class;
976
977         bioscfg_drv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0),
978                                               NULL, "%s", DRIVER_NAME);
979         if (IS_ERR(bioscfg_drv.class_dev)) {
980                 ret = PTR_ERR(bioscfg_drv.class_dev);
981                 goto err_unregister_class;
982         }
983
984         bioscfg_drv.main_dir_kset = kset_create_and_add("attributes", NULL,
985                                                         &bioscfg_drv.class_dev->kobj);
986         if (!bioscfg_drv.main_dir_kset) {
987                 ret = -ENOMEM;
988                 pr_debug("Failed to create and add attributes\n");
989                 goto err_destroy_classdev;
990         }
991
992         bioscfg_drv.authentication_dir_kset = kset_create_and_add("authentication", NULL,
993                                                                   &bioscfg_drv.class_dev->kobj);
994         if (!bioscfg_drv.authentication_dir_kset) {
995                 ret = -ENOMEM;
996                 pr_debug("Failed to create and add authentication\n");
997                 goto err_release_attributes_data;
998         }
999
1000         /*
1001          * sysfs level attributes.
1002          * - pending_reboot
1003          */
1004         ret = create_attributes_level_sysfs_files();
1005         if (ret)
1006                 pr_debug("Failed to create sysfs level attributes\n");
1007
1008         ret = hp_init_bios_attributes(HPWMI_STRING_TYPE, HP_WMI_BIOS_STRING_GUID);
1009         if (ret)
1010                 pr_debug("Failed to populate string type attributes\n");
1011
1012         ret = hp_init_bios_attributes(HPWMI_INTEGER_TYPE, HP_WMI_BIOS_INTEGER_GUID);
1013         if (ret)
1014                 pr_debug("Failed to populate integer type attributes\n");
1015
1016         ret = hp_init_bios_attributes(HPWMI_ENUMERATION_TYPE, HP_WMI_BIOS_ENUMERATION_GUID);
1017         if (ret)
1018                 pr_debug("Failed to populate enumeration type attributes\n");
1019
1020         ret = hp_init_bios_attributes(HPWMI_ORDERED_LIST_TYPE, HP_WMI_BIOS_ORDERED_LIST_GUID);
1021         if (ret)
1022                 pr_debug("Failed to populate ordered list object type attributes\n");
1023
1024         ret = hp_init_bios_attributes(HPWMI_PASSWORD_TYPE, HP_WMI_BIOS_PASSWORD_GUID);
1025         if (ret)
1026                 pr_debug("Failed to populate password object type attributes\n");
1027
1028         bioscfg_drv.spm_data.attr_name_kobj = NULL;
1029         ret = hp_add_other_attributes(HPWMI_SECURE_PLATFORM_TYPE);
1030         if (ret)
1031                 pr_debug("Failed to populate secure platform object type attribute\n");
1032
1033         bioscfg_drv.sure_start_attr_kobj = NULL;
1034         ret = hp_add_other_attributes(HPWMI_SURE_START_TYPE);
1035         if (ret)
1036                 pr_debug("Failed to populate sure start object type attribute\n");
1037
1038         return 0;
1039
1040 err_release_attributes_data:
1041         release_attributes_data();
1042
1043 err_destroy_classdev:
1044         device_destroy(fw_attr_class, MKDEV(0, 0));
1045
1046 err_unregister_class:
1047         fw_attributes_class_put();
1048         hp_exit_attr_set_interface();
1049
1050         return ret;
1051 }
1052
1053 static void __exit hp_exit(void)
1054 {
1055         release_attributes_data();
1056         device_destroy(fw_attr_class, MKDEV(0, 0));
1057
1058         fw_attributes_class_put();
1059         hp_exit_attr_set_interface();
1060 }
1061
1062 module_init(hp_init);
1063 module_exit(hp_exit);