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