xref: /optee_os/lib/libutils/ext/include/fault_mitigation.h (revision 5b6f4be856ca7364f9e92a0e34e3ebf4c64d779a)
17e75ca54SJens Wiklander /* SPDX-License-Identifier: BSD-2-Clause */
27e75ca54SJens Wiklander /*
37e75ca54SJens Wiklander  * Copyright (c) 2022, Linaro Limited
47e75ca54SJens Wiklander  */
57e75ca54SJens Wiklander #ifndef __FAULT_MITIGATION_H
67e75ca54SJens Wiklander #define __FAULT_MITIGATION_H
77e75ca54SJens Wiklander 
87e75ca54SJens Wiklander #include <assert.h>
97e75ca54SJens Wiklander #include <config.h>
107e75ca54SJens Wiklander #include <string.h>
117e75ca54SJens Wiklander #include <util.h>
127e75ca54SJens Wiklander 
137e75ca54SJens Wiklander #ifdef __KERNEL__
147e75ca54SJens Wiklander #include <kernel/panic.h>
157e75ca54SJens Wiklander #include <kernel/thread.h>
167e75ca54SJens Wiklander #else
177e75ca54SJens Wiklander #include <tee_api.h>
187e75ca54SJens Wiklander #endif
197e75ca54SJens Wiklander 
207e75ca54SJens Wiklander /*
217e75ca54SJens Wiklander  * Fault migitigation helpers to make successful Hardware Fault Attacks
227e75ca54SJens Wiklander  * harder to achieve. The paper [1] by Riscure gives background to the
237e75ca54SJens Wiklander  * problem.
247e75ca54SJens Wiklander  *
257e75ca54SJens Wiklander  * These helpers aim to make it hard for a single glitch attack to succeed
267e75ca54SJens Wiklander  * while the protected function or one of the ftmn_*() functions are
277e75ca54SJens Wiklander  * executed.
287e75ca54SJens Wiklander  *
297e75ca54SJens Wiklander  * To have something to work with we assume that a single glitch may affect
307e75ca54SJens Wiklander  * a few instructions in sequence to do nothing or to corrupt the content
317e75ca54SJens Wiklander  * of a few registers.
327e75ca54SJens Wiklander  *
337e75ca54SJens Wiklander  * Using the terminology from [1] we are implementing the following patterns:
347e75ca54SJens Wiklander  * 3 FAULT.VALUE.CHECK
357e75ca54SJens Wiklander  * 5 FAULT.DECISION.CHECK
367e75ca54SJens Wiklander  * 9 FAULT.FLOW.CONTROL
377e75ca54SJens Wiklander  *
387e75ca54SJens Wiklander  * Additionally are the following patterns also acknowledged with a few
397e75ca54SJens Wiklander  * comments:
407e75ca54SJens Wiklander  * 1. FAULT.CONSTANT.CODING
417e75ca54SJens Wiklander  *	Zero is normally a success code in OP-TEE so special functions are
427e75ca54SJens Wiklander  *	added to record anything but a zero result.
437e75ca54SJens Wiklander  * 8. FAULT.NESTED.CHECK
447e75ca54SJens Wiklander  *	The linked calls performed by for instance FTMN_CALL_FUNC() addresses
457e75ca54SJens Wiklander  *	this by relying on the called function to update a state in
467e75ca54SJens Wiklander  *	struct ftmn_func_arg which is checked when the function has returned.
477e75ca54SJens Wiklander  * 11. FAULT.PENALTY
487e75ca54SJens Wiklander  *	This is implicit since we're normally trying to protect things post
497e75ca54SJens Wiklander  *	boot and booting takes quite some time.
507e75ca54SJens Wiklander  *
517e75ca54SJens Wiklander  * [1] https://web.archive.org/web/20220616035354/https://www.riscure.com/uploads/2020/05/Riscure_Whitepaper_Fault_Mitigation_Patterns_final.pdf
527e75ca54SJens Wiklander  */
537e75ca54SJens Wiklander 
547e75ca54SJens Wiklander #include <stdint.h>
557e75ca54SJens Wiklander #include <stdbool.h>
567e75ca54SJens Wiklander 
577e75ca54SJens Wiklander /*
587e75ca54SJens Wiklander  * struct ftmn_check - track current checked state
597e75ca54SJens Wiklander  * @steps:	accumulated checkpoints
607e75ca54SJens Wiklander  * @res:	last stored result or return value
617e75ca54SJens Wiklander  *
627e75ca54SJens Wiklander  * While a function is executed it can update its state as a way of keeping
637e75ca54SJens Wiklander  * track of important passages inside the function. When the function
647e75ca54SJens Wiklander  * returns with for instance ftmn_return_res() it is checked that the
657e75ca54SJens Wiklander  * accumulated state matches the expected state.
667e75ca54SJens Wiklander  *
677e75ca54SJens Wiklander  * @res is xored with FTMN_DEFAULT_HASH in order to retrieve the saved
687e75ca54SJens Wiklander  * result or return value.
697e75ca54SJens Wiklander  */
707e75ca54SJens Wiklander struct ftmn_check {
717e75ca54SJens Wiklander 	unsigned long steps;
727e75ca54SJens Wiklander 	unsigned long res;
737e75ca54SJens Wiklander };
747e75ca54SJens Wiklander 
757e75ca54SJens Wiklander /*
767e75ca54SJens Wiklander  * struct ftmn_func_arg - track a called function
777e75ca54SJens Wiklander  * @hash:	xor bitmask
787e75ca54SJens Wiklander  * @res:	stored result xored with @hash
797e75ca54SJens Wiklander  *
807e75ca54SJens Wiklander  * When the call of a function is tracked @hash is initialized to hash of
817e75ca54SJens Wiklander  * caller xored with hash of called function. Before the called function
827e75ca54SJens Wiklander  * updates @res it first xors @hash with its own hash, which is supposed to
837e75ca54SJens Wiklander  * restore @hash to the hash of the calling function. This allows the
847e75ca54SJens Wiklander  * calling function to confirm that the correct function has been called.
857e75ca54SJens Wiklander  */
867e75ca54SJens Wiklander struct ftmn_func_arg {
877e75ca54SJens Wiklander 	unsigned long hash;
887e75ca54SJens Wiklander 	unsigned long res;
897e75ca54SJens Wiklander };
907e75ca54SJens Wiklander 
917e75ca54SJens Wiklander /*
927e75ca54SJens Wiklander  * struct ftmn - link a tracked call chain
937e75ca54SJens Wiklander  * @check:	local checked state
947e75ca54SJens Wiklander  * @arg:	argument for the next called tracked function
957e75ca54SJens Wiklander  * @saved_arg:	pointer to an optional argument passed to this function
967e75ca54SJens Wiklander  * @arg_pp:	cached return value from __ftmn_get_tsd_func_arg_pp()
977e75ca54SJens Wiklander  * @my_hash:	the hash of the calling function
987e75ca54SJens Wiklander  * @called_hash:the hash of the called function
997e75ca54SJens Wiklander  *
1007e75ca54SJens Wiklander  * In order to maintain the linked call chain of tracked functions the
1017e75ca54SJens Wiklander  * struct ftmn_func_arg passed to this function is saved in @saved_arg
1027e75ca54SJens Wiklander  * before updating the argument pointer with @arg.
1037e75ca54SJens Wiklander  */
1047e75ca54SJens Wiklander struct ftmn {
1057e75ca54SJens Wiklander 	struct ftmn_check check;
1067e75ca54SJens Wiklander 	struct ftmn_func_arg arg;
1077e75ca54SJens Wiklander 	struct ftmn_func_arg *saved_arg;
1087e75ca54SJens Wiklander 	struct ftmn_func_arg **arg_pp;
1097e75ca54SJens Wiklander 	unsigned long my_hash;
1107e75ca54SJens Wiklander 	unsigned long called_hash;
1117e75ca54SJens Wiklander };
1127e75ca54SJens Wiklander 
1137e75ca54SJens Wiklander /*
1147e75ca54SJens Wiklander  * enum ftmn_incr - increase counter values
1157e75ca54SJens Wiklander  *
1167e75ca54SJens Wiklander  * Prime numbers to be used when increasing the accumulated state.
1177e75ca54SJens Wiklander  * Different increase counters can be used to keep apart different
1187e75ca54SJens Wiklander  * checkpoints.
1197e75ca54SJens Wiklander  */
1207e75ca54SJens Wiklander enum ftmn_incr {
1217e75ca54SJens Wiklander 	FTMN_INCR0 = 7873,
1227e75ca54SJens Wiklander 	FTMN_INCR1 = 7877,
1237e75ca54SJens Wiklander 	FTMN_INCR2 = 7879,
1247e75ca54SJens Wiklander 	FTMN_INCR3 = 7883,
1257e75ca54SJens Wiklander 	FTMN_INCR4 = 7901,
1267e75ca54SJens Wiklander 	FTMN_INCR5 = 7907,
1277e75ca54SJens Wiklander 	FTMN_INCR_RESERVED = 7919,
1287e75ca54SJens Wiklander };
1297e75ca54SJens Wiklander 
1307e75ca54SJens Wiklander typedef int (*ftmn_memcmp_t)(const void *p1, const void *p2, size_t nb);
1317e75ca54SJens Wiklander 
1327e75ca54SJens Wiklander /* The default hash used when xoring the result in struct ftmn_check */
1337e75ca54SJens Wiklander #ifdef __ILP32__
1347e75ca54SJens Wiklander #define FTMN_DEFAULT_HASH	0x9c478bf6UL
1357e75ca54SJens Wiklander #else
1367e75ca54SJens Wiklander #define FTMN_DEFAULT_HASH	0xc478bf63e9500cb5UL
1377e75ca54SJens Wiklander #endif
1387e75ca54SJens Wiklander 
1397e75ca54SJens Wiklander /*
1407e75ca54SJens Wiklander  * FTMN_PANIC() - FTMN specific panic function
1417e75ca54SJens Wiklander  *
1427e75ca54SJens Wiklander  * This function is called whenever the FTMN function detects an
1437e75ca54SJens Wiklander  * inconsistency. An inconsistency is able to occur if the system is
1447e75ca54SJens Wiklander  * subject to a fault injection attack, in this case doing a panic() isn't
1457e75ca54SJens Wiklander  * an extreme measure.
1467e75ca54SJens Wiklander  */
1477e75ca54SJens Wiklander #ifdef __KERNEL__
1487e75ca54SJens Wiklander #define FTMN_PANIC()	panic();
1497e75ca54SJens Wiklander #else
1507e75ca54SJens Wiklander #define FTMN_PANIC()	TEE_Panic(0);
1517e75ca54SJens Wiklander #endif
1527e75ca54SJens Wiklander 
1537e75ca54SJens Wiklander #define __FTMN_MAX_FUNC_NAME_LEN	256
1547e75ca54SJens Wiklander 
1557e75ca54SJens Wiklander #define __FTMN_FUNC_BYTE(f, o, l)	((o) < (l) ? (uint8_t)(f)[(o)] : 0)
1567e75ca54SJens Wiklander 
157*5b6f4be8SJens Wiklander #ifdef __ILP32__
158*5b6f4be8SJens Wiklander #define __FTMN_GET_FUNC_U32(f, o, l) \
159*5b6f4be8SJens Wiklander 	(SHIFT_U32(__FTMN_FUNC_BYTE((f), (o), (l)), 0) | \
160*5b6f4be8SJens Wiklander 	 SHIFT_U32(__FTMN_FUNC_BYTE((f), (o) + 1, (l)), 8) | \
161*5b6f4be8SJens Wiklander 	 SHIFT_U32(__FTMN_FUNC_BYTE((f), (o) + 2, (l)), 16) | \
162*5b6f4be8SJens Wiklander 	 SHIFT_U32(__FTMN_FUNC_BYTE((f), (o) + 3, (l)), 24))
163*5b6f4be8SJens Wiklander 
164*5b6f4be8SJens Wiklander #define __FTMN_FUNC_HASH64(f, o, l) \
165*5b6f4be8SJens Wiklander 	(__FTMN_GET_FUNC_U32((f), (o), (l)) ^ \
166*5b6f4be8SJens Wiklander 	 __FTMN_GET_FUNC_U32((f), (o) + 4, (l)))
167*5b6f4be8SJens Wiklander 
168*5b6f4be8SJens Wiklander #define __FTMN_FUNC_HASH32(f, o, l) \
169*5b6f4be8SJens Wiklander 	(__FTMN_FUNC_HASH64((f), (o), (l)) ^ \
170*5b6f4be8SJens Wiklander 	 __FTMN_FUNC_HASH64((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 16, (l)))
171*5b6f4be8SJens Wiklander #else
1727e75ca54SJens Wiklander #define __FTMN_GET_FUNC_U64(f, o, l) \
1737e75ca54SJens Wiklander 	(SHIFT_U64(__FTMN_FUNC_BYTE((f), (o), (l)), 0) | \
1747e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 1, (l)), 8) | \
1757e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 2, (l)), 16) | \
1767e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 3, (l)), 24) | \
1777e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 4, (l)), 32) | \
1787e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 5, (l)), 40) | \
1797e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 6, (l)), 48) | \
1807e75ca54SJens Wiklander 	 SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 7, (l)), 56))
1817e75ca54SJens Wiklander 
1827e75ca54SJens Wiklander #define __FTMN_FUNC_HASH32(f, o, l) \
1837e75ca54SJens Wiklander 	(__FTMN_GET_FUNC_U64((f), (o), (l)) ^ \
1847e75ca54SJens Wiklander 	 __FTMN_GET_FUNC_U64((f), (o) + 8, (l)))
185*5b6f4be8SJens Wiklander #endif
1867e75ca54SJens Wiklander 
1877e75ca54SJens Wiklander #define __FTMN_FUNC_HASH16(f, o, l) \
1887e75ca54SJens Wiklander 	(__FTMN_FUNC_HASH32((f), (o), (l)) ^ \
1897e75ca54SJens Wiklander 	 __FTMN_FUNC_HASH32((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 16, (l)))
1907e75ca54SJens Wiklander 
1917e75ca54SJens Wiklander #define __FTMN_FUNC_HASH8(f, o, l) \
1927e75ca54SJens Wiklander 	(__FTMN_FUNC_HASH16((f), (o), (l)) ^ \
1937e75ca54SJens Wiklander 	 __FTMN_FUNC_HASH16((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 8, (l)))
1947e75ca54SJens Wiklander 
1957e75ca54SJens Wiklander #define __FTMN_FUNC_HASH4(f, o, l) \
1967e75ca54SJens Wiklander 	(__FTMN_FUNC_HASH8((f), (o), (l)) ^ \
1977e75ca54SJens Wiklander 	 __FTMN_FUNC_HASH8((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 4, (l)))
1987e75ca54SJens Wiklander 
1997e75ca54SJens Wiklander #define __FTMN_FUNC_HASH2(f, l) \
2007e75ca54SJens Wiklander 	(__FTMN_FUNC_HASH4(f, 0, l) ^ \
2017e75ca54SJens Wiklander 	 __FTMN_FUNC_HASH4(f, __FTMN_MAX_FUNC_NAME_LEN / 2, l))
2027e75ca54SJens Wiklander 
2037e75ca54SJens Wiklander #define __FTMN_FUNC_HASH(f, l)	(unsigned long)__FTMN_FUNC_HASH2((f), (l))
2047e75ca54SJens Wiklander 
2057e75ca54SJens Wiklander #define __ftmn_step_count_1(c0) ((c0) * FTMN_INCR0)
2067e75ca54SJens Wiklander #define __ftmn_step_count_2(c0, c1) \
2077e75ca54SJens Wiklander 	(__ftmn_step_count_1(c0) + (c1) * FTMN_INCR1)
2087e75ca54SJens Wiklander #define __ftmn_step_count_3(c0, c1, c2) \
2097e75ca54SJens Wiklander 	(__ftmn_step_count_2(c0, c1) + (c2) * FTMN_INCR2)
2107e75ca54SJens Wiklander #define __ftmn_step_count_4(c0, c1, c2, c3)	\
2117e75ca54SJens Wiklander 	(__ftmn_step_count_3(c0, c1, c2) + (c3) * FTMN_INCR3)
2127e75ca54SJens Wiklander #define __ftmn_step_count_5(c0, c1, c2, c3, c4)	\
2137e75ca54SJens Wiklander 	(__ftmn_step_count_4(c0, c1, c2, c3) + (c4) * FTMN_INCR4)
2147e75ca54SJens Wiklander #define __ftmn_step_count_6(c0, c1, c2, c3, c4, c5)	\
2157e75ca54SJens Wiklander 	(__ftmn_step_count_5(c0, c1, c2, c3, c4) + (c5) * FTMN_INCR5)
2167e75ca54SJens Wiklander #define ___ftmn_args_count(_0, _1, _2, _3, _4, _5, x, ...) x
2177e75ca54SJens Wiklander #define __ftmn_args_count(...) \
2187e75ca54SJens Wiklander 	___ftmn_args_count(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
2197e75ca54SJens Wiklander #define ___ftmn_step_count(count, ...)	__ftmn_step_count_ ## count(__VA_ARGS__)
2207e75ca54SJens Wiklander #define __ftmn_step_count(count, ...)	___ftmn_step_count(count, __VA_ARGS__)
2217e75ca54SJens Wiklander 
2227e75ca54SJens Wiklander unsigned long ___ftmn_return_res(struct ftmn_check *check, unsigned long steps,
2237e75ca54SJens Wiklander 				 unsigned long res);
2247e75ca54SJens Wiklander void ___ftmn_expect_state(struct ftmn_check *check, enum ftmn_incr incr,
2257e75ca54SJens Wiklander 			  unsigned long steps, unsigned long res);
2267e75ca54SJens Wiklander 
2277e75ca54SJens Wiklander void ___ftmn_callee_done(struct ftmn_func_arg *arg, unsigned long my_hash,
2287e75ca54SJens Wiklander 			 unsigned long res);
2297e75ca54SJens Wiklander void ___ftmn_callee_done_not_zero(struct ftmn_func_arg *arg,
2307e75ca54SJens Wiklander 				  unsigned long my_hash,
2317e75ca54SJens Wiklander 				  unsigned long res);
2327e75ca54SJens Wiklander void ___ftmn_callee_done_memcmp(struct ftmn_func_arg *arg,
2337e75ca54SJens Wiklander 				unsigned long my_hash, int res,
2347e75ca54SJens Wiklander 				ftmn_memcmp_t my_memcmp,
2357e75ca54SJens Wiklander 				const void *p1, const void *p2, size_t nb);
2367e75ca54SJens Wiklander void ___ftmn_callee_done_check(struct ftmn_func_arg *arg, unsigned long my_hash,
2377e75ca54SJens Wiklander 			       struct ftmn_check *check, enum ftmn_incr incr,
2387e75ca54SJens Wiklander 			       unsigned long steps, unsigned long res);
2397e75ca54SJens Wiklander 
2407e75ca54SJens Wiklander void ___ftmn_callee_update_not_zero(struct ftmn_func_arg *arg,
2417e75ca54SJens Wiklander 				    unsigned long res);
2427e75ca54SJens Wiklander 
2437e75ca54SJens Wiklander void ___ftmn_set_check_res(struct ftmn_check *check, enum ftmn_incr incr,
2447e75ca54SJens Wiklander 			   unsigned long res);
2457e75ca54SJens Wiklander void ___ftmn_set_check_res_not_zero(struct ftmn_check *check,
2467e75ca54SJens Wiklander 				    enum ftmn_incr incr,
2477e75ca54SJens Wiklander 				    unsigned long res);
2487e75ca54SJens Wiklander void ___ftmn_set_check_res_memcmp(struct ftmn_check *check, enum ftmn_incr incr,
2497e75ca54SJens Wiklander 				  int res, ftmn_memcmp_t my_memcmp,
2507e75ca54SJens Wiklander 				  const void *p1, const void *p2, size_t nb);
2517e75ca54SJens Wiklander 
2527e75ca54SJens Wiklander void ___ftmn_copy_linked_call_res(struct ftmn_check *check, enum ftmn_incr incr,
2537e75ca54SJens Wiklander 				  struct ftmn_func_arg *arg, unsigned long res);
2547e75ca54SJens Wiklander 
2557e75ca54SJens Wiklander 
2567e75ca54SJens Wiklander #ifndef __KERNEL__
2577e75ca54SJens Wiklander extern struct ftmn_func_arg *__ftmn_global_func_arg;
2587e75ca54SJens Wiklander #endif
2597e75ca54SJens Wiklander 
__ftmn_get_tsd_func_arg_pp(void)2607e75ca54SJens Wiklander static inline struct ftmn_func_arg **__ftmn_get_tsd_func_arg_pp(void)
2617e75ca54SJens Wiklander {
2627e75ca54SJens Wiklander #if defined(CFG_FAULT_MITIGATION) && defined(__KERNEL__)
263ce56605aSSichun Qin 	if (thread_get_id_may_fail() >= 0)
2647e75ca54SJens Wiklander 		return &thread_get_tsd()->ftmn_arg;
265ce56605aSSichun Qin 	else
266ce56605aSSichun Qin 		return &thread_get_core_local()->ftmn_arg;
2677e75ca54SJens Wiklander #elif defined(CFG_FAULT_MITIGATION)
2687e75ca54SJens Wiklander 	return &__ftmn_global_func_arg;
2697e75ca54SJens Wiklander #else
2707e75ca54SJens Wiklander 	return NULL;
2717e75ca54SJens Wiklander #endif
2727e75ca54SJens Wiklander }
2737e75ca54SJens Wiklander 
__ftmn_get_tsd_func_arg(void)2747e75ca54SJens Wiklander static inline struct ftmn_func_arg *__ftmn_get_tsd_func_arg(void)
2757e75ca54SJens Wiklander {
2767e75ca54SJens Wiklander 	struct ftmn_func_arg **pp = __ftmn_get_tsd_func_arg_pp();
2777e75ca54SJens Wiklander 
2787e75ca54SJens Wiklander 	if (!pp)
2797e75ca54SJens Wiklander 		return NULL;
2807e75ca54SJens Wiklander 
2817e75ca54SJens Wiklander 	return *pp;
2827e75ca54SJens Wiklander }
2837e75ca54SJens Wiklander 
__ftmn_push_linked_call(struct ftmn * ftmn,unsigned long my_hash,unsigned long called_hash)2847e75ca54SJens Wiklander static inline void __ftmn_push_linked_call(struct ftmn *ftmn,
2857e75ca54SJens Wiklander 					 unsigned long my_hash,
2867e75ca54SJens Wiklander 					 unsigned long called_hash)
2877e75ca54SJens Wiklander {
2887e75ca54SJens Wiklander 	struct ftmn_func_arg **arg_pp = __ftmn_get_tsd_func_arg_pp();
2897e75ca54SJens Wiklander 
2907e75ca54SJens Wiklander 	if (arg_pp) {
2917e75ca54SJens Wiklander 		ftmn->arg_pp = arg_pp;
2927e75ca54SJens Wiklander 		ftmn->my_hash = my_hash;
2937e75ca54SJens Wiklander 		ftmn->called_hash = called_hash;
2947e75ca54SJens Wiklander 		ftmn->saved_arg = *ftmn->arg_pp;
2957e75ca54SJens Wiklander 		*ftmn->arg_pp = &ftmn->arg;
2967e75ca54SJens Wiklander 		ftmn->arg.hash = my_hash;
2977e75ca54SJens Wiklander 	}
2987e75ca54SJens Wiklander }
2997e75ca54SJens Wiklander 
__ftmn_pop_linked_call(struct ftmn * ftmn)3007e75ca54SJens Wiklander static inline void __ftmn_pop_linked_call(struct ftmn *ftmn)
3017e75ca54SJens Wiklander {
3027e75ca54SJens Wiklander 	if (ftmn->arg_pp)
3037e75ca54SJens Wiklander 		*ftmn->arg_pp = ftmn->saved_arg;
3047e75ca54SJens Wiklander }
3057e75ca54SJens Wiklander 
__ftmn_copy_linked_call_res(struct ftmn * f,enum ftmn_incr incr,unsigned long res)3067e75ca54SJens Wiklander static inline void __ftmn_copy_linked_call_res(struct ftmn *f,
3077e75ca54SJens Wiklander 					       enum ftmn_incr incr,
3087e75ca54SJens Wiklander 					       unsigned long res)
3097e75ca54SJens Wiklander {
3107e75ca54SJens Wiklander 	if (f->arg_pp) {
3117e75ca54SJens Wiklander 		assert(f->arg.hash == (f->my_hash ^ f->called_hash));
3127e75ca54SJens Wiklander 		assert(&f->arg == *f->arg_pp);
3137e75ca54SJens Wiklander 		assert((f->arg.hash ^ f->arg.res) == res);
3147e75ca54SJens Wiklander 		___ftmn_copy_linked_call_res(&f->check, incr, &f->arg, res);
3157e75ca54SJens Wiklander 	}
3167e75ca54SJens Wiklander }
3177e75ca54SJens Wiklander 
__ftmn_calle_swap_hash(struct ftmn_func_arg * arg,unsigned long my_old_hash,unsigned long my_new_hash)3187e75ca54SJens Wiklander static inline void __ftmn_calle_swap_hash(struct ftmn_func_arg *arg,
3197e75ca54SJens Wiklander 					  unsigned long my_old_hash,
3207e75ca54SJens Wiklander 					  unsigned long my_new_hash)
3217e75ca54SJens Wiklander {
3227e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
3237e75ca54SJens Wiklander 		arg->hash ^= my_old_hash ^ my_new_hash;
3247e75ca54SJens Wiklander }
3257e75ca54SJens Wiklander 
__ftmn_callee_done(struct ftmn_func_arg * arg,unsigned long my_hash,unsigned long res)3267e75ca54SJens Wiklander static inline void __ftmn_callee_done(struct ftmn_func_arg *arg,
3277e75ca54SJens Wiklander 				      unsigned long my_hash, unsigned long res)
3287e75ca54SJens Wiklander {
3297e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
3307e75ca54SJens Wiklander 		___ftmn_callee_done(arg, my_hash, res);
3317e75ca54SJens Wiklander }
3327e75ca54SJens Wiklander 
__ftmn_callee_done_not_zero(struct ftmn_func_arg * arg,unsigned long hash,unsigned long res)3337e75ca54SJens Wiklander static inline void __ftmn_callee_done_not_zero(struct ftmn_func_arg *arg,
3347e75ca54SJens Wiklander 					       unsigned long hash,
3357e75ca54SJens Wiklander 					       unsigned long res)
3367e75ca54SJens Wiklander {
3377e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
3387e75ca54SJens Wiklander 		___ftmn_callee_done_not_zero(arg, hash, res);
3397e75ca54SJens Wiklander }
3407e75ca54SJens Wiklander 
3417e75ca54SJens Wiklander static inline int
__ftmn_callee_done_memcmp(struct ftmn_func_arg * arg,unsigned long hash,ftmn_memcmp_t my_memcmp,const void * p1,const void * p2,size_t nb)3427e75ca54SJens Wiklander __ftmn_callee_done_memcmp(struct ftmn_func_arg *arg, unsigned long hash,
3437e75ca54SJens Wiklander 			  ftmn_memcmp_t my_memcmp,
3447e75ca54SJens Wiklander 			  const void *p1, const void *p2, size_t nb)
3457e75ca54SJens Wiklander {
3467e75ca54SJens Wiklander 	int res = my_memcmp(p1, p2, nb);
3477e75ca54SJens Wiklander 
3487e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
3497e75ca54SJens Wiklander 		___ftmn_callee_done_memcmp(arg, hash, res, my_memcmp,
3507e75ca54SJens Wiklander 					   p1, p2, nb);
3517e75ca54SJens Wiklander 
3527e75ca54SJens Wiklander 	return res;
3537e75ca54SJens Wiklander }
3547e75ca54SJens Wiklander 
__ftmn_callee_done_check(struct ftmn * ftmn,unsigned long my_hash,enum ftmn_incr incr,unsigned long steps,unsigned long res)3557e75ca54SJens Wiklander static inline void __ftmn_callee_done_check(struct ftmn *ftmn,
3567e75ca54SJens Wiklander 					    unsigned long my_hash,
3577e75ca54SJens Wiklander 					    enum ftmn_incr incr,
3587e75ca54SJens Wiklander 					    unsigned long steps,
3597e75ca54SJens Wiklander 					    unsigned long res)
3607e75ca54SJens Wiklander {
3617e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION))
3627e75ca54SJens Wiklander 		___ftmn_callee_done_check(__ftmn_get_tsd_func_arg(), my_hash,
3637e75ca54SJens Wiklander 					  &ftmn->check, incr, steps, res);
3647e75ca54SJens Wiklander }
3657e75ca54SJens Wiklander 
__ftmn_callee_update_not_zero(struct ftmn_func_arg * arg,unsigned long res)3667e75ca54SJens Wiklander static inline void __ftmn_callee_update_not_zero(struct ftmn_func_arg *arg,
3677e75ca54SJens Wiklander 						 unsigned long res)
3687e75ca54SJens Wiklander {
3697e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg)
3707e75ca54SJens Wiklander 		___ftmn_callee_update_not_zero(arg, res);
3717e75ca54SJens Wiklander }
3727e75ca54SJens Wiklander 
__ftmn_set_check_res(struct ftmn * ftmn,enum ftmn_incr incr,unsigned long res)3737e75ca54SJens Wiklander static inline void __ftmn_set_check_res(struct ftmn *ftmn, enum ftmn_incr incr,
3747e75ca54SJens Wiklander 				      unsigned long res)
3757e75ca54SJens Wiklander {
3767e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION))
3777e75ca54SJens Wiklander 		___ftmn_set_check_res(&ftmn->check, incr, res);
3787e75ca54SJens Wiklander }
3797e75ca54SJens Wiklander 
__ftmn_set_check_res_not_zero(struct ftmn * ftmn,enum ftmn_incr incr,unsigned long res)3807e75ca54SJens Wiklander static inline void __ftmn_set_check_res_not_zero(struct ftmn *ftmn,
3817e75ca54SJens Wiklander 					       enum ftmn_incr incr,
3827e75ca54SJens Wiklander 					       unsigned long res)
3837e75ca54SJens Wiklander {
3847e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION))
3857e75ca54SJens Wiklander 		___ftmn_set_check_res_not_zero(&ftmn->check, incr, res);
3867e75ca54SJens Wiklander }
3877e75ca54SJens Wiklander 
3887e75ca54SJens Wiklander 
3897e75ca54SJens Wiklander 
3907e75ca54SJens Wiklander /*
3917e75ca54SJens Wiklander  * FTMN_FUNC_HASH() - "hash" a function name
3927e75ca54SJens Wiklander  *
3937e75ca54SJens Wiklander  * Function names are "hashed" into an unsigned long. The "hashing" is done
3947e75ca54SJens Wiklander  * by xoring each 32/64 bit word of the function name producing a bit
3957e75ca54SJens Wiklander  * pattern that should be mostly unique for each function. Only the first
3967e75ca54SJens Wiklander  * 256 characters of the name are used when xoring as this is expected to
3977e75ca54SJens Wiklander  * be optimized to be calculated when compiling the source code in order to
3987e75ca54SJens Wiklander  * minimize the overhead.
3997e75ca54SJens Wiklander  */
4007e75ca54SJens Wiklander #define FTMN_FUNC_HASH(name)	__FTMN_FUNC_HASH(name, sizeof(name))
4017e75ca54SJens Wiklander 
4027e75ca54SJens Wiklander /*
4037e75ca54SJens Wiklander  * FTMN_PUSH_LINKED_CALL() - push call into a linked call chain
4047e75ca54SJens Wiklander  * @ftmn:		The local struct ftmn
4057e75ca54SJens Wiklander  * @called_func_hash:	The hash of the called function
4067e75ca54SJens Wiklander  *
4077e75ca54SJens Wiklander  * Inserts a call into a linked call chain or starts a new call chain if
4087e75ca54SJens Wiklander  * the passed struct ftmn_func_arg pointer was NULL.
4097e75ca54SJens Wiklander  *
4107e75ca54SJens Wiklander  * Each FTMN_PUSH_LINKED_CALL() is supposed to be matched by a
4117e75ca54SJens Wiklander  * FTMN_POP_LINKED_CALL().
4127e75ca54SJens Wiklander  */
4137e75ca54SJens Wiklander #define FTMN_PUSH_LINKED_CALL(ftmn, called_func_hash) \
4147e75ca54SJens Wiklander 	__ftmn_push_linked_call((ftmn), FTMN_FUNC_HASH(__func__), \
4157e75ca54SJens Wiklander 				(called_func_hash))
4167e75ca54SJens Wiklander 
4177e75ca54SJens Wiklander /*
4187e75ca54SJens Wiklander  * FTMN_SET_CHECK_RES_FROM_CALL() - copy the result from a linked call
4197e75ca54SJens Wiklander  * @ftmn:	The struct ftmn used during the linked call
4207e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
4217e75ca54SJens Wiklander  * @res:	Returned result to be match against the saved/copied result
4227e75ca54SJens Wiklander  *
4237e75ca54SJens Wiklander  * This macro is called just after a checked linked function has returned.
4247e75ca54SJens Wiklander  * The return value from the function is copied from the struct ftmn_func_arg
4257e75ca54SJens Wiklander  * passed to the called function into the local checked state. The checked
4267e75ca54SJens Wiklander  * state is increased with @incr. @res is checked against the saved result
4277e75ca54SJens Wiklander  * of the called function.
4287e75ca54SJens Wiklander  */
4297e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES_FROM_CALL(ftmn, incr, res) \
4307e75ca54SJens Wiklander 	__ftmn_copy_linked_call_res((ftmn), (incr), (res))
4317e75ca54SJens Wiklander 
4327e75ca54SJens Wiklander /*
4337e75ca54SJens Wiklander  * FTMN_POP_LINKED_CALL() - remove a call from a linked call chain
4347e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
4357e75ca54SJens Wiklander  *
4367e75ca54SJens Wiklander  * Supposed to match a call to FTMN_PUSH_LINKED_CALL()
4377e75ca54SJens Wiklander  */
4387e75ca54SJens Wiklander #define FTMN_POP_LINKED_CALL(ftmn) __ftmn_pop_linked_call((ftmn))
4397e75ca54SJens Wiklander 
4407e75ca54SJens Wiklander /*
4417e75ca54SJens Wiklander  * FTMN_CALL_FUNC() - Do a linked call to a function
4427e75ca54SJens Wiklander  * @res:	Variable to be assigned the result of the called function
4437e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
4447e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
4457e75ca54SJens Wiklander  * @func:	Function to be called
4467e75ca54SJens Wiklander  * @...:	Arguments to pass to @func
4477e75ca54SJens Wiklander  *
4487e75ca54SJens Wiklander  * This macro can be used to make a linked call to another function, the
4497e75ca54SJens Wiklander  * callee. This macro depends on the callee to always update the struct
4507e75ca54SJens Wiklander  * ftmn_func_arg (part of struct ftmn) even when returning an error.
4517e75ca54SJens Wiklander  *
4527e75ca54SJens Wiklander  * Note that in the cases where the callee may skip updating the struct
4537e75ca54SJens Wiklander  * ftmn_func_arg this macro cannot be used as
4547e75ca54SJens Wiklander  * FTMN_SET_CHECK_RES_FROM_CALL() would cause a panic due to mismatching
4557e75ca54SJens Wiklander  * return value and saved result.
4567e75ca54SJens Wiklander  */
4577e75ca54SJens Wiklander #define FTMN_CALL_FUNC(res, ftmn, incr, func, ...) \
4587e75ca54SJens Wiklander 	do { \
4597e75ca54SJens Wiklander 		FTMN_PUSH_LINKED_CALL((ftmn), FTMN_FUNC_HASH(#func)); \
4607e75ca54SJens Wiklander 		(res) = func(__VA_ARGS__); \
4617e75ca54SJens Wiklander 		FTMN_SET_CHECK_RES_FROM_CALL((ftmn), (incr), (res)); \
4627e75ca54SJens Wiklander 		FTMN_POP_LINKED_CALL((ftmn)); \
4637e75ca54SJens Wiklander 	} while (0)
4647e75ca54SJens Wiklander 
4657e75ca54SJens Wiklander /*
4667e75ca54SJens Wiklander  * FTMN_CALLEE_DONE() - Record result of callee
4677e75ca54SJens Wiklander  * @res:	Result or return value
4687e75ca54SJens Wiklander  *
4697e75ca54SJens Wiklander  * The passed result will be stored in the struct ftmn_func_arg struct
4707e75ca54SJens Wiklander  * supplied by the caller. This function must only be called once by the
4717e75ca54SJens Wiklander  * callee.
4727e75ca54SJens Wiklander  *
4737e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
4747e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
4757e75ca54SJens Wiklander  * redundant checks to rely on.
4767e75ca54SJens Wiklander  */
4777e75ca54SJens Wiklander #define FTMN_CALLEE_DONE(res) \
4787e75ca54SJens Wiklander 	__ftmn_callee_done(__ftmn_get_tsd_func_arg(), \
4797e75ca54SJens Wiklander 			   FTMN_FUNC_HASH(__func__), (res))
4807e75ca54SJens Wiklander /*
4817e75ca54SJens Wiklander  * FTMN_CALLEE_DONE_NOT_ZERO() - Record non-zero result of callee
4827e75ca54SJens Wiklander  * @res:	Result or return value
4837e75ca54SJens Wiklander  *
4847e75ca54SJens Wiklander  * The passed result will be stored in the struct ftmn_func_arg struct
4857e75ca54SJens Wiklander  * supplied by the caller. This function must only be called once by the
4867e75ca54SJens Wiklander  * callee.
4877e75ca54SJens Wiklander  *
4887e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
4897e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
4907e75ca54SJens Wiklander  * redundant checks to rely on. However, there are extra checks against
4917e75ca54SJens Wiklander  * unintentionally storing a zero which often is interpreted as a
4927e75ca54SJens Wiklander  * successful return value.
4937e75ca54SJens Wiklander  */
4947e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_NOT_ZERO(res) \
4957e75ca54SJens Wiklander 	__ftmn_callee_done_not_zero(__ftmn_get_tsd_func_arg(), \
4967e75ca54SJens Wiklander 				    FTMN_FUNC_HASH(__func__), (res))
4977e75ca54SJens Wiklander 
4987e75ca54SJens Wiklander /*
4997e75ca54SJens Wiklander  * FTMN_CALLEE_DONE_CHECK() - Record result of callee with checked state
5007e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
5017e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
5027e75ca54SJens Wiklander  * @exp_steps:	Expected recorded checkpoints
5037e75ca54SJens Wiklander  * @res:	Result or return value
5047e75ca54SJens Wiklander  *
5057e75ca54SJens Wiklander  * The passed result will be stored in the struct ftmn_func_arg struct
5067e75ca54SJens Wiklander  * supplied by the caller. This function must only be called once by the
5077e75ca54SJens Wiklander  * callee.
5087e75ca54SJens Wiklander  *
5097e75ca54SJens Wiklander  * @res is double checked against the value stored in local checked state.
5107e75ca54SJens Wiklander  * @exp_steps is checked against the locate checked state. The local
5117e75ca54SJens Wiklander  * checked state is increased by @incr.
5127e75ca54SJens Wiklander  */
5137e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_CHECK(ftmn, incr, exp_steps, res) \
5147e75ca54SJens Wiklander 	__ftmn_callee_done_check((ftmn), FTMN_FUNC_HASH(__func__), \
5157e75ca54SJens Wiklander 				 (incr), (exp_steps), (res))
5167e75ca54SJens Wiklander 
5177e75ca54SJens Wiklander /*
5187e75ca54SJens Wiklander  * FTMN_CALLEE_DONE_MEMCMP() - Record result of memcmp() in a callee
5197e75ca54SJens Wiklander  * @my_memcmp:		Function pointer of custom memcmp()
5207e75ca54SJens Wiklander  * @p1:			Pointer to first buffer
5217e75ca54SJens Wiklander  * @p2:			Pointer to second buffer
5227e75ca54SJens Wiklander  * @nb:			Number of bytes
5237e75ca54SJens Wiklander  *
5247e75ca54SJens Wiklander  * The result from the mem compare is saved in the local checked state.
5257e75ca54SJens Wiklander  * This function must only be called once by the callee.
5267e75ca54SJens Wiklander  */
5277e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_MEMCMP(my_memcmp, p1, p2, nb) \
5287e75ca54SJens Wiklander 	__ftmn_callee_done_memcmp(__ftmn_get_tsd_func_arg(), \
5297e75ca54SJens Wiklander 				  FTMN_FUNC_HASH(__func__), (my_memcmp), \
5307e75ca54SJens Wiklander 				  (p1), (p2), (nb))
5317e75ca54SJens Wiklander 
5327e75ca54SJens Wiklander /*
5337e75ca54SJens Wiklander  * FTMN_CALLEE_UPDATE_NOT_ZERO() - Update the result of a callee with a
5347e75ca54SJens Wiklander  *				   non-zero value
5357e75ca54SJens Wiklander  * @res:	Result or return value
5367e75ca54SJens Wiklander  *
5377e75ca54SJens Wiklander  * The passed result will be stored in the struct ftmn_func_arg struct
5387e75ca54SJens Wiklander  * supplied by the caller. This function can be called any number of times
5397e75ca54SJens Wiklander  * by the callee, provided that one of the FTMN_CALLEE_DONE_XXX() functions
5407e75ca54SJens Wiklander  * has been called first.
5417e75ca54SJens Wiklander  *
5427e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
5437e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
5447e75ca54SJens Wiklander  * redundant checks to rely on. However, there are extra checks against
5457e75ca54SJens Wiklander  * unintentionally storing a zero which often is interpreted as a
5467e75ca54SJens Wiklander  * successful return value.
5477e75ca54SJens Wiklander  */
5487e75ca54SJens Wiklander #define FTMN_CALLEE_UPDATE_NOT_ZERO(res) \
5497e75ca54SJens Wiklander 	__ftmn_callee_update_not_zero(__ftmn_get_tsd_func_arg(), res)
5507e75ca54SJens Wiklander 
5517e75ca54SJens Wiklander /*
5527e75ca54SJens Wiklander  * FTMN_CALLEE_SWAP_HASH() - Remove old hash and add new hash
5537e75ca54SJens Wiklander  * @my_old_hash:	The old hash to remove
5547e75ca54SJens Wiklander  *
5557e75ca54SJens Wiklander  * This macro replaces the old expected function hash with the hash of the
5567e75ca54SJens Wiklander  * current function.
5577e75ca54SJens Wiklander  *
5587e75ca54SJens Wiklander  * If a function is called using an alias the caller uses the hash of the
5597e75ca54SJens Wiklander  * alias not the real function name. This hash is recoded in the field
5607e75ca54SJens Wiklander  * "hash" in struct ftmn_func_arg which can be found with
5617e75ca54SJens Wiklander  * __ftmn_get_tsd_func_arg().
5627e75ca54SJens Wiklander  *
5637e75ca54SJens Wiklander  * The FTMN_CALLE_* functions only work with the real function name so the
5647e75ca54SJens Wiklander  * old hash must be removed and replaced with the new for the calling
5657e75ca54SJens Wiklander  * function to be able to verify the result.
5667e75ca54SJens Wiklander  */
5677e75ca54SJens Wiklander #define FTMN_CALLEE_SWAP_HASH(my_old_hash) \
5687e75ca54SJens Wiklander 	__ftmn_calle_swap_hash(__ftmn_get_tsd_func_arg(), \
5697e75ca54SJens Wiklander 			       (my_old_hash), FTMN_FUNC_HASH(__func__))
5707e75ca54SJens Wiklander 
5717e75ca54SJens Wiklander /*
5727e75ca54SJens Wiklander  * FTMN_SET_CHECK_RES() - Records a result in local checked state
5737e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
5747e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
5757e75ca54SJens Wiklander  * @res:	Result or return value
5767e75ca54SJens Wiklander  *
5777e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
5787e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
5797e75ca54SJens Wiklander  * redundant checks to rely on.
5807e75ca54SJens Wiklander  */
5817e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES(ftmn, incr, res) \
5827e75ca54SJens Wiklander 	__ftmn_set_check_res((ftmn), (incr), (res))
5837e75ca54SJens Wiklander 
5847e75ca54SJens Wiklander /*
5857e75ca54SJens Wiklander  * FTMN_SET_CHECK_RES_NOT_ZERO() - Records a non-zero result in local checked
5867e75ca54SJens Wiklander  *				   state
5877e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
5887e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
5897e75ca54SJens Wiklander  * @res:	Result or return value
5907e75ca54SJens Wiklander  *
5917e75ca54SJens Wiklander  * Note that this function is somewhat dangerous as any passed value will
5927e75ca54SJens Wiklander  * be stored so if the value has been tampered with there is no additional
5937e75ca54SJens Wiklander  * redundant checks to rely on. However, there are extra checks against
5947e75ca54SJens Wiklander  * unintentionally storing a zero which often is interpreted as a
5957e75ca54SJens Wiklander  * successful return value.
5967e75ca54SJens Wiklander  */
5977e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES_NOT_ZERO(ftmn, incr, res) \
5987e75ca54SJens Wiklander 	__ftmn_set_check_res_not_zero((ftmn), (incr), (res))
5997e75ca54SJens Wiklander 
ftmn_set_check_res_memcmp(struct ftmn * ftmn,enum ftmn_incr incr,ftmn_memcmp_t my_memcmp,const void * p1,const void * p2,size_t nb)6007e75ca54SJens Wiklander static inline int ftmn_set_check_res_memcmp(struct ftmn *ftmn,
6017e75ca54SJens Wiklander 					    enum ftmn_incr incr,
6027e75ca54SJens Wiklander 					    ftmn_memcmp_t my_memcmp,
6037e75ca54SJens Wiklander 					    const void *p1, const void *p2,
6047e75ca54SJens Wiklander 					    size_t nb)
6057e75ca54SJens Wiklander {
6067e75ca54SJens Wiklander 	int res = my_memcmp(p1, p2, nb);
6077e75ca54SJens Wiklander 
6087e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION))
6097e75ca54SJens Wiklander 		___ftmn_set_check_res_memcmp(&ftmn->check, incr, res,
6107e75ca54SJens Wiklander 					     my_memcmp, p1, p2, nb);
6117e75ca54SJens Wiklander 
6127e75ca54SJens Wiklander 	return res;
6137e75ca54SJens Wiklander }
6147e75ca54SJens Wiklander 
6157e75ca54SJens Wiklander /*
6167e75ca54SJens Wiklander  * FTMN_STEP_COUNT() - Calculate total step count
6177e75ca54SJens Wiklander  *
6187e75ca54SJens Wiklander  * Takes variable number of arguments, up to a total of 6. Where arg0
6197e75ca54SJens Wiklander  * is the number of times the counter has been increased by FTMN_INCR0,
6207e75ca54SJens Wiklander  * arg1 FTMN_INCR1 and so on.
6217e75ca54SJens Wiklander  */
6227e75ca54SJens Wiklander #define FTMN_STEP_COUNT(...)	\
6237e75ca54SJens Wiklander 	__ftmn_step_count(__ftmn_args_count(__VA_ARGS__), __VA_ARGS__)
6247e75ca54SJens Wiklander 
6257e75ca54SJens Wiklander /*
6267e75ca54SJens Wiklander  * ftmn_checkpoint() - Add a checkpoint
6277e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
6287e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
6297e75ca54SJens Wiklander  *
6307e75ca54SJens Wiklander  * Adds a checkpoint by increasing the internal checked state. This
6317e75ca54SJens Wiklander  * can be checked at a later point in the calling function, for instance
6327e75ca54SJens Wiklander  * with ftmn_return_res().
6337e75ca54SJens Wiklander  */
ftmn_checkpoint(struct ftmn * ftmn,enum ftmn_incr incr)6347e75ca54SJens Wiklander static inline void ftmn_checkpoint(struct ftmn *ftmn, enum ftmn_incr incr)
6357e75ca54SJens Wiklander {
6367e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION)) {
6377e75ca54SJens Wiklander 		/*
6387e75ca54SJens Wiklander 		 * The purpose of the barriers is to prevent the compiler
6397e75ca54SJens Wiklander 		 * from optimizing this increase to some other location
6407e75ca54SJens Wiklander 		 * in the calling function.
6417e75ca54SJens Wiklander 		 */
6427e75ca54SJens Wiklander 		barrier();
6437e75ca54SJens Wiklander 		ftmn->check.steps += incr;
6447e75ca54SJens Wiklander 		barrier();
6457e75ca54SJens Wiklander 	}
6467e75ca54SJens Wiklander }
6477e75ca54SJens Wiklander 
6487e75ca54SJens Wiklander /*
6497e75ca54SJens Wiklander  * ftmn_expect_state() - Check expected state
6507e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
6517e75ca54SJens Wiklander  * @incr:	Value to increase the checked state with
6527e75ca54SJens Wiklander  * @steps:	Expected accumulated steps
6537e75ca54SJens Wiklander  * @res:	Expected saved result or return value
6547e75ca54SJens Wiklander  *
6557e75ca54SJens Wiklander  * This is a more advanced version of ftmn_checkpoint() which before
6567e75ca54SJens Wiklander  * increasing the accumulated steps first checks the accumulated steps and
6577e75ca54SJens Wiklander  * saved result or return value.
6587e75ca54SJens Wiklander  */
ftmn_expect_state(struct ftmn * ftmn,enum ftmn_incr incr,unsigned long steps,unsigned long res)6597e75ca54SJens Wiklander static inline void ftmn_expect_state(struct ftmn *ftmn,
6607e75ca54SJens Wiklander 				     enum ftmn_incr incr, unsigned long steps,
6617e75ca54SJens Wiklander 				     unsigned long res)
6627e75ca54SJens Wiklander {
6637e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION)) {
6647e75ca54SJens Wiklander 		assert((ftmn->check.res ^ FTMN_DEFAULT_HASH) == res);
6657e75ca54SJens Wiklander 		assert(ftmn->check.steps == steps);
6667e75ca54SJens Wiklander 
6677e75ca54SJens Wiklander 		___ftmn_expect_state(&ftmn->check, incr, steps, res);
6687e75ca54SJens Wiklander 	}
6697e75ca54SJens Wiklander }
6707e75ca54SJens Wiklander 
6717e75ca54SJens Wiklander /*
6727e75ca54SJens Wiklander  * ftmn_return_res() - Check and return result
6737e75ca54SJens Wiklander  * @ftmn:	The local struct ftmn
6747e75ca54SJens Wiklander  * @steps:	Expected accumulated steps
6757e75ca54SJens Wiklander  * @res:	Expected saved result or return value
6767e75ca54SJens Wiklander  *
6777e75ca54SJens Wiklander  * Checks that the internal accumulated state matches the supplied @steps
6787e75ca54SJens Wiklander  * and that the saved result or return value matches the supplied one.
6797e75ca54SJens Wiklander  *
6807e75ca54SJens Wiklander  * Returns @res.
6817e75ca54SJens Wiklander  */
ftmn_return_res(struct ftmn * ftmn,unsigned long steps,unsigned long res)6827e75ca54SJens Wiklander static inline unsigned long ftmn_return_res(struct ftmn *ftmn,
6837e75ca54SJens Wiklander 					    unsigned long steps,
6847e75ca54SJens Wiklander 					    unsigned long res)
6857e75ca54SJens Wiklander {
6867e75ca54SJens Wiklander 	/*
6877e75ca54SJens Wiklander 	 * We're expecting that the compiler does a tail call optimization
6887e75ca54SJens Wiklander 	 * allowing ___ftmn_return_res() to have full control over the
6897e75ca54SJens Wiklander 	 * returned value. Thus trying to reduce the window where the
6907e75ca54SJens Wiklander 	 * return value can be tampered with.
6917e75ca54SJens Wiklander 	 */
6927e75ca54SJens Wiklander 	if (IS_ENABLED(CFG_FAULT_MITIGATION)) {
6937e75ca54SJens Wiklander 		assert((ftmn->check.res ^ FTMN_DEFAULT_HASH) == res);
6947e75ca54SJens Wiklander 		assert(ftmn->check.steps == steps);
6957e75ca54SJens Wiklander 
6967e75ca54SJens Wiklander 		return ___ftmn_return_res(&ftmn->check, steps, res);
6977e75ca54SJens Wiklander 	}
6987e75ca54SJens Wiklander 	return res;
6997e75ca54SJens Wiklander }
7007e75ca54SJens Wiklander #endif /*__FAULT_MITIGATION_H*/
701