1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org>
4 *
5 * Deterministic automata (DA) monitor functions, to be used together
6 * with automata models in C generated by the dot2k tool.
7 *
8 * The dot2k tool is available at tools/verification/dot2k/
9 *
10 * For further information, see:
11 * Documentation/trace/rv/monitor_synthesis.rst
12 */
13
14 #ifndef _RV_DA_MONITOR_H
15 #define _RV_DA_MONITOR_H
16
17 #include <rv/automata.h>
18 #include <linux/rv.h>
19 #include <linux/stringify.h>
20 #include <linux/bug.h>
21 #include <linux/sched.h>
22
23 /*
24 * Per-cpu variables require a unique name although static in some
25 * configurations (e.g. CONFIG_DEBUG_FORCE_WEAK_PER_CPU or alpha modules).
26 */
27 #define DA_MON_NAME CONCATENATE(da_mon_, MONITOR_NAME)
28
29 static struct rv_monitor rv_this;
30
react(enum states curr_state,enum events event)31 static void react(enum states curr_state, enum events event)
32 {
33 rv_react(&rv_this,
34 "rv: monitor %s does not allow event %s on state %s\n",
35 __stringify(MONITOR_NAME),
36 model_get_event_name(event),
37 model_get_state_name(curr_state));
38 }
39
40 /*
41 * da_monitor_reset - reset a monitor and setting it to init state
42 */
da_monitor_reset(struct da_monitor * da_mon)43 static inline void da_monitor_reset(struct da_monitor *da_mon)
44 {
45 da_mon->monitoring = 0;
46 da_mon->curr_state = model_get_initial_state();
47 }
48
49 /*
50 * da_monitor_start - start monitoring
51 *
52 * The monitor will ignore all events until monitoring is set to true. This
53 * function needs to be called to tell the monitor to start monitoring.
54 */
da_monitor_start(struct da_monitor * da_mon)55 static inline void da_monitor_start(struct da_monitor *da_mon)
56 {
57 da_mon->curr_state = model_get_initial_state();
58 da_mon->monitoring = 1;
59 }
60
61 /*
62 * da_monitoring - returns true if the monitor is processing events
63 */
da_monitoring(struct da_monitor * da_mon)64 static inline bool da_monitoring(struct da_monitor *da_mon)
65 {
66 return da_mon->monitoring;
67 }
68
69 /*
70 * da_monitor_enabled - checks if the monitor is enabled
71 */
da_monitor_enabled(void)72 static inline bool da_monitor_enabled(void)
73 {
74 /* global switch */
75 if (unlikely(!rv_monitoring_on()))
76 return 0;
77
78 /* monitor enabled */
79 if (unlikely(!rv_this.enabled))
80 return 0;
81
82 return 1;
83 }
84
85 /*
86 * da_monitor_handling_event - checks if the monitor is ready to handle events
87 */
da_monitor_handling_event(struct da_monitor * da_mon)88 static inline bool da_monitor_handling_event(struct da_monitor *da_mon)
89 {
90 if (!da_monitor_enabled())
91 return 0;
92
93 /* monitor is actually monitoring */
94 if (unlikely(!da_monitoring(da_mon)))
95 return 0;
96
97 return 1;
98 }
99
100 #if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU
101 /*
102 * Event handler for implicit monitors. Implicit monitor is the one which the
103 * handler does not need to specify which da_monitor to manipulate. Examples
104 * of implicit monitor are the per_cpu or the global ones.
105 *
106 * Retry in case there is a race between getting and setting the next state,
107 * warn and reset the monitor if it runs out of retries. The monitor should be
108 * able to handle various orders.
109 */
110
da_event(struct da_monitor * da_mon,enum events event)111 static inline bool da_event(struct da_monitor *da_mon, enum events event)
112 {
113 enum states curr_state, next_state;
114
115 curr_state = READ_ONCE(da_mon->curr_state);
116 for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
117 next_state = model_get_next_state(curr_state, event);
118 if (next_state == INVALID_STATE) {
119 react(curr_state, event);
120 CONCATENATE(trace_error_, MONITOR_NAME)(
121 model_get_state_name(curr_state),
122 model_get_event_name(event));
123 return false;
124 }
125 if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
126 CONCATENATE(trace_event_, MONITOR_NAME)(
127 model_get_state_name(curr_state),
128 model_get_event_name(event),
129 model_get_state_name(next_state),
130 model_is_final_state(next_state));
131 return true;
132 }
133 }
134
135 trace_rv_retries_error(__stringify(MONITOR_NAME), model_get_event_name(event));
136 pr_warn("rv: " __stringify(MAX_DA_RETRY_RACING_EVENTS)
137 " retries reached for event %s, resetting monitor %s",
138 model_get_event_name(event), __stringify(MONITOR_NAME));
139 return false;
140 }
141
142 #elif RV_MON_TYPE == RV_MON_PER_TASK
143 /*
144 * Event handler for per_task monitors.
145 *
146 * Retry in case there is a race between getting and setting the next state,
147 * warn and reset the monitor if it runs out of retries. The monitor should be
148 * able to handle various orders.
149 */
150
da_event(struct da_monitor * da_mon,struct task_struct * tsk,enum events event)151 static inline bool da_event(struct da_monitor *da_mon, struct task_struct *tsk,
152 enum events event)
153 {
154 enum states curr_state, next_state;
155
156 curr_state = READ_ONCE(da_mon->curr_state);
157 for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
158 next_state = model_get_next_state(curr_state, event);
159 if (next_state == INVALID_STATE) {
160 react(curr_state, event);
161 CONCATENATE(trace_error_, MONITOR_NAME)(tsk->pid,
162 model_get_state_name(curr_state),
163 model_get_event_name(event));
164 return false;
165 }
166 if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
167 CONCATENATE(trace_event_, MONITOR_NAME)(tsk->pid,
168 model_get_state_name(curr_state),
169 model_get_event_name(event),
170 model_get_state_name(next_state),
171 model_is_final_state(next_state));
172 return true;
173 }
174 }
175
176 trace_rv_retries_error(__stringify(MONITOR_NAME), model_get_event_name(event));
177 pr_warn("rv: " __stringify(MAX_DA_RETRY_RACING_EVENTS)
178 " retries reached for event %s, resetting monitor %s",
179 model_get_event_name(event), __stringify(MONITOR_NAME));
180 return false;
181 }
182 #endif /* RV_MON_TYPE */
183
184 #if RV_MON_TYPE == RV_MON_GLOBAL
185 /*
186 * Functions to define, init and get a global monitor.
187 */
188
189 /*
190 * global monitor (a single variable)
191 */
192 static struct da_monitor DA_MON_NAME;
193
194 /*
195 * da_get_monitor - return the global monitor address
196 */
da_get_monitor(void)197 static struct da_monitor *da_get_monitor(void)
198 {
199 return &DA_MON_NAME;
200 }
201
202 /*
203 * da_monitor_reset_all - reset the single monitor
204 */
da_monitor_reset_all(void)205 static void da_monitor_reset_all(void)
206 {
207 da_monitor_reset(da_get_monitor());
208 }
209
210 /*
211 * da_monitor_init - initialize a monitor
212 */
da_monitor_init(void)213 static inline int da_monitor_init(void)
214 {
215 da_monitor_reset_all();
216 return 0;
217 }
218
219 /*
220 * da_monitor_destroy - destroy the monitor
221 */
da_monitor_destroy(void)222 static inline void da_monitor_destroy(void) { }
223
224 #elif RV_MON_TYPE == RV_MON_PER_CPU
225 /*
226 * Functions to define, init and get a per-cpu monitor.
227 */
228
229 /*
230 * per-cpu monitor variables
231 */
232 static DEFINE_PER_CPU(struct da_monitor, DA_MON_NAME);
233
234 /*
235 * da_get_monitor - return current CPU monitor address
236 */
da_get_monitor(void)237 static struct da_monitor *da_get_monitor(void)
238 {
239 return this_cpu_ptr(&DA_MON_NAME);
240 }
241
242 /*
243 * da_monitor_reset_all - reset all CPUs' monitor
244 */
da_monitor_reset_all(void)245 static void da_monitor_reset_all(void)
246 {
247 struct da_monitor *da_mon;
248 int cpu;
249
250 for_each_cpu(cpu, cpu_online_mask) {
251 da_mon = per_cpu_ptr(&DA_MON_NAME, cpu);
252 da_monitor_reset(da_mon);
253 }
254 }
255
256 /*
257 * da_monitor_init - initialize all CPUs' monitor
258 */
da_monitor_init(void)259 static inline int da_monitor_init(void)
260 {
261 da_monitor_reset_all();
262 return 0;
263 }
264
265 /*
266 * da_monitor_destroy - destroy the monitor
267 */
da_monitor_destroy(void)268 static inline void da_monitor_destroy(void) { }
269
270 #elif RV_MON_TYPE == RV_MON_PER_TASK
271 /*
272 * Functions to define, init and get a per-task monitor.
273 */
274
275 /*
276 * The per-task monitor is stored a vector in the task struct. This variable
277 * stores the position on the vector reserved for this monitor.
278 */
279 static int task_mon_slot = RV_PER_TASK_MONITOR_INIT;
280
281 /*
282 * da_get_monitor - return the monitor in the allocated slot for tsk
283 */
da_get_monitor(struct task_struct * tsk)284 static inline struct da_monitor *da_get_monitor(struct task_struct *tsk)
285 {
286 return &tsk->rv[task_mon_slot].da_mon;
287 }
288
da_monitor_reset_all(void)289 static void da_monitor_reset_all(void)
290 {
291 struct task_struct *g, *p;
292 int cpu;
293
294 read_lock(&tasklist_lock);
295 for_each_process_thread(g, p)
296 da_monitor_reset(da_get_monitor(p));
297 for_each_present_cpu(cpu)
298 da_monitor_reset(da_get_monitor(idle_task(cpu)));
299 read_unlock(&tasklist_lock);
300 }
301
302 /*
303 * da_monitor_init - initialize the per-task monitor
304 *
305 * Try to allocate a slot in the task's vector of monitors. If there
306 * is an available slot, use it and reset all task's monitor.
307 */
da_monitor_init(void)308 static int da_monitor_init(void)
309 {
310 int slot;
311
312 slot = rv_get_task_monitor_slot();
313 if (slot < 0 || slot >= RV_PER_TASK_MONITOR_INIT)
314 return slot;
315
316 task_mon_slot = slot;
317
318 da_monitor_reset_all();
319 return 0;
320 }
321
322 /*
323 * da_monitor_destroy - return the allocated slot
324 */
da_monitor_destroy(void)325 static inline void da_monitor_destroy(void)
326 {
327 if (task_mon_slot == RV_PER_TASK_MONITOR_INIT) {
328 WARN_ONCE(1, "Disabling a disabled monitor: " __stringify(MONITOR_NAME));
329 return;
330 }
331 rv_put_task_monitor_slot(task_mon_slot);
332 task_mon_slot = RV_PER_TASK_MONITOR_INIT;
333 }
334 #endif /* RV_MON_TYPE */
335
336 #if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU
337 /*
338 * Handle event for implicit monitor: da_get_monitor() will figure out
339 * the monitor.
340 */
341
__da_handle_event(struct da_monitor * da_mon,enum events event)342 static inline void __da_handle_event(struct da_monitor *da_mon,
343 enum events event)
344 {
345 bool retval;
346
347 retval = da_event(da_mon, event);
348 if (!retval)
349 da_monitor_reset(da_mon);
350 }
351
352 /*
353 * da_handle_event - handle an event
354 */
da_handle_event(enum events event)355 static inline void da_handle_event(enum events event)
356 {
357 struct da_monitor *da_mon = da_get_monitor();
358 bool retval;
359
360 retval = da_monitor_handling_event(da_mon);
361 if (!retval)
362 return;
363
364 __da_handle_event(da_mon, event);
365 }
366
367 /*
368 * da_handle_start_event - start monitoring or handle event
369 *
370 * This function is used to notify the monitor that the system is returning
371 * to the initial state, so the monitor can start monitoring in the next event.
372 * Thus:
373 *
374 * If the monitor already started, handle the event.
375 * If the monitor did not start yet, start the monitor but skip the event.
376 */
da_handle_start_event(enum events event)377 static inline bool da_handle_start_event(enum events event)
378 {
379 struct da_monitor *da_mon;
380
381 if (!da_monitor_enabled())
382 return 0;
383
384 da_mon = da_get_monitor();
385
386 if (unlikely(!da_monitoring(da_mon))) {
387 da_monitor_start(da_mon);
388 return 0;
389 }
390
391 __da_handle_event(da_mon, event);
392
393 return 1;
394 }
395
396 /*
397 * da_handle_start_run_event - start monitoring and handle event
398 *
399 * This function is used to notify the monitor that the system is in the
400 * initial state, so the monitor can start monitoring and handling event.
401 */
da_handle_start_run_event(enum events event)402 static inline bool da_handle_start_run_event(enum events event)
403 {
404 struct da_monitor *da_mon;
405
406 if (!da_monitor_enabled())
407 return 0;
408
409 da_mon = da_get_monitor();
410
411 if (unlikely(!da_monitoring(da_mon)))
412 da_monitor_start(da_mon);
413
414 __da_handle_event(da_mon, event);
415
416 return 1;
417 }
418
419 #elif RV_MON_TYPE == RV_MON_PER_TASK
420 /*
421 * Handle event for per task.
422 */
423
__da_handle_event(struct da_monitor * da_mon,struct task_struct * tsk,enum events event)424 static inline void __da_handle_event(struct da_monitor *da_mon,
425 struct task_struct *tsk, enum events event)
426 {
427 bool retval;
428
429 retval = da_event(da_mon, tsk, event);
430 if (!retval)
431 da_monitor_reset(da_mon);
432 }
433
434 /*
435 * da_handle_event - handle an event
436 */
da_handle_event(struct task_struct * tsk,enum events event)437 static inline void da_handle_event(struct task_struct *tsk, enum events event)
438 {
439 struct da_monitor *da_mon = da_get_monitor(tsk);
440 bool retval;
441
442 retval = da_monitor_handling_event(da_mon);
443 if (!retval)
444 return;
445
446 __da_handle_event(da_mon, tsk, event);
447 }
448
449 /*
450 * da_handle_start_event - start monitoring or handle event
451 *
452 * This function is used to notify the monitor that the system is returning
453 * to the initial state, so the monitor can start monitoring in the next event.
454 * Thus:
455 *
456 * If the monitor already started, handle the event.
457 * If the monitor did not start yet, start the monitor but skip the event.
458 */
da_handle_start_event(struct task_struct * tsk,enum events event)459 static inline bool da_handle_start_event(struct task_struct *tsk,
460 enum events event)
461 {
462 struct da_monitor *da_mon;
463
464 if (!da_monitor_enabled())
465 return 0;
466
467 da_mon = da_get_monitor(tsk);
468
469 if (unlikely(!da_monitoring(da_mon))) {
470 da_monitor_start(da_mon);
471 return 0;
472 }
473
474 __da_handle_event(da_mon, tsk, event);
475
476 return 1;
477 }
478
479 /*
480 * da_handle_start_run_event - start monitoring and handle event
481 *
482 * This function is used to notify the monitor that the system is in the
483 * initial state, so the monitor can start monitoring and handling event.
484 */
da_handle_start_run_event(struct task_struct * tsk,enum events event)485 static inline bool da_handle_start_run_event(struct task_struct *tsk,
486 enum events event)
487 {
488 struct da_monitor *da_mon;
489
490 if (!da_monitor_enabled())
491 return 0;
492
493 da_mon = da_get_monitor(tsk);
494
495 if (unlikely(!da_monitoring(da_mon)))
496 da_monitor_start(da_mon);
497
498 __da_handle_event(da_mon, tsk, event);
499
500 return 1;
501 }
502 #endif /* RV_MON_TYPE */
503
504 #endif
505