hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/lib/test_firmware.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * This module provides an interface to trigger and test firmware loading.
34 *
....@@ -17,14 +18,19 @@
1718 #include <linux/device.h>
1819 #include <linux/fs.h>
1920 #include <linux/miscdevice.h>
21
+#include <linux/sizes.h>
2022 #include <linux/slab.h>
2123 #include <linux/uaccess.h>
2224 #include <linux/delay.h>
2325 #include <linux/kthread.h>
2426 #include <linux/vmalloc.h>
27
+#include <linux/efi_embedded_fw.h>
28
+
29
+MODULE_IMPORT_NS(TEST_FIRMWARE);
2530
2631 #define TEST_FIRMWARE_NAME "test-firmware.bin"
2732 #define TEST_FIRMWARE_NUM_REQS 4
33
+#define TEST_FIRMWARE_BUF_SIZE SZ_1K
2834
2935 static DEFINE_MUTEX(test_fw_mutex);
3036 static const struct firmware *test_firmware;
....@@ -44,6 +50,11 @@
4450 * test_config - represents configuration for the test for different triggers
4551 *
4652 * @name: the name of the firmware file to look for
53
+ * @into_buf: when the into_buf is used if this is true
54
+ * request_firmware_into_buf() will be used instead.
55
+ * @buf_size: size of buf to allocate when into_buf is true
56
+ * @file_offset: file offset to request when calling request_firmware_into_buf
57
+ * @partial: partial read opt when calling request_firmware_into_buf
4758 * @sync_direct: when the sync trigger is used if this is true
4859 * request_firmware_direct() will be used instead.
4960 * @send_uevent: whether or not to send a uevent for async requests
....@@ -82,6 +93,10 @@
8293 */
8394 struct test_config {
8495 char *name;
96
+ bool into_buf;
97
+ size_t buf_size;
98
+ size_t file_offset;
99
+ bool partial;
85100 bool sync_direct;
86101 bool send_uevent;
87102 u8 num_requests;
....@@ -175,6 +190,10 @@
175190
176191 test_fw_config->num_requests = TEST_FIRMWARE_NUM_REQS;
177192 test_fw_config->send_uevent = true;
193
+ test_fw_config->into_buf = false;
194
+ test_fw_config->buf_size = TEST_FIRMWARE_BUF_SIZE;
195
+ test_fw_config->file_offset = 0;
196
+ test_fw_config->partial = false;
178197 test_fw_config->sync_direct = false;
179198 test_fw_config->req_firmware = request_firmware;
180199 test_fw_config->test_result = 0;
....@@ -228,25 +247,35 @@
228247 dev_name(dev));
229248
230249 if (test_fw_config->name)
231
- len += scnprintf(buf+len, PAGE_SIZE - len,
250
+ len += scnprintf(buf + len, PAGE_SIZE - len,
232251 "name:\t%s\n",
233252 test_fw_config->name);
234253 else
235
- len += scnprintf(buf+len, PAGE_SIZE - len,
254
+ len += scnprintf(buf + len, PAGE_SIZE - len,
236255 "name:\tEMTPY\n");
237256
238
- len += scnprintf(buf+len, PAGE_SIZE - len,
257
+ len += scnprintf(buf + len, PAGE_SIZE - len,
239258 "num_requests:\t%u\n", test_fw_config->num_requests);
240259
241
- len += scnprintf(buf+len, PAGE_SIZE - len,
260
+ len += scnprintf(buf + len, PAGE_SIZE - len,
242261 "send_uevent:\t\t%s\n",
243262 test_fw_config->send_uevent ?
244263 "FW_ACTION_HOTPLUG" :
245264 "FW_ACTION_NOHOTPLUG");
246
- len += scnprintf(buf+len, PAGE_SIZE - len,
265
+ len += scnprintf(buf + len, PAGE_SIZE - len,
266
+ "into_buf:\t\t%s\n",
267
+ test_fw_config->into_buf ? "true" : "false");
268
+ len += scnprintf(buf + len, PAGE_SIZE - len,
269
+ "buf_size:\t%zu\n", test_fw_config->buf_size);
270
+ len += scnprintf(buf + len, PAGE_SIZE - len,
271
+ "file_offset:\t%zu\n", test_fw_config->file_offset);
272
+ len += scnprintf(buf + len, PAGE_SIZE - len,
273
+ "partial:\t\t%s\n",
274
+ test_fw_config->partial ? "true" : "false");
275
+ len += scnprintf(buf + len, PAGE_SIZE - len,
247276 "sync_direct:\t\t%s\n",
248277 test_fw_config->sync_direct ? "true" : "false");
249
- len += scnprintf(buf+len, PAGE_SIZE - len,
278
+ len += scnprintf(buf + len, PAGE_SIZE - len,
250279 "read_fw_idx:\t%u\n", test_fw_config->read_fw_idx);
251280
252281 mutex_unlock(&test_fw_mutex);
....@@ -299,27 +328,37 @@
299328 return ret;
300329 }
301330
302
-static ssize_t
303
-test_dev_config_show_bool(char *buf,
304
- bool config)
331
+static ssize_t test_dev_config_show_bool(char *buf, bool val)
305332 {
306
- bool val;
307
-
308
- mutex_lock(&test_fw_mutex);
309
- val = config;
310
- mutex_unlock(&test_fw_mutex);
311
-
312333 return snprintf(buf, PAGE_SIZE, "%d\n", val);
313334 }
314335
315
-static ssize_t test_dev_config_show_int(char *buf, int cfg)
336
+static int test_dev_config_update_size_t(const char *buf,
337
+ size_t size,
338
+ size_t *cfg)
316339 {
317
- int val;
340
+ int ret;
341
+ long new;
342
+
343
+ ret = kstrtol(buf, 10, &new);
344
+ if (ret)
345
+ return ret;
318346
319347 mutex_lock(&test_fw_mutex);
320
- val = cfg;
348
+ *(size_t *)cfg = new;
321349 mutex_unlock(&test_fw_mutex);
322350
351
+ /* Always return full write size even if we didn't consume all */
352
+ return size;
353
+}
354
+
355
+static ssize_t test_dev_config_show_size_t(char *buf, size_t val)
356
+{
357
+ return snprintf(buf, PAGE_SIZE, "%zu\n", val);
358
+}
359
+
360
+static ssize_t test_dev_config_show_int(char *buf, int val)
361
+{
323362 return snprintf(buf, PAGE_SIZE, "%d\n", val);
324363 }
325364
....@@ -343,14 +382,8 @@
343382 return size;
344383 }
345384
346
-static ssize_t test_dev_config_show_u8(char *buf, u8 cfg)
385
+static ssize_t test_dev_config_show_u8(char *buf, u8 val)
347386 {
348
- u8 val;
349
-
350
- mutex_lock(&test_fw_mutex);
351
- val = cfg;
352
- mutex_unlock(&test_fw_mutex);
353
-
354387 return snprintf(buf, PAGE_SIZE, "%u\n", val);
355388 }
356389
....@@ -391,6 +424,100 @@
391424 return test_dev_config_show_u8(buf, test_fw_config->num_requests);
392425 }
393426 static DEVICE_ATTR_RW(config_num_requests);
427
+
428
+static ssize_t config_into_buf_store(struct device *dev,
429
+ struct device_attribute *attr,
430
+ const char *buf, size_t count)
431
+{
432
+ return test_dev_config_update_bool(buf,
433
+ count,
434
+ &test_fw_config->into_buf);
435
+}
436
+
437
+static ssize_t config_into_buf_show(struct device *dev,
438
+ struct device_attribute *attr,
439
+ char *buf)
440
+{
441
+ return test_dev_config_show_bool(buf, test_fw_config->into_buf);
442
+}
443
+static DEVICE_ATTR_RW(config_into_buf);
444
+
445
+static ssize_t config_buf_size_store(struct device *dev,
446
+ struct device_attribute *attr,
447
+ const char *buf, size_t count)
448
+{
449
+ int rc;
450
+
451
+ mutex_lock(&test_fw_mutex);
452
+ if (test_fw_config->reqs) {
453
+ pr_err("Must call release_all_firmware prior to changing config\n");
454
+ rc = -EINVAL;
455
+ mutex_unlock(&test_fw_mutex);
456
+ goto out;
457
+ }
458
+ mutex_unlock(&test_fw_mutex);
459
+
460
+ rc = test_dev_config_update_size_t(buf, count,
461
+ &test_fw_config->buf_size);
462
+
463
+out:
464
+ return rc;
465
+}
466
+
467
+static ssize_t config_buf_size_show(struct device *dev,
468
+ struct device_attribute *attr,
469
+ char *buf)
470
+{
471
+ return test_dev_config_show_size_t(buf, test_fw_config->buf_size);
472
+}
473
+static DEVICE_ATTR_RW(config_buf_size);
474
+
475
+static ssize_t config_file_offset_store(struct device *dev,
476
+ struct device_attribute *attr,
477
+ const char *buf, size_t count)
478
+{
479
+ int rc;
480
+
481
+ mutex_lock(&test_fw_mutex);
482
+ if (test_fw_config->reqs) {
483
+ pr_err("Must call release_all_firmware prior to changing config\n");
484
+ rc = -EINVAL;
485
+ mutex_unlock(&test_fw_mutex);
486
+ goto out;
487
+ }
488
+ mutex_unlock(&test_fw_mutex);
489
+
490
+ rc = test_dev_config_update_size_t(buf, count,
491
+ &test_fw_config->file_offset);
492
+
493
+out:
494
+ return rc;
495
+}
496
+
497
+static ssize_t config_file_offset_show(struct device *dev,
498
+ struct device_attribute *attr,
499
+ char *buf)
500
+{
501
+ return test_dev_config_show_size_t(buf, test_fw_config->file_offset);
502
+}
503
+static DEVICE_ATTR_RW(config_file_offset);
504
+
505
+static ssize_t config_partial_store(struct device *dev,
506
+ struct device_attribute *attr,
507
+ const char *buf, size_t count)
508
+{
509
+ return test_dev_config_update_bool(buf,
510
+ count,
511
+ &test_fw_config->partial);
512
+}
513
+
514
+static ssize_t config_partial_show(struct device *dev,
515
+ struct device_attribute *attr,
516
+ char *buf)
517
+{
518
+ return test_dev_config_show_bool(buf, test_fw_config->partial);
519
+}
520
+static DEVICE_ATTR_RW(config_partial);
394521
395522 static ssize_t config_sync_direct_store(struct device *dev,
396523 struct device_attribute *attr,
....@@ -480,6 +607,64 @@
480607 }
481608 static DEVICE_ATTR_WO(trigger_request);
482609
610
+#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
611
+extern struct list_head efi_embedded_fw_list;
612
+extern bool efi_embedded_fw_checked;
613
+
614
+static ssize_t trigger_request_platform_store(struct device *dev,
615
+ struct device_attribute *attr,
616
+ const char *buf, size_t count)
617
+{
618
+ static const u8 test_data[] = {
619
+ 0x55, 0xaa, 0x55, 0xaa, 0x01, 0x02, 0x03, 0x04,
620
+ 0x55, 0xaa, 0x55, 0xaa, 0x05, 0x06, 0x07, 0x08,
621
+ 0x55, 0xaa, 0x55, 0xaa, 0x10, 0x20, 0x30, 0x40,
622
+ 0x55, 0xaa, 0x55, 0xaa, 0x50, 0x60, 0x70, 0x80
623
+ };
624
+ struct efi_embedded_fw efi_embedded_fw;
625
+ const struct firmware *firmware = NULL;
626
+ bool saved_efi_embedded_fw_checked;
627
+ char *name;
628
+ int rc;
629
+
630
+ name = kstrndup(buf, count, GFP_KERNEL);
631
+ if (!name)
632
+ return -ENOSPC;
633
+
634
+ pr_info("inserting test platform fw '%s'\n", name);
635
+ efi_embedded_fw.name = name;
636
+ efi_embedded_fw.data = (void *)test_data;
637
+ efi_embedded_fw.length = sizeof(test_data);
638
+ list_add(&efi_embedded_fw.list, &efi_embedded_fw_list);
639
+ saved_efi_embedded_fw_checked = efi_embedded_fw_checked;
640
+ efi_embedded_fw_checked = true;
641
+
642
+ pr_info("loading '%s'\n", name);
643
+ rc = firmware_request_platform(&firmware, name, dev);
644
+ if (rc) {
645
+ pr_info("load of '%s' failed: %d\n", name, rc);
646
+ goto out;
647
+ }
648
+ if (firmware->size != sizeof(test_data) ||
649
+ memcmp(firmware->data, test_data, sizeof(test_data)) != 0) {
650
+ pr_info("firmware contents mismatch for '%s'\n", name);
651
+ rc = -EINVAL;
652
+ goto out;
653
+ }
654
+ pr_info("loaded: %zu\n", firmware->size);
655
+ rc = count;
656
+
657
+out:
658
+ efi_embedded_fw_checked = saved_efi_embedded_fw_checked;
659
+ release_firmware(firmware);
660
+ list_del(&efi_embedded_fw.list);
661
+ kfree(name);
662
+
663
+ return rc;
664
+}
665
+static DEVICE_ATTR_WO(trigger_request_platform);
666
+#endif
667
+
483668 static DECLARE_COMPLETION(async_fw_done);
484669
485670 static void trigger_async_request_cb(const struct firmware *fw, void *context)
....@@ -521,7 +706,7 @@
521706 rc = count;
522707 } else {
523708 pr_err("failed to async load firmware\n");
524
- rc = -ENODEV;
709
+ rc = -ENOMEM;
525710 }
526711
527712 out:
....@@ -584,7 +769,36 @@
584769 return -EINVAL;
585770 }
586771
587
- req->rc = test_fw_config->req_firmware(&req->fw, req->name, req->dev);
772
+ if (test_fw_config->into_buf) {
773
+ void *test_buf;
774
+
775
+ test_buf = kzalloc(TEST_FIRMWARE_BUF_SIZE, GFP_KERNEL);
776
+ if (!test_buf)
777
+ return -ENOSPC;
778
+
779
+ if (test_fw_config->partial)
780
+ req->rc = request_partial_firmware_into_buf
781
+ (&req->fw,
782
+ req->name,
783
+ req->dev,
784
+ test_buf,
785
+ test_fw_config->buf_size,
786
+ test_fw_config->file_offset);
787
+ else
788
+ req->rc = request_firmware_into_buf
789
+ (&req->fw,
790
+ req->name,
791
+ req->dev,
792
+ test_buf,
793
+ test_fw_config->buf_size);
794
+ if (!req->fw)
795
+ kfree(test_buf);
796
+ } else {
797
+ req->rc = test_fw_config->req_firmware(&req->fw,
798
+ req->name,
799
+ req->dev);
800
+ }
801
+
588802 if (req->rc) {
589803 pr_info("#%u: batched sync load failed: %d\n",
590804 req->idx, req->rc);
....@@ -631,11 +845,6 @@
631845
632846 for (i = 0; i < test_fw_config->num_requests; i++) {
633847 req = &test_fw_config->reqs[i];
634
- if (!req) {
635
- WARN_ON(1);
636
- rc = -ENOMEM;
637
- goto out_bail;
638
- }
639848 req->fw = NULL;
640849 req->idx = i;
641850 req->name = test_fw_config->name;
....@@ -737,10 +946,6 @@
737946
738947 for (i = 0; i < test_fw_config->num_requests; i++) {
739948 req = &test_fw_config->reqs[i];
740
- if (!req) {
741
- WARN_ON(1);
742
- goto out_bail;
743
- }
744949 req->name = test_fw_config->name;
745950 req->fw = NULL;
746951 req->idx = i;
....@@ -857,6 +1062,10 @@
8571062 TEST_FW_DEV_ATTR(config),
8581063 TEST_FW_DEV_ATTR(config_name),
8591064 TEST_FW_DEV_ATTR(config_num_requests),
1065
+ TEST_FW_DEV_ATTR(config_into_buf),
1066
+ TEST_FW_DEV_ATTR(config_buf_size),
1067
+ TEST_FW_DEV_ATTR(config_file_offset),
1068
+ TEST_FW_DEV_ATTR(config_partial),
8601069 TEST_FW_DEV_ATTR(config_sync_direct),
8611070 TEST_FW_DEV_ATTR(config_send_uevent),
8621071 TEST_FW_DEV_ATTR(config_read_fw_idx),
....@@ -865,6 +1074,9 @@
8651074 TEST_FW_DEV_ATTR(trigger_request),
8661075 TEST_FW_DEV_ATTR(trigger_async_request),
8671076 TEST_FW_DEV_ATTR(trigger_custom_fallback),
1077
+#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
1078
+ TEST_FW_DEV_ATTR(trigger_request_platform),
1079
+#endif
8681080
8691081 /* These use the config and can use the test_result */
8701082 TEST_FW_DEV_ATTR(trigger_batched_requests),