1 /* Support for generating ACPI tables and passing them to Guests 2 * 3 * Copyright (C) 2015 Red Hat Inc 4 * 5 * Author: Michael S. Tsirkin <mst@redhat.com> 6 * Author: Igor Mammedov <imammedo@redhat.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include <stdio.h> 23 #include <stdarg.h> 24 #include <assert.h> 25 #include <stdbool.h> 26 #include <string.h> 27 #include "hw/acpi/aml-build.h" 28 29 GArray *build_alloc_array(void) 30 { 31 return g_array_new(false, true /* clear */, 1); 32 } 33 34 void build_free_array(GArray *array) 35 { 36 g_array_free(array, true); 37 } 38 39 void build_prepend_byte(GArray *array, uint8_t val) 40 { 41 g_array_prepend_val(array, val); 42 } 43 44 void build_append_byte(GArray *array, uint8_t val) 45 { 46 g_array_append_val(array, val); 47 } 48 49 void build_append_array(GArray *array, GArray *val) 50 { 51 g_array_append_vals(array, val->data, val->len); 52 } 53 54 #define ACPI_NAMESEG_LEN 4 55 56 static void 57 build_append_nameseg(GArray *array, const char *seg) 58 { 59 /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */ 60 int len; 61 62 len = strlen(seg); 63 assert(len <= ACPI_NAMESEG_LEN); 64 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); 68 } 69 70 static void 71 build_append_namestringv(GArray *array, const char *format, va_list ap) 72 { 73 /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */ 74 char *s; 75 int len; 76 va_list va_len; 77 char **segs; 78 char **segs_iter; 79 int seg_count = 0; 80 81 va_copy(va_len, ap); 82 len = vsnprintf(NULL, 0, format, va_len); 83 va_end(va_len); 84 len += 1; 85 s = g_new(typeof(*s), len); 86 87 len = vsnprintf(s, len, format, ap); 88 89 segs = g_strsplit(s, ".", 0); 90 g_free(s); 91 92 /* count segments */ 93 segs_iter = segs; 94 while (*segs_iter) { 95 ++segs_iter; 96 ++seg_count; 97 } 98 /* 99 * ACPI 5.0 spec: 20.2.2 Name Objects Encoding: 100 * "SegCount can be from 1 to 255" 101 */ 102 assert(seg_count > 0 && seg_count <= 255); 103 104 /* handle RootPath || PrefixPath */ 105 s = *segs; 106 while (*s == '\\' || *s == '^') { 107 build_append_byte(array, *s); 108 ++s; 109 } 110 111 switch (seg_count) { 112 case 1: 113 if (!*s) { 114 build_append_byte(array, 0x0); /* NullName */ 115 } else { 116 build_append_nameseg(array, s); 117 } 118 break; 119 120 case 2: 121 build_append_byte(array, 0x2E); /* DualNamePrefix */ 122 build_append_nameseg(array, s); 123 build_append_nameseg(array, segs[1]); 124 break; 125 default: 126 build_append_byte(array, 0x2F); /* MultiNamePrefix */ 127 build_append_byte(array, seg_count); 128 129 /* handle the 1st segment manually due to prefix/root path */ 130 build_append_nameseg(array, s); 131 132 /* add the rest of segments */ 133 segs_iter = segs + 1; 134 while (*segs_iter) { 135 build_append_nameseg(array, *segs_iter); 136 ++segs_iter; 137 } 138 break; 139 } 140 g_strfreev(segs); 141 } 142 143 void build_append_namestring(GArray *array, const char *format, ...) 144 { 145 va_list ap; 146 147 va_start(ap, format); 148 build_append_namestringv(array, format, ap); 149 va_end(ap); 150 } 151 152 /* 5.4 Definition Block Encoding */ 153 enum { 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, 158 }; 159 160 void build_prepend_package_length(GArray *package) 161 { 162 uint8_t byte; 163 unsigned length = package->len; 164 unsigned length_bytes; 165 166 if (length + 1 < (1 << PACKAGE_LENGTH_1BYTE_SHIFT)) { 167 length_bytes = 1; 168 } else if (length + 2 < (1 << PACKAGE_LENGTH_3BYTE_SHIFT)) { 169 length_bytes = 2; 170 } else if (length + 3 < (1 << PACKAGE_LENGTH_4BYTE_SHIFT)) { 171 length_bytes = 3; 172 } else { 173 length_bytes = 4; 174 } 175 176 /* PkgLength is the length of the inclusive length of the data. */ 177 length += length_bytes; 178 179 switch (length_bytes) { 180 case 1: 181 byte = length; 182 build_prepend_byte(package, byte); 183 return; 184 case 4: 185 byte = length >> PACKAGE_LENGTH_4BYTE_SHIFT; 186 build_prepend_byte(package, byte); 187 length &= (1 << PACKAGE_LENGTH_4BYTE_SHIFT) - 1; 188 /* fall through */ 189 case 3: 190 byte = length >> PACKAGE_LENGTH_3BYTE_SHIFT; 191 build_prepend_byte(package, byte); 192 length &= (1 << PACKAGE_LENGTH_3BYTE_SHIFT) - 1; 193 /* fall through */ 194 case 2: 195 byte = length >> PACKAGE_LENGTH_2BYTE_SHIFT; 196 build_prepend_byte(package, byte); 197 length &= (1 << PACKAGE_LENGTH_2BYTE_SHIFT) - 1; 198 /* fall through */ 199 } 200 /* 201 * Most significant two bits of byte zero indicate how many following bytes 202 * are in PkgLength encoding. 203 */ 204 byte = ((length_bytes - 1) << PACKAGE_LENGTH_1BYTE_SHIFT) | length; 205 build_prepend_byte(package, byte); 206 } 207 208 void build_package(GArray *package, uint8_t op) 209 { 210 build_prepend_package_length(package); 211 build_prepend_byte(package, op); 212 } 213 214 void build_extop_package(GArray *package, uint8_t op) 215 { 216 build_package(package, op); 217 build_prepend_byte(package, 0x5B); /* ExtOpPrefix */ 218 } 219 220 void build_append_value(GArray *table, uint32_t value, int size) 221 { 222 uint8_t prefix; 223 int i; 224 225 switch (size) { 226 case 1: 227 prefix = 0x0A; /* BytePrefix */ 228 break; 229 case 2: 230 prefix = 0x0B; /* WordPrefix */ 231 break; 232 case 4: 233 prefix = 0x0C; /* DWordPrefix */ 234 break; 235 default: 236 assert(0); 237 return; 238 } 239 build_append_byte(table, prefix); 240 for (i = 0; i < size; ++i) { 241 build_append_byte(table, value & 0xFF); 242 value = value >> 8; 243 } 244 } 245 246 void build_append_int(GArray *table, uint32_t value) 247 { 248 if (value == 0x00) { 249 build_append_byte(table, 0x00); /* ZeroOp */ 250 } else if (value == 0x01) { 251 build_append_byte(table, 0x01); /* OneOp */ 252 } else if (value <= 0xFF) { 253 build_append_value(table, value, 1); 254 } else if (value <= 0xFFFF) { 255 build_append_value(table, value, 2); 256 } else { 257 build_append_value(table, value, 4); 258 } 259 } 260