]> Git Repo - qemu.git/blob - hw/acpi/aml-build.c
acpi: add aml_resource_template() helper
[qemu.git] / hw / acpi / aml-build.c
1 /* Support for generating ACPI tables and passing them to Guests
2  *
3  * Copyright (C) 2015 Red Hat Inc
4  *
5  * Author: Michael S. Tsirkin <[email protected]>
6  * Author: Igor Mammedov <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include "hw/acpi/aml-build.h"
28 #include "qemu/bswap.h"
29
30 GArray *build_alloc_array(void)
31 {
32     return g_array_new(false, true /* clear */, 1);
33 }
34
35 void build_free_array(GArray *array)
36 {
37     g_array_free(array, true);
38 }
39
40 void build_prepend_byte(GArray *array, uint8_t val)
41 {
42     g_array_prepend_val(array, val);
43 }
44
45 void build_append_byte(GArray *array, uint8_t val)
46 {
47     g_array_append_val(array, val);
48 }
49
50 void build_append_array(GArray *array, GArray *val)
51 {
52     g_array_append_vals(array, val->data, val->len);
53 }
54
55 #define ACPI_NAMESEG_LEN 4
56
57 static void
58 build_append_nameseg(GArray *array, const char *seg)
59 {
60     /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
61     int len;
62
63     len = strlen(seg);
64     assert(len <= ACPI_NAMESEG_LEN);
65
66     g_array_append_vals(array, seg, len);
67     /* Pad up to ACPI_NAMESEG_LEN characters if necessary. */
68     g_array_append_vals(array, "____", ACPI_NAMESEG_LEN - len);
69 }
70
71 static void
72 build_append_namestringv(GArray *array, const char *format, va_list ap)
73 {
74     /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
75     char *s;
76     int len;
77     va_list va_len;
78     char **segs;
79     char **segs_iter;
80     int seg_count = 0;
81
82     va_copy(va_len, ap);
83     len = vsnprintf(NULL, 0, format, va_len);
84     va_end(va_len);
85     len += 1;
86     s = g_new(typeof(*s), len);
87
88     len = vsnprintf(s, len, format, ap);
89
90     segs = g_strsplit(s, ".", 0);
91     g_free(s);
92
93     /* count segments */
94     segs_iter = segs;
95     while (*segs_iter) {
96         ++segs_iter;
97         ++seg_count;
98     }
99     /*
100      * ACPI 5.0 spec: 20.2.2 Name Objects Encoding:
101      * "SegCount can be from 1 to 255"
102      */
103     assert(seg_count > 0 && seg_count <= 255);
104
105     /* handle RootPath || PrefixPath */
106     s = *segs;
107     while (*s == '\\' || *s == '^') {
108         build_append_byte(array, *s);
109         ++s;
110     }
111
112     switch (seg_count) {
113     case 1:
114         if (!*s) {
115             build_append_byte(array, 0x0); /* NullName */
116         } else {
117             build_append_nameseg(array, s);
118         }
119         break;
120
121     case 2:
122         build_append_byte(array, 0x2E); /* DualNamePrefix */
123         build_append_nameseg(array, s);
124         build_append_nameseg(array, segs[1]);
125         break;
126     default:
127         build_append_byte(array, 0x2F); /* MultiNamePrefix */
128         build_append_byte(array, seg_count);
129
130         /* handle the 1st segment manually due to prefix/root path */
131         build_append_nameseg(array, s);
132
133         /* add the rest of segments */
134         segs_iter = segs + 1;
135         while (*segs_iter) {
136             build_append_nameseg(array, *segs_iter);
137             ++segs_iter;
138         }
139         break;
140     }
141     g_strfreev(segs);
142 }
143
144 void build_append_namestring(GArray *array, const char *format, ...)
145 {
146     va_list ap;
147
148     va_start(ap, format);
149     build_append_namestringv(array, format, ap);
150     va_end(ap);
151 }
152
153 /* 5.4 Definition Block Encoding */
154 enum {
155     PACKAGE_LENGTH_1BYTE_SHIFT = 6, /* Up to 63 - use extra 2 bits. */
156     PACKAGE_LENGTH_2BYTE_SHIFT = 4,
157     PACKAGE_LENGTH_3BYTE_SHIFT = 12,
158     PACKAGE_LENGTH_4BYTE_SHIFT = 20,
159 };
160
161 void build_prepend_package_length(GArray *package)
162 {
163     uint8_t byte;
164     unsigned length = package->len;
165     unsigned length_bytes;
166
167     if (length + 1 < (1 << PACKAGE_LENGTH_1BYTE_SHIFT)) {
168         length_bytes = 1;
169     } else if (length + 2 < (1 << PACKAGE_LENGTH_3BYTE_SHIFT)) {
170         length_bytes = 2;
171     } else if (length + 3 < (1 << PACKAGE_LENGTH_4BYTE_SHIFT)) {
172         length_bytes = 3;
173     } else {
174         length_bytes = 4;
175     }
176
177     /* PkgLength is the length of the inclusive length of the data. */
178     length += length_bytes;
179
180     switch (length_bytes) {
181     case 1:
182         byte = length;
183         build_prepend_byte(package, byte);
184         return;
185     case 4:
186         byte = length >> PACKAGE_LENGTH_4BYTE_SHIFT;
187         build_prepend_byte(package, byte);
188         length &= (1 << PACKAGE_LENGTH_4BYTE_SHIFT) - 1;
189         /* fall through */
190     case 3:
191         byte = length >> PACKAGE_LENGTH_3BYTE_SHIFT;
192         build_prepend_byte(package, byte);
193         length &= (1 << PACKAGE_LENGTH_3BYTE_SHIFT) - 1;
194         /* fall through */
195     case 2:
196         byte = length >> PACKAGE_LENGTH_2BYTE_SHIFT;
197         build_prepend_byte(package, byte);
198         length &= (1 << PACKAGE_LENGTH_2BYTE_SHIFT) - 1;
199         /* fall through */
200     }
201     /*
202      * Most significant two bits of byte zero indicate how many following bytes
203      * are in PkgLength encoding.
204      */
205     byte = ((length_bytes - 1) << PACKAGE_LENGTH_1BYTE_SHIFT) | length;
206     build_prepend_byte(package, byte);
207 }
208
209 void build_package(GArray *package, uint8_t op)
210 {
211     build_prepend_package_length(package);
212     build_prepend_byte(package, op);
213 }
214
215 void build_extop_package(GArray *package, uint8_t op)
216 {
217     build_package(package, op);
218     build_prepend_byte(package, 0x5B); /* ExtOpPrefix */
219 }
220
221 static void build_append_int_noprefix(GArray *table, uint64_t value, int size)
222 {
223     int i;
224
225     for (i = 0; i < size; ++i) {
226         build_append_byte(table, value & 0xFF);
227         value = value >> 8;
228     }
229 }
230
231 void build_append_int(GArray *table, uint64_t value)
232 {
233     if (value == 0x00) {
234         build_append_byte(table, 0x00); /* ZeroOp */
235     } else if (value == 0x01) {
236         build_append_byte(table, 0x01); /* OneOp */
237     } else if (value <= 0xFF) {
238         build_append_byte(table, 0x0A); /* BytePrefix */
239         build_append_int_noprefix(table, value, 1);
240     } else if (value <= 0xFFFF) {
241         build_append_byte(table, 0x0B); /* WordPrefix */
242         build_append_int_noprefix(table, value, 2);
243     } else if (value <= 0xFFFFFFFF) {
244         build_append_byte(table, 0x0C); /* DWordPrefix */
245         build_append_int_noprefix(table, value, 4);
246     } else {
247         build_append_byte(table, 0x0E); /* QWordPrefix */
248         build_append_int_noprefix(table, value, 8);
249     }
250 }
251
252 static GPtrArray *alloc_list;
253
254 static Aml *aml_alloc(void)
255 {
256     Aml *var = g_new0(typeof(*var), 1);
257
258     g_ptr_array_add(alloc_list, var);
259     var->block_flags = AML_NO_OPCODE;
260     var->buf = build_alloc_array();
261     return var;
262 }
263
264 static Aml *aml_opcode(uint8_t op)
265 {
266     Aml *var = aml_alloc();
267
268     var->op  = op;
269     var->block_flags = AML_OPCODE;
270     return var;
271 }
272
273 static Aml *aml_bundle(uint8_t op, AmlBlockFlags flags)
274 {
275     Aml *var = aml_alloc();
276
277     var->op  = op;
278     var->block_flags = flags;
279     return var;
280 }
281
282 static void aml_free(gpointer data)
283 {
284     Aml *var = data;
285     build_free_array(var->buf);
286 }
287
288 Aml *init_aml_allocator(void)
289 {
290     Aml *var;
291
292     assert(!alloc_list);
293     alloc_list = g_ptr_array_new_with_free_func(aml_free);
294     var = aml_alloc();
295     return var;
296 }
297
298 void free_aml_allocator(void)
299 {
300     g_ptr_array_free(alloc_list, true);
301     alloc_list = 0;
302 }
303
304 /* pack data with DefBuffer encoding */
305 static void build_buffer(GArray *array, uint8_t op)
306 {
307     GArray *data = build_alloc_array();
308
309     build_append_int(data, array->len);
310     g_array_prepend_vals(array, data->data, data->len);
311     build_free_array(data);
312     build_package(array, op);
313 }
314
315 void aml_append(Aml *parent_ctx, Aml *child)
316 {
317     switch (child->block_flags) {
318     case AML_OPCODE:
319         build_append_byte(parent_ctx->buf, child->op);
320         break;
321     case AML_EXT_PACKAGE:
322         build_extop_package(child->buf, child->op);
323         break;
324     case AML_PACKAGE:
325         build_package(child->buf, child->op);
326         break;
327     case AML_RES_TEMPLATE:
328         build_append_byte(child->buf, 0x79); /* EndTag */
329         /*
330          * checksum operations are treated as succeeded if checksum
331          * field is zero. [ACPI Spec 1.0b, 6.4.2.8 End Tag]
332          */
333         build_append_byte(child->buf, 0);
334         /* fall through, to pack resources in buffer */
335     case AML_BUFFER:
336         build_buffer(child->buf, child->op);
337         break;
338     case AML_NO_OPCODE:
339         break;
340     default:
341         assert(0);
342         break;
343     }
344     build_append_array(parent_ctx->buf, child->buf);
345 }
346
347 /* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefScope */
348 Aml *aml_scope(const char *name_format, ...)
349 {
350     va_list ap;
351     Aml *var = aml_bundle(0x10 /* ScopeOp */, AML_PACKAGE);
352     va_start(ap, name_format);
353     build_append_namestringv(var->buf, name_format, ap);
354     va_end(ap);
355     return var;
356 }
357
358 /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefReturn */
359 Aml *aml_return(Aml *val)
360 {
361     Aml *var = aml_opcode(0xA4 /* ReturnOp */);
362     aml_append(var, val);
363     return var;
364 }
365
366 /*
367  * ACPI 1.0b: 16.2.3 Data Objects Encoding:
368  * encodes: ByteConst, WordConst, DWordConst, QWordConst, ZeroOp, OneOp
369  */
370 Aml *aml_int(const uint64_t val)
371 {
372     Aml *var = aml_alloc();
373     build_append_int(var->buf, val);
374     return var;
375 }
376
377 /*
378  * helper to construct NameString, which returns Aml object
379  * for using with aml_append or other aml_* terms
380  */
381 Aml *aml_name(const char *name_format, ...)
382 {
383     va_list ap;
384     Aml *var = aml_alloc();
385     va_start(ap, name_format);
386     build_append_namestringv(var->buf, name_format, ap);
387     va_end(ap);
388     return var;
389 }
390
391 /* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefName */
392 Aml *aml_name_decl(const char *name, Aml *val)
393 {
394     Aml *var = aml_opcode(0x08 /* NameOp */);
395     build_append_namestring(var->buf, "%s", name);
396     aml_append(var, val);
397     return var;
398 }
399
400 /* ACPI 1.0b: 16.2.6.1 Arg Objects Encoding */
401 Aml *aml_arg(int pos)
402 {
403     Aml *var;
404     uint8_t op = 0x68 /* ARG0 op */ + pos;
405
406     assert(pos <= 6);
407     var = aml_opcode(op);
408     return var;
409 }
410
411 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefStore */
412 Aml *aml_store(Aml *val, Aml *target)
413 {
414     Aml *var = aml_opcode(0x70 /* StoreOp */);
415     aml_append(var, val);
416     aml_append(var, target);
417     return var;
418 }
419
420 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAnd */
421 Aml *aml_and(Aml *arg1, Aml *arg2)
422 {
423     Aml *var = aml_opcode(0x7B /* AndOp */);
424     aml_append(var, arg1);
425     aml_append(var, arg2);
426     build_append_int(var->buf, 0x00 /* NullNameOp */);
427     return var;
428 }
429
430 /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
431 Aml *aml_notify(Aml *arg1, Aml *arg2)
432 {
433     Aml *var = aml_opcode(0x86 /* NotifyOp */);
434     aml_append(var, arg1);
435     aml_append(var, arg2);
436     return var;
437 }
438
439 /* helper to call method with 1 argument */
440 Aml *aml_call1(const char *method, Aml *arg1)
441 {
442     Aml *var = aml_alloc();
443     build_append_namestring(var->buf, "%s", method);
444     aml_append(var, arg1);
445     return var;
446 }
447
448 /* helper to call method with 2 arguments */
449 Aml *aml_call2(const char *method, Aml *arg1, Aml *arg2)
450 {
451     Aml *var = aml_alloc();
452     build_append_namestring(var->buf, "%s", method);
453     aml_append(var, arg1);
454     aml_append(var, arg2);
455     return var;
456 }
457
458 /* helper to call method with 3 arguments */
459 Aml *aml_call3(const char *method, Aml *arg1, Aml *arg2, Aml *arg3)
460 {
461     Aml *var = aml_alloc();
462     build_append_namestring(var->buf, "%s", method);
463     aml_append(var, arg1);
464     aml_append(var, arg2);
465     aml_append(var, arg3);
466     return var;
467 }
468
469 /* helper to call method with 4 arguments */
470 Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4)
471 {
472     Aml *var = aml_alloc();
473     build_append_namestring(var->buf, "%s", method);
474     aml_append(var, arg1);
475     aml_append(var, arg2);
476     aml_append(var, arg3);
477     aml_append(var, arg4);
478     return var;
479 }
480
481 /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefIfElse */
482 Aml *aml_if(Aml *predicate)
483 {
484     Aml *var = aml_bundle(0xA0 /* IfOp */, AML_PACKAGE);
485     aml_append(var, predicate);
486     return var;
487 }
488
489 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */
490 Aml *aml_method(const char *name, int arg_count)
491 {
492     Aml *var = aml_bundle(0x14 /* MethodOp */, AML_PACKAGE);
493     build_append_namestring(var->buf, "%s", name);
494     build_append_byte(var->buf, arg_count); /* MethodFlags: ArgCount */
495     return var;
496 }
497
498 /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefDevice */
499 Aml *aml_device(const char *name_format, ...)
500 {
501     va_list ap;
502     Aml *var = aml_bundle(0x82 /* DeviceOp */, AML_EXT_PACKAGE);
503     va_start(ap, name_format);
504     build_append_namestringv(var->buf, name_format, ap);
505     va_end(ap);
506     return var;
507 }
508
509 /* ACPI 1.0b: 6.4.1 ASL Macros for Resource Descriptors */
510 Aml *aml_resource_template(void)
511 {
512     /* ResourceTemplate is a buffer of Resources with EndTag at the end */
513     Aml *var = aml_bundle(0x11 /* BufferOp */, AML_RES_TEMPLATE);
514     return var;
515 }
516
517 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer */
518 Aml *aml_buffer(void)
519 {
520     Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
521     return var;
522 }
523
524 /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefPackage */
525 Aml *aml_package(uint8_t num_elements)
526 {
527     Aml *var = aml_bundle(0x12 /* PackageOp */, AML_PACKAGE);
528     build_append_byte(var->buf, num_elements);
529     return var;
530 }
This page took 0.050822 seconds and 4 git commands to generate.