1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Functions corresponding to ordered list type attributes under 4 * BIOS ORDERED LIST GUID for use with hp-bioscfg driver. 5 * 6 * Copyright (c) 2022 HP Development Company, L.P. 7 */ 8 9 #include "bioscfg.h" 10 11 GET_INSTANCE_ID(ordered_list); 12 13 static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 14 { 15 int instance_id = get_ordered_list_instance_id(kobj); 16 17 if (instance_id < 0) 18 return -EIO; 19 20 return sysfs_emit(buf, "%s\n", 21 bioscfg_drv.ordered_list_data[instance_id].current_value); 22 } 23 24 static int replace_char_str(u8 *buffer, char *repl_char, char *repl_with) 25 { 26 char *src = buffer; 27 int buflen = strlen(buffer); 28 int item; 29 30 if (buflen < 1) 31 return -EINVAL; 32 33 for (item = 0; item < buflen; item++) 34 if (src[item] == *repl_char) 35 src[item] = *repl_with; 36 37 return 0; 38 } 39 40 /** 41 * validate_ordered_list_input() - 42 * Validate input of current_value against possible values 43 * 44 * @instance: The instance on which input is validated 45 * @buf: Input value 46 */ 47 static int validate_ordered_list_input(int instance, char *buf) 48 { 49 /* validation is done by BIOS. This validation function will 50 * convert semicolon to commas. BIOS uses commas as 51 * separators when reporting ordered-list values. 52 */ 53 return replace_char_str(buf, SEMICOLON_SEP, COMMA_SEP); 54 } 55 56 static void update_ordered_list_value(int instance, char *attr_value) 57 { 58 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance]; 59 60 strscpy(ordered_list_data->current_value, 61 attr_value, 62 sizeof(ordered_list_data->current_value)); 63 } 64 65 ATTRIBUTE_S_COMMON_PROPERTY_SHOW(display_name, ordered_list); 66 static struct kobj_attribute ordered_list_display_name = 67 __ATTR_RO(display_name); 68 69 ATTRIBUTE_PROPERTY_STORE(current_value, ordered_list); 70 static struct kobj_attribute ordered_list_current_val = 71 __ATTR_RW_MODE(current_value, 0644); 72 73 ATTRIBUTE_VALUES_PROPERTY_SHOW(elements, ordered_list, SEMICOLON_SEP); 74 static struct kobj_attribute ordered_list_elements_val = 75 __ATTR_RO(elements); 76 77 static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, 78 char *buf) 79 { 80 return sysfs_emit(buf, "ordered-list\n"); 81 } 82 83 static struct kobj_attribute ordered_list_type = 84 __ATTR_RO(type); 85 86 static struct attribute *ordered_list_attrs[] = { 87 &common_display_langcode.attr, 88 &ordered_list_display_name.attr, 89 &ordered_list_current_val.attr, 90 &ordered_list_elements_val.attr, 91 &ordered_list_type.attr, 92 NULL 93 }; 94 95 static const struct attribute_group ordered_list_attr_group = { 96 .attrs = ordered_list_attrs, 97 }; 98 99 int hp_alloc_ordered_list_data(void) 100 { 101 bioscfg_drv.ordered_list_instances_count = 102 hp_get_instance_count(HP_WMI_BIOS_ORDERED_LIST_GUID); 103 bioscfg_drv.ordered_list_data = kcalloc(bioscfg_drv.ordered_list_instances_count, 104 sizeof(*bioscfg_drv.ordered_list_data), 105 GFP_KERNEL); 106 if (!bioscfg_drv.ordered_list_data) { 107 bioscfg_drv.ordered_list_instances_count = 0; 108 return -ENOMEM; 109 } 110 return 0; 111 } 112 113 /* Expected Values types associated with each element */ 114 static const acpi_object_type expected_order_types[] = { 115 [NAME] = ACPI_TYPE_STRING, 116 [VALUE] = ACPI_TYPE_STRING, 117 [PATH] = ACPI_TYPE_STRING, 118 [IS_READONLY] = ACPI_TYPE_INTEGER, 119 [DISPLAY_IN_UI] = ACPI_TYPE_INTEGER, 120 [REQUIRES_PHYSICAL_PRESENCE] = ACPI_TYPE_INTEGER, 121 [SEQUENCE] = ACPI_TYPE_INTEGER, 122 [PREREQUISITES_SIZE] = ACPI_TYPE_INTEGER, 123 [PREREQUISITES] = ACPI_TYPE_STRING, 124 [SECURITY_LEVEL] = ACPI_TYPE_INTEGER, 125 [ORD_LIST_SIZE] = ACPI_TYPE_INTEGER, 126 [ORD_LIST_ELEMENTS] = ACPI_TYPE_STRING, 127 }; 128 129 static int hp_populate_ordered_list_elements_from_package(union acpi_object *order_obj, 130 int order_obj_count, 131 int instance_id) 132 { 133 char *str_value = NULL; 134 int value_len; 135 int ret; 136 u32 size; 137 u32 int_value; 138 int elem; 139 int reqs; 140 int eloc; 141 char *tmpstr = NULL; 142 char *part_tmp = NULL; 143 int tmp_len = 0; 144 char *part = NULL; 145 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; 146 147 if (!order_obj) 148 return -EINVAL; 149 150 for (elem = 1, eloc = 1; elem < order_obj_count; elem++, eloc++) { 151 /* ONLY look at the first ORDERED_ELEM_CNT elements */ 152 if (eloc == ORD_ELEM_CNT) 153 goto exit_list; 154 155 switch (order_obj[elem].type) { 156 case ACPI_TYPE_STRING: 157 if (elem != PREREQUISITES && elem != ORD_LIST_ELEMENTS) { 158 ret = hp_convert_hexstr_to_str(order_obj[elem].string.pointer, 159 order_obj[elem].string.length, 160 &str_value, &value_len); 161 if (ret) 162 continue; 163 } 164 break; 165 case ACPI_TYPE_INTEGER: 166 int_value = (u32)order_obj[elem].integer.value; 167 break; 168 default: 169 pr_warn("Unsupported object type [%d]\n", order_obj[elem].type); 170 continue; 171 } 172 173 /* Check that both expected and read object type match */ 174 if (expected_order_types[eloc] != order_obj[elem].type) { 175 pr_err("Error expected type %d for elem %d, but got type %d instead\n", 176 expected_order_types[eloc], elem, order_obj[elem].type); 177 kfree(str_value); 178 return -EIO; 179 } 180 181 /* Assign appropriate element value to corresponding field*/ 182 switch (eloc) { 183 case VALUE: 184 strscpy(ordered_list_data->current_value, 185 str_value, sizeof(ordered_list_data->current_value)); 186 replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP); 187 break; 188 case PATH: 189 strscpy(ordered_list_data->common.path, str_value, 190 sizeof(ordered_list_data->common.path)); 191 break; 192 case IS_READONLY: 193 ordered_list_data->common.is_readonly = int_value; 194 break; 195 case DISPLAY_IN_UI: 196 ordered_list_data->common.display_in_ui = int_value; 197 break; 198 case REQUIRES_PHYSICAL_PRESENCE: 199 ordered_list_data->common.requires_physical_presence = int_value; 200 break; 201 case SEQUENCE: 202 ordered_list_data->common.sequence = int_value; 203 break; 204 case PREREQUISITES_SIZE: 205 ordered_list_data->common.prerequisites_size = int_value; 206 if (int_value > MAX_PREREQUISITES_SIZE) 207 pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n"); 208 209 /* 210 * This HACK is needed to keep the expected 211 * element list pointing to the right obj[elem].type 212 * when the size is zero. PREREQUISITES 213 * object is omitted by BIOS when the size is 214 * zero. 215 */ 216 if (int_value == 0) 217 eloc++; 218 break; 219 case PREREQUISITES: 220 size = min_t(u32, ordered_list_data->common.prerequisites_size, 221 MAX_PREREQUISITES_SIZE); 222 for (reqs = 0; reqs < size; reqs++) { 223 ret = hp_convert_hexstr_to_str(order_obj[elem + reqs].string.pointer, 224 order_obj[elem + reqs].string.length, 225 &str_value, &value_len); 226 227 if (ret) 228 continue; 229 230 strscpy(ordered_list_data->common.prerequisites[reqs], 231 str_value, 232 sizeof(ordered_list_data->common.prerequisites[reqs])); 233 234 kfree(str_value); 235 str_value = NULL; 236 } 237 break; 238 239 case SECURITY_LEVEL: 240 ordered_list_data->common.security_level = int_value; 241 break; 242 243 case ORD_LIST_SIZE: 244 ordered_list_data->elements_size = int_value; 245 if (int_value > MAX_ELEMENTS_SIZE) 246 pr_warn("Ordered List size value exceeded the maximum number of elements supported or data may be malformed\n"); 247 /* 248 * This HACK is needed to keep the expected 249 * element list pointing to the right obj[elem].type 250 * when the size is zero. ORD_LIST_ELEMENTS 251 * object is omitted by BIOS when the size is 252 * zero. 253 */ 254 if (int_value == 0) 255 eloc++; 256 break; 257 case ORD_LIST_ELEMENTS: 258 size = ordered_list_data->elements_size; 259 260 /* 261 * Ordered list data is stored in hex and comma separated format 262 * Convert the data and split it to show each element 263 */ 264 ret = hp_convert_hexstr_to_str(str_value, value_len, &tmpstr, &tmp_len); 265 if (ret) 266 goto exit_list; 267 268 part_tmp = tmpstr; 269 part = strsep(&part_tmp, COMMA_SEP); 270 if (!part) 271 strscpy(ordered_list_data->elements[0], 272 tmpstr, 273 sizeof(ordered_list_data->elements[0])); 274 275 for (elem = 1; elem < MAX_ELEMENTS_SIZE && part; elem++) { 276 strscpy(ordered_list_data->elements[elem], 277 part, 278 sizeof(ordered_list_data->elements[elem])); 279 part = strsep(&part_tmp, SEMICOLON_SEP); 280 } 281 282 kfree(str_value); 283 str_value = NULL; 284 break; 285 default: 286 pr_warn("Invalid element: %d found in Ordered_List attribute or data may be malformed\n", elem); 287 break; 288 } 289 kfree(tmpstr); 290 tmpstr = NULL; 291 kfree(str_value); 292 str_value = NULL; 293 } 294 295 exit_list: 296 kfree(tmpstr); 297 kfree(str_value); 298 return 0; 299 } 300 301 /** 302 * hp_populate_ordered_list_package_data() - 303 * Populate all properties of an instance under ordered_list attribute 304 * 305 * @order_obj: ACPI object with ordered_list data 306 * @instance_id: The instance to enumerate 307 * @attr_name_kobj: The parent kernel object 308 */ 309 int hp_populate_ordered_list_package_data(union acpi_object *order_obj, int instance_id, 310 struct kobject *attr_name_kobj) 311 { 312 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; 313 314 ordered_list_data->attr_name_kobj = attr_name_kobj; 315 316 hp_populate_ordered_list_elements_from_package(order_obj, 317 order_obj->package.count, 318 instance_id); 319 hp_update_attribute_permissions(ordered_list_data->common.is_readonly, 320 &ordered_list_current_val); 321 hp_friendly_user_name_update(ordered_list_data->common.path, 322 attr_name_kobj->name, 323 ordered_list_data->common.display_name, 324 sizeof(ordered_list_data->common.display_name)); 325 return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group); 326 } 327 328 static int hp_populate_ordered_list_elements_from_buffer(u8 *buffer_ptr, u32 *buffer_size, 329 int instance_id) 330 { 331 int values; 332 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; 333 int ret = 0; 334 335 /* 336 * Only data relevant to this driver and its functionality is 337 * read. BIOS defines the order in which each * element is 338 * read. Element 0 data is not relevant to this 339 * driver hence it is ignored. For clarity, all element names 340 * (DISPLAY_IN_UI) which defines the order in which is read 341 * and the name matches the variable where the data is stored. 342 * 343 * In earlier implementation, reported errors were ignored 344 * causing the data to remain uninitialized. It is not 345 * possible to determine if data read from BIOS is valid or 346 * not. It is for this reason functions may return a error 347 * without validating the data itself. 348 */ 349 350 // VALUE: 351 ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, ordered_list_data->current_value, 352 sizeof(ordered_list_data->current_value)); 353 if (ret < 0) 354 goto buffer_exit; 355 356 replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP); 357 358 // COMMON: 359 ret = hp_get_common_data_from_buffer(&buffer_ptr, buffer_size, 360 &ordered_list_data->common); 361 if (ret < 0) 362 goto buffer_exit; 363 364 // ORD_LIST_SIZE: 365 ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size, 366 &ordered_list_data->elements_size); 367 368 if (ordered_list_data->elements_size > MAX_ELEMENTS_SIZE) { 369 /* Report a message and limit elements size to maximum value */ 370 pr_warn("Ordered List size value exceeded the maximum number of elements supported or data may be malformed\n"); 371 ordered_list_data->elements_size = MAX_ELEMENTS_SIZE; 372 } 373 374 // ORD_LIST_ELEMENTS: 375 for (values = 0; values < ordered_list_data->elements_size; values++) { 376 ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, 377 ordered_list_data->elements[values], 378 sizeof(ordered_list_data->elements[values])); 379 if (ret < 0) 380 break; 381 } 382 383 buffer_exit: 384 return ret; 385 } 386 387 /** 388 * hp_populate_ordered_list_buffer_data() - Populate all properties of an 389 * instance under ordered list attribute 390 * 391 * @buffer_ptr: Buffer pointer 392 * @buffer_size: Buffer size 393 * @instance_id: The instance to enumerate 394 * @attr_name_kobj: The parent kernel object 395 */ 396 int hp_populate_ordered_list_buffer_data(u8 *buffer_ptr, u32 *buffer_size, int instance_id, 397 struct kobject *attr_name_kobj) 398 { 399 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; 400 int ret = 0; 401 402 ordered_list_data->attr_name_kobj = attr_name_kobj; 403 404 /* Populate ordered list elements */ 405 ret = hp_populate_ordered_list_elements_from_buffer(buffer_ptr, buffer_size, 406 instance_id); 407 if (ret < 0) 408 return ret; 409 410 hp_update_attribute_permissions(ordered_list_data->common.is_readonly, 411 &ordered_list_current_val); 412 hp_friendly_user_name_update(ordered_list_data->common.path, 413 attr_name_kobj->name, 414 ordered_list_data->common.display_name, 415 sizeof(ordered_list_data->common.display_name)); 416 417 return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group); 418 } 419 420 /** 421 * hp_exit_ordered_list_attributes() - Clear all attribute data 422 * 423 * Clears all data allocated for this group of attributes 424 */ 425 void hp_exit_ordered_list_attributes(void) 426 { 427 int instance_id; 428 429 for (instance_id = 0; instance_id < bioscfg_drv.ordered_list_instances_count; 430 instance_id++) { 431 struct kobject *attr_name_kobj = 432 bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj; 433 434 if (attr_name_kobj) 435 sysfs_remove_group(attr_name_kobj, 436 &ordered_list_attr_group); 437 } 438 bioscfg_drv.ordered_list_instances_count = 0; 439 440 kfree(bioscfg_drv.ordered_list_data); 441 bioscfg_drv.ordered_list_data = NULL; 442 } 443