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