xref: /linux/lib/tests/liveupdate.c (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
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 
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 
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 
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 
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 
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 
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 
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