xref: /linux/lib/tests/liveupdate.c (revision 995832b2cebe6969d1b42635db698803ee31294d)
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 		if (!err)
110 			liveupdate_flb_put_incoming(flb);
111 	}
112 	initialized = true;
113 }
114 
115 void liveupdate_test_register(struct liveupdate_file_handler *fh)
116 {
117 	int err, i;
118 
119 	liveupdate_test_init();
120 
121 	for (i = 0; i < TEST_NFLBS; i++) {
122 		struct liveupdate_flb *flb = &test_flbs[i];
123 
124 		err = liveupdate_register_flb(fh, flb);
125 		if (err) {
126 			pr_err("Failed to register %s %pe\n",
127 			       flb->compatible, ERR_PTR(err));
128 		}
129 	}
130 
131 	err = liveupdate_register_flb(fh, &test_flbs[0]);
132 	if (!err || err != -EEXIST) {
133 		pr_err("Failed: %s should be already registered, but got err: %pe\n",
134 		       test_flbs[0].compatible, ERR_PTR(err));
135 	}
136 
137 	pr_info("Registered %d FLBs with file handler: [%s]\n",
138 		TEST_NFLBS, fh->compatible);
139 }
140 
141 MODULE_LICENSE("GPL");
142 MODULE_AUTHOR("Pasha Tatashin <pasha.tatashin@soleen.com>");
143 MODULE_DESCRIPTION("In-kernel test for LUO mechanism");
144