xref: /openbmc/qemu/hw/acpi/aml-build.c (revision 24602b77f5658ae8377958c15fdef2f44affc743)
119934e0eSIgor Mammedov /* Support for generating ACPI tables and passing them to Guests
219934e0eSIgor Mammedov  *
319934e0eSIgor Mammedov  * Copyright (C) 2015 Red Hat Inc
419934e0eSIgor Mammedov  *
519934e0eSIgor Mammedov  * Author: Michael S. Tsirkin <mst@redhat.com>
619934e0eSIgor Mammedov  * Author: Igor Mammedov <imammedo@redhat.com>
719934e0eSIgor Mammedov  *
819934e0eSIgor Mammedov  * This program is free software; you can redistribute it and/or modify
919934e0eSIgor Mammedov  * it under the terms of the GNU General Public License as published by
1019934e0eSIgor Mammedov  * the Free Software Foundation; either version 2 of the License, or
1119934e0eSIgor Mammedov  * (at your option) any later version.
1219934e0eSIgor Mammedov 
1319934e0eSIgor Mammedov  * This program is distributed in the hope that it will be useful,
1419934e0eSIgor Mammedov  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1519934e0eSIgor Mammedov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1619934e0eSIgor Mammedov  * GNU General Public License for more details.
1719934e0eSIgor Mammedov 
1819934e0eSIgor Mammedov  * You should have received a copy of the GNU General Public License along
1919934e0eSIgor Mammedov  * with this program; if not, see <http://www.gnu.org/licenses/>.
2019934e0eSIgor Mammedov  */
2119934e0eSIgor Mammedov 
22b6a0aa05SPeter Maydell #include "qemu/osdep.h"
23c3bdc56cSMarkus Armbruster #include <glib/gprintf.h>
2419934e0eSIgor Mammedov #include "hw/acpi/aml-build.h"
250f2707e4SIgor Mammedov #include "qemu/bswap.h"
26dc17ab1dSShannon Zhao #include "qemu/bitops.h"
270f203430SHe Chen #include "sysemu/numa.h"
28aa570207STao Xu #include "hw/boards.h"
2943384160SEric Auger #include "hw/acpi/tpm.h"
3037d5c0a8SYubo Miao #include "hw/pci/pci_host.h"
3137d5c0a8SYubo Miao #include "hw/pci/pci_bus.h"
3237d5c0a8SYubo Miao #include "hw/pci/pci_bridge.h"
33602b4582SMarian Postevca #include "qemu/cutils.h"
3419934e0eSIgor Mammedov 
build_alloc_array(void)35af59b35cSIgor Mammedov static GArray *build_alloc_array(void)
3619934e0eSIgor Mammedov {
3719934e0eSIgor Mammedov     return g_array_new(false, true /* clear */, 1);
3819934e0eSIgor Mammedov }
3919934e0eSIgor Mammedov 
build_free_array(GArray * array)40af59b35cSIgor Mammedov static void build_free_array(GArray *array)
4119934e0eSIgor Mammedov {
4219934e0eSIgor Mammedov     g_array_free(array, true);
4319934e0eSIgor Mammedov }
4419934e0eSIgor Mammedov 
build_prepend_byte(GArray * array,uint8_t val)45af59b35cSIgor Mammedov static void build_prepend_byte(GArray *array, uint8_t val)
4619934e0eSIgor Mammedov {
4719934e0eSIgor Mammedov     g_array_prepend_val(array, val);
4819934e0eSIgor Mammedov }
4919934e0eSIgor Mammedov 
build_append_byte(GArray * array,uint8_t val)50af59b35cSIgor Mammedov static void build_append_byte(GArray *array, uint8_t val)
5119934e0eSIgor Mammedov {
5219934e0eSIgor Mammedov     g_array_append_val(array, val);
5319934e0eSIgor Mammedov }
5419934e0eSIgor Mammedov 
build_append_padded_str(GArray * array,const char * str,size_t maxlen,char pad)55c151fd87SIgor Mammedov static void build_append_padded_str(GArray *array, const char *str,
56c151fd87SIgor Mammedov                                     size_t maxlen, char pad)
57c151fd87SIgor Mammedov {
58c151fd87SIgor Mammedov     size_t i;
59c151fd87SIgor Mammedov     size_t len = strlen(str);
60c151fd87SIgor Mammedov 
61c151fd87SIgor Mammedov     g_assert(len <= maxlen);
62c151fd87SIgor Mammedov     g_array_append_vals(array, str, len);
63c151fd87SIgor Mammedov     for (i = maxlen - len; i > 0; i--) {
64c151fd87SIgor Mammedov         g_array_append_val(array, pad);
65c151fd87SIgor Mammedov     }
66c151fd87SIgor Mammedov }
67c151fd87SIgor Mammedov 
build_append_array(GArray * array,GArray * val)68af59b35cSIgor Mammedov static void build_append_array(GArray *array, GArray *val)
6919934e0eSIgor Mammedov {
7019934e0eSIgor Mammedov     g_array_append_vals(array, val->data, val->len);
7119934e0eSIgor Mammedov }
7219934e0eSIgor Mammedov 
7319934e0eSIgor Mammedov #define ACPI_NAMESEG_LEN 4
7419934e0eSIgor Mammedov 
crs_range_insert(GPtrArray * ranges,uint64_t base,uint64_t limit)7537d5c0a8SYubo Miao void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t limit)
7637d5c0a8SYubo Miao {
7737d5c0a8SYubo Miao     CrsRangeEntry *entry;
7837d5c0a8SYubo Miao 
7937d5c0a8SYubo Miao     entry = g_malloc(sizeof(*entry));
8037d5c0a8SYubo Miao     entry->base = base;
8137d5c0a8SYubo Miao     entry->limit = limit;
8237d5c0a8SYubo Miao 
8337d5c0a8SYubo Miao     g_ptr_array_add(ranges, entry);
8437d5c0a8SYubo Miao }
8537d5c0a8SYubo Miao 
crs_range_free(gpointer data)8637d5c0a8SYubo Miao static void crs_range_free(gpointer data)
8737d5c0a8SYubo Miao {
8837d5c0a8SYubo Miao     CrsRangeEntry *entry = (CrsRangeEntry *)data;
8937d5c0a8SYubo Miao     g_free(entry);
9037d5c0a8SYubo Miao }
9137d5c0a8SYubo Miao 
crs_range_set_init(CrsRangeSet * range_set)9237d5c0a8SYubo Miao void crs_range_set_init(CrsRangeSet *range_set)
9337d5c0a8SYubo Miao {
9437d5c0a8SYubo Miao     range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
9537d5c0a8SYubo Miao     range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
9637d5c0a8SYubo Miao     range_set->mem_64bit_ranges =
9737d5c0a8SYubo Miao             g_ptr_array_new_with_free_func(crs_range_free);
9837d5c0a8SYubo Miao }
9937d5c0a8SYubo Miao 
crs_range_set_free(CrsRangeSet * range_set)10037d5c0a8SYubo Miao void crs_range_set_free(CrsRangeSet *range_set)
10137d5c0a8SYubo Miao {
10237d5c0a8SYubo Miao     g_ptr_array_free(range_set->io_ranges, true);
10337d5c0a8SYubo Miao     g_ptr_array_free(range_set->mem_ranges, true);
10437d5c0a8SYubo Miao     g_ptr_array_free(range_set->mem_64bit_ranges, true);
10537d5c0a8SYubo Miao }
10637d5c0a8SYubo Miao 
crs_range_compare(gconstpointer a,gconstpointer b)10737d5c0a8SYubo Miao static gint crs_range_compare(gconstpointer a, gconstpointer b)
10837d5c0a8SYubo Miao {
10937d5c0a8SYubo Miao     CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
11037d5c0a8SYubo Miao     CrsRangeEntry *entry_b = *(CrsRangeEntry **)b;
11137d5c0a8SYubo Miao 
11237d5c0a8SYubo Miao     if (entry_a->base < entry_b->base) {
11337d5c0a8SYubo Miao         return -1;
11437d5c0a8SYubo Miao     } else if (entry_a->base > entry_b->base) {
11537d5c0a8SYubo Miao         return 1;
11637d5c0a8SYubo Miao     } else {
11737d5c0a8SYubo Miao         return 0;
11837d5c0a8SYubo Miao     }
11937d5c0a8SYubo Miao }
12037d5c0a8SYubo Miao 
12137d5c0a8SYubo Miao /*
12237d5c0a8SYubo Miao  * crs_replace_with_free_ranges - given the 'used' ranges within [start - end]
12337d5c0a8SYubo Miao  * interval, computes the 'free' ranges from the same interval.
12437d5c0a8SYubo Miao  * Example: If the input array is { [a1 - a2],[b1 - b2] }, the function
12537d5c0a8SYubo Miao  * will return { [base - a1], [a2 - b1], [b2 - limit] }.
12637d5c0a8SYubo Miao  */
crs_replace_with_free_ranges(GPtrArray * ranges,uint64_t start,uint64_t end)12737d5c0a8SYubo Miao void crs_replace_with_free_ranges(GPtrArray *ranges,
12837d5c0a8SYubo Miao                                   uint64_t start, uint64_t end)
12937d5c0a8SYubo Miao {
13037d5c0a8SYubo Miao     GPtrArray *free_ranges = g_ptr_array_new();
13137d5c0a8SYubo Miao     uint64_t free_base = start;
13237d5c0a8SYubo Miao     int i;
13337d5c0a8SYubo Miao 
13437d5c0a8SYubo Miao     g_ptr_array_sort(ranges, crs_range_compare);
13537d5c0a8SYubo Miao     for (i = 0; i < ranges->len; i++) {
13637d5c0a8SYubo Miao         CrsRangeEntry *used = g_ptr_array_index(ranges, i);
13737d5c0a8SYubo Miao 
13837d5c0a8SYubo Miao         if (free_base < used->base) {
13937d5c0a8SYubo Miao             crs_range_insert(free_ranges, free_base, used->base - 1);
14037d5c0a8SYubo Miao         }
14137d5c0a8SYubo Miao 
14237d5c0a8SYubo Miao         free_base = used->limit + 1;
14337d5c0a8SYubo Miao     }
14437d5c0a8SYubo Miao 
14537d5c0a8SYubo Miao     if (free_base < end) {
14637d5c0a8SYubo Miao         crs_range_insert(free_ranges, free_base, end);
14737d5c0a8SYubo Miao     }
14837d5c0a8SYubo Miao 
14937d5c0a8SYubo Miao     g_ptr_array_set_size(ranges, 0);
15037d5c0a8SYubo Miao     for (i = 0; i < free_ranges->len; i++) {
15137d5c0a8SYubo Miao         g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i));
15237d5c0a8SYubo Miao     }
15337d5c0a8SYubo Miao 
15437d5c0a8SYubo Miao     g_ptr_array_free(free_ranges, true);
15537d5c0a8SYubo Miao }
15637d5c0a8SYubo Miao 
15737d5c0a8SYubo Miao /*
15837d5c0a8SYubo Miao  * crs_range_merge - merges adjacent ranges in the given array.
15937d5c0a8SYubo Miao  * Array elements are deleted and replaced with the merged ranges.
16037d5c0a8SYubo Miao  */
crs_range_merge(GPtrArray * range)16137d5c0a8SYubo Miao static void crs_range_merge(GPtrArray *range)
16237d5c0a8SYubo Miao {
16337d5c0a8SYubo Miao     GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free);
16437d5c0a8SYubo Miao     CrsRangeEntry *entry;
16537d5c0a8SYubo Miao     uint64_t range_base, range_limit;
16637d5c0a8SYubo Miao     int i;
16737d5c0a8SYubo Miao 
16837d5c0a8SYubo Miao     if (!range->len) {
16937d5c0a8SYubo Miao         return;
17037d5c0a8SYubo Miao     }
17137d5c0a8SYubo Miao 
17237d5c0a8SYubo Miao     g_ptr_array_sort(range, crs_range_compare);
17337d5c0a8SYubo Miao 
17437d5c0a8SYubo Miao     entry = g_ptr_array_index(range, 0);
17537d5c0a8SYubo Miao     range_base = entry->base;
17637d5c0a8SYubo Miao     range_limit = entry->limit;
17737d5c0a8SYubo Miao     for (i = 1; i < range->len; i++) {
17837d5c0a8SYubo Miao         entry = g_ptr_array_index(range, i);
17937d5c0a8SYubo Miao         if (entry->base - 1 == range_limit) {
18037d5c0a8SYubo Miao             range_limit = entry->limit;
18137d5c0a8SYubo Miao         } else {
18237d5c0a8SYubo Miao             crs_range_insert(tmp, range_base, range_limit);
18337d5c0a8SYubo Miao             range_base = entry->base;
18437d5c0a8SYubo Miao             range_limit = entry->limit;
18537d5c0a8SYubo Miao         }
18637d5c0a8SYubo Miao     }
18737d5c0a8SYubo Miao     crs_range_insert(tmp, range_base, range_limit);
18837d5c0a8SYubo Miao 
18937d5c0a8SYubo Miao     g_ptr_array_set_size(range, 0);
19037d5c0a8SYubo Miao     for (i = 0; i < tmp->len; i++) {
19137d5c0a8SYubo Miao         entry = g_ptr_array_index(tmp, i);
19237d5c0a8SYubo Miao         crs_range_insert(range, entry->base, entry->limit);
19337d5c0a8SYubo Miao     }
19437d5c0a8SYubo Miao     g_ptr_array_free(tmp, true);
19537d5c0a8SYubo Miao }
19637d5c0a8SYubo Miao 
197eae8bdedSIgor Mammedov static void
build_append_nameseg(GArray * array,const char * seg)198eae8bdedSIgor Mammedov build_append_nameseg(GArray *array, const char *seg)
19919934e0eSIgor Mammedov {
20019934e0eSIgor Mammedov     int len;
20119934e0eSIgor Mammedov 
202eae8bdedSIgor Mammedov     len = strlen(seg);
20319934e0eSIgor Mammedov     assert(len <= ACPI_NAMESEG_LEN);
20419934e0eSIgor Mammedov 
205eae8bdedSIgor Mammedov     g_array_append_vals(array, seg, len);
20619934e0eSIgor Mammedov     /* Pad up to ACPI_NAMESEG_LEN characters if necessary. */
20719934e0eSIgor Mammedov     g_array_append_vals(array, "____", ACPI_NAMESEG_LEN - len);
20819934e0eSIgor Mammedov }
20919934e0eSIgor Mammedov 
2109edc6313SMarc-André Lureau static void G_GNUC_PRINTF(2, 0)
build_append_namestringv(GArray * array,const char * format,va_list ap)211eae8bdedSIgor Mammedov build_append_namestringv(GArray *array, const char *format, va_list ap)
212eae8bdedSIgor Mammedov {
213eae8bdedSIgor Mammedov     char *s;
214eae8bdedSIgor Mammedov     char **segs;
215eae8bdedSIgor Mammedov     char **segs_iter;
216eae8bdedSIgor Mammedov     int seg_count = 0;
217eae8bdedSIgor Mammedov 
218c3bdc56cSMarkus Armbruster     s = g_strdup_vprintf(format, ap);
219eae8bdedSIgor Mammedov     segs = g_strsplit(s, ".", 0);
220eae8bdedSIgor Mammedov     g_free(s);
221eae8bdedSIgor Mammedov 
222eae8bdedSIgor Mammedov     /* count segments */
223eae8bdedSIgor Mammedov     segs_iter = segs;
224eae8bdedSIgor Mammedov     while (*segs_iter) {
225eae8bdedSIgor Mammedov         ++segs_iter;
226eae8bdedSIgor Mammedov         ++seg_count;
227eae8bdedSIgor Mammedov     }
228eae8bdedSIgor Mammedov     /*
229eae8bdedSIgor Mammedov      * ACPI 5.0 spec: 20.2.2 Name Objects Encoding:
230eae8bdedSIgor Mammedov      * "SegCount can be from 1 to 255"
231eae8bdedSIgor Mammedov      */
232eae8bdedSIgor Mammedov     assert(seg_count > 0 && seg_count <= 255);
233eae8bdedSIgor Mammedov 
234eae8bdedSIgor Mammedov     /* handle RootPath || PrefixPath */
235eae8bdedSIgor Mammedov     s = *segs;
236eae8bdedSIgor Mammedov     while (*s == '\\' || *s == '^') {
237eae8bdedSIgor Mammedov         build_append_byte(array, *s);
238eae8bdedSIgor Mammedov         ++s;
239eae8bdedSIgor Mammedov     }
240eae8bdedSIgor Mammedov 
241eae8bdedSIgor Mammedov     switch (seg_count) {
242eae8bdedSIgor Mammedov     case 1:
243eae8bdedSIgor Mammedov         if (!*s) {
244aea10cdeSMichael S. Tsirkin             build_append_byte(array, 0x00); /* NullName */
245eae8bdedSIgor Mammedov         } else {
246eae8bdedSIgor Mammedov             build_append_nameseg(array, s);
247eae8bdedSIgor Mammedov         }
248eae8bdedSIgor Mammedov         break;
249eae8bdedSIgor Mammedov 
250eae8bdedSIgor Mammedov     case 2:
251eae8bdedSIgor Mammedov         build_append_byte(array, 0x2E); /* DualNamePrefix */
252eae8bdedSIgor Mammedov         build_append_nameseg(array, s);
253eae8bdedSIgor Mammedov         build_append_nameseg(array, segs[1]);
254eae8bdedSIgor Mammedov         break;
255eae8bdedSIgor Mammedov     default:
256eae8bdedSIgor Mammedov         build_append_byte(array, 0x2F); /* MultiNamePrefix */
257eae8bdedSIgor Mammedov         build_append_byte(array, seg_count);
258eae8bdedSIgor Mammedov 
259eae8bdedSIgor Mammedov         /* handle the 1st segment manually due to prefix/root path */
260eae8bdedSIgor Mammedov         build_append_nameseg(array, s);
261eae8bdedSIgor Mammedov 
262eae8bdedSIgor Mammedov         /* add the rest of segments */
263eae8bdedSIgor Mammedov         segs_iter = segs + 1;
264eae8bdedSIgor Mammedov         while (*segs_iter) {
265eae8bdedSIgor Mammedov             build_append_nameseg(array, *segs_iter);
266eae8bdedSIgor Mammedov             ++segs_iter;
267eae8bdedSIgor Mammedov         }
268eae8bdedSIgor Mammedov         break;
269eae8bdedSIgor Mammedov     }
270eae8bdedSIgor Mammedov     g_strfreev(segs);
271eae8bdedSIgor Mammedov }
272eae8bdedSIgor Mammedov 
2739edc6313SMarc-André Lureau G_GNUC_PRINTF(2, 3)
build_append_namestring(GArray * array,const char * format,...)274af59b35cSIgor Mammedov static void build_append_namestring(GArray *array, const char *format, ...)
275eae8bdedSIgor Mammedov {
276eae8bdedSIgor Mammedov     va_list ap;
277eae8bdedSIgor Mammedov 
278eae8bdedSIgor Mammedov     va_start(ap, format);
279eae8bdedSIgor Mammedov     build_append_namestringv(array, format, ap);
280eae8bdedSIgor Mammedov     va_end(ap);
281eae8bdedSIgor Mammedov }
282eae8bdedSIgor Mammedov 
28319934e0eSIgor Mammedov /* 5.4 Definition Block Encoding */
28419934e0eSIgor Mammedov enum {
28519934e0eSIgor Mammedov     PACKAGE_LENGTH_1BYTE_SHIFT = 6, /* Up to 63 - use extra 2 bits. */
28619934e0eSIgor Mammedov     PACKAGE_LENGTH_2BYTE_SHIFT = 4,
28719934e0eSIgor Mammedov     PACKAGE_LENGTH_3BYTE_SHIFT = 12,
28819934e0eSIgor Mammedov     PACKAGE_LENGTH_4BYTE_SHIFT = 20,
28919934e0eSIgor Mammedov };
29019934e0eSIgor Mammedov 
291af59b35cSIgor Mammedov static void
build_prepend_package_length(GArray * package,unsigned length,bool incl_self)29219fff2d4SIgor Mammedov build_prepend_package_length(GArray *package, unsigned length, bool incl_self)
29319934e0eSIgor Mammedov {
29419934e0eSIgor Mammedov     uint8_t byte;
29519934e0eSIgor Mammedov     unsigned length_bytes;
29619934e0eSIgor Mammedov 
29719934e0eSIgor Mammedov     if (length + 1 < (1 << PACKAGE_LENGTH_1BYTE_SHIFT)) {
29819934e0eSIgor Mammedov         length_bytes = 1;
29919934e0eSIgor Mammedov     } else if (length + 2 < (1 << PACKAGE_LENGTH_3BYTE_SHIFT)) {
30019934e0eSIgor Mammedov         length_bytes = 2;
30119934e0eSIgor Mammedov     } else if (length + 3 < (1 << PACKAGE_LENGTH_4BYTE_SHIFT)) {
30219934e0eSIgor Mammedov         length_bytes = 3;
30319934e0eSIgor Mammedov     } else {
30419934e0eSIgor Mammedov         length_bytes = 4;
30519934e0eSIgor Mammedov     }
30619934e0eSIgor Mammedov 
30719fff2d4SIgor Mammedov     /*
30819fff2d4SIgor Mammedov      * NamedField uses PkgLength encoding but it doesn't include length
30919fff2d4SIgor Mammedov      * of PkgLength itself.
31019fff2d4SIgor Mammedov      */
31119fff2d4SIgor Mammedov     if (incl_self) {
31219fff2d4SIgor Mammedov         /*
31319fff2d4SIgor Mammedov          * PkgLength is the length of the inclusive length of the data
31419fff2d4SIgor Mammedov          * and PkgLength's length itself when used for terms with
3159b4b4e51SMichael Tokarev          * explicit length.
31619fff2d4SIgor Mammedov          */
31719934e0eSIgor Mammedov         length += length_bytes;
31819fff2d4SIgor Mammedov     }
31919934e0eSIgor Mammedov 
32019934e0eSIgor Mammedov     switch (length_bytes) {
32119934e0eSIgor Mammedov     case 1:
32219934e0eSIgor Mammedov         byte = length;
32319934e0eSIgor Mammedov         build_prepend_byte(package, byte);
32419934e0eSIgor Mammedov         return;
32519934e0eSIgor Mammedov     case 4:
32619934e0eSIgor Mammedov         byte = length >> PACKAGE_LENGTH_4BYTE_SHIFT;
32719934e0eSIgor Mammedov         build_prepend_byte(package, byte);
32819934e0eSIgor Mammedov         length &= (1 << PACKAGE_LENGTH_4BYTE_SHIFT) - 1;
32919934e0eSIgor Mammedov         /* fall through */
33019934e0eSIgor Mammedov     case 3:
33119934e0eSIgor Mammedov         byte = length >> PACKAGE_LENGTH_3BYTE_SHIFT;
33219934e0eSIgor Mammedov         build_prepend_byte(package, byte);
33319934e0eSIgor Mammedov         length &= (1 << PACKAGE_LENGTH_3BYTE_SHIFT) - 1;
33419934e0eSIgor Mammedov         /* fall through */
33519934e0eSIgor Mammedov     case 2:
33619934e0eSIgor Mammedov         byte = length >> PACKAGE_LENGTH_2BYTE_SHIFT;
33719934e0eSIgor Mammedov         build_prepend_byte(package, byte);
33819934e0eSIgor Mammedov         length &= (1 << PACKAGE_LENGTH_2BYTE_SHIFT) - 1;
33919934e0eSIgor Mammedov         /* fall through */
34019934e0eSIgor Mammedov     }
34119934e0eSIgor Mammedov     /*
34219934e0eSIgor Mammedov      * Most significant two bits of byte zero indicate how many following bytes
34319934e0eSIgor Mammedov      * are in PkgLength encoding.
34419934e0eSIgor Mammedov      */
34519934e0eSIgor Mammedov     byte = ((length_bytes - 1) << PACKAGE_LENGTH_1BYTE_SHIFT) | length;
34619934e0eSIgor Mammedov     build_prepend_byte(package, byte);
34719934e0eSIgor Mammedov }
34819934e0eSIgor Mammedov 
349214ae59fSIgor Mammedov static void
build_append_pkg_length(GArray * array,unsigned length,bool incl_self)350214ae59fSIgor Mammedov build_append_pkg_length(GArray *array, unsigned length, bool incl_self)
351214ae59fSIgor Mammedov {
352214ae59fSIgor Mammedov     GArray *tmp = build_alloc_array();
353214ae59fSIgor Mammedov 
354214ae59fSIgor Mammedov     build_prepend_package_length(tmp, length, incl_self);
355214ae59fSIgor Mammedov     build_append_array(array, tmp);
356214ae59fSIgor Mammedov     build_free_array(tmp);
357214ae59fSIgor Mammedov }
358214ae59fSIgor Mammedov 
build_package(GArray * package,uint8_t op)359af59b35cSIgor Mammedov static void build_package(GArray *package, uint8_t op)
36019934e0eSIgor Mammedov {
36119fff2d4SIgor Mammedov     build_prepend_package_length(package, package->len, true);
36219934e0eSIgor Mammedov     build_prepend_byte(package, op);
36319934e0eSIgor Mammedov }
36419934e0eSIgor Mammedov 
build_extop_package(GArray * package,uint8_t op)365af59b35cSIgor Mammedov static void build_extop_package(GArray *package, uint8_t op)
36619934e0eSIgor Mammedov {
367661875e9SIgor Mammedov     build_package(package, op);
36819934e0eSIgor Mammedov     build_prepend_byte(package, 0x5B); /* ExtOpPrefix */
36919934e0eSIgor Mammedov }
37019934e0eSIgor Mammedov 
build_append_int_noprefix(GArray * table,uint64_t value,int size)371fb9f5926SDavid Kiarie void build_append_int_noprefix(GArray *table, uint64_t value, int size)
37219934e0eSIgor Mammedov {
37319934e0eSIgor Mammedov     int i;
37419934e0eSIgor Mammedov 
37519934e0eSIgor Mammedov     for (i = 0; i < size; ++i) {
37619934e0eSIgor Mammedov         build_append_byte(table, value & 0xFF);
37719934e0eSIgor Mammedov         value = value >> 8;
37819934e0eSIgor Mammedov     }
37919934e0eSIgor Mammedov }
38019934e0eSIgor Mammedov 
build_append_int(GArray * table,uint64_t value)381af59b35cSIgor Mammedov static void build_append_int(GArray *table, uint64_t value)
38219934e0eSIgor Mammedov {
38319934e0eSIgor Mammedov     if (value == 0x00) {
38419934e0eSIgor Mammedov         build_append_byte(table, 0x00); /* ZeroOp */
38519934e0eSIgor Mammedov     } else if (value == 0x01) {
38619934e0eSIgor Mammedov         build_append_byte(table, 0x01); /* OneOp */
38719934e0eSIgor Mammedov     } else if (value <= 0xFF) {
388295a515dSIgor Mammedov         build_append_byte(table, 0x0A); /* BytePrefix */
389295a515dSIgor Mammedov         build_append_int_noprefix(table, value, 1);
39019934e0eSIgor Mammedov     } else if (value <= 0xFFFF) {
391295a515dSIgor Mammedov         build_append_byte(table, 0x0B); /* WordPrefix */
392295a515dSIgor Mammedov         build_append_int_noprefix(table, value, 2);
393295a515dSIgor Mammedov     } else if (value <= 0xFFFFFFFF) {
394295a515dSIgor Mammedov         build_append_byte(table, 0x0C); /* DWordPrefix */
395295a515dSIgor Mammedov         build_append_int_noprefix(table, value, 4);
39619934e0eSIgor Mammedov     } else {
397295a515dSIgor Mammedov         build_append_byte(table, 0x0E); /* QWordPrefix */
398295a515dSIgor Mammedov         build_append_int_noprefix(table, value, 8);
39919934e0eSIgor Mammedov     }
40019934e0eSIgor Mammedov }
4010f2707e4SIgor Mammedov 
402d0384d90SIgor Mammedov /* Generic Address Structure (GAS)
403d0384d90SIgor Mammedov  * ACPI 2.0/3.0: 5.2.3.1 Generic Address Structure
404d0384d90SIgor Mammedov  * 2.0 compat note:
405d0384d90SIgor Mammedov  *    @access_width must be 0, see ACPI 2.0:Table 5-1
406d0384d90SIgor Mammedov  */
build_append_gas(GArray * table,AmlAddressSpace as,uint8_t bit_width,uint8_t bit_offset,uint8_t access_width,uint64_t address)407d0384d90SIgor Mammedov void build_append_gas(GArray *table, AmlAddressSpace as,
408d0384d90SIgor Mammedov                       uint8_t bit_width, uint8_t bit_offset,
409d0384d90SIgor Mammedov                       uint8_t access_width, uint64_t address)
410d0384d90SIgor Mammedov {
411d0384d90SIgor Mammedov     build_append_int_noprefix(table, as, 1);
412d0384d90SIgor Mammedov     build_append_int_noprefix(table, bit_width, 1);
413d0384d90SIgor Mammedov     build_append_int_noprefix(table, bit_offset, 1);
414d0384d90SIgor Mammedov     build_append_int_noprefix(table, access_width, 1);
415d0384d90SIgor Mammedov     build_append_int_noprefix(table, address, 8);
416d0384d90SIgor Mammedov }
417d0384d90SIgor Mammedov 
418f2035491SMichael S. Tsirkin /*
419f2035491SMichael S. Tsirkin  * Build NAME(XXXX, 0x00000000) where 0x00000000 is encoded as a dword,
420f2035491SMichael S. Tsirkin  * and return the offset to 0x00000000 for runtime patching.
421f2035491SMichael S. Tsirkin  *
422f2035491SMichael S. Tsirkin  * Warning: runtime patching is best avoided. Only use this as
423f2035491SMichael S. Tsirkin  * a replacement for DataTableRegion (for guests that don't
424f2035491SMichael S. Tsirkin  * support it).
425f2035491SMichael S. Tsirkin  */
426f2035491SMichael S. Tsirkin int
build_append_named_dword(GArray * array,const char * name_format,...)427f2035491SMichael S. Tsirkin build_append_named_dword(GArray *array, const char *name_format, ...)
428f2035491SMichael S. Tsirkin {
429f2035491SMichael S. Tsirkin     int offset;
430f2035491SMichael S. Tsirkin     va_list ap;
431f2035491SMichael S. Tsirkin 
432f2035491SMichael S. Tsirkin     build_append_byte(array, 0x08); /* NameOp */
433f2035491SMichael S. Tsirkin     va_start(ap, name_format);
434f2035491SMichael S. Tsirkin     build_append_namestringv(array, name_format, ap);
435f2035491SMichael S. Tsirkin     va_end(ap);
436f2035491SMichael S. Tsirkin 
437f2035491SMichael S. Tsirkin     build_append_byte(array, 0x0C); /* DWordPrefix */
438f2035491SMichael S. Tsirkin 
439f2035491SMichael S. Tsirkin     offset = array->len;
440f2035491SMichael S. Tsirkin     build_append_int_noprefix(array, 0x00000000, 4);
441f2035491SMichael S. Tsirkin     assert(array->len == offset + 4);
442f2035491SMichael S. Tsirkin 
443f2035491SMichael S. Tsirkin     return offset;
444f2035491SMichael S. Tsirkin }
445f2035491SMichael S. Tsirkin 
4460f2707e4SIgor Mammedov static GPtrArray *alloc_list;
4470f2707e4SIgor Mammedov 
aml_alloc(void)4480f2707e4SIgor Mammedov static Aml *aml_alloc(void)
4490f2707e4SIgor Mammedov {
4500f2707e4SIgor Mammedov     Aml *var = g_new0(typeof(*var), 1);
4510f2707e4SIgor Mammedov 
4520f2707e4SIgor Mammedov     g_ptr_array_add(alloc_list, var);
4530f2707e4SIgor Mammedov     var->block_flags = AML_NO_OPCODE;
4540f2707e4SIgor Mammedov     var->buf = build_alloc_array();
4550f2707e4SIgor Mammedov     return var;
4560f2707e4SIgor Mammedov }
4570f2707e4SIgor Mammedov 
aml_opcode(uint8_t op)4583c054bd5SIgor Mammedov static Aml *aml_opcode(uint8_t op)
4593c054bd5SIgor Mammedov {
4603c054bd5SIgor Mammedov     Aml *var = aml_alloc();
4613c054bd5SIgor Mammedov 
4623c054bd5SIgor Mammedov     var->op  = op;
4633c054bd5SIgor Mammedov     var->block_flags = AML_OPCODE;
4643c054bd5SIgor Mammedov     return var;
4653c054bd5SIgor Mammedov }
4663c054bd5SIgor Mammedov 
aml_bundle(uint8_t op,AmlBlockFlags flags)4672ef7c27bSIgor Mammedov static Aml *aml_bundle(uint8_t op, AmlBlockFlags flags)
4682ef7c27bSIgor Mammedov {
4692ef7c27bSIgor Mammedov     Aml *var = aml_alloc();
4702ef7c27bSIgor Mammedov 
4712ef7c27bSIgor Mammedov     var->op  = op;
4722ef7c27bSIgor Mammedov     var->block_flags = flags;
4732ef7c27bSIgor Mammedov     return var;
4742ef7c27bSIgor Mammedov }
4752ef7c27bSIgor Mammedov 
aml_free(gpointer data,gpointer user_data)4762e5feadbSMichael S. Tsirkin static void aml_free(gpointer data, gpointer user_data)
4770f2707e4SIgor Mammedov {
4780f2707e4SIgor Mammedov     Aml *var = data;
4790f2707e4SIgor Mammedov     build_free_array(var->buf);
480afcf905cSShannon Zhao     g_free(var);
4810f2707e4SIgor Mammedov }
4820f2707e4SIgor Mammedov 
init_aml_allocator(void)4830f2707e4SIgor Mammedov Aml *init_aml_allocator(void)
4840f2707e4SIgor Mammedov {
4850f2707e4SIgor Mammedov     assert(!alloc_list);
4862e5feadbSMichael S. Tsirkin     alloc_list = g_ptr_array_new();
4879be38598SEduardo Habkost     return aml_alloc();
4880f2707e4SIgor Mammedov }
4890f2707e4SIgor Mammedov 
free_aml_allocator(void)4900f2707e4SIgor Mammedov void free_aml_allocator(void)
4910f2707e4SIgor Mammedov {
4922e5feadbSMichael S. Tsirkin     g_ptr_array_foreach(alloc_list, aml_free, NULL);
4930f2707e4SIgor Mammedov     g_ptr_array_free(alloc_list, true);
4940f2707e4SIgor Mammedov     alloc_list = 0;
4950f2707e4SIgor Mammedov }
4960f2707e4SIgor Mammedov 
4970f2707e4SIgor Mammedov /* pack data with DefBuffer encoding */
build_buffer(GArray * array,uint8_t op)4980f2707e4SIgor Mammedov static void build_buffer(GArray *array, uint8_t op)
4990f2707e4SIgor Mammedov {
5000f2707e4SIgor Mammedov     GArray *data = build_alloc_array();
5010f2707e4SIgor Mammedov 
5020f2707e4SIgor Mammedov     build_append_int(data, array->len);
5030f2707e4SIgor Mammedov     g_array_prepend_vals(array, data->data, data->len);
5040f2707e4SIgor Mammedov     build_free_array(data);
5050f2707e4SIgor Mammedov     build_package(array, op);
5060f2707e4SIgor Mammedov }
5070f2707e4SIgor Mammedov 
aml_append(Aml * parent_ctx,Aml * child)5080f2707e4SIgor Mammedov void aml_append(Aml *parent_ctx, Aml *child)
5090f2707e4SIgor Mammedov {
5107d433b0dSMichael S. Tsirkin     GArray *buf = build_alloc_array();
5117d433b0dSMichael S. Tsirkin     build_append_array(buf, child->buf);
5127d433b0dSMichael S. Tsirkin 
5130f2707e4SIgor Mammedov     switch (child->block_flags) {
5140f2707e4SIgor Mammedov     case AML_OPCODE:
5150f2707e4SIgor Mammedov         build_append_byte(parent_ctx->buf, child->op);
5160f2707e4SIgor Mammedov         break;
5170f2707e4SIgor Mammedov     case AML_EXT_PACKAGE:
5187d433b0dSMichael S. Tsirkin         build_extop_package(buf, child->op);
5190f2707e4SIgor Mammedov         break;
5200f2707e4SIgor Mammedov     case AML_PACKAGE:
5217d433b0dSMichael S. Tsirkin         build_package(buf, child->op);
5220f2707e4SIgor Mammedov         break;
5230f2707e4SIgor Mammedov     case AML_RES_TEMPLATE:
5247d433b0dSMichael S. Tsirkin         build_append_byte(buf, 0x79); /* EndTag */
5250f2707e4SIgor Mammedov         /*
5260f2707e4SIgor Mammedov          * checksum operations are treated as succeeded if checksum
5270f2707e4SIgor Mammedov          * field is zero. [ACPI Spec 1.0b, 6.4.2.8 End Tag]
5280f2707e4SIgor Mammedov          */
5297d433b0dSMichael S. Tsirkin         build_append_byte(buf, 0);
5300f2707e4SIgor Mammedov         /* fall through, to pack resources in buffer */
5310f2707e4SIgor Mammedov     case AML_BUFFER:
5327d433b0dSMichael S. Tsirkin         build_buffer(buf, child->op);
5330f2707e4SIgor Mammedov         break;
5340f2707e4SIgor Mammedov     case AML_NO_OPCODE:
5350f2707e4SIgor Mammedov         break;
5360f2707e4SIgor Mammedov     default:
5373f46ff1dSPierrick Bouvier         g_assert_not_reached();
5380f2707e4SIgor Mammedov     }
5397d433b0dSMichael S. Tsirkin     build_append_array(parent_ctx->buf, buf);
5407d433b0dSMichael S. Tsirkin     build_free_array(buf);
5410f2707e4SIgor Mammedov }
5422ef7c27bSIgor Mammedov 
5432ef7c27bSIgor Mammedov /* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefScope */
aml_scope(const char * name_format,...)5442ef7c27bSIgor Mammedov Aml *aml_scope(const char *name_format, ...)
5452ef7c27bSIgor Mammedov {
5462ef7c27bSIgor Mammedov     va_list ap;
5472ef7c27bSIgor Mammedov     Aml *var = aml_bundle(0x10 /* ScopeOp */, AML_PACKAGE);
5482ef7c27bSIgor Mammedov     va_start(ap, name_format);
5492ef7c27bSIgor Mammedov     build_append_namestringv(var->buf, name_format, ap);
5502ef7c27bSIgor Mammedov     va_end(ap);
5512ef7c27bSIgor Mammedov     return var;
5522ef7c27bSIgor Mammedov }
553be06ebd0SIgor Mammedov 
554b25af5adSIgor Mammedov /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefReturn */
aml_return(Aml * val)555b25af5adSIgor Mammedov Aml *aml_return(Aml *val)
556b25af5adSIgor Mammedov {
557b25af5adSIgor Mammedov     Aml *var = aml_opcode(0xA4 /* ReturnOp */);
558b25af5adSIgor Mammedov     aml_append(var, val);
559b25af5adSIgor Mammedov     return var;
560b25af5adSIgor Mammedov }
561b25af5adSIgor Mammedov 
562e8977414SIgor Mammedov /* ACPI 1.0b: 16.2.6.3 Debug Objects Encoding: DebugObj */
aml_debug(void)563e8977414SIgor Mammedov Aml *aml_debug(void)
564e8977414SIgor Mammedov {
565e8977414SIgor Mammedov     Aml *var = aml_alloc();
566e8977414SIgor Mammedov     build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
567e8977414SIgor Mammedov     build_append_byte(var->buf, 0x31); /* DebugOp */
568e8977414SIgor Mammedov     return var;
569e8977414SIgor Mammedov }
570e8977414SIgor Mammedov 
5713c054bd5SIgor Mammedov /*
572295a515dSIgor Mammedov  * ACPI 1.0b: 16.2.3 Data Objects Encoding:
573295a515dSIgor Mammedov  * encodes: ByteConst, WordConst, DWordConst, QWordConst, ZeroOp, OneOp
574295a515dSIgor Mammedov  */
aml_int(const uint64_t val)575295a515dSIgor Mammedov Aml *aml_int(const uint64_t val)
576295a515dSIgor Mammedov {
577295a515dSIgor Mammedov     Aml *var = aml_alloc();
578295a515dSIgor Mammedov     build_append_int(var->buf, val);
579295a515dSIgor Mammedov     return var;
580295a515dSIgor Mammedov }
581295a515dSIgor Mammedov 
582295a515dSIgor Mammedov /*
5833c054bd5SIgor Mammedov  * helper to construct NameString, which returns Aml object
5843c054bd5SIgor Mammedov  * for using with aml_append or other aml_* terms
5853c054bd5SIgor Mammedov  */
aml_name(const char * name_format,...)5863c054bd5SIgor Mammedov Aml *aml_name(const char *name_format, ...)
5873c054bd5SIgor Mammedov {
5883c054bd5SIgor Mammedov     va_list ap;
5893c054bd5SIgor Mammedov     Aml *var = aml_alloc();
5903c054bd5SIgor Mammedov     va_start(ap, name_format);
5913c054bd5SIgor Mammedov     build_append_namestringv(var->buf, name_format, ap);
5923c054bd5SIgor Mammedov     va_end(ap);
5933c054bd5SIgor Mammedov     return var;
5943c054bd5SIgor Mammedov }
5953c054bd5SIgor Mammedov 
5963c054bd5SIgor Mammedov /* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefName */
aml_name_decl(const char * name,Aml * val)5973c054bd5SIgor Mammedov Aml *aml_name_decl(const char *name, Aml *val)
5983c054bd5SIgor Mammedov {
5993c054bd5SIgor Mammedov     Aml *var = aml_opcode(0x08 /* NameOp */);
6003c054bd5SIgor Mammedov     build_append_namestring(var->buf, "%s", name);
6013c054bd5SIgor Mammedov     aml_append(var, val);
6023c054bd5SIgor Mammedov     return var;
6033c054bd5SIgor Mammedov }
6043c054bd5SIgor Mammedov 
6057193f3a6SIgor Mammedov /* ACPI 1.0b: 16.2.6.1 Arg Objects Encoding */
aml_arg(int pos)6067193f3a6SIgor Mammedov Aml *aml_arg(int pos)
6077193f3a6SIgor Mammedov {
6087193f3a6SIgor Mammedov     uint8_t op = 0x68 /* ARG0 op */ + pos;
6097193f3a6SIgor Mammedov 
6107193f3a6SIgor Mammedov     assert(pos <= 6);
6119be38598SEduardo Habkost     return aml_opcode(op);
6127193f3a6SIgor Mammedov }
6137193f3a6SIgor Mammedov 
614f411199dSIgor Mammedov /* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToInteger */
aml_to_integer(Aml * arg)615f411199dSIgor Mammedov Aml *aml_to_integer(Aml *arg)
616f411199dSIgor Mammedov {
617f411199dSIgor Mammedov     Aml *var = aml_opcode(0x99 /* ToIntegerOp */);
618f411199dSIgor Mammedov     aml_append(var, arg);
619f411199dSIgor Mammedov     build_append_byte(var->buf, 0x00 /* NullNameOp */);
620f411199dSIgor Mammedov     return var;
621f411199dSIgor Mammedov }
622f411199dSIgor Mammedov 
6236d5ea945SIgor Mammedov /* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToHexString */
aml_to_hexstring(Aml * src,Aml * dst)6246d5ea945SIgor Mammedov Aml *aml_to_hexstring(Aml *src, Aml *dst)
6256d5ea945SIgor Mammedov {
6266d5ea945SIgor Mammedov     Aml *var = aml_opcode(0x98 /* ToHexStringOp */);
6276d5ea945SIgor Mammedov     aml_append(var, src);
6286d5ea945SIgor Mammedov     if (dst) {
6296d5ea945SIgor Mammedov         aml_append(var, dst);
6306d5ea945SIgor Mammedov     } else {
6316d5ea945SIgor Mammedov         build_append_byte(var->buf, 0x00 /* NullNameOp */);
6326d5ea945SIgor Mammedov     }
6336d5ea945SIgor Mammedov     return var;
6346d5ea945SIgor Mammedov }
6356d5ea945SIgor Mammedov 
63625c1432eSIgor Mammedov /* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToBuffer */
aml_to_buffer(Aml * src,Aml * dst)63725c1432eSIgor Mammedov Aml *aml_to_buffer(Aml *src, Aml *dst)
63825c1432eSIgor Mammedov {
63925c1432eSIgor Mammedov     Aml *var = aml_opcode(0x96 /* ToBufferOp */);
64025c1432eSIgor Mammedov     aml_append(var, src);
64125c1432eSIgor Mammedov     if (dst) {
64225c1432eSIgor Mammedov         aml_append(var, dst);
64325c1432eSIgor Mammedov     } else {
64425c1432eSIgor Mammedov         build_append_byte(var->buf, 0x00 /* NullNameOp */);
64525c1432eSIgor Mammedov     }
64625c1432eSIgor Mammedov     return var;
64725c1432eSIgor Mammedov }
64825c1432eSIgor Mammedov 
649910e4069SIgor Mammedov /* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToDecimalString */
aml_to_decimalstring(Aml * src,Aml * dst)650910e4069SIgor Mammedov Aml *aml_to_decimalstring(Aml *src, Aml *dst)
651910e4069SIgor Mammedov {
652910e4069SIgor Mammedov     Aml *var = aml_opcode(0x97 /* ToDecimalStringOp */);
653910e4069SIgor Mammedov     aml_append(var, src);
654910e4069SIgor Mammedov     if (dst) {
655910e4069SIgor Mammedov         aml_append(var, dst);
656910e4069SIgor Mammedov     } else {
657910e4069SIgor Mammedov         build_append_byte(var->buf, 0x00 /* NullNameOp */);
658910e4069SIgor Mammedov     }
659910e4069SIgor Mammedov     return var;
660910e4069SIgor Mammedov }
661910e4069SIgor Mammedov 
662c263b3f7SIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefStore */
aml_store(Aml * val,Aml * target)663c263b3f7SIgor Mammedov Aml *aml_store(Aml *val, Aml *target)
664c263b3f7SIgor Mammedov {
665c263b3f7SIgor Mammedov     Aml *var = aml_opcode(0x70 /* StoreOp */);
666c263b3f7SIgor Mammedov     aml_append(var, val);
667c263b3f7SIgor Mammedov     aml_append(var, target);
668c263b3f7SIgor Mammedov     return var;
669c263b3f7SIgor Mammedov }
670c263b3f7SIgor Mammedov 
671439e2a6eSIgor Mammedov /**
672439e2a6eSIgor Mammedov  * build_opcode_2arg_dst:
673439e2a6eSIgor Mammedov  * @op: 1-byte opcode
674439e2a6eSIgor Mammedov  * @arg1: 1st operand
675439e2a6eSIgor Mammedov  * @arg2: 2nd operand
676439e2a6eSIgor Mammedov  * @dst: optional target to store to, set to NULL if it's not required
677439e2a6eSIgor Mammedov  *
678439e2a6eSIgor Mammedov  * An internal helper to compose AML terms that have
679439e2a6eSIgor Mammedov  *   "Op Operand Operand Target"
680439e2a6eSIgor Mammedov  * pattern.
681439e2a6eSIgor Mammedov  *
6829b4b4e51SMichael Tokarev  * Returns: The newly allocated and composed according to pattern Aml object.
683439e2a6eSIgor Mammedov  */
684439e2a6eSIgor Mammedov static Aml *
build_opcode_2arg_dst(uint8_t op,Aml * arg1,Aml * arg2,Aml * dst)685439e2a6eSIgor Mammedov build_opcode_2arg_dst(uint8_t op, Aml *arg1, Aml *arg2, Aml *dst)
686439e2a6eSIgor Mammedov {
687439e2a6eSIgor Mammedov     Aml *var = aml_opcode(op);
688439e2a6eSIgor Mammedov     aml_append(var, arg1);
689439e2a6eSIgor Mammedov     aml_append(var, arg2);
690439e2a6eSIgor Mammedov     if (dst) {
691439e2a6eSIgor Mammedov         aml_append(var, dst);
692439e2a6eSIgor Mammedov     } else {
693439e2a6eSIgor Mammedov         build_append_byte(var->buf, 0x00 /* NullNameOp */);
694439e2a6eSIgor Mammedov     }
695439e2a6eSIgor Mammedov     return var;
696439e2a6eSIgor Mammedov }
697439e2a6eSIgor Mammedov 
698926f5aaeSIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAnd */
aml_and(Aml * arg1,Aml * arg2,Aml * dst)6995530427fSIgor Mammedov Aml *aml_and(Aml *arg1, Aml *arg2, Aml *dst)
700926f5aaeSIgor Mammedov {
7015530427fSIgor Mammedov     return build_opcode_2arg_dst(0x7B /* AndOp */, arg1, arg2, dst);
702926f5aaeSIgor Mammedov }
703926f5aaeSIgor Mammedov 
704922cc882SShannon Zhao /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefOr */
aml_or(Aml * arg1,Aml * arg2,Aml * dst)705ca3df95dSIgor Mammedov Aml *aml_or(Aml *arg1, Aml *arg2, Aml *dst)
706922cc882SShannon Zhao {
707ca3df95dSIgor Mammedov     return build_opcode_2arg_dst(0x7D /* OrOp */, arg1, arg2, dst);
708922cc882SShannon Zhao }
709922cc882SShannon Zhao 
7105776fa99SIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLAnd */
aml_land(Aml * arg1,Aml * arg2)7115776fa99SIgor Mammedov Aml *aml_land(Aml *arg1, Aml *arg2)
7125776fa99SIgor Mammedov {
7135776fa99SIgor Mammedov     Aml *var = aml_opcode(0x90 /* LAndOp */);
7145776fa99SIgor Mammedov     aml_append(var, arg1);
7155776fa99SIgor Mammedov     aml_append(var, arg2);
7165776fa99SIgor Mammedov     return var;
7175776fa99SIgor Mammedov }
7185776fa99SIgor Mammedov 
719df241999SIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLOr */
aml_lor(Aml * arg1,Aml * arg2)720df241999SIgor Mammedov Aml *aml_lor(Aml *arg1, Aml *arg2)
721df241999SIgor Mammedov {
722df241999SIgor Mammedov     Aml *var = aml_opcode(0x91 /* LOrOp */);
723df241999SIgor Mammedov     aml_append(var, arg1);
724df241999SIgor Mammedov     aml_append(var, arg2);
725df241999SIgor Mammedov     return var;
726df241999SIgor Mammedov }
727df241999SIgor Mammedov 
728a57dddddSMarcel Apfelbaum /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftLeft */
aml_shiftleft(Aml * arg1,Aml * count)729a57dddddSMarcel Apfelbaum Aml *aml_shiftleft(Aml *arg1, Aml *count)
730a57dddddSMarcel Apfelbaum {
731439e2a6eSIgor Mammedov     return build_opcode_2arg_dst(0x79 /* ShiftLeftOp */, arg1, count, NULL);
732a57dddddSMarcel Apfelbaum }
733a57dddddSMarcel Apfelbaum 
734f7bd7b8eSMarcel Apfelbaum /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftRight */
aml_shiftright(Aml * arg1,Aml * count,Aml * dst)735c360639aSIgor Mammedov Aml *aml_shiftright(Aml *arg1, Aml *count, Aml *dst)
736f7bd7b8eSMarcel Apfelbaum {
737c360639aSIgor Mammedov     return build_opcode_2arg_dst(0x7A /* ShiftRightOp */, arg1, count, dst);
738f7bd7b8eSMarcel Apfelbaum }
739f7bd7b8eSMarcel Apfelbaum 
74096396e28SMarcel Apfelbaum /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLLess */
aml_lless(Aml * arg1,Aml * arg2)74196396e28SMarcel Apfelbaum Aml *aml_lless(Aml *arg1, Aml *arg2)
74296396e28SMarcel Apfelbaum {
74396396e28SMarcel Apfelbaum     Aml *var = aml_opcode(0x95 /* LLessOp */);
74496396e28SMarcel Apfelbaum     aml_append(var, arg1);
74596396e28SMarcel Apfelbaum     aml_append(var, arg2);
74696396e28SMarcel Apfelbaum     return var;
74796396e28SMarcel Apfelbaum }
74896396e28SMarcel Apfelbaum 
749c08cf070SMarcel Apfelbaum /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAdd */
aml_add(Aml * arg1,Aml * arg2,Aml * dst)75020ca5208SIgor Mammedov Aml *aml_add(Aml *arg1, Aml *arg2, Aml *dst)
751c08cf070SMarcel Apfelbaum {
75220ca5208SIgor Mammedov     return build_opcode_2arg_dst(0x72 /* AddOp */, arg1, arg2, dst);
753c08cf070SMarcel Apfelbaum }
754c08cf070SMarcel Apfelbaum 
7557059eb42SIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSubtract */
aml_subtract(Aml * arg1,Aml * arg2,Aml * dst)7567059eb42SIgor Mammedov Aml *aml_subtract(Aml *arg1, Aml *arg2, Aml *dst)
7577059eb42SIgor Mammedov {
7587059eb42SIgor Mammedov     return build_opcode_2arg_dst(0x74 /* SubtractOp */, arg1, arg2, dst);
7597059eb42SIgor Mammedov }
7607059eb42SIgor Mammedov 
761af39d536SMarcel Apfelbaum /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIncrement */
aml_increment(Aml * arg)762af39d536SMarcel Apfelbaum Aml *aml_increment(Aml *arg)
763af39d536SMarcel Apfelbaum {
764af39d536SMarcel Apfelbaum     Aml *var = aml_opcode(0x75 /* IncrementOp */);
765af39d536SMarcel Apfelbaum     aml_append(var, arg);
766af39d536SMarcel Apfelbaum     return var;
767af39d536SMarcel Apfelbaum }
768af39d536SMarcel Apfelbaum 
7697059eb42SIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDecrement */
aml_decrement(Aml * arg)7707059eb42SIgor Mammedov Aml *aml_decrement(Aml *arg)
7717059eb42SIgor Mammedov {
7727059eb42SIgor Mammedov     Aml *var = aml_opcode(0x76 /* DecrementOp */);
7737059eb42SIgor Mammedov     aml_append(var, arg);
7747059eb42SIgor Mammedov     return var;
7757059eb42SIgor Mammedov }
7767059eb42SIgor Mammedov 
777928b8996SMarcel Apfelbaum /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIndex */
aml_index(Aml * arg1,Aml * idx)778928b8996SMarcel Apfelbaum Aml *aml_index(Aml *arg1, Aml *idx)
779928b8996SMarcel Apfelbaum {
780439e2a6eSIgor Mammedov     return build_opcode_2arg_dst(0x88 /* IndexOp */, arg1, idx, NULL);
781928b8996SMarcel Apfelbaum }
782928b8996SMarcel Apfelbaum 
78334189453SIgor Mammedov /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
aml_notify(Aml * arg1,Aml * arg2)78434189453SIgor Mammedov Aml *aml_notify(Aml *arg1, Aml *arg2)
78534189453SIgor Mammedov {
78634189453SIgor Mammedov     Aml *var = aml_opcode(0x86 /* NotifyOp */);
78734189453SIgor Mammedov     aml_append(var, arg1);
78834189453SIgor Mammedov     aml_append(var, arg2);
78934189453SIgor Mammedov     return var;
79034189453SIgor Mammedov }
79134189453SIgor Mammedov 
7925776fa99SIgor Mammedov /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefBreak */
aml_break(void)7935776fa99SIgor Mammedov Aml *aml_break(void)
7945776fa99SIgor Mammedov {
7955776fa99SIgor Mammedov     Aml *var = aml_opcode(0xa5 /* BreakOp */);
7965776fa99SIgor Mammedov     return var;
7975776fa99SIgor Mammedov }
7985776fa99SIgor Mammedov 
7999a232487SMarc-André Lureau /* helper to call method without argument */
aml_call0(const char * method)8007b38ba9cSIgor Mammedov Aml *aml_call0(const char *method)
8017b38ba9cSIgor Mammedov {
8027b38ba9cSIgor Mammedov     Aml *var = aml_alloc();
8037b38ba9cSIgor Mammedov     build_append_namestring(var->buf, "%s", method);
8047b38ba9cSIgor Mammedov     return var;
8057b38ba9cSIgor Mammedov }
8067b38ba9cSIgor Mammedov 
8077b38ba9cSIgor Mammedov /* helper to call method with 1 argument */
aml_call1(const char * method,Aml * arg1)8083f3992b7SIgor Mammedov Aml *aml_call1(const char *method, Aml *arg1)
8093f3992b7SIgor Mammedov {
8103f3992b7SIgor Mammedov     Aml *var = aml_alloc();
8113f3992b7SIgor Mammedov     build_append_namestring(var->buf, "%s", method);
8123f3992b7SIgor Mammedov     aml_append(var, arg1);
8133f3992b7SIgor Mammedov     return var;
8143f3992b7SIgor Mammedov }
8153f3992b7SIgor Mammedov 
8163f3992b7SIgor Mammedov /* helper to call method with 2 arguments */
aml_call2(const char * method,Aml * arg1,Aml * arg2)8173f3992b7SIgor Mammedov Aml *aml_call2(const char *method, Aml *arg1, Aml *arg2)
8183f3992b7SIgor Mammedov {
8193f3992b7SIgor Mammedov     Aml *var = aml_alloc();
8203f3992b7SIgor Mammedov     build_append_namestring(var->buf, "%s", method);
8213f3992b7SIgor Mammedov     aml_append(var, arg1);
8223f3992b7SIgor Mammedov     aml_append(var, arg2);
8233f3992b7SIgor Mammedov     return var;
8243f3992b7SIgor Mammedov }
8253f3992b7SIgor Mammedov 
8263f3992b7SIgor Mammedov /* helper to call method with 3 arguments */
aml_call3(const char * method,Aml * arg1,Aml * arg2,Aml * arg3)8273f3992b7SIgor Mammedov Aml *aml_call3(const char *method, Aml *arg1, Aml *arg2, Aml *arg3)
8283f3992b7SIgor Mammedov {
8293f3992b7SIgor Mammedov     Aml *var = aml_alloc();
8303f3992b7SIgor Mammedov     build_append_namestring(var->buf, "%s", method);
8313f3992b7SIgor Mammedov     aml_append(var, arg1);
8323f3992b7SIgor Mammedov     aml_append(var, arg2);
8333f3992b7SIgor Mammedov     aml_append(var, arg3);
8343f3992b7SIgor Mammedov     return var;
8353f3992b7SIgor Mammedov }
8363f3992b7SIgor Mammedov 
8373f3992b7SIgor Mammedov /* helper to call method with 4 arguments */
aml_call4(const char * method,Aml * arg1,Aml * arg2,Aml * arg3,Aml * arg4)8383f3992b7SIgor Mammedov Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4)
8393f3992b7SIgor Mammedov {
8403f3992b7SIgor Mammedov     Aml *var = aml_alloc();
8413f3992b7SIgor Mammedov     build_append_namestring(var->buf, "%s", method);
8423f3992b7SIgor Mammedov     aml_append(var, arg1);
8433f3992b7SIgor Mammedov     aml_append(var, arg2);
8443f3992b7SIgor Mammedov     aml_append(var, arg3);
8453f3992b7SIgor Mammedov     aml_append(var, arg4);
8463f3992b7SIgor Mammedov     return var;
8473f3992b7SIgor Mammedov }
8483f3992b7SIgor Mammedov 
849052889b8SXiao Guangrong /* helper to call method with 5 arguments */
aml_call5(const char * method,Aml * arg1,Aml * arg2,Aml * arg3,Aml * arg4,Aml * arg5)850052889b8SXiao Guangrong Aml *aml_call5(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4,
851052889b8SXiao Guangrong                Aml *arg5)
852052889b8SXiao Guangrong {
853052889b8SXiao Guangrong     Aml *var = aml_alloc();
854052889b8SXiao Guangrong     build_append_namestring(var->buf, "%s", method);
855052889b8SXiao Guangrong     aml_append(var, arg1);
856052889b8SXiao Guangrong     aml_append(var, arg2);
857052889b8SXiao Guangrong     aml_append(var, arg3);
858052889b8SXiao Guangrong     aml_append(var, arg4);
859052889b8SXiao Guangrong     aml_append(var, arg5);
860052889b8SXiao Guangrong     return var;
861052889b8SXiao Guangrong }
862052889b8SXiao Guangrong 
863910e4069SIgor Mammedov /* helper to call method with 5 arguments */
aml_call6(const char * method,Aml * arg1,Aml * arg2,Aml * arg3,Aml * arg4,Aml * arg5,Aml * arg6)864910e4069SIgor Mammedov Aml *aml_call6(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4,
865910e4069SIgor Mammedov                Aml *arg5, Aml *arg6)
866910e4069SIgor Mammedov {
867910e4069SIgor Mammedov     Aml *var = aml_alloc();
868910e4069SIgor Mammedov     build_append_namestring(var->buf, "%s", method);
869910e4069SIgor Mammedov     aml_append(var, arg1);
870910e4069SIgor Mammedov     aml_append(var, arg2);
871910e4069SIgor Mammedov     aml_append(var, arg3);
872910e4069SIgor Mammedov     aml_append(var, arg4);
873910e4069SIgor Mammedov     aml_append(var, arg5);
874910e4069SIgor Mammedov     aml_append(var, arg6);
875910e4069SIgor Mammedov     return var;
876910e4069SIgor Mammedov }
877910e4069SIgor Mammedov 
878dc17ab1dSShannon Zhao /*
8794ecdc746SShannon Zhao  * ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor
8804ecdc746SShannon Zhao  * Type 1, Large Item Name 0xC
8814ecdc746SShannon Zhao  */
8824ecdc746SShannon Zhao 
aml_gpio_connection(AmlGpioConnectionType type,AmlConsumerAndProducer con_and_pro,uint8_t flags,AmlPinConfig pin_config,uint16_t output_drive,uint16_t debounce_timeout,const uint32_t pin_list[],uint32_t pin_count,const char * resource_source_name,const uint8_t * vendor_data,uint16_t vendor_data_len)8834ecdc746SShannon Zhao static Aml *aml_gpio_connection(AmlGpioConnectionType type,
8844ecdc746SShannon Zhao                                 AmlConsumerAndProducer con_and_pro,
8854ecdc746SShannon Zhao                                 uint8_t flags, AmlPinConfig pin_config,
8864ecdc746SShannon Zhao                                 uint16_t output_drive,
8874ecdc746SShannon Zhao                                 uint16_t debounce_timeout,
8884ecdc746SShannon Zhao                                 const uint32_t pin_list[], uint32_t pin_count,
8894ecdc746SShannon Zhao                                 const char *resource_source_name,
8904ecdc746SShannon Zhao                                 const uint8_t *vendor_data,
8914ecdc746SShannon Zhao                                 uint16_t vendor_data_len)
8924ecdc746SShannon Zhao {
8934ecdc746SShannon Zhao     Aml *var = aml_alloc();
8944ecdc746SShannon Zhao     const uint16_t min_desc_len = 0x16;
8954ecdc746SShannon Zhao     uint16_t resource_source_name_len, length;
8964ecdc746SShannon Zhao     uint16_t pin_table_offset, resource_source_name_offset, vendor_data_offset;
8974ecdc746SShannon Zhao     uint32_t i;
8984ecdc746SShannon Zhao 
8994ecdc746SShannon Zhao     assert(resource_source_name);
9004ecdc746SShannon Zhao     resource_source_name_len = strlen(resource_source_name) + 1;
9014ecdc746SShannon Zhao     length = min_desc_len + resource_source_name_len + vendor_data_len;
9024ecdc746SShannon Zhao     pin_table_offset = min_desc_len + 1;
9034ecdc746SShannon Zhao     resource_source_name_offset = pin_table_offset + pin_count * 2;
9044ecdc746SShannon Zhao     vendor_data_offset = resource_source_name_offset + resource_source_name_len;
9054ecdc746SShannon Zhao 
9064ecdc746SShannon Zhao     build_append_byte(var->buf, 0x8C);  /* GPIO Connection Descriptor */
9074ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, length, 2); /* Length */
9084ecdc746SShannon Zhao     build_append_byte(var->buf, 1);     /* Revision ID */
9094ecdc746SShannon Zhao     build_append_byte(var->buf, type);  /* GPIO Connection Type */
9104ecdc746SShannon Zhao     /* General Flags (2 bytes) */
9114ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, con_and_pro, 2);
9124ecdc746SShannon Zhao     /* Interrupt and IO Flags (2 bytes) */
9134ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, flags, 2);
9144ecdc746SShannon Zhao     /* Pin Configuration 0 = Default 1 = Pull-up 2 = Pull-down 3 = No Pull */
9154ecdc746SShannon Zhao     build_append_byte(var->buf, pin_config);
9164ecdc746SShannon Zhao     /* Output Drive Strength (2 bytes) */
9174ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, output_drive, 2);
9184ecdc746SShannon Zhao     /* Debounce Timeout (2 bytes) */
9194ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, debounce_timeout, 2);
9204ecdc746SShannon Zhao     /* Pin Table Offset (2 bytes) */
9214ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, pin_table_offset, 2);
9224ecdc746SShannon Zhao     build_append_byte(var->buf, 0);     /* Resource Source Index */
9234ecdc746SShannon Zhao     /* Resource Source Name Offset (2 bytes) */
9244ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, resource_source_name_offset, 2);
9254ecdc746SShannon Zhao     /* Vendor Data Offset (2 bytes) */
9264ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, vendor_data_offset, 2);
9274ecdc746SShannon Zhao     /* Vendor Data Length (2 bytes) */
9284ecdc746SShannon Zhao     build_append_int_noprefix(var->buf, vendor_data_len, 2);
9294ecdc746SShannon Zhao     /* Pin Number (2n bytes)*/
9304ecdc746SShannon Zhao     for (i = 0; i < pin_count; i++) {
9314ecdc746SShannon Zhao         build_append_int_noprefix(var->buf, pin_list[i], 2);
9324ecdc746SShannon Zhao     }
9334ecdc746SShannon Zhao 
9344ecdc746SShannon Zhao     /* Resource Source Name */
9354ecdc746SShannon Zhao     build_append_namestring(var->buf, "%s", resource_source_name);
9364ecdc746SShannon Zhao     build_append_byte(var->buf, '\0');
9374ecdc746SShannon Zhao 
9384ecdc746SShannon Zhao     /* Vendor-defined Data */
9394ecdc746SShannon Zhao     if (vendor_data != NULL) {
9404ecdc746SShannon Zhao         g_array_append_vals(var->buf, vendor_data, vendor_data_len);
9414ecdc746SShannon Zhao     }
9424ecdc746SShannon Zhao 
9434ecdc746SShannon Zhao     return var;
9444ecdc746SShannon Zhao }
9454ecdc746SShannon Zhao 
9464ecdc746SShannon Zhao /*
94737d0e980SShannon Zhao  * ACPI 5.0: 19.5.53
94837d0e980SShannon Zhao  * GpioInt(GPIO Interrupt Connection Resource Descriptor Macro)
94937d0e980SShannon Zhao  */
aml_gpio_int(AmlConsumerAndProducer con_and_pro,AmlLevelAndEdge edge_level,AmlActiveHighAndLow active_level,AmlShared shared,AmlPinConfig pin_config,uint16_t debounce_timeout,const uint32_t pin_list[],uint32_t pin_count,const char * resource_source_name,const uint8_t * vendor_data,uint16_t vendor_data_len)95037d0e980SShannon Zhao Aml *aml_gpio_int(AmlConsumerAndProducer con_and_pro,
95137d0e980SShannon Zhao                   AmlLevelAndEdge edge_level,
95237d0e980SShannon Zhao                   AmlActiveHighAndLow active_level, AmlShared shared,
95337d0e980SShannon Zhao                   AmlPinConfig pin_config, uint16_t debounce_timeout,
95437d0e980SShannon Zhao                   const uint32_t pin_list[], uint32_t pin_count,
95537d0e980SShannon Zhao                   const char *resource_source_name,
95637d0e980SShannon Zhao                   const uint8_t *vendor_data, uint16_t vendor_data_len)
95737d0e980SShannon Zhao {
95837d0e980SShannon Zhao     uint8_t flags = edge_level | (active_level << 1) | (shared << 3);
95937d0e980SShannon Zhao 
96037d0e980SShannon Zhao     return aml_gpio_connection(AML_INTERRUPT_CONNECTION, con_and_pro, flags,
96137d0e980SShannon Zhao                                pin_config, 0, debounce_timeout, pin_list,
96237d0e980SShannon Zhao                                pin_count, resource_source_name, vendor_data,
96337d0e980SShannon Zhao                                vendor_data_len);
96437d0e980SShannon Zhao }
96537d0e980SShannon Zhao 
96637d0e980SShannon Zhao /*
967dc17ab1dSShannon Zhao  * ACPI 1.0b: 6.4.3.4 32-Bit Fixed Location Memory Range Descriptor
968dc17ab1dSShannon Zhao  * (Type 1, Large Item Name 0x6)
969dc17ab1dSShannon Zhao  */
aml_memory32_fixed(uint32_t addr,uint32_t size,AmlReadAndWrite read_and_write)970dc17ab1dSShannon Zhao Aml *aml_memory32_fixed(uint32_t addr, uint32_t size,
971dc17ab1dSShannon Zhao                         AmlReadAndWrite read_and_write)
972dc17ab1dSShannon Zhao {
973dc17ab1dSShannon Zhao     Aml *var = aml_alloc();
974dc17ab1dSShannon Zhao     build_append_byte(var->buf, 0x86); /* Memory32Fixed Resource Descriptor */
975dc17ab1dSShannon Zhao     build_append_byte(var->buf, 9);    /* Length, bits[7:0] value = 9 */
976dc17ab1dSShannon Zhao     build_append_byte(var->buf, 0);    /* Length, bits[15:8] value = 0 */
977dc17ab1dSShannon Zhao     build_append_byte(var->buf, read_and_write); /* Write status, 1 rw 0 ro */
978dc17ab1dSShannon Zhao 
979dc17ab1dSShannon Zhao     /* Range base address */
980dc17ab1dSShannon Zhao     build_append_byte(var->buf, extract32(addr, 0, 8));  /* bits[7:0] */
981dc17ab1dSShannon Zhao     build_append_byte(var->buf, extract32(addr, 8, 8));  /* bits[15:8] */
982dc17ab1dSShannon Zhao     build_append_byte(var->buf, extract32(addr, 16, 8)); /* bits[23:16] */
983dc17ab1dSShannon Zhao     build_append_byte(var->buf, extract32(addr, 24, 8)); /* bits[31:24] */
984dc17ab1dSShannon Zhao 
985dc17ab1dSShannon Zhao     /* Range length */
986dc17ab1dSShannon Zhao     build_append_byte(var->buf, extract32(size, 0, 8));  /* bits[7:0] */
987dc17ab1dSShannon Zhao     build_append_byte(var->buf, extract32(size, 8, 8));  /* bits[15:8] */
988dc17ab1dSShannon Zhao     build_append_byte(var->buf, extract32(size, 16, 8)); /* bits[23:16] */
989dc17ab1dSShannon Zhao     build_append_byte(var->buf, extract32(size, 24, 8)); /* bits[31:24] */
990dc17ab1dSShannon Zhao     return var;
991dc17ab1dSShannon Zhao }
992dc17ab1dSShannon Zhao 
993205d1d1cSShannon Zhao /*
994205d1d1cSShannon Zhao  * ACPI 5.0: 6.4.3.6 Extended Interrupt Descriptor
995205d1d1cSShannon Zhao  * Type 1, Large Item Name 0x9
996205d1d1cSShannon Zhao  */
aml_interrupt(AmlConsumerAndProducer con_and_pro,AmlLevelAndEdge level_and_edge,AmlActiveHighAndLow high_and_low,AmlShared shared,uint32_t * irq_list,uint8_t irq_count)997205d1d1cSShannon Zhao Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro,
998205d1d1cSShannon Zhao                    AmlLevelAndEdge level_and_edge,
999205d1d1cSShannon Zhao                    AmlActiveHighAndLow high_and_low, AmlShared shared,
100045fcf539SIgor Mammedov                    uint32_t *irq_list, uint8_t irq_count)
1001205d1d1cSShannon Zhao {
100245fcf539SIgor Mammedov     int i;
1003205d1d1cSShannon Zhao     Aml *var = aml_alloc();
1004205d1d1cSShannon Zhao     uint8_t irq_flags = con_and_pro | (level_and_edge << 1)
1005205d1d1cSShannon Zhao                         | (high_and_low << 2) | (shared << 3);
100645fcf539SIgor Mammedov     const int header_bytes_in_len = 2;
100745fcf539SIgor Mammedov     uint16_t len = header_bytes_in_len + irq_count * sizeof(uint32_t);
100845fcf539SIgor Mammedov 
100945fcf539SIgor Mammedov     assert(irq_count > 0);
1010205d1d1cSShannon Zhao 
1011205d1d1cSShannon Zhao     build_append_byte(var->buf, 0x89); /* Extended irq descriptor */
101245fcf539SIgor Mammedov     build_append_byte(var->buf, len & 0xFF); /* Length, bits[7:0] */
101345fcf539SIgor Mammedov     build_append_byte(var->buf, len >> 8); /* Length, bits[15:8] */
1014205d1d1cSShannon Zhao     build_append_byte(var->buf, irq_flags); /* Interrupt Vector Information. */
101545fcf539SIgor Mammedov     build_append_byte(var->buf, irq_count);   /* Interrupt table length */
1016205d1d1cSShannon Zhao 
101745fcf539SIgor Mammedov     /* Interrupt Number List */
101845fcf539SIgor Mammedov     for (i = 0; i < irq_count; i++) {
101945fcf539SIgor Mammedov         build_append_int_noprefix(var->buf, irq_list[i], 4);
102045fcf539SIgor Mammedov     }
1021205d1d1cSShannon Zhao     return var;
1022205d1d1cSShannon Zhao }
1023205d1d1cSShannon Zhao 
102452fa397cSIgor Mammedov /* ACPI 1.0b: 6.4.2.5 I/O Port Descriptor */
aml_io(AmlIODecode dec,uint16_t min_base,uint16_t max_base,uint8_t aln,uint8_t len)102552fa397cSIgor Mammedov Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
102652fa397cSIgor Mammedov             uint8_t aln, uint8_t len)
102752fa397cSIgor Mammedov {
102852fa397cSIgor Mammedov     Aml *var = aml_alloc();
102952fa397cSIgor Mammedov     build_append_byte(var->buf, 0x47); /* IO port descriptor */
103052fa397cSIgor Mammedov     build_append_byte(var->buf, dec);
103152fa397cSIgor Mammedov     build_append_byte(var->buf, min_base & 0xff);
103252fa397cSIgor Mammedov     build_append_byte(var->buf, (min_base >> 8) & 0xff);
103352fa397cSIgor Mammedov     build_append_byte(var->buf, max_base & 0xff);
103452fa397cSIgor Mammedov     build_append_byte(var->buf, (max_base >> 8) & 0xff);
103552fa397cSIgor Mammedov     build_append_byte(var->buf, aln);
103652fa397cSIgor Mammedov     build_append_byte(var->buf, len);
103752fa397cSIgor Mammedov     return var;
103852fa397cSIgor Mammedov }
103952fa397cSIgor Mammedov 
104070560453SIgor Mammedov /*
104170560453SIgor Mammedov  * ACPI 1.0b: 6.4.2.1.1 ASL Macro for IRQ Descriptor
104270560453SIgor Mammedov  *
104370560453SIgor Mammedov  * More verbose description at:
104470560453SIgor Mammedov  * ACPI 5.0: 19.5.64 IRQNoFlags (Interrupt Resource Descriptor Macro)
104570560453SIgor Mammedov  *           6.4.2.1 IRQ Descriptor
104670560453SIgor Mammedov  */
aml_irq_no_flags(uint8_t irq)104770560453SIgor Mammedov Aml *aml_irq_no_flags(uint8_t irq)
104870560453SIgor Mammedov {
104970560453SIgor Mammedov     uint16_t irq_mask;
105070560453SIgor Mammedov     Aml *var = aml_alloc();
105170560453SIgor Mammedov 
105270560453SIgor Mammedov     assert(irq < 16);
105370560453SIgor Mammedov     build_append_byte(var->buf, 0x22); /* IRQ descriptor 2 byte form */
105470560453SIgor Mammedov 
105570560453SIgor Mammedov     irq_mask = 1U << irq;
105670560453SIgor Mammedov     build_append_byte(var->buf, irq_mask & 0xFF); /* IRQ mask bits[7:0] */
105770560453SIgor Mammedov     build_append_byte(var->buf, irq_mask >> 8); /* IRQ mask bits[15:8] */
105870560453SIgor Mammedov     return var;
105970560453SIgor Mammedov }
106070560453SIgor Mammedov 
1061ea7df04aSShannon Zhao /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLNot */
aml_lnot(Aml * arg)1062ea7df04aSShannon Zhao Aml *aml_lnot(Aml *arg)
1063ea7df04aSShannon Zhao {
1064ea7df04aSShannon Zhao     Aml *var = aml_opcode(0x92 /* LNotOp */);
1065ea7df04aSShannon Zhao     aml_append(var, arg);
1066ea7df04aSShannon Zhao     return var;
1067ea7df04aSShannon Zhao }
1068ea7df04aSShannon Zhao 
106915e44e56SIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLEqual */
aml_equal(Aml * arg1,Aml * arg2)107015e44e56SIgor Mammedov Aml *aml_equal(Aml *arg1, Aml *arg2)
107115e44e56SIgor Mammedov {
107215e44e56SIgor Mammedov     Aml *var = aml_opcode(0x93 /* LequalOp */);
107315e44e56SIgor Mammedov     aml_append(var, arg1);
107415e44e56SIgor Mammedov     aml_append(var, arg2);
107515e44e56SIgor Mammedov     return var;
107615e44e56SIgor Mammedov }
107715e44e56SIgor Mammedov 
1078dabad78bSIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreater */
aml_lgreater(Aml * arg1,Aml * arg2)1079dabad78bSIgor Mammedov Aml *aml_lgreater(Aml *arg1, Aml *arg2)
1080dabad78bSIgor Mammedov {
1081dabad78bSIgor Mammedov     Aml *var = aml_opcode(0x94 /* LGreaterOp */);
1082dabad78bSIgor Mammedov     aml_append(var, arg1);
1083dabad78bSIgor Mammedov     aml_append(var, arg2);
1084dabad78bSIgor Mammedov     return var;
1085dabad78bSIgor Mammedov }
1086dabad78bSIgor Mammedov 
10872d3f667dSIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreaterEqual */
aml_lgreater_equal(Aml * arg1,Aml * arg2)10882d3f667dSIgor Mammedov Aml *aml_lgreater_equal(Aml *arg1, Aml *arg2)
10892d3f667dSIgor Mammedov {
10902d3f667dSIgor Mammedov     /* LGreaterEqualOp := LNotOp LLessOp */
10912d3f667dSIgor Mammedov     Aml *var = aml_opcode(0x92 /* LNotOp */);
10922d3f667dSIgor Mammedov     build_append_byte(var->buf, 0x95 /* LLessOp */);
10932d3f667dSIgor Mammedov     aml_append(var, arg1);
10942d3f667dSIgor Mammedov     aml_append(var, arg2);
10952d3f667dSIgor Mammedov     return var;
10962d3f667dSIgor Mammedov }
10972d3f667dSIgor Mammedov 
109832acac9eSIgor Mammedov /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefIfElse */
aml_if(Aml * predicate)109932acac9eSIgor Mammedov Aml *aml_if(Aml *predicate)
110032acac9eSIgor Mammedov {
110132acac9eSIgor Mammedov     Aml *var = aml_bundle(0xA0 /* IfOp */, AML_PACKAGE);
110232acac9eSIgor Mammedov     aml_append(var, predicate);
110332acac9eSIgor Mammedov     return var;
110432acac9eSIgor Mammedov }
110532acac9eSIgor Mammedov 
1106467b07dfSShannon Zhao /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefElse */
aml_else(void)1107467b07dfSShannon Zhao Aml *aml_else(void)
1108467b07dfSShannon Zhao {
1109467b07dfSShannon Zhao     Aml *var = aml_bundle(0xA1 /* ElseOp */, AML_PACKAGE);
1110467b07dfSShannon Zhao     return var;
1111467b07dfSShannon Zhao }
1112467b07dfSShannon Zhao 
111332d9ca15SMarcel Apfelbaum /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefWhile */
aml_while(Aml * predicate)111432d9ca15SMarcel Apfelbaum Aml *aml_while(Aml *predicate)
111532d9ca15SMarcel Apfelbaum {
111632d9ca15SMarcel Apfelbaum     Aml *var = aml_bundle(0xA2 /* WhileOp */, AML_PACKAGE);
111732d9ca15SMarcel Apfelbaum     aml_append(var, predicate);
111832d9ca15SMarcel Apfelbaum     return var;
111932d9ca15SMarcel Apfelbaum }
112032d9ca15SMarcel Apfelbaum 
1121ea2407d7SIgor Mammedov /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */
aml_method(const char * name,int arg_count,AmlSerializeFlag sflag)11224dbfc881SXiao Guangrong Aml *aml_method(const char *name, int arg_count, AmlSerializeFlag sflag)
1123ea2407d7SIgor Mammedov {
1124ea2407d7SIgor Mammedov     Aml *var = aml_bundle(0x14 /* MethodOp */, AML_PACKAGE);
11254dbfc881SXiao Guangrong     int methodflags;
11264dbfc881SXiao Guangrong 
11274dbfc881SXiao Guangrong     /*
11284dbfc881SXiao Guangrong      * MethodFlags:
11294dbfc881SXiao Guangrong      *   bit 0-2: ArgCount (0-7)
11304dbfc881SXiao Guangrong      *   bit 3: SerializeFlag
11314dbfc881SXiao Guangrong      *     0: NotSerialized
11324dbfc881SXiao Guangrong      *     1: Serialized
11334dbfc881SXiao Guangrong      *   bit 4-7: reserved (must be 0)
11344dbfc881SXiao Guangrong      */
11354dbfc881SXiao Guangrong     assert(arg_count < 8);
11364dbfc881SXiao Guangrong     methodflags = arg_count | (sflag << 3);
11374dbfc881SXiao Guangrong 
1138ea2407d7SIgor Mammedov     build_append_namestring(var->buf, "%s", name);
11394dbfc881SXiao Guangrong     build_append_byte(var->buf, methodflags); /* MethodFlags: ArgCount */
1140ea2407d7SIgor Mammedov     return var;
1141ea2407d7SIgor Mammedov }
1142ea2407d7SIgor Mammedov 
1143be06ebd0SIgor Mammedov /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefDevice */
aml_device(const char * name_format,...)1144be06ebd0SIgor Mammedov Aml *aml_device(const char *name_format, ...)
1145be06ebd0SIgor Mammedov {
1146be06ebd0SIgor Mammedov     va_list ap;
1147be06ebd0SIgor Mammedov     Aml *var = aml_bundle(0x82 /* DeviceOp */, AML_EXT_PACKAGE);
1148be06ebd0SIgor Mammedov     va_start(ap, name_format);
1149be06ebd0SIgor Mammedov     build_append_namestringv(var->buf, name_format, ap);
1150be06ebd0SIgor Mammedov     va_end(ap);
1151be06ebd0SIgor Mammedov     return var;
1152be06ebd0SIgor Mammedov }
11533bfa74a7SIgor Mammedov 
1154ad4a80bcSIgor Mammedov /* ACPI 1.0b: 6.4.1 ASL Macros for Resource Descriptors */
aml_resource_template(void)1155ad4a80bcSIgor Mammedov Aml *aml_resource_template(void)
1156ad4a80bcSIgor Mammedov {
1157ad4a80bcSIgor Mammedov     /* ResourceTemplate is a buffer of Resources with EndTag at the end */
1158ad4a80bcSIgor Mammedov     Aml *var = aml_bundle(0x11 /* BufferOp */, AML_RES_TEMPLATE);
1159ad4a80bcSIgor Mammedov     return var;
1160ad4a80bcSIgor Mammedov }
1161ad4a80bcSIgor Mammedov 
1162ed8b5847SShannon Zhao /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer
1163ed8b5847SShannon Zhao  * Pass byte_list as NULL to request uninitialized buffer to reserve space.
1164ed8b5847SShannon Zhao  */
aml_buffer(int buffer_size,uint8_t * byte_list)1165ed8b5847SShannon Zhao Aml *aml_buffer(int buffer_size, uint8_t *byte_list)
116604b8da54SIgor Mammedov {
1167ed8b5847SShannon Zhao     int i;
116804b8da54SIgor Mammedov     Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
1169ed8b5847SShannon Zhao 
1170ed8b5847SShannon Zhao     for (i = 0; i < buffer_size; i++) {
1171ed8b5847SShannon Zhao         if (byte_list == NULL) {
1172ed8b5847SShannon Zhao             build_append_byte(var->buf, 0x0);
1173ed8b5847SShannon Zhao         } else {
1174ed8b5847SShannon Zhao             build_append_byte(var->buf, byte_list[i]);
1175ed8b5847SShannon Zhao         }
1176ed8b5847SShannon Zhao     }
1177ed8b5847SShannon Zhao 
117804b8da54SIgor Mammedov     return var;
117904b8da54SIgor Mammedov }
118004b8da54SIgor Mammedov 
11813bfa74a7SIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefPackage */
aml_package(uint8_t num_elements)11823bfa74a7SIgor Mammedov Aml *aml_package(uint8_t num_elements)
11833bfa74a7SIgor Mammedov {
11843bfa74a7SIgor Mammedov     Aml *var = aml_bundle(0x12 /* PackageOp */, AML_PACKAGE);
11853bfa74a7SIgor Mammedov     build_append_byte(var->buf, num_elements);
11863bfa74a7SIgor Mammedov     return var;
11873bfa74a7SIgor Mammedov }
118831127938SIgor Mammedov 
118931127938SIgor Mammedov /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefOpRegion */
aml_operation_region(const char * name,AmlRegionSpace rs,Aml * offset,uint32_t len)119031127938SIgor Mammedov Aml *aml_operation_region(const char *name, AmlRegionSpace rs,
11913f3009c0SXiao Guangrong                           Aml *offset, uint32_t len)
119231127938SIgor Mammedov {
119331127938SIgor Mammedov     Aml *var = aml_alloc();
119431127938SIgor Mammedov     build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
119531127938SIgor Mammedov     build_append_byte(var->buf, 0x80); /* OpRegionOp */
119631127938SIgor Mammedov     build_append_namestring(var->buf, "%s", name);
119731127938SIgor Mammedov     build_append_byte(var->buf, rs);
11983f3009c0SXiao Guangrong     aml_append(var, offset);
119931127938SIgor Mammedov     build_append_int(var->buf, len);
120031127938SIgor Mammedov     return var;
120131127938SIgor Mammedov }
1202214ae59fSIgor Mammedov 
1203214ae59fSIgor Mammedov /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: NamedField */
aml_named_field(const char * name,unsigned length)1204214ae59fSIgor Mammedov Aml *aml_named_field(const char *name, unsigned length)
1205214ae59fSIgor Mammedov {
1206214ae59fSIgor Mammedov     Aml *var = aml_alloc();
1207214ae59fSIgor Mammedov     build_append_nameseg(var->buf, name);
1208214ae59fSIgor Mammedov     build_append_pkg_length(var->buf, length, false);
1209214ae59fSIgor Mammedov     return var;
1210214ae59fSIgor Mammedov }
1211214ae59fSIgor Mammedov 
1212e2ea299bSIgor Mammedov /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: ReservedField */
aml_reserved_field(unsigned length)1213e2ea299bSIgor Mammedov Aml *aml_reserved_field(unsigned length)
1214e2ea299bSIgor Mammedov {
1215e2ea299bSIgor Mammedov     Aml *var = aml_alloc();
1216e2ea299bSIgor Mammedov     /* ReservedField  := 0x00 PkgLength */
1217e2ea299bSIgor Mammedov     build_append_byte(var->buf, 0x00);
1218e2ea299bSIgor Mammedov     build_append_pkg_length(var->buf, length, false);
1219e2ea299bSIgor Mammedov     return var;
1220e2ea299bSIgor Mammedov }
1221e2ea299bSIgor Mammedov 
1222214ae59fSIgor Mammedov /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */
aml_field(const char * name,AmlAccessType type,AmlLockRule lock,AmlUpdateRule rule)122336de884aSIgor Mammedov Aml *aml_field(const char *name, AmlAccessType type, AmlLockRule lock,
122436de884aSIgor Mammedov                AmlUpdateRule rule)
1225214ae59fSIgor Mammedov {
1226214ae59fSIgor Mammedov     Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE);
1227af509897SZhu Guihua     uint8_t flags = rule << 5 | type;
1228af509897SZhu Guihua 
122936de884aSIgor Mammedov     flags |= lock << 4; /* LockRule at 4 bit offset */
123036de884aSIgor Mammedov 
1231214ae59fSIgor Mammedov     build_append_namestring(var->buf, "%s", name);
1232214ae59fSIgor Mammedov     build_append_byte(var->buf, flags);
1233214ae59fSIgor Mammedov     return var;
1234214ae59fSIgor Mammedov }
1235b8a5d689SIgor Mammedov 
12367e192a38SIgor Mammedov static
create_field_common(int opcode,Aml * srcbuf,Aml * index,const char * name)12377e192a38SIgor Mammedov Aml *create_field_common(int opcode, Aml *srcbuf, Aml *index, const char *name)
1238ed8176a3SShannon Zhao {
12397e192a38SIgor Mammedov     Aml *var = aml_opcode(opcode);
1240ed8176a3SShannon Zhao     aml_append(var, srcbuf);
1241ed8176a3SShannon Zhao     aml_append(var, index);
1242ed8176a3SShannon Zhao     build_append_namestring(var->buf, "%s", name);
1243ed8176a3SShannon Zhao     return var;
1244ed8176a3SShannon Zhao }
1245ed8176a3SShannon Zhao 
124639b6dbd8SXiao Guangrong /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateField */
aml_create_field(Aml * srcbuf,Aml * bit_index,Aml * num_bits,const char * name)124739b6dbd8SXiao Guangrong Aml *aml_create_field(Aml *srcbuf, Aml *bit_index, Aml *num_bits,
124839b6dbd8SXiao Guangrong                       const char *name)
124939b6dbd8SXiao Guangrong {
125039b6dbd8SXiao Guangrong     Aml *var = aml_alloc();
125139b6dbd8SXiao Guangrong     build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
125239b6dbd8SXiao Guangrong     build_append_byte(var->buf, 0x13); /* CreateFieldOp */
125339b6dbd8SXiao Guangrong     aml_append(var, srcbuf);
125439b6dbd8SXiao Guangrong     aml_append(var, bit_index);
125539b6dbd8SXiao Guangrong     aml_append(var, num_bits);
125639b6dbd8SXiao Guangrong     build_append_namestring(var->buf, "%s", name);
125739b6dbd8SXiao Guangrong     return var;
125839b6dbd8SXiao Guangrong }
125939b6dbd8SXiao Guangrong 
12607e192a38SIgor Mammedov /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateDWordField */
aml_create_dword_field(Aml * srcbuf,Aml * index,const char * name)12617e192a38SIgor Mammedov Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name)
12627e192a38SIgor Mammedov {
12637e192a38SIgor Mammedov     return create_field_common(0x8A /* CreateDWordFieldOp */,
12647e192a38SIgor Mammedov                                srcbuf, index, name);
12657e192a38SIgor Mammedov }
12667e192a38SIgor Mammedov 
12677e192a38SIgor Mammedov /* ACPI 2.0a: 17.2.4.2 Named Objects Encoding: DefCreateQWordField */
aml_create_qword_field(Aml * srcbuf,Aml * index,const char * name)12687e192a38SIgor Mammedov Aml *aml_create_qword_field(Aml *srcbuf, Aml *index, const char *name)
12697e192a38SIgor Mammedov {
12707e192a38SIgor Mammedov     return create_field_common(0x8F /* CreateQWordFieldOp */,
12717e192a38SIgor Mammedov                                srcbuf, index, name);
12727e192a38SIgor Mammedov }
12737e192a38SIgor Mammedov 
1274d5e5830fSIgor Mammedov /* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */
aml_string(const char * name_format,...)1275d5e5830fSIgor Mammedov Aml *aml_string(const char *name_format, ...)
1276d5e5830fSIgor Mammedov {
1277d5e5830fSIgor Mammedov     Aml *var = aml_opcode(0x0D /* StringPrefix */);
1278c3bdc56cSMarkus Armbruster     va_list ap;
1279d5e5830fSIgor Mammedov     char *s;
1280d5e5830fSIgor Mammedov     int len;
1281d5e5830fSIgor Mammedov 
1282d5e5830fSIgor Mammedov     va_start(ap, name_format);
1283c3bdc56cSMarkus Armbruster     len = g_vasprintf(&s, name_format, ap);
1284d5e5830fSIgor Mammedov     va_end(ap);
1285d5e5830fSIgor Mammedov 
1286c3bdc56cSMarkus Armbruster     g_array_append_vals(var->buf, s, len + 1);
1287d5e5830fSIgor Mammedov     g_free(s);
1288d5e5830fSIgor Mammedov 
1289d5e5830fSIgor Mammedov     return var;
1290d5e5830fSIgor Mammedov }
1291d5e5830fSIgor Mammedov 
1292b8a5d689SIgor Mammedov /* ACPI 1.0b: 16.2.6.2 Local Objects Encoding */
aml_local(int num)1293b8a5d689SIgor Mammedov Aml *aml_local(int num)
1294b8a5d689SIgor Mammedov {
1295b8a5d689SIgor Mammedov     uint8_t op = 0x60 /* Local0Op */ + num;
1296b8a5d689SIgor Mammedov 
1297b8a5d689SIgor Mammedov     assert(num <= 7);
12989be38598SEduardo Habkost     return aml_opcode(op);
1299b8a5d689SIgor Mammedov }
1300a678508eSIgor Mammedov 
1301a678508eSIgor Mammedov /* ACPI 2.0a: 17.2.2 Data Objects Encoding: DefVarPackage */
aml_varpackage(uint32_t num_elements)1302a678508eSIgor Mammedov Aml *aml_varpackage(uint32_t num_elements)
1303a678508eSIgor Mammedov {
1304a678508eSIgor Mammedov     Aml *var = aml_bundle(0x13 /* VarPackageOp */, AML_PACKAGE);
1305a678508eSIgor Mammedov     build_append_int(var->buf, num_elements);
1306a678508eSIgor Mammedov     return var;
1307a678508eSIgor Mammedov }
13083dd15643SIgor Mammedov 
13093dd15643SIgor Mammedov /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefProcessor */
aml_processor(uint8_t proc_id,uint32_t pblk_addr,uint8_t pblk_len,const char * name_format,...)13103dd15643SIgor Mammedov Aml *aml_processor(uint8_t proc_id, uint32_t pblk_addr, uint8_t pblk_len,
13113dd15643SIgor Mammedov                    const char *name_format, ...)
13123dd15643SIgor Mammedov {
13133dd15643SIgor Mammedov     va_list ap;
13143dd15643SIgor Mammedov     Aml *var = aml_bundle(0x83 /* ProcessorOp */, AML_EXT_PACKAGE);
13153dd15643SIgor Mammedov     va_start(ap, name_format);
13163dd15643SIgor Mammedov     build_append_namestringv(var->buf, name_format, ap);
13173dd15643SIgor Mammedov     va_end(ap);
13183dd15643SIgor Mammedov     build_append_byte(var->buf, proc_id); /* ProcID */
13193dd15643SIgor Mammedov     build_append_int_noprefix(var->buf, pblk_addr, sizeof(pblk_addr));
13203dd15643SIgor Mammedov     build_append_byte(var->buf, pblk_len); /* PblkLen */
13213dd15643SIgor Mammedov     return var;
13223dd15643SIgor Mammedov }
1323a7891dacSIgor Mammedov 
Hex2Digit(char c)1324a7891dacSIgor Mammedov static uint8_t Hex2Digit(char c)
1325a7891dacSIgor Mammedov {
1326a7891dacSIgor Mammedov     if (c >= 'A') {
1327a7891dacSIgor Mammedov         return c - 'A' + 10;
1328a7891dacSIgor Mammedov     }
1329a7891dacSIgor Mammedov 
1330a7891dacSIgor Mammedov     return c - '0';
1331a7891dacSIgor Mammedov }
1332a7891dacSIgor Mammedov 
1333a7891dacSIgor Mammedov /* ACPI 1.0b: 15.2.3.6.4.1 EISAID Macro - Convert EISA ID String To Integer */
aml_eisaid(const char * str)1334a7891dacSIgor Mammedov Aml *aml_eisaid(const char *str)
1335a7891dacSIgor Mammedov {
1336a7891dacSIgor Mammedov     Aml *var = aml_alloc();
1337a7891dacSIgor Mammedov     uint32_t id;
1338a7891dacSIgor Mammedov 
1339a7891dacSIgor Mammedov     g_assert(strlen(str) == 7);
1340a7891dacSIgor Mammedov     id = (str[0] - 0x40) << 26 |
1341a7891dacSIgor Mammedov     (str[1] - 0x40) << 21 |
1342a7891dacSIgor Mammedov     (str[2] - 0x40) << 16 |
1343a7891dacSIgor Mammedov     Hex2Digit(str[3]) << 12 |
1344a7891dacSIgor Mammedov     Hex2Digit(str[4]) << 8 |
1345a7891dacSIgor Mammedov     Hex2Digit(str[5]) << 4 |
1346a7891dacSIgor Mammedov     Hex2Digit(str[6]);
1347a7891dacSIgor Mammedov 
1348a7891dacSIgor Mammedov     build_append_byte(var->buf, 0x0C); /* DWordPrefix */
1349a7891dacSIgor Mammedov     build_append_int_noprefix(var->buf, bswap32(id), sizeof(id));
1350a7891dacSIgor Mammedov     return var;
1351a7891dacSIgor Mammedov }
13526ece7053SIgor Mammedov 
13536ece7053SIgor Mammedov /* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor: bytes 3-5 */
aml_as_desc_header(AmlResourceType type,AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlDecode dec,uint8_t type_flags)13546ece7053SIgor Mammedov static Aml *aml_as_desc_header(AmlResourceType type, AmlMinFixed min_fixed,
13556ece7053SIgor Mammedov                                AmlMaxFixed max_fixed, AmlDecode dec,
13566ece7053SIgor Mammedov                                uint8_t type_flags)
13576ece7053SIgor Mammedov {
13586ece7053SIgor Mammedov     uint8_t flags = max_fixed | min_fixed | dec;
13596ece7053SIgor Mammedov     Aml *var = aml_alloc();
13606ece7053SIgor Mammedov 
13616ece7053SIgor Mammedov     build_append_byte(var->buf, type);
13626ece7053SIgor Mammedov     build_append_byte(var->buf, flags);
13636ece7053SIgor Mammedov     build_append_byte(var->buf, type_flags); /* Type Specific Flags */
13646ece7053SIgor Mammedov     return var;
13656ece7053SIgor Mammedov }
13666ece7053SIgor Mammedov 
13676ece7053SIgor Mammedov /* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor */
aml_word_as_desc(AmlResourceType type,AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlDecode dec,uint16_t addr_gran,uint16_t addr_min,uint16_t addr_max,uint16_t addr_trans,uint16_t len,uint8_t type_flags)13686ece7053SIgor Mammedov static Aml *aml_word_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
13696ece7053SIgor Mammedov                              AmlMaxFixed max_fixed, AmlDecode dec,
13706ece7053SIgor Mammedov                              uint16_t addr_gran, uint16_t addr_min,
13716ece7053SIgor Mammedov                              uint16_t addr_max, uint16_t addr_trans,
13726ece7053SIgor Mammedov                              uint16_t len, uint8_t type_flags)
13736ece7053SIgor Mammedov {
13746ece7053SIgor Mammedov     Aml *var = aml_alloc();
13756ece7053SIgor Mammedov 
13766ece7053SIgor Mammedov     build_append_byte(var->buf, 0x88); /* Word Address Space Descriptor */
13776ece7053SIgor Mammedov     /* minimum length since we do not encode optional fields */
13786ece7053SIgor Mammedov     build_append_byte(var->buf, 0x0D);
13796ece7053SIgor Mammedov     build_append_byte(var->buf, 0x0);
13806ece7053SIgor Mammedov 
13816ece7053SIgor Mammedov     aml_append(var,
13826ece7053SIgor Mammedov         aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
13836ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
13846ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
13856ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
13866ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
13876ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, len, sizeof(len));
13886ece7053SIgor Mammedov     return var;
13896ece7053SIgor Mammedov }
13906ece7053SIgor Mammedov 
13916ece7053SIgor Mammedov /* ACPI 1.0b: 6.4.3.5.3 DWord Address Space Descriptor */
aml_dword_as_desc(AmlResourceType type,AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlDecode dec,uint32_t addr_gran,uint32_t addr_min,uint32_t addr_max,uint32_t addr_trans,uint32_t len,uint8_t type_flags)13926ece7053SIgor Mammedov static Aml *aml_dword_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
13936ece7053SIgor Mammedov                               AmlMaxFixed max_fixed, AmlDecode dec,
13946ece7053SIgor Mammedov                               uint32_t addr_gran, uint32_t addr_min,
13956ece7053SIgor Mammedov                               uint32_t addr_max, uint32_t addr_trans,
13966ece7053SIgor Mammedov                               uint32_t len, uint8_t type_flags)
13976ece7053SIgor Mammedov {
13986ece7053SIgor Mammedov     Aml *var = aml_alloc();
13996ece7053SIgor Mammedov 
14006ece7053SIgor Mammedov     build_append_byte(var->buf, 0x87); /* DWord Address Space Descriptor */
14016ece7053SIgor Mammedov     /* minimum length since we do not encode optional fields */
14026ece7053SIgor Mammedov     build_append_byte(var->buf, 23);
14036ece7053SIgor Mammedov     build_append_byte(var->buf, 0x0);
14046ece7053SIgor Mammedov 
14056ece7053SIgor Mammedov 
14066ece7053SIgor Mammedov     aml_append(var,
14076ece7053SIgor Mammedov         aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
14086ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
14096ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
14106ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
14116ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
14126ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, len, sizeof(len));
14136ece7053SIgor Mammedov     return var;
14146ece7053SIgor Mammedov }
14156ece7053SIgor Mammedov 
14166ece7053SIgor Mammedov /* ACPI 1.0b: 6.4.3.5.1 QWord Address Space Descriptor */
aml_qword_as_desc(AmlResourceType type,AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlDecode dec,uint64_t addr_gran,uint64_t addr_min,uint64_t addr_max,uint64_t addr_trans,uint64_t len,uint8_t type_flags)14176ece7053SIgor Mammedov static Aml *aml_qword_as_desc(AmlResourceType type, AmlMinFixed min_fixed,
14186ece7053SIgor Mammedov                               AmlMaxFixed max_fixed, AmlDecode dec,
14196ece7053SIgor Mammedov                               uint64_t addr_gran, uint64_t addr_min,
14206ece7053SIgor Mammedov                               uint64_t addr_max, uint64_t addr_trans,
14216ece7053SIgor Mammedov                               uint64_t len, uint8_t type_flags)
14226ece7053SIgor Mammedov {
14236ece7053SIgor Mammedov     Aml *var = aml_alloc();
14246ece7053SIgor Mammedov 
14256ece7053SIgor Mammedov     build_append_byte(var->buf, 0x8A); /* QWord Address Space Descriptor */
14266ece7053SIgor Mammedov     /* minimum length since we do not encode optional fields */
14276ece7053SIgor Mammedov     build_append_byte(var->buf, 0x2B);
14286ece7053SIgor Mammedov     build_append_byte(var->buf, 0x0);
14296ece7053SIgor Mammedov 
14306ece7053SIgor Mammedov     aml_append(var,
14316ece7053SIgor Mammedov         aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags));
14326ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran));
14336ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min));
14346ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max));
14356ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans));
14366ece7053SIgor Mammedov     build_append_int_noprefix(var->buf, len, sizeof(len));
14376ece7053SIgor Mammedov     return var;
14386ece7053SIgor Mammedov }
14396ece7053SIgor Mammedov 
14406ece7053SIgor Mammedov /*
14416ece7053SIgor Mammedov  * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor
14426ece7053SIgor Mammedov  *
14436ece7053SIgor Mammedov  * More verbose description at:
14446ece7053SIgor Mammedov  * ACPI 5.0: 19.5.141 WordBusNumber (Word Bus Number Resource Descriptor Macro)
14456ece7053SIgor Mammedov  */
aml_word_bus_number(AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlDecode dec,uint16_t addr_gran,uint16_t addr_min,uint16_t addr_max,uint16_t addr_trans,uint16_t len)14466ece7053SIgor Mammedov Aml *aml_word_bus_number(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
14476ece7053SIgor Mammedov                          AmlDecode dec, uint16_t addr_gran,
14486ece7053SIgor Mammedov                          uint16_t addr_min, uint16_t addr_max,
14496ece7053SIgor Mammedov                          uint16_t addr_trans, uint16_t len)
14506ece7053SIgor Mammedov 
14516ece7053SIgor Mammedov {
1452ff80dc7fSShannon Zhao     return aml_word_as_desc(AML_BUS_NUMBER_RANGE, min_fixed, max_fixed, dec,
14536ece7053SIgor Mammedov                             addr_gran, addr_min, addr_max, addr_trans, len, 0);
14546ece7053SIgor Mammedov }
14556ece7053SIgor Mammedov 
14566ece7053SIgor Mammedov /*
14576ece7053SIgor Mammedov  * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor
14586ece7053SIgor Mammedov  *
14596ece7053SIgor Mammedov  * More verbose description at:
14606ece7053SIgor Mammedov  * ACPI 5.0: 19.5.142 WordIO (Word IO Resource Descriptor Macro)
14616ece7053SIgor Mammedov  */
aml_word_io(AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlDecode dec,AmlISARanges isa_ranges,uint16_t addr_gran,uint16_t addr_min,uint16_t addr_max,uint16_t addr_trans,uint16_t len)14626ece7053SIgor Mammedov Aml *aml_word_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
14636ece7053SIgor Mammedov                  AmlDecode dec, AmlISARanges isa_ranges,
14646ece7053SIgor Mammedov                  uint16_t addr_gran, uint16_t addr_min,
14656ece7053SIgor Mammedov                  uint16_t addr_max, uint16_t addr_trans,
14666ece7053SIgor Mammedov                  uint16_t len)
14676ece7053SIgor Mammedov 
14686ece7053SIgor Mammedov {
1469ff80dc7fSShannon Zhao     return aml_word_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec,
14706ece7053SIgor Mammedov                             addr_gran, addr_min, addr_max, addr_trans, len,
14716ece7053SIgor Mammedov                             isa_ranges);
14726ece7053SIgor Mammedov }
14736ece7053SIgor Mammedov 
14746ece7053SIgor Mammedov /*
1475616ef329SShannon Zhao  * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Descriptor
1476616ef329SShannon Zhao  *
1477616ef329SShannon Zhao  * More verbose description at:
1478616ef329SShannon Zhao  * ACPI 5.0: 19.5.33 DWordIO (DWord IO Resource Descriptor Macro)
1479616ef329SShannon Zhao  */
aml_dword_io(AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlDecode dec,AmlISARanges isa_ranges,uint32_t addr_gran,uint32_t addr_min,uint32_t addr_max,uint32_t addr_trans,uint32_t len)1480616ef329SShannon Zhao Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
1481616ef329SShannon Zhao                  AmlDecode dec, AmlISARanges isa_ranges,
1482616ef329SShannon Zhao                  uint32_t addr_gran, uint32_t addr_min,
1483616ef329SShannon Zhao                  uint32_t addr_max, uint32_t addr_trans,
1484616ef329SShannon Zhao                  uint32_t len)
1485616ef329SShannon Zhao 
1486616ef329SShannon Zhao {
1487616ef329SShannon Zhao     return aml_dword_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec,
1488616ef329SShannon Zhao                             addr_gran, addr_min, addr_max, addr_trans, len,
1489616ef329SShannon Zhao                             isa_ranges);
1490616ef329SShannon Zhao }
1491616ef329SShannon Zhao 
1492616ef329SShannon Zhao /*
14936ece7053SIgor Mammedov  * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Space Descriptor
14946ece7053SIgor Mammedov  *
14956ece7053SIgor Mammedov  * More verbose description at:
14966ece7053SIgor Mammedov  * ACPI 5.0: 19.5.34 DWordMemory (DWord Memory Resource Descriptor Macro)
14976ece7053SIgor Mammedov  */
aml_dword_memory(AmlDecode dec,AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlCacheable cacheable,AmlReadAndWrite read_and_write,uint32_t addr_gran,uint32_t addr_min,uint32_t addr_max,uint32_t addr_trans,uint32_t len)14986ece7053SIgor Mammedov Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
1499ff80dc7fSShannon Zhao                       AmlMaxFixed max_fixed, AmlCacheable cacheable,
15006ece7053SIgor Mammedov                       AmlReadAndWrite read_and_write,
15016ece7053SIgor Mammedov                       uint32_t addr_gran, uint32_t addr_min,
15026ece7053SIgor Mammedov                       uint32_t addr_max, uint32_t addr_trans,
15036ece7053SIgor Mammedov                       uint32_t len)
15046ece7053SIgor Mammedov {
15056ece7053SIgor Mammedov     uint8_t flags = read_and_write | (cacheable << 1);
15066ece7053SIgor Mammedov 
1507ff80dc7fSShannon Zhao     return aml_dword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed,
15086ece7053SIgor Mammedov                              dec, addr_gran, addr_min, addr_max,
15096ece7053SIgor Mammedov                              addr_trans, len, flags);
15106ece7053SIgor Mammedov }
15116ece7053SIgor Mammedov 
15126ece7053SIgor Mammedov /*
15136ece7053SIgor Mammedov  * ACPI 1.0b: 6.4.3.5.2 ASL Macros for QWORD Address Space Descriptor
15146ece7053SIgor Mammedov  *
15156ece7053SIgor Mammedov  * More verbose description at:
15166ece7053SIgor Mammedov  * ACPI 5.0: 19.5.102 QWordMemory (QWord Memory Resource Descriptor Macro)
15176ece7053SIgor Mammedov  */
aml_qword_memory(AmlDecode dec,AmlMinFixed min_fixed,AmlMaxFixed max_fixed,AmlCacheable cacheable,AmlReadAndWrite read_and_write,uint64_t addr_gran,uint64_t addr_min,uint64_t addr_max,uint64_t addr_trans,uint64_t len)15186ece7053SIgor Mammedov Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
1519ff80dc7fSShannon Zhao                       AmlMaxFixed max_fixed, AmlCacheable cacheable,
15206ece7053SIgor Mammedov                       AmlReadAndWrite read_and_write,
15216ece7053SIgor Mammedov                       uint64_t addr_gran, uint64_t addr_min,
15226ece7053SIgor Mammedov                       uint64_t addr_max, uint64_t addr_trans,
15236ece7053SIgor Mammedov                       uint64_t len)
15246ece7053SIgor Mammedov {
15256ece7053SIgor Mammedov     uint8_t flags = read_and_write | (cacheable << 1);
15266ece7053SIgor Mammedov 
1527ff80dc7fSShannon Zhao     return aml_qword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed,
15286ece7053SIgor Mammedov                              dec, addr_gran, addr_min, addr_max,
15296ece7053SIgor Mammedov                              addr_trans, len, flags);
15306ece7053SIgor Mammedov }
1531658c2718SShannon Zhao 
1532a23b8872SIgor Mammedov /* ACPI 1.0b: 6.4.2.2 DMA Format/6.4.2.2.1 ASL Macro for DMA Descriptor */
aml_dma(AmlDmaType typ,AmlDmaBusMaster bm,AmlTransferSize sz,uint8_t channel)1533a23b8872SIgor Mammedov Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz,
1534a23b8872SIgor Mammedov              uint8_t channel)
1535a23b8872SIgor Mammedov {
1536a23b8872SIgor Mammedov     Aml *var = aml_alloc();
1537a23b8872SIgor Mammedov     uint8_t flags = sz | bm << 2 | typ << 5;
1538a23b8872SIgor Mammedov 
1539a23b8872SIgor Mammedov     assert(channel < 8);
1540a23b8872SIgor Mammedov     build_append_byte(var->buf, 0x2A);    /* Byte 0: DMA Descriptor */
1541a23b8872SIgor Mammedov     build_append_byte(var->buf, 1U << channel); /* Byte 1: _DMA - DmaChannel */
1542a23b8872SIgor Mammedov     build_append_byte(var->buf, flags);   /* Byte 2 */
1543a23b8872SIgor Mammedov     return var;
1544a23b8872SIgor Mammedov }
1545a23b8872SIgor Mammedov 
15460073518dSIgor Mammedov /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefSleep */
aml_sleep(uint64_t msec)15470073518dSIgor Mammedov Aml *aml_sleep(uint64_t msec)
15480073518dSIgor Mammedov {
15490073518dSIgor Mammedov     Aml *var = aml_alloc();
15500073518dSIgor Mammedov     build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
15510073518dSIgor Mammedov     build_append_byte(var->buf, 0x22); /* SleepOp */
15520073518dSIgor Mammedov     aml_append(var, aml_int(msec));
15530073518dSIgor Mammedov     return var;
15540073518dSIgor Mammedov }
15550073518dSIgor Mammedov 
Hex2Byte(const char * src)1556b930fb9dSShannon Zhao static uint8_t Hex2Byte(const char *src)
1557b930fb9dSShannon Zhao {
1558b930fb9dSShannon Zhao     int hi, lo;
1559b930fb9dSShannon Zhao 
1560b930fb9dSShannon Zhao     hi = Hex2Digit(src[0]);
1561b930fb9dSShannon Zhao     assert(hi >= 0);
1562b930fb9dSShannon Zhao     assert(hi <= 15);
1563b930fb9dSShannon Zhao 
1564b930fb9dSShannon Zhao     lo = Hex2Digit(src[1]);
1565b930fb9dSShannon Zhao     assert(lo >= 0);
1566b930fb9dSShannon Zhao     assert(lo <= 15);
1567b930fb9dSShannon Zhao     return (hi << 4) | lo;
1568b930fb9dSShannon Zhao }
1569b930fb9dSShannon Zhao 
1570b930fb9dSShannon Zhao /*
1571b930fb9dSShannon Zhao  * ACPI 3.0: 17.5.124 ToUUID (Convert String to UUID Macro)
1572b930fb9dSShannon Zhao  * e.g. UUID: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
1573b930fb9dSShannon Zhao  * call aml_touuid("aabbccdd-eeff-gghh-iijj-kkllmmnnoopp");
1574b930fb9dSShannon Zhao  */
aml_touuid(const char * uuid)1575b930fb9dSShannon Zhao Aml *aml_touuid(const char *uuid)
1576b930fb9dSShannon Zhao {
1577b930fb9dSShannon Zhao     Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
1578b930fb9dSShannon Zhao 
1579b930fb9dSShannon Zhao     assert(strlen(uuid) == 36);
1580b930fb9dSShannon Zhao     assert(uuid[8] == '-');
1581b930fb9dSShannon Zhao     assert(uuid[13] == '-');
1582b930fb9dSShannon Zhao     assert(uuid[18] == '-');
1583b930fb9dSShannon Zhao     assert(uuid[23] == '-');
1584b930fb9dSShannon Zhao 
1585b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 6));  /* dd - at offset 00 */
1586b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 4));  /* cc - at offset 01 */
1587b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 2));  /* bb - at offset 02 */
1588b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 0));  /* aa - at offset 03 */
1589b930fb9dSShannon Zhao 
1590b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 11)); /* ff - at offset 04 */
1591b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 9));  /* ee - at offset 05 */
1592b930fb9dSShannon Zhao 
1593b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 16)); /* hh - at offset 06 */
1594b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 14)); /* gg - at offset 07 */
1595b930fb9dSShannon Zhao 
1596b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 19)); /* ii - at offset 08 */
1597b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 21)); /* jj - at offset 09 */
1598b930fb9dSShannon Zhao 
1599b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 24)); /* kk - at offset 10 */
1600b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 26)); /* ll - at offset 11 */
1601b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 28)); /* mm - at offset 12 */
1602b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 30)); /* nn - at offset 13 */
1603b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 32)); /* oo - at offset 14 */
1604b930fb9dSShannon Zhao     build_append_byte(var->buf, Hex2Byte(uuid + 34)); /* pp - at offset 15 */
1605b930fb9dSShannon Zhao 
1606b930fb9dSShannon Zhao     return var;
1607b930fb9dSShannon Zhao }
1608b930fb9dSShannon Zhao 
1609e1f776c4SShannon Zhao /*
1610e1f776c4SShannon Zhao  * ACPI 2.0b: 16.2.3.6.4.3  Unicode Macro (Convert Ascii String To Unicode)
1611e1f776c4SShannon Zhao  */
aml_unicode(const char * str)1612e1f776c4SShannon Zhao Aml *aml_unicode(const char *str)
1613e1f776c4SShannon Zhao {
1614e1f776c4SShannon Zhao     int i = 0;
1615e1f776c4SShannon Zhao     Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
1616e1f776c4SShannon Zhao 
1617e1f776c4SShannon Zhao     do {
1618e1f776c4SShannon Zhao         build_append_byte(var->buf, str[i]);
1619e1f776c4SShannon Zhao         build_append_byte(var->buf, 0);
1620e1f776c4SShannon Zhao         i++;
1621e1f776c4SShannon Zhao     } while (i <= strlen(str));
1622e1f776c4SShannon Zhao 
1623e1f776c4SShannon Zhao     return var;
1624e1f776c4SShannon Zhao }
1625e1f776c4SShannon Zhao 
16267bc6fd24SIgor Mammedov /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefRefOf */
aml_refof(Aml * arg)16277bc6fd24SIgor Mammedov Aml *aml_refof(Aml *arg)
16287bc6fd24SIgor Mammedov {
16297bc6fd24SIgor Mammedov     Aml *var = aml_opcode(0x71 /* RefOfOp */);
16307bc6fd24SIgor Mammedov     aml_append(var, arg);
16317bc6fd24SIgor Mammedov     return var;
16327bc6fd24SIgor Mammedov }
16337bc6fd24SIgor Mammedov 
163495cb0661SXiao Guangrong /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDerefOf */
aml_derefof(Aml * arg)163595cb0661SXiao Guangrong Aml *aml_derefof(Aml *arg)
163695cb0661SXiao Guangrong {
163795cb0661SXiao Guangrong     Aml *var = aml_opcode(0x83 /* DerefOfOp */);
163895cb0661SXiao Guangrong     aml_append(var, arg);
163995cb0661SXiao Guangrong     return var;
164095cb0661SXiao Guangrong }
164195cb0661SXiao Guangrong 
164252483d14SXiao Guangrong /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSizeOf */
aml_sizeof(Aml * arg)164352483d14SXiao Guangrong Aml *aml_sizeof(Aml *arg)
164452483d14SXiao Guangrong {
164552483d14SXiao Guangrong     Aml *var = aml_opcode(0x87 /* SizeOfOp */);
164652483d14SXiao Guangrong     aml_append(var, arg);
164752483d14SXiao Guangrong     return var;
164852483d14SXiao Guangrong }
164952483d14SXiao Guangrong 
16506e1db3f2SXiao Guangrong /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMutex */
aml_mutex(const char * name,uint8_t sync_level)16516e1db3f2SXiao Guangrong Aml *aml_mutex(const char *name, uint8_t sync_level)
16526e1db3f2SXiao Guangrong {
16536e1db3f2SXiao Guangrong     Aml *var = aml_alloc();
16546e1db3f2SXiao Guangrong     build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
16556e1db3f2SXiao Guangrong     build_append_byte(var->buf, 0x01); /* MutexOp */
16566e1db3f2SXiao Guangrong     build_append_namestring(var->buf, "%s", name);
16576e1db3f2SXiao Guangrong     assert(!(sync_level & 0xF0));
16586e1db3f2SXiao Guangrong     build_append_byte(var->buf, sync_level);
16596e1db3f2SXiao Guangrong     return var;
16606e1db3f2SXiao Guangrong }
16616e1db3f2SXiao Guangrong 
16626e1db3f2SXiao Guangrong /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAcquire */
aml_acquire(Aml * mutex,uint16_t timeout)16636e1db3f2SXiao Guangrong Aml *aml_acquire(Aml *mutex, uint16_t timeout)
16646e1db3f2SXiao Guangrong {
16656e1db3f2SXiao Guangrong     Aml *var = aml_alloc();
16666e1db3f2SXiao Guangrong     build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
16676e1db3f2SXiao Guangrong     build_append_byte(var->buf, 0x23); /* AcquireOp */
16686e1db3f2SXiao Guangrong     aml_append(var, mutex);
16696e1db3f2SXiao Guangrong     build_append_int_noprefix(var->buf, timeout, sizeof(timeout));
16706e1db3f2SXiao Guangrong     return var;
16716e1db3f2SXiao Guangrong }
16726e1db3f2SXiao Guangrong 
16736e1db3f2SXiao Guangrong /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefRelease */
aml_release(Aml * mutex)16746e1db3f2SXiao Guangrong Aml *aml_release(Aml *mutex)
16756e1db3f2SXiao Guangrong {
16766e1db3f2SXiao Guangrong     Aml *var = aml_alloc();
16776e1db3f2SXiao Guangrong     build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
16786e1db3f2SXiao Guangrong     build_append_byte(var->buf, 0x27); /* ReleaseOp */
16796e1db3f2SXiao Guangrong     aml_append(var, mutex);
16806e1db3f2SXiao Guangrong     return var;
16816e1db3f2SXiao Guangrong }
16826e1db3f2SXiao Guangrong 
168367a5c0faSIgor Mammedov /* ACPI 1.0b: 16.2.5.1 Name Space Modifier Objects Encoding: DefAlias */
aml_alias(const char * source_object,const char * alias_object)168467a5c0faSIgor Mammedov Aml *aml_alias(const char *source_object, const char *alias_object)
168567a5c0faSIgor Mammedov {
168667a5c0faSIgor Mammedov     Aml *var = aml_opcode(0x06 /* AliasOp */);
168767a5c0faSIgor Mammedov     aml_append(var, aml_name("%s", source_object));
168867a5c0faSIgor Mammedov     aml_append(var, aml_name("%s", alias_object));
168967a5c0faSIgor Mammedov     return var;
169067a5c0faSIgor Mammedov }
169167a5c0faSIgor Mammedov 
16929815cba5SXiao Guangrong /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefConcat */
aml_concatenate(Aml * source1,Aml * source2,Aml * target)16939815cba5SXiao Guangrong Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target)
16949815cba5SXiao Guangrong {
16959815cba5SXiao Guangrong     return build_opcode_2arg_dst(0x73 /* ConcatOp */, source1, source2,
16969815cba5SXiao Guangrong                                  target);
16979815cba5SXiao Guangrong }
16989815cba5SXiao Guangrong 
1699b265f27cSXiao Guangrong /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefObjectType */
aml_object_type(Aml * object)1700b265f27cSXiao Guangrong Aml *aml_object_type(Aml *object)
1701b265f27cSXiao Guangrong {
1702b265f27cSXiao Guangrong     Aml *var = aml_opcode(0x8E /* ObjectTypeOp */);
1703b265f27cSXiao Guangrong     aml_append(var, object);
1704b265f27cSXiao Guangrong     return var;
1705b265f27cSXiao Guangrong }
1706b265f27cSXiao Guangrong 
acpi_table_begin(AcpiTable * desc,GArray * array)1707c151fd87SIgor Mammedov void acpi_table_begin(AcpiTable *desc, GArray *array)
1708c151fd87SIgor Mammedov {
1709c151fd87SIgor Mammedov 
1710c151fd87SIgor Mammedov     desc->array = array;
1711c151fd87SIgor Mammedov     desc->table_offset = array->len;
1712c151fd87SIgor Mammedov 
1713c151fd87SIgor Mammedov     /*
1714c151fd87SIgor Mammedov      * ACPI spec 1.0b
1715c151fd87SIgor Mammedov      * 5.2.3 System Description Table Header
1716c151fd87SIgor Mammedov      */
1717c151fd87SIgor Mammedov     g_assert(strlen(desc->sig) == 4);
1718c151fd87SIgor Mammedov     g_array_append_vals(array, desc->sig, 4); /* Signature */
1719c151fd87SIgor Mammedov     /*
1720c151fd87SIgor Mammedov      * reserve space for Length field, which will be patched by
1721c151fd87SIgor Mammedov      * acpi_table_end() when the table creation is finished.
1722c151fd87SIgor Mammedov      */
1723c151fd87SIgor Mammedov     build_append_int_noprefix(array, 0, 4); /* Length */
1724c151fd87SIgor Mammedov     build_append_int_noprefix(array, desc->rev, 1); /* Revision */
1725c151fd87SIgor Mammedov     build_append_int_noprefix(array, 0, 1); /* Checksum */
1726748c030fSIgor Mammedov     build_append_padded_str(array, desc->oem_id, 6, '\0'); /* OEMID */
1727c151fd87SIgor Mammedov     /* OEM Table ID */
1728748c030fSIgor Mammedov     build_append_padded_str(array, desc->oem_table_id, 8, '\0');
1729c151fd87SIgor Mammedov     build_append_int_noprefix(array, 1, 4); /* OEM Revision */
1730c151fd87SIgor Mammedov     g_array_append_vals(array, ACPI_BUILD_APPNAME8, 4); /* Creator ID */
1731c151fd87SIgor Mammedov     build_append_int_noprefix(array, 1, 4); /* Creator Revision */
1732c151fd87SIgor Mammedov }
1733c151fd87SIgor Mammedov 
acpi_table_end(BIOSLinker * linker,AcpiTable * desc)1734c151fd87SIgor Mammedov void acpi_table_end(BIOSLinker *linker, AcpiTable *desc)
1735c151fd87SIgor Mammedov {
1736c151fd87SIgor Mammedov     /*
1737c151fd87SIgor Mammedov      * ACPI spec 1.0b
1738c151fd87SIgor Mammedov      * 5.2.3 System Description Table Header
1739c151fd87SIgor Mammedov      * Table 5-2 DESCRIPTION_HEADER Fields
1740c151fd87SIgor Mammedov      */
1741c151fd87SIgor Mammedov     const unsigned checksum_offset = 9;
1742c151fd87SIgor Mammedov     uint32_t table_len = desc->array->len - desc->table_offset;
1743c151fd87SIgor Mammedov     uint32_t table_len_le = cpu_to_le32(table_len);
1744c151fd87SIgor Mammedov     gchar *len_ptr = &desc->array->data[desc->table_offset + 4];
1745c151fd87SIgor Mammedov 
1746c151fd87SIgor Mammedov     /* patch "Length" field that has been reserved by acpi_table_begin()
1747c151fd87SIgor Mammedov      * to the actual length, i.e. accumulated table length from
1748c151fd87SIgor Mammedov      * acpi_table_begin() till acpi_table_end()
1749c151fd87SIgor Mammedov      */
1750c151fd87SIgor Mammedov     memcpy(len_ptr, &table_len_le, sizeof table_len_le);
1751c151fd87SIgor Mammedov 
1752c151fd87SIgor Mammedov     bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
1753c151fd87SIgor Mammedov         desc->table_offset, table_len, desc->table_offset + checksum_offset);
1754c151fd87SIgor Mammedov }
1755c151fd87SIgor Mammedov 
acpi_data_push(GArray * table_data,unsigned size)1756658c2718SShannon Zhao void *acpi_data_push(GArray *table_data, unsigned size)
1757658c2718SShannon Zhao {
1758658c2718SShannon Zhao     unsigned off = table_data->len;
1759658c2718SShannon Zhao     g_array_set_size(table_data, off + size);
1760658c2718SShannon Zhao     return table_data->data + off;
1761658c2718SShannon Zhao }
1762658c2718SShannon Zhao 
acpi_data_len(GArray * table)1763658c2718SShannon Zhao unsigned acpi_data_len(GArray *table)
1764658c2718SShannon Zhao {
1765658c2718SShannon Zhao     assert(g_array_get_element_size(table) == 1);
1766658c2718SShannon Zhao     return table->len;
1767658c2718SShannon Zhao }
1768658c2718SShannon Zhao 
acpi_add_table(GArray * table_offsets,GArray * table_data)1769658c2718SShannon Zhao void acpi_add_table(GArray *table_offsets, GArray *table_data)
1770658c2718SShannon Zhao {
17714678124bSIgor Mammedov     uint32_t offset = table_data->len;
1772658c2718SShannon Zhao     g_array_append_val(table_offsets, offset);
1773658c2718SShannon Zhao }
1774658c2718SShannon Zhao 
acpi_build_tables_init(AcpiBuildTables * tables)1775658c2718SShannon Zhao void acpi_build_tables_init(AcpiBuildTables *tables)
1776658c2718SShannon Zhao {
1777658c2718SShannon Zhao     tables->rsdp = g_array_new(false, true /* clear */, 1);
1778658c2718SShannon Zhao     tables->table_data = g_array_new(false, true /* clear */, 1);
1779658c2718SShannon Zhao     tables->tcpalog = g_array_new(false, true /* clear */, 1);
1780c7809e6cSBen Warren     tables->vmgenid = g_array_new(false, true /* clear */, 1);
1781aa16508fSDongjiu Geng     tables->hardware_errors = g_array_new(false, true /* clear */, 1);
1782658c2718SShannon Zhao     tables->linker = bios_linker_loader_init();
1783658c2718SShannon Zhao }
1784658c2718SShannon Zhao 
acpi_build_tables_cleanup(AcpiBuildTables * tables,bool mfre)1785658c2718SShannon Zhao void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
1786658c2718SShannon Zhao {
17878cc87c31SIgor Mammedov     bios_linker_loader_cleanup(tables->linker);
1788658c2718SShannon Zhao     g_array_free(tables->rsdp, true);
1789658c2718SShannon Zhao     g_array_free(tables->table_data, true);
1790658c2718SShannon Zhao     g_array_free(tables->tcpalog, mfre);
1791c7809e6cSBen Warren     g_array_free(tables->vmgenid, mfre);
1792aa16508fSDongjiu Geng     g_array_free(tables->hardware_errors, mfre);
1793658c2718SShannon Zhao }
1794243bdb79SShannon Zhao 
1795a46ce1c2SSamuel Ortiz /*
1796a46ce1c2SSamuel Ortiz  * ACPI spec 5.2.5.3 Root System Description Pointer (RSDP).
1797a46ce1c2SSamuel Ortiz  * (Revision 1.0 or later)
1798a46ce1c2SSamuel Ortiz  */
1799a46ce1c2SSamuel Ortiz void
build_rsdp(GArray * tbl,BIOSLinker * linker,AcpiRsdpData * rsdp_data)1800a46ce1c2SSamuel Ortiz build_rsdp(GArray *tbl, BIOSLinker *linker, AcpiRsdpData *rsdp_data)
1801a46ce1c2SSamuel Ortiz {
1802a46ce1c2SSamuel Ortiz     int tbl_off = tbl->len; /* Table offset in the RSDP file */
1803a46ce1c2SSamuel Ortiz 
1804a46ce1c2SSamuel Ortiz     switch (rsdp_data->revision) {
1805a46ce1c2SSamuel Ortiz     case 0:
1806a46ce1c2SSamuel Ortiz         /* With ACPI 1.0, we must have an RSDT pointer */
1807a46ce1c2SSamuel Ortiz         g_assert(rsdp_data->rsdt_tbl_offset);
1808a46ce1c2SSamuel Ortiz         break;
1809a46ce1c2SSamuel Ortiz     case 2:
1810a46ce1c2SSamuel Ortiz         /* With ACPI 2.0+, we must have an XSDT pointer */
1811a46ce1c2SSamuel Ortiz         g_assert(rsdp_data->xsdt_tbl_offset);
1812a46ce1c2SSamuel Ortiz         break;
1813a46ce1c2SSamuel Ortiz     default:
1814a46ce1c2SSamuel Ortiz         /* Only revisions 0 (ACPI 1.0) and 2 (ACPI 2.0+) are valid for RSDP */
1815a46ce1c2SSamuel Ortiz         g_assert_not_reached();
1816a46ce1c2SSamuel Ortiz     }
1817a46ce1c2SSamuel Ortiz 
1818a46ce1c2SSamuel Ortiz     bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, tbl, 16,
1819a46ce1c2SSamuel Ortiz                              true /* fseg memory */);
1820a46ce1c2SSamuel Ortiz 
1821a46ce1c2SSamuel Ortiz     g_array_append_vals(tbl, "RSD PTR ", 8); /* Signature */
1822a46ce1c2SSamuel Ortiz     build_append_int_noprefix(tbl, 0, 1); /* Checksum */
1823a46ce1c2SSamuel Ortiz     g_array_append_vals(tbl, rsdp_data->oem_id, 6); /* OEMID */
1824a46ce1c2SSamuel Ortiz     build_append_int_noprefix(tbl, rsdp_data->revision, 1); /* Revision */
1825a46ce1c2SSamuel Ortiz     build_append_int_noprefix(tbl, 0, 4); /* RsdtAddress */
1826a46ce1c2SSamuel Ortiz     if (rsdp_data->rsdt_tbl_offset) {
1827a46ce1c2SSamuel Ortiz         /* RSDT address to be filled by guest linker */
1828a46ce1c2SSamuel Ortiz         bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
1829a46ce1c2SSamuel Ortiz                                        tbl_off + 16, 4,
1830a46ce1c2SSamuel Ortiz                                        ACPI_BUILD_TABLE_FILE,
1831a46ce1c2SSamuel Ortiz                                        *rsdp_data->rsdt_tbl_offset);
1832a46ce1c2SSamuel Ortiz     }
1833a46ce1c2SSamuel Ortiz 
1834a46ce1c2SSamuel Ortiz     /* Checksum to be filled by guest linker */
1835a46ce1c2SSamuel Ortiz     bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
1836a46ce1c2SSamuel Ortiz                                     tbl_off, 20, /* ACPI rev 1.0 RSDP size */
1837a46ce1c2SSamuel Ortiz                                     8);
1838a46ce1c2SSamuel Ortiz 
1839a46ce1c2SSamuel Ortiz     if (rsdp_data->revision == 0) {
1840a46ce1c2SSamuel Ortiz         /* ACPI 1.0 RSDP, we're done */
1841a46ce1c2SSamuel Ortiz         return;
1842a46ce1c2SSamuel Ortiz     }
1843a46ce1c2SSamuel Ortiz 
1844a46ce1c2SSamuel Ortiz     build_append_int_noprefix(tbl, 36, 4); /* Length */
1845a46ce1c2SSamuel Ortiz 
1846a46ce1c2SSamuel Ortiz     /* XSDT address to be filled by guest linker */
1847a46ce1c2SSamuel Ortiz     build_append_int_noprefix(tbl, 0, 8); /* XsdtAddress */
1848a46ce1c2SSamuel Ortiz     /* We already validated our xsdt pointer */
1849a46ce1c2SSamuel Ortiz     bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
1850a46ce1c2SSamuel Ortiz                                    tbl_off + 24, 8,
1851a46ce1c2SSamuel Ortiz                                    ACPI_BUILD_TABLE_FILE,
1852a46ce1c2SSamuel Ortiz                                    *rsdp_data->xsdt_tbl_offset);
1853a46ce1c2SSamuel Ortiz 
1854a46ce1c2SSamuel Ortiz     build_append_int_noprefix(tbl, 0, 1); /* Extended Checksum */
1855a46ce1c2SSamuel Ortiz     build_append_int_noprefix(tbl, 0, 3); /* Reserved */
1856a46ce1c2SSamuel Ortiz 
1857a46ce1c2SSamuel Ortiz     /* Extended checksum to be filled by Guest linker */
1858a46ce1c2SSamuel Ortiz     bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
1859a46ce1c2SSamuel Ortiz                                     tbl_off, 36, /* ACPI rev 2.0 RSDP size */
1860a46ce1c2SSamuel Ortiz                                     32);
1861a46ce1c2SSamuel Ortiz }
1862a46ce1c2SSamuel Ortiz 
1863ea298e83SIgor Mammedov /*
1864ea298e83SIgor Mammedov  * ACPI 1.0 Root System Description Table (RSDT)
1865ea298e83SIgor Mammedov  */
1866243bdb79SShannon Zhao void
build_rsdt(GArray * table_data,BIOSLinker * linker,GArray * table_offsets,const char * oem_id,const char * oem_table_id)18670e9b9edaSIgor Mammedov build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
186851513558SLaszlo Ersek            const char *oem_id, const char *oem_table_id)
1869243bdb79SShannon Zhao {
1870243bdb79SShannon Zhao     int i;
1871ea298e83SIgor Mammedov     AcpiTable table = { .sig = "RSDT", .rev = 1,
1872ea298e83SIgor Mammedov                         .oem_id = oem_id, .oem_table_id = oem_table_id };
1873243bdb79SShannon Zhao 
1874ea298e83SIgor Mammedov     acpi_table_begin(&table, table_data);
1875243bdb79SShannon Zhao     for (i = 0; i < table_offsets->len; ++i) {
18764678124bSIgor Mammedov         uint32_t ref_tbl_offset = g_array_index(table_offsets, uint32_t, i);
1877ea298e83SIgor Mammedov         uint32_t rsdt_entry_offset = table.array->len;
18784678124bSIgor Mammedov 
1879ea298e83SIgor Mammedov         /* reserve space for entry */
1880ea298e83SIgor Mammedov         build_append_int_noprefix(table.array, 0, 4);
1881ea298e83SIgor Mammedov 
1882ea298e83SIgor Mammedov         /* mark position of RSDT entry to be filled by Guest linker */
1883243bdb79SShannon Zhao         bios_linker_loader_add_pointer(linker,
1884ea298e83SIgor Mammedov             ACPI_BUILD_TABLE_FILE, rsdt_entry_offset, 4,
18854678124bSIgor Mammedov             ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
1886ea298e83SIgor Mammedov 
1887243bdb79SShannon Zhao     }
1888ea298e83SIgor Mammedov     acpi_table_end(linker, &table);
1889243bdb79SShannon Zhao }
189064b83136SShannon Zhao 
1891f497b7caSIgor Mammedov /*
1892f497b7caSIgor Mammedov  * ACPI 2.0 eXtended System Description Table (XSDT)
1893f497b7caSIgor Mammedov  */
1894cb51ac2fSArd Biesheuvel void
build_xsdt(GArray * table_data,BIOSLinker * linker,GArray * table_offsets,const char * oem_id,const char * oem_table_id)1895cb51ac2fSArd Biesheuvel build_xsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
1896cb51ac2fSArd Biesheuvel            const char *oem_id, const char *oem_table_id)
1897cb51ac2fSArd Biesheuvel {
1898cb51ac2fSArd Biesheuvel     int i;
1899f497b7caSIgor Mammedov     AcpiTable table = { .sig = "XSDT", .rev = 1,
1900f497b7caSIgor Mammedov                         .oem_id = oem_id, .oem_table_id = oem_table_id };
1901cb51ac2fSArd Biesheuvel 
1902f497b7caSIgor Mammedov     acpi_table_begin(&table, table_data);
1903f497b7caSIgor Mammedov 
1904cb51ac2fSArd Biesheuvel     for (i = 0; i < table_offsets->len; ++i) {
1905cb51ac2fSArd Biesheuvel         uint64_t ref_tbl_offset = g_array_index(table_offsets, uint32_t, i);
1906f497b7caSIgor Mammedov         uint64_t xsdt_entry_offset = table.array->len;
1907cb51ac2fSArd Biesheuvel 
1908f497b7caSIgor Mammedov         /* reserve space for entry */
1909f497b7caSIgor Mammedov         build_append_int_noprefix(table.array, 0, 8);
1910f497b7caSIgor Mammedov 
1911f497b7caSIgor Mammedov         /* mark position of RSDT entry to be filled by Guest linker */
1912cb51ac2fSArd Biesheuvel         bios_linker_loader_add_pointer(linker,
1913f497b7caSIgor Mammedov             ACPI_BUILD_TABLE_FILE, xsdt_entry_offset, 8,
1914cb51ac2fSArd Biesheuvel             ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
1915cb51ac2fSArd Biesheuvel     }
1916f497b7caSIgor Mammedov     acpi_table_end(linker, &table);
1917cb51ac2fSArd Biesheuvel }
1918cb51ac2fSArd Biesheuvel 
1919e5b6d55aSIgor Mammedov /*
1920e5b6d55aSIgor Mammedov  * ACPI spec, Revision 4.0
1921e5b6d55aSIgor Mammedov  * 5.2.16.2 Memory Affinity Structure
1922e5b6d55aSIgor Mammedov  */
build_srat_memory(GArray * table_data,uint64_t base,uint64_t len,int node,MemoryAffinityFlags flags)1923e5b6d55aSIgor Mammedov void build_srat_memory(GArray *table_data, uint64_t base,
192464b83136SShannon Zhao                        uint64_t len, int node, MemoryAffinityFlags flags)
192564b83136SShannon Zhao {
1926e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, 1, 1); /* Type */
1927e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, 40, 1); /* Length */
1928e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, node, 4); /* Proximity Domain */
1929e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, 0, 2); /* Reserved */
1930e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, base, 4); /* Base Address Low */
1931e5b6d55aSIgor Mammedov     /* Base Address High */
1932e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, base >> 32, 4);
1933e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, len, 4); /* Length Low */
1934e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, len >> 32, 4); /* Length High */
1935e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, 0, 4); /* Reserved */
1936e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, flags, 4); /* Flags */
1937e5b6d55aSIgor Mammedov     build_append_int_noprefix(table_data, 0, 8); /* Reserved */
193864b83136SShannon Zhao }
19390f203430SHe Chen 
19400f203430SHe Chen /*
1941d8a4b4c3SJonathan Cameron  * ACPI Spec Revision 6.3
1942d8a4b4c3SJonathan Cameron  * Table 5-80 Device Handle - PCI
1943d8a4b4c3SJonathan Cameron  */
build_append_srat_pci_device_handle(GArray * table_data,uint16_t segment,uint8_t bus,uint8_t devfn)1944d8a4b4c3SJonathan Cameron static void build_append_srat_pci_device_handle(GArray *table_data,
1945d8a4b4c3SJonathan Cameron                                                 uint16_t segment,
1946d8a4b4c3SJonathan Cameron                                                 uint8_t bus, uint8_t devfn)
1947d8a4b4c3SJonathan Cameron {
1948d8a4b4c3SJonathan Cameron     /* PCI segment number */
1949d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, segment, 2);
1950d8a4b4c3SJonathan Cameron     /* PCI Bus Device Function */
1951d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, bus, 1);
1952d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, devfn, 1);
1953d8a4b4c3SJonathan Cameron     /* Reserved */
1954d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, 0, 12);
1955d8a4b4c3SJonathan Cameron }
1956d8a4b4c3SJonathan Cameron 
build_append_srat_acpi_device_handle(GArray * table_data,const char * hid,uint32_t uid)1957a82fe829SJonathan Cameron static void build_append_srat_acpi_device_handle(GArray *table_data,
1958a82fe829SJonathan Cameron                                                  const char *hid,
1959a82fe829SJonathan Cameron                                                  uint32_t uid)
1960a82fe829SJonathan Cameron {
1961a82fe829SJonathan Cameron     assert(strlen(hid) == 8);
1962a82fe829SJonathan Cameron     /* Device Handle - ACPI */
1963*13a4a6baSJonathan Cameron     for (int i = 0; i < 8; i++) {
1964a82fe829SJonathan Cameron         build_append_int_noprefix(table_data, hid[i], 1);
1965a82fe829SJonathan Cameron     }
1966a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, uid, 4);
1967a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, 0, 4);
1968a82fe829SJonathan Cameron }
1969a82fe829SJonathan Cameron 
1970d8a4b4c3SJonathan Cameron /*
1971d8a4b4c3SJonathan Cameron  * ACPI spec, Revision 6.3
1972d8a4b4c3SJonathan Cameron  * 5.2.16.6 Generic Initiator Affinity Structure
1973d8a4b4c3SJonathan Cameron  *    With PCI Device Handle.
1974d8a4b4c3SJonathan Cameron  */
build_srat_pci_generic_initiator(GArray * table_data,uint32_t node,uint16_t segment,uint8_t bus,uint8_t devfn)1975cf2181aeSJonathan Cameron void build_srat_pci_generic_initiator(GArray *table_data, uint32_t node,
1976d8a4b4c3SJonathan Cameron                                       uint16_t segment, uint8_t bus,
1977d8a4b4c3SJonathan Cameron                                       uint8_t devfn)
1978d8a4b4c3SJonathan Cameron {
1979d8a4b4c3SJonathan Cameron     /* Type */
1980d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, 5, 1);
1981d8a4b4c3SJonathan Cameron     /* Length */
1982d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, 32, 1);
1983d8a4b4c3SJonathan Cameron     /* Reserved */
1984d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, 0, 1);
1985d8a4b4c3SJonathan Cameron     /* Device Handle Type: PCI */
1986d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, 1, 1);
1987d8a4b4c3SJonathan Cameron     /* Proximity Domain */
1988d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, node, 4);
1989d8a4b4c3SJonathan Cameron     /* Device Handle */
1990d8a4b4c3SJonathan Cameron     build_append_srat_pci_device_handle(table_data, segment, bus, devfn);
1991d8a4b4c3SJonathan Cameron     /* Flags - GI Enabled */
1992d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, 1, 4);
1993d8a4b4c3SJonathan Cameron     /* Reserved */
1994d8a4b4c3SJonathan Cameron     build_append_int_noprefix(table_data, 0, 4);
1995d8a4b4c3SJonathan Cameron }
1996d8a4b4c3SJonathan Cameron 
1997d8a4b4c3SJonathan Cameron /*
1998a82fe829SJonathan Cameron  * ACPI spec, Revision 6.5
1999a82fe829SJonathan Cameron  * 5.2.16.7 Generic Port Affinity Structure
2000a82fe829SJonathan Cameron  *   With ACPI Device Handle.
2001a82fe829SJonathan Cameron  */
build_srat_acpi_generic_port(GArray * table_data,uint32_t node,const char * hid,uint32_t uid)2002a82fe829SJonathan Cameron void build_srat_acpi_generic_port(GArray *table_data, uint32_t node,
2003a82fe829SJonathan Cameron                                   const char *hid, uint32_t uid)
2004a82fe829SJonathan Cameron {
2005a82fe829SJonathan Cameron     /* Type */
2006a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, 6, 1);
2007a82fe829SJonathan Cameron     /* Length */
2008a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, 32, 1);
2009a82fe829SJonathan Cameron     /* Reserved */
2010a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, 0, 1);
2011a82fe829SJonathan Cameron     /* Device Handle Type: ACPI */
2012a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, 0, 1);
2013a82fe829SJonathan Cameron     /* Proximity Domain */
2014a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, node, 4);
2015a82fe829SJonathan Cameron     /* Device Handle */
2016a82fe829SJonathan Cameron     build_append_srat_acpi_device_handle(table_data, hid, uid);
2017a82fe829SJonathan Cameron     /* Flags - GP Enabled */
2018a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, 1, 4);
2019a82fe829SJonathan Cameron     /* Reserved */
2020a82fe829SJonathan Cameron     build_append_int_noprefix(table_data, 0, 4);
2021a82fe829SJonathan Cameron }
2022a82fe829SJonathan Cameron 
2023a82fe829SJonathan Cameron /*
20240f203430SHe Chen  * ACPI spec 5.2.17 System Locality Distance Information Table
20250f203430SHe Chen  * (Revision 2.0 or later)
20260f203430SHe Chen  */
build_slit(GArray * table_data,BIOSLinker * linker,MachineState * ms,const char * oem_id,const char * oem_table_id)2027602b4582SMarian Postevca void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms,
2028602b4582SMarian Postevca                 const char *oem_id, const char *oem_table_id)
20290f203430SHe Chen {
20307469f199SIgor Mammedov     int i, j;
2031aa570207STao Xu     int nb_numa_nodes = ms->numa_state->num_nodes;
20327469f199SIgor Mammedov     AcpiTable table = { .sig = "SLIT", .rev = 1,
20337469f199SIgor Mammedov                         .oem_id = oem_id, .oem_table_id = oem_table_id };
20340f203430SHe Chen 
20357469f199SIgor Mammedov     acpi_table_begin(&table, table_data);
20360f203430SHe Chen 
20370f203430SHe Chen     build_append_int_noprefix(table_data, nb_numa_nodes, 8);
20380f203430SHe Chen     for (i = 0; i < nb_numa_nodes; i++) {
20390f203430SHe Chen         for (j = 0; j < nb_numa_nodes; j++) {
20407e721e7bSTao Xu             assert(ms->numa_state->nodes[i].distance[j]);
20417e721e7bSTao Xu             build_append_int_noprefix(table_data,
20427e721e7bSTao Xu                                       ms->numa_state->nodes[i].distance[j],
20437e721e7bSTao Xu                                       1);
20440f203430SHe Chen         }
20450f203430SHe Chen     }
20467469f199SIgor Mammedov     acpi_table_end(linker, &table);
20470f203430SHe Chen }
20488612f8bdSIgor Mammedov 
20499de36ef8SYanan Wang /*
20509de36ef8SYanan Wang  * ACPI spec, Revision 6.3
20519de36ef8SYanan Wang  * 5.2.29.1 Processor hierarchy node structure (Type 0)
20529de36ef8SYanan Wang  */
build_processor_hierarchy_node(GArray * tbl,uint32_t flags,uint32_t parent,uint32_t id,uint32_t * priv_rsrc,uint32_t priv_num)20539de36ef8SYanan Wang static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags,
20549de36ef8SYanan Wang                                            uint32_t parent, uint32_t id,
20559de36ef8SYanan Wang                                            uint32_t *priv_rsrc,
20569de36ef8SYanan Wang                                            uint32_t priv_num)
20579de36ef8SYanan Wang {
20589de36ef8SYanan Wang     int i;
20599de36ef8SYanan Wang 
20609de36ef8SYanan Wang     build_append_byte(tbl, 0);                 /* Type 0 - processor */
20619de36ef8SYanan Wang     build_append_byte(tbl, 20 + priv_num * 4); /* Length */
20629de36ef8SYanan Wang     build_append_int_noprefix(tbl, 0, 2);      /* Reserved */
20639de36ef8SYanan Wang     build_append_int_noprefix(tbl, flags, 4);  /* Flags */
20649de36ef8SYanan Wang     build_append_int_noprefix(tbl, parent, 4); /* Parent */
20659de36ef8SYanan Wang     build_append_int_noprefix(tbl, id, 4);     /* ACPI Processor ID */
20669de36ef8SYanan Wang 
20679de36ef8SYanan Wang     /* Number of private resources */
20689de36ef8SYanan Wang     build_append_int_noprefix(tbl, priv_num, 4);
20699de36ef8SYanan Wang 
20709de36ef8SYanan Wang     /* Private resources[N] */
20719de36ef8SYanan Wang     if (priv_num > 0) {
20729de36ef8SYanan Wang         assert(priv_rsrc);
20739de36ef8SYanan Wang         for (i = 0; i < priv_num; i++) {
20749de36ef8SYanan Wang             build_append_int_noprefix(tbl, priv_rsrc[i], 4);
20759de36ef8SYanan Wang         }
20769de36ef8SYanan Wang     }
20779de36ef8SYanan Wang }
20789de36ef8SYanan Wang 
build_spcr(GArray * table_data,BIOSLinker * linker,const AcpiSpcrData * f,const uint8_t rev,const char * oem_id,const char * oem_table_id)20797dd0b070SSia Jee Heng void build_spcr(GArray *table_data, BIOSLinker *linker,
20807dd0b070SSia Jee Heng                 const AcpiSpcrData *f, const uint8_t rev,
20817dd0b070SSia Jee Heng                 const char *oem_id, const char *oem_table_id)
20827dd0b070SSia Jee Heng {
20837dd0b070SSia Jee Heng     AcpiTable table = { .sig = "SPCR", .rev = rev, .oem_id = oem_id,
20847dd0b070SSia Jee Heng                         .oem_table_id = oem_table_id };
20857dd0b070SSia Jee Heng 
20867dd0b070SSia Jee Heng     acpi_table_begin(&table, table_data);
20877dd0b070SSia Jee Heng     /* Interface type */
20887dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->interface_type, 1);
20897dd0b070SSia Jee Heng     /* Reserved */
20907dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, 0, 3);
20917dd0b070SSia Jee Heng     /* Base Address */
20927dd0b070SSia Jee Heng     build_append_gas(table_data, f->base_addr.id, f->base_addr.width,
20937dd0b070SSia Jee Heng                      f->base_addr.offset, f->base_addr.size,
20947dd0b070SSia Jee Heng                      f->base_addr.addr);
20957dd0b070SSia Jee Heng     /* Interrupt type */
20967dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->interrupt_type, 1);
20977dd0b070SSia Jee Heng     /* IRQ */
20987dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->pc_interrupt, 1);
20997dd0b070SSia Jee Heng     /* Global System Interrupt */
21007dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->interrupt, 4);
21017dd0b070SSia Jee Heng     /* Baud Rate */
21027dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->baud_rate, 1);
21037dd0b070SSia Jee Heng     /* Parity */
21047dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->parity, 1);
21057dd0b070SSia Jee Heng     /* Stop Bits */
21067dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->stop_bits, 1);
21077dd0b070SSia Jee Heng     /* Flow Control */
21087dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->flow_control, 1);
21097dd0b070SSia Jee Heng     /* Language */
21107dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->language, 1);
21117dd0b070SSia Jee Heng     /* Terminal Type */
21127dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->terminal_type, 1);
21137dd0b070SSia Jee Heng     /* PCI Device ID  */
21147dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->pci_device_id, 2);
21157dd0b070SSia Jee Heng     /* PCI Vendor ID */
21167dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->pci_vendor_id, 2);
21177dd0b070SSia Jee Heng     /* PCI Bus Number */
21187dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->pci_bus, 1);
21197dd0b070SSia Jee Heng     /* PCI Device Number */
21207dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->pci_device, 1);
21217dd0b070SSia Jee Heng     /* PCI Function Number */
21227dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->pci_function, 1);
21237dd0b070SSia Jee Heng     /* PCI Flags */
21247dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->pci_flags, 4);
21257dd0b070SSia Jee Heng     /* PCI Segment */
21267dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, f->pci_segment, 1);
21277dd0b070SSia Jee Heng     /* Reserved */
21287dd0b070SSia Jee Heng     build_append_int_noprefix(table_data, 0, 4);
21297dd0b070SSia Jee Heng 
21307dd0b070SSia Jee Heng     acpi_table_end(linker, &table);
21317dd0b070SSia Jee Heng }
2132099f2df2SAndrew Jones /*
2133099f2df2SAndrew Jones  * ACPI spec, Revision 6.3
2134099f2df2SAndrew Jones  * 5.2.29 Processor Properties Topology Table (PPTT)
2135099f2df2SAndrew Jones  */
build_pptt(GArray * table_data,BIOSLinker * linker,MachineState * ms,const char * oem_id,const char * oem_table_id)2136099f2df2SAndrew Jones void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
2137099f2df2SAndrew Jones                 const char *oem_id, const char *oem_table_id)
2138099f2df2SAndrew Jones {
213988d0278aSYanan Wang     MachineClass *mc = MACHINE_GET_CLASS(ms);
2140ae9141d4SGavin Shan     CPUArchIdList *cpus = ms->possible_cpus;
2141ae9141d4SGavin Shan     int64_t socket_id = -1, cluster_id = -1, core_id = -1;
2142ae9141d4SGavin Shan     uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0;
2143ae9141d4SGavin Shan     uint32_t pptt_start = table_data->len;
2144ae9141d4SGavin Shan     int n;
2145099f2df2SAndrew Jones     AcpiTable table = { .sig = "PPTT", .rev = 2,
2146099f2df2SAndrew Jones                         .oem_id = oem_id, .oem_table_id = oem_table_id };
2147099f2df2SAndrew Jones 
2148099f2df2SAndrew Jones     acpi_table_begin(&table, table_data);
2149099f2df2SAndrew Jones 
2150099f2df2SAndrew Jones     /*
2151ae9141d4SGavin Shan      * This works with the assumption that cpus[n].props.*_id has been
2152ae9141d4SGavin Shan      * sorted from top to down levels in mc->possible_cpu_arch_ids().
2153ae9141d4SGavin Shan      * Otherwise, the unexpected and duplicated containers will be
2154ae9141d4SGavin Shan      * created.
2155099f2df2SAndrew Jones      */
2156ae9141d4SGavin Shan     for (n = 0; n < cpus->len; n++) {
2157ae9141d4SGavin Shan         if (cpus->cpus[n].props.socket_id != socket_id) {
2158ae9141d4SGavin Shan             assert(cpus->cpus[n].props.socket_id > socket_id);
2159ae9141d4SGavin Shan             socket_id = cpus->cpus[n].props.socket_id;
2160ae9141d4SGavin Shan             cluster_id = -1;
2161ae9141d4SGavin Shan             core_id = -1;
2162ae9141d4SGavin Shan             socket_offset = table_data->len - pptt_start;
2163ae9141d4SGavin Shan             build_processor_hierarchy_node(table_data,
2164ae9141d4SGavin Shan                 (1 << 0), /* Physical package */
2165ae9141d4SGavin Shan                 0, socket_id, NULL, 0);
216611b9eb1bSYanan Wang         }
2167099f2df2SAndrew Jones 
216897f4effeSYicong Yang         if (mc->smp_props.clusters_supported && mc->smp_props.has_clusters) {
2169ae9141d4SGavin Shan             if (cpus->cpus[n].props.cluster_id != cluster_id) {
2170ae9141d4SGavin Shan                 assert(cpus->cpus[n].props.cluster_id > cluster_id);
2171ae9141d4SGavin Shan                 cluster_id = cpus->cpus[n].props.cluster_id;
2172ae9141d4SGavin Shan                 core_id = -1;
2173ae9141d4SGavin Shan                 cluster_offset = table_data->len - pptt_start;
2174ae9141d4SGavin Shan                 build_processor_hierarchy_node(table_data,
2175ae9141d4SGavin Shan                     (0 << 0), /* Not a physical package */
2176ae9141d4SGavin Shan                     socket_offset, cluster_id, NULL, 0);
217788d0278aSYanan Wang             }
217811b9eb1bSYanan Wang         } else {
2179ae9141d4SGavin Shan             cluster_offset = socket_offset;
2180ae9141d4SGavin Shan         }
2181ae9141d4SGavin Shan 
2182ae9141d4SGavin Shan         if (ms->smp.threads == 1) {
2183ae9141d4SGavin Shan             build_processor_hierarchy_node(table_data,
218411b9eb1bSYanan Wang                 (1 << 1) | /* ACPI Processor ID valid */
218511b9eb1bSYanan Wang                 (1 << 3),  /* Node is a Leaf */
2186ae9141d4SGavin Shan                 cluster_offset, n, NULL, 0);
2187ae9141d4SGavin Shan         } else {
2188ae9141d4SGavin Shan             if (cpus->cpus[n].props.core_id != core_id) {
2189ae9141d4SGavin Shan                 assert(cpus->cpus[n].props.core_id > core_id);
2190ae9141d4SGavin Shan                 core_id = cpus->cpus[n].props.core_id;
2191ae9141d4SGavin Shan                 core_offset = table_data->len - pptt_start;
2192ae9141d4SGavin Shan                 build_processor_hierarchy_node(table_data,
2193ae9141d4SGavin Shan                     (0 << 0), /* Not a physical package */
2194ae9141d4SGavin Shan                     cluster_offset, core_id, NULL, 0);
219511b9eb1bSYanan Wang             }
2196099f2df2SAndrew Jones 
2197ae9141d4SGavin Shan             build_processor_hierarchy_node(table_data,
2198099f2df2SAndrew Jones                 (1 << 1) | /* ACPI Processor ID valid */
2199099f2df2SAndrew Jones                 (1 << 2) | /* Processor is a Thread */
2200099f2df2SAndrew Jones                 (1 << 3),  /* Node is a Leaf */
2201ae9141d4SGavin Shan                 core_offset, n, NULL, 0);
2202099f2df2SAndrew Jones         }
2203099f2df2SAndrew Jones     }
2204099f2df2SAndrew Jones 
2205099f2df2SAndrew Jones     acpi_table_end(linker, &table);
2206099f2df2SAndrew Jones }
2207099f2df2SAndrew Jones 
22084496d1d3SMiguel Luis /* build rev1/rev3/rev5.1/rev6.0 FADT */
build_fadt(GArray * tbl,BIOSLinker * linker,const AcpiFadtData * f,const char * oem_id,const char * oem_table_id)22098612f8bdSIgor Mammedov void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
22108612f8bdSIgor Mammedov                 const char *oem_id, const char *oem_table_id)
22118612f8bdSIgor Mammedov {
22128612f8bdSIgor Mammedov     int off;
22134b56e1e4SIgor Mammedov     AcpiTable table = { .sig = "FACP", .rev = f->rev,
22144b56e1e4SIgor Mammedov                         .oem_id = oem_id, .oem_table_id = oem_table_id };
22158612f8bdSIgor Mammedov 
22164b56e1e4SIgor Mammedov     acpi_table_begin(&table, tbl);
22178612f8bdSIgor Mammedov 
22188612f8bdSIgor Mammedov     /* FACS address to be filled by Guest linker at runtime */
22198612f8bdSIgor Mammedov     off = tbl->len;
22208612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 4); /* FIRMWARE_CTRL */
22218612f8bdSIgor Mammedov     if (f->facs_tbl_offset) { /* don't patch if not supported by platform */
22228612f8bdSIgor Mammedov         bios_linker_loader_add_pointer(linker,
22238612f8bdSIgor Mammedov             ACPI_BUILD_TABLE_FILE, off, 4,
22248612f8bdSIgor Mammedov             ACPI_BUILD_TABLE_FILE, *f->facs_tbl_offset);
22258612f8bdSIgor Mammedov     }
22268612f8bdSIgor Mammedov 
22278612f8bdSIgor Mammedov     /* DSDT address to be filled by Guest linker at runtime */
22288612f8bdSIgor Mammedov     off = tbl->len;
22298612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 4); /* DSDT */
22308612f8bdSIgor Mammedov     if (f->dsdt_tbl_offset) { /* don't patch if not supported by platform */
22318612f8bdSIgor Mammedov         bios_linker_loader_add_pointer(linker,
22328612f8bdSIgor Mammedov             ACPI_BUILD_TABLE_FILE, off, 4,
22338612f8bdSIgor Mammedov             ACPI_BUILD_TABLE_FILE, *f->dsdt_tbl_offset);
22348612f8bdSIgor Mammedov     }
22358612f8bdSIgor Mammedov 
22368612f8bdSIgor Mammedov     /* ACPI1.0: INT_MODEL, ACPI2.0+: Reserved */
22378612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->int_model /* Multiple APIC */, 1);
22388612f8bdSIgor Mammedov     /* Preferred_PM_Profile */
22398612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0 /* Unspecified */, 1);
22408612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->sci_int, 2); /* SCI_INT */
22418612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->smi_cmd, 4); /* SMI_CMD */
22428612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->acpi_enable_cmd, 1); /* ACPI_ENABLE */
22438612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->acpi_disable_cmd, 1); /* ACPI_DISABLE */
22448612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0 /* not supported */, 1); /* S4BIOS_REQ */
22458612f8bdSIgor Mammedov     /* ACPI1.0: Reserved, ACPI2.0+: PSTATE_CNT */
22468612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1);
22478612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->pm1a_evt.address, 4); /* PM1a_EVT_BLK */
22488612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 4); /* PM1b_EVT_BLK */
22498612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->pm1a_cnt.address, 4); /* PM1a_CNT_BLK */
22508612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 4); /* PM1b_CNT_BLK */
22518612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 4); /* PM2_CNT_BLK */
22528612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->pm_tmr.address, 4); /* PM_TMR_BLK */
22538612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->gpe0_blk.address, 4); /* GPE0_BLK */
22548612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 4); /* GPE1_BLK */
22558612f8bdSIgor Mammedov     /* PM1_EVT_LEN */
22568612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->pm1a_evt.bit_width / 8, 1);
22578612f8bdSIgor Mammedov     /* PM1_CNT_LEN */
22588612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->pm1a_cnt.bit_width / 8, 1);
22598612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* PM2_CNT_LEN */
22608612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->pm_tmr.bit_width / 8, 1); /* PM_TMR_LEN */
22618612f8bdSIgor Mammedov     /* GPE0_BLK_LEN */
22628612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->gpe0_blk.bit_width / 8, 1);
22638612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* GPE1_BLK_LEN */
22648612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* GPE1_BASE */
22658612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* CST_CNT */
22668612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->plvl2_lat, 2); /* P_LVL2_LAT */
22678612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->plvl3_lat, 2); /* P_LVL3_LAT */
22688612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 2); /* FLUSH_SIZE */
22698612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 2); /* FLUSH_STRIDE */
22708612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* DUTY_OFFSET */
22718612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* DUTY_WIDTH */
22728612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* DAY_ALRM */
22738612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* MON_ALRM */
22748612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->rtc_century, 1); /* CENTURY */
22755334bf57SLiav Albani     /* IAPC_BOOT_ARCH */
22765334bf57SLiav Albani     if (f->rev == 1) {
22775334bf57SLiav Albani         build_append_int_noprefix(tbl, 0, 2);
22785334bf57SLiav Albani     } else {
22795334bf57SLiav Albani         /* since ACPI v2.0 */
22805334bf57SLiav Albani         build_append_int_noprefix(tbl, f->iapc_boot_arch, 2);
22815334bf57SLiav Albani     }
22828612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 1); /* Reserved */
22838612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->flags, 4); /* Flags */
22848612f8bdSIgor Mammedov 
22858612f8bdSIgor Mammedov     if (f->rev == 1) {
22864b56e1e4SIgor Mammedov         goto done;
22878612f8bdSIgor Mammedov     }
22888612f8bdSIgor Mammedov 
22898612f8bdSIgor Mammedov     build_append_gas_from_struct(tbl, &f->reset_reg); /* RESET_REG */
22908612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, f->reset_val, 1); /* RESET_VALUE */
2291dd1b2037SIgor Mammedov     /* Since ACPI 5.1 */
2292dd1b2037SIgor Mammedov     if ((f->rev >= 6) || ((f->rev == 5) && f->minor_ver > 0)) {
2293dd1b2037SIgor Mammedov         build_append_int_noprefix(tbl, f->arm_boot_arch, 2); /* ARM_BOOT_ARCH */
2294dd1b2037SIgor Mammedov         /* FADT Minor Version */
2295dd1b2037SIgor Mammedov         build_append_int_noprefix(tbl, f->minor_ver, 1);
2296dd1b2037SIgor Mammedov     } else {
2297dd1b2037SIgor Mammedov         build_append_int_noprefix(tbl, 0, 3); /* Reserved up to ACPI 5.0 */
2298dd1b2037SIgor Mammedov     }
22998612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 8); /* X_FIRMWARE_CTRL */
23008612f8bdSIgor Mammedov 
23018612f8bdSIgor Mammedov     /* XDSDT address to be filled by Guest linker at runtime */
23028612f8bdSIgor Mammedov     off = tbl->len;
23038612f8bdSIgor Mammedov     build_append_int_noprefix(tbl, 0, 8); /* X_DSDT */
23048612f8bdSIgor Mammedov     if (f->xdsdt_tbl_offset) {
23058612f8bdSIgor Mammedov         bios_linker_loader_add_pointer(linker,
23068612f8bdSIgor Mammedov             ACPI_BUILD_TABLE_FILE, off, 8,
23078612f8bdSIgor Mammedov             ACPI_BUILD_TABLE_FILE, *f->xdsdt_tbl_offset);
23088612f8bdSIgor Mammedov     }
23098612f8bdSIgor Mammedov 
23108612f8bdSIgor Mammedov     build_append_gas_from_struct(tbl, &f->pm1a_evt); /* X_PM1a_EVT_BLK */
23118612f8bdSIgor Mammedov     /* X_PM1b_EVT_BLK */
23128612f8bdSIgor Mammedov     build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
23138612f8bdSIgor Mammedov     build_append_gas_from_struct(tbl, &f->pm1a_cnt); /* X_PM1a_CNT_BLK */
23148612f8bdSIgor Mammedov     /* X_PM1b_CNT_BLK */
23158612f8bdSIgor Mammedov     build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
23168612f8bdSIgor Mammedov     /* X_PM2_CNT_BLK */
23178612f8bdSIgor Mammedov     build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
23188612f8bdSIgor Mammedov     build_append_gas_from_struct(tbl, &f->pm_tmr); /* X_PM_TMR_BLK */
23198612f8bdSIgor Mammedov     build_append_gas_from_struct(tbl, &f->gpe0_blk); /* X_GPE0_BLK */
23208612f8bdSIgor Mammedov     build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0); /* X_GPE1_BLK */
23218612f8bdSIgor Mammedov 
2322dd1b2037SIgor Mammedov     if (f->rev <= 4) {
23234b56e1e4SIgor Mammedov         goto done;
2324dd1b2037SIgor Mammedov     }
2325dd1b2037SIgor Mammedov 
2326dd1b2037SIgor Mammedov     /* SLEEP_CONTROL_REG */
2327c8ed8f57SGerd Hoffmann     build_append_gas_from_struct(tbl, &f->sleep_ctl);
2328dd1b2037SIgor Mammedov     /* SLEEP_STATUS_REG */
2329c8ed8f57SGerd Hoffmann     build_append_gas_from_struct(tbl, &f->sleep_sts);
2330dd1b2037SIgor Mammedov 
23314496d1d3SMiguel Luis     if (f->rev == 5) {
23324496d1d3SMiguel Luis         goto done;
23334496d1d3SMiguel Luis     }
23344496d1d3SMiguel Luis 
23354496d1d3SMiguel Luis     /* Hypervisor Vendor Identity */
23364496d1d3SMiguel Luis     build_append_padded_str(tbl, "QEMU", 8, '\0');
23374496d1d3SMiguel Luis 
23384496d1d3SMiguel Luis     /* TODO: extra fields need to be added to support revisions above rev6 */
23394496d1d3SMiguel Luis     assert(f->rev == 6);
2340dd1b2037SIgor Mammedov 
23414b56e1e4SIgor Mammedov done:
23424b56e1e4SIgor Mammedov     acpi_table_end(linker, &table);
23438612f8bdSIgor Mammedov }
2344ef48a8ceSCorey Minyard 
2345295f7dcbSStefan Berger #ifdef CONFIG_TPM
2346e27e1e63SEric Auger /*
2347e27e1e63SEric Auger  * build_tpm2 - Build the TPM2 table as specified in
2348e27e1e63SEric Auger  * table 7: TCG Hardware Interface Description Table Format for TPM 2.0
2349e27e1e63SEric Auger  * of TCG ACPI Specification, Family “1.2” and “2.0”, Version 1.2, Rev 8
2350e27e1e63SEric Auger  */
build_tpm2(GArray * table_data,BIOSLinker * linker,GArray * tcpalog,const char * oem_id,const char * oem_table_id)2351602b4582SMarian Postevca void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
2352602b4582SMarian Postevca                 const char *oem_id, const char *oem_table_id)
235343384160SEric Auger {
235443384160SEric Auger     uint8_t start_method_params[12] = {};
23553e39c1edSIgor Mammedov     unsigned log_addr_offset;
2356e27e1e63SEric Auger     uint64_t control_area_start_address;
235780bde693SEric Auger     TPMIf *tpmif = tpm_find();
2358e27e1e63SEric Auger     uint32_t start_method;
23593e39c1edSIgor Mammedov     AcpiTable table = { .sig = "TPM2", .rev = 4,
23603e39c1edSIgor Mammedov                         .oem_id = oem_id, .oem_table_id = oem_table_id };
236143384160SEric Auger 
23623e39c1edSIgor Mammedov     acpi_table_begin(&table, table_data);
2363e27e1e63SEric Auger 
2364e27e1e63SEric Auger     /* Platform Class */
236543384160SEric Auger     build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2);
2366e27e1e63SEric Auger     /* Reserved */
236743384160SEric Auger     build_append_int_noprefix(table_data, 0, 2);
236880bde693SEric Auger     if (TPM_IS_TIS_ISA(tpmif) || TPM_IS_TIS_SYSBUS(tpmif)) {
2369e27e1e63SEric Auger         control_area_start_address = 0;
2370e27e1e63SEric Auger         start_method = TPM2_START_METHOD_MMIO;
237180bde693SEric Auger     } else if (TPM_IS_CRB(tpmif)) {
2372e27e1e63SEric Auger         control_area_start_address = TPM_CRB_ADDR_CTRL;
2373e27e1e63SEric Auger         start_method = TPM2_START_METHOD_CRB;
237443384160SEric Auger     } else {
2375e27e1e63SEric Auger         g_assert_not_reached();
237643384160SEric Auger     }
2377e27e1e63SEric Auger     /* Address of Control Area */
2378e27e1e63SEric Auger     build_append_int_noprefix(table_data, control_area_start_address, 8);
2379e27e1e63SEric Auger     /* Start Method */
2380e27e1e63SEric Auger     build_append_int_noprefix(table_data, start_method, 4);
238143384160SEric Auger 
2382e27e1e63SEric Auger     /* Platform Specific Parameters */
2383e27e1e63SEric Auger     g_array_append_vals(table_data, &start_method_params,
2384e27e1e63SEric Auger                         ARRAY_SIZE(start_method_params));
238543384160SEric Auger 
2386e27e1e63SEric Auger     /* Log Area Minimum Length */
238743384160SEric Auger     build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4);
238843384160SEric Auger 
238943384160SEric Auger     acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE);
239043384160SEric Auger     bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1,
239143384160SEric Auger                              false);
239243384160SEric Auger 
2393e27e1e63SEric Auger     log_addr_offset = table_data->len;
2394e27e1e63SEric Auger 
2395e27e1e63SEric Auger     /* Log Area Start Address to be filled by Guest linker */
239643384160SEric Auger     build_append_int_noprefix(table_data, 0, 8);
239743384160SEric Auger     bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
2398e27e1e63SEric Auger                                    log_addr_offset, 8,
239943384160SEric Auger                                    ACPI_BUILD_TPMLOG_FILE, 0);
24003e39c1edSIgor Mammedov     acpi_table_end(linker, &table);
240143384160SEric Auger }
2402295f7dcbSStefan Berger #endif
240343384160SEric Auger 
build_crs(PCIHostState * host,CrsRangeSet * range_set,uint32_t io_offset,uint32_t mmio32_offset,uint64_t mmio64_offset,uint16_t bus_nr_offset)2404e41ee855SJiahui Cen Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set, uint32_t io_offset,
2405e41ee855SJiahui Cen                uint32_t mmio32_offset, uint64_t mmio64_offset,
2406e41ee855SJiahui Cen                uint16_t bus_nr_offset)
240737d5c0a8SYubo Miao {
240837d5c0a8SYubo Miao     Aml *crs = aml_resource_template();
240937d5c0a8SYubo Miao     CrsRangeSet temp_range_set;
241037d5c0a8SYubo Miao     CrsRangeEntry *entry;
241137d5c0a8SYubo Miao     uint8_t max_bus = pci_bus_num(host->bus);
241237d5c0a8SYubo Miao     uint8_t type;
241337d5c0a8SYubo Miao     int devfn;
241437d5c0a8SYubo Miao     int i;
241537d5c0a8SYubo Miao 
241637d5c0a8SYubo Miao     crs_range_set_init(&temp_range_set);
241737d5c0a8SYubo Miao     for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
241837d5c0a8SYubo Miao         uint64_t range_base, range_limit;
241937d5c0a8SYubo Miao         PCIDevice *dev = host->bus->devices[devfn];
242037d5c0a8SYubo Miao 
242137d5c0a8SYubo Miao         if (!dev) {
242237d5c0a8SYubo Miao             continue;
242337d5c0a8SYubo Miao         }
242437d5c0a8SYubo Miao 
242537d5c0a8SYubo Miao         for (i = 0; i < PCI_NUM_REGIONS; i++) {
242637d5c0a8SYubo Miao             PCIIORegion *r = &dev->io_regions[i];
242737d5c0a8SYubo Miao 
242837d5c0a8SYubo Miao             range_base = r->addr;
242937d5c0a8SYubo Miao             range_limit = r->addr + r->size - 1;
243037d5c0a8SYubo Miao 
243137d5c0a8SYubo Miao             /*
243237d5c0a8SYubo Miao              * Work-around for old bioses
243337d5c0a8SYubo Miao              * that do not support multiple root buses
243437d5c0a8SYubo Miao              */
243537d5c0a8SYubo Miao             if (!range_base || range_base > range_limit) {
243637d5c0a8SYubo Miao                 continue;
243737d5c0a8SYubo Miao             }
243837d5c0a8SYubo Miao 
243937d5c0a8SYubo Miao             if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
244037d5c0a8SYubo Miao                 crs_range_insert(temp_range_set.io_ranges,
244137d5c0a8SYubo Miao                                  range_base, range_limit);
244237d5c0a8SYubo Miao             } else { /* "memory" */
244337d5c0a8SYubo Miao                 uint64_t length = range_limit - range_base + 1;
244437d5c0a8SYubo Miao                 if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
244537d5c0a8SYubo Miao                     crs_range_insert(temp_range_set.mem_ranges, range_base,
244637d5c0a8SYubo Miao                                      range_limit);
244737d5c0a8SYubo Miao                 } else {
244837d5c0a8SYubo Miao                     crs_range_insert(temp_range_set.mem_64bit_ranges,
244937d5c0a8SYubo Miao                                      range_base, range_limit);
245037d5c0a8SYubo Miao                 }
245137d5c0a8SYubo Miao             }
245237d5c0a8SYubo Miao         }
245337d5c0a8SYubo Miao 
245437d5c0a8SYubo Miao         type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
245537d5c0a8SYubo Miao         if (type == PCI_HEADER_TYPE_BRIDGE) {
245637d5c0a8SYubo Miao             uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS];
245737d5c0a8SYubo Miao             if (subordinate > max_bus) {
245837d5c0a8SYubo Miao                 max_bus = subordinate;
245937d5c0a8SYubo Miao             }
246037d5c0a8SYubo Miao 
246137d5c0a8SYubo Miao             range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
246237d5c0a8SYubo Miao             range_limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
246337d5c0a8SYubo Miao 
246437d5c0a8SYubo Miao              /*
246537d5c0a8SYubo Miao               * Work-around for old bioses
246637d5c0a8SYubo Miao               * that do not support multiple root buses
246737d5c0a8SYubo Miao               */
246837d5c0a8SYubo Miao             if (range_base && range_base <= range_limit) {
246937d5c0a8SYubo Miao                 crs_range_insert(temp_range_set.io_ranges,
247037d5c0a8SYubo Miao                                  range_base, range_limit);
247137d5c0a8SYubo Miao             }
247237d5c0a8SYubo Miao 
247337d5c0a8SYubo Miao             range_base =
247437d5c0a8SYubo Miao                 pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
247537d5c0a8SYubo Miao             range_limit =
247637d5c0a8SYubo Miao                 pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
247737d5c0a8SYubo Miao 
247837d5c0a8SYubo Miao             /*
247937d5c0a8SYubo Miao              * Work-around for old bioses
248037d5c0a8SYubo Miao              * that do not support multiple root buses
248137d5c0a8SYubo Miao              */
248237d5c0a8SYubo Miao             if (range_base && range_base <= range_limit) {
248337d5c0a8SYubo Miao                 uint64_t length = range_limit - range_base + 1;
248437d5c0a8SYubo Miao                 if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
248537d5c0a8SYubo Miao                     crs_range_insert(temp_range_set.mem_ranges,
248637d5c0a8SYubo Miao                                      range_base, range_limit);
248737d5c0a8SYubo Miao                 } else {
248837d5c0a8SYubo Miao                     crs_range_insert(temp_range_set.mem_64bit_ranges,
248937d5c0a8SYubo Miao                                      range_base, range_limit);
249037d5c0a8SYubo Miao                 }
249137d5c0a8SYubo Miao             }
249237d5c0a8SYubo Miao 
249337d5c0a8SYubo Miao             range_base =
249437d5c0a8SYubo Miao                 pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
249537d5c0a8SYubo Miao             range_limit =
249637d5c0a8SYubo Miao                 pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
249737d5c0a8SYubo Miao 
249837d5c0a8SYubo Miao             /*
249937d5c0a8SYubo Miao              * Work-around for old bioses
250037d5c0a8SYubo Miao              * that do not support multiple root buses
250137d5c0a8SYubo Miao              */
250237d5c0a8SYubo Miao             if (range_base && range_base <= range_limit) {
250337d5c0a8SYubo Miao                 uint64_t length = range_limit - range_base + 1;
250437d5c0a8SYubo Miao                 if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
250537d5c0a8SYubo Miao                     crs_range_insert(temp_range_set.mem_ranges,
250637d5c0a8SYubo Miao                                      range_base, range_limit);
250737d5c0a8SYubo Miao                 } else {
250837d5c0a8SYubo Miao                     crs_range_insert(temp_range_set.mem_64bit_ranges,
250937d5c0a8SYubo Miao                                      range_base, range_limit);
251037d5c0a8SYubo Miao                 }
251137d5c0a8SYubo Miao             }
251237d5c0a8SYubo Miao         }
251337d5c0a8SYubo Miao     }
251437d5c0a8SYubo Miao 
251537d5c0a8SYubo Miao     crs_range_merge(temp_range_set.io_ranges);
251637d5c0a8SYubo Miao     for (i = 0; i < temp_range_set.io_ranges->len; i++) {
251737d5c0a8SYubo Miao         entry = g_ptr_array_index(temp_range_set.io_ranges, i);
251837d5c0a8SYubo Miao         aml_append(crs,
2519e41ee855SJiahui Cen                    aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED,
252037d5c0a8SYubo Miao                                 AML_POS_DECODE, AML_ENTIRE_RANGE,
2521e41ee855SJiahui Cen                                 0, entry->base, entry->limit, io_offset,
252237d5c0a8SYubo Miao                                 entry->limit - entry->base + 1));
252337d5c0a8SYubo Miao         crs_range_insert(range_set->io_ranges, entry->base, entry->limit);
252437d5c0a8SYubo Miao     }
252537d5c0a8SYubo Miao 
252637d5c0a8SYubo Miao     crs_range_merge(temp_range_set.mem_ranges);
252737d5c0a8SYubo Miao     for (i = 0; i < temp_range_set.mem_ranges->len; i++) {
252837d5c0a8SYubo Miao         entry = g_ptr_array_index(temp_range_set.mem_ranges, i);
252937d5c0a8SYubo Miao         assert(entry->limit <= UINT32_MAX &&
253037d5c0a8SYubo Miao                (entry->limit - entry->base + 1) <= UINT32_MAX);
253137d5c0a8SYubo Miao         aml_append(crs,
253237d5c0a8SYubo Miao                    aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
253337d5c0a8SYubo Miao                                     AML_MAX_FIXED, AML_NON_CACHEABLE,
253437d5c0a8SYubo Miao                                     AML_READ_WRITE,
2535e41ee855SJiahui Cen                                     0, entry->base, entry->limit, mmio32_offset,
253637d5c0a8SYubo Miao                                     entry->limit - entry->base + 1));
253737d5c0a8SYubo Miao         crs_range_insert(range_set->mem_ranges, entry->base, entry->limit);
253837d5c0a8SYubo Miao     }
253937d5c0a8SYubo Miao 
254037d5c0a8SYubo Miao     crs_range_merge(temp_range_set.mem_64bit_ranges);
254137d5c0a8SYubo Miao     for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) {
254237d5c0a8SYubo Miao         entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i);
254337d5c0a8SYubo Miao         aml_append(crs,
254437d5c0a8SYubo Miao                    aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
254537d5c0a8SYubo Miao                                     AML_MAX_FIXED, AML_NON_CACHEABLE,
254637d5c0a8SYubo Miao                                     AML_READ_WRITE,
2547e41ee855SJiahui Cen                                     0, entry->base, entry->limit, mmio64_offset,
254837d5c0a8SYubo Miao                                     entry->limit - entry->base + 1));
254937d5c0a8SYubo Miao         crs_range_insert(range_set->mem_64bit_ranges,
255037d5c0a8SYubo Miao                          entry->base, entry->limit);
255137d5c0a8SYubo Miao     }
255237d5c0a8SYubo Miao 
255337d5c0a8SYubo Miao     crs_range_set_free(&temp_range_set);
255437d5c0a8SYubo Miao 
255537d5c0a8SYubo Miao     aml_append(crs,
255637d5c0a8SYubo Miao         aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
255737d5c0a8SYubo Miao                             0,
255837d5c0a8SYubo Miao                             pci_bus_num(host->bus),
255937d5c0a8SYubo Miao                             max_bus,
2560e41ee855SJiahui Cen                             bus_nr_offset,
256137d5c0a8SYubo Miao                             max_bus - pci_bus_num(host->bus) + 1));
256237d5c0a8SYubo Miao 
256337d5c0a8SYubo Miao     return crs;
256437d5c0a8SYubo Miao }
256537d5c0a8SYubo Miao 
2566ef48a8ceSCorey Minyard /* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */
aml_serial_bus_device(uint8_t serial_bus_type,uint8_t flags,uint16_t type_flags,uint8_t revid,uint16_t data_length,uint16_t resource_source_len)2567ef48a8ceSCorey Minyard static Aml *aml_serial_bus_device(uint8_t serial_bus_type, uint8_t flags,
2568ef48a8ceSCorey Minyard                                   uint16_t type_flags,
2569ef48a8ceSCorey Minyard                                   uint8_t revid, uint16_t data_length,
2570ef48a8ceSCorey Minyard                                   uint16_t resource_source_len)
2571ef48a8ceSCorey Minyard {
2572ef48a8ceSCorey Minyard     Aml *var = aml_alloc();
2573ef48a8ceSCorey Minyard     uint16_t length = data_length + resource_source_len + 9;
2574ef48a8ceSCorey Minyard 
2575ef48a8ceSCorey Minyard     build_append_byte(var->buf, 0x8e); /* Serial Bus Connection Descriptor */
2576ef48a8ceSCorey Minyard     build_append_int_noprefix(var->buf, length, sizeof(length));
2577ef48a8ceSCorey Minyard     build_append_byte(var->buf, 1);    /* Revision ID */
2578ef48a8ceSCorey Minyard     build_append_byte(var->buf, 0);    /* Resource Source Index */
2579ef48a8ceSCorey Minyard     build_append_byte(var->buf, serial_bus_type); /* Serial Bus Type */
2580ef48a8ceSCorey Minyard     build_append_byte(var->buf, flags); /* General Flags */
2581ef48a8ceSCorey Minyard     build_append_int_noprefix(var->buf, type_flags, /* Type Specific Flags */
2582ef48a8ceSCorey Minyard                               sizeof(type_flags));
2583ef48a8ceSCorey Minyard     build_append_byte(var->buf, revid); /* Type Specification Revision ID */
2584ef48a8ceSCorey Minyard     build_append_int_noprefix(var->buf, data_length, sizeof(data_length));
2585ef48a8ceSCorey Minyard 
2586ef48a8ceSCorey Minyard     return var;
2587ef48a8ceSCorey Minyard }
2588ef48a8ceSCorey Minyard 
2589ef48a8ceSCorey Minyard /* ACPI 5.0: 6.4.3.8.2.1 I2C Serial Bus Connection Resource Descriptor */
aml_i2c_serial_bus_device(uint16_t address,const char * resource_source)2590ef48a8ceSCorey Minyard Aml *aml_i2c_serial_bus_device(uint16_t address, const char *resource_source)
2591ef48a8ceSCorey Minyard {
2592ef48a8ceSCorey Minyard     uint16_t resource_source_len = strlen(resource_source) + 1;
2593ef48a8ceSCorey Minyard     Aml *var = aml_serial_bus_device(AML_SERIAL_BUS_TYPE_I2C, 0, 0, 1,
2594ef48a8ceSCorey Minyard                                      6, resource_source_len);
2595ef48a8ceSCorey Minyard 
2596ef48a8ceSCorey Minyard     /* Connection Speed.  Just set to 100K for now, it doesn't really matter. */
2597ef48a8ceSCorey Minyard     build_append_int_noprefix(var->buf, 100000, 4);
2598ef48a8ceSCorey Minyard     build_append_int_noprefix(var->buf, address, sizeof(address));
2599ef48a8ceSCorey Minyard 
2600ef48a8ceSCorey Minyard     /* This is a string, not a name, so just copy it directly in. */
2601ef48a8ceSCorey Minyard     g_array_append_vals(var->buf, resource_source, resource_source_len);
2602ef48a8ceSCorey Minyard 
2603ef48a8ceSCorey Minyard     return var;
2604ef48a8ceSCorey Minyard }
2605