xref: /openbmc/qemu/hw/acpi/aml-build.c (revision 6ece7053d6a4a502d2ea5d24ecf512caaa1437c7)
1 /* Support for generating ACPI tables and passing them to Guests
2  *
3  * Copyright (C) 2015 Red Hat Inc
4  *
5  * Author: Michael S. Tsirkin <mst@redhat.com>
6  * Author: Igor Mammedov <imammedo@redhat.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17 
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include "hw/acpi/aml-build.h"
28 #include "qemu/bswap.h"
29 
30 GArray *build_alloc_array(void)
31 {
32     return g_array_new(false, true /* clear */, 1);
33 }
34 
35 void build_free_array(GArray *array)
36 {
37     g_array_free(array, true);
38 }
39 
40 void build_prepend_byte(GArray *array, uint8_t val)
41 {
42     g_array_prepend_val(array, val);
43 }
44 
45 void build_append_byte(GArray *array, uint8_t val)
46 {
47     g_array_append_val(array, val);
48 }
49 
50 void build_append_array(GArray *array, GArray *val)
51 {
52     g_array_append_vals(array, val->data, val->len);
53 }
54 
55 #define ACPI_NAMESEG_LEN 4
56 
57 static void
58 build_append_nameseg(GArray *array, const char *seg)
59 {
60     /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
61     int len;
62 
63     len = strlen(seg);
64     assert(len <= ACPI_NAMESEG_LEN);
65 
66     g_array_append_vals(array, seg, len);
67     /* Pad up to ACPI_NAMESEG_LEN characters if necessary. */
68     g_array_append_vals(array, "____", ACPI_NAMESEG_LEN - len);
69 }
70 
71 static void
72 build_append_namestringv(GArray *array, const char *format, va_list ap)
73 {
74     /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
75     char *s;
76     int len;
77     va_list va_len;
78     char **segs;
79     char **segs_iter;
80     int seg_count = 0;
81 
82     va_copy(va_len, ap);
83     len = vsnprintf(NULL, 0, format, va_len);
84     va_end(va_len);
85     len += 1;
86     s = g_new(typeof(*s), len);
87 
88     len = vsnprintf(s, len, format, ap);
89 
90     segs = g_strsplit(s, ".", 0);
91     g_free(s);
92 
93     /* count segments */
94     segs_iter = segs;
95     while (*segs_iter) {
96         ++segs_iter;
97         ++seg_count;
98     }
99     /*
100      * ACPI 5.0 spec: 20.2.2 Name Objects Encoding:
101      * "SegCount can be from 1 to 255"
102      */
103     assert(seg_count > 0 && seg_count <= 255);
104 
105     /* handle RootPath || PrefixPath */
106     s = *segs;
107     while (*s == '\\' || *s == '^') {
108         build_append_byte(array, *s);
109         ++s;
110     }
111 
112     switch (seg_count) {
113     case 1:
114         if (!*s) {
115             build_append_byte(array, 0x0); /* NullName */
116         } else {
117             build_append_nameseg(array, s);
118         }
119         break;
120 
121     case 2:
122         build_append_byte(array, 0x2E); /* DualNamePrefix */
123         build_append_nameseg(array, s);
124         build_append_nameseg(array, segs[1]);
125         break;
126     default:
127         build_append_byte(array, 0x2F); /* MultiNamePrefix */
128         build_append_byte(array, seg_count);
129 
130         /* handle the 1st segment manually due to prefix/root path */
131         build_append_nameseg(array, s);
132 
133         /* add the rest of segments */
134         segs_iter = segs + 1;
135         while (*segs_iter) {
136             build_append_nameseg(array, *segs_iter);
137             ++segs_iter;
138         }
139         break;
140     }
141     g_strfreev(segs);
142 }
143 
144 void build_append_namestring(GArray *array, const char *format, ...)
145 {
146     va_list ap;
147 
148     va_start(ap, format);
149     build_append_namestringv(array, format, ap);
150     va_end(ap);
151 }
152 
153 /* 5.4 Definition Block Encoding */
154 enum {
155     PACKAGE_LENGTH_1BYTE_SHIFT = 6, /* Up to 63 - use extra 2 bits. */
156     PACKAGE_LENGTH_2BYTE_SHIFT = 4,
157     PACKAGE_LENGTH_3BYTE_SHIFT = 12,
158     PACKAGE_LENGTH_4BYTE_SHIFT = 20,
159 };
160 
161 void
162 build_prepend_package_length(GArray *package, unsigned length, bool incl_self)
163 {
164     uint8_t byte;
165     unsigned length_bytes;
166 
167     if (length + 1 < (1 << PACKAGE_LENGTH_1BYTE_SHIFT)) {
168         length_bytes = 1;
169     } else if (length + 2 < (1 << PACKAGE_LENGTH_3BYTE_SHIFT)) {
170         length_bytes = 2;
171     } else if (length + 3 < (1 << PACKAGE_LENGTH_4BYTE_SHIFT)) {
172         length_bytes = 3;
173     } else {
174         length_bytes = 4;
175     }
176 
177     /*
178      * NamedField uses PkgLength encoding but it doesn't include length
179      * of PkgLength itself.
180      */
181     if (incl_self) {
182         /*
183          * PkgLength is the length of the inclusive length of the data
184          * and PkgLength's length itself when used for terms with
185          * explitit length.
186          */
187         length += length_bytes;
188     }
189 
190     switch (length_bytes) {
191     case 1:
192         byte = length;
193         build_prepend_byte(package, byte);
194         return;
195     case 4:
196         byte = length >> PACKAGE_LENGTH_4BYTE_SHIFT;
197         build_prepend_byte(package, byte);
198         length &= (1 << PACKAGE_LENGTH_4BYTE_SHIFT) - 1;
199         /* fall through */
200     case 3:
201         byte = length >> PACKAGE_LENGTH_3BYTE_SHIFT;
202         build_prepend_byte(package, byte);
203         length &= (1 << PACKAGE_LENGTH_3BYTE_SHIFT) - 1;
204         /* fall through */
205     case 2:
206         byte = length >> PACKAGE_LENGTH_2BYTE_SHIFT;
207         build_prepend_byte(package, byte);
208         length &= (1 << PACKAGE_LENGTH_2BYTE_SHIFT) - 1;
209         /* fall through */
210     }
211     /*
212      * Most significant two bits of byte zero indicate how many following bytes
213      * are in PkgLength encoding.
214      */
215     byte = ((length_bytes - 1) << PACKAGE_LENGTH_1BYTE_SHIFT) | length;
216     build_prepend_byte(package, byte);
217 }
218 
219 static void
220 build_append_pkg_length(GArray *array, unsigned length, bool incl_self)
221 {
222     GArray *tmp = build_alloc_array();
223 
224     build_prepend_package_length(tmp, length, incl_self);
225     build_append_array(array, tmp);
226     build_free_array(tmp);
227 }
228 
229 void build_package(GArray *package, uint8_t op)
230 {
231     build_prepend_package_length(package, package->len, true);
232     build_prepend_byte(package, op);
233 }
234 
235 void build_extop_package(GArray *package, uint8_t op)
236 {
237     build_package(package, op);
238     build_prepend_byte(package, 0x5B); /* ExtOpPrefix */
239 }
240 
241 static void build_append_int_noprefix(GArray *table, uint64_t value, int size)
242 {
243     int i;
244 
245     for (i = 0; i < size; ++i) {
246         build_append_byte(table, value & 0xFF);
247         value = value >> 8;
248     }
249 }
250 
251 void build_append_int(GArray *table, uint64_t value)
252 {
253     if (value == 0x00) {
254         build_append_byte(table, 0x00); /* ZeroOp */
255     } else if (value == 0x01) {
256         build_append_byte(table, 0x01); /* OneOp */
257     } else if (value <= 0xFF) {
258         build_append_byte(table, 0x0A); /* BytePrefix */
259         build_append_int_noprefix(table, value, 1);
260     } else if (value <= 0xFFFF) {
261         build_append_byte(table, 0x0B); /* WordPrefix */
262         build_append_int_noprefix(table, value, 2);
263     } else if (value <= 0xFFFFFFFF) {
264         build_append_byte(table, 0x0C); /* DWordPrefix */
265         build_append_int_noprefix(table, value, 4);
266     } else {
267         build_append_byte(table, 0x0E); /* QWordPrefix */
268         build_append_int_noprefix(table, value, 8);
269     }
270 }
271 
272 static GPtrArray *alloc_list;
273 
274 static Aml *aml_alloc(void)
275 {
276     Aml *var = g_new0(typeof(*var), 1);
277 
278     g_ptr_array_add(alloc_list, var);
279     var->block_flags = AML_NO_OPCODE;
280     var->buf = build_alloc_array();
281     return var;
282 }
283 
284 static Aml *aml_opcode(uint8_t op)
285 {
286     Aml *var = aml_alloc();
287 
288     var->op  = op;
289     var->block_flags = AML_OPCODE;
290     return var;
291 }
292 
293 static Aml *aml_bundle(uint8_t op, AmlBlockFlags flags)
294 {
295     Aml *var = aml_alloc();
296 
297     var->op  = op;
298     var->block_flags = flags;
299     return var;
300 }
301 
302 static void aml_free(gpointer data)
303 {
304     Aml *var = data;
305     build_free_array(var->buf);
306 }
307 
308 Aml *init_aml_allocator(void)
309 {
310     Aml *var;
311 
312     assert(!alloc_list);
313     alloc_list = g_ptr_array_new_with_free_func(aml_free);
314     var = aml_alloc();
315     return var;
316 }
317 
318 void free_aml_allocator(void)
319 {
320     g_ptr_array_free(alloc_list, true);
321     alloc_list = 0;
322 }
323 
324 /* pack data with DefBuffer encoding */
325 static void build_buffer(GArray *array, uint8_t op)
326 {
327     GArray *data = build_alloc_array();
328 
329     build_append_int(data, array->len);
330     g_array_prepend_vals(array, data->data, data->len);
331     build_free_array(data);
332     build_package(array, op);
333 }
334 
335 void aml_append(Aml *parent_ctx, Aml *child)
336 {
337     switch (child->block_flags) {
338     case AML_OPCODE:
339         build_append_byte(parent_ctx->buf, child->op);
340         break;
341     case AML_EXT_PACKAGE:
342         build_extop_package(child->buf, child->op);
343         break;
344     case AML_PACKAGE:
345         build_package(child->buf, child->op);
346         break;
347     case AML_RES_TEMPLATE:
348         build_append_byte(child->buf, 0x79); /* EndTag */
349         /*
350          * checksum operations are treated as succeeded if checksum
351          * field is zero. [ACPI Spec 1.0b, 6.4.2.8 End Tag]
352          */
353         build_append_byte(child->buf, 0);
354         /* fall through, to pack resources in buffer */
355     case AML_BUFFER:
356         build_buffer(child->buf, child->op);
357         break;
358     case AML_NO_OPCODE:
359         break;
360     default:
361         assert(0);
362         break;
363     }
364     build_append_array(parent_ctx->buf, child->buf);
365 }
366 
367 /* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefScope */
368 Aml *aml_scope(const char *name_format, ...)
369 {
370     va_list ap;
371     Aml *var = aml_bundle(0x10 /* ScopeOp */, AML_PACKAGE);
372     va_start(ap, name_format);
373     build_append_namestringv(var->buf, name_format, ap);
374     va_end(ap);
375     return var;
376 }
377 
378 /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefReturn */
379 Aml *aml_return(Aml *val)
380 {
381     Aml *var = aml_opcode(0xA4 /* ReturnOp */);
382     aml_append(var, val);
383     return var;
384 }
385 
386 /*
387  * ACPI 1.0b: 16.2.3 Data Objects Encoding:
388  * encodes: ByteConst, WordConst, DWordConst, QWordConst, ZeroOp, OneOp
389  */
390 Aml *aml_int(const uint64_t val)
391 {
392     Aml *var = aml_alloc();
393     build_append_int(var->buf, val);
394     return var;
395 }
396 
397 /*
398  * helper to construct NameString, which returns Aml object
399  * for using with aml_append or other aml_* terms
400  */
401 Aml *aml_name(const char *name_format, ...)
402 {
403     va_list ap;
404     Aml *var = aml_alloc();
405     va_start(ap, name_format);
406     build_append_namestringv(var->buf, name_format, ap);
407     va_end(ap);
408     return var;
409 }
410 
411 /* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefName */
412 Aml *aml_name_decl(const char *name, Aml *val)
413 {
414     Aml *var = aml_opcode(0x08 /* NameOp */);
415     build_append_namestring(var->buf, "%s", name);
416     aml_append(var, val);
417     return var;
418 }
419 
420 /* ACPI 1.0b: 16.2.6.1 Arg Objects Encoding */
421 Aml *aml_arg(int pos)
422 {
423     Aml *var;
424     uint8_t op = 0x68 /* ARG0 op */ + pos;
425 
426     assert(pos <= 6);
427     var = aml_opcode(op);
428     return var;
429 }
430 
431 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefStore */
432 Aml *aml_store(Aml *val, Aml *target)
433 {
434     Aml *var = aml_opcode(0x70 /* StoreOp */);
435     aml_append(var, val);
436     aml_append(var, target);
437     return var;
438 }
439 
440 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAnd */
441 Aml *aml_and(Aml *arg1, Aml *arg2)
442 {
443     Aml *var = aml_opcode(0x7B /* AndOp */);
444     aml_append(var, arg1);
445     aml_append(var, arg2);
446     build_append_int(var->buf, 0x00 /* NullNameOp */);
447     return var;
448 }
449 
450 /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
451 Aml *aml_notify(Aml *arg1, Aml *arg2)
452 {
453     Aml *var = aml_opcode(0x86 /* NotifyOp */);
454     aml_append(var, arg1);
455     aml_append(var, arg2);
456     return var;
457 }
458 
459 /* helper to call method with 1 argument */
460 Aml *aml_call1(const char *method, Aml *arg1)
461 {
462     Aml *var = aml_alloc();
463     build_append_namestring(var->buf, "%s", method);
464     aml_append(var, arg1);
465     return var;
466 }
467 
468 /* helper to call method with 2 arguments */
469 Aml *aml_call2(const char *method, Aml *arg1, Aml *arg2)
470 {
471     Aml *var = aml_alloc();
472     build_append_namestring(var->buf, "%s", method);
473     aml_append(var, arg1);
474     aml_append(var, arg2);
475     return var;
476 }
477 
478 /* helper to call method with 3 arguments */
479 Aml *aml_call3(const char *method, Aml *arg1, Aml *arg2, Aml *arg3)
480 {
481     Aml *var = aml_alloc();
482     build_append_namestring(var->buf, "%s", method);
483     aml_append(var, arg1);
484     aml_append(var, arg2);
485     aml_append(var, arg3);
486     return var;
487 }
488 
489 /* helper to call method with 4 arguments */
490 Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4)
491 {
492     Aml *var = aml_alloc();
493     build_append_namestring(var->buf, "%s", method);
494     aml_append(var, arg1);
495     aml_append(var, arg2);
496     aml_append(var, arg3);
497     aml_append(var, arg4);
498     return var;
499 }
500 
501 /* ACPI 1.0b: 6.4.2.5 I/O Port Descriptor */
502 Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
503             uint8_t aln, uint8_t len)
504 {
505     Aml *var = aml_alloc();
506     build_append_byte(var->buf, 0x47); /* IO port descriptor */
507     build_append_byte(var->buf, dec);
508     build_append_byte(var->buf, min_base & 0xff);
509     build_append_byte(var->buf, (min_base >> 8) & 0xff);
510     build_append_byte(var->buf, max_base & 0xff);
511     build_append_byte(var->buf, (max_base >> 8) & 0xff);
512     build_append_byte(var->buf, aln);
513     build_append_byte(var->buf, len);
514     return var;
515 }
516 
517 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLEqual */
518 Aml *aml_equal(Aml *arg1, Aml *arg2)
519 {
520     Aml *var = aml_opcode(0x93 /* LequalOp */);
521     aml_append(var, arg1);
522     aml_append(var, arg2);
523     build_append_int(var->buf, 0x00); /* NullNameOp */
524     return var;
525 }
526 
527 /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefIfElse */
528 Aml *aml_if(Aml *predicate)
529 {
530     Aml *var = aml_bundle(0xA0 /* IfOp */, AML_PACKAGE);
531     aml_append(var, predicate);
532     return var;
533 }
534 
535 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */
536 Aml *aml_method(const char *name, int arg_count)
537 {
538     Aml *var = aml_bundle(0x14 /* MethodOp */, AML_PACKAGE);
539     build_append_namestring(var->buf, "%s", name);
540     build_append_byte(var->buf, arg_count); /* MethodFlags: ArgCount */
541     return var;
542 }
543 
544 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefDevice */
545 Aml *aml_device(const char *name_format, ...)
546 {
547     va_list ap;
548     Aml *var = aml_bundle(0x82 /* DeviceOp */, AML_EXT_PACKAGE);
549     va_start(ap, name_format);
550     build_append_namestringv(var->buf, name_format, ap);
551     va_end(ap);
552     return var;
553 }
554 
555 /* ACPI 1.0b: 6.4.1 ASL Macros for Resource Descriptors */
556 Aml *aml_resource_template(void)
557 {
558     /* ResourceTemplate is a buffer of Resources with EndTag at the end */
559     Aml *var = aml_bundle(0x11 /* BufferOp */, AML_RES_TEMPLATE);
560     return var;
561 }
562 
563 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer */
564 Aml *aml_buffer(void)
565 {
566     Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
567     return var;
568 }
569 
570 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefPackage */
571 Aml *aml_package(uint8_t num_elements)
572 {
573     Aml *var = aml_bundle(0x12 /* PackageOp */, AML_PACKAGE);
574     build_append_byte(var->buf, num_elements);
575     return var;
576 }
577 
578 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefOpRegion */
579 Aml *aml_operation_region(const char *name, AmlRegionSpace rs,
580                           uint32_t offset, uint32_t len)
581 {
582     Aml *var = aml_alloc();
583     build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
584     build_append_byte(var->buf, 0x80); /* OpRegionOp */
585     build_append_namestring(var->buf, "%s", name);
586     build_append_byte(var->buf, rs);
587     build_append_int(var->buf, offset);
588     build_append_int(var->buf, len);
589     return var;
590 }
591 
592 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: NamedField */
593 Aml *aml_named_field(const char *name, unsigned length)
594 {
595     Aml *var = aml_alloc();
596     build_append_nameseg(var->buf, name);
597     build_append_pkg_length(var->buf, length, false);
598     return var;
599 }
600 
601 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: ReservedField */
602 Aml *aml_reserved_field(unsigned length)
603 {
604     Aml *var = aml_alloc();
605     /* ReservedField  := 0x00 PkgLength */
606     build_append_byte(var->buf, 0x00);
607     build_append_pkg_length(var->buf, length, false);
608     return var;
609 }
610 
611 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */
612 Aml *aml_field(const char *name, AmlFieldFlags flags)
613 {
614     Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE);
615     build_append_namestring(var->buf, "%s", name);
616     build_append_byte(var->buf, flags);
617     return var;
618 }
619 
620 /* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */
621 Aml *aml_string(const char *name_format, ...)
622 {
623     Aml *var = aml_opcode(0x0D /* StringPrefix */);
624     va_list ap, va_len;
625     char *s;
626     int len;
627 
628     va_start(ap, name_format);
629     va_copy(va_len, ap);
630     len = vsnprintf(NULL, 0, name_format, va_len);
631     va_end(va_len);
632     len += 1;
633     s = g_new0(typeof(*s), len);
634 
635     len = vsnprintf(s, len, name_format, ap);
636     va_end(ap);
637 
638     g_array_append_vals(var->buf, s, len);
639     build_append_byte(var->buf, 0x0); /* NullChar */
640     g_free(s);
641 
642     return var;
643 }
644 
645 /* ACPI 1.0b: 16.2.6.2 Local Objects Encoding */
646 Aml *aml_local(int num)
647 {
648     Aml *var;
649     uint8_t op = 0x60 /* Local0Op */ + num;
650 
651     assert(num <= 7);
652     var = aml_opcode(op);
653     return var;
654 }
655 
656 /* ACPI 2.0a: 17.2.2 Data Objects Encoding: DefVarPackage */
657 Aml *aml_varpackage(uint32_t num_elements)
658 {
659     Aml *var = aml_bundle(0x13 /* VarPackageOp */, AML_PACKAGE);
660     build_append_int(var->buf, num_elements);
661     return var;
662 }
663 
664 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefProcessor */
665 Aml *aml_processor(uint8_t proc_id, uint32_t pblk_addr, uint8_t pblk_len,
666                    const char *name_format, ...)
667 {
668     va_list ap;
669     Aml *var = aml_bundle(0x83 /* ProcessorOp */, AML_EXT_PACKAGE);
670     va_start(ap, name_format);
671     build_append_namestringv(var->buf, name_format, ap);
672     va_end(ap);
673     build_append_byte(var->buf, proc_id); /* ProcID */
674     build_append_int_noprefix(var->buf, pblk_addr, sizeof(pblk_addr));
675     build_append_byte(var->buf, pblk_len); /* PblkLen */
676     return var;
677 }
678 
679 static uint8_t Hex2Digit(char c)
680 {
681     if (c >= 'A') {
682         return c - 'A' + 10;
683     }
684 
685     return c - '0';
686 }
687 
688 /* ACPI 1.0b: 15.2.3.6.4.1 EISAID Macro - Convert EISA ID String To Integer */
689 Aml *aml_eisaid(const char *str)
690 {
691     Aml *var = aml_alloc();
692     uint32_t id;
693 
694     g_assert(strlen(str) == 7);
695     id = (str[0] - 0x40) << 26 |
696     (str[1] - 0x40) << 21 |
697     (str[2] - 0x40) << 16 |
698     Hex2Digit(str[3]) << 12 |
699     Hex2Digit(str[4]) << 8 |
700     Hex2Digit(str[5]) << 4 |
701     Hex2Digit(str[6]);
702 
703     build_append_byte(var->buf, 0x0C); /* DWordPrefix */
704     build_append_int_noprefix(var->buf, bswap32(id), sizeof(id));
705     return var;
706 }
707 
708 /* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor: bytes 3-5 */
709 static Aml *aml_as_desc_header(AmlResourceType type, AmlMinFixed min_fixed,
710                                AmlMaxFixed max_fixed, AmlDecode dec,
711                                uint8_t type_flags)
712 {
713     uint8_t flags = max_fixed | min_fixed | dec;
714     Aml *var = aml_alloc();
715 
716     build_append_byte(var->buf, type);
717     build_append_byte(var->buf, flags);
718     build_append_byte(var->buf, type_flags); /* Type Specific Flags */
719     return var;
720 }
721 
722 /* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor */
723 static Aml *aml_word_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
724                              AmlMaxFixed max_fixed, AmlDecode dec,
725                              uint16_t addr_gran, uint16_t addr_min,
726                              uint16_t addr_max, uint16_t addr_trans,
727                              uint16_t len, uint8_t type_flags)
728 {
729     Aml *var = aml_alloc();
730 
731     build_append_byte(var->buf, 0x88); /* Word Address Space Descriptor */
732     /* minimum length since we do not encode optional fields */
733     build_append_byte(var->buf, 0x0D);
734     build_append_byte(var->buf, 0x0);
735 
736     aml_append(var,
737         aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
738     build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
739     build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
740     build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
741     build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
742     build_append_int_noprefix(var->buf, len, sizeof(len));
743     return var;
744 }
745 
746 /* ACPI 1.0b: 6.4.3.5.3 DWord Address Space Descriptor */
747 static Aml *aml_dword_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
748                               AmlMaxFixed max_fixed, AmlDecode dec,
749                               uint32_t addr_gran, uint32_t addr_min,
750                               uint32_t addr_max, uint32_t addr_trans,
751                               uint32_t len, uint8_t type_flags)
752 {
753     Aml *var = aml_alloc();
754 
755     build_append_byte(var->buf, 0x87); /* DWord Address Space Descriptor */
756     /* minimum length since we do not encode optional fields */
757     build_append_byte(var->buf, 23);
758     build_append_byte(var->buf, 0x0);
759 
760 
761     aml_append(var,
762         aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
763     build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
764     build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
765     build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
766     build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
767     build_append_int_noprefix(var->buf, len, sizeof(len));
768     return var;
769 }
770 
771 /* ACPI 1.0b: 6.4.3.5.1 QWord Address Space Descriptor */
772 static Aml *aml_qword_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
773                               AmlMaxFixed max_fixed, AmlDecode dec,
774                               uint64_t addr_gran, uint64_t addr_min,
775                               uint64_t addr_max, uint64_t addr_trans,
776                               uint64_t len, uint8_t type_flags)
777 {
778     Aml *var = aml_alloc();
779 
780     build_append_byte(var->buf, 0x8A); /* QWord Address Space Descriptor */
781     /* minimum length since we do not encode optional fields */
782     build_append_byte(var->buf, 0x2B);
783     build_append_byte(var->buf, 0x0);
784 
785     aml_append(var,
786         aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
787     build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
788     build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
789     build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
790     build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
791     build_append_int_noprefix(var->buf, len, sizeof(len));
792     return var;
793 }
794 
795 /*
796  * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor
797  *
798  * More verbose description at:
799  * ACPI 5.0: 19.5.141 WordBusNumber (Word Bus Number Resource Descriptor Macro)
800  */
801 Aml *aml_word_bus_number(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
802                          AmlDecode dec, uint16_t addr_gran,
803                          uint16_t addr_min, uint16_t addr_max,
804                          uint16_t addr_trans, uint16_t len)
805 
806 {
807     return aml_word_as_desc(aml_bus_number_range, min_fixed, max_fixed, dec,
808                             addr_gran, addr_min, addr_max, addr_trans, len, 0);
809 }
810 
811 /*
812  * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor
813  *
814  * More verbose description at:
815  * ACPI 5.0: 19.5.142 WordIO (Word IO Resource Descriptor Macro)
816  */
817 Aml *aml_word_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
818                  AmlDecode dec, AmlISARanges isa_ranges,
819                  uint16_t addr_gran, uint16_t addr_min,
820                  uint16_t addr_max, uint16_t addr_trans,
821                  uint16_t len)
822 
823 {
824     return aml_word_as_desc(aml_io_range, min_fixed, max_fixed, dec,
825                             addr_gran, addr_min, addr_max, addr_trans, len,
826                             isa_ranges);
827 }
828 
829 /*
830  * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Space Descriptor
831  *
832  * More verbose description at:
833  * ACPI 5.0: 19.5.34 DWordMemory (DWord Memory Resource Descriptor Macro)
834  */
835 Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
836                       AmlMaxFixed max_fixed, AmlCacheble cacheable,
837                       AmlReadAndWrite read_and_write,
838                       uint32_t addr_gran, uint32_t addr_min,
839                       uint32_t addr_max, uint32_t addr_trans,
840                       uint32_t len)
841 {
842     uint8_t flags = read_and_write | (cacheable << 1);
843 
844     return aml_dword_as_desc(aml_memory_range, min_fixed, max_fixed,
845                              dec, addr_gran, addr_min, addr_max,
846                              addr_trans, len, flags);
847 }
848 
849 /*
850  * ACPI 1.0b: 6.4.3.5.2 ASL Macros for QWORD Address Space Descriptor
851  *
852  * More verbose description at:
853  * ACPI 5.0: 19.5.102 QWordMemory (QWord Memory Resource Descriptor Macro)
854  */
855 Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
856                       AmlMaxFixed max_fixed, AmlCacheble cacheable,
857                       AmlReadAndWrite read_and_write,
858                       uint64_t addr_gran, uint64_t addr_min,
859                       uint64_t addr_max, uint64_t addr_trans,
860                       uint64_t len)
861 {
862     uint8_t flags = read_and_write | (cacheable << 1);
863 
864     return aml_qword_as_desc(aml_memory_range, min_fixed, max_fixed,
865                              dec, addr_gran, addr_min, addr_max,
866                              addr_trans, len, flags);
867 }
868