1#include <uacpi/platform/atomic.h>
2#include <uacpi/internal/osi.h>
3#include <uacpi/internal/helpers.h>
4#include <uacpi/internal/stdlib.h>
5#include <uacpi/internal/utilities.h>
6#include <uacpi/kernel_api.h>
7
8struct registered_interface {
9 const uacpi_char *name;
10 uacpi_u8 weight;
11 uacpi_u8 kind;
12
13 // Only applicable for predefined host interfaces
14 uacpi_u8 host_type;
15
16 // Only applicable for predefined interfaces
17 uacpi_u8 disabled : 1;
18 uacpi_u8 dynamic : 1;
19
20 struct registered_interface *next;
21};
22
23static uacpi_handle interface_mutex;
24static struct registered_interface *registered_interfaces;
25static uacpi_interface_handler interface_handler;
26static uacpi_u32 latest_queried_interface;
27
28#define WINDOWS(string, interface) \
29 { \
30 .name = "Windows "string, \
31 .weight = UACPI_VENDOR_INTERFACE_WINDOWS_##interface, \
32 .kind = UACPI_INTERFACE_KIND_VENDOR, \
33 .host_type = 0, \
34 .disabled = 0, \
35 .dynamic = 0, \
36 .next = UACPI_NULL \
37 }
38
39#define HOST_FEATURE(string, type) \
40 { \
41 .name = string, \
42 .weight = 0, \
43 .kind = UACPI_INTERFACE_KIND_FEATURE, \
44 .host_type = UACPI_HOST_INTERFACE_##type, \
45 .disabled = 1, \
46 .dynamic = 0, \
47 .next = UACPI_NULL, \
48 }
49
50static struct registered_interface predefined_interfaces[] = {
51 // Vendor strings
52 WINDOWS("2000", 2000),
53 WINDOWS("2001", XP),
54 WINDOWS("2001 SP1", XP_SP1),
55 WINDOWS("2001.1", SERVER_2003),
56 WINDOWS("2001 SP2", XP_SP2),
57 WINDOWS("2001.1 SP1", SERVER_2003_SP1),
58 WINDOWS("2006", VISTA),
59 WINDOWS("2006.1", SERVER_2008),
60 WINDOWS("2006 SP1", VISTA_SP1),
61 WINDOWS("2006 SP2", VISTA_SP2),
62 WINDOWS("2009", 7),
63 WINDOWS("2012", 8),
64 WINDOWS("2013", 8_1),
65 WINDOWS("2015", 10),
66 WINDOWS("2016", 10_RS1),
67 WINDOWS("2017", 10_RS2),
68 WINDOWS("2017.2", 10_RS3),
69 WINDOWS("2018", 10_RS4),
70 WINDOWS("2018.2", 10_RS5),
71 WINDOWS("2019", 10_19H1),
72 WINDOWS("2020", 10_20H1),
73 WINDOWS("2021", 11),
74 WINDOWS("2022", 11_22H2),
75
76 // Feature strings
77 HOST_FEATURE("Module Device", MODULE_DEVICE),
78 HOST_FEATURE("Processor Device", PROCESSOR_DEVICE),
79 HOST_FEATURE("3.0 Thermal Model", 3_0_THERMAL_MODEL),
80 HOST_FEATURE("3.0 _SCP Extensions", 3_0_SCP_EXTENSIONS),
81 HOST_FEATURE("Processor Aggregator Device", PROCESSOR_AGGREGATOR_DEVICE),
82
83 // Interpreter features
84 { .name = "Extended Address Space Descriptor" },
85};
86
87uacpi_status uacpi_initialize_interfaces(void)
88{
89 uacpi_size i;
90
91 registered_interfaces = &predefined_interfaces[0];
92
93 interface_mutex = uacpi_kernel_create_mutex();
94 if (uacpi_unlikely(interface_mutex == UACPI_NULL))
95 return UACPI_STATUS_OUT_OF_MEMORY;
96
97 for (i = 0; i < (UACPI_ARRAY_SIZE(predefined_interfaces) - 1); ++i)
98 predefined_interfaces[i].next = &predefined_interfaces[i + 1];
99
100 return UACPI_STATUS_OK;
101}
102
103uacpi_vendor_interface uacpi_latest_queried_vendor_interface(void)
104{
105 return uacpi_atomic_load32(&latest_queried_interface);
106}
107
108static struct registered_interface *find_interface_unlocked(
109 const uacpi_char *name
110)
111{
112 struct registered_interface *interface = registered_interfaces;
113
114 while (interface) {
115 if (uacpi_strcmp(lhs: interface->name, rhs: name) == 0)
116 return interface;
117
118 interface = interface->next;
119 }
120
121 return UACPI_NULL;
122}
123
124static struct registered_interface *find_host_interface_unlocked(
125 uacpi_host_interface type
126)
127{
128 struct registered_interface *interface = registered_interfaces;
129
130 while (interface) {
131 if (interface->host_type == type)
132 return interface;
133
134 interface = interface->next;
135 }
136
137 return UACPI_NULL;
138}
139
140uacpi_status uacpi_install_interface(
141 const uacpi_char *name, uacpi_interface_kind kind
142)
143{
144 struct registered_interface *interface;
145 uacpi_status ret = UACPI_STATUS_ALREADY_EXISTS;
146 uacpi_char *name_copy;
147 uacpi_size name_size;
148
149 UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED);
150
151 UACPI_MUTEX_ACQUIRE(interface_mutex);
152
153 interface = find_interface_unlocked(name);
154 if (interface != UACPI_NULL) {
155 if (interface->disabled) {
156 interface->disabled = UACPI_FALSE;
157 ret = UACPI_STATUS_OK;
158 }
159 goto out;
160 }
161
162 interface = uacpi_kernel_alloc(size: sizeof(*interface));
163 if (uacpi_unlikely(interface == UACPI_NULL)) {
164 ret = UACPI_STATUS_OUT_OF_MEMORY;
165 goto out;
166 }
167
168 name_size = uacpi_strlen(str: name) + 1;
169 name_copy = uacpi_kernel_alloc(size: name_size);
170 if (uacpi_unlikely(name_copy == UACPI_NULL)) {
171 uacpi_free(interface, sizeof(*interface));
172 ret = UACPI_STATUS_OUT_OF_MEMORY;
173 goto out;
174 }
175
176 uacpi_memcpy(dest: name_copy, src: name, count: name_size);
177 interface->name = name_copy;
178 interface->weight = 0;
179 interface->kind = kind;
180 interface->host_type = 0;
181 interface->disabled = 0;
182 interface->dynamic = 1;
183 interface->next = registered_interfaces;
184 registered_interfaces = interface;
185 ret = UACPI_STATUS_OK;
186
187out:
188 UACPI_MUTEX_RELEASE(interface_mutex);
189 return ret;
190}
191
192uacpi_status uacpi_uninstall_interface(const uacpi_char *name)
193{
194 struct registered_interface *cur, *prev;
195 uacpi_status ret = UACPI_STATUS_NOT_FOUND;
196
197 UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED);
198
199 UACPI_MUTEX_ACQUIRE(interface_mutex);
200
201 cur = registered_interfaces;
202 prev = cur;
203
204 while (cur) {
205 if (uacpi_strcmp(lhs: cur->name, rhs: name) != 0) {
206 prev = cur;
207 cur = cur->next;
208 continue;
209 }
210
211 if (cur->dynamic) {
212 if (prev == cur) {
213 registered_interfaces = cur->next;
214 } else {
215 prev->next = cur->next;
216 }
217
218 UACPI_MUTEX_RELEASE(interface_mutex);
219 uacpi_free_dynamic_string(str: cur->name);
220 uacpi_free(cur, sizeof(*cur));
221 return UACPI_STATUS_OK;
222 }
223
224 /*
225 * If this interface was already disabled, pretend we didn't actually
226 * find it and keep ret as UACPI_STATUS_NOT_FOUND. The fact that it's
227 * still in the registered list is an implementation detail of
228 * predefined interfaces.
229 */
230 if (!cur->disabled) {
231 cur->disabled = UACPI_TRUE;
232 ret = UACPI_STATUS_OK;
233 }
234
235 break;
236 }
237
238 UACPI_MUTEX_RELEASE(interface_mutex);
239 return ret;
240}
241
242static uacpi_status configure_host_interface(
243 uacpi_host_interface type, uacpi_bool enabled
244)
245{
246 struct registered_interface *interface;
247 uacpi_status ret = UACPI_STATUS_NOT_FOUND;
248
249 UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED);
250
251 UACPI_MUTEX_ACQUIRE(interface_mutex);
252
253 interface = find_host_interface_unlocked(type);
254 if (interface == UACPI_NULL)
255 goto out;
256
257 interface->disabled = !enabled;
258 ret = UACPI_STATUS_OK;
259
260out:
261 UACPI_MUTEX_RELEASE(interface_mutex);
262 return ret;
263}
264
265uacpi_status uacpi_enable_host_interface(uacpi_host_interface type)
266{
267 return configure_host_interface(type, UACPI_TRUE);
268}
269
270uacpi_status uacpi_disable_host_interface(uacpi_host_interface type)
271{
272 return configure_host_interface(type, UACPI_FALSE);
273}
274
275uacpi_status uacpi_set_interface_query_handler(
276 uacpi_interface_handler handler
277)
278{
279 uacpi_status ret = UACPI_STATUS_ALREADY_EXISTS;
280
281 UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED);
282
283 UACPI_MUTEX_ACQUIRE(interface_mutex);
284
285 if (interface_handler != UACPI_NULL && handler != UACPI_NULL)
286 goto out;
287
288 interface_handler = handler;
289 ret = UACPI_STATUS_OK;
290
291out:
292 UACPI_MUTEX_RELEASE(interface_mutex);
293 return ret;
294}
295
296uacpi_status uacpi_bulk_configure_interfaces(
297 uacpi_interface_action action, uacpi_interface_kind kind
298)
299{
300 struct registered_interface *interface;
301
302 UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED);
303
304 UACPI_MUTEX_ACQUIRE(interface_mutex);
305
306 interface = registered_interfaces;
307 while (interface) {
308 if (kind & interface->kind)
309 interface->disabled = (action == UACPI_INTERFACE_ACTION_DISABLE);
310
311 interface = interface->next;
312 }
313
314 UACPI_MUTEX_RELEASE(interface_mutex);
315 return UACPI_STATUS_OK;
316}
317
318uacpi_status uacpi_handle_osi(const uacpi_char *string, uacpi_bool *out_value)
319{
320 struct registered_interface *interface;
321 uacpi_bool is_supported = UACPI_FALSE;
322
323 UACPI_MUTEX_ACQUIRE(interface_mutex);
324
325 interface = find_interface_unlocked(name: string);
326 if (interface == UACPI_NULL)
327 goto out;
328
329 if (interface->weight > latest_queried_interface)
330 uacpi_atomic_store32(&latest_queried_interface, interface->weight);
331
332 is_supported = !interface->disabled;
333 if (interface_handler)
334 is_supported = interface_handler(string, is_supported);
335out:
336 UACPI_MUTEX_RELEASE(interface_mutex);
337 *out_value = is_supported;
338 return UACPI_STATUS_OK;
339}
340