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
rv_cond_react(struct task_struct * task)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
rv_cond_react(struct task_struct * task)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
ltl_get_monitor(struct task_struct * task)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
ltl_task_init(struct task_struct * task,bool task_creation)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
handle_task_newtask(void * data,struct task_struct * task,unsigned long flags)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
ltl_monitor_init(void)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
ltl_monitor_destroy(void)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
ltl_illegal_state(struct task_struct * task,struct ltl_monitor * mon)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
ltl_attempt_start(struct task_struct * task,struct ltl_monitor * mon)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
ltl_atom_set(struct ltl_monitor * mon,enum ltl_atom atom,bool value)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
ltl_trace_event(struct task_struct * task,struct ltl_monitor * mon,unsigned long * next_state)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
ltl_validate(struct task_struct * task,struct ltl_monitor * mon)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
ltl_atom_update(struct task_struct * task,enum ltl_atom atom,bool value)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
ltl_atom_pulse(struct task_struct * task,enum ltl_atom atom,bool value)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