1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <pasha.tatashin@soleen.com>
6 */
7
8 #define pr_fmt(fmt) KBUILD_MODNAME " test: " fmt
9
10 #include <linux/cleanup.h>
11 #include <linux/errno.h>
12 #include <linux/init.h>
13 #include <linux/liveupdate.h>
14 #include <linux/module.h>
15 #include "../../kernel/liveupdate/luo_internal.h"
16
17 static const struct liveupdate_flb_ops test_flb_ops;
18 #define DEFINE_TEST_FLB(i) { \
19 .ops = &test_flb_ops, \
20 .compatible = LIVEUPDATE_TEST_FLB_COMPATIBLE(i), \
21 }
22
23 /* Number of Test FLBs to register with every file handler */
24 #define TEST_NFLBS 3
25 static struct liveupdate_flb test_flbs[TEST_NFLBS] = {
26 DEFINE_TEST_FLB(0),
27 DEFINE_TEST_FLB(1),
28 DEFINE_TEST_FLB(2),
29 };
30
31 #define TEST_FLB_MAGIC_BASE 0xFEEDF00DCAFEBEE0ULL
32
test_flb_preserve(struct liveupdate_flb_op_args * argp)33 static int test_flb_preserve(struct liveupdate_flb_op_args *argp)
34 {
35 ptrdiff_t index = argp->flb - test_flbs;
36
37 pr_info("%s: preserve was triggered\n", argp->flb->compatible);
38 argp->data = TEST_FLB_MAGIC_BASE + index;
39
40 return 0;
41 }
42
test_flb_unpreserve(struct liveupdate_flb_op_args * argp)43 static void test_flb_unpreserve(struct liveupdate_flb_op_args *argp)
44 {
45 pr_info("%s: unpreserve was triggered\n", argp->flb->compatible);
46 }
47
test_flb_retrieve(struct liveupdate_flb_op_args * argp)48 static int test_flb_retrieve(struct liveupdate_flb_op_args *argp)
49 {
50 ptrdiff_t index = argp->flb - test_flbs;
51 u64 expected_data = TEST_FLB_MAGIC_BASE + index;
52
53 if (argp->data == expected_data) {
54 pr_info("%s: found flb data from the previous boot\n",
55 argp->flb->compatible);
56 argp->obj = (void *)argp->data;
57 } else {
58 pr_err("%s: ERROR - incorrect data handle: %llx, expected %llx\n",
59 argp->flb->compatible, argp->data, expected_data);
60 return -EINVAL;
61 }
62
63 return 0;
64 }
65
test_flb_finish(struct liveupdate_flb_op_args * argp)66 static void test_flb_finish(struct liveupdate_flb_op_args *argp)
67 {
68 ptrdiff_t index = argp->flb - test_flbs;
69 void *expected_obj = (void *)(TEST_FLB_MAGIC_BASE + index);
70
71 if (argp->obj == expected_obj) {
72 pr_info("%s: finish was triggered\n", argp->flb->compatible);
73 } else {
74 pr_err("%s: ERROR - finish called with invalid object\n",
75 argp->flb->compatible);
76 }
77 }
78
79 static const struct liveupdate_flb_ops test_flb_ops = {
80 .preserve = test_flb_preserve,
81 .unpreserve = test_flb_unpreserve,
82 .retrieve = test_flb_retrieve,
83 .finish = test_flb_finish,
84 .owner = THIS_MODULE,
85 };
86
liveupdate_test_init(void)87 static void liveupdate_test_init(void)
88 {
89 static DEFINE_MUTEX(init_lock);
90 static bool initialized;
91 int i;
92
93 guard(mutex)(&init_lock);
94
95 if (initialized)
96 return;
97
98 for (i = 0; i < TEST_NFLBS; i++) {
99 struct liveupdate_flb *flb = &test_flbs[i];
100 void *obj;
101 int err;
102
103 err = liveupdate_flb_get_incoming(flb, &obj);
104 if (err && err != -ENODATA && err != -ENOENT) {
105 pr_err("liveupdate_flb_get_incoming for %s failed: %pe\n",
106 flb->compatible, ERR_PTR(err));
107 }
108 }
109 initialized = true;
110 }
111
liveupdate_test_register(struct liveupdate_file_handler * fh)112 void liveupdate_test_register(struct liveupdate_file_handler *fh)
113 {
114 int err, i;
115
116 liveupdate_test_init();
117
118 for (i = 0; i < TEST_NFLBS; i++) {
119 struct liveupdate_flb *flb = &test_flbs[i];
120
121 err = liveupdate_register_flb(fh, flb);
122 if (err) {
123 pr_err("Failed to register %s %pe\n",
124 flb->compatible, ERR_PTR(err));
125 }
126 }
127
128 err = liveupdate_register_flb(fh, &test_flbs[0]);
129 if (!err || err != -EEXIST) {
130 pr_err("Failed: %s should be already registered, but got err: %pe\n",
131 test_flbs[0].compatible, ERR_PTR(err));
132 }
133
134 pr_info("Registered %d FLBs with file handler: [%s]\n",
135 TEST_NFLBS, fh->compatible);
136 }
137
liveupdate_test_unregister(struct liveupdate_file_handler * fh)138 void liveupdate_test_unregister(struct liveupdate_file_handler *fh)
139 {
140 int err, i;
141
142 for (i = 0; i < TEST_NFLBS; i++) {
143 struct liveupdate_flb *flb = &test_flbs[i];
144
145 err = liveupdate_unregister_flb(fh, flb);
146 if (err) {
147 pr_err("Failed to unregister %s %pe\n",
148 flb->compatible, ERR_PTR(err));
149 }
150 }
151
152 pr_info("Unregistered %d FLBs from file handler: [%s]\n",
153 TEST_NFLBS, fh->compatible);
154 }
155
156 MODULE_LICENSE("GPL");
157 MODULE_AUTHOR("Pasha Tatashin <pasha.tatashin@soleen.com>");
158 MODULE_DESCRIPTION("In-kernel test for LUO mechanism");
159