xref: /linux/include/rv/ltl_monitor.h (revision 0a949252556809ce922e0289c148883e838cb9bb)
1a9769a5bSNam Cao /* SPDX-License-Identifier: GPL-2.0 */
2a9769a5bSNam Cao /**
3a9769a5bSNam Cao  * This file must be combined with the $(MODEL_NAME).h file generated by
4a9769a5bSNam Cao  * tools/verification/rvgen.
5a9769a5bSNam Cao  */
6a9769a5bSNam Cao 
7a9769a5bSNam Cao #include <linux/args.h>
8a9769a5bSNam Cao #include <linux/rv.h>
9a9769a5bSNam Cao #include <linux/stringify.h>
10a9769a5bSNam Cao #include <linux/seq_buf.h>
11a9769a5bSNam Cao #include <rv/instrumentation.h>
12a9769a5bSNam Cao #include <trace/events/task.h>
13a9769a5bSNam Cao #include <trace/events/sched.h>
14a9769a5bSNam Cao 
15a9769a5bSNam Cao #ifndef MONITOR_NAME
16a9769a5bSNam Cao #error "Please include $(MODEL_NAME).h generated by rvgen"
17a9769a5bSNam Cao #endif
18a9769a5bSNam Cao 
19a9769a5bSNam Cao #ifdef CONFIG_RV_REACTORS
20a9769a5bSNam Cao #define RV_MONITOR_NAME CONCATENATE(rv_, MONITOR_NAME)
21a9769a5bSNam Cao static struct rv_monitor RV_MONITOR_NAME;
22a9769a5bSNam Cao 
23a9769a5bSNam Cao static void rv_cond_react(struct task_struct *task)
24a9769a5bSNam Cao {
25a9769a5bSNam Cao 	if (!rv_reacting_on() || !RV_MONITOR_NAME.react)
26a9769a5bSNam Cao 		return;
27a9769a5bSNam Cao 	RV_MONITOR_NAME.react("rv: "__stringify(MONITOR_NAME)": %s[%d]: violation detected\n",
28a9769a5bSNam Cao 			      task->comm, task->pid);
29a9769a5bSNam Cao }
30a9769a5bSNam Cao #else
31a9769a5bSNam Cao static void rv_cond_react(struct task_struct *task)
32a9769a5bSNam Cao {
33a9769a5bSNam Cao }
34a9769a5bSNam Cao #endif
35a9769a5bSNam Cao 
36a9769a5bSNam Cao static int ltl_monitor_slot = RV_PER_TASK_MONITOR_INIT;
37a9769a5bSNam Cao 
38a9769a5bSNam Cao static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon);
39a9769a5bSNam Cao static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation);
40a9769a5bSNam Cao 
41a9769a5bSNam Cao static struct ltl_monitor *ltl_get_monitor(struct task_struct *task)
42a9769a5bSNam Cao {
43a9769a5bSNam Cao 	return &task->rv[ltl_monitor_slot].ltl_mon;
44a9769a5bSNam Cao }
45a9769a5bSNam Cao 
46a9769a5bSNam Cao static void ltl_task_init(struct task_struct *task, bool task_creation)
47a9769a5bSNam Cao {
48a9769a5bSNam Cao 	struct ltl_monitor *mon = ltl_get_monitor(task);
49a9769a5bSNam Cao 
50a9769a5bSNam Cao 	memset(&mon->states, 0, sizeof(mon->states));
51a9769a5bSNam Cao 
52a9769a5bSNam Cao 	for (int i = 0; i < LTL_NUM_ATOM; ++i)
53a9769a5bSNam Cao 		__set_bit(i, mon->unknown_atoms);
54a9769a5bSNam Cao 
55a9769a5bSNam Cao 	ltl_atoms_init(task, mon, task_creation);
56a9769a5bSNam Cao 	ltl_atoms_fetch(task, mon);
57a9769a5bSNam Cao }
58a9769a5bSNam Cao 
59a9769a5bSNam Cao static void handle_task_newtask(void *data, struct task_struct *task, unsigned long flags)
60a9769a5bSNam Cao {
61a9769a5bSNam Cao 	ltl_task_init(task, true);
62a9769a5bSNam Cao }
63a9769a5bSNam Cao 
64a9769a5bSNam Cao static int ltl_monitor_init(void)
65a9769a5bSNam Cao {
66a9769a5bSNam Cao 	struct task_struct *g, *p;
67a9769a5bSNam Cao 	int ret, cpu;
68a9769a5bSNam Cao 
69a9769a5bSNam Cao 	ret = rv_get_task_monitor_slot();
70a9769a5bSNam Cao 	if (ret < 0)
71a9769a5bSNam Cao 		return ret;
72a9769a5bSNam Cao 
73a9769a5bSNam Cao 	ltl_monitor_slot = ret;
74a9769a5bSNam Cao 
75a9769a5bSNam Cao 	rv_attach_trace_probe(name, task_newtask, handle_task_newtask);
76a9769a5bSNam Cao 
77a9769a5bSNam Cao 	read_lock(&tasklist_lock);
78a9769a5bSNam Cao 
79a9769a5bSNam Cao 	for_each_process_thread(g, p)
80a9769a5bSNam Cao 		ltl_task_init(p, false);
81a9769a5bSNam Cao 
82a9769a5bSNam Cao 	for_each_present_cpu(cpu)
83a9769a5bSNam Cao 		ltl_task_init(idle_task(cpu), false);
84a9769a5bSNam Cao 
85a9769a5bSNam Cao 	read_unlock(&tasklist_lock);
86a9769a5bSNam Cao 
87a9769a5bSNam Cao 	return 0;
88a9769a5bSNam Cao }
89a9769a5bSNam Cao 
90a9769a5bSNam Cao static void ltl_monitor_destroy(void)
91a9769a5bSNam Cao {
92a9769a5bSNam Cao 	rv_detach_trace_probe(name, task_newtask, handle_task_newtask);
93a9769a5bSNam Cao 
94a9769a5bSNam Cao 	rv_put_task_monitor_slot(ltl_monitor_slot);
95a9769a5bSNam Cao 	ltl_monitor_slot = RV_PER_TASK_MONITOR_INIT;
96a9769a5bSNam Cao }
97a9769a5bSNam Cao 
98a9769a5bSNam Cao static void ltl_illegal_state(struct task_struct *task, struct ltl_monitor *mon)
99a9769a5bSNam Cao {
100a9769a5bSNam Cao 	CONCATENATE(trace_error_, MONITOR_NAME)(task);
101a9769a5bSNam Cao 	rv_cond_react(task);
102a9769a5bSNam Cao }
103a9769a5bSNam Cao 
104a9769a5bSNam Cao static void ltl_attempt_start(struct task_struct *task, struct ltl_monitor *mon)
105a9769a5bSNam Cao {
106a9769a5bSNam Cao 	if (rv_ltl_all_atoms_known(mon))
107a9769a5bSNam Cao 		ltl_start(task, mon);
108a9769a5bSNam Cao }
109a9769a5bSNam Cao 
110a9769a5bSNam Cao static inline void ltl_atom_set(struct ltl_monitor *mon, enum ltl_atom atom, bool value)
111a9769a5bSNam Cao {
112a9769a5bSNam Cao 	__clear_bit(atom, mon->unknown_atoms);
113a9769a5bSNam Cao 	if (value)
114a9769a5bSNam Cao 		__set_bit(atom, mon->atoms);
115a9769a5bSNam Cao 	else
116a9769a5bSNam Cao 		__clear_bit(atom, mon->atoms);
117a9769a5bSNam Cao }
118a9769a5bSNam Cao 
119a9769a5bSNam Cao static void
120a9769a5bSNam Cao ltl_trace_event(struct task_struct *task, struct ltl_monitor *mon, unsigned long *next_state)
121a9769a5bSNam Cao {
122a9769a5bSNam Cao 	const char *format_str = "%s";
123a9769a5bSNam Cao 	DECLARE_SEQ_BUF(atoms, 64);
124a9769a5bSNam Cao 	char states[32], next[32];
125a9769a5bSNam Cao 	int i;
126a9769a5bSNam Cao 
127a9769a5bSNam Cao 	if (!CONCATENATE(CONCATENATE(trace_event_, MONITOR_NAME), _enabled)())
128a9769a5bSNam Cao 		return;
129a9769a5bSNam Cao 
130a9769a5bSNam Cao 	snprintf(states, sizeof(states), "%*pbl", RV_MAX_BA_STATES, mon->states);
131a9769a5bSNam Cao 	snprintf(next, sizeof(next), "%*pbl", RV_MAX_BA_STATES, next_state);
132a9769a5bSNam Cao 
133a9769a5bSNam Cao 	for (i = 0; i < LTL_NUM_ATOM; ++i) {
134a9769a5bSNam Cao 		if (test_bit(i, mon->atoms)) {
135a9769a5bSNam Cao 			seq_buf_printf(&atoms, format_str, ltl_atom_str(i));
136a9769a5bSNam Cao 			format_str = ",%s";
137a9769a5bSNam Cao 		}
138a9769a5bSNam Cao 	}
139a9769a5bSNam Cao 
140a9769a5bSNam Cao 	CONCATENATE(trace_event_, MONITOR_NAME)(task, states, atoms.buffer, next);
141a9769a5bSNam Cao }
142a9769a5bSNam Cao 
143a9769a5bSNam Cao static void ltl_validate(struct task_struct *task, struct ltl_monitor *mon)
144a9769a5bSNam Cao {
145a9769a5bSNam Cao 	DECLARE_BITMAP(next_states, RV_MAX_BA_STATES) = {0};
146a9769a5bSNam Cao 
147a9769a5bSNam Cao 	if (!rv_ltl_valid_state(mon))
148a9769a5bSNam Cao 		return;
149a9769a5bSNam Cao 
150a9769a5bSNam Cao 	for (unsigned int i = 0; i < RV_NUM_BA_STATES; ++i) {
151a9769a5bSNam Cao 		if (test_bit(i, mon->states))
152a9769a5bSNam Cao 			ltl_possible_next_states(mon, i, next_states);
153a9769a5bSNam Cao 	}
154a9769a5bSNam Cao 
155a9769a5bSNam Cao 	ltl_trace_event(task, mon, next_states);
156a9769a5bSNam Cao 
157a9769a5bSNam Cao 	memcpy(mon->states, next_states, sizeof(next_states));
158a9769a5bSNam Cao 
159a9769a5bSNam Cao 	if (!rv_ltl_valid_state(mon))
160a9769a5bSNam Cao 		ltl_illegal_state(task, mon);
161a9769a5bSNam Cao }
162a9769a5bSNam Cao 
163a9769a5bSNam Cao static void ltl_atom_update(struct task_struct *task, enum ltl_atom atom, bool value)
164a9769a5bSNam Cao {
165a9769a5bSNam Cao 	struct ltl_monitor *mon = ltl_get_monitor(task);
166a9769a5bSNam Cao 
167a9769a5bSNam Cao 	ltl_atom_set(mon, atom, value);
168a9769a5bSNam Cao 	ltl_atoms_fetch(task, mon);
169a9769a5bSNam Cao 
170*0a949252SNam Cao 	if (!rv_ltl_valid_state(mon)) {
171a9769a5bSNam Cao 		ltl_attempt_start(task, mon);
172*0a949252SNam Cao 		return;
173*0a949252SNam Cao 	}
174a9769a5bSNam Cao 
175a9769a5bSNam Cao 	ltl_validate(task, mon);
176a9769a5bSNam Cao }
177a9769a5bSNam Cao 
178a9769a5bSNam Cao static void __maybe_unused ltl_atom_pulse(struct task_struct *task, enum ltl_atom atom, bool value)
179a9769a5bSNam Cao {
180a9769a5bSNam Cao 	struct ltl_monitor *mon = ltl_get_monitor(task);
181a9769a5bSNam Cao 
182a9769a5bSNam Cao 	ltl_atom_update(task, atom, value);
183a9769a5bSNam Cao 
184a9769a5bSNam Cao 	ltl_atom_set(mon, atom, !value);
185a9769a5bSNam Cao 	ltl_validate(task, mon);
186a9769a5bSNam Cao }
187