1/* @title: Lock Validation Layout Types */
2#pragma once
3#include <asm.h>
4#include <atomic.h>
5#include <irq/irq.h>
6#include <sch/irql.h>
7#include <stdbool.h>
8#include <stdint.h>
9#include <sync/lock_chk.h>
10#include <sync/lock_general.h>
11#include <types/types.h>
12
13struct lock_chk_node;
14
15#define LOCK_CHK_MAX_NODES 1024
16#define LOCK_CHK_MAX_EDGES 8192
17#define LOCK_CHK_HASH_BUCKETS 1024
18#define LOCK_CHK_MAX_HELD_LOCKS 32
19#define LOCK_CHK_MAX_SPIN_DEPTH 32
20#define LOCK_CHK_MAX_SUBCLASSES 8
21#define LOCK_CHK_MODE_STATE_COUNT (LOCK_CHK_MAX_NODES * 2)
22
23enum lock_chk_context_bits : uint8_t {
24 LOCK_CHK_CTX_IRQ = 1 << 0,
25 LOCK_CHK_CTX_SPIN_DISPATCH = 1 << 1,
26 LOCK_CHK_CTX_SPIN_HIGH = 1 << 2,
27 LOCK_CHK_CTX_RAW_OPERATION = 1 << 3,
28};
29
30#ifdef DEBUG_LOCK_CHK
31
32struct lock_chk_map {
33 const struct lock_chk_class *class;
34 struct lock_chk_class instance_class;
35 atomic(struct lock_chk_node *) base_node;
36};
37
38struct lock_chk_lock {
39 atomic_bool used;
40 struct lock_chk_map map;
41 void *instance;
42
43 enum lock_chk_type type : 4;
44 enum lock_chk_flags flags : 4;
45 bool initialized : 1;
46 bool manages_irql : 1;
47 bool raw_operation : 1;
48};
49
50struct lock_chk_id {
51 void *instance;
52 enum lock_chk_type type;
53 enum lock_chk_flags flags;
54};
55
56static inline struct lock_chk_id
57lock_chk_id_of(const struct lock_chk_lock *lock) {
58 return (struct lock_chk_id) {
59 .instance = lock->instance,
60 .type = lock->type,
61 .flags = lock->flags,
62 };
63}
64
65struct lock_chk_held {
66 struct lock_chk_node *node;
67 struct lock_chk_id lock;
68 const struct lock_chk_site *acquire_site;
69 uint64_t acquire_tsc;
70 enum irql prev_irql;
71 uint16_t cpu; /* TODO: We use this to represent CPU due to size,
72 * cpu_id_t is a size_t */
73 enum lock_chk_mode mode;
74 enum lock_subclass subclass;
75 bool trylock;
76 bool raw_operation;
77};
78
79struct lock_chk_thread_data {
80 struct lock_chk_held held[LOCK_CHK_MAX_HELD_LOCKS];
81 uint8_t depth;
82 uint8_t thread_checked_depth;
83 uint8_t thread_checked_spin_depth;
84};
85
86struct lock_chk_acq_req {
87 struct lock_chk_map *map;
88 struct lock_chk_id lock;
89 const struct lock_chk_site *site;
90 enum lock_chk_mode mode;
91 enum irql prev_irql;
92 enum lock_subclass subclass;
93 enum lock_op_flags op_flags;
94 bool irqs_enabled : 1;
95 bool in_irq : 1;
96 bool in_nmi : 1;
97};
98
99struct lock_chk_acq_token {
100 struct lock_chk_node *node;
101 struct lock_chk_node *context_node;
102 const struct lock_chk_acq_req *request;
103 struct lock_chk_thread_data *thread_data;
104 bool active;
105};
106
107struct lock_chk_rel_req {
108 struct lock_chk_map *map;
109 struct lock_chk_id lock;
110 const struct lock_chk_site *site;
111 enum lock_chk_mode mode;
112};
113
114struct lock_chk_rel_token {
115 struct lock_chk_thread_data *thread_data;
116 void *instance;
117 uint8_t held_index;
118 bool active;
119};
120
121void lock_chk_before_acq(struct lock_chk_acq_token *token,
122 const struct lock_chk_acq_req *request);
123void lock_chk_acqd(struct lock_chk_acq_token *token);
124void lock_chk_cancel(struct lock_chk_acq_token *token);
125void lock_chk_before_rel(struct lock_chk_rel_token *token,
126 const struct lock_chk_rel_req *request);
127void lock_chk_reld(struct lock_chk_rel_token *token);
128
129/* LOCK_CHK_ASSERT_HELD/NOT_HELD and whatnot use this, which
130 * returns true if the engine could evaluate the assertion,
131 * and otherwise will return false, and panic if a violation is found */
132bool lock_chk_assert_held_deep(struct lock_chk_lock *lock,
133 enum lock_chk_mode mode, bool want_held,
134 const struct lock_chk_site *site);
135
136#define LOCK_CHK_MAP_VALUE_INIT(class_) \
137 ((struct lock_chk_map) { \
138 .class = (class_), \
139 .instance_class = \
140 { \
141 .name = "<instance>", \
142 .file = __RELFILE__, \
143 .line = __LINE__, \
144 }, \
145 .base_node = ATOMIC_VAR_INIT(NULL), \
146 })
147
148#define LOCK_CHK_LOCK_VALUE_INIT(class_, flags_) \
149 ((struct lock_chk_lock) { \
150 .flags = (flags_), \
151 .initialized = true, \
152 .used = ATOMIC_VAR_INIT(false), \
153 .map = LOCK_CHK_MAP_VALUE_INIT(class_), \
154 })
155
156static inline void
157lock_chk_map_runtime_init(struct lock_chk_map *map,
158 const struct lock_chk_class *class) {
159 map->class = class;
160 map->instance_class = (struct lock_chk_class) {
161 .name = "<instance>",
162 .file = __RELFILE__,
163 .line = 0,
164 };
165 atomic_store_rlx(&map->base_node, NULL);
166}
167
168static inline struct lock_chk_acq_req
169lock_chk_acq_req_make(struct lock_chk_lock *lock,
170 const struct lock_chk_site *site, enum lock_chk_mode mode,
171 enum lock_subclass subclass, enum lock_op_flags flags) {
172 return (struct lock_chk_acq_req) {
173 .map = &lock->map,
174 .lock = lock_chk_id_of(lock),
175 .site = site,
176 .mode = mode,
177 .prev_irql = irql_get(),
178 .subclass = subclass,
179 .op_flags = flags,
180 .irqs_enabled = irqs_enabled(),
181 .in_irq = irq_in_interrupt(),
182 .in_nmi = irq_in_nmi(),
183 };
184}
185
186static inline struct lock_chk_rel_req
187lock_chk_rel_req_make(struct lock_chk_lock *lock,
188 const struct lock_chk_site *site,
189 enum lock_chk_mode mode) {
190 return (struct lock_chk_rel_req) {
191 .map = &lock->map,
192 .lock = lock_chk_id_of(lock),
193 .site = site,
194 .mode = mode,
195 };
196}
197
198#endif /* DEBUG_LOCK_CHK */
199