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