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