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