1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * coreboot CFR firmware attributes driver.
4 *
5 * Parses LB_TAG_CFR_ROOT records from the coreboot table and exposes
6 * runtime EFI variable-backed options through the firmware-attributes class.
7 */
8
9 #include <linux/array_size.h>
10 #include <linux/bitops.h>
11 #include <linux/cleanup.h>
12 #include <linux/compiler_attributes.h>
13 #include <linux/container_of.h>
14 #include <linux/crc32.h>
15 #include <linux/ctype.h>
16 #include <linux/device.h>
17 #include <linux/device-id/coreboot.h>
18 #include <linux/efi.h>
19 #include <linux/err.h>
20 #include <linux/firmware_attributes.h>
21 #include <linux/io.h>
22 #include <linux/kdev_t.h>
23 #include <linux/kobject.h>
24 #include <linux/kstrtox.h>
25 #include <linux/limits.h>
26 #include <linux/list.h>
27 #include <linux/module.h>
28 #include <linux/mutex.h>
29 #include <linux/slab.h>
30 #include <linux/string.h>
31 #include <linux/sysfs.h>
32 #include <linux/types.h>
33
34 #include "coreboot_table.h"
35
36 #define DRIVER_NAME "coreboot-cfr"
37
38 #define LB_TAG_CFR_ROOT 0x47
39 #define CFR_VERSION 0
40
41 enum cfr_tags {
42 CFR_TAG_OPTION_FORM = 1,
43 CFR_TAG_ENUM_VALUE = 2,
44 CFR_TAG_OPTION_ENUM = 3,
45 CFR_TAG_OPTION_NUMBER = 4,
46 CFR_TAG_OPTION_BOOL = 5,
47 CFR_TAG_VARCHAR_OPT_NAME = 7,
48 CFR_TAG_VARCHAR_UI_NAME = 8,
49 CFR_TAG_RUNTIME_APPLY = 13,
50 };
51
52 enum cfr_option_flags {
53 CFR_OPTFLAG_READONLY = BIT(0),
54 CFR_OPTFLAG_INACTIVE = BIT(1),
55 CFR_OPTFLAG_SUPPRESS = BIT(2),
56 CFR_OPTFLAG_VOLATILE = BIT(3),
57 CFR_OPTFLAG_RUNTIME = BIT(4),
58 };
59
60 enum cfr_runtime_apply_method {
61 CFR_RUNTIME_APPLY_NONE = 0,
62 CFR_RUNTIME_APPLY_APM_CNT = 1,
63 };
64
65 struct lb_cfr {
66 u32 tag;
67 u32 size;
68 u32 version;
69 u32 checksum;
70 } __packed;
71
72 struct lb_cfr_varbinary {
73 u32 tag;
74 u32 size;
75 u32 data_length;
76 } __packed;
77
78 struct lb_cfr_enum_value {
79 u32 tag;
80 u32 size;
81 u32 value;
82 } __packed;
83
84 struct lb_cfr_runtime_apply {
85 u32 tag;
86 u32 size;
87 u32 method;
88 u32 id;
89 } __packed;
90
91 struct lb_cfr_numeric_option {
92 u32 tag;
93 u32 size;
94 cb_u64 object_id;
95 cb_u64 dependency_id;
96 u32 flags;
97 u32 default_value;
98 u32 min;
99 u32 max;
100 u32 step;
101 u32 display_flags;
102 } __packed;
103
104 struct lb_cfr_option_form {
105 u32 tag;
106 u32 size;
107 cb_u64 object_id;
108 cb_u64 dependency_id;
109 u32 flags;
110 } __packed;
111
112 #define COREBOOT_CFR_OPT_SKIP_FLAGS \
113 (CFR_OPTFLAG_SUPPRESS | CFR_OPTFLAG_VOLATILE)
114
115 #define COREBOOT_CFR_OPT_READ_ONLY_FLAGS \
116 (CFR_OPTFLAG_READONLY | CFR_OPTFLAG_INACTIVE)
117
118 #define COREBOOT_CFR_EFI_ATTRS \
119 (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | \
120 EFI_VARIABLE_RUNTIME_ACCESS)
121
122 #define COREBOOT_CFR_APM_CNT_PORT 0xb2
123 #define COREBOOT_CFR_APM_STS_PORT 0xb3
124 #define COREBOOT_CFR_APM_APPLY_CMD 0xe3
125 #define COREBOOT_CFR_MAX_FORM_DEPTH 16
126
127 static efi_guid_t coreboot_cfr_guid = EFI_GUID(0xceae4c1d, 0x335b, 0x4685,
128 0xa4, 0xa0, 0xfc, 0x4a,
129 0x94, 0xee, 0xa0, 0x85);
130
131 enum coreboot_cfr_setting_type {
132 COREBOOT_CFR_SETTING_ENUM,
133 COREBOOT_CFR_SETTING_NUMBER,
134 COREBOOT_CFR_SETTING_BOOL,
135 };
136
137 struct coreboot_cfr_enum {
138 char *label;
139 u32 value;
140 };
141
142 struct coreboot_cfr_setting {
143 struct kobject kobj;
144 struct list_head node;
145 struct coreboot_cfr_drvdata *drvdata;
146 enum coreboot_cfr_setting_type type;
147 char *name;
148 char *display_name;
149 struct coreboot_cfr_enum *values;
150 unsigned int n_values;
151 u32 default_value;
152 u32 min;
153 u32 max;
154 u32 step;
155 u32 runtime_apply_method;
156 u32 runtime_apply_id;
157 bool read_only;
158 };
159
160 struct coreboot_cfr_drvdata {
161 struct device *class_dev;
162 struct kset *attrs_kset;
163 struct list_head settings;
164 /* Serializes EFI variable writes and the matching runtime apply hook. */
165 struct mutex lock;
166 bool efi_writes_supported;
167 bool pending_reboot;
168 };
169
170 struct coreboot_cfr_iterator {
171 const u8 *cursor;
172 size_t remaining;
173 };
174
to_coreboot_cfr_setting(struct kobject * kobj)175 static struct coreboot_cfr_setting *to_coreboot_cfr_setting(struct kobject *kobj)
176 {
177 return container_of(kobj, struct coreboot_cfr_setting, kobj);
178 }
179
coreboot_cfr_string_is_valid_name(const char * name)180 static bool coreboot_cfr_string_is_valid_name(const char *name)
181 {
182 return name && name[0] && !strchr(name, '/') &&
183 strcmp(name, "pending_reboot") != 0;
184 }
185
coreboot_cfr_string_is_valid_label(const char * label)186 static bool coreboot_cfr_string_is_valid_label(const char *label)
187 {
188 return label && !strchr(label, ';') && !strchr(label, '\n');
189 }
190
coreboot_cfr_string_dup(const struct lb_cfr_varbinary * str)191 static char *coreboot_cfr_string_dup(const struct lb_cfr_varbinary *str)
192 {
193 const char *data = (const char *)(str + 1);
194 size_t len = str->data_length;
195
196 if (len && !data[len - 1])
197 len--;
198
199 return kmemdup_nul(data, len, GFP_KERNEL);
200 }
201
202 static const struct coreboot_table_entry *
coreboot_cfr_next_entry(struct coreboot_cfr_iterator * iterator)203 coreboot_cfr_next_entry(struct coreboot_cfr_iterator *iterator)
204 {
205 const struct coreboot_table_entry *entry;
206
207 if (!iterator->remaining)
208 return NULL;
209
210 if (iterator->remaining < sizeof(*entry))
211 return ERR_PTR(-EINVAL);
212
213 entry = (const struct coreboot_table_entry *)iterator->cursor;
214 if (entry->size < sizeof(*entry) || entry->size > iterator->remaining)
215 return ERR_PTR(-EINVAL);
216
217 iterator->cursor += entry->size;
218 iterator->remaining -= entry->size;
219
220 return entry;
221 }
222
223 static const struct coreboot_table_entry *
coreboot_cfr_child_entry(const void * base,size_t len,u32 tag)224 coreboot_cfr_child_entry(const void *base, size_t len, u32 tag)
225 {
226 struct coreboot_cfr_iterator iterator = {
227 .cursor = base,
228 .remaining = len,
229 };
230 const struct coreboot_table_entry *entry;
231
232 for (;;) {
233 entry = coreboot_cfr_next_entry(&iterator);
234 if (IS_ERR_OR_NULL(entry))
235 return entry;
236
237 if (entry->tag == tag)
238 return entry;
239 }
240 }
241
242 static const struct lb_cfr_varbinary *
coreboot_cfr_child_string(const void * base,size_t len,u32 tag)243 coreboot_cfr_child_string(const void *base, size_t len, u32 tag)
244 {
245 const struct lb_cfr_varbinary *str;
246 const struct coreboot_table_entry *entry;
247
248 entry = coreboot_cfr_child_entry(base, len, tag);
249 if (IS_ERR(entry))
250 return ERR_CAST(entry);
251 if (!entry)
252 return NULL;
253
254 if (entry->size < sizeof(*str))
255 return ERR_PTR(-EINVAL);
256
257 str = (const struct lb_cfr_varbinary *)entry;
258 if (str->data_length > entry->size - sizeof(*str))
259 return ERR_PTR(-EINVAL);
260
261 return str;
262 }
263
264 static const struct lb_cfr_runtime_apply *
coreboot_cfr_child_runtime_apply(const void * base,size_t len)265 coreboot_cfr_child_runtime_apply(const void *base, size_t len)
266 {
267 const struct lb_cfr_runtime_apply *runtime_apply;
268 const struct coreboot_table_entry *entry;
269
270 entry = coreboot_cfr_child_entry(base, len, CFR_TAG_RUNTIME_APPLY);
271 if (IS_ERR(entry))
272 return ERR_CAST(entry);
273 if (!entry)
274 return NULL;
275
276 if (entry->size < sizeof(*runtime_apply))
277 return ERR_PTR(-EINVAL);
278
279 runtime_apply = (const struct lb_cfr_runtime_apply *)entry;
280 if (runtime_apply->method == CFR_RUNTIME_APPLY_APM_CNT &&
281 runtime_apply->id > U8_MAX)
282 return ERR_PTR(-EINVAL);
283
284 return runtime_apply;
285 }
286
coreboot_cfr_efi_name(const char * name)287 static efi_char16_t *coreboot_cfr_efi_name(const char *name)
288 {
289 size_t len, i;
290
291 len = strlen(name);
292 if (len >= EFI_VAR_NAME_LEN)
293 return ERR_PTR(-ENAMETOOLONG);
294
295 efi_char16_t *efi_name __free(kfree) =
296 kcalloc(len + 1, sizeof(*efi_name), GFP_KERNEL);
297 if (!efi_name)
298 return ERR_PTR(-ENOMEM);
299
300 for (i = 0; i < len; i++) {
301 if (!isascii(name[i]))
302 return ERR_PTR(-EINVAL);
303 efi_name[i] = name[i];
304 }
305
306 return no_free_ptr(efi_name);
307 }
308
309 /* Caller must hold the efivar lock. */
coreboot_cfr_read_efi_value(efi_char16_t * efi_name,u32 * value,u32 * attrs)310 static int coreboot_cfr_read_efi_value(efi_char16_t *efi_name, u32 *value,
311 u32 *attrs)
312 {
313 unsigned long size = sizeof(__le32);
314 efi_status_t status;
315 __le32 data;
316 u32 attr;
317
318 status = efivar_get_variable(efi_name, &coreboot_cfr_guid, &attr,
319 &size, &data);
320 if (status != EFI_SUCCESS)
321 return efi_status_to_err(status);
322
323 if (size != sizeof(data))
324 return -EINVAL;
325
326 if (!(attr & EFI_VARIABLE_RUNTIME_ACCESS))
327 return -EOPNOTSUPP;
328
329 *value = le32_to_cpu(data);
330 if (attrs)
331 *attrs = attr;
332
333 return 0;
334 }
335
coreboot_cfr_read_value(const struct coreboot_cfr_setting * setting,u32 * value,u32 * attrs)336 static int coreboot_cfr_read_value(const struct coreboot_cfr_setting *setting,
337 u32 *value, u32 *attrs)
338 {
339 efi_char16_t *efi_name __free(kfree) =
340 coreboot_cfr_efi_name(setting->name);
341 int ret;
342
343 if (IS_ERR(efi_name))
344 return PTR_ERR(no_free_ptr(efi_name));
345
346 ret = efivar_lock();
347 if (ret)
348 return ret;
349
350 ret = coreboot_cfr_read_efi_value(efi_name, value, attrs);
351 efivar_unlock();
352
353 return ret;
354 }
355
356 /* Caller must hold the efivar lock. */
coreboot_cfr_write_efi_value(efi_char16_t * efi_name,u32 value,u32 attrs)357 static int coreboot_cfr_write_efi_value(efi_char16_t *efi_name, u32 value,
358 u32 attrs)
359 {
360 efi_status_t status;
361 __le32 data;
362
363 if (!efivar_supports_writes())
364 return -EROFS;
365
366 data = cpu_to_le32(value);
367 status = efivar_set_variable_locked(efi_name, &coreboot_cfr_guid, attrs,
368 sizeof(data), &data, false);
369 if (status != EFI_SUCCESS)
370 return efi_status_to_err(status);
371
372 return 0;
373 }
374
coreboot_cfr_apply_runtime(struct coreboot_cfr_setting * setting)375 static int coreboot_cfr_apply_runtime(struct coreboot_cfr_setting *setting)
376 {
377 u8 status;
378
379 if (setting->runtime_apply_method != CFR_RUNTIME_APPLY_APM_CNT)
380 return -EOPNOTSUPP;
381
382 outb((u8)setting->runtime_apply_id, COREBOOT_CFR_APM_STS_PORT);
383 outb(COREBOOT_CFR_APM_APPLY_CMD, COREBOOT_CFR_APM_CNT_PORT);
384 status = inb(COREBOOT_CFR_APM_STS_PORT);
385 if (status)
386 return -EIO;
387
388 return 0;
389 }
390
coreboot_cfr_write_value(struct coreboot_cfr_setting * setting,u32 value)391 static int coreboot_cfr_write_value(struct coreboot_cfr_setting *setting,
392 u32 value)
393 {
394 efi_char16_t *efi_name;
395 u32 attrs;
396 u32 old;
397 int restore_ret;
398 int ret;
399
400 if (setting->read_only)
401 return -EACCES;
402
403 efi_name = coreboot_cfr_efi_name(setting->name);
404 if (IS_ERR(efi_name))
405 return PTR_ERR(efi_name);
406
407 mutex_lock(&setting->drvdata->lock);
408
409 ret = efivar_lock();
410 if (ret)
411 goto out_unlock_mutex;
412
413 ret = coreboot_cfr_read_efi_value(efi_name, &old, &attrs);
414 if (ret)
415 goto out_unlock_efi;
416
417 if ((attrs & COREBOOT_CFR_EFI_ATTRS) != COREBOOT_CFR_EFI_ATTRS) {
418 ret = -EOPNOTSUPP;
419 goto out_unlock_efi;
420 }
421
422 if (old == value)
423 goto out_unlock_efi;
424
425 ret = coreboot_cfr_write_efi_value(efi_name, value, attrs);
426 if (ret)
427 goto out_unlock_efi;
428
429 ret = coreboot_cfr_apply_runtime(setting);
430 if (ret == -EOPNOTSUPP) {
431 /* EFI changed; firmware will consume it after reboot. */
432 setting->drvdata->pending_reboot = true;
433 ret = 0;
434 } else if (ret) {
435 restore_ret = coreboot_cfr_write_efi_value(efi_name, old, attrs);
436 if (restore_ret) {
437 setting->drvdata->pending_reboot = true;
438 ret = restore_ret;
439 } else {
440 goto out_unlock_efi;
441 }
442 }
443
444 efivar_unlock();
445 kobject_uevent(&setting->drvdata->class_dev->kobj, KOBJ_CHANGE);
446 mutex_unlock(&setting->drvdata->lock);
447 kfree(efi_name);
448 return ret;
449
450 out_unlock_efi:
451 efivar_unlock();
452 out_unlock_mutex:
453 mutex_unlock(&setting->drvdata->lock);
454 kfree(efi_name);
455 return ret;
456 }
457
458 static const char *
coreboot_cfr_label_from_value(const struct coreboot_cfr_setting * setting,u32 value)459 coreboot_cfr_label_from_value(const struct coreboot_cfr_setting *setting,
460 u32 value)
461 {
462 unsigned int i;
463
464 for (i = 0; i < setting->n_values; i++) {
465 if (setting->values[i].value == value)
466 return setting->values[i].label;
467 }
468
469 return NULL;
470 }
471
coreboot_cfr_parse_value(struct coreboot_cfr_setting * setting,const char * label,u32 * value_out)472 static int coreboot_cfr_parse_value(struct coreboot_cfr_setting *setting,
473 const char *label, u32 *value_out)
474 {
475 unsigned int i;
476
477 for (i = 0; i < setting->n_values; i++) {
478 if (!sysfs_streq(label, setting->values[i].label))
479 continue;
480
481 *value_out = setting->values[i].value;
482 return 0;
483 }
484
485 return kstrtou32(label, 0, value_out);
486 }
487
coreboot_cfr_value_is_valid(struct coreboot_cfr_setting * setting,u32 value)488 static bool coreboot_cfr_value_is_valid(struct coreboot_cfr_setting *setting,
489 u32 value)
490 {
491 u32 delta;
492
493 if (setting->type != COREBOOT_CFR_SETTING_NUMBER) {
494 /* Enum and bool values are valid only if they have a label. */
495 return coreboot_cfr_label_from_value(setting, value);
496 }
497
498 if (value < setting->min || value > setting->max)
499 return false;
500
501 if (!setting->step)
502 return true;
503
504 delta = value - setting->min;
505 return delta % setting->step == 0;
506 }
507
type_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)508 static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
509 char *buf)
510 {
511 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
512
513 if (setting->type == COREBOOT_CFR_SETTING_NUMBER)
514 return sysfs_emit(buf, "integer\n");
515
516 return sysfs_emit(buf, "enumeration\n");
517 }
518
display_name_language_code_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)519 static ssize_t display_name_language_code_show(struct kobject *kobj,
520 struct kobj_attribute *attr,
521 char *buf)
522 {
523 return sysfs_emit(buf, "en_US.UTF-8\n");
524 }
525
display_name_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)526 static ssize_t display_name_show(struct kobject *kobj,
527 struct kobj_attribute *attr, char *buf)
528 {
529 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
530
531 return sysfs_emit(buf, "%s\n", setting->display_name);
532 }
533
possible_values_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)534 static ssize_t possible_values_show(struct kobject *kobj,
535 struct kobj_attribute *attr, char *buf)
536 {
537 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
538 ssize_t len = 0;
539 unsigned int i;
540
541 for (i = 0; i < setting->n_values; i++) {
542 len += sysfs_emit_at(buf, len, "%s%s", i ? ";" : "",
543 setting->values[i].label);
544 }
545
546 len += sysfs_emit_at(buf, len, "\n");
547 return len;
548 }
549
min_value_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)550 static ssize_t min_value_show(struct kobject *kobj, struct kobj_attribute *attr,
551 char *buf)
552 {
553 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
554
555 return sysfs_emit(buf, "%u\n", setting->min);
556 }
557
max_value_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)558 static ssize_t max_value_show(struct kobject *kobj, struct kobj_attribute *attr,
559 char *buf)
560 {
561 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
562
563 return sysfs_emit(buf, "%u\n", setting->max);
564 }
565
scalar_increment_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)566 static ssize_t scalar_increment_show(struct kobject *kobj,
567 struct kobj_attribute *attr, char *buf)
568 {
569 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
570
571 return sysfs_emit(buf, "%u\n", setting->step);
572 }
573
default_value_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)574 static ssize_t default_value_show(struct kobject *kobj,
575 struct kobj_attribute *attr, char *buf)
576 {
577 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
578 const char *label;
579
580 if (setting->type == COREBOOT_CFR_SETTING_NUMBER)
581 return sysfs_emit(buf, "%u\n", setting->default_value);
582
583 label = coreboot_cfr_label_from_value(setting, setting->default_value);
584 if (!label)
585 return sysfs_emit(buf, "%u\n", setting->default_value);
586
587 return sysfs_emit(buf, "%s\n", label);
588 }
589
current_value_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)590 static ssize_t current_value_show(struct kobject *kobj,
591 struct kobj_attribute *attr, char *buf)
592 {
593 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
594 const char *label;
595 u32 value;
596 int ret;
597
598 ret = coreboot_cfr_read_value(setting, &value, NULL);
599 if (ret)
600 return ret;
601
602 if (setting->type == COREBOOT_CFR_SETTING_NUMBER)
603 return sysfs_emit(buf, "%u\n", value);
604
605 label = coreboot_cfr_label_from_value(setting, value);
606 if (!label)
607 return -EINVAL;
608
609 return sysfs_emit(buf, "%s\n", label);
610 }
611
current_value_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)612 static ssize_t current_value_store(struct kobject *kobj,
613 struct kobj_attribute *attr,
614 const char *buf, size_t count)
615 {
616 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
617 u32 value;
618 int ret;
619
620 ret = coreboot_cfr_parse_value(setting, buf, &value);
621 if (ret)
622 return ret;
623
624 if (!coreboot_cfr_value_is_valid(setting, value))
625 return -EINVAL;
626
627 ret = coreboot_cfr_write_value(setting, value);
628 if (ret)
629 return ret;
630
631 return count;
632 }
633
634 static struct kobj_attribute type_attr = __ATTR_RO(type);
635 static struct kobj_attribute display_name_language_code_attr =
636 __ATTR_RO(display_name_language_code);
637 static struct kobj_attribute display_name_attr = __ATTR_RO(display_name);
638 static struct kobj_attribute possible_values_attr = __ATTR_RO(possible_values);
639 static struct kobj_attribute min_value_attr = __ATTR_RO(min_value);
640 static struct kobj_attribute max_value_attr = __ATTR_RO(max_value);
641 static struct kobj_attribute scalar_increment_attr = __ATTR_RO(scalar_increment);
642 static struct kobj_attribute default_value_attr = __ATTR_RO(default_value);
643 static struct kobj_attribute current_value_attr = __ATTR_RW(current_value);
644
645 static struct attribute *coreboot_cfr_setting_attrs[] = {
646 &type_attr.attr,
647 &display_name_language_code_attr.attr,
648 &display_name_attr.attr,
649 &possible_values_attr.attr,
650 &min_value_attr.attr,
651 &max_value_attr.attr,
652 &scalar_increment_attr.attr,
653 &default_value_attr.attr,
654 ¤t_value_attr.attr,
655 NULL,
656 };
657
coreboot_cfr_attr_is_visible(struct kobject * kobj,struct attribute * attr,int n)658 static umode_t coreboot_cfr_attr_is_visible(struct kobject *kobj,
659 struct attribute *attr, int n)
660 {
661 struct coreboot_cfr_setting *setting = to_coreboot_cfr_setting(kobj);
662
663 if (setting->type == COREBOOT_CFR_SETTING_NUMBER &&
664 attr == &possible_values_attr.attr)
665 return 0;
666
667 if (setting->type != COREBOOT_CFR_SETTING_NUMBER &&
668 (attr == &min_value_attr.attr || attr == &max_value_attr.attr ||
669 attr == &scalar_increment_attr.attr))
670 return 0;
671
672 if (setting->read_only && attr == ¤t_value_attr.attr)
673 return 0444;
674
675 return attr->mode;
676 }
677
678 static const struct attribute_group coreboot_cfr_setting_group = {
679 .attrs = coreboot_cfr_setting_attrs,
680 .is_visible = coreboot_cfr_attr_is_visible,
681 };
682
coreboot_cfr_free_setting(struct coreboot_cfr_setting * setting)683 static void coreboot_cfr_free_setting(struct coreboot_cfr_setting *setting)
684 {
685 unsigned int i;
686
687 for (i = 0; i < setting->n_values; i++)
688 kfree(setting->values[i].label);
689
690 kfree(setting->values);
691 kfree(setting->display_name);
692 kfree(setting->name);
693 kfree(setting);
694 }
695
coreboot_cfr_setting_release(struct kobject * kobj)696 static void coreboot_cfr_setting_release(struct kobject *kobj)
697 {
698 coreboot_cfr_free_setting(to_coreboot_cfr_setting(kobj));
699 }
700
701 static const struct kobj_type coreboot_cfr_setting_ktype = {
702 .release = coreboot_cfr_setting_release,
703 .sysfs_ops = &kobj_sysfs_ops,
704 };
705
pending_reboot_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)706 static ssize_t pending_reboot_show(struct kobject *kobj,
707 struct kobj_attribute *attr, char *buf)
708 {
709 struct device *dev = kobj_to_dev(kobj->parent);
710 struct coreboot_cfr_drvdata *data;
711
712 data = dev_get_drvdata(dev);
713
714 return sysfs_emit(buf, "%d\n", data->pending_reboot);
715 }
716
717 static struct kobj_attribute pending_reboot_attr = __ATTR_RO(pending_reboot);
718
coreboot_cfr_copy_bool_values(struct coreboot_cfr_setting * setting)719 static int coreboot_cfr_copy_bool_values(struct coreboot_cfr_setting *setting)
720 {
721 static const struct coreboot_cfr_enum bool_values[] = {
722 { .label = "Disabled", .value = 0 },
723 { .label = "Enabled", .value = 1 },
724 };
725 unsigned int i;
726
727 setting->values = kcalloc(ARRAY_SIZE(bool_values), sizeof(*setting->values),
728 GFP_KERNEL);
729 if (!setting->values)
730 return -ENOMEM;
731
732 for (i = 0; i < ARRAY_SIZE(bool_values); i++) {
733 setting->values[i].label = kstrdup(bool_values[i].label,
734 GFP_KERNEL);
735 if (!setting->values[i].label)
736 return -ENOMEM;
737 setting->values[i].value = bool_values[i].value;
738 setting->n_values++;
739 }
740
741 return 0;
742 }
743
coreboot_cfr_count_enum_values(const void * base,size_t len)744 static int coreboot_cfr_count_enum_values(const void *base, size_t len)
745 {
746 struct coreboot_cfr_iterator iterator = {
747 .cursor = base,
748 .remaining = len,
749 };
750 const struct coreboot_table_entry *entry;
751 int count = 0;
752
753 for (;;) {
754 entry = coreboot_cfr_next_entry(&iterator);
755 if (IS_ERR(entry))
756 return PTR_ERR(entry);
757 if (!entry)
758 return count;
759
760 if (entry->tag == CFR_TAG_ENUM_VALUE)
761 count++;
762 }
763 }
764
coreboot_cfr_copy_enum_values(struct coreboot_cfr_setting * setting,const void * base,size_t len)765 static int coreboot_cfr_copy_enum_values(struct coreboot_cfr_setting *setting,
766 const void *base, size_t len)
767 {
768 struct coreboot_cfr_iterator iterator = {
769 .cursor = base,
770 .remaining = len,
771 };
772 const struct lb_cfr_enum_value *enum_value;
773 const struct lb_cfr_varbinary *label;
774 const struct coreboot_table_entry *entry;
775 struct coreboot_cfr_enum *value;
776 int count;
777
778 count = coreboot_cfr_count_enum_values(base, len);
779 if (count <= 0)
780 return count ?: -EINVAL;
781
782 setting->values = kcalloc(count, sizeof(*setting->values), GFP_KERNEL);
783 if (!setting->values)
784 return -ENOMEM;
785
786 for (;;) {
787 entry = coreboot_cfr_next_entry(&iterator);
788 if (IS_ERR(entry))
789 return PTR_ERR(entry);
790 if (!entry)
791 return 0;
792
793 if (entry->tag != CFR_TAG_ENUM_VALUE)
794 continue;
795
796 if (entry->size < sizeof(*enum_value))
797 return -EINVAL;
798
799 enum_value = (const struct lb_cfr_enum_value *)entry;
800 label = coreboot_cfr_child_string(enum_value + 1,
801 enum_value->size - sizeof(*enum_value),
802 CFR_TAG_VARCHAR_UI_NAME);
803 if (IS_ERR(label))
804 return PTR_ERR(label);
805 if (!label)
806 return -EINVAL;
807
808 value = &setting->values[setting->n_values];
809 value->label = coreboot_cfr_string_dup(label);
810 if (!value->label)
811 return -ENOMEM;
812 if (!coreboot_cfr_string_is_valid_label(value->label)) {
813 kfree(value->label);
814 value->label = NULL;
815 return -EINVAL;
816 }
817
818 value->value = enum_value->value;
819 setting->n_values++;
820 }
821 }
822
823 static bool
coreboot_cfr_possible_values_fit(const struct coreboot_cfr_setting * setting)824 coreboot_cfr_possible_values_fit(const struct coreboot_cfr_setting *setting)
825 {
826 size_t len = 1; /* Trailing newline. */
827 size_t label_len;
828 unsigned int i;
829
830 for (i = 0; i < setting->n_values; i++) {
831 if (len >= PAGE_SIZE)
832 return false;
833
834 if (i)
835 len++;
836
837 label_len = strlen(setting->values[i].label);
838 if (label_len >= PAGE_SIZE - len)
839 return false;
840
841 len += label_len;
842 }
843
844 return true;
845 }
846
coreboot_cfr_setting_is_usable(struct coreboot_cfr_setting * setting)847 static int coreboot_cfr_setting_is_usable(struct coreboot_cfr_setting *setting)
848 {
849 u32 value;
850 int ret;
851
852 ret = coreboot_cfr_read_value(setting, &value, NULL);
853 if (ret)
854 return ret;
855
856 if (!coreboot_cfr_value_is_valid(setting, value))
857 return -EINVAL;
858
859 return 0;
860 }
861
coreboot_cfr_register_setting(struct coreboot_cfr_drvdata * data,struct coreboot_cfr_setting * setting)862 static int coreboot_cfr_register_setting(struct coreboot_cfr_drvdata *data,
863 struct coreboot_cfr_setting *setting)
864 {
865 int ret;
866
867 ret = kobject_init_and_add(&setting->kobj, &coreboot_cfr_setting_ktype,
868 &data->attrs_kset->kobj, "%s", setting->name);
869 if (ret)
870 goto err_put_kobj;
871
872 ret = sysfs_create_group(&setting->kobj, &coreboot_cfr_setting_group);
873 if (ret)
874 goto err_put_kobj;
875
876 list_add_tail(&setting->node, &data->settings);
877 return 0;
878
879 err_put_kobj:
880 kobject_put(&setting->kobj);
881 return ret;
882 }
883
coreboot_cfr_add_numeric_option(struct coreboot_cfr_drvdata * data,const struct lb_cfr_numeric_option * option,bool parent_read_only)884 static int coreboot_cfr_add_numeric_option(struct coreboot_cfr_drvdata *data,
885 const struct lb_cfr_numeric_option *option,
886 bool parent_read_only)
887 {
888 const struct lb_cfr_varbinary *name;
889 const struct lb_cfr_varbinary *display_name;
890 const struct lb_cfr_runtime_apply *runtime_apply;
891 const void *child_base = option + 1;
892 struct coreboot_cfr_setting *setting;
893 size_t child_len = option->size - sizeof(*option);
894 int ret;
895
896 if (!(option->flags & CFR_OPTFLAG_RUNTIME))
897 return 0;
898
899 if (option->flags & COREBOOT_CFR_OPT_SKIP_FLAGS)
900 return 0;
901
902 if (option->dependency_id)
903 return 0;
904
905 setting = kzalloc_obj(*setting, GFP_KERNEL);
906 if (!setting)
907 return -ENOMEM;
908
909 INIT_LIST_HEAD(&setting->node);
910 setting->drvdata = data;
911 setting->default_value = option->default_value;
912 setting->min = option->min;
913 setting->max = option->max;
914 setting->step = option->step ?: 1;
915 setting->read_only =
916 (option->flags & COREBOOT_CFR_OPT_READ_ONLY_FLAGS) ||
917 !data->efi_writes_supported || parent_read_only;
918
919 runtime_apply = coreboot_cfr_child_runtime_apply(child_base, child_len);
920 if (IS_ERR(runtime_apply)) {
921 ret = PTR_ERR(runtime_apply);
922 goto err_put_setting;
923 }
924
925 if (runtime_apply && runtime_apply->method == CFR_RUNTIME_APPLY_APM_CNT) {
926 setting->runtime_apply_method = runtime_apply->method;
927 setting->runtime_apply_id = runtime_apply->id;
928 }
929
930 name = coreboot_cfr_child_string(child_base, child_len,
931 CFR_TAG_VARCHAR_OPT_NAME);
932 if (IS_ERR(name)) {
933 ret = PTR_ERR(name);
934 goto err_put_setting;
935 }
936 if (!name) {
937 ret = -EINVAL;
938 goto err_put_setting;
939 }
940
941 setting->name = coreboot_cfr_string_dup(name);
942 if (!setting->name) {
943 ret = -ENOMEM;
944 goto err_put_setting;
945 }
946
947 if (!coreboot_cfr_string_is_valid_name(setting->name)) {
948 ret = -EINVAL;
949 goto err_put_setting;
950 }
951
952 display_name = coreboot_cfr_child_string(child_base, child_len,
953 CFR_TAG_VARCHAR_UI_NAME);
954 if (IS_ERR(display_name)) {
955 ret = PTR_ERR(display_name);
956 goto err_put_setting;
957 }
958 if (display_name)
959 setting->display_name = coreboot_cfr_string_dup(display_name);
960 else
961 setting->display_name = kstrdup(setting->name, GFP_KERNEL);
962 if (!setting->display_name) {
963 ret = -ENOMEM;
964 goto err_put_setting;
965 }
966
967 switch (option->tag) {
968 case CFR_TAG_OPTION_BOOL:
969 setting->type = COREBOOT_CFR_SETTING_BOOL;
970 setting->min = 0;
971 setting->max = 1;
972 setting->step = 1;
973 ret = coreboot_cfr_copy_bool_values(setting);
974 break;
975 case CFR_TAG_OPTION_ENUM:
976 setting->type = COREBOOT_CFR_SETTING_ENUM;
977 ret = coreboot_cfr_copy_enum_values(setting, child_base,
978 child_len);
979 break;
980 case CFR_TAG_OPTION_NUMBER:
981 setting->type = COREBOOT_CFR_SETTING_NUMBER;
982 if (setting->max < setting->min)
983 ret = -EINVAL;
984 else
985 ret = 0;
986 break;
987 default:
988 ret = -EINVAL;
989 break;
990 }
991
992 if (ret)
993 goto err_put_setting;
994 /* possible_values must be returned completely in one sysfs read. */
995 if (setting->type != COREBOOT_CFR_SETTING_NUMBER &&
996 !coreboot_cfr_possible_values_fit(setting)) {
997 ret = 0;
998 goto err_put_setting;
999 }
1000
1001 ret = coreboot_cfr_setting_is_usable(setting);
1002 if (ret) {
1003 /*
1004 * CFR may describe options without a matching, readable runtime
1005 * EFI variable. Skip those, but propagate transient EFI failures.
1006 */
1007 if (ret == -ENOENT || ret == -EINVAL || ret == -EOPNOTSUPP ||
1008 ret == -ENAMETOOLONG)
1009 ret = 0;
1010 goto err_put_setting;
1011 }
1012
1013 /* The kobject release callback owns setting after this call. */
1014 return coreboot_cfr_register_setting(data, setting);
1015
1016 err_put_setting:
1017 coreboot_cfr_free_setting(setting);
1018 return ret;
1019 }
1020
coreboot_cfr_parse_records(struct coreboot_cfr_drvdata * data,const void * base,size_t len,unsigned int depth,bool parent_read_only)1021 static int coreboot_cfr_parse_records(struct coreboot_cfr_drvdata *data,
1022 const void *base, size_t len,
1023 unsigned int depth,
1024 bool parent_read_only)
1025 {
1026 struct coreboot_cfr_iterator iterator = {
1027 .cursor = base,
1028 .remaining = len,
1029 };
1030 const struct lb_cfr_option_form *form;
1031 const struct lb_cfr_numeric_option *option;
1032 const struct coreboot_table_entry *entry;
1033 const void *child_base;
1034 size_t child_len;
1035 int ret;
1036
1037 for (;;) {
1038 entry = coreboot_cfr_next_entry(&iterator);
1039 if (IS_ERR(entry))
1040 return PTR_ERR(entry);
1041 if (!entry)
1042 return 0;
1043
1044 switch (entry->tag) {
1045 case CFR_TAG_OPTION_FORM:
1046 if (entry->size < sizeof(struct lb_cfr_option_form))
1047 return -EINVAL;
1048
1049 form = (const struct lb_cfr_option_form *)entry;
1050 if (form->dependency_id ||
1051 form->flags & CFR_OPTFLAG_SUPPRESS)
1052 break;
1053
1054 if (depth >= COREBOOT_CFR_MAX_FORM_DEPTH)
1055 return -E2BIG;
1056
1057 child_base = form + 1;
1058 child_len = entry->size - sizeof(struct lb_cfr_option_form);
1059 ret = coreboot_cfr_parse_records(data, child_base,
1060 child_len, depth + 1,
1061 parent_read_only ||
1062 (form->flags &
1063 COREBOOT_CFR_OPT_READ_ONLY_FLAGS));
1064 if (ret)
1065 return ret;
1066 break;
1067 case CFR_TAG_OPTION_ENUM:
1068 case CFR_TAG_OPTION_NUMBER:
1069 case CFR_TAG_OPTION_BOOL:
1070 option = (const struct lb_cfr_numeric_option *)entry;
1071 if (entry->size < sizeof(*option))
1072 return -EINVAL;
1073 ret = coreboot_cfr_add_numeric_option(data, option,
1074 parent_read_only);
1075 if (ret)
1076 return ret;
1077 break;
1078 default:
1079 /* Ignore unsupported, child-only and future record types. */
1080 break;
1081 }
1082 }
1083 }
1084
coreboot_cfr_unregister_settings(struct coreboot_cfr_drvdata * data)1085 static void coreboot_cfr_unregister_settings(struct coreboot_cfr_drvdata *data)
1086 {
1087 struct coreboot_cfr_setting *setting, *tmp;
1088
1089 list_for_each_entry_safe(setting, tmp, &data->settings, node) {
1090 sysfs_remove_group(&setting->kobj, &coreboot_cfr_setting_group);
1091 list_del(&setting->node);
1092 kobject_put(&setting->kobj);
1093 }
1094 }
1095
coreboot_cfr_probe(struct coreboot_device * dev)1096 static int coreboot_cfr_probe(struct coreboot_device *dev)
1097 {
1098 const struct lb_cfr *root = (const struct lb_cfr *)dev->raw;
1099 struct coreboot_cfr_drvdata *data;
1100 size_t payload_len;
1101 int ret;
1102
1103 if (dev->entry.size < sizeof(*root))
1104 return -EINVAL;
1105
1106 if (root->tag != LB_TAG_CFR_ROOT || root->version != CFR_VERSION)
1107 return -EINVAL;
1108
1109 if (root->size < sizeof(*root) || root->size > dev->entry.size)
1110 return -EINVAL;
1111
1112 payload_len = root->size - sizeof(*root);
1113 if (crc32_be(0, root + 1, payload_len) != root->checksum)
1114 return -EBADMSG;
1115
1116 if (!efivar_is_available())
1117 return -EPROBE_DEFER;
1118
1119 data = devm_kzalloc(&dev->dev, sizeof(*data), GFP_KERNEL);
1120 if (!data)
1121 return -ENOMEM;
1122
1123 ret = efivar_lock();
1124 if (ret)
1125 return ret;
1126 data->efi_writes_supported = efivar_supports_writes();
1127 efivar_unlock();
1128
1129 INIT_LIST_HEAD(&data->settings);
1130 ret = devm_mutex_init(&dev->dev, &data->lock);
1131 if (ret)
1132 return ret;
1133
1134 dev_set_drvdata(&dev->dev, data);
1135
1136 data->class_dev = device_create(&firmware_attributes_class, NULL,
1137 MKDEV(0, 0), NULL, DRIVER_NAME);
1138 if (IS_ERR(data->class_dev))
1139 return PTR_ERR(data->class_dev);
1140 dev_set_drvdata(data->class_dev, data);
1141
1142 data->attrs_kset = kset_create_and_add("attributes", NULL,
1143 &data->class_dev->kobj);
1144 if (!data->attrs_kset) {
1145 ret = -ENOMEM;
1146 goto err_unregister_dev;
1147 }
1148
1149 ret = sysfs_create_file(&data->attrs_kset->kobj,
1150 &pending_reboot_attr.attr);
1151 if (ret)
1152 goto err_unregister_attrs;
1153
1154 ret = coreboot_cfr_parse_records(data, root + 1, payload_len, 0, false);
1155 if (ret)
1156 goto err_unregister_settings;
1157
1158 if (list_empty(&data->settings)) {
1159 ret = -ENODEV;
1160 goto err_unregister_settings;
1161 }
1162
1163 return 0;
1164
1165 err_unregister_settings:
1166 coreboot_cfr_unregister_settings(data);
1167 sysfs_remove_file(&data->attrs_kset->kobj, &pending_reboot_attr.attr);
1168 err_unregister_attrs:
1169 kset_unregister(data->attrs_kset);
1170 err_unregister_dev:
1171 device_unregister(data->class_dev);
1172 return ret;
1173 }
1174
coreboot_cfr_remove(struct coreboot_device * dev)1175 static void coreboot_cfr_remove(struct coreboot_device *dev)
1176 {
1177 struct coreboot_cfr_drvdata *data = dev_get_drvdata(&dev->dev);
1178
1179 coreboot_cfr_unregister_settings(data);
1180 sysfs_remove_file(&data->attrs_kset->kobj, &pending_reboot_attr.attr);
1181 kset_unregister(data->attrs_kset);
1182 device_unregister(data->class_dev);
1183 }
1184
1185 static const struct coreboot_device_id coreboot_cfr_ids[] = {
1186 { .tag = LB_TAG_CFR_ROOT },
1187 { }
1188 };
1189 MODULE_DEVICE_TABLE(coreboot, coreboot_cfr_ids);
1190
1191 static struct coreboot_driver coreboot_cfr_driver = {
1192 .probe = coreboot_cfr_probe,
1193 .remove = coreboot_cfr_remove,
1194 .drv = {
1195 .name = DRIVER_NAME,
1196 },
1197 .id_table = coreboot_cfr_ids,
1198 };
1199 module_coreboot_driver(coreboot_cfr_driver);
1200
1201 MODULE_AUTHOR("Sean Rhodes <sean@starlabs.systems>");
1202 MODULE_DESCRIPTION("coreboot CFR firmware attributes driver");
1203 MODULE_LICENSE("GPL");
1204 MODULE_IMPORT_NS("EFIVAR");
1205