1 /* Support for generating ACPI tables and passing them to Guests
3 * Copyright (C) 2015 Red Hat Inc
5 * Author: Michael S. Tsirkin <mst@redhat.com>
6 * Author: Igor Mammedov <imammedo@redhat.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, see <http://www.gnu.org/licenses/>.
27 #include "hw/acpi/aml-build.h"
29 GArray
*build_alloc_array(void)
31 return g_array_new(false, true /* clear */, 1);
34 void build_free_array(GArray
*array
)
36 g_array_free(array
, true);
39 void build_prepend_byte(GArray
*array
, uint8_t val
)
41 g_array_prepend_val(array
, val
);
44 void build_append_byte(GArray
*array
, uint8_t val
)
46 g_array_append_val(array
, val
);
49 void build_append_array(GArray
*array
, GArray
*val
)
51 g_array_append_vals(array
, val
->data
, val
->len
);
54 #define ACPI_NAMESEG_LEN 4
57 build_append_nameseg(GArray
*array
, const char *seg
)
59 /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
63 assert(len
<= ACPI_NAMESEG_LEN
);
65 g_array_append_vals(array
, seg
, len
);
66 /* Pad up to ACPI_NAMESEG_LEN characters if necessary. */
67 g_array_append_vals(array
, "____", ACPI_NAMESEG_LEN
- len
);
71 build_append_namestringv(GArray
*array
, const char *format
, va_list ap
)
73 /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
82 len
= vsnprintf(NULL
, 0, format
, va_len
);
85 s
= g_new(typeof(*s
), len
);
87 len
= vsnprintf(s
, len
, format
, ap
);
89 segs
= g_strsplit(s
, ".", 0);
99 * ACPI 5.0 spec: 20.2.2 Name Objects Encoding:
100 * "SegCount can be from 1 to 255"
102 assert(seg_count
> 0 && seg_count
<= 255);
104 /* handle RootPath || PrefixPath */
106 while (*s
== '\\' || *s
== '^') {
107 build_append_byte(array
, *s
);
114 build_append_byte(array
, 0x0); /* NullName */
116 build_append_nameseg(array
, s
);
121 build_append_byte(array
, 0x2E); /* DualNamePrefix */
122 build_append_nameseg(array
, s
);
123 build_append_nameseg(array
, segs
[1]);
126 build_append_byte(array
, 0x2F); /* MultiNamePrefix */
127 build_append_byte(array
, seg_count
);
129 /* handle the 1st segment manually due to prefix/root path */
130 build_append_nameseg(array
, s
);
132 /* add the rest of segments */
133 segs_iter
= segs
+ 1;
135 build_append_nameseg(array
, *segs_iter
);
143 void build_append_namestring(GArray
*array
, const char *format
, ...)
147 va_start(ap
, format
);
148 build_append_namestringv(array
, format
, ap
);
152 /* 5.4 Definition Block Encoding */
154 PACKAGE_LENGTH_1BYTE_SHIFT
= 6, /* Up to 63 - use extra 2 bits. */
155 PACKAGE_LENGTH_2BYTE_SHIFT
= 4,
156 PACKAGE_LENGTH_3BYTE_SHIFT
= 12,
157 PACKAGE_LENGTH_4BYTE_SHIFT
= 20,
160 void build_prepend_package_length(GArray
*package
, unsigned min_bytes
)
163 unsigned length
= package
->len
;
164 unsigned length_bytes
;
166 if (length
+ 1 < (1 << PACKAGE_LENGTH_1BYTE_SHIFT
)) {
168 } else if (length
+ 2 < (1 << PACKAGE_LENGTH_3BYTE_SHIFT
)) {
170 } else if (length
+ 3 < (1 << PACKAGE_LENGTH_4BYTE_SHIFT
)) {
176 /* Force length to at least min_bytes.
177 * This wastes memory but that's how bios did it.
179 length_bytes
= MAX(length_bytes
, min_bytes
);
181 /* PkgLength is the length of the inclusive length of the data. */
182 length
+= length_bytes
;
184 switch (length_bytes
) {
187 build_prepend_byte(package
, byte
);
190 byte
= length
>> PACKAGE_LENGTH_4BYTE_SHIFT
;
191 build_prepend_byte(package
, byte
);
192 length
&= (1 << PACKAGE_LENGTH_4BYTE_SHIFT
) - 1;
195 byte
= length
>> PACKAGE_LENGTH_3BYTE_SHIFT
;
196 build_prepend_byte(package
, byte
);
197 length
&= (1 << PACKAGE_LENGTH_3BYTE_SHIFT
) - 1;
200 byte
= length
>> PACKAGE_LENGTH_2BYTE_SHIFT
;
201 build_prepend_byte(package
, byte
);
202 length
&= (1 << PACKAGE_LENGTH_2BYTE_SHIFT
) - 1;
206 * Most significant two bits of byte zero indicate how many following bytes
207 * are in PkgLength encoding.
209 byte
= ((length_bytes
- 1) << PACKAGE_LENGTH_1BYTE_SHIFT
) | length
;
210 build_prepend_byte(package
, byte
);
213 void build_package(GArray
*package
, uint8_t op
, unsigned min_bytes
)
215 build_prepend_package_length(package
, min_bytes
);
216 build_prepend_byte(package
, op
);
219 void build_extop_package(GArray
*package
, uint8_t op
)
221 build_package(package
, op
, 1);
222 build_prepend_byte(package
, 0x5B); /* ExtOpPrefix */
225 void build_append_value(GArray
*table
, uint32_t value
, int size
)
232 prefix
= 0x0A; /* BytePrefix */
235 prefix
= 0x0B; /* WordPrefix */
238 prefix
= 0x0C; /* DWordPrefix */
244 build_append_byte(table
, prefix
);
245 for (i
= 0; i
< size
; ++i
) {
246 build_append_byte(table
, value
& 0xFF);
251 void build_append_int(GArray
*table
, uint32_t value
)
254 build_append_byte(table
, 0x00); /* ZeroOp */
255 } else if (value
== 0x01) {
256 build_append_byte(table
, 0x01); /* OneOp */
257 } else if (value
<= 0xFF) {
258 build_append_value(table
, value
, 1);
259 } else if (value
<= 0xFFFF) {
260 build_append_value(table
, value
, 2);
262 build_append_value(table
, value
, 4);