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