xref: /optee_os/lib/libutils/ext/include/fault_mitigation.h (revision 7e75ca5422dc58ae35fd4ced30d204796fc8b3fb)
1*7e75ca54SJens Wiklander /* SPDX-License-Identifier: BSD-2-Clause */
2*7e75ca54SJens Wiklander /*
3*7e75ca54SJens Wiklander  * Copyright (c) 2022, Linaro Limited
4*7e75ca54SJens Wiklander  */
5*7e75ca54SJens Wiklander #ifndef __FAULT_MITIGATION_H
6*7e75ca54SJens Wiklander #define __FAULT_MITIGATION_H
7*7e75ca54SJens Wiklander 
8*7e75ca54SJens Wiklander #include <assert.h>
9*7e75ca54SJens Wiklander #include <config.h>
10*7e75ca54SJens Wiklander #include <string.h>
11*7e75ca54SJens Wiklander #include <util.h>
12*7e75ca54SJens Wiklander 
13*7e75ca54SJens Wiklander #ifdef __KERNEL__
14*7e75ca54SJens Wiklander #include <kernel/panic.h>
15*7e75ca54SJens Wiklander #include <kernel/thread.h>
16*7e75ca54SJens Wiklander #else
17*7e75ca54SJens Wiklander #include <tee_api.h>
18*7e75ca54SJens Wiklander #endif
19*7e75ca54SJens Wiklander 
20*7e75ca54SJens Wiklander /*
21*7e75ca54SJens Wiklander  * Fault migitigation helpers to make successful Hardware Fault Attacks
22*7e75ca54SJens Wiklander  * harder to achieve. The paper [1] by Riscure gives background to the
23*7e75ca54SJens Wiklander  * problem.
24*7e75ca54SJens Wiklander  *
25*7e75ca54SJens Wiklander  * These helpers aim to make it hard for a single glitch attack to succeed
26*7e75ca54SJens Wiklander  * while the protected function or one of the ftmn_*() functions are
27*7e75ca54SJens Wiklander  * executed.
28*7e75ca54SJens Wiklander  *
29*7e75ca54SJens Wiklander  * To have something to work with we assume that a single glitch may affect
30*7e75ca54SJens Wiklander  * a few instructions in sequence to do nothing or to corrupt the content
31*7e75ca54SJens Wiklander  * of a few registers.
32*7e75ca54SJens Wiklander  *
33*7e75ca54SJens Wiklander  * Using the terminology from [1] we are implementing the following patterns:
34*7e75ca54SJens Wiklander  * 3 FAULT.VALUE.CHECK
35*7e75ca54SJens Wiklander  * 5 FAULT.DECISION.CHECK
36*7e75ca54SJens Wiklander  * 9 FAULT.FLOW.CONTROL
37*7e75ca54SJens Wiklander  *
38*7e75ca54SJens Wiklander  * Additionally are the following patterns also acknowledged with a few
39*7e75ca54SJens Wiklander  * comments:
40*7e75ca54SJens Wiklander  * 1. FAULT.CONSTANT.CODING
41*7e75ca54SJens Wiklander  *	Zero is normally a success code in OP-TEE so special functions are
42*7e75ca54SJens Wiklander  *	added to record anything but a zero result.
43*7e75ca54SJens Wiklander  * 8. FAULT.NESTED.CHECK
44*7e75ca54SJens Wiklander  *	The linked calls performed by for instance FTMN_CALL_FUNC() addresses
45*7e75ca54SJens Wiklander  *	this by relying on the called function to update a state in
46*7e75ca54SJens Wiklander  *	struct ftmn_func_arg which is checked when the function has returned.
47*7e75ca54SJens Wiklander  * 11. FAULT.PENALTY
48*7e75ca54SJens Wiklander  *	This is implicit since we're normally trying to protect things post
49*7e75ca54SJens Wiklander  *	boot and booting takes quite some time.
50*7e75ca54SJens Wiklander  *
51*7e75ca54SJens Wiklander  * [1] https://web.archive.org/web/20220616035354/https://www.riscure.com/uploads/2020/05/Riscure_Whitepaper_Fault_Mitigation_Patterns_final.pdf
52*7e75ca54SJens Wiklander  */
53*7e75ca54SJens Wiklander 
54*7e75ca54SJens Wiklander #include <stdint.h>
55*7e75ca54SJens Wiklander #include <stdbool.h>
56*7e75ca54SJens Wiklander 
57*7e75ca54SJens Wiklander /*
58*7e75ca54SJens Wiklander  * struct ftmn_check - track current checked state
59*7e75ca54SJens Wiklander  * @steps:	accumulated checkpoints
60*7e75ca54SJens Wiklander  * @res:	last stored result or return value
61*7e75ca54SJens Wiklander  *
62*7e75ca54SJens Wiklander  * While a function is executed it can update its state as a way of keeping
63*7e75ca54SJens Wiklander  * track of important passages inside the function. When the function
64*7e75ca54SJens Wiklander  * returns with for instance ftmn_return_res() it is checked that the
65*7e75ca54SJens Wiklander  * accumulated state matches the expected state.
66*7e75ca54SJens Wiklander  *
67*7e75ca54SJens Wiklander  * @res is xored with FTMN_DEFAULT_HASH in order to retrieve the saved
68*7e75ca54SJens Wiklander  * result or return value.
69*7e75ca54SJens Wiklander  */
70*7e75ca54SJens Wiklander struct ftmn_check {
71*7e75ca54SJens Wiklander 	unsigned long steps;
72*7e75ca54SJens Wiklander 	unsigned long res;
73*7e75ca54SJens Wiklander };
74*7e75ca54SJens Wiklander 
75*7e75ca54SJens Wiklander /*
76*7e75ca54SJens Wiklander  * struct ftmn_func_arg - track a called function
77*7e75ca54SJens Wiklander  * @hash:	xor bitmask
78*7e75ca54SJens Wiklander  * @res:	stored result xored with @hash
79*7e75ca54SJens Wiklander  *
80*7e75ca54SJens Wiklander  * When the call of a function is tracked @hash is initialized to hash of
81*7e75ca54SJens Wiklander  * caller xored with hash of called function. Before the called function
82*7e75ca54SJens Wiklander  * updates @res it first xors @hash with its own hash, which is supposed to
83*7e75ca54SJens Wiklander  * restore @hash to the hash of the calling function. This allows the
84*7e75ca54SJens Wiklander  * calling function to confirm that the correct function has been called.
85*7e75ca54SJens Wiklander  */
86*7e75ca54SJens Wiklander struct ftmn_func_arg {
87*7e75ca54SJens Wiklander 	unsigned long hash;
88*7e75ca54SJens Wiklander 	unsigned long res;
89*7e75ca54SJens Wiklander };
90*7e75ca54SJens Wiklander 
91*7e75ca54SJens Wiklander /*
92*7e75ca54SJens Wiklander  * struct ftmn - link a tracked call chain
93*7e75ca54SJens Wiklander  * @check:	local checked state
94*7e75ca54SJens Wiklander  * @arg:	argument for the next called tracked function
95*7e75ca54SJens Wiklander  * @saved_arg:	pointer to an optional argument passed to this function
96*7e75ca54SJens Wiklander  * @arg_pp:	cached return value from __ftmn_get_tsd_func_arg_pp()
97*7e75ca54SJens Wiklander  * @my_hash:	the hash of the calling function
98*7e75ca54SJens Wiklander  * @called_hash:the hash of the called function
99*7e75ca54SJens Wiklander  *
100*7e75ca54SJens Wiklander  * In order to maintain the linked call chain of tracked functions the
101*7e75ca54SJens Wiklander  * struct ftmn_func_arg passed to this function is saved in @saved_arg
102*7e75ca54SJens Wiklander  * before updating the argument pointer with @arg.
103*7e75ca54SJens Wiklander  */
104*7e75ca54SJens Wiklander struct ftmn {
105*7e75ca54SJens Wiklander 	struct ftmn_check check;
106*7e75ca54SJens Wiklander 	struct ftmn_func_arg arg;
107*7e75ca54SJens Wiklander 	struct ftmn_func_arg *saved_arg;
108*7e75ca54SJens Wiklander 	struct ftmn_func_arg **arg_pp;
109*7e75ca54SJens Wiklander 	unsigned long my_hash;
110*7e75ca54SJens Wiklander 	unsigned long called_hash;
111*7e75ca54SJens Wiklander };
112*7e75ca54SJens Wiklander 
113*7e75ca54SJens Wiklander /*
114*7e75ca54SJens Wiklander  * enum ftmn_incr - increase counter values
115*7e75ca54SJens Wiklander  *
116*7e75ca54SJens Wiklander  * Prime numbers to be used when increasing the accumulated state.
117*7e75ca54SJens Wiklander  * Different increase counters can be used to keep apart different
118*7e75ca54SJens Wiklander  * checkpoints.
119*7e75ca54SJens Wiklander  */
120*7e75ca54SJens Wiklander enum ftmn_incr {
121*7e75ca54SJens Wiklander 	FTMN_INCR0 = 7873,
122*7e75ca54SJens Wiklander 	FTMN_INCR1 = 7877,
123*7e75ca54SJens Wiklander 	FTMN_INCR2 = 7879,
124*7e75ca54SJens Wiklander 	FTMN_INCR3 = 7883,
125*7e75ca54SJens Wiklander 	FTMN_INCR4 = 7901,
126*7e75ca54SJens Wiklander 	FTMN_INCR5 = 7907,
127*7e75ca54SJens Wiklander 	FTMN_INCR_RESERVED = 7919,
128*7e75ca54SJens Wiklander };
129*7e75ca54SJens Wiklander 
130*7e75ca54SJens Wiklander typedef int (*ftmn_memcmp_t)(const void *p1, const void *p2, size_t nb);
131*7e75ca54SJens Wiklander 
132*7e75ca54SJens Wiklander /* The default hash used when xoring the result in struct ftmn_check */
133*7e75ca54SJens Wiklander #ifdef __ILP32__
134*7e75ca54SJens Wiklander #define FTMN_DEFAULT_HASH	0x9c478bf6UL
135*7e75ca54SJens Wiklander #else
136*7e75ca54SJens Wiklander #define FTMN_DEFAULT_HASH	0xc478bf63e9500cb5UL
137*7e75ca54SJens Wiklander #endif
138*7e75ca54SJens Wiklander 
139*7e75ca54SJens Wiklander /*
140*7e75ca54SJens Wiklander  * FTMN_PANIC() - FTMN specific panic function
141*7e75ca54SJens Wiklander  *
142*7e75ca54SJens Wiklander  * This function is called whenever the FTMN function detects an
143*7e75ca54SJens Wiklander  * inconsistency. An inconsistency is able to occur if the system is
144*7e75ca54SJens Wiklander  * subject to a fault injection attack, in this case doing a panic() isn't
145*7e75ca54SJens Wiklander  * an extreme measure.
146*7e75ca54SJens Wiklander  */
147*7e75ca54SJens Wiklander #ifdef __KERNEL__
148*7e75ca54SJens Wiklander #define FTMN_PANIC()	panic();
149*7e75ca54SJens Wiklander #else
150*7e75ca54SJens Wiklander #define FTMN_PANIC()	TEE_Panic(0);
151*7e75ca54SJens Wiklander #endif
152*7e75ca54SJens Wiklander 
153*7e75ca54SJens Wiklander #define __FTMN_MAX_FUNC_NAME_LEN	256
154*7e75ca54SJens Wiklander 
155*7e75ca54SJens Wiklander #define __FTMN_FUNC_BYTE(f, o, l)	((o) < (l) ? (uint8_t)(f)[(o)] : 0)
156*7e75ca54SJens Wiklander 
157*7e75ca54SJens Wiklander #define __FTMN_GET_FUNC_U64(f, o, l) \
158*7e75ca54SJens Wiklander 	(SHIFT_U64(__FTMN_FUNC_BYTE((f), (o), (l)), 0) | \
159*7e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 1, (l)), 8) | \
160*7e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 2, (l)), 16) | \
161*7e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 3, (l)), 24) | \
162*7e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 4, (l)), 32) | \
163*7e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 5, (l)), 40) | \
164*7e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 6, (l)), 48) | \
165*7e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 7, (l)), 56))
166*7e75ca54SJens Wiklander 
167*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH32(f, o, l) \
168*7e75ca54SJens Wiklander 	(__FTMN_GET_FUNC_U64((f), (o), (l)) ^ \
169*7e75ca54SJens Wiklander 	 __FTMN_GET_FUNC_U64((f), (o) + 8, (l)))
170*7e75ca54SJens Wiklander 
171*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH16(f, o, l) \
172*7e75ca54SJens Wiklander 	(__FTMN_FUNC_HASH32((f), (o), (l)) ^ \
173*7e75ca54SJens Wiklander 	 __FTMN_FUNC_HASH32((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 16, (l)))
174*7e75ca54SJens Wiklander 
175*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH8(f, o, l) \
176*7e75ca54SJens Wiklander 	(__FTMN_FUNC_HASH16((f), (o), (l)) ^ \
177*7e75ca54SJens Wiklander 	 __FTMN_FUNC_HASH16((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 8, (l)))
178*7e75ca54SJens Wiklander 
179*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH4(f, o, l) \
180*7e75ca54SJens Wiklander 	(__FTMN_FUNC_HASH8((f), (o), (l)) ^ \
181*7e75ca54SJens Wiklander 	 __FTMN_FUNC_HASH8((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 4, (l)))
182*7e75ca54SJens Wiklander 
183*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH2(f, l) \
184*7e75ca54SJens Wiklander 	(__FTMN_FUNC_HASH4(f, 0, l) ^ \
185*7e75ca54SJens Wiklander 	 __FTMN_FUNC_HASH4(f, __FTMN_MAX_FUNC_NAME_LEN / 2, l))
186*7e75ca54SJens Wiklander 
187*7e75ca54SJens Wiklander #ifdef __ILP32__
188*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH(f, l) \
189*7e75ca54SJens Wiklander 	(unsigned long)(__FTMN_FUNC_HASH2((f), (l)) ^ \
190*7e75ca54SJens Wiklander 		        (__FTMN_FUNC_HASH2((f), (l)) >> 32))
191*7e75ca54SJens Wiklander #else
192*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH(f, l)	(unsigned long)__FTMN_FUNC_HASH2((f), (l))
193*7e75ca54SJens Wiklander #endif
194*7e75ca54SJens Wiklander 
195*7e75ca54SJens Wiklander #define __ftmn_step_count_1(c0) ((c0) * FTMN_INCR0)
196*7e75ca54SJens Wiklander #define __ftmn_step_count_2(c0, c1) \
197*7e75ca54SJens Wiklander 	(__ftmn_step_count_1(c0) + (c1) * FTMN_INCR1)
198*7e75ca54SJens Wiklander #define __ftmn_step_count_3(c0, c1, c2) \
199*7e75ca54SJens Wiklander 	(__ftmn_step_count_2(c0, c1) + (c2) * FTMN_INCR2)
200*7e75ca54SJens Wiklander #define __ftmn_step_count_4(c0, c1, c2, c3)	\
201*7e75ca54SJens Wiklander 	(__ftmn_step_count_3(c0, c1, c2) + (c3) * FTMN_INCR3)
202*7e75ca54SJens Wiklander #define __ftmn_step_count_5(c0, c1, c2, c3, c4)	\
203*7e75ca54SJens Wiklander 	(__ftmn_step_count_4(c0, c1, c2, c3) + (c4) * FTMN_INCR4)
204*7e75ca54SJens Wiklander #define __ftmn_step_count_6(c0, c1, c2, c3, c4, c5)	\
205*7e75ca54SJens Wiklander 	(__ftmn_step_count_5(c0, c1, c2, c3, c4) + (c5) * FTMN_INCR5)
206*7e75ca54SJens Wiklander #define ___ftmn_args_count(_0, _1, _2, _3, _4, _5, x, ...) x
207*7e75ca54SJens Wiklander #define __ftmn_args_count(...) \
208*7e75ca54SJens Wiklander 	___ftmn_args_count(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
209*7e75ca54SJens Wiklander #define ___ftmn_step_count(count, ...)	__ftmn_step_count_ ## count(__VA_ARGS__)
210*7e75ca54SJens Wiklander #define __ftmn_step_count(count, ...)	___ftmn_step_count(count, __VA_ARGS__)
211*7e75ca54SJens Wiklander 
212*7e75ca54SJens Wiklander unsigned long ___ftmn_return_res(struct ftmn_check *check, unsigned long steps,
213*7e75ca54SJens Wiklander 				 unsigned long res);
214*7e75ca54SJens Wiklander void ___ftmn_expect_state(struct ftmn_check *check, enum ftmn_incr incr,
215*7e75ca54SJens Wiklander 			  unsigned long steps, unsigned long res);
216*7e75ca54SJens Wiklander 
217*7e75ca54SJens Wiklander void ___ftmn_callee_done(struct ftmn_func_arg *arg, unsigned long my_hash,
218*7e75ca54SJens Wiklander 			 unsigned long res);
219*7e75ca54SJens Wiklander void ___ftmn_callee_done_not_zero(struct ftmn_func_arg *arg,
220*7e75ca54SJens Wiklander 				  unsigned long my_hash,
221*7e75ca54SJens Wiklander 				  unsigned long res);
222*7e75ca54SJens Wiklander void ___ftmn_callee_done_memcmp(struct ftmn_func_arg *arg,
223*7e75ca54SJens Wiklander 				unsigned long my_hash, int res,
224*7e75ca54SJens Wiklander 				ftmn_memcmp_t my_memcmp,
225*7e75ca54SJens Wiklander 				const void *p1, const void *p2, size_t nb);
226*7e75ca54SJens Wiklander void ___ftmn_callee_done_check(struct ftmn_func_arg *arg, unsigned long my_hash,
227*7e75ca54SJens Wiklander 			       struct ftmn_check *check, enum ftmn_incr incr,
228*7e75ca54SJens Wiklander 			       unsigned long steps, unsigned long res);
229*7e75ca54SJens Wiklander 
230*7e75ca54SJens Wiklander void ___ftmn_callee_update_not_zero(struct ftmn_func_arg *arg,
231*7e75ca54SJens Wiklander 				    unsigned long res);
232*7e75ca54SJens Wiklander 
233*7e75ca54SJens Wiklander void ___ftmn_set_check_res(struct ftmn_check *check, enum ftmn_incr incr,
234*7e75ca54SJens Wiklander 			   unsigned long res);
235*7e75ca54SJens Wiklander void ___ftmn_set_check_res_not_zero(struct ftmn_check *check,
236*7e75ca54SJens Wiklander 				    enum ftmn_incr incr,
237*7e75ca54SJens Wiklander 				    unsigned long res);
238*7e75ca54SJens Wiklander void ___ftmn_set_check_res_memcmp(struct ftmn_check *check, enum ftmn_incr incr,
239*7e75ca54SJens Wiklander 				  int res, ftmn_memcmp_t my_memcmp,
240*7e75ca54SJens Wiklander 				  const void *p1, const void *p2, size_t nb);
241*7e75ca54SJens Wiklander 
242*7e75ca54SJens Wiklander void ___ftmn_copy_linked_call_res(struct ftmn_check *check, enum ftmn_incr incr,
243*7e75ca54SJens Wiklander 				  struct ftmn_func_arg *arg, unsigned long res);
244*7e75ca54SJens Wiklander 
245*7e75ca54SJens Wiklander 
246*7e75ca54SJens Wiklander #ifndef __KERNEL__
247*7e75ca54SJens Wiklander extern struct ftmn_func_arg *__ftmn_global_func_arg;
248*7e75ca54SJens Wiklander #endif
249*7e75ca54SJens Wiklander 
250*7e75ca54SJens Wiklander static inline struct ftmn_func_arg **__ftmn_get_tsd_func_arg_pp(void)
251*7e75ca54SJens Wiklander {
252*7e75ca54SJens Wiklander #if defined(CFG_FAULT_MITIGATION) && defined(__KERNEL__)
253*7e75ca54SJens Wiklander 	return &thread_get_tsd()->ftmn_arg;
254*7e75ca54SJens Wiklander #elif defined(CFG_FAULT_MITIGATION)
255*7e75ca54SJens Wiklander 	return &__ftmn_global_func_arg;
256*7e75ca54SJens Wiklander #else
257*7e75ca54SJens Wiklander 	return NULL;
258*7e75ca54SJens Wiklander #endif
259*7e75ca54SJens Wiklander }
260*7e75ca54SJens Wiklander 
261*7e75ca54SJens Wiklander static inline struct ftmn_func_arg *__ftmn_get_tsd_func_arg(void)
262*7e75ca54SJens Wiklander {
263*7e75ca54SJens Wiklander 	struct ftmn_func_arg **pp = __ftmn_get_tsd_func_arg_pp();
264*7e75ca54SJens Wiklander 
265*7e75ca54SJens Wiklander 	if (!pp)
266*7e75ca54SJens Wiklander 		return NULL;
267*7e75ca54SJens Wiklander 
268*7e75ca54SJens Wiklander 	return *pp;
269*7e75ca54SJens Wiklander }
270*7e75ca54SJens Wiklander 
271*7e75ca54SJens Wiklander static inline void __ftmn_push_linked_call(struct ftmn *ftmn,
272*7e75ca54SJens Wiklander 					 unsigned long my_hash,
273*7e75ca54SJens Wiklander 					 unsigned long called_hash)
274*7e75ca54SJens Wiklander {
275*7e75ca54SJens Wiklander 	struct ftmn_func_arg **arg_pp = __ftmn_get_tsd_func_arg_pp();
276*7e75ca54SJens Wiklander 
277*7e75ca54SJens Wiklander 	if (arg_pp) {
278*7e75ca54SJens Wiklander 		ftmn->arg_pp = arg_pp;
279*7e75ca54SJens Wiklander 		ftmn->my_hash = my_hash;
280*7e75ca54SJens Wiklander 		ftmn->called_hash = called_hash;
281*7e75ca54SJens Wiklander 		ftmn->saved_arg = *ftmn->arg_pp;
282*7e75ca54SJens Wiklander 		*ftmn->arg_pp = &ftmn->arg;
283*7e75ca54SJens Wiklander 		ftmn->arg.hash = my_hash;
284*7e75ca54SJens Wiklander 	}
285*7e75ca54SJens Wiklander }
286*7e75ca54SJens Wiklander 
287*7e75ca54SJens Wiklander static inline void __ftmn_pop_linked_call(struct ftmn *ftmn)
288*7e75ca54SJens Wiklander {
289*7e75ca54SJens Wiklander 	if (ftmn->arg_pp)
290*7e75ca54SJens Wiklander 		*ftmn->arg_pp = ftmn->saved_arg;
291*7e75ca54SJens Wiklander }
292*7e75ca54SJens Wiklander 
293*7e75ca54SJens Wiklander static inline void __ftmn_copy_linked_call_res(struct ftmn *f,
294*7e75ca54SJens Wiklander 					       enum ftmn_incr incr,
295*7e75ca54SJens Wiklander 					       unsigned long res)
296*7e75ca54SJens Wiklander {
297*7e75ca54SJens Wiklander 	if (f->arg_pp) {
298*7e75ca54SJens Wiklander 		assert(f->arg.hash == (f->my_hash ^ f->called_hash));
299*7e75ca54SJens Wiklander 		assert(&f->arg == *f->arg_pp);
300*7e75ca54SJens Wiklander 		assert((f->arg.hash ^ f->arg.res) == res);
301*7e75ca54SJens Wiklander 		___ftmn_copy_linked_call_res(&f->check, incr, &f->arg, res);
302*7e75ca54SJens Wiklander 	}
303*7e75ca54SJens Wiklander }
304*7e75ca54SJens Wiklander 
305*7e75ca54SJens Wiklander static inline void __ftmn_calle_swap_hash(struct ftmn_func_arg *arg,
306*7e75ca54SJens Wiklander 					  unsigned long my_old_hash,
307*7e75ca54SJens Wiklander 					  unsigned long my_new_hash)
308*7e75ca54SJens Wiklander {
309*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
310*7e75ca54SJens Wiklander 		arg->hash ^= my_old_hash ^ my_new_hash;
311*7e75ca54SJens Wiklander }
312*7e75ca54SJens Wiklander 
313*7e75ca54SJens Wiklander static inline void __ftmn_callee_done(struct ftmn_func_arg *arg,
314*7e75ca54SJens Wiklander 				      unsigned long my_hash, unsigned long res)
315*7e75ca54SJens Wiklander {
316*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
317*7e75ca54SJens Wiklander 		___ftmn_callee_done(arg, my_hash, res);
318*7e75ca54SJens Wiklander }
319*7e75ca54SJens Wiklander 
320*7e75ca54SJens Wiklander static inline void __ftmn_callee_done_not_zero(struct ftmn_func_arg *arg,
321*7e75ca54SJens Wiklander 					       unsigned long hash,
322*7e75ca54SJens Wiklander 					       unsigned long res)
323*7e75ca54SJens Wiklander {
324*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
325*7e75ca54SJens Wiklander 		___ftmn_callee_done_not_zero(arg, hash, res);
326*7e75ca54SJens Wiklander }
327*7e75ca54SJens Wiklander 
328*7e75ca54SJens Wiklander static inline int
329*7e75ca54SJens Wiklander __ftmn_callee_done_memcmp(struct ftmn_func_arg *arg, unsigned long hash,
330*7e75ca54SJens Wiklander 			  ftmn_memcmp_t my_memcmp,
331*7e75ca54SJens Wiklander 			  const void *p1, const void *p2, size_t nb)
332*7e75ca54SJens Wiklander {
333*7e75ca54SJens Wiklander 	int res = my_memcmp(p1, p2, nb);
334*7e75ca54SJens Wiklander 
335*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
336*7e75ca54SJens Wiklander 		___ftmn_callee_done_memcmp(arg, hash, res, my_memcmp,
337*7e75ca54SJens Wiklander 					   p1, p2, nb);
338*7e75ca54SJens Wiklander 
339*7e75ca54SJens Wiklander 	return res;
340*7e75ca54SJens Wiklander }
341*7e75ca54SJens Wiklander 
342*7e75ca54SJens Wiklander static inline void __ftmn_callee_done_check(struct ftmn *ftmn,
343*7e75ca54SJens Wiklander 					    unsigned long my_hash,
344*7e75ca54SJens Wiklander 					    enum ftmn_incr incr,
345*7e75ca54SJens Wiklander 					    unsigned long steps,
346*7e75ca54SJens Wiklander 					    unsigned long res)
347*7e75ca54SJens Wiklander {
348*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION))
349*7e75ca54SJens Wiklander 		___ftmn_callee_done_check(__ftmn_get_tsd_func_arg(), my_hash,
350*7e75ca54SJens Wiklander 					  &ftmn->check, incr, steps, res);
351*7e75ca54SJens Wiklander }
352*7e75ca54SJens Wiklander 
353*7e75ca54SJens Wiklander static inline void __ftmn_callee_update_not_zero(struct ftmn_func_arg *arg,
354*7e75ca54SJens Wiklander 						 unsigned long res)
355*7e75ca54SJens Wiklander {
356*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
357*7e75ca54SJens Wiklander 		___ftmn_callee_update_not_zero(arg, res);
358*7e75ca54SJens Wiklander }
359*7e75ca54SJens Wiklander 
360*7e75ca54SJens Wiklander static inline void __ftmn_set_check_res(struct ftmn *ftmn, enum ftmn_incr incr,
361*7e75ca54SJens Wiklander 				      unsigned long res)
362*7e75ca54SJens Wiklander {
363*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION))
364*7e75ca54SJens Wiklander 		___ftmn_set_check_res(&ftmn->check, incr, res);
365*7e75ca54SJens Wiklander }
366*7e75ca54SJens Wiklander 
367*7e75ca54SJens Wiklander static inline void __ftmn_set_check_res_not_zero(struct ftmn *ftmn,
368*7e75ca54SJens Wiklander 					       enum ftmn_incr incr,
369*7e75ca54SJens Wiklander 					       unsigned long res)
370*7e75ca54SJens Wiklander {
371*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION))
372*7e75ca54SJens Wiklander 		___ftmn_set_check_res_not_zero(&ftmn->check, incr, res);
373*7e75ca54SJens Wiklander }
374*7e75ca54SJens Wiklander 
375*7e75ca54SJens Wiklander 
376*7e75ca54SJens Wiklander 
377*7e75ca54SJens Wiklander /*
378*7e75ca54SJens Wiklander  * FTMN_FUNC_HASH() - "hash" a function name
379*7e75ca54SJens Wiklander  *
380*7e75ca54SJens Wiklander  * Function names are "hashed" into an unsigned long. The "hashing" is done
381*7e75ca54SJens Wiklander  * by xoring each 32/64 bit word of the function name producing a bit
382*7e75ca54SJens Wiklander  * pattern that should be mostly unique for each function. Only the first
383*7e75ca54SJens Wiklander  * 256 characters of the name are used when xoring as this is expected to
384*7e75ca54SJens Wiklander  * be optimized to be calculated when compiling the source code in order to
385*7e75ca54SJens Wiklander  * minimize the overhead.
386*7e75ca54SJens Wiklander  */
387*7e75ca54SJens Wiklander #define FTMN_FUNC_HASH(name)	__FTMN_FUNC_HASH(name, sizeof(name))
388*7e75ca54SJens Wiklander 
389*7e75ca54SJens Wiklander /*
390*7e75ca54SJens Wiklander  * FTMN_PUSH_LINKED_CALL() - push call into a linked call chain
391*7e75ca54SJens Wiklander  * @ftmn:		The local struct ftmn
392*7e75ca54SJens Wiklander  * @called_func_hash:	The hash of the called function
393*7e75ca54SJens Wiklander  *
394*7e75ca54SJens Wiklander  * Inserts a call into a linked call chain or starts a new call chain if
395*7e75ca54SJens Wiklander  * the passed struct ftmn_func_arg pointer was NULL.
396*7e75ca54SJens Wiklander  *
397*7e75ca54SJens Wiklander  * Each FTMN_PUSH_LINKED_CALL() is supposed to be matched by a
398*7e75ca54SJens Wiklander  * FTMN_POP_LINKED_CALL().
399*7e75ca54SJens Wiklander  */
400*7e75ca54SJens Wiklander #define FTMN_PUSH_LINKED_CALL(ftmn, called_func_hash) \
401*7e75ca54SJens Wiklander 	__ftmn_push_linked_call((ftmn), FTMN_FUNC_HASH(__func__), \
402*7e75ca54SJens Wiklander 				(called_func_hash))
403*7e75ca54SJens Wiklander 
404*7e75ca54SJens Wiklander /*
405*7e75ca54SJens Wiklander  * FTMN_SET_CHECK_RES_FROM_CALL() - copy the result from a linked call
406*7e75ca54SJens Wiklander  * @ftmn:	The struct ftmn used during the linked call
407*7e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
408*7e75ca54SJens Wiklander  * @res:	Returned result to be match against the saved/copied result
409*7e75ca54SJens Wiklander  *
410*7e75ca54SJens Wiklander  * This macro is called just after a checked linked function has returned.
411*7e75ca54SJens Wiklander  * The return value from the function is copied from the struct ftmn_func_arg
412*7e75ca54SJens Wiklander  * passed to the called function into the local checked state. The checked
413*7e75ca54SJens Wiklander  * state is increased with @incr. @res is checked against the saved result
414*7e75ca54SJens Wiklander  * of the called function.
415*7e75ca54SJens Wiklander  */
416*7e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES_FROM_CALL(ftmn, incr, res) \
417*7e75ca54SJens Wiklander 	__ftmn_copy_linked_call_res((ftmn), (incr), (res))
418*7e75ca54SJens Wiklander 
419*7e75ca54SJens Wiklander /*
420*7e75ca54SJens Wiklander  * FTMN_POP_LINKED_CALL() - remove a call from a linked call chain
421*7e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
422*7e75ca54SJens Wiklander  *
423*7e75ca54SJens Wiklander  * Supposed to match a call to FTMN_PUSH_LINKED_CALL()
424*7e75ca54SJens Wiklander  */
425*7e75ca54SJens Wiklander #define FTMN_POP_LINKED_CALL(ftmn) __ftmn_pop_linked_call((ftmn))
426*7e75ca54SJens Wiklander 
427*7e75ca54SJens Wiklander /*
428*7e75ca54SJens Wiklander  * FTMN_CALL_FUNC() - Do a linked call to a function
429*7e75ca54SJens Wiklander  * @res:	Variable to be assigned the result of the called function
430*7e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
431*7e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
432*7e75ca54SJens Wiklander  * @func:	Function to be called
433*7e75ca54SJens Wiklander  * @...:	Arguments to pass to @func
434*7e75ca54SJens Wiklander  *
435*7e75ca54SJens Wiklander  * This macro can be used to make a linked call to another function, the
436*7e75ca54SJens Wiklander  * callee. This macro depends on the callee to always update the struct
437*7e75ca54SJens Wiklander  * ftmn_func_arg (part of struct ftmn) even when returning an error.
438*7e75ca54SJens Wiklander  *
439*7e75ca54SJens Wiklander  * Note that in the cases where the callee may skip updating the struct
440*7e75ca54SJens Wiklander  * ftmn_func_arg this macro cannot be used as
441*7e75ca54SJens Wiklander  * FTMN_SET_CHECK_RES_FROM_CALL() would cause a panic due to mismatching
442*7e75ca54SJens Wiklander  * return value and saved result.
443*7e75ca54SJens Wiklander  */
444*7e75ca54SJens Wiklander #define FTMN_CALL_FUNC(res, ftmn, incr, func, ...) \
445*7e75ca54SJens Wiklander 	do { \
446*7e75ca54SJens Wiklander 		FTMN_PUSH_LINKED_CALL((ftmn), FTMN_FUNC_HASH(#func)); \
447*7e75ca54SJens Wiklander 		(res) = func(__VA_ARGS__); \
448*7e75ca54SJens Wiklander 		FTMN_SET_CHECK_RES_FROM_CALL((ftmn), (incr), (res)); \
449*7e75ca54SJens Wiklander 		FTMN_POP_LINKED_CALL((ftmn)); \
450*7e75ca54SJens Wiklander 	} while (0)
451*7e75ca54SJens Wiklander 
452*7e75ca54SJens Wiklander /*
453*7e75ca54SJens Wiklander  * FTMN_CALLEE_DONE() - Record result of callee
454*7e75ca54SJens Wiklander  * @res:	Result or return value
455*7e75ca54SJens Wiklander  *
456*7e75ca54SJens Wiklander  * The passed result will be stored in the struct ftmn_func_arg struct
457*7e75ca54SJens Wiklander  * supplied by the caller. This function must only be called once by the
458*7e75ca54SJens Wiklander  * callee.
459*7e75ca54SJens Wiklander  *
460*7e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
461*7e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
462*7e75ca54SJens Wiklander  * redundant checks to rely on.
463*7e75ca54SJens Wiklander  */
464*7e75ca54SJens Wiklander #define FTMN_CALLEE_DONE(res) \
465*7e75ca54SJens Wiklander 	__ftmn_callee_done(__ftmn_get_tsd_func_arg(), \
466*7e75ca54SJens Wiklander 			   FTMN_FUNC_HASH(__func__), (res))
467*7e75ca54SJens Wiklander /*
468*7e75ca54SJens Wiklander  * FTMN_CALLEE_DONE_NOT_ZERO() - Record non-zero result of callee
469*7e75ca54SJens Wiklander  * @res:	Result or return value
470*7e75ca54SJens Wiklander  *
471*7e75ca54SJens Wiklander  * The passed result will be stored in the struct ftmn_func_arg struct
472*7e75ca54SJens Wiklander  * supplied by the caller. This function must only be called once by the
473*7e75ca54SJens Wiklander  * callee.
474*7e75ca54SJens Wiklander  *
475*7e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
476*7e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
477*7e75ca54SJens Wiklander  * redundant checks to rely on. However, there are extra checks against
478*7e75ca54SJens Wiklander  * unintentionally storing a zero which often is interpreted as a
479*7e75ca54SJens Wiklander  * successful return value.
480*7e75ca54SJens Wiklander  */
481*7e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_NOT_ZERO(res) \
482*7e75ca54SJens Wiklander 	__ftmn_callee_done_not_zero(__ftmn_get_tsd_func_arg(), \
483*7e75ca54SJens Wiklander 				    FTMN_FUNC_HASH(__func__), (res))
484*7e75ca54SJens Wiklander 
485*7e75ca54SJens Wiklander /*
486*7e75ca54SJens Wiklander  * FTMN_CALLEE_DONE_CHECK() - Record result of callee with checked state
487*7e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
488*7e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
489*7e75ca54SJens Wiklander  * @exp_steps:	Expected recorded checkpoints
490*7e75ca54SJens Wiklander  * @res:	Result or return value
491*7e75ca54SJens Wiklander  *
492*7e75ca54SJens Wiklander  * The passed result will be stored in the struct ftmn_func_arg struct
493*7e75ca54SJens Wiklander  * supplied by the caller. This function must only be called once by the
494*7e75ca54SJens Wiklander  * callee.
495*7e75ca54SJens Wiklander  *
496*7e75ca54SJens Wiklander  * @res is double checked against the value stored in local checked state.
497*7e75ca54SJens Wiklander  * @exp_steps is checked against the locate checked state. The local
498*7e75ca54SJens Wiklander  * checked state is increased by @incr.
499*7e75ca54SJens Wiklander  */
500*7e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_CHECK(ftmn, incr, exp_steps, res) \
501*7e75ca54SJens Wiklander 	__ftmn_callee_done_check((ftmn), FTMN_FUNC_HASH(__func__), \
502*7e75ca54SJens Wiklander 				 (incr), (exp_steps), (res))
503*7e75ca54SJens Wiklander 
504*7e75ca54SJens Wiklander /*
505*7e75ca54SJens Wiklander  * FTMN_CALLEE_DONE_MEMCMP() - Record result of memcmp() in a callee
506*7e75ca54SJens Wiklander  * @my_memcmp:		Function pointer of custom memcmp()
507*7e75ca54SJens Wiklander  * @p1:			Pointer to first buffer
508*7e75ca54SJens Wiklander  * @p2:			Pointer to second buffer
509*7e75ca54SJens Wiklander  * @nb:			Number of bytes
510*7e75ca54SJens Wiklander  *
511*7e75ca54SJens Wiklander  * The result from the mem compare is saved in the local checked state.
512*7e75ca54SJens Wiklander  * This function must only be called once by the callee.
513*7e75ca54SJens Wiklander  */
514*7e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_MEMCMP(my_memcmp, p1, p2, nb) \
515*7e75ca54SJens Wiklander 	__ftmn_callee_done_memcmp(__ftmn_get_tsd_func_arg(), \
516*7e75ca54SJens Wiklander 				  FTMN_FUNC_HASH(__func__), (my_memcmp), \
517*7e75ca54SJens Wiklander 				  (p1), (p2), (nb))
518*7e75ca54SJens Wiklander 
519*7e75ca54SJens Wiklander /*
520*7e75ca54SJens Wiklander  * FTMN_CALLEE_UPDATE_NOT_ZERO() - Update the result of a callee with a
521*7e75ca54SJens Wiklander  *				   non-zero value
522*7e75ca54SJens Wiklander  * @res:	Result or return value
523*7e75ca54SJens Wiklander  *
524*7e75ca54SJens Wiklander  * The passed result will be stored in the struct ftmn_func_arg struct
525*7e75ca54SJens Wiklander  * supplied by the caller. This function can be called any number of times
526*7e75ca54SJens Wiklander  * by the callee, provided that one of the FTMN_CALLEE_DONE_XXX() functions
527*7e75ca54SJens Wiklander  * has been called first.
528*7e75ca54SJens Wiklander  *
529*7e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
530*7e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
531*7e75ca54SJens Wiklander  * redundant checks to rely on. However, there are extra checks against
532*7e75ca54SJens Wiklander  * unintentionally storing a zero which often is interpreted as a
533*7e75ca54SJens Wiklander  * successful return value.
534*7e75ca54SJens Wiklander  */
535*7e75ca54SJens Wiklander #define FTMN_CALLEE_UPDATE_NOT_ZERO(res) \
536*7e75ca54SJens Wiklander 	__ftmn_callee_update_not_zero(__ftmn_get_tsd_func_arg(), res)
537*7e75ca54SJens Wiklander 
538*7e75ca54SJens Wiklander /*
539*7e75ca54SJens Wiklander  * FTMN_CALLEE_SWAP_HASH() - Remove old hash and add new hash
540*7e75ca54SJens Wiklander  * @my_old_hash:	The old hash to remove
541*7e75ca54SJens Wiklander  *
542*7e75ca54SJens Wiklander  * This macro replaces the old expected function hash with the hash of the
543*7e75ca54SJens Wiklander  * current function.
544*7e75ca54SJens Wiklander  *
545*7e75ca54SJens Wiklander  * If a function is called using an alias the caller uses the hash of the
546*7e75ca54SJens Wiklander  * alias not the real function name. This hash is recoded in the field
547*7e75ca54SJens Wiklander  * "hash" in struct ftmn_func_arg which can be found with
548*7e75ca54SJens Wiklander  * __ftmn_get_tsd_func_arg().
549*7e75ca54SJens Wiklander  *
550*7e75ca54SJens Wiklander  * The FTMN_CALLE_* functions only work with the real function name so the
551*7e75ca54SJens Wiklander  * old hash must be removed and replaced with the new for the calling
552*7e75ca54SJens Wiklander  * function to be able to verify the result.
553*7e75ca54SJens Wiklander  */
554*7e75ca54SJens Wiklander #define FTMN_CALLEE_SWAP_HASH(my_old_hash) \
555*7e75ca54SJens Wiklander 	__ftmn_calle_swap_hash(__ftmn_get_tsd_func_arg(), \
556*7e75ca54SJens Wiklander 			       (my_old_hash), FTMN_FUNC_HASH(__func__))
557*7e75ca54SJens Wiklander 
558*7e75ca54SJens Wiklander /*
559*7e75ca54SJens Wiklander  * FTMN_SET_CHECK_RES() - Records a result in local checked state
560*7e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
561*7e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
562*7e75ca54SJens Wiklander  * @res:	Result or return value
563*7e75ca54SJens Wiklander  *
564*7e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
565*7e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
566*7e75ca54SJens Wiklander  * redundant checks to rely on.
567*7e75ca54SJens Wiklander  */
568*7e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES(ftmn, incr, res) \
569*7e75ca54SJens Wiklander 	__ftmn_set_check_res((ftmn), (incr), (res))
570*7e75ca54SJens Wiklander 
571*7e75ca54SJens Wiklander /*
572*7e75ca54SJens Wiklander  * FTMN_SET_CHECK_RES_NOT_ZERO() - Records a non-zero result in local checked
573*7e75ca54SJens Wiklander  *				   state
574*7e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
575*7e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
576*7e75ca54SJens Wiklander  * @res:	Result or return value
577*7e75ca54SJens Wiklander  *
578*7e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
579*7e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
580*7e75ca54SJens Wiklander  * redundant checks to rely on. However, there are extra checks against
581*7e75ca54SJens Wiklander  * unintentionally storing a zero which often is interpreted as a
582*7e75ca54SJens Wiklander  * successful return value.
583*7e75ca54SJens Wiklander  */
584*7e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES_NOT_ZERO(ftmn, incr, res) \
585*7e75ca54SJens Wiklander 	__ftmn_set_check_res_not_zero((ftmn), (incr), (res))
586*7e75ca54SJens Wiklander 
587*7e75ca54SJens Wiklander static inline int ftmn_set_check_res_memcmp(struct ftmn *ftmn,
588*7e75ca54SJens Wiklander 					    enum ftmn_incr incr,
589*7e75ca54SJens Wiklander 					    ftmn_memcmp_t my_memcmp,
590*7e75ca54SJens Wiklander 					    const void *p1, const void *p2,
591*7e75ca54SJens Wiklander 					    size_t nb)
592*7e75ca54SJens Wiklander {
593*7e75ca54SJens Wiklander 	int res = my_memcmp(p1, p2, nb);
594*7e75ca54SJens Wiklander 
595*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION))
596*7e75ca54SJens Wiklander 		___ftmn_set_check_res_memcmp(&ftmn->check, incr, res,
597*7e75ca54SJens Wiklander 					     my_memcmp, p1, p2, nb);
598*7e75ca54SJens Wiklander 
599*7e75ca54SJens Wiklander 	return res;
600*7e75ca54SJens Wiklander }
601*7e75ca54SJens Wiklander 
602*7e75ca54SJens Wiklander /*
603*7e75ca54SJens Wiklander  * FTMN_STEP_COUNT() - Calculate total step count
604*7e75ca54SJens Wiklander  *
605*7e75ca54SJens Wiklander  * Takes variable number of arguments, up to a total of 6. Where arg0
606*7e75ca54SJens Wiklander  * is the number of times the counter has been increased by FTMN_INCR0,
607*7e75ca54SJens Wiklander  * arg1 FTMN_INCR1 and so on.
608*7e75ca54SJens Wiklander  */
609*7e75ca54SJens Wiklander #define FTMN_STEP_COUNT(...)	\
610*7e75ca54SJens Wiklander 	__ftmn_step_count(__ftmn_args_count(__VA_ARGS__), __VA_ARGS__)
611*7e75ca54SJens Wiklander 
612*7e75ca54SJens Wiklander /*
613*7e75ca54SJens Wiklander  * ftmn_checkpoint() - Add a checkpoint
614*7e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
615*7e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
616*7e75ca54SJens Wiklander  *
617*7e75ca54SJens Wiklander  * Adds a checkpoint by increasing the internal checked state. This
618*7e75ca54SJens Wiklander  * can be checked at a later point in the calling function, for instance
619*7e75ca54SJens Wiklander  * with ftmn_return_res().
620*7e75ca54SJens Wiklander  */
621*7e75ca54SJens Wiklander static inline void ftmn_checkpoint(struct ftmn *ftmn, enum ftmn_incr incr)
622*7e75ca54SJens Wiklander {
623*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION)) {
624*7e75ca54SJens Wiklander 		/*
625*7e75ca54SJens Wiklander 		 * The purpose of the barriers is to prevent the compiler
626*7e75ca54SJens Wiklander 		 * from optimizing this increase to some other location
627*7e75ca54SJens Wiklander 		 * in the calling function.
628*7e75ca54SJens Wiklander 		 */
629*7e75ca54SJens Wiklander 		barrier();
630*7e75ca54SJens Wiklander 		ftmn->check.steps += incr;
631*7e75ca54SJens Wiklander 		barrier();
632*7e75ca54SJens Wiklander 	}
633*7e75ca54SJens Wiklander }
634*7e75ca54SJens Wiklander 
635*7e75ca54SJens Wiklander /*
636*7e75ca54SJens Wiklander  * ftmn_expect_state() - Check expected state
637*7e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
638*7e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
639*7e75ca54SJens Wiklander  * @steps:	Expected accumulated steps
640*7e75ca54SJens Wiklander  * @res:	Expected saved result or return value
641*7e75ca54SJens Wiklander  *
642*7e75ca54SJens Wiklander  * This is a more advanced version of ftmn_checkpoint() which before
643*7e75ca54SJens Wiklander  * increasing the accumulated steps first checks the accumulated steps and
644*7e75ca54SJens Wiklander  * saved result or return value.
645*7e75ca54SJens Wiklander  */
646*7e75ca54SJens Wiklander static inline void ftmn_expect_state(struct ftmn *ftmn,
647*7e75ca54SJens Wiklander 				     enum ftmn_incr incr, unsigned long steps,
648*7e75ca54SJens Wiklander 				     unsigned long res)
649*7e75ca54SJens Wiklander {
650*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION)) {
651*7e75ca54SJens Wiklander 		assert((ftmn->check.res ^ FTMN_DEFAULT_HASH) == res);
652*7e75ca54SJens Wiklander 		assert(ftmn->check.steps == steps);
653*7e75ca54SJens Wiklander 
654*7e75ca54SJens Wiklander 		___ftmn_expect_state(&ftmn->check, incr, steps, res);
655*7e75ca54SJens Wiklander 	}
656*7e75ca54SJens Wiklander }
657*7e75ca54SJens Wiklander 
658*7e75ca54SJens Wiklander /*
659*7e75ca54SJens Wiklander  * ftmn_return_res() - Check and return result
660*7e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
661*7e75ca54SJens Wiklander  * @steps:	Expected accumulated steps
662*7e75ca54SJens Wiklander  * @res:	Expected saved result or return value
663*7e75ca54SJens Wiklander  *
664*7e75ca54SJens Wiklander  * Checks that the internal accumulated state matches the supplied @steps
665*7e75ca54SJens Wiklander  * and that the saved result or return value matches the supplied one.
666*7e75ca54SJens Wiklander  *
667*7e75ca54SJens Wiklander  * Returns @res.
668*7e75ca54SJens Wiklander  */
669*7e75ca54SJens Wiklander static inline unsigned long ftmn_return_res(struct ftmn *ftmn,
670*7e75ca54SJens Wiklander 					    unsigned long steps,
671*7e75ca54SJens Wiklander 					    unsigned long res)
672*7e75ca54SJens Wiklander {
673*7e75ca54SJens Wiklander 	/*
674*7e75ca54SJens Wiklander 	 * We're expecting that the compiler does a tail call optimization
675*7e75ca54SJens Wiklander 	 * allowing ___ftmn_return_res() to have full control over the
676*7e75ca54SJens Wiklander 	 * returned value. Thus trying to reduce the window where the
677*7e75ca54SJens Wiklander 	 * return value can be tampered with.
678*7e75ca54SJens Wiklander 	 */
679*7e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION)) {
680*7e75ca54SJens Wiklander 		assert((ftmn->check.res ^ FTMN_DEFAULT_HASH) == res);
681*7e75ca54SJens Wiklander 		assert(ftmn->check.steps == steps);
682*7e75ca54SJens Wiklander 
683*7e75ca54SJens Wiklander 		return ___ftmn_return_res(&ftmn->check, steps, res);
684*7e75ca54SJens Wiklander 	}
685*7e75ca54SJens Wiklander 	return res;
686*7e75ca54SJens Wiklander }
687*7e75ca54SJens Wiklander #endif /*__FAULT_MITIGATION_H*/
688