1#include <uacpi/types.h>
2#include <uacpi/status.h>
3
4#include <uacpi/internal/context.h>
5#include <uacpi/internal/utilities.h>
6#include <uacpi/internal/log.h>
7#include <uacpi/uacpi.h>
8
9void uacpi_eisa_id_to_string(uacpi_u32 id, uacpi_char *out_string)
10{
11 static uacpi_char hex_to_ascii[16] = {
12 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
13 'A', 'B', 'C', 'D', 'E', 'F'
14 };
15
16 /*
17 * For whatever reason bits are encoded upper to lower here, swap
18 * them around so that we don't have to do ridiculous bit shifts
19 * everywhere.
20 */
21 union {
22 uacpi_u8 bytes[4];
23 uacpi_u32 dword;
24 } orig, swapped;
25
26 orig.dword = id;
27 swapped.bytes[0] = orig.bytes[3];
28 swapped.bytes[1] = orig.bytes[2];
29 swapped.bytes[2] = orig.bytes[1];
30 swapped.bytes[3] = orig.bytes[0];
31
32 /*
33 * Bit 16 - 20: 3rd character (- 0x40) of mfg code
34 * Bit 21 - 25: 2nd character (- 0x40) of mfg code
35 * Bit 26 - 30: 1st character (- 0x40) of mfg code
36 */
37 out_string[0] = (uacpi_char)(0x40 + ((swapped.dword >> 26) & 0x1F));
38 out_string[1] = (uacpi_char)(0x40 + ((swapped.dword >> 21) & 0x1F));
39 out_string[2] = (uacpi_char)(0x40 + ((swapped.dword >> 16) & 0x1F));
40
41 /*
42 * Bit 0 - 3 : 4th hex digit of product number
43 * Bit 4 - 7 : 3rd hex digit of product number
44 * Bit 8 - 11: 2nd hex digit of product number
45 * Bit 12 - 15: 1st hex digit of product number
46 */
47 out_string[3] = hex_to_ascii[(swapped.dword >> 12) & 0x0F];
48 out_string[4] = hex_to_ascii[(swapped.dword >> 8 ) & 0x0F];
49 out_string[5] = hex_to_ascii[(swapped.dword >> 4 ) & 0x0F];
50 out_string[6] = hex_to_ascii[(swapped.dword >> 0 ) & 0x0F];
51
52 out_string[7] = '\0';
53}
54
55enum char_type {
56 CHAR_TYPE_CONTROL = 1 << 0,
57 CHAR_TYPE_SPACE = 1 << 1,
58 CHAR_TYPE_BLANK = 1 << 2,
59 CHAR_TYPE_PUNCTUATION = 1 << 3,
60 CHAR_TYPE_LOWER = 1 << 4,
61 CHAR_TYPE_UPPER = 1 << 5,
62 CHAR_TYPE_DIGIT = 1 << 6,
63 CHAR_TYPE_HEX_DIGIT = 1 << 7,
64 CHAR_TYPE_ALPHA = CHAR_TYPE_LOWER | CHAR_TYPE_UPPER,
65 CHAR_TYPE_ALHEX = CHAR_TYPE_ALPHA | CHAR_TYPE_HEX_DIGIT,
66 CHAR_TYPE_ALNUM = CHAR_TYPE_ALPHA | CHAR_TYPE_DIGIT,
67};
68
69static const uacpi_u8 ascii_map[256] = {
70 CHAR_TYPE_CONTROL, // 0
71 CHAR_TYPE_CONTROL, // 1
72 CHAR_TYPE_CONTROL, // 2
73 CHAR_TYPE_CONTROL, // 3
74 CHAR_TYPE_CONTROL, // 4
75 CHAR_TYPE_CONTROL, // 5
76 CHAR_TYPE_CONTROL, // 6
77 CHAR_TYPE_CONTROL, // 7
78 CHAR_TYPE_CONTROL, // -> 8 control codes
79
80 CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE | CHAR_TYPE_BLANK, // 9 tab
81
82 CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE, // 10
83 CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE, // 11
84 CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE, // 12
85 CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE, // -> 13 whitespaces
86
87 CHAR_TYPE_CONTROL, // 14
88 CHAR_TYPE_CONTROL, // 15
89 CHAR_TYPE_CONTROL, // 16
90 CHAR_TYPE_CONTROL, // 17
91 CHAR_TYPE_CONTROL, // 18
92 CHAR_TYPE_CONTROL, // 19
93 CHAR_TYPE_CONTROL, // 20
94 CHAR_TYPE_CONTROL, // 21
95 CHAR_TYPE_CONTROL, // 22
96 CHAR_TYPE_CONTROL, // 23
97 CHAR_TYPE_CONTROL, // 24
98 CHAR_TYPE_CONTROL, // 25
99 CHAR_TYPE_CONTROL, // 26
100 CHAR_TYPE_CONTROL, // 27
101 CHAR_TYPE_CONTROL, // 28
102 CHAR_TYPE_CONTROL, // 29
103 CHAR_TYPE_CONTROL, // 30
104 CHAR_TYPE_CONTROL, // -> 31 control codes
105
106 CHAR_TYPE_SPACE | CHAR_TYPE_BLANK, // 32 space
107
108 CHAR_TYPE_PUNCTUATION, // 33
109 CHAR_TYPE_PUNCTUATION, // 34
110 CHAR_TYPE_PUNCTUATION, // 35
111 CHAR_TYPE_PUNCTUATION, // 36
112 CHAR_TYPE_PUNCTUATION, // 37
113 CHAR_TYPE_PUNCTUATION, // 38
114 CHAR_TYPE_PUNCTUATION, // 39
115 CHAR_TYPE_PUNCTUATION, // 40
116 CHAR_TYPE_PUNCTUATION, // 41
117 CHAR_TYPE_PUNCTUATION, // 42
118 CHAR_TYPE_PUNCTUATION, // 43
119 CHAR_TYPE_PUNCTUATION, // 44
120 CHAR_TYPE_PUNCTUATION, // 45
121 CHAR_TYPE_PUNCTUATION, // 46
122 CHAR_TYPE_PUNCTUATION, // -> 47 punctuation
123
124 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 48
125 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 49
126 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 50
127 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 51
128 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 52
129 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 53
130 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 54
131 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 55
132 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 56
133 CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // -> 57 digits
134
135 CHAR_TYPE_PUNCTUATION, // 58
136 CHAR_TYPE_PUNCTUATION, // 59
137 CHAR_TYPE_PUNCTUATION, // 60
138 CHAR_TYPE_PUNCTUATION, // 61
139 CHAR_TYPE_PUNCTUATION, // 62
140 CHAR_TYPE_PUNCTUATION, // 63
141 CHAR_TYPE_PUNCTUATION, // -> 64 punctuation
142
143 CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 65
144 CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 66
145 CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 67
146 CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 68
147 CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 69
148 CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // -> 70 ABCDEF
149
150 CHAR_TYPE_UPPER, // 71
151 CHAR_TYPE_UPPER, // 72
152 CHAR_TYPE_UPPER, // 73
153 CHAR_TYPE_UPPER, // 74
154 CHAR_TYPE_UPPER, // 75
155 CHAR_TYPE_UPPER, // 76
156 CHAR_TYPE_UPPER, // 77
157 CHAR_TYPE_UPPER, // 78
158 CHAR_TYPE_UPPER, // 79
159 CHAR_TYPE_UPPER, // 80
160 CHAR_TYPE_UPPER, // 81
161 CHAR_TYPE_UPPER, // 82
162 CHAR_TYPE_UPPER, // 83
163 CHAR_TYPE_UPPER, // 84
164 CHAR_TYPE_UPPER, // 85
165 CHAR_TYPE_UPPER, // 86
166 CHAR_TYPE_UPPER, // 87
167 CHAR_TYPE_UPPER, // 88
168 CHAR_TYPE_UPPER, // 89
169 CHAR_TYPE_UPPER, // -> 90 the rest of UPPERCASE alphabet
170
171 CHAR_TYPE_PUNCTUATION, // 91
172 CHAR_TYPE_PUNCTUATION, // 92
173 CHAR_TYPE_PUNCTUATION, // 93
174 CHAR_TYPE_PUNCTUATION, // 94
175 CHAR_TYPE_PUNCTUATION, // 95
176 CHAR_TYPE_PUNCTUATION, // -> 96 punctuation
177
178 CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 97
179 CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 98
180 CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 99
181 CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 100
182 CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 101
183 CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // -> 102 abcdef
184
185 CHAR_TYPE_LOWER, // 103
186 CHAR_TYPE_LOWER, // 104
187 CHAR_TYPE_LOWER, // 105
188 CHAR_TYPE_LOWER, // 106
189 CHAR_TYPE_LOWER, // 107
190 CHAR_TYPE_LOWER, // 108
191 CHAR_TYPE_LOWER, // 109
192 CHAR_TYPE_LOWER, // 110
193 CHAR_TYPE_LOWER, // 111
194 CHAR_TYPE_LOWER, // 112
195 CHAR_TYPE_LOWER, // 113
196 CHAR_TYPE_LOWER, // 114
197 CHAR_TYPE_LOWER, // 115
198 CHAR_TYPE_LOWER, // 116
199 CHAR_TYPE_LOWER, // 117
200 CHAR_TYPE_LOWER, // 118
201 CHAR_TYPE_LOWER, // 119
202 CHAR_TYPE_LOWER, // 120
203 CHAR_TYPE_LOWER, // 121
204 CHAR_TYPE_LOWER, // -> 122 the rest of UPPERCASE alphabet
205
206 CHAR_TYPE_PUNCTUATION, // 123
207 CHAR_TYPE_PUNCTUATION, // 124
208 CHAR_TYPE_PUNCTUATION, // 125
209 CHAR_TYPE_PUNCTUATION, // -> 126 punctuation
210
211 CHAR_TYPE_CONTROL // 127 backspace
212};
213
214static inline uacpi_bool is_valid_name_byte(uacpi_u8 c)
215{
216 // ‘_’ := 0x5F
217 if (c == 0x5F)
218 return UACPI_TRUE;
219
220 /*
221 * LeadNameChar := ‘A’-‘Z’ | ‘_’
222 * DigitChar := ‘0’ - ‘9’
223 * NameChar := DigitChar | LeadNameChar
224 * ‘A’-‘Z’ := 0x41 - 0x5A
225 * ‘0’-‘9’ := 0x30 - 0x39
226 */
227 return (ascii_map[c] & (CHAR_TYPE_DIGIT | CHAR_TYPE_UPPER)) != 0;
228}
229
230uacpi_bool uacpi_is_valid_nameseg(uacpi_u8 *nameseg)
231{
232 return is_valid_name_byte(c: nameseg[0]) &&
233 is_valid_name_byte(c: nameseg[1]) &&
234 is_valid_name_byte(c: nameseg[2]) &&
235 is_valid_name_byte(c: nameseg[3]);
236}
237
238static uacpi_bool is_char(uacpi_char c, enum char_type type)
239{
240 return (ascii_map[(uacpi_u8)c] & type) == type;
241}
242
243static uacpi_char to_lower(uacpi_char c)
244{
245 if (is_char(c, type: CHAR_TYPE_UPPER))
246 return c + ('a' - 'A');
247
248 return c;
249}
250
251static uacpi_bool peek_one(
252 const uacpi_char **str, const uacpi_size *size, uacpi_char *out_char
253)
254{
255 if (*size == 0)
256 return UACPI_FALSE;
257
258 *out_char = **str;
259 return UACPI_TRUE;
260}
261
262static uacpi_bool consume_one(
263 const uacpi_char **str, uacpi_size *size, uacpi_char *out_char
264)
265{
266 if (!peek_one(str, size, out_char))
267 return UACPI_FALSE;
268
269 *str += 1;
270 *size -= 1;
271 return UACPI_TRUE;
272}
273
274static uacpi_bool consume_if(
275 const uacpi_char **str, uacpi_size *size, enum char_type type
276)
277{
278 uacpi_char c;
279
280 if (!peek_one(str, size, out_char: &c) || !is_char(c, type))
281 return UACPI_FALSE;
282
283 *str += 1;
284 *size -= 1;
285 return UACPI_TRUE;
286}
287
288static uacpi_bool consume_if_equals(
289 const uacpi_char **str, uacpi_size *size, uacpi_char c
290)
291{
292 uacpi_char c1;
293
294 if (!peek_one(str, size, out_char: &c1) || to_lower(c: c1) != c)
295 return UACPI_FALSE;
296
297 *str += 1;
298 *size -= 1;
299 return UACPI_TRUE;
300}
301
302uacpi_status uacpi_string_to_integer(
303 const uacpi_char *str, uacpi_size max_chars, enum uacpi_base base,
304 uacpi_u64 *out_value
305)
306{
307 uacpi_status ret = UACPI_STATUS_INVALID_ARGUMENT;
308 uacpi_bool negative = UACPI_FALSE;
309 uacpi_u64 next, value = 0;
310 uacpi_char c = '\0';
311
312 while (consume_if(str: &str, size: &max_chars, type: CHAR_TYPE_SPACE));
313
314 if (consume_if_equals(str: &str, size: &max_chars, c: '-'))
315 negative = UACPI_TRUE;
316 else
317 consume_if_equals(str: &str, size: &max_chars, c: '+');
318
319 if (base == UACPI_BASE_AUTO) {
320 base = UACPI_BASE_DEC;
321
322 if (consume_if_equals(str: &str, size: &max_chars, c: '0')) {
323 base = UACPI_BASE_OCT;
324 if (consume_if_equals(str: &str, size: &max_chars, c: 'x'))
325 base = UACPI_BASE_HEX;
326 }
327 }
328
329 while (consume_one(str: &str, size: &max_chars, out_char: &c)) {
330 switch (ascii_map[(uacpi_u8)c] & (CHAR_TYPE_DIGIT | CHAR_TYPE_ALHEX)) {
331 case CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT:
332 next = c - '0';
333 if (base == UACPI_BASE_OCT && next > 7)
334 goto out;
335 break;
336 case CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT:
337 case CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT:
338 if (base != UACPI_BASE_HEX)
339 goto out;
340 next = 10 + (to_lower(c) - 'a');
341 break;
342 default:
343 goto out;
344 }
345
346 next = (value * base) + next;
347 if ((next / base) != value) {
348 value = 0xFFFFFFFFFFFFFFFF;
349 goto out;
350 }
351
352 value = next;
353 }
354
355out:
356 if (negative)
357 value = -((uacpi_i64)value);
358
359 *out_value = value;
360 if (max_chars == 0 || c == '\0')
361 ret = UACPI_STATUS_OK;
362
363 return ret;
364}
365
366#define PNP_ID_LENGTH 8
367
368uacpi_status uacpi_eval_hid(uacpi_namespace_node *node, uacpi_id_string **out_id)
369{
370 uacpi_status ret;
371 uacpi_object *hid_ret;
372 uacpi_id_string *id;
373 uacpi_u32 size;
374
375 ret = uacpi_eval_typed(
376 parent: node, path: "_HID", UACPI_NULL,
377 UACPI_OBJECT_INTEGER_BIT | UACPI_OBJECT_STRING_BIT,
378 ret: &hid_ret
379 );
380 if (ret != UACPI_STATUS_OK)
381 return ret;
382
383 size = sizeof(uacpi_id_string);
384
385 switch (hid_ret->type) {
386 case UACPI_OBJECT_STRING: {
387 uacpi_buffer *buf = hid_ret->buffer;
388
389 size += buf->size;
390 if (uacpi_unlikely(buf->size == 0 || size < buf->size)) {
391 uacpi_error(
392 "%.4s._HID: empty/invalid EISA ID string (%zu bytes)\n",
393 uacpi_namespace_node_name(node).text, buf->size
394 );
395 ret = UACPI_STATUS_AML_BAD_ENCODING;
396 break;
397 }
398
399 id = uacpi_kernel_alloc(size);
400 if (uacpi_unlikely(id == UACPI_NULL)) {
401 ret = UACPI_STATUS_OUT_OF_MEMORY;
402 break;
403 }
404 id->size = buf->size;
405 id->value = UACPI_PTR_ADD(id, sizeof(uacpi_id_string));
406
407 uacpi_memcpy(dest: id->value, src: buf->text, count: buf->size);
408 id->value[buf->size - 1] = '\0';
409 break;
410 }
411
412 case UACPI_OBJECT_INTEGER:
413 size += PNP_ID_LENGTH;
414
415 id = uacpi_kernel_alloc(size);
416 if (uacpi_unlikely(id == UACPI_NULL)) {
417 ret = UACPI_STATUS_OUT_OF_MEMORY;
418 break;
419 }
420 id->size = PNP_ID_LENGTH;
421 id->value = UACPI_PTR_ADD(id, sizeof(uacpi_id_string));
422
423 uacpi_eisa_id_to_string(id: hid_ret->integer, out_string: id->value);
424 break;
425 }
426
427 uacpi_object_unref(obj: hid_ret);
428 if (uacpi_likely_success(ret))
429 *out_id = id;
430 return ret;
431}
432
433void uacpi_free_id_string(uacpi_id_string *id)
434{
435 if (id == UACPI_NULL)
436 return;
437
438 uacpi_free(id, sizeof(uacpi_id_string) + id->size);
439}
440
441uacpi_status uacpi_eval_cid(
442 uacpi_namespace_node *node, uacpi_pnp_id_list **out_list
443)
444{
445 uacpi_status ret;
446 uacpi_object *object, *cid_ret;
447 uacpi_object **objects;
448 uacpi_size num_ids, i;
449 uacpi_u32 size;
450 uacpi_id_string *id;
451 uacpi_char *id_buffer;
452 uacpi_pnp_id_list *list;
453
454 ret = uacpi_eval_typed(
455 parent: node, path: "_CID", UACPI_NULL,
456 UACPI_OBJECT_INTEGER_BIT | UACPI_OBJECT_STRING_BIT |
457 UACPI_OBJECT_PACKAGE_BIT,
458 ret: &cid_ret
459 );
460 if (ret != UACPI_STATUS_OK)
461 return ret;
462
463 switch (cid_ret->type) {
464 case UACPI_OBJECT_PACKAGE:
465 objects = cid_ret->package->objects;
466 num_ids = cid_ret->package->count;
467 break;
468 default:
469 objects = &cid_ret;
470 num_ids = 1;
471 break;
472 }
473
474 size = sizeof(uacpi_pnp_id_list);
475 size += num_ids * sizeof(uacpi_id_string);
476
477 for (i = 0; i < num_ids; ++i) {
478 object = objects[i];
479
480 switch (object->type) {
481 case UACPI_OBJECT_STRING: {
482 uacpi_size buf_size = object->buffer->size;
483
484 if (uacpi_unlikely(buf_size == 0)) {
485 uacpi_error(
486 "%.4s._CID: empty EISA ID string (sub-object %zu)\n",
487 uacpi_namespace_node_name(node).text, i
488 );
489 return UACPI_STATUS_AML_INCOMPATIBLE_OBJECT_TYPE;
490 }
491
492 size += buf_size;
493 if (uacpi_unlikely(size < buf_size)) {
494 uacpi_error(
495 "%.4s._CID: buffer size overflow (+ %zu)\n",
496 uacpi_namespace_node_name(node).text, buf_size
497 );
498 return UACPI_STATUS_AML_BAD_ENCODING;
499 }
500
501 break;
502 }
503
504 case UACPI_OBJECT_INTEGER:
505 size += PNP_ID_LENGTH;
506 break;
507 default:
508 uacpi_error(
509 "%.4s._CID: invalid package sub-object %zu type: %s\n",
510 uacpi_namespace_node_name(node).text, i,
511 uacpi_object_type_to_string(object->type)
512 );
513 return UACPI_STATUS_AML_INCOMPATIBLE_OBJECT_TYPE;
514 }
515 }
516
517 list = uacpi_kernel_alloc(size);
518 if (uacpi_unlikely(list == UACPI_NULL))
519 return UACPI_STATUS_OUT_OF_MEMORY;
520 list->num_ids = num_ids;
521 list->size = size - sizeof(uacpi_pnp_id_list);
522
523 id_buffer = UACPI_PTR_ADD(list, sizeof(uacpi_pnp_id_list));
524 id_buffer += num_ids * sizeof(uacpi_id_string);
525
526 for (i = 0; i < num_ids; ++i) {
527 object = objects[i];
528 id = &list->ids[i];
529
530 switch (object->type) {
531 case UACPI_OBJECT_STRING: {
532 uacpi_buffer *buf = object->buffer;
533
534 id->size = buf->size;
535 id->value = id_buffer;
536
537 uacpi_memcpy(dest: id->value, src: buf->text, count: id->size);
538 id->value[id->size - 1] = '\0';
539 break;
540 }
541
542 case UACPI_OBJECT_INTEGER:
543 id->size = PNP_ID_LENGTH;
544 id->value = id_buffer;
545 uacpi_eisa_id_to_string(id: object->integer, out_string: id_buffer);
546 break;
547 }
548
549 id_buffer += id->size;
550 }
551
552 uacpi_object_unref(obj: cid_ret);
553 *out_list = list;
554 return ret;
555}
556
557void uacpi_free_pnp_id_list(uacpi_pnp_id_list *list)
558{
559 if (list == UACPI_NULL)
560 return;
561
562 uacpi_free(list, sizeof(uacpi_pnp_id_list) + list->size);
563}
564
565uacpi_status uacpi_eval_sta(uacpi_namespace_node *node, uacpi_u32 *flags)
566{
567 uacpi_status ret;
568 uacpi_u64 value = 0;
569
570 ret = uacpi_eval_integer(parent: node, path: "_STA", UACPI_NULL, out_value: &value);
571
572 /*
573 * ACPI 6.5 specification:
574 * If a device object (including the processor object) does not have
575 * an _STA object, then OSPM assumes that all of the above bits are
576 * set (i.e., the device is present, enabled, shown in the UI,
577 * and functioning).
578 */
579 if (ret == UACPI_STATUS_NOT_FOUND) {
580 value = 0xFFFFFFFF;
581 ret = UACPI_STATUS_OK;
582 }
583
584 *flags = value;
585 return ret;
586}
587
588uacpi_status uacpi_eval_adr(uacpi_namespace_node *node, uacpi_u64 *out)
589{
590 return uacpi_eval_integer(parent: node, path: "_ADR", UACPI_NULL, out_value: out);
591}
592
593#define CLS_REPR_SIZE 7
594
595static uacpi_u8 extract_package_byte_or_zero(uacpi_package *pkg, uacpi_size i)
596{
597 uacpi_object *obj;
598
599 if (uacpi_unlikely(pkg->count <= i))
600 return 0;
601
602 obj = pkg->objects[i];
603 if (uacpi_unlikely(obj->type != UACPI_OBJECT_INTEGER))
604 return 0;
605
606 return obj->integer;
607}
608
609uacpi_status uacpi_eval_cls(
610 uacpi_namespace_node *node, uacpi_id_string **out_id
611)
612{
613 uacpi_status ret;
614 uacpi_object *obj;
615 uacpi_package *pkg;
616 uacpi_u8 class_codes[3];
617 uacpi_id_string *id_string;
618
619 ret = uacpi_eval_typed(
620 parent: node, path: "_CLS", UACPI_NULL, UACPI_OBJECT_PACKAGE_BIT, ret: &obj
621 );
622 if (ret != UACPI_STATUS_OK)
623 return ret;
624
625 pkg = obj->package;
626 class_codes[0] = extract_package_byte_or_zero(pkg, i: 0);
627 class_codes[1] = extract_package_byte_or_zero(pkg, i: 1);
628 class_codes[2] = extract_package_byte_or_zero(pkg, i: 2);
629
630 id_string = uacpi_kernel_alloc(size: sizeof(uacpi_id_string) + CLS_REPR_SIZE);
631 if (uacpi_unlikely(id_string == UACPI_NULL)) {
632 ret = UACPI_STATUS_OUT_OF_MEMORY;
633 goto out;
634 }
635
636 id_string->size = CLS_REPR_SIZE;
637 id_string->value = UACPI_PTR_ADD(id_string, sizeof(uacpi_id_string));
638
639 uacpi_snprintf(
640 buffer: id_string->value, CLS_REPR_SIZE, fmt: "%02X%02X%02X",
641 class_codes[0], class_codes[1], class_codes[2]
642 );
643
644out:
645 if (uacpi_likely_success(ret))
646 *out_id = id_string;
647
648 uacpi_object_unref(obj);
649 return ret;
650}
651
652uacpi_status uacpi_eval_uid(
653 uacpi_namespace_node *node, uacpi_id_string **out_uid
654)
655{
656 uacpi_status ret;
657 uacpi_object *obj;
658 uacpi_id_string *id_string;
659 uacpi_u32 size;
660
661 ret = uacpi_eval_typed(
662 parent: node, path: "_UID", UACPI_NULL,
663 UACPI_OBJECT_INTEGER_BIT | UACPI_OBJECT_STRING_BIT,
664 ret: &obj
665 );
666 if (ret != UACPI_STATUS_OK)
667 return ret;
668
669 if (obj->type == UACPI_OBJECT_STRING) {
670 size = obj->buffer->size;
671 if (uacpi_unlikely(size == 0 || size > 0xE0000000)) {
672 uacpi_error(
673 "invalid %.4s._UID string size: %u\n",
674 uacpi_namespace_node_name(node).text, size
675 );
676 ret = UACPI_STATUS_AML_BAD_ENCODING;
677 goto out;
678 }
679 } else {
680 size = uacpi_snprintf(
681 UACPI_NULL, capacity: 0, fmt: "%"UACPI_PRIu64, UACPI_FMT64(obj->integer)
682 ) + 1;
683 }
684
685 id_string = uacpi_kernel_alloc(size: sizeof(uacpi_id_string) + size);
686 if (uacpi_unlikely(id_string == UACPI_NULL)) {
687 ret = UACPI_STATUS_OUT_OF_MEMORY;
688 goto out;
689 }
690
691 id_string->value = UACPI_PTR_ADD(id_string, sizeof(uacpi_id_string));
692 id_string->size = size;
693
694 if (obj->type == UACPI_OBJECT_STRING) {
695 uacpi_memcpy(dest: id_string->value, src: obj->buffer->text, count: size);
696 id_string->value[size - 1] = '\0';
697 } else {
698 uacpi_snprintf(
699 buffer: id_string->value, capacity: id_string->size, fmt: "%"UACPI_PRIu64,
700 UACPI_FMT64(obj->integer)
701 );
702 }
703
704out:
705 if (uacpi_likely_success(ret))
706 *out_uid = id_string;
707
708 uacpi_object_unref(obj);
709 return ret;
710}
711
712static uacpi_bool matches_any(
713 uacpi_id_string *id, const uacpi_char *const *ids
714)
715{
716 uacpi_size i;
717
718 for (i = 0; ids[i]; ++i) {
719 if (uacpi_strcmp(lhs: id->value, rhs: ids[i]) == 0)
720 return UACPI_TRUE;
721 }
722
723 return UACPI_FALSE;
724}
725
726static uacpi_status uacpi_eval_dstate_method_template(
727 uacpi_namespace_node *parent, uacpi_char *template, uacpi_u8 num_methods,
728 uacpi_u8 *out_values
729)
730{
731 uacpi_u8 i;
732 uacpi_status ret = UACPI_STATUS_NOT_FOUND, eval_ret;
733 uacpi_object *obj;
734
735 // We expect either _SxD or _SxW, so increment template[2]
736 for (i = 0; i < num_methods; ++i, template[2]++) {
737 eval_ret = uacpi_eval_typed(
738 parent, path: template, UACPI_NULL, UACPI_OBJECT_INTEGER_BIT, ret: &obj
739 );
740 if (eval_ret == UACPI_STATUS_OK) {
741 ret = UACPI_STATUS_OK;
742 out_values[i] = obj->integer;
743 uacpi_object_unref(obj);
744 continue;
745 }
746
747 out_values[i] = 0xFF;
748 if (uacpi_unlikely(eval_ret != UACPI_STATUS_NOT_FOUND)) {
749 const char *path;
750
751 path = uacpi_namespace_node_generate_absolute_path(node: parent);
752 uacpi_warn(
753 "failed to evaluate %s.%s: %s\n",
754 path, template, uacpi_status_to_string(eval_ret)
755 );
756 uacpi_free_dynamic_string(str: path);
757 }
758 }
759
760 return ret;
761}
762
763#define NODE_INFO_EVAL_ADD_ID(name) \
764 if (uacpi_eval_##name(node, &name) == UACPI_STATUS_OK) { \
765 size += name->size; \
766 if (uacpi_unlikely(size < name->size)) { \
767 ret = UACPI_STATUS_AML_BAD_ENCODING; \
768 goto out; \
769 } \
770 }
771
772#define NODE_INFO_COPY_ID(name, flag) \
773 if (name != UACPI_NULL) { \
774 flags |= UACPI_NS_NODE_INFO_HAS_##flag; \
775 info->name.value = cursor; \
776 info->name.size = name->size; \
777 uacpi_memcpy(cursor, name->value, name->size); \
778 cursor += name->size; \
779 } else { \
780 uacpi_memzero(&info->name, sizeof(*name)); \
781 } \
782
783uacpi_status uacpi_get_namespace_node_info(
784 uacpi_namespace_node *node, uacpi_namespace_node_info **out_info
785)
786{
787 uacpi_status ret = UACPI_STATUS_OK;
788 uacpi_u32 size = sizeof(uacpi_namespace_node_info);
789 uacpi_object *obj;
790 uacpi_namespace_node_info *info;
791 uacpi_id_string *hid = UACPI_NULL, *uid = UACPI_NULL, *cls = UACPI_NULL;
792 uacpi_pnp_id_list *cid = UACPI_NULL;
793 uacpi_char *cursor;
794 uacpi_u64 adr = 0;
795 uacpi_u8 flags = 0;
796 uacpi_u8 sxd[4], sxw[5];
797
798 obj = uacpi_namespace_node_get_object(node);
799 if (uacpi_unlikely(obj == UACPI_NULL))
800 return UACPI_STATUS_INVALID_ARGUMENT;
801
802 if (obj->type == UACPI_OBJECT_DEVICE ||
803 obj->type == UACPI_OBJECT_PROCESSOR) {
804 char dstate_method_template[5] = { '_', 'S', '1', 'D', '\0' };
805
806 NODE_INFO_EVAL_ADD_ID(hid)
807 NODE_INFO_EVAL_ADD_ID(uid)
808 NODE_INFO_EVAL_ADD_ID(cls)
809 NODE_INFO_EVAL_ADD_ID(cid)
810
811 if (uacpi_eval_adr(node, out: &adr) == UACPI_STATUS_OK)
812 flags |= UACPI_NS_NODE_INFO_HAS_ADR;
813
814 if (uacpi_eval_dstate_method_template(
815 parent: node, template: dstate_method_template, num_methods: sizeof(sxd), out_values: sxd
816 ) == UACPI_STATUS_OK)
817 flags |= UACPI_NS_NODE_INFO_HAS_SXD;
818
819 dstate_method_template[2] = '0';
820 dstate_method_template[3] = 'W';
821
822 if (uacpi_eval_dstate_method_template(
823 parent: node, template: dstate_method_template, num_methods: sizeof(sxw), out_values: sxw
824 ) == UACPI_STATUS_OK)
825 flags |= UACPI_NS_NODE_INFO_HAS_SXW;
826 }
827
828 info = uacpi_kernel_alloc(size);
829 if (uacpi_unlikely(info == UACPI_NULL)) {
830 ret = UACPI_STATUS_OUT_OF_MEMORY;
831 goto out;
832 }
833 info->size = size;
834 cursor = UACPI_PTR_ADD(info, sizeof(uacpi_namespace_node_info));
835 info->name = uacpi_namespace_node_name(node);
836 info->type = obj->type;
837 info->num_params = info->type == UACPI_OBJECT_METHOD ? obj->method->args : 0;
838
839 info->adr = adr;
840 if (flags & UACPI_NS_NODE_INFO_HAS_SXD)
841 uacpi_memcpy(dest: info->sxd, src: sxd, count: sizeof(sxd));
842 else
843 uacpi_memzero(info->sxd, sizeof(info->sxd));
844
845 if (flags & UACPI_NS_NODE_INFO_HAS_SXW)
846 uacpi_memcpy(dest: info->sxw, src: sxw, count: sizeof(sxw));
847 else
848 uacpi_memzero(info->sxw, sizeof(info->sxw));
849
850 if (cid != UACPI_NULL) {
851 uacpi_u32 i;
852
853 uacpi_memcpy(dest: &info->cid, src: cid, count: cid->size + sizeof(*cid));
854 cursor += cid->num_ids * sizeof(uacpi_id_string);
855
856 for (i = 0; i < cid->num_ids; ++i) {
857 info->cid.ids[i].value = cursor;
858 cursor += info->cid.ids[i].size;
859 }
860
861 flags |= UACPI_NS_NODE_INFO_HAS_CID;
862 } else {
863 uacpi_memzero(&info->cid, sizeof(*cid));
864 }
865
866 NODE_INFO_COPY_ID(hid, HID)
867 NODE_INFO_COPY_ID(uid, UID)
868 NODE_INFO_COPY_ID(cls, CLS)
869
870out:
871 if (uacpi_likely_success(ret)) {
872 info->flags = flags;
873 *out_info = info;
874 }
875
876 uacpi_free_id_string(id: hid);
877 uacpi_free_id_string(id: uid);
878 uacpi_free_id_string(id: cls);
879 uacpi_free_pnp_id_list(list: cid);
880 return ret;
881}
882
883void uacpi_free_namespace_node_info(uacpi_namespace_node_info *info)
884{
885 if (info == UACPI_NULL)
886 return;
887
888 uacpi_free(info, info->size);
889}
890
891uacpi_bool uacpi_device_matches_pnp_id(
892 uacpi_namespace_node *node, const uacpi_char *const *ids
893)
894{
895 uacpi_status st;
896 uacpi_bool ret = UACPI_FALSE;
897 uacpi_id_string *id = UACPI_NULL;
898 uacpi_pnp_id_list *id_list = UACPI_NULL;
899
900 st = uacpi_eval_hid(node, out_id: &id);
901 if (st == UACPI_STATUS_OK && matches_any(id, ids)) {
902 ret = UACPI_TRUE;
903 goto out;
904 }
905
906 st = uacpi_eval_cid(node, out_list: &id_list);
907 if (st == UACPI_STATUS_OK) {
908 uacpi_size i;
909
910 for (i = 0; i < id_list->num_ids; ++i) {
911 if (matches_any(id: &id_list->ids[i], ids)) {
912 ret = UACPI_TRUE;
913 goto out;
914 }
915 }
916 }
917
918out:
919 uacpi_free_id_string(id);
920 uacpi_free_pnp_id_list(list: id_list);
921 return ret;
922}
923
924struct device_find_ctx {
925 const uacpi_char *const *target_hids;
926 void *user;
927 uacpi_iteration_callback cb;
928};
929
930enum uacpi_ns_iteration_decision find_one_device(
931 void *opaque, uacpi_namespace_node *node
932)
933{
934 struct device_find_ctx *ctx = opaque;
935 uacpi_status ret;
936 uacpi_u32 flags;
937 uacpi_object *obj;
938
939 obj = uacpi_namespace_node_get_object(node);
940 if (uacpi_unlikely(obj == UACPI_NULL))
941 return UACPI_NS_ITERATION_DECISION_CONTINUE;
942 if (obj->type != UACPI_OBJECT_DEVICE)
943 return UACPI_NS_ITERATION_DECISION_CONTINUE;
944
945 if (!uacpi_device_matches_pnp_id(node, ids: ctx->target_hids))
946 return UACPI_NS_ITERATION_DECISION_CONTINUE;
947
948 ret = uacpi_eval_sta(node, flags: &flags);
949 if (uacpi_unlikely_error(ret))
950 return UACPI_NS_ITERATION_DECISION_NEXT_PEER;
951
952 if (!(flags & ACPI_STA_RESULT_DEVICE_PRESENT) &&
953 !(flags & ACPI_STA_RESULT_DEVICE_FUNCTIONING))
954 return UACPI_NS_ITERATION_DECISION_NEXT_PEER;
955
956 return ctx->cb(ctx->user, node);
957}
958
959
960uacpi_status uacpi_find_devices_at(
961 uacpi_namespace_node *parent, const uacpi_char *const *hids,
962 uacpi_iteration_callback cb, void *user
963)
964{
965 UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_NAMESPACE_LOADED);
966
967 struct device_find_ctx ctx = {
968 .target_hids = hids,
969 .user = user,
970 .cb = cb,
971 };
972
973 uacpi_namespace_for_each_node_depth_first(parent, callback: find_one_device, user: &ctx);
974 return UACPI_STATUS_OK;
975}
976
977uacpi_status uacpi_find_devices(
978 const uacpi_char *hid, uacpi_iteration_callback cb, void *user
979)
980{
981 const uacpi_char *hids[] = {
982 hid, UACPI_NULL
983 };
984
985 return uacpi_find_devices_at(parent: uacpi_namespace_root(), hids, cb, user);
986}
987
988uacpi_status uacpi_set_interrupt_model(uacpi_interrupt_model model)
989{
990 uacpi_status ret;
991 uacpi_object *arg;
992 uacpi_args args;
993
994 UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_NAMESPACE_LOADED);
995
996 arg = uacpi_create_object(type: UACPI_OBJECT_INTEGER);
997 if (uacpi_unlikely(arg == UACPI_NULL))
998 return UACPI_STATUS_OUT_OF_MEMORY;
999
1000 arg->integer = model;
1001 args.objects = &arg;
1002 args.count = 1;
1003
1004 ret = uacpi_eval(parent: uacpi_namespace_root(), path: "_PIC", args: &args, UACPI_NULL);
1005 uacpi_object_unref(obj: arg);
1006
1007 if (ret == UACPI_STATUS_NOT_FOUND)
1008 ret = UACPI_STATUS_OK;
1009
1010 return ret;
1011}
1012
1013uacpi_status uacpi_get_pci_routing_table(
1014 uacpi_namespace_node *parent, uacpi_pci_routing_table **out_table
1015)
1016{
1017 uacpi_status ret;
1018 uacpi_object *obj, *entry_obj, *elem_obj;
1019 uacpi_package *table_pkg, *entry_pkg;
1020 uacpi_pci_routing_table_entry *entry;
1021 uacpi_pci_routing_table *table;
1022 uacpi_size size, i;
1023
1024 UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_NAMESPACE_LOADED);
1025
1026 obj = uacpi_namespace_node_get_object(node: parent);
1027 if (uacpi_unlikely(obj == UACPI_NULL || obj->type != UACPI_OBJECT_DEVICE))
1028 return UACPI_STATUS_INVALID_ARGUMENT;
1029
1030 ret = uacpi_eval_typed(
1031 parent, path: "_PRT", UACPI_NULL, UACPI_OBJECT_PACKAGE_BIT, ret: &obj
1032 );
1033 if (uacpi_unlikely_error(ret))
1034 return ret;
1035
1036 table_pkg = obj->package;
1037 if (uacpi_unlikely(table_pkg->count == 0 || table_pkg->count > 1024)) {
1038 uacpi_error("invalid number of _PRT entries: %zu\n", table_pkg->count);
1039 uacpi_object_unref(obj);
1040 return UACPI_STATUS_AML_BAD_ENCODING;
1041 }
1042
1043 size = table_pkg->count * sizeof(uacpi_pci_routing_table_entry);
1044 table = uacpi_kernel_alloc(size: sizeof(uacpi_pci_routing_table) + size);
1045 if (uacpi_unlikely(table == UACPI_NULL)) {
1046 uacpi_object_unref(obj);
1047 return UACPI_STATUS_OUT_OF_MEMORY;
1048 }
1049 table->num_entries = table_pkg->count;
1050
1051 for (i = 0; i < table_pkg->count; ++i) {
1052 entry_obj = table_pkg->objects[i];
1053
1054 if (uacpi_unlikely(entry_obj->type != UACPI_OBJECT_PACKAGE)) {
1055 uacpi_error("_PRT sub-object %zu is not a package: %s\n",
1056 i, uacpi_object_type_to_string(entry_obj->type));
1057 goto out_bad_encoding;
1058 }
1059
1060 entry_pkg = entry_obj->package;
1061 if (uacpi_unlikely(entry_pkg->count != 4)) {
1062 uacpi_error("invalid _PRT sub-package entry count %zu\n",
1063 entry_pkg->count);
1064 goto out_bad_encoding;
1065 }
1066
1067 entry = &table->entries[i];
1068
1069 elem_obj = entry_pkg->objects[0];
1070 if (uacpi_unlikely(elem_obj->type != UACPI_OBJECT_INTEGER)) {
1071 uacpi_error("invalid _PRT sub-package %zu address type: %s\n",
1072 i, uacpi_object_type_to_string(elem_obj->type));
1073 goto out_bad_encoding;
1074 }
1075 entry->address = elem_obj->integer;
1076
1077 elem_obj = entry_pkg->objects[1];
1078 if (uacpi_unlikely(elem_obj->type != UACPI_OBJECT_INTEGER)) {
1079 uacpi_error("invalid _PRT sub-package %zu pin type: %s\n",
1080 i, uacpi_object_type_to_string(elem_obj->type));
1081 goto out_bad_encoding;
1082 }
1083 entry->pin = elem_obj->integer;
1084
1085 elem_obj = entry_pkg->objects[2];
1086 switch (elem_obj->type) {
1087 case UACPI_OBJECT_STRING:
1088 entry->source = uacpi_namespace_node_resolve_from_aml_namepath(
1089 scope: parent, path: elem_obj->buffer->text
1090 );
1091 if (uacpi_unlikely(entry->source == UACPI_NULL)) {
1092 uacpi_error("unable to lookup _PRT source: %s\n",
1093 elem_obj->buffer->text);
1094 goto out_bad_encoding;
1095 }
1096 break;
1097 case UACPI_OBJECT_INTEGER:
1098 entry->source = UACPI_NULL;
1099 break;
1100 default:
1101 uacpi_error("invalid _PRT sub-package %zu source type: %s\n",
1102 i, uacpi_object_type_to_string(elem_obj->type));
1103 goto out_bad_encoding;
1104 }
1105
1106 elem_obj = entry_pkg->objects[3];
1107 if (uacpi_unlikely(elem_obj->type != UACPI_OBJECT_INTEGER)) {
1108 uacpi_error("invalid _PRT sub-package %zu source index type: %s\n",
1109 i, uacpi_object_type_to_string(elem_obj->type));
1110 goto out_bad_encoding;
1111 }
1112 entry->index = elem_obj->integer;
1113 }
1114
1115 uacpi_object_unref(obj);
1116 *out_table = table;
1117 return UACPI_STATUS_OK;
1118
1119out_bad_encoding:
1120 uacpi_object_unref(obj);
1121 uacpi_free_pci_routing_table(table);
1122 return UACPI_STATUS_AML_BAD_ENCODING;
1123}
1124
1125void uacpi_free_pci_routing_table(uacpi_pci_routing_table *table)
1126{
1127 if (table == UACPI_NULL)
1128 return;
1129
1130 uacpi_free(
1131 table,
1132 sizeof(uacpi_pci_routing_table) +
1133 table->num_entries * sizeof(uacpi_pci_routing_table_entry)
1134 );
1135}
1136
1137void uacpi_free_dynamic_string(const uacpi_char *str)
1138{
1139 if (str == UACPI_NULL)
1140 return;
1141
1142 uacpi_free((void*)str, uacpi_strlen(str) + 1);
1143}
1144