1#include <uacpi/types.h>
2#include <uacpi/acpi.h>
3#include <uacpi/internal/resources.h>
4#include <uacpi/internal/stdlib.h>
5#include <uacpi/internal/utilities.h>
6#include <uacpi/internal/log.h>
7#include <uacpi/uacpi.h>
8
9#define LARGE_RESOURCE_BASE (ACPI_RESOURCE_END_TAG + 1)
10#define L(x) (x + LARGE_RESOURCE_BASE)
11
12/*
13 * Map raw AML resource types to the internal enum, this also takes care of type
14 * sanitization by returning UACPI_AML_RESOURCE_INVALID for any unknown type.
15 */
16static const uacpi_u8 aml_resource_to_type[256] = {
17 // Small items
18 [ACPI_RESOURCE_IRQ] = UACPI_AML_RESOURCE_IRQ,
19 [ACPI_RESOURCE_DMA] = UACPI_AML_RESOURCE_DMA,
20 [ACPI_RESOURCE_START_DEPENDENT] = UACPI_AML_RESOURCE_START_DEPENDENT,
21 [ACPI_RESOURCE_END_DEPENDENT] = UACPI_AML_RESOURCE_END_DEPENDENT,
22 [ACPI_RESOURCE_IO] = UACPI_AML_RESOURCE_IO,
23 [ACPI_RESOURCE_FIXED_IO] = UACPI_AML_RESOURCE_FIXED_IO,
24 [ACPI_RESOURCE_FIXED_DMA] = UACPI_AML_RESOURCE_FIXED_DMA,
25 [ACPI_RESOURCE_VENDOR_TYPE0] = UACPI_AML_RESOURCE_VENDOR_TYPE0,
26 [ACPI_RESOURCE_END_TAG] = UACPI_AML_RESOURCE_END_TAG,
27
28 // Large items
29 [L(ACPI_RESOURCE_MEMORY24)] = UACPI_AML_RESOURCE_MEMORY24,
30 [L(ACPI_RESOURCE_GENERIC_REGISTER)] = UACPI_AML_RESOURCE_GENERIC_REGISTER,
31 [L(ACPI_RESOURCE_VENDOR_TYPE1)] = UACPI_AML_RESOURCE_VENDOR_TYPE1,
32 [L(ACPI_RESOURCE_MEMORY32)] = UACPI_AML_RESOURCE_MEMORY32,
33 [L(ACPI_RESOURCE_FIXED_MEMORY32)] = UACPI_AML_RESOURCE_FIXED_MEMORY32,
34 [L(ACPI_RESOURCE_ADDRESS32)] = UACPI_AML_RESOURCE_ADDRESS32,
35 [L(ACPI_RESOURCE_ADDRESS16)] = UACPI_AML_RESOURCE_ADDRESS16,
36 [L(ACPI_RESOURCE_EXTENDED_IRQ)] = UACPI_AML_RESOURCE_EXTENDED_IRQ,
37 [L(ACPI_RESOURCE_ADDRESS64_EXTENDED)] = UACPI_AML_RESOURCE_ADDRESS64_EXTENDED,
38 [L(ACPI_RESOURCE_ADDRESS64)] = UACPI_AML_RESOURCE_ADDRESS64,
39 [L(ACPI_RESOURCE_GPIO_CONNECTION)] = UACPI_AML_RESOURCE_GPIO_CONNECTION,
40 [L(ACPI_RESOURCE_PIN_FUNCTION)] = UACPI_AML_RESOURCE_PIN_FUNCTION,
41 [L(ACPI_RESOURCE_SERIAL_CONNECTION)] = UACPI_AML_RESOURCE_SERIAL_CONNECTION,
42 [L(ACPI_RESOURCE_PIN_CONFIGURATION)] = UACPI_AML_RESOURCE_PIN_CONFIGURATION,
43 [L(ACPI_RESOURCE_PIN_GROUP)] = UACPI_AML_RESOURCE_PIN_GROUP,
44 [L(ACPI_RESOURCE_PIN_GROUP_FUNCTION)] = UACPI_AML_RESOURCE_PIN_GROUP_FUNCTION,
45 [L(ACPI_RESOURCE_PIN_GROUP_CONFIGURATION)] = UACPI_AML_RESOURCE_PIN_GROUP_CONFIGURATION,
46 [L(ACPI_RESOURCE_CLOCK_INPUT)] = UACPI_AML_RESOURCE_CLOCK_INPUT,
47};
48
49static const uacpi_u8 type_to_aml_resource[] = {
50 [UACPI_AML_RESOURCE_IRQ] = ACPI_RESOURCE_IRQ,
51 [UACPI_AML_RESOURCE_DMA] = ACPI_RESOURCE_DMA,
52 [UACPI_AML_RESOURCE_START_DEPENDENT] = ACPI_RESOURCE_START_DEPENDENT,
53 [UACPI_AML_RESOURCE_END_DEPENDENT] = ACPI_RESOURCE_END_DEPENDENT,
54 [UACPI_AML_RESOURCE_IO] = ACPI_RESOURCE_IO,
55 [UACPI_AML_RESOURCE_FIXED_IO] = ACPI_RESOURCE_FIXED_IO,
56 [UACPI_AML_RESOURCE_FIXED_DMA] = ACPI_RESOURCE_FIXED_DMA,
57 [UACPI_AML_RESOURCE_VENDOR_TYPE0] = ACPI_RESOURCE_VENDOR_TYPE0,
58 [UACPI_AML_RESOURCE_END_TAG] = ACPI_RESOURCE_END_TAG,
59
60 // Large items
61 [UACPI_AML_RESOURCE_MEMORY24] = ACPI_RESOURCE_MEMORY24,
62 [UACPI_AML_RESOURCE_GENERIC_REGISTER] = ACPI_RESOURCE_GENERIC_REGISTER,
63 [UACPI_AML_RESOURCE_VENDOR_TYPE1] = ACPI_RESOURCE_VENDOR_TYPE1,
64 [UACPI_AML_RESOURCE_MEMORY32] = ACPI_RESOURCE_MEMORY32,
65 [UACPI_AML_RESOURCE_FIXED_MEMORY32] = ACPI_RESOURCE_FIXED_MEMORY32,
66 [UACPI_AML_RESOURCE_ADDRESS32] = ACPI_RESOURCE_ADDRESS32,
67 [UACPI_AML_RESOURCE_ADDRESS16] = ACPI_RESOURCE_ADDRESS16,
68 [UACPI_AML_RESOURCE_EXTENDED_IRQ] = ACPI_RESOURCE_EXTENDED_IRQ,
69 [UACPI_AML_RESOURCE_ADDRESS64_EXTENDED] = ACPI_RESOURCE_ADDRESS64_EXTENDED,
70 [UACPI_AML_RESOURCE_ADDRESS64] = ACPI_RESOURCE_ADDRESS64,
71 [UACPI_AML_RESOURCE_GPIO_CONNECTION] = ACPI_RESOURCE_GPIO_CONNECTION,
72 [UACPI_AML_RESOURCE_PIN_FUNCTION] = ACPI_RESOURCE_PIN_FUNCTION,
73 [UACPI_AML_RESOURCE_SERIAL_CONNECTION] = ACPI_RESOURCE_SERIAL_CONNECTION,
74 [UACPI_AML_RESOURCE_PIN_CONFIGURATION] = ACPI_RESOURCE_PIN_CONFIGURATION,
75 [UACPI_AML_RESOURCE_PIN_GROUP] = ACPI_RESOURCE_PIN_GROUP,
76 [UACPI_AML_RESOURCE_PIN_GROUP_FUNCTION] = ACPI_RESOURCE_PIN_GROUP_FUNCTION,
77 [UACPI_AML_RESOURCE_PIN_GROUP_CONFIGURATION] = ACPI_RESOURCE_PIN_GROUP_CONFIGURATION,
78 [UACPI_AML_RESOURCE_CLOCK_INPUT] = ACPI_RESOURCE_CLOCK_INPUT,
79};
80
81static const uacpi_u8 native_resource_to_type[UACPI_RESOURCE_TYPE_MAX + 1] = {
82 [UACPI_RESOURCE_TYPE_IRQ] = UACPI_AML_RESOURCE_IRQ,
83 [UACPI_RESOURCE_TYPE_EXTENDED_IRQ] = UACPI_AML_RESOURCE_EXTENDED_IRQ,
84 [UACPI_RESOURCE_TYPE_DMA] = UACPI_AML_RESOURCE_DMA,
85 [UACPI_RESOURCE_TYPE_FIXED_DMA] = UACPI_AML_RESOURCE_FIXED_DMA,
86 [UACPI_RESOURCE_TYPE_IO] = UACPI_AML_RESOURCE_IO,
87 [UACPI_RESOURCE_TYPE_FIXED_IO] = UACPI_AML_RESOURCE_FIXED_IO,
88 [UACPI_RESOURCE_TYPE_ADDRESS16] = UACPI_AML_RESOURCE_ADDRESS16,
89 [UACPI_RESOURCE_TYPE_ADDRESS32] = UACPI_AML_RESOURCE_ADDRESS32,
90 [UACPI_RESOURCE_TYPE_ADDRESS64] = UACPI_AML_RESOURCE_ADDRESS64,
91 [UACPI_RESOURCE_TYPE_ADDRESS64_EXTENDED] = UACPI_AML_RESOURCE_ADDRESS64_EXTENDED,
92 [UACPI_RESOURCE_TYPE_MEMORY24] = UACPI_AML_RESOURCE_MEMORY24,
93 [UACPI_RESOURCE_TYPE_MEMORY32] = UACPI_AML_RESOURCE_MEMORY32,
94 [UACPI_RESOURCE_TYPE_FIXED_MEMORY32] = UACPI_AML_RESOURCE_FIXED_MEMORY32,
95 [UACPI_RESOURCE_TYPE_START_DEPENDENT] = UACPI_AML_RESOURCE_START_DEPENDENT,
96 [UACPI_RESOURCE_TYPE_END_DEPENDENT] = UACPI_AML_RESOURCE_END_DEPENDENT,
97 [UACPI_RESOURCE_TYPE_VENDOR_SMALL] = UACPI_AML_RESOURCE_VENDOR_TYPE0,
98 [UACPI_RESOURCE_TYPE_VENDOR_LARGE] = UACPI_AML_RESOURCE_VENDOR_TYPE1,
99 [UACPI_RESOURCE_TYPE_GENERIC_REGISTER] = UACPI_AML_RESOURCE_GENERIC_REGISTER,
100 [UACPI_RESOURCE_TYPE_GPIO_CONNECTION] = UACPI_AML_RESOURCE_GPIO_CONNECTION,
101 [UACPI_RESOURCE_TYPE_SERIAL_I2C_CONNECTION] = UACPI_AML_RESOURCE_SERIAL_CONNECTION,
102 [UACPI_RESOURCE_TYPE_SERIAL_SPI_CONNECTION] = UACPI_AML_RESOURCE_SERIAL_CONNECTION,
103 [UACPI_RESOURCE_TYPE_SERIAL_UART_CONNECTION] = UACPI_AML_RESOURCE_SERIAL_CONNECTION,
104 [UACPI_RESOURCE_TYPE_SERIAL_CSI2_CONNECTION] = UACPI_AML_RESOURCE_SERIAL_CONNECTION,
105 [UACPI_RESOURCE_TYPE_PIN_FUNCTION] = UACPI_AML_RESOURCE_PIN_FUNCTION,
106 [UACPI_RESOURCE_TYPE_PIN_CONFIGURATION] = UACPI_AML_RESOURCE_PIN_CONFIGURATION,
107 [UACPI_RESOURCE_TYPE_PIN_GROUP] = UACPI_AML_RESOURCE_PIN_GROUP,
108 [UACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION] = UACPI_AML_RESOURCE_PIN_GROUP_FUNCTION,
109 [UACPI_RESOURCE_TYPE_PIN_GROUP_CONFIGURATION] = UACPI_AML_RESOURCE_PIN_GROUP_CONFIGURATION,
110 [UACPI_RESOURCE_TYPE_CLOCK_INPUT] = UACPI_AML_RESOURCE_CLOCK_INPUT,
111 [UACPI_RESOURCE_TYPE_END_TAG] = UACPI_AML_RESOURCE_END_TAG,
112};
113
114#define SMALL_ITEM_HEADER_SIZE sizeof(struct acpi_small_item)
115#define LARGE_ITEM_HEADER_SIZE sizeof(struct acpi_large_item)
116
117static const uacpi_u8 aml_resource_kind_to_header_size[2] = {
118 [UACPI_AML_RESOURCE_KIND_SMALL] = SMALL_ITEM_HEADER_SIZE,
119 [UACPI_AML_RESOURCE_KIND_LARGE] = LARGE_ITEM_HEADER_SIZE,
120};
121
122static uacpi_size aml_size_with_header(const struct uacpi_resource_spec *spec)
123{
124 return spec->aml_size +
125 aml_resource_kind_to_header_size[spec->resource_kind];
126}
127
128static uacpi_size extra_size_for_native_irq_or_dma(
129 const struct uacpi_resource_spec *spec, void *data, uacpi_size size
130)
131{
132 UACPI_UNUSED(size);
133 uacpi_u16 mask;
134
135 if (spec->type == UACPI_AML_RESOURCE_IRQ) {
136 struct acpi_resource_irq *irq = data;
137 mask = irq->irq_mask;
138 } else {
139 struct acpi_resource_dma *dma = data;
140 mask = dma->channel_mask;
141 }
142
143 return uacpi_popcount(mask);
144}
145
146static uacpi_size size_for_aml_irq(
147 const struct uacpi_resource_spec *spec, uacpi_resource *resource
148)
149{
150 uacpi_resource_irq *irq = &resource->irq;
151 uacpi_size size;
152
153 size = aml_size_with_header(spec);
154
155 switch (irq->length_kind) {
156 case UACPI_RESOURCE_LENGTH_KIND_FULL:
157 goto out_full;
158 case UACPI_RESOURCE_LENGTH_KIND_ONE_LESS:
159 case UACPI_RESOURCE_LENGTH_KIND_DONT_CARE:
160 if (irq->triggering != UACPI_TRIGGERING_EDGE)
161 goto out_full;
162 if (irq->polarity != UACPI_POLARITY_ACTIVE_HIGH)
163 goto out_full;
164 if (irq->sharing != UACPI_EXCLUSIVE)
165 goto out_full;
166
167 return size - 1;
168 }
169
170out_full:
171 if (uacpi_unlikely(irq->length_kind ==
172 UACPI_RESOURCE_LENGTH_KIND_ONE_LESS)) {
173 uacpi_warn("requested IRQ resource length is "
174 "not compatible with specified flags, corrected\n");
175 }
176
177 return size;
178}
179
180static uacpi_size size_for_aml_start_dependent(
181 const struct uacpi_resource_spec *spec, uacpi_resource *resource
182)
183{
184 uacpi_resource_start_dependent *start_dep = &resource->start_dependent;
185 uacpi_size size;
186
187 size = aml_size_with_header(spec);
188 switch (start_dep->length_kind) {
189 case UACPI_RESOURCE_LENGTH_KIND_FULL:
190 goto out_full;
191 case UACPI_RESOURCE_LENGTH_KIND_ONE_LESS:
192 case UACPI_RESOURCE_LENGTH_KIND_DONT_CARE:
193 if (start_dep->compatibility != UACPI_ACCEPTABLE)
194 goto out_full;
195 if (start_dep->performance != UACPI_ACCEPTABLE)
196 goto out_full;
197
198 return size - 1;
199 }
200
201out_full:
202 if (uacpi_unlikely(start_dep->length_kind ==
203 UACPI_RESOURCE_LENGTH_KIND_ONE_LESS)) {
204 uacpi_warn("requested StartDependentFn resource length is "
205 "not compatible with specified flags, corrected\n");
206 }
207
208 return size;
209}
210
211static uacpi_size extra_size_for_native_vendor(
212 const struct uacpi_resource_spec *spec, void *data, uacpi_size size
213)
214{
215 UACPI_UNUSED(spec);
216 UACPI_UNUSED(data);
217 return size;
218}
219
220static uacpi_size size_for_aml_vendor(
221 const struct uacpi_resource_spec *spec, uacpi_resource *resource
222)
223{
224 UACPI_UNUSED(spec);
225 uacpi_size size = resource->vendor.length;
226
227 if (size > 7 || resource->type == UACPI_RESOURCE_TYPE_VENDOR_LARGE) {
228 size += aml_resource_kind_to_header_size[
229 UACPI_AML_RESOURCE_KIND_LARGE
230 ];
231
232 if (uacpi_unlikely(resource->type != UACPI_RESOURCE_TYPE_VENDOR_LARGE)) {
233 uacpi_warn("vendor data too large for small descriptor (%zu), "
234 "correcting to large\n", size);
235 resource->type = UACPI_RESOURCE_TYPE_VENDOR_LARGE;
236 }
237 } else {
238 size += aml_resource_kind_to_header_size[
239 UACPI_AML_RESOURCE_KIND_SMALL
240 ];
241 }
242
243 return size;
244}
245
246static uacpi_size extra_size_for_resource_source(
247 uacpi_size base_size, uacpi_size reported_size
248)
249{
250 uacpi_size string_length;
251
252 if (reported_size <= base_size)
253 return 0;
254
255 /*
256 * The remainder of the descriptor minus the resource index field
257 */
258 string_length = (reported_size - base_size) - 1;
259 return UACPI_ALIGN_UP(string_length, sizeof(void*), uacpi_size);
260}
261
262static uacpi_size size_for_aml_resource_source(
263 uacpi_resource_source *source, uacpi_bool with_index
264)
265{
266 uacpi_size length = source->length;
267
268 if (uacpi_unlikely(length && !source->index_present)) {
269 uacpi_warn("resource declares no source index with non-empty "
270 "string (%zu bytes), corrected\n", length);
271 source->index_present = UACPI_TRUE;
272 }
273
274 // If index is included in the dynamic resource source, add it to the length
275 if (with_index)
276 length += source->index_present;
277
278 return length;
279}
280
281static uacpi_size extra_size_for_native_address_or_clock_input(
282 const struct uacpi_resource_spec *spec, void *data, uacpi_size size
283)
284{
285 UACPI_UNUSED(data);
286 return extra_size_for_resource_source(base_size: spec->aml_size, reported_size: size);
287}
288
289static uacpi_size size_for_aml_address_or_clock_input(
290 const struct uacpi_resource_spec *spec, uacpi_resource *resource
291)
292{
293 uacpi_resource_source *source;
294 bool has_index = UACPI_TRUE;
295
296 switch (resource->type) {
297 case UACPI_RESOURCE_TYPE_ADDRESS16:
298 source = &resource->address16.source;
299 break;
300 case UACPI_RESOURCE_TYPE_ADDRESS32:
301 source = &resource->address32.source;
302 break;
303 case UACPI_RESOURCE_TYPE_ADDRESS64:
304 source = &resource->address64.source;
305 break;
306 case UACPI_RESOURCE_TYPE_CLOCK_INPUT:
307 source = &resource->clock_input.source;
308 has_index = UACPI_FALSE;
309 break;
310 default:
311 return 0;
312 }
313
314 return aml_size_with_header(spec) +
315 size_for_aml_resource_source(source, with_index: has_index);
316}
317
318static uacpi_size extra_size_for_extended_irq(
319 const struct uacpi_resource_spec *spec, void *data, uacpi_size size
320)
321{
322 struct acpi_resource_extended_irq *irq = data;
323 uacpi_size extra_size = 0;
324
325 extra_size += irq->num_irqs * sizeof(uacpi_u32);
326 extra_size += extra_size_for_resource_source(
327 base_size: spec->aml_size, reported_size: size - extra_size
328 );
329
330 return extra_size;
331}
332
333static uacpi_size size_for_aml_extended_irq(
334 const struct uacpi_resource_spec *spec, uacpi_resource *resource
335)
336{
337 uacpi_resource_extended_irq *irq = &resource->extended_irq;
338 uacpi_size size;
339
340 size = aml_size_with_header(spec);
341 size += irq->num_irqs * 4;
342 size += size_for_aml_resource_source(source: &irq->source, UACPI_TRUE);
343
344 return size;
345}
346
347static uacpi_size extra_size_for_native_gpio_or_pins(
348 const struct uacpi_resource_spec *spec, void *data, uacpi_size size
349)
350{
351 uacpi_size pin_table_offset;
352
353 /*
354 * These resources pretend to have variable layout by declaring "offset"
355 * fields, but the layout is hardcoded and mandated by the spec to be
356 * very specific. We can use the offset numbers here to calculate the final
357 * length.
358 *
359 * For example, the layout of GPIO connection _always_ looks as follows:
360 * [0...22] -> fixed data
361 * [23...<source name offset - 1>] -> pin table
362 * [<source name offset>...<vendor data offset - 1>] -> source name
363 * [<vendor data offset>...<data offset + data length>] -> vendor data
364 */
365 switch (spec->type) {
366 case UACPI_AML_RESOURCE_GPIO_CONNECTION: {
367 struct acpi_resource_gpio_connection *gpio = data;
368 pin_table_offset = gpio->pin_table_offset;
369 break;
370 }
371
372 case UACPI_AML_RESOURCE_PIN_FUNCTION: {
373 struct acpi_resource_pin_function *pin = data;
374 pin_table_offset = pin->pin_table_offset;
375 break;
376 }
377
378 case UACPI_AML_RESOURCE_PIN_CONFIGURATION: {
379 struct acpi_resource_pin_configuration *config = data;
380 pin_table_offset = config->pin_table_offset;
381 break;
382 }
383
384 case UACPI_AML_RESOURCE_PIN_GROUP: {
385 struct acpi_resource_pin_group *group = data;
386 pin_table_offset = group->pin_table_offset;
387 break;
388 }
389
390 default:
391 return 0;
392 }
393
394 /*
395 * The size we get passed here does not include the header size because
396 * that's how resources are encoded. Subtract it here so that we get the
397 * correct final length.
398 */
399 return size - (pin_table_offset - LARGE_ITEM_HEADER_SIZE);
400}
401
402static uacpi_size size_for_aml_gpio_or_pins(
403 const struct uacpi_resource_spec *spec, uacpi_resource *resource
404)
405{
406 uacpi_size source_length, vendor_length, pin_table_length, size;
407
408 size = aml_size_with_header(spec);
409 switch (spec->type) {
410 case UACPI_AML_RESOURCE_GPIO_CONNECTION: {
411 uacpi_resource_gpio_connection *res = &resource->gpio_connection;
412 source_length = res->source.length;
413 pin_table_length = res->pin_table_length;
414 vendor_length = res->vendor_data_length;
415 break;
416 }
417
418 case UACPI_AML_RESOURCE_PIN_FUNCTION: {
419 uacpi_resource_pin_function *res = &resource->pin_function;
420 source_length = res->source.length;
421 pin_table_length = res->pin_table_length;
422 vendor_length = res->vendor_data_length;
423 break;
424 }
425
426 case UACPI_AML_RESOURCE_PIN_CONFIGURATION: {
427 uacpi_resource_pin_configuration *res = &resource->pin_configuration;
428 source_length = res->source.length;
429 pin_table_length = res->pin_table_length;
430 vendor_length = res->vendor_data_length;
431 break;
432 }
433
434 case UACPI_AML_RESOURCE_PIN_GROUP: {
435 uacpi_resource_pin_group *res = &resource->pin_group;
436 source_length = res->label.length;
437 pin_table_length = res->pin_table_length;
438 vendor_length = res->vendor_data_length;
439 break;
440 }
441
442 default:
443 return 0;
444 }
445
446 size += source_length;
447 size += pin_table_length * 2;
448 size += vendor_length;
449
450 return size;
451}
452
453static uacpi_size extra_size_for_native_pin_group(
454 const struct uacpi_resource_spec *spec, void *data, uacpi_size size
455)
456{
457 uacpi_size source_offset;
458
459 switch (spec->type) {
460 case UACPI_AML_RESOURCE_PIN_GROUP_FUNCTION: {
461 struct acpi_resource_pin_group_function *func = data;
462 source_offset = func->source_offset;
463 break;
464 }
465
466 case UACPI_AML_RESOURCE_PIN_GROUP_CONFIGURATION: {
467 struct acpi_resource_pin_group_configuration *config = data;
468 source_offset = config->source_offset;
469 break;
470 }
471
472 default:
473 return 0;
474 }
475
476 // Same logic as extra_size_for_native_gpio_or_pins
477 return size - (source_offset - LARGE_ITEM_HEADER_SIZE);
478}
479
480static uacpi_size size_for_aml_pin_group(
481 const struct uacpi_resource_spec *spec, uacpi_resource *resource
482)
483{
484 uacpi_size source_length, label_length, vendor_length, size;
485
486 size = aml_size_with_header(spec);
487 switch (spec->type) {
488 case UACPI_AML_RESOURCE_PIN_GROUP_FUNCTION: {
489 uacpi_resource_pin_group_function *res = &resource->pin_group_function;
490 source_length = res->source.length;
491 label_length = res->label.length;
492 vendor_length = res->vendor_data_length;
493 break;
494 }
495
496 case UACPI_AML_RESOURCE_PIN_GROUP_CONFIGURATION: {
497 uacpi_resource_pin_group_configuration *res;
498 res = &resource->pin_group_configuration;
499 source_length = res->source.length;
500 label_length = res->label.length;
501 vendor_length = res->vendor_data_length;
502 break;
503 }
504
505 default:
506 return 0;
507 }
508
509 size += source_length;
510 size += label_length;
511 size += vendor_length;
512
513 return size;
514}
515
516#define AML_SERIAL_RESOURCE_EXTRA_SIZE(type) \
517 (sizeof(struct acpi_resource_serial_##type) \
518 - sizeof(struct acpi_resource_serial))
519
520#define NATIVE_SERIAL_RESOURCE_EXTRA_SIZE(type) \
521 (sizeof(uacpi_resource_##type##_connection) \
522 - sizeof(uacpi_resource_serial_bus_common))
523
524static const uacpi_u8 aml_serial_resource_to_extra_aml_size
525[ACPI_SERIAL_TYPE_MAX + 1] = {
526 [ACPI_SERIAL_TYPE_I2C] = AML_SERIAL_RESOURCE_EXTRA_SIZE(i2c),
527 [ACPI_SERIAL_TYPE_SPI] = AML_SERIAL_RESOURCE_EXTRA_SIZE(spi),
528 [ACPI_SERIAL_TYPE_UART] = AML_SERIAL_RESOURCE_EXTRA_SIZE(uart),
529 [ACPI_SERIAL_TYPE_CSI2] = AML_SERIAL_RESOURCE_EXTRA_SIZE(csi2),
530};
531
532static const uacpi_u8 aml_serial_resource_to_extra_native_size
533[ACPI_SERIAL_TYPE_MAX + 1] = {
534 [ACPI_SERIAL_TYPE_I2C] = NATIVE_SERIAL_RESOURCE_EXTRA_SIZE(i2c),
535 [ACPI_SERIAL_TYPE_SPI] = NATIVE_SERIAL_RESOURCE_EXTRA_SIZE(spi),
536 [ACPI_SERIAL_TYPE_UART] = NATIVE_SERIAL_RESOURCE_EXTRA_SIZE(uart),
537 [ACPI_SERIAL_TYPE_CSI2] = NATIVE_SERIAL_RESOURCE_EXTRA_SIZE(csi2),
538};
539
540static uacpi_size extra_size_for_serial_connection(
541 const struct uacpi_resource_spec *spec, void *data, uacpi_size size
542)
543{
544 struct acpi_resource_serial *serial = data;
545 uacpi_size extra_bytes = size;
546
547 extra_bytes -= spec->aml_size;
548 extra_bytes -= aml_serial_resource_to_extra_aml_size[serial->type];
549 extra_bytes += aml_serial_resource_to_extra_native_size[serial->type];
550
551 return extra_bytes;
552}
553
554static uacpi_size aml_size_for_serial_connection(
555 const struct uacpi_resource_spec *spec, uacpi_resource *resource
556)
557{
558 uacpi_size size;
559 uacpi_resource_serial_bus_common *serial_bus = &resource->serial_bus_common;
560
561 size = aml_size_with_header(spec);
562 size += aml_serial_resource_to_extra_aml_size[serial_bus->type];
563 size += serial_bus->vendor_data_length;
564 size += serial_bus->source.length;
565
566 return size;
567}
568
569#define OP(short_code, ...) \
570{ \
571 .code = UACPI_RESOURCE_CONVERT_OPCODE_##short_code, \
572 __VA_ARGS__ \
573}
574
575#define END() OP(END)
576
577#define AML_O(short_aml_name, field) \
578 uacpi_offsetof(struct acpi_resource_##short_aml_name, field)
579
580#define AML_F(short_aml_name, field) \
581 .aml_offset = AML_O(short_aml_name, field)
582
583#define NATIVE_O(short_name, field) \
584 uacpi_offsetof(uacpi_resource_##short_name, field)
585
586#define NATIVE_F(short_native_name, field) \
587 .native_offset = NATIVE_O(short_native_name, field)
588
589#define IMM(value) .imm = value
590#define ARG0(value) .arg0 = (value)
591#define ARG1(value) .arg1 = (value)
592#define ARG2(value) .arg2 = (value)
593
594
595static const struct uacpi_resource_convert_instruction convert_irq_to_native[] = {
596 OP(PACKED_ARRAY_16, AML_F(irq, irq_mask), NATIVE_F(irq, irqs),
597 ARG2(NATIVE_O(irq, num_irqs))),
598 OP(SKIP_IF_AML_SIZE_LESS_THAN, ARG0(3), IMM(6)),
599 OP(SET_TO_IMM, NATIVE_F(irq, length_kind),
600 IMM(UACPI_RESOURCE_LENGTH_KIND_FULL)),
601 OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, triggering), IMM(0)),
602 OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, polarity), IMM(3)),
603 OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, sharing), IMM(4)),
604 OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, wake_capability), IMM(5)),
605 END(),
606 OP(SET_TO_IMM, NATIVE_F(irq, length_kind),
607 IMM(UACPI_RESOURCE_LENGTH_KIND_ONE_LESS)),
608 OP(SET_TO_IMM, NATIVE_F(irq, triggering), IMM(UACPI_TRIGGERING_EDGE)),
609 END(),
610};
611
612const struct uacpi_resource_convert_instruction convert_irq_to_aml[] = {
613 OP(PACKED_ARRAY_16, AML_F(irq, irq_mask), NATIVE_F(irq, irqs),
614 ARG2(NATIVE_O(irq, num_irqs))),
615 OP(SKIP_IF_AML_SIZE_LESS_THAN, ARG0(3), IMM(4)),
616 OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, triggering), IMM(0)),
617 OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, polarity), IMM(3)),
618 OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, sharing), IMM(4)),
619 OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, wake_capability), IMM(5)),
620 END(),
621};
622
623static const struct uacpi_resource_convert_instruction convert_dma[] = {
624 OP(PACKED_ARRAY_8, AML_F(dma, channel_mask), NATIVE_F(dma, channels),
625 ARG2(NATIVE_O(dma, num_channels))),
626 OP(BIT_FIELD_2, AML_F(dma, flags), NATIVE_F(dma, transfer_type), IMM(0)),
627 OP(BIT_FIELD_1, AML_F(dma, flags), NATIVE_F(dma, bus_master_status), IMM(2)),
628 OP(BIT_FIELD_2, AML_F(dma, flags), NATIVE_F(dma, channel_speed), IMM(5)),
629 END(),
630};
631
632static const struct uacpi_resource_convert_instruction
633convert_start_dependent_to_native[] = {
634 OP(SKIP_IF_AML_SIZE_LESS_THAN, ARG0(1), IMM(4)),
635 OP(SET_TO_IMM, NATIVE_F(start_dependent, length_kind),
636 IMM(UACPI_RESOURCE_LENGTH_KIND_FULL)),
637 OP(BIT_FIELD_2, AML_F(start_dependent, flags),
638 NATIVE_F(start_dependent, compatibility), IMM(0)),
639 OP(BIT_FIELD_2, AML_F(start_dependent, flags),
640 NATIVE_F(start_dependent, performance), IMM(2)),
641 END(),
642 OP(SET_TO_IMM, NATIVE_F(start_dependent, length_kind),
643 IMM(UACPI_RESOURCE_LENGTH_KIND_ONE_LESS)),
644 OP(SET_TO_IMM, NATIVE_F(start_dependent, compatibility),
645 IMM(UACPI_ACCEPTABLE)),
646 OP(SET_TO_IMM, NATIVE_F(start_dependent, performance),
647 IMM(UACPI_ACCEPTABLE)),
648 END(),
649};
650
651static const struct uacpi_resource_convert_instruction
652convert_start_dependent_to_aml[] = {
653 OP(SKIP_IF_AML_SIZE_LESS_THAN, ARG0(1), IMM(1)),
654 OP(BIT_FIELD_2, AML_F(start_dependent, flags),
655 NATIVE_F(start_dependent, compatibility), IMM(0)),
656 OP(BIT_FIELD_2, AML_F(start_dependent, flags),
657 NATIVE_F(start_dependent, performance), IMM(2)),
658 END(),
659};
660
661static const struct uacpi_resource_convert_instruction convert_io[] = {
662 OP(BIT_FIELD_1, AML_F(io, information), NATIVE_F(io, decode_type)),
663 OP(FIELD_16, AML_F(io, minimum), NATIVE_F(io, minimum)),
664 OP(FIELD_16, AML_F(io, maximum), NATIVE_F(io, maximum)),
665 OP(FIELD_8, AML_F(io, alignment), NATIVE_F(io, alignment)),
666 OP(FIELD_8, AML_F(io, length), NATIVE_F(io, length)),
667 END(),
668};
669
670static const struct uacpi_resource_convert_instruction convert_fixed_io[] = {
671 OP(FIELD_16, AML_F(fixed_io, address), NATIVE_F(fixed_io, address)),
672 OP(FIELD_8, AML_F(fixed_io, length), NATIVE_F(fixed_io, length)),
673 END(),
674};
675
676static const struct uacpi_resource_convert_instruction convert_fixed_dma[] = {
677 OP(FIELD_16, AML_F(fixed_dma, request_line),
678 NATIVE_F(fixed_dma, request_line)),
679 OP(FIELD_16, AML_F(fixed_dma, channel), NATIVE_F(fixed_dma, channel)),
680 OP(FIELD_8, AML_F(fixed_dma, transfer_width),
681 NATIVE_F(fixed_dma, transfer_width)),
682 END(),
683};
684
685static const struct uacpi_resource_convert_instruction convert_vendor_type0[] = {
686 OP(LOAD_AML_SIZE_32, NATIVE_F(vendor, length)),
687 OP(FIELD_8, AML_F(vendor_defined_type0, byte_data), NATIVE_F(vendor, data)),
688 END(),
689};
690
691static const struct uacpi_resource_convert_instruction convert_vendor_type1[] = {
692 OP(LOAD_AML_SIZE_32, NATIVE_F(vendor, length)),
693 OP(FIELD_8, AML_F(vendor_defined_type1, byte_data), NATIVE_F(vendor, data)),
694 END(),
695};
696
697static const struct uacpi_resource_convert_instruction convert_memory24[] = {
698 OP(BIT_FIELD_1, AML_F(memory24, information),
699 NATIVE_F(memory24, write_status), IMM(0)),
700 OP(FIELD_16, AML_F(memory24, minimum), NATIVE_F(memory24, minimum), IMM(4)),
701 END(),
702};
703
704static const struct uacpi_resource_convert_instruction convert_memory32[] = {
705 OP(BIT_FIELD_1, AML_F(memory32, information),
706 NATIVE_F(memory32, write_status), IMM(0)),
707 OP(FIELD_32, AML_F(memory32, minimum), NATIVE_F(memory32, minimum), IMM(4)),
708 END(),
709};
710
711static const struct uacpi_resource_convert_instruction
712convert_fixed_memory32[] = {
713 OP(BIT_FIELD_1, AML_F(fixed_memory32, information),
714 NATIVE_F(fixed_memory32, write_status), IMM(0)),
715 OP(FIELD_32, AML_F(fixed_memory32, address),
716 NATIVE_F(fixed_memory32, address)),
717 OP(FIELD_32, AML_F(fixed_memory32, length),
718 NATIVE_F(fixed_memory32, length)),
719 END(),
720};
721
722static const struct uacpi_resource_convert_instruction
723convert_generic_register[] = {
724 OP(FIELD_8, AML_F(generic_register, address_space_id),
725 NATIVE_F(generic_register, address_space_id), IMM(4)),
726 OP(FIELD_64, AML_F(generic_register, address),
727 NATIVE_F(generic_register, address)),
728 END(),
729};
730
731#define CONVERT_TYPE_SPECIFIC_FLAGS(addr_type) \
732 OP(LOAD_8_STORE, AML_F(addr_type, common.type), \
733 NATIVE_F(addr_type, common.type)), \
734 OP(SKIP_IF_NOT_EQUALS, ARG0(UACPI_RANGE_MEMORY), IMM(5)), \
735 OP(BIT_FIELD_1, \
736 AML_F(addr_type, common.type_flags), \
737 NATIVE_F(addr_type, common.attribute.memory.write_status), IMM(0)), \
738 OP(BIT_FIELD_2, \
739 AML_F(addr_type, common.type_flags), \
740 NATIVE_F(addr_type, common.attribute.memory.caching), IMM(1)), \
741 OP(BIT_FIELD_2, \
742 AML_F(addr_type, common.type_flags), \
743 NATIVE_F(addr_type, common.attribute.memory.range_type), IMM(3)), \
744 OP(BIT_FIELD_1, \
745 AML_F(addr_type, common.type_flags), \
746 NATIVE_F(addr_type, common.attribute.memory.translation), IMM(5)), \
747 END(), \
748 OP(SKIP_IF_NOT_EQUALS, ARG0(UACPI_RANGE_IO), IMM(4)), \
749 OP(BIT_FIELD_2, \
750 AML_F(addr_type, common.type_flags), \
751 NATIVE_F(addr_type, common.attribute.io.range_type), IMM(0)), \
752 OP(BIT_FIELD_1, \
753 AML_F(addr_type, common.type_flags), \
754 NATIVE_F(addr_type, common.attribute.io.translation_type), IMM(4)), \
755 OP(BIT_FIELD_1, \
756 AML_F(addr_type, common.type_flags), \
757 NATIVE_F(addr_type, common.attribute.io.translation), IMM(5)), \
758 END(), \
759 /* Memory type that we don't know, just copy the byte */ \
760 OP(FIELD_8, AML_F(addr_type, common.type_flags), \
761 NATIVE_F(addr_type, common.attribute.type_specific), IMM(0xFF)), \
762 END()
763
764#define CONVERT_GENERAL_ADDRESS_FLAGS(addr_type) \
765 OP(BIT_FIELD_1, \
766 AML_F(addr_type, common.flags), \
767 NATIVE_F(addr_type, common.direction), IMM(0)), \
768 OP(BIT_FIELD_1, \
769 AML_F(addr_type, common.flags), \
770 NATIVE_F(addr_type, common.decode_type), IMM(1)), \
771 OP(BIT_FIELD_1, \
772 AML_F(addr_type, common.flags), \
773 NATIVE_F(addr_type, common.fixed_min_address), IMM(2)), \
774 OP(BIT_FIELD_1, \
775 AML_F(addr_type, common.flags), \
776 NATIVE_F(addr_type, common.fixed_max_address), IMM(3)) \
777
778#define DEFINE_ADDRESS_CONVERSION(width) \
779 static const struct uacpi_resource_convert_instruction \
780 convert_address##width[] = { \
781 CONVERT_GENERAL_ADDRESS_FLAGS(address##width), \
782 OP(FIELD_##width, AML_F(address##width, granularity), \
783 NATIVE_F(address##width, granularity), IMM(5)), \
784 OP(RESOURCE_SOURCE, NATIVE_F(address##width, source)), \
785 CONVERT_TYPE_SPECIFIC_FLAGS(address##width), \
786 };
787
788DEFINE_ADDRESS_CONVERSION(16)
789DEFINE_ADDRESS_CONVERSION(32)
790DEFINE_ADDRESS_CONVERSION(64)
791
792static const struct uacpi_resource_convert_instruction
793convert_address64_extended[] = {
794 CONVERT_GENERAL_ADDRESS_FLAGS(address64_extended),
795 OP(FIELD_8, AML_F(address64_extended, revision_id),
796 NATIVE_F(address64_extended, revision_id)),
797 OP(FIELD_64, AML_F(address64_extended, granularity),
798 NATIVE_F(address64_extended, granularity), IMM(6)),
799 CONVERT_TYPE_SPECIFIC_FLAGS(address64_extended),
800};
801
802static const struct uacpi_resource_convert_instruction
803convert_extended_irq[] = {
804 OP(BIT_FIELD_1, AML_F(extended_irq, flags),
805 NATIVE_F(extended_irq, direction), IMM(0)),
806 OP(BIT_FIELD_1, AML_F(extended_irq, flags),
807 NATIVE_F(extended_irq, triggering), IMM(1)),
808 OP(BIT_FIELD_1, AML_F(extended_irq, flags),
809 NATIVE_F(extended_irq, polarity), IMM(2)),
810 OP(BIT_FIELD_1, AML_F(extended_irq, flags),
811 NATIVE_F(extended_irq, sharing), IMM(3)),
812 OP(BIT_FIELD_1, AML_F(extended_irq, flags),
813 NATIVE_F(extended_irq, wake_capability), IMM(4)),
814 OP(LOAD_8_STORE, AML_F(extended_irq, num_irqs),
815 NATIVE_F(extended_irq, num_irqs), IMM(4)),
816 OP(RESOURCE_SOURCE, NATIVE_F(extended_irq, source)),
817
818 // Use FIELD_8 here since the accumulator has been multiplied by 4
819 OP(FIELD_8, AML_F(extended_irq, irqs), NATIVE_F(extended_irq, irqs)),
820 END(),
821};
822
823static const struct uacpi_resource_convert_instruction convert_clock_input[] = {
824 OP(FIELD_8, AML_F(clock_input, revision_id),
825 NATIVE_F(clock_input, revision_id)),
826 OP(BIT_FIELD_1, AML_F(clock_input, flags), NATIVE_F(clock_input, frequency),
827 IMM(0)),
828 OP(BIT_FIELD_2, AML_F(clock_input, flags), NATIVE_F(clock_input, scale),
829 IMM(1)),
830 OP(FIELD_16, AML_F(clock_input, divisor), NATIVE_F(clock_input, divisor)),
831 OP(FIELD_32, AML_F(clock_input, numerator), NATIVE_F(clock_input, numerator)),
832 OP(FIELD_8, AML_F(clock_input, source_index), NATIVE_F(clock_input, source.index)),
833 OP(RESOURCE_SOURCE_NO_INDEX, NATIVE_F(clock_input, source)),
834 END(),
835};
836
837#define DECODE_SOURCE_INDEX(short_aml_name) \
838 OP(FIELD_8, AML_F(short_aml_name, source_index), \
839 NATIVE_F(short_aml_name, source.index)) \
840
841#define DECODE_RES_PIN_TBL_AND_VENDOR_DATA( \
842 short_aml_name, res_opcode, offset_field, res_field \
843) \
844 OP(LOAD_PIN_TABLE_LENGTH, AML_F(short_aml_name, offset_field), \
845 NATIVE_F(short_aml_name, pin_table_length)), \
846 OP(RESOURCE_##res_opcode, NATIVE_F(short_aml_name, res_field), \
847 AML_F(short_aml_name, offset_field), \
848 ARG2(AML_O(short_aml_name, vendor_data_offset))), \
849 OP(PIN_TABLE, AML_F(short_aml_name, pin_table_offset), \
850 NATIVE_F(short_aml_name, pin_table_length), \
851 ARG2(NATIVE_O(short_aml_name, pin_table))), \
852 OP(VENDOR_DATA, AML_F(short_aml_name, vendor_data_offset), \
853 NATIVE_F(short_aml_name, vendor_data_length), \
854 ARG2(NATIVE_O(short_aml_name, vendor_data)))
855
856static const struct uacpi_resource_convert_instruction
857convert_gpio_connection[] = {
858 OP(FIELD_8, AML_F(gpio_connection, revision_id),
859 NATIVE_F(gpio_connection, revision_id)),
860 OP(BIT_FIELD_1, AML_F(gpio_connection, general_flags),
861 NATIVE_F(gpio_connection, direction)),
862 OP(FIELD_8, AML_F(gpio_connection, pull_configuration),
863 NATIVE_F(gpio_connection, pull_configuration)),
864 OP(FIELD_16, AML_F(gpio_connection, drive_strength),
865 NATIVE_F(gpio_connection, drive_strength), IMM(2)),
866 DECODE_SOURCE_INDEX(gpio_connection),
867 DECODE_RES_PIN_TBL_AND_VENDOR_DATA(
868 gpio_connection, SOURCE_NO_INDEX, source_offset, source
869 ),
870 OP(LOAD_8_STORE, AML_F(gpio_connection, type), NATIVE_F(gpio_connection, type)),
871 OP(SKIP_IF_NOT_EQUALS, ARG0(UACPI_GPIO_CONNECTION_INTERRUPT), IMM(5)),
872 OP(BIT_FIELD_1, AML_F(gpio_connection, connection_flags),
873 NATIVE_F(gpio_connection, interrupt.triggering), IMM(0)),
874 OP(BIT_FIELD_2, AML_F(gpio_connection, connection_flags),
875 NATIVE_F(gpio_connection, interrupt.polarity), IMM(1)),
876 OP(BIT_FIELD_1, AML_F(gpio_connection, connection_flags),
877 NATIVE_F(gpio_connection, interrupt.sharing), IMM(3)),
878 OP(BIT_FIELD_1, AML_F(gpio_connection, connection_flags),
879 NATIVE_F(gpio_connection, interrupt.wake_capability), IMM(4)),
880 END(),
881 OP(SKIP_IF_NOT_EQUALS, ARG0(UACPI_GPIO_CONNECTION_IO), IMM(3)),
882 OP(BIT_FIELD_2, AML_F(gpio_connection, connection_flags),
883 NATIVE_F(gpio_connection, io.restriction), IMM(0)),
884 OP(BIT_FIELD_1, AML_F(gpio_connection, connection_flags),
885 NATIVE_F(gpio_connection, io.sharing), IMM(3)),
886 END(),
887 OP(FIELD_16, AML_F(gpio_connection, connection_flags),
888 NATIVE_F(gpio_connection, type_specific), IMM(0xFF)),
889 END(),
890};
891
892static const struct uacpi_resource_convert_instruction
893convert_pin_function[] = {
894 OP(FIELD_8, AML_F(pin_function, revision_id),
895 NATIVE_F(pin_function, revision_id)),
896 OP(BIT_FIELD_1, AML_F(pin_function, flags),
897 NATIVE_F(pin_function, sharing), IMM(0)),
898 OP(FIELD_8, AML_F(pin_function, pull_configuration),
899 NATIVE_F(pin_function, pull_configuration)),
900 OP(FIELD_16, AML_F(pin_function, function_number),
901 NATIVE_F(pin_function, function_number)),
902 DECODE_SOURCE_INDEX(pin_function),
903 DECODE_RES_PIN_TBL_AND_VENDOR_DATA(
904 pin_function, SOURCE_NO_INDEX, source_offset, source
905 ),
906 END(),
907};
908
909static const struct uacpi_resource_convert_instruction
910convert_pin_configuration[] = {
911 OP(FIELD_8, AML_F(pin_configuration, revision_id),
912 NATIVE_F(pin_configuration, revision_id)),
913 OP(BIT_FIELD_1, AML_F(pin_configuration, flags),
914 NATIVE_F(pin_configuration, sharing), IMM(0)),
915 OP(BIT_FIELD_1, AML_F(pin_configuration, flags),
916 NATIVE_F(pin_configuration, direction), IMM(1)),
917 OP(FIELD_8, AML_F(pin_configuration, type),
918 NATIVE_F(pin_configuration, type)),
919 OP(FIELD_32, AML_F(pin_configuration, value),
920 NATIVE_F(pin_configuration, value)),
921 DECODE_SOURCE_INDEX(pin_configuration),
922 DECODE_RES_PIN_TBL_AND_VENDOR_DATA(
923 pin_configuration, SOURCE_NO_INDEX, source_offset, source
924 ),
925 END(),
926};
927
928static const struct uacpi_resource_convert_instruction convert_pin_group[] = {
929 OP(FIELD_8, AML_F(pin_group, revision_id),
930 NATIVE_F(pin_group, revision_id)),
931 OP(BIT_FIELD_1, AML_F(pin_group, flags),
932 NATIVE_F(pin_group, direction), IMM(0)),
933 DECODE_RES_PIN_TBL_AND_VENDOR_DATA(
934 pin_group, LABEL, source_lable_offset, label
935 ),
936 END(),
937};
938
939#define DECODE_PIN_GROUP_RES_SOURCES(postfix) \
940 DECODE_SOURCE_INDEX(pin_group_##postfix), \
941 OP(RESOURCE_SOURCE_NO_INDEX, NATIVE_F(pin_group_##postfix, source), \
942 AML_F(pin_group_##postfix, source_offset), \
943 ARG2(AML_O(pin_group_##postfix, source_lable_offset))), \
944 OP(LOAD_16_NATIVE, NATIVE_F(pin_group_##postfix, source.length)), \
945 OP(RESOURCE_LABEL, NATIVE_F(pin_group_##postfix, label), \
946 AML_F(pin_group_##postfix, source_lable_offset), \
947 ARG2(AML_O(pin_group_##postfix, vendor_data_offset))), \
948 OP(VENDOR_DATA, AML_F(pin_group_##postfix, vendor_data_offset), \
949 NATIVE_F(pin_group_##postfix, vendor_data_length), \
950 ARG2(NATIVE_O(pin_group_##postfix, vendor_data)))
951
952static const struct uacpi_resource_convert_instruction
953convert_pin_group_function[] = {
954 OP(FIELD_8, AML_F(pin_group_function, revision_id),
955 NATIVE_F(pin_group_function, revision_id)),
956 OP(BIT_FIELD_1, AML_F(pin_group_function, flags),
957 NATIVE_F(pin_group_function, sharing), IMM(0)),
958 OP(BIT_FIELD_1, AML_F(pin_group_function, flags),
959 NATIVE_F(pin_group_function, direction), IMM(1)),
960 OP(FIELD_16, AML_F(pin_group_function, function),
961 NATIVE_F(pin_group_function, function)),
962 DECODE_PIN_GROUP_RES_SOURCES(function),
963 END(),
964};
965
966static const struct uacpi_resource_convert_instruction
967convert_pin_group_configuration[] = {
968 OP(FIELD_8, AML_F(pin_group_configuration, revision_id),
969 NATIVE_F(pin_group_configuration, revision_id)),
970 OP(BIT_FIELD_1, AML_F(pin_group_configuration, flags),
971 NATIVE_F(pin_group_configuration, sharing), IMM(0)),
972 OP(BIT_FIELD_1, AML_F(pin_group_configuration, flags),
973 NATIVE_F(pin_group_configuration, direction), IMM(1)),
974 OP(FIELD_8, AML_F(pin_group_configuration, type),
975 NATIVE_F(pin_group_configuration, type)),
976 OP(FIELD_32, AML_F(pin_group_configuration, value),
977 NATIVE_F(pin_group_configuration, value)),
978 DECODE_PIN_GROUP_RES_SOURCES(configuration),
979 END(),
980};
981
982static const struct uacpi_resource_convert_instruction
983convert_generic_serial_bus[] = {
984 OP(FIELD_8, AML_F(serial, revision_id),
985 NATIVE_F(serial_bus_common, revision_id)),
986 OP(FIELD_8, AML_F(serial, type_specific_revision_id),
987 NATIVE_F(serial_bus_common, type_revision_id)),
988 OP(FIELD_8, AML_F(serial, source_index),
989 NATIVE_F(serial_bus_common, source.index)),
990 OP(FIELD_16, AML_F(serial, type_data_length),
991 NATIVE_F(serial_bus_common, type_data_length)),
992 OP(BIT_FIELD_1, AML_F(serial, flags),
993 NATIVE_F(serial_bus_common, mode), IMM(0)),
994 OP(BIT_FIELD_1, AML_F(serial, flags),
995 NATIVE_F(serial_bus_common, direction), IMM(1)),
996 OP(BIT_FIELD_1, AML_F(serial, flags),
997 NATIVE_F(serial_bus_common, sharing), IMM(2)),
998 OP(SERIAL_TYPE_SPECIFIC, AML_F(serial, type),
999 NATIVE_F(serial_bus_common, type)),
1000 OP(RESOURCE_SOURCE_NO_INDEX, NATIVE_F(serial_bus_common, source)),
1001 OP(LOAD_8_NATIVE, NATIVE_F(serial_bus_common, type)),
1002 OP(SKIP_IF_NOT_EQUALS, ARG0(ACPI_SERIAL_TYPE_I2C), IMM(4)),
1003 OP(BIT_FIELD_1, AML_F(serial, type_specific_flags),
1004 NATIVE_F(i2c_connection, addressing_mode), IMM(0)),
1005 OP(FIELD_32, AML_F(serial_i2c, connection_speed),
1006 NATIVE_F(i2c_connection, connection_speed), IMM(0xFF)),
1007 OP(FIELD_16, AML_F(serial_i2c, slave_address),
1008 NATIVE_F(i2c_connection, slave_address)),
1009 END(),
1010 OP(SKIP_IF_NOT_EQUALS, ARG0(ACPI_SERIAL_TYPE_SPI), IMM(5)),
1011 OP(BIT_FIELD_1, AML_F(serial, type_specific_flags),
1012 NATIVE_F(spi_connection, wire_mode), IMM(0)),
1013 OP(BIT_FIELD_1, AML_F(serial, type_specific_flags),
1014 NATIVE_F(spi_connection, device_polarity), IMM(1)),
1015 OP(FIELD_32, AML_F(serial_spi, connection_speed),
1016 NATIVE_F(spi_connection, connection_speed), IMM(0xFF)),
1017 OP(FIELD_8, AML_F(serial_spi, data_bit_length),
1018 NATIVE_F(spi_connection, data_bit_length), IMM(5)),
1019 END(),
1020 OP(SKIP_IF_NOT_EQUALS, ARG0(ACPI_SERIAL_TYPE_UART), IMM(8)),
1021 OP(BIT_FIELD_2, AML_F(serial, type_specific_flags),
1022 NATIVE_F(uart_connection, flow_control), IMM(0)),
1023 OP(BIT_FIELD_2, AML_F(serial, type_specific_flags),
1024 NATIVE_F(uart_connection, stop_bits), IMM(2)),
1025 OP(BIT_FIELD_3, AML_F(serial, type_specific_flags),
1026 NATIVE_F(uart_connection, data_bits), IMM(4)),
1027 OP(BIT_FIELD_1, AML_F(serial, type_specific_flags),
1028 NATIVE_F(uart_connection, endianness), IMM(7)),
1029 OP(FIELD_32, AML_F(serial_uart, baud_rate),
1030 NATIVE_F(uart_connection, baud_rate), IMM(0xFF)),
1031 OP(FIELD_16, AML_F(serial_uart, rx_fifo),
1032 NATIVE_F(uart_connection, rx_fifo), IMM(2)),
1033 OP(FIELD_8, AML_F(serial_uart, parity),
1034 NATIVE_F(uart_connection, parity), IMM(2)),
1035 END(),
1036 OP(SKIP_IF_NOT_EQUALS, ARG0(ACPI_SERIAL_TYPE_CSI2), IMM(3)),
1037 OP(BIT_FIELD_2, AML_F(serial, type_specific_flags),
1038 NATIVE_F(csi2_connection, phy_type), IMM(0)),
1039 OP(BIT_FIELD_6, AML_F(serial, type_specific_flags),
1040 NATIVE_F(csi2_connection, local_port), IMM(2)),
1041 END(),
1042
1043 /*
1044 * Insert a trap to catch unimplemented types, this should be unreachable
1045 * because of validation earlier.
1046 */
1047 OP(UNREACHABLE),
1048};
1049
1050#define NATIVE_RESOURCE_HEADER_SIZE 8
1051
1052#define DEFINE_SMALL_AML_RESOURCE(aml_type_enum, native_type_enum, \
1053 aml_struct, native_struct, ...) \
1054 [aml_type_enum] = { \
1055 .type = aml_type_enum, \
1056 .native_type = native_type_enum, \
1057 .resource_kind = UACPI_AML_RESOURCE_KIND_SMALL, \
1058 .aml_size = sizeof(aml_struct) - SMALL_ITEM_HEADER_SIZE, \
1059 .native_size = sizeof(native_struct) + NATIVE_RESOURCE_HEADER_SIZE, \
1060 __VA_ARGS__ \
1061 }
1062
1063#define DEFINE_SMALL_AML_RESOURCE_NO_NATIVE_REPR( \
1064 aml_type_enum, native_type_enum, aml_struct, ... \
1065) \
1066 [aml_type_enum] = { \
1067 .type = aml_type_enum, \
1068 .native_type = native_type_enum, \
1069 .resource_kind = UACPI_AML_RESOURCE_KIND_SMALL, \
1070 .aml_size = sizeof(aml_struct) - SMALL_ITEM_HEADER_SIZE, \
1071 .native_size = NATIVE_RESOURCE_HEADER_SIZE, \
1072 __VA_ARGS__ \
1073 }
1074
1075#define DEFINE_LARGE_AML_RESOURCE(aml_type_enum, native_type_enum, \
1076 aml_struct, native_struct, ...) \
1077 [aml_type_enum] = { \
1078 .type = aml_type_enum, \
1079 .native_type = native_type_enum, \
1080 .resource_kind = UACPI_AML_RESOURCE_KIND_LARGE, \
1081 .aml_size = sizeof(aml_struct) - LARGE_ITEM_HEADER_SIZE, \
1082 .native_size = sizeof(native_struct) + NATIVE_RESOURCE_HEADER_SIZE, \
1083 __VA_ARGS__ \
1084 }
1085
1086const struct uacpi_resource_spec aml_resources[UACPI_AML_RESOURCE_MAX + 1] = {
1087 DEFINE_SMALL_AML_RESOURCE(
1088 UACPI_AML_RESOURCE_IRQ,
1089 UACPI_RESOURCE_TYPE_IRQ,
1090 struct acpi_resource_irq,
1091 uacpi_resource_irq,
1092 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED_OR_ONE_LESS,
1093 .extra_size_for_native = extra_size_for_native_irq_or_dma,
1094 .size_for_aml = size_for_aml_irq,
1095 .to_native = convert_irq_to_native,
1096 .to_aml = convert_irq_to_aml,
1097 ),
1098 DEFINE_SMALL_AML_RESOURCE(
1099 UACPI_AML_RESOURCE_DMA,
1100 UACPI_RESOURCE_TYPE_DMA,
1101 struct acpi_resource_dma,
1102 uacpi_resource_dma,
1103 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1104 .extra_size_for_native = extra_size_for_native_irq_or_dma,
1105 .to_native = convert_dma,
1106 .to_aml = convert_dma,
1107 ),
1108 DEFINE_SMALL_AML_RESOURCE(
1109 UACPI_AML_RESOURCE_START_DEPENDENT,
1110 UACPI_RESOURCE_TYPE_START_DEPENDENT,
1111 struct acpi_resource_start_dependent,
1112 uacpi_resource_start_dependent,
1113 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED_OR_ONE_LESS,
1114 .size_for_aml = size_for_aml_start_dependent,
1115 .to_native = convert_start_dependent_to_native,
1116 .to_aml = convert_start_dependent_to_aml,
1117 ),
1118 DEFINE_SMALL_AML_RESOURCE_NO_NATIVE_REPR(
1119 UACPI_AML_RESOURCE_END_DEPENDENT,
1120 UACPI_RESOURCE_TYPE_END_DEPENDENT,
1121 struct acpi_resource_end_dependent,
1122 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1123 ),
1124 DEFINE_SMALL_AML_RESOURCE(
1125 UACPI_AML_RESOURCE_IO,
1126 UACPI_RESOURCE_TYPE_IO,
1127 struct acpi_resource_io,
1128 uacpi_resource_io,
1129 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1130 .to_native = convert_io,
1131 .to_aml = convert_io,
1132 ),
1133 DEFINE_SMALL_AML_RESOURCE(
1134 UACPI_AML_RESOURCE_FIXED_IO,
1135 UACPI_RESOURCE_TYPE_FIXED_IO,
1136 struct acpi_resource_fixed_io,
1137 uacpi_resource_fixed_io,
1138 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1139 .to_native = convert_fixed_io,
1140 .to_aml = convert_fixed_io,
1141 ),
1142 DEFINE_SMALL_AML_RESOURCE(
1143 UACPI_AML_RESOURCE_FIXED_DMA,
1144 UACPI_RESOURCE_TYPE_FIXED_DMA,
1145 struct acpi_resource_fixed_dma,
1146 uacpi_resource_fixed_dma,
1147 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1148 .to_native = convert_fixed_dma,
1149 .to_aml = convert_fixed_dma,
1150 ),
1151 DEFINE_SMALL_AML_RESOURCE(
1152 UACPI_AML_RESOURCE_VENDOR_TYPE0,
1153 UACPI_RESOURCE_TYPE_VENDOR_SMALL,
1154 struct acpi_resource_vendor_defined_type0,
1155 uacpi_resource_vendor,
1156 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1157 .size_for_aml = size_for_aml_vendor,
1158 .extra_size_for_native = extra_size_for_native_vendor,
1159 .to_native = convert_vendor_type0,
1160 .to_aml = convert_vendor_type0,
1161 ),
1162 DEFINE_SMALL_AML_RESOURCE_NO_NATIVE_REPR(
1163 UACPI_AML_RESOURCE_END_TAG,
1164 UACPI_RESOURCE_TYPE_END_TAG,
1165 struct acpi_resource_end_tag,
1166 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1167 ),
1168 DEFINE_LARGE_AML_RESOURCE(
1169 UACPI_AML_RESOURCE_MEMORY24,
1170 UACPI_RESOURCE_TYPE_MEMORY24,
1171 struct acpi_resource_memory24,
1172 uacpi_resource_memory24,
1173 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1174 .to_native = convert_memory24,
1175 .to_aml = convert_memory24,
1176 ),
1177 DEFINE_LARGE_AML_RESOURCE(
1178 UACPI_AML_RESOURCE_GENERIC_REGISTER,
1179 UACPI_RESOURCE_TYPE_GENERIC_REGISTER,
1180 struct acpi_resource_generic_register,
1181 uacpi_resource_generic_register,
1182 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1183 .to_native = convert_generic_register,
1184 .to_aml = convert_generic_register,
1185 ),
1186 DEFINE_LARGE_AML_RESOURCE(
1187 UACPI_AML_RESOURCE_VENDOR_TYPE1,
1188 UACPI_RESOURCE_TYPE_VENDOR_LARGE,
1189 struct acpi_resource_vendor_defined_type1,
1190 uacpi_resource_vendor,
1191 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1192 .extra_size_for_native = extra_size_for_native_vendor,
1193 .size_for_aml = size_for_aml_vendor,
1194 .to_native = convert_vendor_type1,
1195 .to_aml = convert_vendor_type1,
1196 ),
1197 DEFINE_LARGE_AML_RESOURCE(
1198 UACPI_AML_RESOURCE_MEMORY32,
1199 UACPI_RESOURCE_TYPE_MEMORY32,
1200 struct acpi_resource_memory32,
1201 uacpi_resource_memory32,
1202 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1203 .to_native = convert_memory32,
1204 .to_aml = convert_memory32,
1205 ),
1206 DEFINE_LARGE_AML_RESOURCE(
1207 UACPI_AML_RESOURCE_FIXED_MEMORY32,
1208 UACPI_RESOURCE_TYPE_FIXED_MEMORY32,
1209 struct acpi_resource_fixed_memory32,
1210 uacpi_resource_fixed_memory32,
1211 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1212 .to_native = convert_fixed_memory32,
1213 .to_aml = convert_fixed_memory32,
1214 ),
1215 DEFINE_LARGE_AML_RESOURCE(
1216 UACPI_AML_RESOURCE_ADDRESS32,
1217 UACPI_RESOURCE_TYPE_ADDRESS32,
1218 struct acpi_resource_address32,
1219 uacpi_resource_address32,
1220 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1221 .extra_size_for_native = extra_size_for_native_address_or_clock_input,
1222 .size_for_aml = size_for_aml_address_or_clock_input,
1223 .to_native = convert_address32,
1224 .to_aml = convert_address32,
1225 ),
1226 DEFINE_LARGE_AML_RESOURCE(
1227 UACPI_AML_RESOURCE_ADDRESS16,
1228 UACPI_RESOURCE_TYPE_ADDRESS16,
1229 struct acpi_resource_address16,
1230 uacpi_resource_address16,
1231 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1232 .extra_size_for_native = extra_size_for_native_address_or_clock_input,
1233 .size_for_aml = size_for_aml_address_or_clock_input,
1234 .to_native = convert_address16,
1235 .to_aml = convert_address16,
1236 ),
1237 DEFINE_LARGE_AML_RESOURCE(
1238 UACPI_AML_RESOURCE_EXTENDED_IRQ,
1239 UACPI_RESOURCE_TYPE_EXTENDED_IRQ,
1240 struct acpi_resource_extended_irq,
1241 uacpi_resource_extended_irq,
1242 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1243 .extra_size_for_native = extra_size_for_extended_irq,
1244 .size_for_aml = size_for_aml_extended_irq,
1245 .to_native = convert_extended_irq,
1246 .to_aml = convert_extended_irq,
1247 ),
1248 DEFINE_LARGE_AML_RESOURCE(
1249 UACPI_AML_RESOURCE_ADDRESS64,
1250 UACPI_RESOURCE_TYPE_ADDRESS64,
1251 struct acpi_resource_address64,
1252 uacpi_resource_address64,
1253 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1254 .extra_size_for_native = extra_size_for_native_address_or_clock_input,
1255 .size_for_aml = size_for_aml_address_or_clock_input,
1256 .to_native = convert_address64,
1257 .to_aml = convert_address64,
1258 ),
1259 DEFINE_LARGE_AML_RESOURCE(
1260 UACPI_AML_RESOURCE_ADDRESS64_EXTENDED,
1261 UACPI_RESOURCE_TYPE_ADDRESS64_EXTENDED,
1262 struct acpi_resource_address64_extended,
1263 uacpi_resource_address64_extended,
1264 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
1265 .to_native = convert_address64_extended,
1266 .to_aml = convert_address64_extended,
1267 ),
1268 DEFINE_LARGE_AML_RESOURCE(
1269 UACPI_AML_RESOURCE_GPIO_CONNECTION,
1270 UACPI_RESOURCE_TYPE_GPIO_CONNECTION,
1271 struct acpi_resource_gpio_connection,
1272 uacpi_resource_gpio_connection,
1273 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1274 .extra_size_for_native = extra_size_for_native_gpio_or_pins,
1275 .size_for_aml = size_for_aml_gpio_or_pins,
1276 .to_aml = convert_gpio_connection,
1277 .to_native = convert_gpio_connection,
1278 ),
1279 DEFINE_LARGE_AML_RESOURCE(
1280 UACPI_AML_RESOURCE_PIN_FUNCTION,
1281 UACPI_RESOURCE_TYPE_PIN_FUNCTION,
1282 struct acpi_resource_pin_function,
1283 uacpi_resource_pin_function,
1284 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1285 .extra_size_for_native = extra_size_for_native_gpio_or_pins,
1286 .size_for_aml = size_for_aml_gpio_or_pins,
1287 .to_aml = convert_pin_function,
1288 .to_native = convert_pin_function,
1289 ),
1290 DEFINE_LARGE_AML_RESOURCE(
1291 UACPI_AML_RESOURCE_SERIAL_CONNECTION,
1292 0, // the native type here is determined dynamically
1293 struct acpi_resource_serial,
1294 uacpi_resource_serial_bus_common,
1295 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1296 .extra_size_for_native = extra_size_for_serial_connection,
1297 .size_for_aml = aml_size_for_serial_connection,
1298 .to_native = convert_generic_serial_bus,
1299 .to_aml = convert_generic_serial_bus,
1300 ),
1301 DEFINE_LARGE_AML_RESOURCE(
1302 UACPI_AML_RESOURCE_PIN_CONFIGURATION,
1303 UACPI_RESOURCE_TYPE_PIN_CONFIGURATION,
1304 struct acpi_resource_pin_configuration,
1305 uacpi_resource_pin_configuration,
1306 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1307 .extra_size_for_native = extra_size_for_native_gpio_or_pins,
1308 .size_for_aml = size_for_aml_gpio_or_pins,
1309 .to_native = convert_pin_configuration,
1310 .to_aml = convert_pin_configuration,
1311 ),
1312 DEFINE_LARGE_AML_RESOURCE(
1313 UACPI_AML_RESOURCE_PIN_GROUP,
1314 UACPI_RESOURCE_TYPE_PIN_GROUP,
1315 struct acpi_resource_pin_group,
1316 uacpi_resource_pin_group,
1317 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1318 .extra_size_for_native = extra_size_for_native_gpio_or_pins,
1319 .size_for_aml = size_for_aml_gpio_or_pins,
1320 .to_native = convert_pin_group,
1321 .to_aml = convert_pin_group,
1322 ),
1323 DEFINE_LARGE_AML_RESOURCE(
1324 UACPI_AML_RESOURCE_PIN_GROUP_FUNCTION,
1325 UACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION,
1326 struct acpi_resource_pin_group_function,
1327 uacpi_resource_pin_group_function,
1328 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1329 .extra_size_for_native = extra_size_for_native_pin_group,
1330 .size_for_aml = size_for_aml_pin_group,
1331 .to_native = convert_pin_group_function,
1332 .to_aml = convert_pin_group_function,
1333 ),
1334 DEFINE_LARGE_AML_RESOURCE(
1335 UACPI_AML_RESOURCE_PIN_GROUP_CONFIGURATION,
1336 UACPI_RESOURCE_TYPE_PIN_GROUP_CONFIGURATION,
1337 struct acpi_resource_pin_group_configuration,
1338 uacpi_resource_pin_group_configuration,
1339 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1340 .extra_size_for_native = extra_size_for_native_pin_group,
1341 .size_for_aml = size_for_aml_pin_group,
1342 .to_native = convert_pin_group_configuration,
1343 .to_aml = convert_pin_group_configuration,
1344 ),
1345 DEFINE_LARGE_AML_RESOURCE(
1346 UACPI_AML_RESOURCE_CLOCK_INPUT,
1347 UACPI_RESOURCE_TYPE_CLOCK_INPUT,
1348 struct acpi_resource_clock_input,
1349 uacpi_resource_clock_input,
1350 .size_kind = UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
1351 .extra_size_for_native = extra_size_for_native_address_or_clock_input,
1352 .size_for_aml = size_for_aml_address_or_clock_input,
1353 .to_native = convert_clock_input,
1354 .to_aml = convert_clock_input,
1355 ),
1356};
1357
1358static enum uacpi_aml_resource get_aml_resource_type(uacpi_u8 raw_byte)
1359{
1360 if (raw_byte & ACPI_LARGE_ITEM) {
1361 return aml_resource_to_type[
1362 LARGE_RESOURCE_BASE + (raw_byte & ACPI_LARGE_ITEM_NAME_MASK)
1363 ];
1364 }
1365
1366 return aml_resource_to_type[
1367 (raw_byte >> ACPI_SMALL_ITEM_NAME_IDX) & ACPI_SMALL_ITEM_NAME_MASK
1368 ];
1369}
1370
1371static uacpi_status get_aml_resource_size(
1372 uacpi_u8 *data, uacpi_size bytes_left, uacpi_u16 *out_size
1373)
1374{
1375 uacpi_u16 size;
1376
1377 /*
1378 * Resource header is not included in size for both, so we subtract
1379 * the header size from bytes_left to validate it.
1380 */
1381 if (*data & ACPI_LARGE_ITEM) {
1382 if (uacpi_unlikely(bytes_left < 3))
1383 return UACPI_STATUS_AML_INVALID_RESOURCE;
1384
1385 uacpi_memcpy(dest: &size, src: data + 1, count: sizeof(size));
1386 bytes_left -= aml_resource_kind_to_header_size[
1387 UACPI_AML_RESOURCE_KIND_LARGE
1388 ];
1389 } else {
1390 size = *data & ACPI_SMALL_ITEM_LENGTH_MASK;
1391 bytes_left -= aml_resource_kind_to_header_size[
1392 UACPI_AML_RESOURCE_KIND_SMALL
1393 ];
1394 }
1395
1396 if (uacpi_unlikely(size > bytes_left))
1397 return UACPI_STATUS_AML_INVALID_RESOURCE;
1398
1399 *out_size = size;
1400 return UACPI_STATUS_OK;
1401}
1402
1403static uacpi_status validate_aml_serial_type(uacpi_u8 type)
1404{
1405 if (uacpi_unlikely(type < ACPI_SERIAL_TYPE_I2C ||
1406 type > ACPI_SERIAL_TYPE_CSI2)) {
1407 uacpi_error("invalid/unsupported serial connection type %d\n", type);
1408 return UACPI_STATUS_AML_INVALID_RESOURCE;
1409 }
1410
1411 return UACPI_STATUS_OK;
1412}
1413
1414uacpi_status uacpi_for_each_aml_resource(
1415 uacpi_buffer *buffer, uacpi_aml_resource_iteration_callback cb, void *user
1416)
1417{
1418 uacpi_status ret;
1419 uacpi_resource_iteration_decision decision;
1420 uacpi_u8 *data;
1421 uacpi_size bytes_left;
1422 uacpi_u16 resource_size;
1423 enum uacpi_aml_resource type;
1424 const struct uacpi_resource_spec *spec;
1425
1426 bytes_left = buffer->size;
1427 data = buffer->data;
1428
1429 while (bytes_left) {
1430 type = get_aml_resource_type(raw_byte: *data);
1431 if (uacpi_unlikely(type == UACPI_AML_RESOURCE_TYPE_INVALID))
1432 return UACPI_STATUS_AML_INVALID_RESOURCE;
1433
1434 ret = get_aml_resource_size(data, bytes_left, out_size: &resource_size);
1435 if (uacpi_unlikely_error(ret))
1436 return ret;
1437
1438 spec = &aml_resources[type];
1439 switch (spec->size_kind) {
1440 case UACPI_AML_RESOURCE_SIZE_KIND_FIXED:
1441 if (resource_size != spec->aml_size)
1442 return UACPI_STATUS_AML_INVALID_RESOURCE;
1443 break;
1444 case UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE:
1445 if (resource_size < spec->aml_size)
1446 return UACPI_STATUS_AML_INVALID_RESOURCE;
1447 break;
1448 case UACPI_AML_RESOURCE_SIZE_KIND_FIXED_OR_ONE_LESS:
1449 if (resource_size != spec->aml_size &&
1450 resource_size != (spec->aml_size - 1))
1451 return UACPI_STATUS_AML_INVALID_RESOURCE;
1452 break;
1453 default:
1454 return UACPI_STATUS_INTERNAL_ERROR;
1455 }
1456
1457 if (spec->type == UACPI_AML_RESOURCE_SERIAL_CONNECTION) {
1458 struct acpi_resource_serial *serial;
1459
1460 serial = (struct acpi_resource_serial*)data;
1461
1462 ret = validate_aml_serial_type(type: serial->type);
1463 if (uacpi_unlikely_error(ret))
1464 return ret;
1465 }
1466
1467 decision = cb(user, data, resource_size, spec);
1468 switch (decision) {
1469 case UACPI_RESOURCE_ITERATION_ABORT:
1470 return UACPI_STATUS_OK;
1471 case UACPI_RESOURCE_ITERATION_CONTINUE: {
1472 uacpi_size total_size = resource_size;
1473
1474 total_size += aml_resource_kind_to_header_size[spec->resource_kind];
1475 data += total_size;
1476 bytes_left -= total_size;
1477 break;
1478 }
1479 default:
1480 return UACPI_STATUS_INTERNAL_ERROR;
1481 }
1482
1483 if (type == UACPI_AML_RESOURCE_END_TAG)
1484 return UACPI_STATUS_OK;
1485 }
1486
1487 return UACPI_STATUS_NO_RESOURCE_END_TAG;
1488}
1489
1490static uacpi_resource_iteration_decision find_end(
1491 void *opaque, uacpi_u8 *data, uacpi_u16 resource_size,
1492 const struct uacpi_resource_spec *spec
1493)
1494{
1495 uacpi_u8 **out_ptr = opaque;
1496 UACPI_UNUSED(resource_size);
1497
1498 if (spec->type != UACPI_AML_RESOURCE_END_TAG)
1499 return UACPI_RESOURCE_ITERATION_CONTINUE;
1500
1501 *out_ptr = data;
1502 return UACPI_RESOURCE_ITERATION_ABORT;
1503}
1504
1505static uacpi_size native_size_for_aml_resource(
1506 uacpi_u8 *data, uacpi_u16 size, const struct uacpi_resource_spec *spec
1507)
1508{
1509 uacpi_size final_size = spec->native_size;
1510
1511 if (spec->extra_size_for_native)
1512 final_size += spec->extra_size_for_native(spec, data, size);
1513
1514 return UACPI_ALIGN_UP(final_size, sizeof(void*), uacpi_size);
1515}
1516
1517uacpi_status uacpi_find_aml_resource_end_tag(
1518 uacpi_buffer *buffer, uacpi_size *out_offset
1519)
1520{
1521 uacpi_u8 *end_tag_ptr;
1522 uacpi_status ret;
1523
1524 if (!buffer || buffer->size == 0) {
1525 *out_offset = 0;
1526 return UACPI_STATUS_OK;
1527 }
1528
1529 /*
1530 * This returning UACPI_STATUS_OK guarantees that end_tag_ptr is set to
1531 * a valid value because a missing end tag would produce a
1532 * UACPI_STATUS_NO_RESOURCE_END_TAG error.
1533 */
1534 ret = uacpi_for_each_aml_resource(buffer, cb: find_end, user: &end_tag_ptr);
1535 if (uacpi_unlikely_error(ret))
1536 return ret;
1537
1538 *out_offset = end_tag_ptr - buffer->byte_data;
1539 return UACPI_STATUS_OK;
1540}
1541
1542struct resource_conversion_ctx {
1543 union {
1544 void *buf;
1545 uacpi_u8 *byte_buf;
1546 uacpi_size size;
1547 };
1548 uacpi_status st;
1549};
1550
1551// Opcodes that are the same for both AML->native and native->AML
1552#define CONVERSION_OPCODES_COMMON(native_buf) \
1553 case UACPI_RESOURCE_CONVERT_OPCODE_END: \
1554 return UACPI_RESOURCE_ITERATION_CONTINUE; \
1555 \
1556 case UACPI_RESOURCE_CONVERT_OPCODE_FIELD_8: \
1557 case UACPI_RESOURCE_CONVERT_OPCODE_FIELD_16: \
1558 case UACPI_RESOURCE_CONVERT_OPCODE_FIELD_32: \
1559 case UACPI_RESOURCE_CONVERT_OPCODE_FIELD_64: { \
1560 uacpi_u8 bytes; \
1561 \
1562 bytes = 1 << (insn->code - UACPI_RESOURCE_CONVERT_OPCODE_FIELD_8); \
1563 accumulator = insn->imm == 0xFF ? 0 : accumulator + insn->imm; \
1564 \
1565 uacpi_memcpy(dst, src, bytes * UACPI_MAX(1, accumulator)); \
1566 accumulator = 0; \
1567 break; \
1568 } \
1569 \
1570 case UACPI_RESOURCE_CONVERT_OPCODE_SKIP_IF_AML_SIZE_LESS_THAN: \
1571 if (aml_size < insn->arg0) \
1572 pc += insn->imm; \
1573 break; \
1574 case UACPI_RESOURCE_CONVERT_OPCODE_SKIP_IF_NOT_EQUALS: \
1575 if (insn->arg0 != accumulator) \
1576 pc += insn->imm; \
1577 break; \
1578 \
1579 case UACPI_RESOURCE_CONVERT_OPCODE_SET_TO_IMM: \
1580 uacpi_memcpy(dst, &insn->imm, sizeof(insn->imm)); \
1581 break; \
1582 \
1583 case UACPI_RESOURCE_CONVERT_OPCODE_LOAD_IMM: \
1584 accumulator = insn->imm; \
1585 break; \
1586 \
1587 case UACPI_RESOURCE_CONVERT_OPCODE_LOAD_8_STORE: \
1588 uacpi_memcpy_zerout(&accumulator, src, sizeof(accumulator), 1); \
1589 uacpi_memcpy(dst, &accumulator, 1); \
1590 \
1591 if (insn->imm) \
1592 accumulator *= insn->imm; \
1593 break; \
1594 \
1595 case UACPI_RESOURCE_CONVERT_OPCODE_LOAD_8_NATIVE: \
1596 case UACPI_RESOURCE_CONVERT_OPCODE_LOAD_16_NATIVE: { \
1597 uacpi_u8 bytes; \
1598 \
1599 bytes = \
1600 1 << (insn->code - UACPI_RESOURCE_CONVERT_OPCODE_LOAD_8_NATIVE); \
1601 uacpi_memcpy_zerout( \
1602 &accumulator, native_buf, sizeof(accumulator), bytes \
1603 ); \
1604 break; \
1605 } \
1606 \
1607 case UACPI_RESOURCE_CONVERT_OPCODE_UNREACHABLE: \
1608 default: \
1609 if (insn->code != UACPI_RESOURCE_CONVERT_OPCODE_UNREACHABLE) { \
1610 uacpi_error("unhandled resource conversion opcode %d\n", \
1611 insn->code); \
1612 } else { \
1613 uacpi_error("tried to execute unreachable conversion opcode\n"); \
1614 } \
1615 ctx->st = UACPI_STATUS_INTERNAL_ERROR; \
1616 return UACPI_RESOURCE_ITERATION_ABORT;
1617
1618#define PTR_AT(ptr, offset) (void*)((uacpi_u8*)(ptr) + (offset))
1619
1620#define NATIVE_OFFSET(res, offset) \
1621 PTR_AT(res, (offset) + (sizeof(uacpi_u32) * 2))
1622
1623#define NATIVE_FIELD(res, name, field) \
1624 NATIVE_OFFSET(res, NATIVE_O(name, field))
1625
1626#define CHECK_AML_OOB(offset, prefix, what) \
1627 if (uacpi_unlikely(offset > ((uacpi_u32)aml_size + header_size))) { \
1628 uacpi_error(prefix what " is OOB: %zu > %u\n", \
1629 (uacpi_size)offset, (uacpi_u32)aml_size + header_size); \
1630 ctx->st = UACPI_STATUS_AML_INVALID_RESOURCE; \
1631 return UACPI_RESOURCE_ITERATION_ABORT; \
1632 }
1633
1634#define CHECK_AML_OFFSET_BASE(offset, what) \
1635 if (uacpi_unlikely(offset < base_aml_size_with_header)) { \
1636 uacpi_error( \
1637 "invalid " what " offset: %zu, expected at least %u\n", \
1638 (uacpi_size)offset, base_aml_size_with_header); \
1639 ctx->st = UACPI_STATUS_AML_INVALID_RESOURCE; \
1640 return UACPI_RESOURCE_ITERATION_ABORT; \
1641 }
1642
1643#define CHECK_AML_OFFSET(offset, what) \
1644 CHECK_AML_OOB(offset, "end of ", what) \
1645 CHECK_AML_OFFSET_BASE(offset, what)
1646
1647static uacpi_resource_type aml_serial_to_native_type(
1648 uacpi_u8 type
1649)
1650{
1651 return (type - ACPI_SERIAL_TYPE_I2C) +
1652 UACPI_RESOURCE_TYPE_SERIAL_I2C_CONNECTION;
1653}
1654
1655static uacpi_resource_iteration_decision do_aml_resource_to_native(
1656 void *opaque, uacpi_u8 *data, uacpi_u16 aml_size,
1657 const struct uacpi_resource_spec *spec
1658)
1659{
1660 struct resource_conversion_ctx *ctx = opaque;
1661 uacpi_resource *resource = ctx->buf;
1662 const struct uacpi_resource_convert_instruction *insns, *insn;
1663 uacpi_u8 header_size, pc = 0;
1664 uacpi_u8 *src, *dst;
1665 void *resource_end;
1666 uacpi_u16 base_aml_size;
1667 uacpi_u32 base_aml_size_with_header, accumulator = 0;
1668
1669 insns = spec->to_native;
1670
1671 header_size = aml_resource_kind_to_header_size[spec->resource_kind];
1672 resource->type = spec->native_type;
1673 resource->length = native_size_for_aml_resource(data, size: aml_size, spec);
1674 resource_end = ctx->byte_buf + spec->native_size;
1675 ctx->byte_buf += resource->length;
1676
1677 base_aml_size = base_aml_size_with_header = spec->aml_size;
1678 base_aml_size_with_header += header_size;
1679
1680 if (insns == UACPI_NULL)
1681 return UACPI_RESOURCE_ITERATION_CONTINUE;
1682
1683 for (;;) {
1684 insn = &insns[pc++];
1685
1686 src = data + insn->aml_offset;
1687 dst = NATIVE_OFFSET(resource, insn->native_offset);
1688
1689 switch (insn->code) {
1690 case UACPI_RESOURCE_CONVERT_OPCODE_PACKED_ARRAY_8:
1691 case UACPI_RESOURCE_CONVERT_OPCODE_PACKED_ARRAY_16: {
1692 uacpi_size i, j, max_bit;
1693 uacpi_u16 value;
1694
1695 if (insn->code == UACPI_RESOURCE_CONVERT_OPCODE_PACKED_ARRAY_16) {
1696 max_bit = 16;
1697 uacpi_memcpy(dest: &value, src, count: sizeof(uacpi_u16));
1698 } else {
1699 max_bit = 8;
1700 uacpi_memcpy_zerout(
1701 dst: &value, src, dst_size: sizeof(value), src_size: sizeof(uacpi_u8)
1702 );
1703 }
1704
1705 for (i = 0, j = 0; i < max_bit; ++i) {
1706 if (!(value & (1 << i)))
1707 continue;
1708
1709 dst[j++] = i;
1710 }
1711
1712 uacpi_memcpy(NATIVE_OFFSET(resource, insn->arg2), src: &j, count: 1);
1713 break;
1714 }
1715
1716 case UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_1:
1717 case UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_2:
1718 case UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_3:
1719 case UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_6:{
1720 uacpi_u8 mask, value;
1721
1722 mask = (insn->code - UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_1) + 1;
1723 mask = (1 << mask) - 1;
1724
1725 value = (*src >> insn->imm) & mask;
1726 uacpi_memcpy(dest: dst, src: &value, count: sizeof(value));
1727 break;
1728 }
1729
1730 case UACPI_RESOURCE_CONVERT_OPCODE_LOAD_AML_SIZE_32:
1731 accumulator = aml_size;
1732 uacpi_memcpy(dest: dst, src: &accumulator, count: 4);
1733 break;
1734
1735 case UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE:
1736 case UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE_NO_INDEX:
1737 case UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_LABEL: {
1738 uacpi_size offset = 0, max_offset, length = 0;
1739 uacpi_char *src_string, *dst_string;
1740 union {
1741 void *ptr;
1742 uacpi_resource_source *source;
1743 uacpi_resource_label *label;
1744 } dst_name = { .ptr = dst };
1745
1746 /*
1747 * Check if the string is bounded by anything at the top. If not, we
1748 * just assume it ends at the end of the resource.
1749 */
1750 if (insn->arg2) {
1751 uacpi_memcpy_zerout(dst: &max_offset, src: data + insn->arg2,
1752 dst_size: sizeof(max_offset), src_size: sizeof(uacpi_u16));
1753 CHECK_AML_OFFSET(max_offset, "resource source");
1754 } else {
1755 max_offset = aml_size + header_size;
1756 }
1757
1758 offset += base_aml_size_with_header;
1759 offset += accumulator;
1760
1761 if (insn->code != UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_LABEL)
1762 dst_name.source->index_present = UACPI_TRUE;
1763
1764 if (offset >= max_offset) {
1765 if (insn->code == UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE)
1766 dst_name.source->index_present = UACPI_FALSE;
1767 break;
1768 }
1769
1770 src_string = PTR_AT(data, offset);
1771
1772 if (insn->code == UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE) {
1773 uacpi_memcpy(dest: &dst_name.source->index, src: src_string++, count: 1);
1774 offset++;
1775 }
1776
1777 if (offset == max_offset)
1778 break;
1779
1780 while (offset++ < max_offset) {
1781 if (src_string[length++] == '\0')
1782 break;
1783 }
1784
1785 if (src_string[length - 1] != '\0') {
1786 uacpi_error("non-null-terminated resource source string\n");
1787 ctx->st = UACPI_STATUS_AML_INVALID_RESOURCE;
1788 return UACPI_RESOURCE_ITERATION_ABORT;
1789 }
1790
1791 dst_string = PTR_AT(resource_end, accumulator);
1792 uacpi_memcpy(dest: dst_string, src: src_string, count: length);
1793
1794 if (insn->code == UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_LABEL) {
1795 dst_name.label->length = length;
1796 dst_name.label->string = dst_string;
1797 } else {
1798 dst_name.source->length = length;
1799 dst_name.source->string = dst_string;
1800 }
1801
1802 break;
1803 }
1804
1805 case UACPI_RESOURCE_CONVERT_OPCODE_LOAD_PIN_TABLE_LENGTH:
1806 uacpi_memcpy_zerout(dst: &accumulator, src,
1807 dst_size: sizeof(accumulator), src_size: sizeof(uacpi_u16));
1808 CHECK_AML_OFFSET(accumulator, "pin table");
1809
1810 accumulator -= base_aml_size_with_header;
1811 break;
1812
1813 case UACPI_RESOURCE_CONVERT_OPCODE_PIN_TABLE: {
1814 uacpi_u16 entry_count = accumulator / 2;
1815
1816 /*
1817 * Pin table is stored right at the end of the resource buffer,
1818 * copy the data there.
1819 */
1820 uacpi_memcpy(
1821 dest: resource_end,
1822 src: data + base_aml_size_with_header,
1823 count: accumulator
1824 );
1825
1826 // Set pin_table_length
1827 uacpi_memcpy(dest: dst, src: &entry_count, count: sizeof(entry_count));
1828
1829 // Set pin_table pointer
1830 uacpi_memcpy(NATIVE_OFFSET(resource, insn->arg2),
1831 src: &resource_end, count: sizeof(void*));
1832 break;
1833 }
1834
1835 case UACPI_RESOURCE_CONVERT_OPCODE_VENDOR_DATA: {
1836 uacpi_size length;
1837 uacpi_u16 data_offset, offset_from_end;
1838 void *native_dst, *vendor_data;
1839
1840 uacpi_memcpy(dest: &data_offset, src, count: sizeof(data_offset));
1841 CHECK_AML_OFFSET(data_offset, "vendor data");
1842
1843 vendor_data = data + data_offset;
1844
1845 /*
1846 * Rebase the offset to cut off the header as it's not included
1847 * in the size fields.
1848 */
1849 data_offset -= header_size;
1850
1851 length = aml_size - data_offset;
1852 if (length == 0)
1853 break;
1854
1855 uacpi_memcpy(dest: dst, src: &length, count: sizeof(uacpi_u16));
1856
1857 offset_from_end = data_offset - base_aml_size;
1858 native_dst = PTR_AT(resource_end, offset_from_end);
1859
1860 uacpi_memcpy(dest: native_dst, src: vendor_data, count: length);
1861 uacpi_memcpy(NATIVE_OFFSET(resource, insn->arg2),
1862 src: &native_dst, count: sizeof(void*));
1863 break;
1864 }
1865
1866 case UACPI_RESOURCE_CONVERT_OPCODE_SERIAL_TYPE_SPECIFIC: {
1867 uacpi_resource_serial_bus_common *serial_bus_common;
1868 uacpi_u8 serial_type, extra_size, type_length;
1869
1870 serial_bus_common = &resource->serial_bus_common;
1871 serial_type = *src;
1872 serial_bus_common->type = serial_type;
1873 resource->type = aml_serial_to_native_type(type: serial_type);
1874
1875 /*
1876 * Now that we know the serial type rebase the end pointers and
1877 * sizes.
1878 */
1879 resource_end = PTR_AT(
1880 resource_end,
1881 aml_serial_resource_to_extra_native_size[serial_type]
1882 );
1883 extra_size = aml_serial_resource_to_extra_aml_size[serial_type];
1884 base_aml_size += extra_size;
1885 base_aml_size_with_header += extra_size;
1886
1887 type_length = serial_bus_common->type_data_length;
1888 if (uacpi_unlikely(type_length < extra_size)) {
1889 uacpi_error(
1890 "invalid type-specific data length: %d, "
1891 "expected at least %d\n", type_length, extra_size
1892 );
1893 ctx->st = UACPI_STATUS_AML_INVALID_RESOURCE;
1894 return UACPI_RESOURCE_ITERATION_ABORT;
1895 }
1896
1897 /*
1898 * Calculate the length of the vendor data. All the extra data
1899 * beyond the end of type-specific size is considered vendor data.
1900 */
1901 accumulator = type_length - extra_size;
1902 if (accumulator == 0)
1903 break;
1904
1905 serial_bus_common->vendor_data_length = accumulator;
1906 serial_bus_common->vendor_data = resource_end;
1907 uacpi_memcpy(
1908 dest: resource_end,
1909 src: data + base_aml_size_with_header,
1910 count: accumulator
1911 );
1912 break;
1913 }
1914
1915 CONVERSION_OPCODES_COMMON(dst)
1916 }
1917 }
1918}
1919
1920static uacpi_status aml_resources_to_native(
1921 uacpi_buffer *aml_buffer, void *native_buffer
1922)
1923{
1924 uacpi_status ret;
1925 struct resource_conversion_ctx ctx = {
1926 .buf = native_buffer,
1927 };
1928
1929 ret = uacpi_for_each_aml_resource(
1930 buffer: aml_buffer, cb: do_aml_resource_to_native, user: &ctx
1931 );
1932 if (uacpi_unlikely_error(ret))
1933 return ret;
1934
1935 return ctx.st;
1936}
1937
1938static uacpi_resource_iteration_decision accumulate_native_buffer_size(
1939 void *opaque, uacpi_u8 *data, uacpi_u16 resource_size,
1940 const struct uacpi_resource_spec *spec
1941)
1942{
1943 struct resource_conversion_ctx *ctx = opaque;
1944 uacpi_size size_for_this;
1945
1946 size_for_this = native_size_for_aml_resource(data, size: resource_size, spec);
1947 if (size_for_this == 0 || (ctx->size + size_for_this) < ctx->size) {
1948 uacpi_error("invalid native size for aml resource: %zu\n",
1949 size_for_this);
1950 ctx->st = UACPI_STATUS_AML_INVALID_RESOURCE;
1951 return UACPI_RESOURCE_ITERATION_ABORT;
1952 }
1953
1954 ctx->size += size_for_this;
1955 return UACPI_RESOURCE_ITERATION_CONTINUE;
1956}
1957
1958static uacpi_status eval_resource_helper(
1959 uacpi_namespace_node *node, const uacpi_char *method,
1960 uacpi_object **out_obj
1961)
1962{
1963 uacpi_object *obj;
1964
1965 obj = uacpi_namespace_node_get_object(node);
1966 if (uacpi_unlikely(obj == UACPI_NULL || obj->type != UACPI_OBJECT_DEVICE))
1967 return UACPI_STATUS_INVALID_ARGUMENT;
1968
1969 return uacpi_eval_typed(
1970 parent: node, path: method, UACPI_NULL, UACPI_OBJECT_BUFFER_BIT, ret: out_obj
1971 );
1972}
1973
1974uacpi_status uacpi_native_resources_from_aml(
1975 uacpi_buffer *aml_buffer, uacpi_resources **out_resources
1976)
1977{
1978 uacpi_status ret;
1979 struct resource_conversion_ctx ctx = { 0 };
1980 uacpi_resources *resources;
1981
1982 ret = uacpi_for_each_aml_resource(
1983 buffer: aml_buffer, cb: accumulate_native_buffer_size, user: &ctx
1984 );
1985 if (uacpi_unlikely_error(ret))
1986 return ret;
1987
1988 if (uacpi_unlikely_error(ctx.st))
1989 return ctx.st;
1990
1991 // Realistically any resource buffer bigger than this is probably a bug
1992 if (uacpi_unlikely(ctx.size > (5 * 1024u * 1024u))) {
1993 uacpi_error("bug: bogus native resource buffer size %zu\n", ctx.size);
1994 return UACPI_STATUS_INTERNAL_ERROR;
1995 }
1996
1997 resources = uacpi_kernel_calloc(count: ctx.size + sizeof(uacpi_resources), size: 1);
1998 if (uacpi_unlikely(resources == UACPI_NULL))
1999 return UACPI_STATUS_OUT_OF_MEMORY;
2000 resources->length = ctx.size;
2001 resources->entries = UACPI_PTR_ADD(resources, sizeof(uacpi_resources));
2002
2003 ret = aml_resources_to_native(aml_buffer, native_buffer: resources->entries);
2004 if (uacpi_unlikely_error(ret)) {
2005 uacpi_free_resources(resources);
2006 return ret;
2007 }
2008
2009 *out_resources = resources;
2010 return ret;
2011}
2012
2013void uacpi_free_resources(uacpi_resources *resources)
2014{
2015 if (resources == UACPI_NULL)
2016 return;
2017
2018 uacpi_free(resources, sizeof(uacpi_resources) + resources->length);
2019}
2020
2021static uacpi_status extract_native_resources_from_method(
2022 uacpi_namespace_node *device, const uacpi_char *method,
2023 uacpi_resources **out_resources
2024)
2025{
2026 uacpi_status ret;
2027 uacpi_object *obj;
2028
2029 ret = eval_resource_helper(node: device, method, out_obj: &obj);
2030 if (uacpi_unlikely_error(ret))
2031 return ret;
2032
2033 ret = uacpi_native_resources_from_aml(aml_buffer: obj->buffer, out_resources);
2034 uacpi_object_unref(obj);
2035
2036 return ret;
2037}
2038
2039uacpi_status uacpi_get_current_resources(
2040 uacpi_namespace_node *device, uacpi_resources **out_resources
2041)
2042{
2043 return extract_native_resources_from_method(device, method: "_CRS", out_resources);
2044}
2045
2046uacpi_status uacpi_get_possible_resources(
2047 uacpi_namespace_node *device, uacpi_resources **out_resources
2048)
2049{
2050 return extract_native_resources_from_method(device, method: "_PRS", out_resources);
2051}
2052
2053uacpi_status uacpi_for_each_resource(
2054 uacpi_resources *resources, uacpi_resource_iteration_callback cb, void *user
2055)
2056{
2057 uacpi_size bytes_left = resources->length;
2058 uacpi_resource *current = resources->entries;
2059 uacpi_resource_iteration_decision decision;
2060
2061 while (bytes_left) {
2062 // At least the head bytes
2063 if (uacpi_unlikely(bytes_left < 4)) {
2064 uacpi_error("corrupted resource buffer %p length %zu\n",
2065 resources, resources->length);
2066 return UACPI_STATUS_INVALID_ARGUMENT;
2067 }
2068
2069 if (uacpi_unlikely(current->type > UACPI_RESOURCE_TYPE_MAX)) {
2070 uacpi_error("invalid resource type %d\n", current->type);
2071 return UACPI_STATUS_INVALID_ARGUMENT;
2072 }
2073
2074 if (uacpi_unlikely(current->length > bytes_left)) {
2075 uacpi_error("corrupted resource@%p length %u (%zu bytes left)\n",
2076 current, current->length, bytes_left);
2077 return UACPI_STATUS_INVALID_ARGUMENT;
2078 }
2079
2080 decision = cb(user, current);
2081
2082 if (decision == UACPI_RESOURCE_ITERATION_ABORT ||
2083 current->type == UACPI_RESOURCE_TYPE_END_TAG)
2084 return UACPI_STATUS_OK;
2085
2086 bytes_left -= current->length;
2087 current = (uacpi_resource*)((uacpi_u8*)current + current->length);
2088 }
2089
2090 return UACPI_STATUS_NO_RESOURCE_END_TAG;
2091}
2092
2093uacpi_status uacpi_for_each_device_resource(
2094 uacpi_namespace_node *device, const uacpi_char *method,
2095 uacpi_resource_iteration_callback cb, void *user
2096)
2097{
2098 uacpi_status ret;
2099 uacpi_resources *resources;
2100
2101 ret = extract_native_resources_from_method(device, method, out_resources: &resources);
2102 if (uacpi_unlikely_error(ret))
2103 return ret;
2104
2105 ret = uacpi_for_each_resource(resources, cb, user);
2106 uacpi_free_resources(resources);
2107
2108 return ret;
2109}
2110
2111static const struct uacpi_resource_spec *resource_spec_from_native(
2112 uacpi_resource *resource
2113)
2114{
2115 return &aml_resources[native_resource_to_type[resource->type]];
2116}
2117
2118static uacpi_size aml_size_for_native_resource(
2119 uacpi_resource *resource, const struct uacpi_resource_spec *spec
2120)
2121{
2122 return spec->size_for_aml ?
2123 spec->size_for_aml(spec, resource) :
2124 aml_size_with_header(spec);
2125}
2126
2127static uacpi_resource_iteration_decision do_native_resource_to_aml(
2128 void *opaque, uacpi_resource *resource
2129)
2130{
2131 struct resource_conversion_ctx *ctx = opaque;
2132 const struct uacpi_resource_spec *spec;
2133 const struct uacpi_resource_convert_instruction *insns, *insn;
2134 uacpi_u8 pc = 0;
2135 uacpi_u8 *dst_base, *src, *dst;
2136 uacpi_u32 aml_size, base_aml_size_with_header, accumulator = 0;
2137 void *resource_end;
2138
2139 spec = resource_spec_from_native(resource);
2140 aml_size = aml_size_for_native_resource(resource, spec);
2141 insns = spec->to_aml;
2142
2143 dst_base = ctx->byte_buf;
2144 ctx->byte_buf += aml_size;
2145 aml_size -= aml_resource_kind_to_header_size[spec->resource_kind];
2146
2147 base_aml_size_with_header = spec->aml_size;
2148 base_aml_size_with_header += aml_resource_kind_to_header_size[
2149 spec->resource_kind
2150 ];
2151 resource_end = PTR_AT(resource, spec->native_size);
2152
2153 if (spec->resource_kind == UACPI_AML_RESOURCE_KIND_LARGE) {
2154 *dst_base = ACPI_LARGE_ITEM | type_to_aml_resource[spec->type];
2155 uacpi_memcpy(dest: dst_base + 1, src: &aml_size, count: sizeof(uacpi_u16));
2156 } else {
2157 *dst_base = type_to_aml_resource[spec->type] << ACPI_SMALL_ITEM_NAME_IDX;
2158 *dst_base |= aml_size;
2159 }
2160
2161 if (insns == UACPI_NULL)
2162 return UACPI_RESOURCE_ITERATION_CONTINUE;
2163
2164 for (;;) {
2165 insn = &insns[pc++];
2166
2167 src = NATIVE_OFFSET(resource, insn->native_offset);
2168 dst = dst_base + insn->aml_offset;
2169
2170 switch (insn->code) {
2171 case UACPI_RESOURCE_CONVERT_OPCODE_PACKED_ARRAY_8:
2172 case UACPI_RESOURCE_CONVERT_OPCODE_PACKED_ARRAY_16: {
2173 uacpi_u8 i, *array_size, bytes = 1;
2174 uacpi_u16 mask = 0;
2175
2176 array_size = NATIVE_OFFSET(resource, insn->arg2);
2177 for (i = 0; i < *array_size; ++i)
2178 mask |= 1 << src[i];
2179
2180 if (insn->code == UACPI_RESOURCE_CONVERT_OPCODE_PACKED_ARRAY_16)
2181 bytes = 2;
2182
2183 uacpi_memcpy(dest: dst, src: &mask, count: bytes);
2184 break;
2185 }
2186
2187 case UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_1:
2188 case UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_2:
2189 case UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_3:
2190 case UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_6:
2191 *dst |= *src << insn->imm;
2192 break;
2193
2194 case UACPI_RESOURCE_CONVERT_OPCODE_LOAD_AML_SIZE_32:
2195 accumulator = aml_size;
2196 break;
2197
2198 case UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE:
2199 case UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE_NO_INDEX:
2200 case UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_LABEL: {
2201 uacpi_size source_offset, length;
2202 uacpi_u8 *dst_string;
2203 const uacpi_char *src_string;
2204 union {
2205 void *ptr;
2206 uacpi_resource_source *source;
2207 uacpi_resource_label *label;
2208 } src_name = { .ptr = src };
2209
2210 source_offset = base_aml_size_with_header + accumulator;
2211 dst_string = dst_base + source_offset;
2212
2213 if (insn->aml_offset)
2214 uacpi_memcpy(dest: dst, src: &source_offset, count: sizeof(uacpi_u16));
2215
2216 if (insn->code == UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE &&
2217 src_name.source->index_present)
2218 uacpi_memcpy(dest: dst_string++, src: &src_name.source->index, count: 1);
2219
2220 if (insn->code == UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_LABEL) {
2221 length = src_name.label->length;
2222 src_string = src_name.label->string;
2223 } else {
2224 length = src_name.source->length;
2225 src_string = src_name.source->string;
2226 }
2227
2228 if (length == 0)
2229 break;
2230
2231 if (uacpi_unlikely(src_string == UACPI_NULL)) {
2232 uacpi_error(
2233 "source string length is %zu but the pointer is NULL\n",
2234 length
2235 );
2236 ctx->st = UACPI_STATUS_INVALID_ARGUMENT;
2237 return UACPI_RESOURCE_ITERATION_ABORT;
2238 }
2239
2240 uacpi_memcpy(dest: dst_string, src: src_string, count: length);
2241 break;
2242 }
2243
2244 case UACPI_RESOURCE_CONVERT_OPCODE_LOAD_PIN_TABLE_LENGTH:
2245 uacpi_memcpy_zerout(dst: &accumulator, src,
2246 dst_size: sizeof(accumulator), src_size: sizeof(uacpi_u16));
2247 accumulator *= sizeof(uacpi_u16);
2248 break;
2249
2250 case UACPI_RESOURCE_CONVERT_OPCODE_PIN_TABLE:
2251 /*
2252 * The pin table resides right at the end of the base resource,
2253 * set the offset to it in the AML we're encoding.
2254 */
2255 uacpi_memcpy(dest: dst, src: &base_aml_size_with_header, count: sizeof(uacpi_u16));
2256
2257 /*
2258 * Copy the actual data. It also resides right at the end of the
2259 * native base resource.
2260 */
2261 uacpi_memcpy(
2262 dest: dst_base + base_aml_size_with_header,
2263 src: resource_end,
2264 count: accumulator
2265 );
2266 break;
2267
2268 case UACPI_RESOURCE_CONVERT_OPCODE_VENDOR_DATA: {
2269 uacpi_u16 vendor_data_length, data_offset, vendor_data_offset;
2270 uacpi_u8 *vendor_data;
2271
2272 // Read the vendor_data pointer
2273 uacpi_memcpy(dest: &vendor_data, NATIVE_OFFSET(resource, insn->arg2),
2274 count: sizeof(void*));
2275 uacpi_memcpy(dest: &vendor_data_length, src, count: sizeof(uacpi_u16));
2276
2277 if (vendor_data == UACPI_NULL) {
2278 uacpi_size full_aml_size;
2279
2280 if (uacpi_unlikely(vendor_data_length != 0)) {
2281 uacpi_error(
2282 "vendor_data_length is %d, but pointer is NULL\n",
2283 vendor_data_length
2284 );
2285 ctx->st = UACPI_STATUS_INVALID_ARGUMENT;
2286 return UACPI_RESOURCE_ITERATION_ABORT;
2287 }
2288
2289 /*
2290 * There's no vendor data. The specification still mandates
2291 * that we fill the vendor data offset field correctly, meaning
2292 * we set it to the total length of the resource.
2293 */
2294 full_aml_size = aml_size;
2295 full_aml_size += aml_resource_kind_to_header_size[
2296 spec->resource_kind
2297 ];
2298
2299 uacpi_memcpy(dest: dst, src: &full_aml_size, count: sizeof(uacpi_u16));
2300 break;
2301 }
2302
2303 /*
2304 * Calculate the offset of vendor data from the end of the native
2305 * resource and use it since it matches the offset from the end of
2306 * the AML resource.
2307 *
2308 * Non-zero value means there's a source string in between.
2309 */
2310 data_offset = vendor_data - (uacpi_u8*)resource_end;
2311 vendor_data_offset = data_offset + base_aml_size_with_header;
2312
2313 // Write vendor_data_offset
2314 uacpi_memcpy(dest: dst, src: &vendor_data_offset, count: sizeof(uacpi_u16));
2315
2316 /*
2317 * Write vendor_data_length, this field is right after
2318 * vendor_data_offset, and is completely redundant, but it exists
2319 * nonetheless.
2320 */
2321 uacpi_memcpy(
2322 dest: dst + sizeof(uacpi_u16),
2323 src: &vendor_data_length,
2324 count: sizeof(vendor_data_length)
2325 );
2326
2327 // Finally write the data itself
2328 uacpi_memcpy(
2329 dest: dst_base + vendor_data_offset,
2330 src: vendor_data,
2331 count: vendor_data_length
2332 );
2333 break;
2334 }
2335
2336 case UACPI_RESOURCE_CONVERT_OPCODE_SERIAL_TYPE_SPECIFIC: {
2337 uacpi_u8 serial_type = *src;
2338 *dst = serial_type;
2339
2340 ctx->st = validate_aml_serial_type(type: serial_type);
2341 if (uacpi_unlikely_error(ctx->st))
2342 return UACPI_RESOURCE_ITERATION_ABORT;
2343
2344 if (uacpi_unlikely(resource->type !=
2345 aml_serial_to_native_type(serial_type))) {
2346 uacpi_error(
2347 "native serial resource type %d doesn't match expected %d\n",
2348 resource->type, aml_serial_to_native_type(serial_type)
2349 );
2350 ctx->st = UACPI_STATUS_INVALID_ARGUMENT;
2351 return UACPI_RESOURCE_ITERATION_ABORT;
2352 }
2353
2354 // Rebase the end pointer & size now that we know the serial type
2355 resource_end = PTR_AT(
2356 resource_end,
2357 aml_serial_resource_to_extra_native_size[serial_type]
2358 );
2359 base_aml_size_with_header += aml_serial_resource_to_extra_aml_size[
2360 serial_type
2361 ];
2362
2363 accumulator = resource->serial_bus_common.vendor_data_length;
2364 if (accumulator == 0)
2365 break;
2366
2367 // Copy vendor data
2368 uacpi_memcpy(
2369 dest: dst_base + base_aml_size_with_header,
2370 src: resource_end,
2371 count: accumulator
2372 );
2373 break;
2374 }
2375
2376 CONVERSION_OPCODES_COMMON(src)
2377 }
2378 }
2379}
2380
2381#define INLINE_END_TAG &(uacpi_resource) { .type = UACPI_RESOURCE_TYPE_END_TAG }
2382
2383static uacpi_status native_resources_to_aml(
2384 uacpi_resources *native_resources, void *aml_buffer
2385)
2386{
2387 uacpi_status ret;
2388 struct resource_conversion_ctx ctx = {
2389 .buf = aml_buffer,
2390 };
2391
2392 ret = uacpi_for_each_resource(
2393 resources: native_resources, cb: do_native_resource_to_aml, user: &ctx
2394 );
2395 if (ret == UACPI_STATUS_NO_RESOURCE_END_TAG) {
2396 // An end tag is always included
2397 do_native_resource_to_aml(opaque: &ctx, INLINE_END_TAG);
2398 ret = UACPI_STATUS_OK;
2399 }
2400 if (uacpi_unlikely_error(ret))
2401 return ret;
2402
2403 return ctx.st;
2404}
2405
2406static uacpi_resource_iteration_decision accumulate_aml_buffer_size(
2407 void *opaque, uacpi_resource *resource
2408)
2409{
2410 struct resource_conversion_ctx *ctx = opaque;
2411 const struct uacpi_resource_spec *spec;
2412 uacpi_size size_for_this;
2413
2414 // resource->type is sanitized to be valid here by the iteration function
2415 spec = resource_spec_from_native(resource);
2416
2417 size_for_this = aml_size_for_native_resource(resource, spec);
2418 if (size_for_this == 0 || (ctx->size + size_for_this) < ctx->size) {
2419 uacpi_error("invalid aml size for native resource: %zu\n",
2420 size_for_this);
2421 ctx->st = UACPI_STATUS_INVALID_ARGUMENT;
2422 return UACPI_RESOURCE_ITERATION_ABORT;
2423 }
2424
2425 ctx->size += size_for_this;
2426 return UACPI_RESOURCE_ITERATION_CONTINUE;
2427}
2428
2429uacpi_status uacpi_native_resources_to_aml(
2430 uacpi_resources *resources, uacpi_object **out_template
2431)
2432{
2433 uacpi_status ret;
2434 uacpi_object *obj;
2435 void *buffer;
2436 struct resource_conversion_ctx ctx = { 0 };
2437
2438 ret = uacpi_for_each_resource(
2439 resources, cb: accumulate_aml_buffer_size, user: &ctx
2440 );
2441 if (ret == UACPI_STATUS_NO_RESOURCE_END_TAG) {
2442 // An end tag is always included
2443 accumulate_aml_buffer_size(opaque: &ctx, INLINE_END_TAG);
2444 ret = UACPI_STATUS_OK;
2445 }
2446 if (uacpi_unlikely_error(ret))
2447 return ret;
2448 if (uacpi_unlikely_error(ctx.st))
2449 return ctx.st;
2450
2451 // Same reasoning as native_resource_from_aml
2452 if (uacpi_unlikely(ctx.size > (5 * 1024u * 1024u))) {
2453 uacpi_error("bug: bogus target aml resource buffer size %zu\n",
2454 ctx.size);
2455 return UACPI_STATUS_INTERNAL_ERROR;
2456 }
2457
2458 buffer = uacpi_kernel_calloc(count: ctx.size, size: 1);
2459 if (uacpi_unlikely(buffer == UACPI_NULL))
2460 return UACPI_STATUS_OUT_OF_MEMORY;
2461
2462 obj = uacpi_create_object(type: UACPI_OBJECT_BUFFER);
2463 if (uacpi_unlikely(obj == UACPI_NULL)) {
2464 uacpi_free(buffer, ctx.size);
2465 return UACPI_STATUS_OUT_OF_MEMORY;
2466 }
2467
2468 obj->buffer->data = buffer;
2469 obj->buffer->size = ctx.size;
2470
2471 ret = native_resources_to_aml(native_resources: resources, aml_buffer: buffer);
2472 if (uacpi_unlikely_error(ret))
2473 uacpi_object_unref(obj);
2474
2475 if (ret == UACPI_STATUS_OK)
2476 *out_template = obj;
2477
2478 return ret;
2479}
2480
2481uacpi_status uacpi_set_resources(
2482 uacpi_namespace_node *device, uacpi_resources *resources
2483)
2484{
2485 uacpi_status ret;
2486 uacpi_object *res_template;
2487 uacpi_args args;
2488
2489 ret = uacpi_native_resources_to_aml(resources, out_template: &res_template);
2490 if (uacpi_unlikely_error(ret))
2491 return ret;
2492
2493 args.objects = &res_template;
2494 args.count = 1;
2495 ret = uacpi_eval(parent: device, path: "_SRS", args: &args, UACPI_NULL);
2496
2497 uacpi_object_unref(obj: res_template);
2498 return ret;
2499}
2500