diff options
Diffstat (limited to 'qemu/hw/acpi')
-rw-r--r-- | qemu/hw/acpi/Makefile.objs | 8 | ||||
-rw-r--r-- | qemu/hw/acpi/acpi_interface.c | 16 | ||||
-rw-r--r-- | qemu/hw/acpi/aml-build.c | 1565 | ||||
-rw-r--r-- | qemu/hw/acpi/bios-linker-loader.c | 240 | ||||
-rw-r--r-- | qemu/hw/acpi/core.c | 717 | ||||
-rw-r--r-- | qemu/hw/acpi/cpu_hotplug.c | 79 | ||||
-rw-r--r-- | qemu/hw/acpi/cpu_hotplug_acpi_table.c | 136 | ||||
-rw-r--r-- | qemu/hw/acpi/ich9.c | 477 | ||||
-rw-r--r-- | qemu/hw/acpi/memory_hotplug.c | 312 | ||||
-rw-r--r-- | qemu/hw/acpi/memory_hotplug_acpi_table.c | 262 | ||||
-rw-r--r-- | qemu/hw/acpi/nvdimm.c | 706 | ||||
-rw-r--r-- | qemu/hw/acpi/pcihp.c | 336 | ||||
-rw-r--r-- | qemu/hw/acpi/piix4.c | 645 | ||||
-rw-r--r-- | qemu/hw/acpi/tco.c | 265 |
14 files changed, 0 insertions, 5764 deletions
diff --git a/qemu/hw/acpi/Makefile.objs b/qemu/hw/acpi/Makefile.objs deleted file mode 100644 index faee86c5c..000000000 --- a/qemu/hw/acpi/Makefile.objs +++ /dev/null @@ -1,8 +0,0 @@ -common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o -common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o -common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o cpu_hotplug_acpi_table.o -common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o -obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o -common-obj-$(CONFIG_ACPI) += acpi_interface.o -common-obj-$(CONFIG_ACPI) += bios-linker-loader.o -common-obj-$(CONFIG_ACPI) += aml-build.o diff --git a/qemu/hw/acpi/acpi_interface.c b/qemu/hw/acpi/acpi_interface.c deleted file mode 100644 index d82131326..000000000 --- a/qemu/hw/acpi/acpi_interface.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "qemu/osdep.h" -#include "hw/acpi/acpi_dev_interface.h" -#include "qemu/module.h" - -static void register_types(void) -{ - static const TypeInfo acpi_dev_if_info = { - .name = TYPE_ACPI_DEVICE_IF, - .parent = TYPE_INTERFACE, - .class_size = sizeof(AcpiDeviceIfClass), - }; - - type_register_static(&acpi_dev_if_info); -} - -type_init(register_types) diff --git a/qemu/hw/acpi/aml-build.c b/qemu/hw/acpi/aml-build.c deleted file mode 100644 index ab89ca638..000000000 --- a/qemu/hw/acpi/aml-build.c +++ /dev/null @@ -1,1565 +0,0 @@ -/* Support for generating ACPI tables and passing them to Guests - * - * Copyright (C) 2015 Red Hat Inc - * - * Author: Michael S. Tsirkin <mst@redhat.com> - * Author: Igor Mammedov <imammedo@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include <glib/gprintf.h> -#include "hw/acpi/aml-build.h" -#include "qemu/bswap.h" -#include "qemu/bitops.h" -#include "hw/acpi/bios-linker-loader.h" - -static GArray *build_alloc_array(void) -{ - return g_array_new(false, true /* clear */, 1); -} - -static void build_free_array(GArray *array) -{ - g_array_free(array, true); -} - -static void build_prepend_byte(GArray *array, uint8_t val) -{ - g_array_prepend_val(array, val); -} - -static void build_append_byte(GArray *array, uint8_t val) -{ - g_array_append_val(array, val); -} - -static void build_append_array(GArray *array, GArray *val) -{ - g_array_append_vals(array, val->data, val->len); -} - -#define ACPI_NAMESEG_LEN 4 - -static void -build_append_nameseg(GArray *array, const char *seg) -{ - int len; - - len = strlen(seg); - assert(len <= ACPI_NAMESEG_LEN); - - g_array_append_vals(array, seg, len); - /* Pad up to ACPI_NAMESEG_LEN characters if necessary. */ - g_array_append_vals(array, "____", ACPI_NAMESEG_LEN - len); -} - -static void GCC_FMT_ATTR(2, 0) -build_append_namestringv(GArray *array, const char *format, va_list ap) -{ - char *s; - char **segs; - char **segs_iter; - int seg_count = 0; - - s = g_strdup_vprintf(format, ap); - segs = g_strsplit(s, ".", 0); - g_free(s); - - /* count segments */ - segs_iter = segs; - while (*segs_iter) { - ++segs_iter; - ++seg_count; - } - /* - * ACPI 5.0 spec: 20.2.2 Name Objects Encoding: - * "SegCount can be from 1 to 255" - */ - assert(seg_count > 0 && seg_count <= 255); - - /* handle RootPath || PrefixPath */ - s = *segs; - while (*s == '\\' || *s == '^') { - build_append_byte(array, *s); - ++s; - } - - switch (seg_count) { - case 1: - if (!*s) { - build_append_byte(array, 0x00); /* NullName */ - } else { - build_append_nameseg(array, s); - } - break; - - case 2: - build_append_byte(array, 0x2E); /* DualNamePrefix */ - build_append_nameseg(array, s); - build_append_nameseg(array, segs[1]); - break; - default: - build_append_byte(array, 0x2F); /* MultiNamePrefix */ - build_append_byte(array, seg_count); - - /* handle the 1st segment manually due to prefix/root path */ - build_append_nameseg(array, s); - - /* add the rest of segments */ - segs_iter = segs + 1; - while (*segs_iter) { - build_append_nameseg(array, *segs_iter); - ++segs_iter; - } - break; - } - g_strfreev(segs); -} - -GCC_FMT_ATTR(2, 3) -static void build_append_namestring(GArray *array, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - build_append_namestringv(array, format, ap); - va_end(ap); -} - -/* 5.4 Definition Block Encoding */ -enum { - PACKAGE_LENGTH_1BYTE_SHIFT = 6, /* Up to 63 - use extra 2 bits. */ - PACKAGE_LENGTH_2BYTE_SHIFT = 4, - PACKAGE_LENGTH_3BYTE_SHIFT = 12, - PACKAGE_LENGTH_4BYTE_SHIFT = 20, -}; - -static void -build_prepend_package_length(GArray *package, unsigned length, bool incl_self) -{ - uint8_t byte; - unsigned length_bytes; - - if (length + 1 < (1 << PACKAGE_LENGTH_1BYTE_SHIFT)) { - length_bytes = 1; - } else if (length + 2 < (1 << PACKAGE_LENGTH_3BYTE_SHIFT)) { - length_bytes = 2; - } else if (length + 3 < (1 << PACKAGE_LENGTH_4BYTE_SHIFT)) { - length_bytes = 3; - } else { - length_bytes = 4; - } - - /* - * NamedField uses PkgLength encoding but it doesn't include length - * of PkgLength itself. - */ - if (incl_self) { - /* - * PkgLength is the length of the inclusive length of the data - * and PkgLength's length itself when used for terms with - * explitit length. - */ - length += length_bytes; - } - - switch (length_bytes) { - case 1: - byte = length; - build_prepend_byte(package, byte); - return; - case 4: - byte = length >> PACKAGE_LENGTH_4BYTE_SHIFT; - build_prepend_byte(package, byte); - length &= (1 << PACKAGE_LENGTH_4BYTE_SHIFT) - 1; - /* fall through */ - case 3: - byte = length >> PACKAGE_LENGTH_3BYTE_SHIFT; - build_prepend_byte(package, byte); - length &= (1 << PACKAGE_LENGTH_3BYTE_SHIFT) - 1; - /* fall through */ - case 2: - byte = length >> PACKAGE_LENGTH_2BYTE_SHIFT; - build_prepend_byte(package, byte); - length &= (1 << PACKAGE_LENGTH_2BYTE_SHIFT) - 1; - /* fall through */ - } - /* - * Most significant two bits of byte zero indicate how many following bytes - * are in PkgLength encoding. - */ - byte = ((length_bytes - 1) << PACKAGE_LENGTH_1BYTE_SHIFT) | length; - build_prepend_byte(package, byte); -} - -static void -build_append_pkg_length(GArray *array, unsigned length, bool incl_self) -{ - GArray *tmp = build_alloc_array(); - - build_prepend_package_length(tmp, length, incl_self); - build_append_array(array, tmp); - build_free_array(tmp); -} - -static void build_package(GArray *package, uint8_t op) -{ - build_prepend_package_length(package, package->len, true); - build_prepend_byte(package, op); -} - -static void build_extop_package(GArray *package, uint8_t op) -{ - build_package(package, op); - build_prepend_byte(package, 0x5B); /* ExtOpPrefix */ -} - -static void build_append_int_noprefix(GArray *table, uint64_t value, int size) -{ - int i; - - for (i = 0; i < size; ++i) { - build_append_byte(table, value & 0xFF); - value = value >> 8; - } -} - -static void build_append_int(GArray *table, uint64_t value) -{ - if (value == 0x00) { - build_append_byte(table, 0x00); /* ZeroOp */ - } else if (value == 0x01) { - build_append_byte(table, 0x01); /* OneOp */ - } else if (value <= 0xFF) { - build_append_byte(table, 0x0A); /* BytePrefix */ - build_append_int_noprefix(table, value, 1); - } else if (value <= 0xFFFF) { - build_append_byte(table, 0x0B); /* WordPrefix */ - build_append_int_noprefix(table, value, 2); - } else if (value <= 0xFFFFFFFF) { - build_append_byte(table, 0x0C); /* DWordPrefix */ - build_append_int_noprefix(table, value, 4); - } else { - build_append_byte(table, 0x0E); /* QWordPrefix */ - build_append_int_noprefix(table, value, 8); - } -} - -/* - * Build NAME(XXXX, 0x00000000) where 0x00000000 is encoded as a dword, - * and return the offset to 0x00000000 for runtime patching. - * - * Warning: runtime patching is best avoided. Only use this as - * a replacement for DataTableRegion (for guests that don't - * support it). - */ -int -build_append_named_dword(GArray *array, const char *name_format, ...) -{ - int offset; - va_list ap; - - build_append_byte(array, 0x08); /* NameOp */ - va_start(ap, name_format); - build_append_namestringv(array, name_format, ap); - va_end(ap); - - build_append_byte(array, 0x0C); /* DWordPrefix */ - - offset = array->len; - build_append_int_noprefix(array, 0x00000000, 4); - assert(array->len == offset + 4); - - return offset; -} - -static GPtrArray *alloc_list; - -static Aml *aml_alloc(void) -{ - Aml *var = g_new0(typeof(*var), 1); - - g_ptr_array_add(alloc_list, var); - var->block_flags = AML_NO_OPCODE; - var->buf = build_alloc_array(); - return var; -} - -static Aml *aml_opcode(uint8_t op) -{ - Aml *var = aml_alloc(); - - var->op = op; - var->block_flags = AML_OPCODE; - return var; -} - -static Aml *aml_bundle(uint8_t op, AmlBlockFlags flags) -{ - Aml *var = aml_alloc(); - - var->op = op; - var->block_flags = flags; - return var; -} - -static void aml_free(gpointer data, gpointer user_data) -{ - Aml *var = data; - build_free_array(var->buf); - g_free(var); -} - -Aml *init_aml_allocator(void) -{ - Aml *var; - - assert(!alloc_list); - alloc_list = g_ptr_array_new(); - var = aml_alloc(); - return var; -} - -void free_aml_allocator(void) -{ - g_ptr_array_foreach(alloc_list, aml_free, NULL); - g_ptr_array_free(alloc_list, true); - alloc_list = 0; -} - -/* pack data with DefBuffer encoding */ -static void build_buffer(GArray *array, uint8_t op) -{ - GArray *data = build_alloc_array(); - - build_append_int(data, array->len); - g_array_prepend_vals(array, data->data, data->len); - build_free_array(data); - build_package(array, op); -} - -void aml_append(Aml *parent_ctx, Aml *child) -{ - GArray *buf = build_alloc_array(); - build_append_array(buf, child->buf); - - switch (child->block_flags) { - case AML_OPCODE: - build_append_byte(parent_ctx->buf, child->op); - break; - case AML_EXT_PACKAGE: - build_extop_package(buf, child->op); - break; - case AML_PACKAGE: - build_package(buf, child->op); - break; - case AML_RES_TEMPLATE: - build_append_byte(buf, 0x79); /* EndTag */ - /* - * checksum operations are treated as succeeded if checksum - * field is zero. [ACPI Spec 1.0b, 6.4.2.8 End Tag] - */ - build_append_byte(buf, 0); - /* fall through, to pack resources in buffer */ - case AML_BUFFER: - build_buffer(buf, child->op); - break; - case AML_NO_OPCODE: - break; - default: - assert(0); - break; - } - build_append_array(parent_ctx->buf, buf); - build_free_array(buf); -} - -/* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefScope */ -Aml *aml_scope(const char *name_format, ...) -{ - va_list ap; - Aml *var = aml_bundle(0x10 /* ScopeOp */, AML_PACKAGE); - va_start(ap, name_format); - build_append_namestringv(var->buf, name_format, ap); - va_end(ap); - return var; -} - -/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefReturn */ -Aml *aml_return(Aml *val) -{ - Aml *var = aml_opcode(0xA4 /* ReturnOp */); - aml_append(var, val); - return var; -} - -/* - * ACPI 1.0b: 16.2.3 Data Objects Encoding: - * encodes: ByteConst, WordConst, DWordConst, QWordConst, ZeroOp, OneOp - */ -Aml *aml_int(const uint64_t val) -{ - Aml *var = aml_alloc(); - build_append_int(var->buf, val); - return var; -} - -/* - * helper to construct NameString, which returns Aml object - * for using with aml_append or other aml_* terms - */ -Aml *aml_name(const char *name_format, ...) -{ - va_list ap; - Aml *var = aml_alloc(); - va_start(ap, name_format); - build_append_namestringv(var->buf, name_format, ap); - va_end(ap); - return var; -} - -/* ACPI 1.0b: 16.2.5.1 Namespace Modifier Objects Encoding: DefName */ -Aml *aml_name_decl(const char *name, Aml *val) -{ - Aml *var = aml_opcode(0x08 /* NameOp */); - build_append_namestring(var->buf, "%s", name); - aml_append(var, val); - return var; -} - -/* ACPI 1.0b: 16.2.6.1 Arg Objects Encoding */ -Aml *aml_arg(int pos) -{ - Aml *var; - uint8_t op = 0x68 /* ARG0 op */ + pos; - - assert(pos <= 6); - var = aml_opcode(op); - return var; -} - -/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToInteger */ -Aml *aml_to_integer(Aml *arg) -{ - Aml *var = aml_opcode(0x99 /* ToIntegerOp */); - aml_append(var, arg); - build_append_byte(var->buf, 0x00 /* NullNameOp */); - return var; -} - -/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToHexString */ -Aml *aml_to_hexstring(Aml *src, Aml *dst) -{ - Aml *var = aml_opcode(0x98 /* ToHexStringOp */); - aml_append(var, src); - if (dst) { - aml_append(var, dst); - } else { - build_append_byte(var->buf, 0x00 /* NullNameOp */); - } - return var; -} - -/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToBuffer */ -Aml *aml_to_buffer(Aml *src, Aml *dst) -{ - Aml *var = aml_opcode(0x96 /* ToBufferOp */); - aml_append(var, src); - if (dst) { - aml_append(var, dst); - } else { - build_append_byte(var->buf, 0x00 /* NullNameOp */); - } - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefStore */ -Aml *aml_store(Aml *val, Aml *target) -{ - Aml *var = aml_opcode(0x70 /* StoreOp */); - aml_append(var, val); - aml_append(var, target); - return var; -} - -/** - * build_opcode_2arg_dst: - * @op: 1-byte opcode - * @arg1: 1st operand - * @arg2: 2nd operand - * @dst: optional target to store to, set to NULL if it's not required - * - * An internal helper to compose AML terms that have - * "Op Operand Operand Target" - * pattern. - * - * Returns: The newly allocated and composed according to patter Aml object. - */ -static Aml * -build_opcode_2arg_dst(uint8_t op, Aml *arg1, Aml *arg2, Aml *dst) -{ - Aml *var = aml_opcode(op); - aml_append(var, arg1); - aml_append(var, arg2); - if (dst) { - aml_append(var, dst); - } else { - build_append_byte(var->buf, 0x00 /* NullNameOp */); - } - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAnd */ -Aml *aml_and(Aml *arg1, Aml *arg2, Aml *dst) -{ - return build_opcode_2arg_dst(0x7B /* AndOp */, arg1, arg2, dst); -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefOr */ -Aml *aml_or(Aml *arg1, Aml *arg2, Aml *dst) -{ - return build_opcode_2arg_dst(0x7D /* OrOp */, arg1, arg2, dst); -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLOr */ -Aml *aml_lor(Aml *arg1, Aml *arg2) -{ - Aml *var = aml_opcode(0x91 /* LOrOp */); - aml_append(var, arg1); - aml_append(var, arg2); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftLeft */ -Aml *aml_shiftleft(Aml *arg1, Aml *count) -{ - return build_opcode_2arg_dst(0x79 /* ShiftLeftOp */, arg1, count, NULL); -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftRight */ -Aml *aml_shiftright(Aml *arg1, Aml *count, Aml *dst) -{ - return build_opcode_2arg_dst(0x7A /* ShiftRightOp */, arg1, count, dst); -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLLess */ -Aml *aml_lless(Aml *arg1, Aml *arg2) -{ - Aml *var = aml_opcode(0x95 /* LLessOp */); - aml_append(var, arg1); - aml_append(var, arg2); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAdd */ -Aml *aml_add(Aml *arg1, Aml *arg2, Aml *dst) -{ - return build_opcode_2arg_dst(0x72 /* AddOp */, arg1, arg2, dst); -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSubtract */ -Aml *aml_subtract(Aml *arg1, Aml *arg2, Aml *dst) -{ - return build_opcode_2arg_dst(0x74 /* SubtractOp */, arg1, arg2, dst); -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIncrement */ -Aml *aml_increment(Aml *arg) -{ - Aml *var = aml_opcode(0x75 /* IncrementOp */); - aml_append(var, arg); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDecrement */ -Aml *aml_decrement(Aml *arg) -{ - Aml *var = aml_opcode(0x76 /* DecrementOp */); - aml_append(var, arg); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIndex */ -Aml *aml_index(Aml *arg1, Aml *idx) -{ - return build_opcode_2arg_dst(0x88 /* IndexOp */, arg1, idx, NULL); -} - -/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */ -Aml *aml_notify(Aml *arg1, Aml *arg2) -{ - Aml *var = aml_opcode(0x86 /* NotifyOp */); - aml_append(var, arg1); - aml_append(var, arg2); - return var; -} - -/* helper to call method with 1 argument */ -Aml *aml_call0(const char *method) -{ - Aml *var = aml_alloc(); - build_append_namestring(var->buf, "%s", method); - return var; -} - -/* helper to call method with 1 argument */ -Aml *aml_call1(const char *method, Aml *arg1) -{ - Aml *var = aml_alloc(); - build_append_namestring(var->buf, "%s", method); - aml_append(var, arg1); - return var; -} - -/* helper to call method with 2 arguments */ -Aml *aml_call2(const char *method, Aml *arg1, Aml *arg2) -{ - Aml *var = aml_alloc(); - build_append_namestring(var->buf, "%s", method); - aml_append(var, arg1); - aml_append(var, arg2); - return var; -} - -/* helper to call method with 3 arguments */ -Aml *aml_call3(const char *method, Aml *arg1, Aml *arg2, Aml *arg3) -{ - Aml *var = aml_alloc(); - build_append_namestring(var->buf, "%s", method); - aml_append(var, arg1); - aml_append(var, arg2); - aml_append(var, arg3); - return var; -} - -/* helper to call method with 4 arguments */ -Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4) -{ - Aml *var = aml_alloc(); - build_append_namestring(var->buf, "%s", method); - aml_append(var, arg1); - aml_append(var, arg2); - aml_append(var, arg3); - aml_append(var, arg4); - return var; -} - -/* - * ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor - * Type 1, Large Item Name 0xC - */ - -static Aml *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) -{ - Aml *var = aml_alloc(); - const uint16_t min_desc_len = 0x16; - uint16_t resource_source_name_len, length; - uint16_t pin_table_offset, resource_source_name_offset, vendor_data_offset; - uint32_t i; - - assert(resource_source_name); - resource_source_name_len = strlen(resource_source_name) + 1; - length = min_desc_len + resource_source_name_len + vendor_data_len; - pin_table_offset = min_desc_len + 1; - resource_source_name_offset = pin_table_offset + pin_count * 2; - vendor_data_offset = resource_source_name_offset + resource_source_name_len; - - build_append_byte(var->buf, 0x8C); /* GPIO Connection Descriptor */ - build_append_int_noprefix(var->buf, length, 2); /* Length */ - build_append_byte(var->buf, 1); /* Revision ID */ - build_append_byte(var->buf, type); /* GPIO Connection Type */ - /* General Flags (2 bytes) */ - build_append_int_noprefix(var->buf, con_and_pro, 2); - /* Interrupt and IO Flags (2 bytes) */ - build_append_int_noprefix(var->buf, flags, 2); - /* Pin Configuration 0 = Default 1 = Pull-up 2 = Pull-down 3 = No Pull */ - build_append_byte(var->buf, pin_config); - /* Output Drive Strength (2 bytes) */ - build_append_int_noprefix(var->buf, output_drive, 2); - /* Debounce Timeout (2 bytes) */ - build_append_int_noprefix(var->buf, debounce_timeout, 2); - /* Pin Table Offset (2 bytes) */ - build_append_int_noprefix(var->buf, pin_table_offset, 2); - build_append_byte(var->buf, 0); /* Resource Source Index */ - /* Resource Source Name Offset (2 bytes) */ - build_append_int_noprefix(var->buf, resource_source_name_offset, 2); - /* Vendor Data Offset (2 bytes) */ - build_append_int_noprefix(var->buf, vendor_data_offset, 2); - /* Vendor Data Length (2 bytes) */ - build_append_int_noprefix(var->buf, vendor_data_len, 2); - /* Pin Number (2n bytes)*/ - for (i = 0; i < pin_count; i++) { - build_append_int_noprefix(var->buf, pin_list[i], 2); - } - - /* Resource Source Name */ - build_append_namestring(var->buf, "%s", resource_source_name); - build_append_byte(var->buf, '\0'); - - /* Vendor-defined Data */ - if (vendor_data != NULL) { - g_array_append_vals(var->buf, vendor_data, vendor_data_len); - } - - return var; -} - -/* - * ACPI 5.0: 19.5.53 - * GpioInt(GPIO Interrupt Connection Resource Descriptor Macro) - */ -Aml *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) -{ - uint8_t flags = edge_level | (active_level << 1) | (shared << 3); - - return aml_gpio_connection(AML_INTERRUPT_CONNECTION, con_and_pro, flags, - pin_config, 0, debounce_timeout, pin_list, - pin_count, resource_source_name, vendor_data, - vendor_data_len); -} - -/* - * ACPI 1.0b: 6.4.3.4 32-Bit Fixed Location Memory Range Descriptor - * (Type 1, Large Item Name 0x6) - */ -Aml *aml_memory32_fixed(uint32_t addr, uint32_t size, - AmlReadAndWrite read_and_write) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x86); /* Memory32Fixed Resource Descriptor */ - build_append_byte(var->buf, 9); /* Length, bits[7:0] value = 9 */ - build_append_byte(var->buf, 0); /* Length, bits[15:8] value = 0 */ - build_append_byte(var->buf, read_and_write); /* Write status, 1 rw 0 ro */ - - /* Range base address */ - build_append_byte(var->buf, extract32(addr, 0, 8)); /* bits[7:0] */ - build_append_byte(var->buf, extract32(addr, 8, 8)); /* bits[15:8] */ - build_append_byte(var->buf, extract32(addr, 16, 8)); /* bits[23:16] */ - build_append_byte(var->buf, extract32(addr, 24, 8)); /* bits[31:24] */ - - /* Range length */ - build_append_byte(var->buf, extract32(size, 0, 8)); /* bits[7:0] */ - build_append_byte(var->buf, extract32(size, 8, 8)); /* bits[15:8] */ - build_append_byte(var->buf, extract32(size, 16, 8)); /* bits[23:16] */ - build_append_byte(var->buf, extract32(size, 24, 8)); /* bits[31:24] */ - return var; -} - -/* - * ACPI 5.0: 6.4.3.6 Extended Interrupt Descriptor - * Type 1, Large Item Name 0x9 - */ -Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro, - AmlLevelAndEdge level_and_edge, - AmlActiveHighAndLow high_and_low, AmlShared shared, - uint32_t *irq_list, uint8_t irq_count) -{ - int i; - Aml *var = aml_alloc(); - uint8_t irq_flags = con_and_pro | (level_and_edge << 1) - | (high_and_low << 2) | (shared << 3); - const int header_bytes_in_len = 2; - uint16_t len = header_bytes_in_len + irq_count * sizeof(uint32_t); - - assert(irq_count > 0); - - build_append_byte(var->buf, 0x89); /* Extended irq descriptor */ - build_append_byte(var->buf, len & 0xFF); /* Length, bits[7:0] */ - build_append_byte(var->buf, len >> 8); /* Length, bits[15:8] */ - build_append_byte(var->buf, irq_flags); /* Interrupt Vector Information. */ - build_append_byte(var->buf, irq_count); /* Interrupt table length */ - - /* Interrupt Number List */ - for (i = 0; i < irq_count; i++) { - build_append_int_noprefix(var->buf, irq_list[i], 4); - } - return var; -} - -/* ACPI 1.0b: 6.4.2.5 I/O Port Descriptor */ -Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base, - uint8_t aln, uint8_t len) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x47); /* IO port descriptor */ - build_append_byte(var->buf, dec); - build_append_byte(var->buf, min_base & 0xff); - build_append_byte(var->buf, (min_base >> 8) & 0xff); - build_append_byte(var->buf, max_base & 0xff); - build_append_byte(var->buf, (max_base >> 8) & 0xff); - build_append_byte(var->buf, aln); - build_append_byte(var->buf, len); - return var; -} - -/* - * ACPI 1.0b: 6.4.2.1.1 ASL Macro for IRQ Descriptor - * - * More verbose description at: - * ACPI 5.0: 19.5.64 IRQNoFlags (Interrupt Resource Descriptor Macro) - * 6.4.2.1 IRQ Descriptor - */ -Aml *aml_irq_no_flags(uint8_t irq) -{ - uint16_t irq_mask; - Aml *var = aml_alloc(); - - assert(irq < 16); - build_append_byte(var->buf, 0x22); /* IRQ descriptor 2 byte form */ - - irq_mask = 1U << irq; - build_append_byte(var->buf, irq_mask & 0xFF); /* IRQ mask bits[7:0] */ - build_append_byte(var->buf, irq_mask >> 8); /* IRQ mask bits[15:8] */ - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLNot */ -Aml *aml_lnot(Aml *arg) -{ - Aml *var = aml_opcode(0x92 /* LNotOp */); - aml_append(var, arg); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLEqual */ -Aml *aml_equal(Aml *arg1, Aml *arg2) -{ - Aml *var = aml_opcode(0x93 /* LequalOp */); - aml_append(var, arg1); - aml_append(var, arg2); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreater */ -Aml *aml_lgreater(Aml *arg1, Aml *arg2) -{ - Aml *var = aml_opcode(0x94 /* LGreaterOp */); - aml_append(var, arg1); - aml_append(var, arg2); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLGreaterEqual */ -Aml *aml_lgreater_equal(Aml *arg1, Aml *arg2) -{ - /* LGreaterEqualOp := LNotOp LLessOp */ - Aml *var = aml_opcode(0x92 /* LNotOp */); - build_append_byte(var->buf, 0x95 /* LLessOp */); - aml_append(var, arg1); - aml_append(var, arg2); - return var; -} - -/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefIfElse */ -Aml *aml_if(Aml *predicate) -{ - Aml *var = aml_bundle(0xA0 /* IfOp */, AML_PACKAGE); - aml_append(var, predicate); - return var; -} - -/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefElse */ -Aml *aml_else(void) -{ - Aml *var = aml_bundle(0xA1 /* ElseOp */, AML_PACKAGE); - return var; -} - -/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefWhile */ -Aml *aml_while(Aml *predicate) -{ - Aml *var = aml_bundle(0xA2 /* WhileOp */, AML_PACKAGE); - aml_append(var, predicate); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */ -Aml *aml_method(const char *name, int arg_count, AmlSerializeFlag sflag) -{ - Aml *var = aml_bundle(0x14 /* MethodOp */, AML_PACKAGE); - int methodflags; - - /* - * MethodFlags: - * bit 0-2: ArgCount (0-7) - * bit 3: SerializeFlag - * 0: NotSerialized - * 1: Serialized - * bit 4-7: reserved (must be 0) - */ - assert(arg_count < 8); - methodflags = arg_count | (sflag << 3); - - build_append_namestring(var->buf, "%s", name); - build_append_byte(var->buf, methodflags); /* MethodFlags: ArgCount */ - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefDevice */ -Aml *aml_device(const char *name_format, ...) -{ - va_list ap; - Aml *var = aml_bundle(0x82 /* DeviceOp */, AML_EXT_PACKAGE); - va_start(ap, name_format); - build_append_namestringv(var->buf, name_format, ap); - va_end(ap); - return var; -} - -/* ACPI 1.0b: 6.4.1 ASL Macros for Resource Descriptors */ -Aml *aml_resource_template(void) -{ - /* ResourceTemplate is a buffer of Resources with EndTag at the end */ - Aml *var = aml_bundle(0x11 /* BufferOp */, AML_RES_TEMPLATE); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer - * Pass byte_list as NULL to request uninitialized buffer to reserve space. - */ -Aml *aml_buffer(int buffer_size, uint8_t *byte_list) -{ - int i; - Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER); - - for (i = 0; i < buffer_size; i++) { - if (byte_list == NULL) { - build_append_byte(var->buf, 0x0); - } else { - build_append_byte(var->buf, byte_list[i]); - } - } - - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefPackage */ -Aml *aml_package(uint8_t num_elements) -{ - Aml *var = aml_bundle(0x12 /* PackageOp */, AML_PACKAGE); - build_append_byte(var->buf, num_elements); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefOpRegion */ -Aml *aml_operation_region(const char *name, AmlRegionSpace rs, - Aml *offset, uint32_t len) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ - build_append_byte(var->buf, 0x80); /* OpRegionOp */ - build_append_namestring(var->buf, "%s", name); - build_append_byte(var->buf, rs); - aml_append(var, offset); - build_append_int(var->buf, len); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: NamedField */ -Aml *aml_named_field(const char *name, unsigned length) -{ - Aml *var = aml_alloc(); - build_append_nameseg(var->buf, name); - build_append_pkg_length(var->buf, length, false); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: ReservedField */ -Aml *aml_reserved_field(unsigned length) -{ - Aml *var = aml_alloc(); - /* ReservedField := 0x00 PkgLength */ - build_append_byte(var->buf, 0x00); - build_append_pkg_length(var->buf, length, false); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */ -Aml *aml_field(const char *name, AmlAccessType type, AmlLockRule lock, - AmlUpdateRule rule) -{ - Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE); - uint8_t flags = rule << 5 | type; - - flags |= lock << 4; /* LockRule at 4 bit offset */ - - build_append_namestring(var->buf, "%s", name); - build_append_byte(var->buf, flags); - return var; -} - -static -Aml *create_field_common(int opcode, Aml *srcbuf, Aml *index, const char *name) -{ - Aml *var = aml_opcode(opcode); - aml_append(var, srcbuf); - aml_append(var, index); - build_append_namestring(var->buf, "%s", name); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateField */ -Aml *aml_create_field(Aml *srcbuf, Aml *bit_index, Aml *num_bits, - const char *name) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ - build_append_byte(var->buf, 0x13); /* CreateFieldOp */ - aml_append(var, srcbuf); - aml_append(var, bit_index); - aml_append(var, num_bits); - build_append_namestring(var->buf, "%s", name); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateDWordField */ -Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name) -{ - return create_field_common(0x8A /* CreateDWordFieldOp */, - srcbuf, index, name); -} - -/* ACPI 2.0a: 17.2.4.2 Named Objects Encoding: DefCreateQWordField */ -Aml *aml_create_qword_field(Aml *srcbuf, Aml *index, const char *name) -{ - return create_field_common(0x8F /* CreateQWordFieldOp */, - srcbuf, index, name); -} - -/* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */ -Aml *aml_string(const char *name_format, ...) -{ - Aml *var = aml_opcode(0x0D /* StringPrefix */); - va_list ap; - char *s; - int len; - - va_start(ap, name_format); - len = g_vasprintf(&s, name_format, ap); - va_end(ap); - - g_array_append_vals(var->buf, s, len + 1); - g_free(s); - - return var; -} - -/* ACPI 1.0b: 16.2.6.2 Local Objects Encoding */ -Aml *aml_local(int num) -{ - Aml *var; - uint8_t op = 0x60 /* Local0Op */ + num; - - assert(num <= 7); - var = aml_opcode(op); - return var; -} - -/* ACPI 2.0a: 17.2.2 Data Objects Encoding: DefVarPackage */ -Aml *aml_varpackage(uint32_t num_elements) -{ - Aml *var = aml_bundle(0x13 /* VarPackageOp */, AML_PACKAGE); - build_append_int(var->buf, num_elements); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefProcessor */ -Aml *aml_processor(uint8_t proc_id, uint32_t pblk_addr, uint8_t pblk_len, - const char *name_format, ...) -{ - va_list ap; - Aml *var = aml_bundle(0x83 /* ProcessorOp */, AML_EXT_PACKAGE); - va_start(ap, name_format); - build_append_namestringv(var->buf, name_format, ap); - va_end(ap); - build_append_byte(var->buf, proc_id); /* ProcID */ - build_append_int_noprefix(var->buf, pblk_addr, sizeof(pblk_addr)); - build_append_byte(var->buf, pblk_len); /* PblkLen */ - return var; -} - -static uint8_t Hex2Digit(char c) -{ - if (c >= 'A') { - return c - 'A' + 10; - } - - return c - '0'; -} - -/* ACPI 1.0b: 15.2.3.6.4.1 EISAID Macro - Convert EISA ID String To Integer */ -Aml *aml_eisaid(const char *str) -{ - Aml *var = aml_alloc(); - uint32_t id; - - g_assert(strlen(str) == 7); - id = (str[0] - 0x40) << 26 | - (str[1] - 0x40) << 21 | - (str[2] - 0x40) << 16 | - Hex2Digit(str[3]) << 12 | - Hex2Digit(str[4]) << 8 | - Hex2Digit(str[5]) << 4 | - Hex2Digit(str[6]); - - build_append_byte(var->buf, 0x0C); /* DWordPrefix */ - build_append_int_noprefix(var->buf, bswap32(id), sizeof(id)); - return var; -} - -/* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor: bytes 3-5 */ -static Aml *aml_as_desc_header(AmlResourceType type, AmlMinFixed min_fixed, - AmlMaxFixed max_fixed, AmlDecode dec, - uint8_t type_flags) -{ - uint8_t flags = max_fixed | min_fixed | dec; - Aml *var = aml_alloc(); - - build_append_byte(var->buf, type); - build_append_byte(var->buf, flags); - build_append_byte(var->buf, type_flags); /* Type Specific Flags */ - return var; -} - -/* ACPI 1.0b: 6.4.3.5.5 Word Address Space Descriptor */ -static Aml *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) -{ - Aml *var = aml_alloc(); - - build_append_byte(var->buf, 0x88); /* Word Address Space Descriptor */ - /* minimum length since we do not encode optional fields */ - build_append_byte(var->buf, 0x0D); - build_append_byte(var->buf, 0x0); - - aml_append(var, - aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags)); - build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran)); - build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min)); - build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max)); - build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans)); - build_append_int_noprefix(var->buf, len, sizeof(len)); - return var; -} - -/* ACPI 1.0b: 6.4.3.5.3 DWord Address Space Descriptor */ -static Aml *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) -{ - Aml *var = aml_alloc(); - - build_append_byte(var->buf, 0x87); /* DWord Address Space Descriptor */ - /* minimum length since we do not encode optional fields */ - build_append_byte(var->buf, 23); - build_append_byte(var->buf, 0x0); - - - aml_append(var, - aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags)); - build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran)); - build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min)); - build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max)); - build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans)); - build_append_int_noprefix(var->buf, len, sizeof(len)); - return var; -} - -/* ACPI 1.0b: 6.4.3.5.1 QWord Address Space Descriptor */ -static Aml *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) -{ - Aml *var = aml_alloc(); - - build_append_byte(var->buf, 0x8A); /* QWord Address Space Descriptor */ - /* minimum length since we do not encode optional fields */ - build_append_byte(var->buf, 0x2B); - build_append_byte(var->buf, 0x0); - - aml_append(var, - aml_as_desc_header(type, min_fixed, max_fixed, dec, type_flags)); - build_append_int_noprefix(var->buf, addr_gran, sizeof(addr_gran)); - build_append_int_noprefix(var->buf, addr_min, sizeof(addr_min)); - build_append_int_noprefix(var->buf, addr_max, sizeof(addr_max)); - build_append_int_noprefix(var->buf, addr_trans, sizeof(addr_trans)); - build_append_int_noprefix(var->buf, len, sizeof(len)); - return var; -} - -/* - * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor - * - * More verbose description at: - * ACPI 5.0: 19.5.141 WordBusNumber (Word Bus Number Resource Descriptor Macro) - */ -Aml *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) - -{ - return aml_word_as_desc(AML_BUS_NUMBER_RANGE, min_fixed, max_fixed, dec, - addr_gran, addr_min, addr_max, addr_trans, len, 0); -} - -/* - * ACPI 1.0b: 6.4.3.5.6 ASL Macros for WORD Address Descriptor - * - * More verbose description at: - * ACPI 5.0: 19.5.142 WordIO (Word IO Resource Descriptor Macro) - */ -Aml *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) - -{ - return aml_word_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec, - addr_gran, addr_min, addr_max, addr_trans, len, - isa_ranges); -} - -/* - * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Descriptor - * - * More verbose description at: - * ACPI 5.0: 19.5.33 DWordIO (DWord IO Resource Descriptor Macro) - */ -Aml *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) - -{ - return aml_dword_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec, - addr_gran, addr_min, addr_max, addr_trans, len, - isa_ranges); -} - -/* - * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Space Descriptor - * - * More verbose description at: - * ACPI 5.0: 19.5.34 DWordMemory (DWord Memory Resource Descriptor Macro) - */ -Aml *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) -{ - uint8_t flags = read_and_write | (cacheable << 1); - - return aml_dword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed, - dec, addr_gran, addr_min, addr_max, - addr_trans, len, flags); -} - -/* - * ACPI 1.0b: 6.4.3.5.2 ASL Macros for QWORD Address Space Descriptor - * - * More verbose description at: - * ACPI 5.0: 19.5.102 QWordMemory (QWord Memory Resource Descriptor Macro) - */ -Aml *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) -{ - uint8_t flags = read_and_write | (cacheable << 1); - - return aml_qword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed, - dec, addr_gran, addr_min, addr_max, - addr_trans, len, flags); -} - -/* ACPI 1.0b: 6.4.2.2 DMA Format/6.4.2.2.1 ASL Macro for DMA Descriptor */ -Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz, - uint8_t channel) -{ - Aml *var = aml_alloc(); - uint8_t flags = sz | bm << 2 | typ << 5; - - assert(channel < 8); - build_append_byte(var->buf, 0x2A); /* Byte 0: DMA Descriptor */ - build_append_byte(var->buf, 1U << channel); /* Byte 1: _DMA - DmaChannel */ - build_append_byte(var->buf, flags); /* Byte 2 */ - return var; -} - -/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefSleep */ -Aml *aml_sleep(uint64_t msec) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ - build_append_byte(var->buf, 0x22); /* SleepOp */ - aml_append(var, aml_int(msec)); - return var; -} - -static uint8_t Hex2Byte(const char *src) -{ - int hi, lo; - - hi = Hex2Digit(src[0]); - assert(hi >= 0); - assert(hi <= 15); - - lo = Hex2Digit(src[1]); - assert(lo >= 0); - assert(lo <= 15); - return (hi << 4) | lo; -} - -/* - * ACPI 3.0: 17.5.124 ToUUID (Convert String to UUID Macro) - * e.g. UUID: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp - * call aml_touuid("aabbccdd-eeff-gghh-iijj-kkllmmnnoopp"); - */ -Aml *aml_touuid(const char *uuid) -{ - Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER); - - assert(strlen(uuid) == 36); - assert(uuid[8] == '-'); - assert(uuid[13] == '-'); - assert(uuid[18] == '-'); - assert(uuid[23] == '-'); - - build_append_byte(var->buf, Hex2Byte(uuid + 6)); /* dd - at offset 00 */ - build_append_byte(var->buf, Hex2Byte(uuid + 4)); /* cc - at offset 01 */ - build_append_byte(var->buf, Hex2Byte(uuid + 2)); /* bb - at offset 02 */ - build_append_byte(var->buf, Hex2Byte(uuid + 0)); /* aa - at offset 03 */ - - build_append_byte(var->buf, Hex2Byte(uuid + 11)); /* ff - at offset 04 */ - build_append_byte(var->buf, Hex2Byte(uuid + 9)); /* ee - at offset 05 */ - - build_append_byte(var->buf, Hex2Byte(uuid + 16)); /* hh - at offset 06 */ - build_append_byte(var->buf, Hex2Byte(uuid + 14)); /* gg - at offset 07 */ - - build_append_byte(var->buf, Hex2Byte(uuid + 19)); /* ii - at offset 08 */ - build_append_byte(var->buf, Hex2Byte(uuid + 21)); /* jj - at offset 09 */ - - build_append_byte(var->buf, Hex2Byte(uuid + 24)); /* kk - at offset 10 */ - build_append_byte(var->buf, Hex2Byte(uuid + 26)); /* ll - at offset 11 */ - build_append_byte(var->buf, Hex2Byte(uuid + 28)); /* mm - at offset 12 */ - build_append_byte(var->buf, Hex2Byte(uuid + 30)); /* nn - at offset 13 */ - build_append_byte(var->buf, Hex2Byte(uuid + 32)); /* oo - at offset 14 */ - build_append_byte(var->buf, Hex2Byte(uuid + 34)); /* pp - at offset 15 */ - - return var; -} - -/* - * ACPI 2.0b: 16.2.3.6.4.3 Unicode Macro (Convert Ascii String To Unicode) - */ -Aml *aml_unicode(const char *str) -{ - int i = 0; - Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER); - - do { - build_append_byte(var->buf, str[i]); - build_append_byte(var->buf, 0); - i++; - } while (i <= strlen(str)); - - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDerefOf */ -Aml *aml_derefof(Aml *arg) -{ - Aml *var = aml_opcode(0x83 /* DerefOfOp */); - aml_append(var, arg); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefSizeOf */ -Aml *aml_sizeof(Aml *arg) -{ - Aml *var = aml_opcode(0x87 /* SizeOfOp */); - aml_append(var, arg); - return var; -} - -/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMutex */ -Aml *aml_mutex(const char *name, uint8_t sync_level) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ - build_append_byte(var->buf, 0x01); /* MutexOp */ - build_append_namestring(var->buf, "%s", name); - assert(!(sync_level & 0xF0)); - build_append_byte(var->buf, sync_level); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAcquire */ -Aml *aml_acquire(Aml *mutex, uint16_t timeout) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ - build_append_byte(var->buf, 0x23); /* AcquireOp */ - aml_append(var, mutex); - build_append_int_noprefix(var->buf, timeout, sizeof(timeout)); - return var; -} - -/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefRelease */ -Aml *aml_release(Aml *mutex) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ - build_append_byte(var->buf, 0x27); /* ReleaseOp */ - aml_append(var, mutex); - return var; -} - -/* ACPI 1.0b: 16.2.5.1 Name Space Modifier Objects Encoding: DefAlias */ -Aml *aml_alias(const char *source_object, const char *alias_object) -{ - Aml *var = aml_opcode(0x06 /* AliasOp */); - aml_append(var, aml_name("%s", source_object)); - aml_append(var, aml_name("%s", alias_object)); - return var; -} - -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefConcat */ -Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target) -{ - return build_opcode_2arg_dst(0x73 /* ConcatOp */, source1, source2, - target); -} - -void -build_header(GArray *linker, GArray *table_data, - AcpiTableHeader *h, const char *sig, int len, uint8_t rev, - const char *oem_id, const char *oem_table_id) -{ - memcpy(&h->signature, sig, 4); - h->length = cpu_to_le32(len); - h->revision = rev; - - if (oem_id) { - strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id); - } else { - memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); - } - - if (oem_table_id) { - strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id)); - } else { - memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4); - memcpy(h->oem_table_id + 4, sig, 4); - } - - h->oem_revision = cpu_to_le32(1); - memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4); - h->asl_compiler_revision = cpu_to_le32(1); - h->checksum = 0; - /* Checksum to be filled in by Guest linker */ - bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE, - table_data, h, len, &h->checksum); -} - -void *acpi_data_push(GArray *table_data, unsigned size) -{ - unsigned off = table_data->len; - g_array_set_size(table_data, off + size); - return table_data->data + off; -} - -unsigned acpi_data_len(GArray *table) -{ - assert(g_array_get_element_size(table) == 1); - return table->len; -} - -void acpi_add_table(GArray *table_offsets, GArray *table_data) -{ - uint32_t offset = cpu_to_le32(table_data->len); - g_array_append_val(table_offsets, offset); -} - -void acpi_build_tables_init(AcpiBuildTables *tables) -{ - tables->rsdp = g_array_new(false, true /* clear */, 1); - tables->table_data = g_array_new(false, true /* clear */, 1); - tables->tcpalog = g_array_new(false, true /* clear */, 1); - tables->linker = bios_linker_loader_init(); -} - -void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre) -{ - void *linker_data = bios_linker_loader_cleanup(tables->linker); - g_free(linker_data); - g_array_free(tables->rsdp, true); - g_array_free(tables->table_data, true); - g_array_free(tables->tcpalog, mfre); -} - -/* Build rsdt table */ -void -build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets, - const char *oem_id, const char *oem_table_id) -{ - AcpiRsdtDescriptorRev1 *rsdt; - size_t rsdt_len; - int i; - const int table_data_len = (sizeof(uint32_t) * table_offsets->len); - - rsdt_len = sizeof(*rsdt) + table_data_len; - rsdt = acpi_data_push(table_data, rsdt_len); - memcpy(rsdt->table_offset_entry, table_offsets->data, table_data_len); - for (i = 0; i < table_offsets->len; ++i) { - /* rsdt->table_offset_entry to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, - ACPI_BUILD_TABLE_FILE, - table_data, &rsdt->table_offset_entry[i], - sizeof(uint32_t)); - } - build_header(linker, table_data, - (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id); -} diff --git a/qemu/hw/acpi/bios-linker-loader.c b/qemu/hw/acpi/bios-linker-loader.c deleted file mode 100644 index 5153ab151..000000000 --- a/qemu/hw/acpi/bios-linker-loader.c +++ /dev/null @@ -1,240 +0,0 @@ -/* Dynamic linker/loader of ACPI tables - * - * Copyright (C) 2013 Red Hat Inc - * - * Author: Michael S. Tsirkin <mst@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "hw/acpi/bios-linker-loader.h" -#include "hw/nvram/fw_cfg.h" - -#include "qemu/bswap.h" - -/* - * Linker/loader is a paravirtualized interface that passes commands to guest. - * The commands can be used to request guest to - * - allocate memory chunks and initialize them from QEMU FW CFG files - * - link allocated chunks by storing pointer to one chunk into another - * - calculate ACPI checksum of part of the chunk and store into same chunk - */ -#define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH - -struct BiosLinkerLoaderEntry { - uint32_t command; - union { - /* - * COMMAND_ALLOCATE - allocate a table from @alloc.file - * subject to @alloc.align alignment (must be power of 2) - * and @alloc.zone (can be HIGH or FSEG) requirements. - * - * Must appear exactly once for each file, and before - * this file is referenced by any other command. - */ - struct { - char file[BIOS_LINKER_LOADER_FILESZ]; - uint32_t align; - uint8_t zone; - } alloc; - - /* - * COMMAND_ADD_POINTER - patch the table (originating from - * @dest_file) at @pointer.offset, by adding a pointer to the table - * originating from @src_file. 1,2,4 or 8 byte unsigned - * addition is used depending on @pointer.size. - */ - struct { - char dest_file[BIOS_LINKER_LOADER_FILESZ]; - char src_file[BIOS_LINKER_LOADER_FILESZ]; - uint32_t offset; - uint8_t size; - } pointer; - - /* - * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by - * @cksum_start and @cksum_length fields, - * and then add the value at @cksum.offset. - * Checksum simply sums -X for each byte X in the range - * using 8-bit math. - */ - struct { - char file[BIOS_LINKER_LOADER_FILESZ]; - uint32_t offset; - uint32_t start; - uint32_t length; - } cksum; - - /* padding */ - char pad[124]; - }; -} QEMU_PACKED; -typedef struct BiosLinkerLoaderEntry BiosLinkerLoaderEntry; - -enum { - BIOS_LINKER_LOADER_COMMAND_ALLOCATE = 0x1, - BIOS_LINKER_LOADER_COMMAND_ADD_POINTER = 0x2, - BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3, -}; - -enum { - BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1, - BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2, -}; - -/* - * bios_linker_loader_init: allocate a new linker file blob array. - * - * After initialization, linker commands can be added, and will - * be stored in the array. - */ -GArray *bios_linker_loader_init(void) -{ - return g_array_new(false, true /* clear */, 1); -} - -/* Free linker wrapper and return the linker array. */ -void *bios_linker_loader_cleanup(GArray *linker) -{ - return g_array_free(linker, false); -} - -/* - * bios_linker_loader_alloc: ask guest to load file into guest memory. - * - * @linker: linker file blob array - * @file: file to be loaded - * @alloc_align: required minimal alignment in bytes. Must be a power of 2. - * @alloc_fseg: request allocation in FSEG zone (useful for the RSDP ACPI table) - * - * Note: this command must precede any other linker command using this file. - */ -void bios_linker_loader_alloc(GArray *linker, - const char *file, - uint32_t alloc_align, - bool alloc_fseg) -{ - BiosLinkerLoaderEntry entry; - - assert(!(alloc_align & (alloc_align - 1))); - - memset(&entry, 0, sizeof entry); - strncpy(entry.alloc.file, file, sizeof entry.alloc.file - 1); - entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ALLOCATE); - entry.alloc.align = cpu_to_le32(alloc_align); - entry.alloc.zone = alloc_fseg ? BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG : - BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH; - - /* Alloc entries must come first, so prepend them */ - g_array_prepend_vals(linker, &entry, sizeof entry); -} - -/* - * bios_linker_loader_add_checksum: ask guest to add checksum of file data - * into (same) file at the specified pointer. - * - * Checksum calculation simply sums -X for each byte X in the range - * using 8-bit math (i.e. ACPI checksum). - * - * @linker: linker file blob array - * @file: file that includes the checksum to be calculated - * and the data to be checksummed - * @table: @file blob contents - * @start, @size: range of data to checksum - * @checksum: location of the checksum to be patched within file blob - * - * Notes: - * - checksum byte initial value must have been pushed into @table - * and reside at address @checksum. - * - @size bytes must have been pushed into @table and reside at address - * @start. - * - Guest calculates checksum of specified range of data, result is added to - * initial value at @checksum into copy of @file in Guest memory. - * - Range might include the checksum itself. - * - To avoid confusion, caller must always put 0x0 at @checksum. - * - @file must be loaded into Guest memory using bios_linker_loader_alloc - */ -void bios_linker_loader_add_checksum(GArray *linker, const char *file, - GArray *table, - void *start, unsigned size, - uint8_t *checksum) -{ - BiosLinkerLoaderEntry entry; - ptrdiff_t checksum_offset = (gchar *)checksum - table->data; - ptrdiff_t start_offset = (gchar *)start - table->data; - - assert(checksum_offset >= 0); - assert(start_offset >= 0); - assert(checksum_offset + 1 <= table->len); - assert(start_offset + size <= table->len); - assert(*checksum == 0x0); - - memset(&entry, 0, sizeof entry); - strncpy(entry.cksum.file, file, sizeof entry.cksum.file - 1); - entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM); - entry.cksum.offset = cpu_to_le32(checksum_offset); - entry.cksum.start = cpu_to_le32(start_offset); - entry.cksum.length = cpu_to_le32(size); - - g_array_append_vals(linker, &entry, sizeof entry); -} - -/* - * bios_linker_loader_add_pointer: ask guest to add address of source file - * into destination file at the specified pointer. - * - * @linker: linker file blob array - * @dest_file: destination file that must be changed - * @src_file: source file who's address must be taken - * @table: @dest_file blob contents array - * @pointer: location of the pointer to be patched within destination file blob - * @pointer_size: size of pointer to be patched, in bytes - * - * Notes: - * - @pointer_size bytes must have been pushed into @table - * and reside at address @pointer. - * - Guest address is added to initial value at @pointer - * into copy of @dest_file in Guest memory. - * e.g. to get start of src_file in guest memory, put 0x0 there - * to get address of a field at offset 0x10 in src_file, put 0x10 there - * - Both @dest_file and @src_file must be - * loaded into Guest memory using bios_linker_loader_alloc - */ -void bios_linker_loader_add_pointer(GArray *linker, - const char *dest_file, - const char *src_file, - GArray *table, void *pointer, - uint8_t pointer_size) -{ - BiosLinkerLoaderEntry entry; - ptrdiff_t offset = (gchar *)pointer - table->data; - - assert(offset >= 0); - assert(offset + pointer_size <= table->len); - - memset(&entry, 0, sizeof entry); - strncpy(entry.pointer.dest_file, dest_file, - sizeof entry.pointer.dest_file - 1); - strncpy(entry.pointer.src_file, src_file, - sizeof entry.pointer.src_file - 1); - entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER); - entry.pointer.offset = cpu_to_le32(offset); - entry.pointer.size = pointer_size; - assert(pointer_size == 1 || pointer_size == 2 || - pointer_size == 4 || pointer_size == 8); - - g_array_append_vals(linker, &entry, sizeof entry); -} diff --git a/qemu/hw/acpi/core.c b/qemu/hw/acpi/core.c deleted file mode 100644 index 6a2f45214..000000000 --- a/qemu/hw/acpi/core.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * ACPI implementation - * - * Copyright (c) 2006 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "qemu/osdep.h" -#include "sysemu/sysemu.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/acpi/acpi.h" -#include "hw/nvram/fw_cfg.h" -#include "qemu/config-file.h" -#include "qapi/opts-visitor.h" -#include "qapi-visit.h" -#include "qapi-event.h" - -struct acpi_table_header { - uint16_t _length; /* our length, not actual part of the hdr */ - /* allows easier parsing for fw_cfg clients */ - char sig[4]; /* ACPI signature (4 ASCII characters) */ - uint32_t length; /* Length of table, in bytes, including header */ - uint8_t revision; /* ACPI Specification minor version # */ - uint8_t checksum; /* To make sum of entire table == 0 */ - char oem_id[6]; /* OEM identification */ - char oem_table_id[8]; /* OEM table identification */ - uint32_t oem_revision; /* OEM revision number */ - char asl_compiler_id[4]; /* ASL compiler vendor ID */ - uint32_t asl_compiler_revision; /* ASL compiler revision number */ -} QEMU_PACKED; - -#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header) -#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */ - -static const char unsigned dfl_hdr[ACPI_TABLE_HDR_SIZE - ACPI_TABLE_PFX_SIZE] = - "QEMU\0\0\0\0\1\0" /* sig (4), len(4), revno (1), csum (1) */ - "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */ - "QEMU\1\0\0\0" /* ASL compiler ID (4), version (4) */ - ; - -char unsigned *acpi_tables; -size_t acpi_tables_len; - -static QemuOptsList qemu_acpi_opts = { - .name = "acpi", - .implied_opt_name = "data", - .head = QTAILQ_HEAD_INITIALIZER(qemu_acpi_opts.head), - .desc = { { 0 } } /* validated with OptsVisitor */ -}; - -static void acpi_register_config(void) -{ - qemu_add_opts(&qemu_acpi_opts); -} - -opts_init(acpi_register_config); - -static int acpi_checksum(const uint8_t *data, int len) -{ - int sum, i; - sum = 0; - for (i = 0; i < len; i++) { - sum += data[i]; - } - return (-sum) & 0xff; -} - - -/* Install a copy of the ACPI table specified in @blob. - * - * If @has_header is set, @blob starts with the System Description Table Header - * structure. Otherwise, "dfl_hdr" is prepended. In any case, each header field - * is optionally overwritten from @hdrs. - * - * It is valid to call this function with - * (@blob == NULL && bloblen == 0 && !has_header). - * - * @hdrs->file and @hdrs->data are ignored. - * - * SIZE_MAX is considered "infinity" in this function. - * - * The number of tables that can be installed is not limited, but the 16-bit - * counter at the beginning of "acpi_tables" wraps around after UINT16_MAX. - */ -static void acpi_table_install(const char unsigned *blob, size_t bloblen, - bool has_header, - const struct AcpiTableOptions *hdrs, - Error **errp) -{ - size_t body_start; - const char unsigned *hdr_src; - size_t body_size, acpi_payload_size; - struct acpi_table_header *ext_hdr; - unsigned changed_fields; - - /* Calculate where the ACPI table body starts within the blob, plus where - * to copy the ACPI table header from. - */ - if (has_header) { - /* _length | ACPI header in blob | blob body - * ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ - * ACPI_TABLE_PFX_SIZE sizeof dfl_hdr body_size - * == body_start - * - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * acpi_payload_size == bloblen - */ - body_start = sizeof dfl_hdr; - - if (bloblen < body_start) { - error_setg(errp, "ACPI table claiming to have header is too " - "short, available: %zu, expected: %zu", bloblen, - body_start); - return; - } - hdr_src = blob; - } else { - /* _length | ACPI header in template | blob body - * ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ - * ACPI_TABLE_PFX_SIZE sizeof dfl_hdr body_size - * == bloblen - * - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * acpi_payload_size - */ - body_start = 0; - hdr_src = dfl_hdr; - } - body_size = bloblen - body_start; - acpi_payload_size = sizeof dfl_hdr + body_size; - - if (acpi_payload_size > UINT16_MAX) { - error_setg(errp, "ACPI table too big, requested: %zu, max: %u", - acpi_payload_size, (unsigned)UINT16_MAX); - return; - } - - /* We won't fail from here on. Initialize / extend the globals. */ - if (acpi_tables == NULL) { - acpi_tables_len = sizeof(uint16_t); - acpi_tables = g_malloc0(acpi_tables_len); - } - - acpi_tables = g_realloc(acpi_tables, acpi_tables_len + - ACPI_TABLE_PFX_SIZE + - sizeof dfl_hdr + body_size); - - ext_hdr = (struct acpi_table_header *)(acpi_tables + acpi_tables_len); - acpi_tables_len += ACPI_TABLE_PFX_SIZE; - - memcpy(acpi_tables + acpi_tables_len, hdr_src, sizeof dfl_hdr); - acpi_tables_len += sizeof dfl_hdr; - - if (blob != NULL) { - memcpy(acpi_tables + acpi_tables_len, blob + body_start, body_size); - acpi_tables_len += body_size; - } - - /* increase number of tables */ - stw_le_p(acpi_tables, lduw_le_p(acpi_tables) + 1u); - - /* Update the header fields. The strings need not be NUL-terminated. */ - changed_fields = 0; - ext_hdr->_length = cpu_to_le16(acpi_payload_size); - - if (hdrs->has_sig) { - strncpy(ext_hdr->sig, hdrs->sig, sizeof ext_hdr->sig); - ++changed_fields; - } - - if (has_header && le32_to_cpu(ext_hdr->length) != acpi_payload_size) { - fprintf(stderr, - "warning: ACPI table has wrong length, header says " - "%" PRIu32 ", actual size %zu bytes\n", - le32_to_cpu(ext_hdr->length), acpi_payload_size); - } - ext_hdr->length = cpu_to_le32(acpi_payload_size); - - if (hdrs->has_rev) { - ext_hdr->revision = hdrs->rev; - ++changed_fields; - } - - ext_hdr->checksum = 0; - - if (hdrs->has_oem_id) { - strncpy(ext_hdr->oem_id, hdrs->oem_id, sizeof ext_hdr->oem_id); - ++changed_fields; - } - if (hdrs->has_oem_table_id) { - strncpy(ext_hdr->oem_table_id, hdrs->oem_table_id, - sizeof ext_hdr->oem_table_id); - ++changed_fields; - } - if (hdrs->has_oem_rev) { - ext_hdr->oem_revision = cpu_to_le32(hdrs->oem_rev); - ++changed_fields; - } - if (hdrs->has_asl_compiler_id) { - strncpy(ext_hdr->asl_compiler_id, hdrs->asl_compiler_id, - sizeof ext_hdr->asl_compiler_id); - ++changed_fields; - } - if (hdrs->has_asl_compiler_rev) { - ext_hdr->asl_compiler_revision = cpu_to_le32(hdrs->asl_compiler_rev); - ++changed_fields; - } - - if (!has_header && changed_fields == 0) { - fprintf(stderr, "warning: ACPI table: no headers are specified\n"); - } - - /* recalculate checksum */ - ext_hdr->checksum = acpi_checksum((const char unsigned *)ext_hdr + - ACPI_TABLE_PFX_SIZE, acpi_payload_size); -} - -void acpi_table_add(const QemuOpts *opts, Error **errp) -{ - AcpiTableOptions *hdrs = NULL; - Error *err = NULL; - char **pathnames = NULL; - char **cur; - size_t bloblen = 0; - char unsigned *blob = NULL; - - { - OptsVisitor *ov; - - ov = opts_visitor_new(opts); - visit_type_AcpiTableOptions(opts_get_visitor(ov), NULL, &hdrs, &err); - opts_visitor_cleanup(ov); - } - - if (err) { - goto out; - } - if (hdrs->has_file == hdrs->has_data) { - error_setg(&err, "'-acpitable' requires one of 'data' or 'file'"); - goto out; - } - - pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0); - if (pathnames == NULL || pathnames[0] == NULL) { - error_setg(&err, "'-acpitable' requires at least one pathname"); - goto out; - } - - /* now read in the data files, reallocating buffer as needed */ - for (cur = pathnames; *cur; ++cur) { - int fd = open(*cur, O_RDONLY | O_BINARY); - - if (fd < 0) { - error_setg(&err, "can't open file %s: %s", *cur, strerror(errno)); - goto out; - } - - for (;;) { - char unsigned data[8192]; - ssize_t r; - - r = read(fd, data, sizeof data); - if (r == 0) { - break; - } else if (r > 0) { - blob = g_realloc(blob, bloblen + r); - memcpy(blob + bloblen, data, r); - bloblen += r; - } else if (errno != EINTR) { - error_setg(&err, "can't read file %s: %s", - *cur, strerror(errno)); - close(fd); - goto out; - } - } - - close(fd); - } - - acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, &err); - -out: - g_free(blob); - g_strfreev(pathnames); - qapi_free_AcpiTableOptions(hdrs); - - error_propagate(errp, err); -} - -static bool acpi_table_builtin = false; - -void acpi_table_add_builtin(const QemuOpts *opts, Error **errp) -{ - acpi_table_builtin = true; - acpi_table_add(opts, errp); -} - -unsigned acpi_table_len(void *current) -{ - struct acpi_table_header *hdr = current - sizeof(hdr->_length); - return hdr->_length; -} - -static -void *acpi_table_hdr(void *h) -{ - struct acpi_table_header *hdr = h; - return &hdr->sig; -} - -uint8_t *acpi_table_first(void) -{ - if (acpi_table_builtin || !acpi_tables) { - return NULL; - } - return acpi_table_hdr(acpi_tables + ACPI_TABLE_PFX_SIZE); -} - -uint8_t *acpi_table_next(uint8_t *current) -{ - uint8_t *next = current + acpi_table_len(current); - - if (next - acpi_tables >= acpi_tables_len) { - return NULL; - } else { - return acpi_table_hdr(next); - } -} - -int acpi_get_slic_oem(AcpiSlicOem *oem) -{ - uint8_t *u; - - for (u = acpi_table_first(); u; u = acpi_table_next(u)) { - struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length)); - - if (memcmp(hdr->sig, "SLIC", 4) == 0) { - oem->id = hdr->oem_id; - oem->table_id = hdr->oem_table_id; - return 0; - } - } - return -1; -} - -static void acpi_notify_wakeup(Notifier *notifier, void *data) -{ - ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); - WakeupReason *reason = data; - - switch (*reason) { - case QEMU_WAKEUP_REASON_RTC: - ar->pm1.evt.sts |= - (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS); - break; - case QEMU_WAKEUP_REASON_PMTIMER: - ar->pm1.evt.sts |= - (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS); - break; - case QEMU_WAKEUP_REASON_OTHER: - /* ACPI_BITMASK_WAKE_STATUS should be set on resume. - Pretend that resume was caused by power button */ - ar->pm1.evt.sts |= - (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); - break; - default: - break; - } -} - -/* ACPI PM1a EVT */ -uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar) -{ - /* Compare ns-clock, not PM timer ticks, because - acpi_pm_tmr_update function uses ns for setting the timer. */ - int64_t d = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - if (d >= muldiv64(ar->tmr.overflow_time, - NANOSECONDS_PER_SECOND, PM_TIMER_FREQUENCY)) { - ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS; - } - return ar->pm1.evt.sts; -} - -static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) -{ - uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar); - if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { - /* if TMRSTS is reset, then compute the new overflow time */ - acpi_pm_tmr_calc_overflow_time(ar); - } - ar->pm1.evt.sts &= ~val; -} - -static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) -{ - ar->pm1.evt.en = val; - qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, - val & ACPI_BITMASK_RT_CLOCK_ENABLE); - qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, - val & ACPI_BITMASK_TIMER_ENABLE); -} - -void acpi_pm1_evt_power_down(ACPIREGS *ar) -{ - if (ar->pm1.evt.en & ACPI_BITMASK_POWER_BUTTON_ENABLE) { - ar->pm1.evt.sts |= ACPI_BITMASK_POWER_BUTTON_STATUS; - ar->tmr.update_sci(ar); - } -} - -void acpi_pm1_evt_reset(ACPIREGS *ar) -{ - ar->pm1.evt.sts = 0; - ar->pm1.evt.en = 0; - qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, 0); - qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, 0); -} - -static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width) -{ - ACPIREGS *ar = opaque; - switch (addr) { - case 0: - return acpi_pm1_evt_get_sts(ar); - case 2: - return ar->pm1.evt.en; - default: - return 0; - } -} - -static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - ACPIREGS *ar = opaque; - switch (addr) { - case 0: - acpi_pm1_evt_write_sts(ar, val); - ar->pm1.evt.update_sci(ar); - break; - case 2: - acpi_pm1_evt_write_en(ar, val); - ar->pm1.evt.update_sci(ar); - break; - } -} - -static const MemoryRegionOps acpi_pm_evt_ops = { - .read = acpi_pm_evt_read, - .write = acpi_pm_evt_write, - .valid.min_access_size = 2, - .valid.max_access_size = 2, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, - MemoryRegion *parent) -{ - ar->pm1.evt.update_sci = update_sci; - memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent), - &acpi_pm_evt_ops, ar, "acpi-evt", 4); - memory_region_add_subregion(parent, 0, &ar->pm1.evt.io); -} - -/* ACPI PM_TMR */ -void acpi_pm_tmr_update(ACPIREGS *ar, bool enable) -{ - int64_t expire_time; - - /* schedule a timer interruption if needed */ - if (enable) { - expire_time = muldiv64(ar->tmr.overflow_time, NANOSECONDS_PER_SECOND, - PM_TIMER_FREQUENCY); - timer_mod(ar->tmr.timer, expire_time); - } else { - timer_del(ar->tmr.timer); - } -} - -void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar) -{ - int64_t d = acpi_pm_tmr_get_clock(); - ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL; -} - -static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) -{ - uint32_t d = acpi_pm_tmr_get_clock(); - return d & 0xffffff; -} - -static void acpi_pm_tmr_timer(void *opaque) -{ - ACPIREGS *ar = opaque; - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER); - ar->tmr.update_sci(ar); -} - -static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width) -{ - return acpi_pm_tmr_get(opaque); -} - -static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - /* nothing */ -} - -static const MemoryRegionOps acpi_pm_tmr_ops = { - .read = acpi_pm_tmr_read, - .write = acpi_pm_tmr_write, - .valid.min_access_size = 4, - .valid.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, - MemoryRegion *parent) -{ - ar->tmr.update_sci = update_sci; - ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar); - memory_region_init_io(&ar->tmr.io, memory_region_owner(parent), - &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); - memory_region_add_subregion(parent, 8, &ar->tmr.io); -} - -void acpi_pm_tmr_reset(ACPIREGS *ar) -{ - ar->tmr.overflow_time = 0; - timer_del(ar->tmr.timer); -} - -/* ACPI PM1aCNT */ -static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) -{ - ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); - - if (val & ACPI_BITMASK_SLEEP_ENABLE) { - /* change suspend type */ - uint16_t sus_typ = (val >> 10) & 7; - switch(sus_typ) { - case 0: /* soft power off */ - qemu_system_shutdown_request(); - break; - case 1: - qemu_system_suspend_request(); - break; - default: - if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */ - qapi_event_send_suspend_disk(&error_abort); - qemu_system_shutdown_request(); - } - break; - } - } -} - -void acpi_pm1_cnt_update(ACPIREGS *ar, - bool sci_enable, bool sci_disable) -{ - /* ACPI specs 3.0, 4.7.2.5 */ - if (sci_enable) { - ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE; - } else if (sci_disable) { - ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE; - } -} - -static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) -{ - ACPIREGS *ar = opaque; - return ar->pm1.cnt.cnt; -} - -static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - acpi_pm1_cnt_write(opaque, val); -} - -static const MemoryRegionOps acpi_pm_cnt_ops = { - .read = acpi_pm_cnt_read, - .write = acpi_pm_cnt_write, - .valid.min_access_size = 2, - .valid.max_access_size = 2, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, - bool disable_s3, bool disable_s4, uint8_t s4_val) -{ - FWCfgState *fw_cfg; - - ar->pm1.cnt.s4_val = s4_val; - ar->wakeup.notify = acpi_notify_wakeup; - qemu_register_wakeup_notifier(&ar->wakeup); - memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent), - &acpi_pm_cnt_ops, ar, "acpi-cnt", 2); - memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io); - - fw_cfg = fw_cfg_find(); - if (fw_cfg) { - uint8_t suspend[6] = {128, 0, 0, 129, 128, 128}; - suspend[3] = 1 | ((!disable_s3) << 7); - suspend[4] = s4_val | ((!disable_s4) << 7); - - fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6); - } -} - -void acpi_pm1_cnt_reset(ACPIREGS *ar) -{ - ar->pm1.cnt.cnt = 0; -} - -/* ACPI GPE */ -void acpi_gpe_init(ACPIREGS *ar, uint8_t len) -{ - ar->gpe.len = len; - /* Only first len / 2 bytes are ever used, - * but the caller in ich9.c migrates full len bytes. - * TODO: fix ich9.c and drop the extra allocation. - */ - ar->gpe.sts = g_malloc0(len); - ar->gpe.en = g_malloc0(len); -} - -void acpi_gpe_reset(ACPIREGS *ar) -{ - memset(ar->gpe.sts, 0, ar->gpe.len / 2); - memset(ar->gpe.en, 0, ar->gpe.len / 2); -} - -static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS *ar, uint32_t addr) -{ - uint8_t *cur = NULL; - - if (addr < ar->gpe.len / 2) { - cur = ar->gpe.sts + addr; - } else if (addr < ar->gpe.len) { - cur = ar->gpe.en + addr - ar->gpe.len / 2; - } else { - abort(); - } - - return cur; -} - -void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val) -{ - uint8_t *cur; - - cur = acpi_gpe_ioport_get_ptr(ar, addr); - if (addr < ar->gpe.len / 2) { - /* GPE_STS */ - *cur = (*cur) & ~val; - } else if (addr < ar->gpe.len) { - /* GPE_EN */ - *cur = val; - } else { - abort(); - } -} - -uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr) -{ - uint8_t *cur; - uint32_t val; - - cur = acpi_gpe_ioport_get_ptr(ar, addr); - val = 0; - if (cur != NULL) { - val = *cur; - } - - return val; -} - -void acpi_send_gpe_event(ACPIREGS *ar, qemu_irq irq, - AcpiGPEStatusBits status) -{ - ar->gpe.sts[0] |= status; - acpi_update_sci(ar, irq); -} - -void acpi_update_sci(ACPIREGS *regs, qemu_irq irq) -{ - int sci_level, pm1a_sts; - - pm1a_sts = acpi_pm1_evt_get_sts(regs); - - sci_level = ((pm1a_sts & - regs->pm1.evt.en & ACPI_BITMASK_PM1_COMMON_ENABLED) != 0) || - ((regs->gpe.sts[0] & regs->gpe.en[0]) != 0); - - qemu_set_irq(irq, sci_level); - - /* schedule a timer interruption if needed */ - acpi_pm_tmr_update(regs, - (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && - !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS)); -} diff --git a/qemu/hw/acpi/cpu_hotplug.c b/qemu/hw/acpi/cpu_hotplug.c deleted file mode 100644 index 4d86743fd..000000000 --- a/qemu/hw/acpi/cpu_hotplug.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * QEMU ACPI hotplug utilities - * - * Copyright (C) 2013 Red Hat Inc - * - * Authors: - * Igor Mammedov <imammedo@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/acpi/cpu_hotplug.h" -#include "qapi/error.h" -#include "qom/cpu.h" - -static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size) -{ - AcpiCpuHotplug *cpus = opaque; - uint64_t val = cpus->sts[addr]; - - return val; -} - -static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) -{ - /* TODO: implement VCPU removal on guest signal that CPU can be removed */ -} - -static const MemoryRegionOps AcpiCpuHotplug_ops = { - .read = cpu_status_read, - .write = cpu_status_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu, - Error **errp) -{ - CPUClass *k = CPU_GET_CLASS(cpu); - int64_t cpu_id; - - cpu_id = k->get_arch_id(cpu); - if ((cpu_id / 8) >= ACPI_GPE_PROC_LEN) { - error_setg(errp, "acpi: invalid cpu id: %" PRIi64, cpu_id); - return; - } - - g->sts[cpu_id / 8] |= (1 << (cpu_id % 8)); -} - -void acpi_cpu_plug_cb(ACPIREGS *ar, qemu_irq irq, - AcpiCpuHotplug *g, DeviceState *dev, Error **errp) -{ - acpi_set_cpu_present_bit(g, CPU(dev), errp); - if (*errp != NULL) { - return; - } - - acpi_send_gpe_event(ar, irq, ACPI_CPU_HOTPLUG_STATUS); -} - -void acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, - AcpiCpuHotplug *gpe_cpu, uint16_t base) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - acpi_set_cpu_present_bit(gpe_cpu, cpu, &error_abort); - } - memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops, - gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN); - memory_region_add_subregion(parent, base, &gpe_cpu->io); -} diff --git a/qemu/hw/acpi/cpu_hotplug_acpi_table.c b/qemu/hw/acpi/cpu_hotplug_acpi_table.c deleted file mode 100644 index 97bb1092a..000000000 --- a/qemu/hw/acpi/cpu_hotplug_acpi_table.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/acpi/cpu_hotplug.h" - -void build_cpu_hotplug_aml(Aml *ctx) -{ - Aml *method; - Aml *if_ctx; - Aml *else_ctx; - Aml *sb_scope = aml_scope("_SB"); - uint8_t madt_tmpl[8] = {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}; - Aml *cpu_id = aml_arg(0); - Aml *cpu_on = aml_local(0); - Aml *madt = aml_local(1); - Aml *cpus_map = aml_name(CPU_ON_BITMAP); - Aml *zero = aml_int(0); - Aml *one = aml_int(1); - - /* - * _MAT method - creates an madt apic buffer - * cpu_id = Arg0 = Processor ID = Local APIC ID - * cpu_on = Local0 = CPON flag for this cpu - * madt = Local1 = Buffer (in madt apic form) to return - */ - method = aml_method(CPU_MAT_METHOD, 1, AML_NOTSERIALIZED); - aml_append(method, - aml_store(aml_derefof(aml_index(cpus_map, cpu_id)), cpu_on)); - aml_append(method, - aml_store(aml_buffer(sizeof(madt_tmpl), madt_tmpl), madt)); - /* Update the processor id, lapic id, and enable/disable status */ - aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(2)))); - aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(3)))); - aml_append(method, aml_store(cpu_on, aml_index(madt, aml_int(4)))); - aml_append(method, aml_return(madt)); - aml_append(sb_scope, method); - - /* - * _STA method - return ON status of cpu - * cpu_id = Arg0 = Processor ID = Local APIC ID - * cpu_on = Local0 = CPON flag for this cpu - */ - method = aml_method(CPU_STATUS_METHOD, 1, AML_NOTSERIALIZED); - aml_append(method, - aml_store(aml_derefof(aml_index(cpus_map, cpu_id)), cpu_on)); - if_ctx = aml_if(cpu_on); - { - aml_append(if_ctx, aml_return(aml_int(0xF))); - } - aml_append(method, if_ctx); - else_ctx = aml_else(); - { - aml_append(else_ctx, aml_return(zero)); - } - aml_append(method, else_ctx); - aml_append(sb_scope, method); - - method = aml_method(CPU_EJECT_METHOD, 2, AML_NOTSERIALIZED); - aml_append(method, aml_sleep(200)); - aml_append(sb_scope, method); - - method = aml_method(CPU_SCAN_METHOD, 0, AML_NOTSERIALIZED); - { - Aml *while_ctx, *if_ctx2, *else_ctx2; - Aml *bus_check_evt = aml_int(1); - Aml *remove_evt = aml_int(3); - Aml *status_map = aml_local(5); /* Local5 = active cpu bitmap */ - Aml *byte = aml_local(2); /* Local2 = last read byte from bitmap */ - Aml *idx = aml_local(0); /* Processor ID / APIC ID iterator */ - Aml *is_cpu_on = aml_local(1); /* Local1 = CPON flag for cpu */ - Aml *status = aml_local(3); /* Local3 = active state for cpu */ - - aml_append(method, aml_store(aml_name(CPU_STATUS_MAP), status_map)); - aml_append(method, aml_store(zero, byte)); - aml_append(method, aml_store(zero, idx)); - - /* While (idx < SizeOf(CPON)) */ - while_ctx = aml_while(aml_lless(idx, aml_sizeof(cpus_map))); - aml_append(while_ctx, - aml_store(aml_derefof(aml_index(cpus_map, idx)), is_cpu_on)); - - if_ctx = aml_if(aml_and(idx, aml_int(0x07), NULL)); - { - /* Shift down previously read bitmap byte */ - aml_append(if_ctx, aml_shiftright(byte, one, byte)); - } - aml_append(while_ctx, if_ctx); - - else_ctx = aml_else(); - { - /* Read next byte from cpu bitmap */ - aml_append(else_ctx, aml_store(aml_derefof(aml_index(status_map, - aml_shiftright(idx, aml_int(3), NULL))), byte)); - } - aml_append(while_ctx, else_ctx); - - aml_append(while_ctx, aml_store(aml_and(byte, one, NULL), status)); - if_ctx = aml_if(aml_lnot(aml_equal(is_cpu_on, status))); - { - /* State change - update CPON with new state */ - aml_append(if_ctx, aml_store(status, aml_index(cpus_map, idx))); - if_ctx2 = aml_if(aml_equal(status, one)); - { - aml_append(if_ctx2, - aml_call2(AML_NOTIFY_METHOD, idx, bus_check_evt)); - } - aml_append(if_ctx, if_ctx2); - else_ctx2 = aml_else(); - { - aml_append(else_ctx2, - aml_call2(AML_NOTIFY_METHOD, idx, remove_evt)); - } - } - aml_append(if_ctx, else_ctx2); - aml_append(while_ctx, if_ctx); - - aml_append(while_ctx, aml_increment(idx)); /* go to next cpu */ - aml_append(method, while_ctx); - } - aml_append(sb_scope, method); - - aml_append(ctx, sb_scope); -} diff --git a/qemu/hw/acpi/ich9.c b/qemu/hw/acpi/ich9.c deleted file mode 100644 index 27e978f5f..000000000 --- a/qemu/hw/acpi/ich9.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * ACPI implementation - * - * Copyright (c) 2006 Fabrice Bellard - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> - * - * This is based on acpi.c. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "qapi/error.h" -#include "qapi/visitor.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "hw/acpi/acpi.h" -#include "hw/acpi/tco.h" -#include "sysemu/kvm.h" -#include "exec/address-spaces.h" - -#include "hw/i386/ich9.h" -#include "hw/mem/pc-dimm.h" - -//#define DEBUG - -#ifdef DEBUG -#define ICH9_DEBUG(fmt, ...) \ -do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0) -#else -#define ICH9_DEBUG(fmt, ...) do { } while (0) -#endif - -static void ich9_pm_update_sci_fn(ACPIREGS *regs) -{ - ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs); - acpi_update_sci(&pm->acpi_regs, pm->irq); -} - -static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width) -{ - ICH9LPCPMRegs *pm = opaque; - return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); -} - -static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - ICH9LPCPMRegs *pm = opaque; - acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); - acpi_update_sci(&pm->acpi_regs, pm->irq); -} - -static const MemoryRegionOps ich9_gpe_ops = { - .read = ich9_gpe_readb, - .write = ich9_gpe_writeb, - .valid.min_access_size = 1, - .valid.max_access_size = 4, - .impl.min_access_size = 1, - .impl.max_access_size = 1, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width) -{ - ICH9LPCPMRegs *pm = opaque; - switch (addr) { - case 0: - return pm->smi_en; - case 4: - return pm->smi_sts; - default: - return 0; - } -} - -static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - ICH9LPCPMRegs *pm = opaque; - TCOIORegs *tr = &pm->tco_regs; - uint64_t tco_en; - - switch (addr) { - case 0: - tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN; - /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */ - if (tr->tco.cnt1 & TCO_LOCK) { - val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en; - } - pm->smi_en &= ~pm->smi_en_wmask; - pm->smi_en |= (val & pm->smi_en_wmask); - break; - } -} - -static const MemoryRegionOps ich9_smi_ops = { - .read = ich9_smi_readl, - .write = ich9_smi_writel, - .valid.min_access_size = 4, - .valid.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base) -{ - ICH9_DEBUG("to 0x%x\n", pm_io_base); - - assert((pm_io_base & ICH9_PMIO_MASK) == 0); - - pm->pm_io_base = pm_io_base; - memory_region_transaction_begin(); - memory_region_set_enabled(&pm->io, pm->pm_io_base != 0); - memory_region_set_address(&pm->io, pm->pm_io_base); - memory_region_transaction_commit(); -} - -static int ich9_pm_post_load(void *opaque, int version_id) -{ - ICH9LPCPMRegs *pm = opaque; - uint32_t pm_io_base = pm->pm_io_base; - pm->pm_io_base = 0; - ich9_pm_iospace_update(pm, pm_io_base); - return 0; -} - -#define VMSTATE_GPE_ARRAY(_field, _state) \ - { \ - .name = (stringify(_field)), \ - .version_id = 0, \ - .num = ICH9_PMIO_GPE0_LEN, \ - .info = &vmstate_info_uint8, \ - .size = sizeof(uint8_t), \ - .flags = VMS_ARRAY | VMS_POINTER, \ - .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ - } - -static bool vmstate_test_use_memhp(void *opaque) -{ - ICH9LPCPMRegs *s = opaque; - return s->acpi_memory_hotplug.is_enabled; -} - -static const VMStateDescription vmstate_memhp_state = { - .name = "ich9_pm/memhp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .needed = vmstate_test_use_memhp, - .fields = (VMStateField[]) { - VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs), - VMSTATE_END_OF_LIST() - } -}; - -static bool vmstate_test_use_tco(void *opaque) -{ - ICH9LPCPMRegs *s = opaque; - return s->enable_tco; -} - -static const VMStateDescription vmstate_tco_io_state = { - .name = "ich9_pm/tco", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .needed = vmstate_test_use_tco, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts, - TCOIORegs), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_ich9_pm = { - .name = "ich9_pm", - .version_id = 1, - .minimum_version_id = 1, - .post_load = ich9_pm_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs), - VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs), - VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs), - VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs), - VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs), - VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs), - VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs), - VMSTATE_UINT32(smi_en, ICH9LPCPMRegs), - VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_memhp_state, - &vmstate_tco_io_state, - NULL - } -}; - -static void pm_reset(void *opaque) -{ - ICH9LPCPMRegs *pm = opaque; - ich9_pm_iospace_update(pm, 0); - - acpi_pm1_evt_reset(&pm->acpi_regs); - acpi_pm1_cnt_reset(&pm->acpi_regs); - acpi_pm_tmr_reset(&pm->acpi_regs); - acpi_gpe_reset(&pm->acpi_regs); - - pm->smi_en = 0; - if (!pm->smm_enabled) { - /* Mark SMM as already inited to prevent SMM from running. */ - pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN; - } - pm->smi_en_wmask = ~0; - - acpi_update_sci(&pm->acpi_regs, pm->irq); -} - -static void pm_powerdown_req(Notifier *n, void *opaque) -{ - ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier); - - acpi_pm1_evt_power_down(&pm->acpi_regs); -} - -void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, - bool smm_enabled, - qemu_irq sci_irq) -{ - memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE); - memory_region_set_enabled(&pm->io, false); - memory_region_add_subregion(pci_address_space_io(lpc_pci), - 0, &pm->io); - - acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); - acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); - acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4, - pm->s4_val); - - acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN); - memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm, - "acpi-gpe0", ICH9_PMIO_GPE0_LEN); - memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe); - - memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm, - "acpi-smi", 8); - memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); - - pm->smm_enabled = smm_enabled; - - pm->enable_tco = true; - acpi_pm_tco_init(&pm->tco_regs, &pm->io); - - pm->irq = sci_irq; - qemu_register_reset(pm_reset, pm); - pm->powerdown_notifier.notify = pm_powerdown_req; - qemu_register_powerdown_notifier(&pm->powerdown_notifier); - - acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci), - &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE); - - if (pm->acpi_memory_hotplug.is_enabled) { - acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci), - &pm->acpi_memory_hotplug); - } -} - -static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ICH9LPCPMRegs *pm = opaque; - uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS; - - visit_type_uint32(v, name, &value, errp); -} - -static bool ich9_pm_get_memory_hotplug_support(Object *obj, Error **errp) -{ - ICH9LPCState *s = ICH9_LPC_DEVICE(obj); - - return s->pm.acpi_memory_hotplug.is_enabled; -} - -static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value, - Error **errp) -{ - ICH9LPCState *s = ICH9_LPC_DEVICE(obj); - - s->pm.acpi_memory_hotplug.is_enabled = value; -} - -static void ich9_pm_get_disable_s3(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ICH9LPCPMRegs *pm = opaque; - uint8_t value = pm->disable_s3; - - visit_type_uint8(v, name, &value, errp); -} - -static void ich9_pm_set_disable_s3(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ICH9LPCPMRegs *pm = opaque; - Error *local_err = NULL; - uint8_t value; - - visit_type_uint8(v, name, &value, &local_err); - if (local_err) { - goto out; - } - pm->disable_s3 = value; -out: - error_propagate(errp, local_err); -} - -static void ich9_pm_get_disable_s4(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ICH9LPCPMRegs *pm = opaque; - uint8_t value = pm->disable_s4; - - visit_type_uint8(v, name, &value, errp); -} - -static void ich9_pm_set_disable_s4(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ICH9LPCPMRegs *pm = opaque; - Error *local_err = NULL; - uint8_t value; - - visit_type_uint8(v, name, &value, &local_err); - if (local_err) { - goto out; - } - pm->disable_s4 = value; -out: - error_propagate(errp, local_err); -} - -static void ich9_pm_get_s4_val(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ICH9LPCPMRegs *pm = opaque; - uint8_t value = pm->s4_val; - - visit_type_uint8(v, name, &value, errp); -} - -static void ich9_pm_set_s4_val(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - ICH9LPCPMRegs *pm = opaque; - Error *local_err = NULL; - uint8_t value; - - visit_type_uint8(v, name, &value, &local_err); - if (local_err) { - goto out; - } - pm->s4_val = value; -out: - error_propagate(errp, local_err); -} - -static bool ich9_pm_get_enable_tco(Object *obj, Error **errp) -{ - ICH9LPCState *s = ICH9_LPC_DEVICE(obj); - return s->pm.enable_tco; -} - -static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) -{ - ICH9LPCState *s = ICH9_LPC_DEVICE(obj); - s->pm.enable_tco = value; -} - -void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) -{ - static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; - pm->acpi_memory_hotplug.is_enabled = true; - pm->disable_s3 = 0; - pm->disable_s4 = 0; - pm->s4_val = 2; - - object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, - &pm->pm_io_base, errp); - object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", - ich9_pm_get_gpe0_blk, - NULL, NULL, pm, NULL); - object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, - &gpe0_len, errp); - object_property_add_bool(obj, "memory-hotplug-support", - ich9_pm_get_memory_hotplug_support, - ich9_pm_set_memory_hotplug_support, - NULL); - object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", - ich9_pm_get_disable_s3, - ich9_pm_set_disable_s3, - NULL, pm, NULL); - object_property_add(obj, ACPI_PM_PROP_S4_DISABLED, "uint8", - ich9_pm_get_disable_s4, - ich9_pm_set_disable_s4, - NULL, pm, NULL); - object_property_add(obj, ACPI_PM_PROP_S4_VAL, "uint8", - ich9_pm_get_s4_val, - ich9_pm_set_s4_val, - NULL, pm, NULL); - object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED, - ich9_pm_get_enable_tco, - ich9_pm_set_enable_tco, - NULL); -} - -void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp) -{ - if (pm->acpi_memory_hotplug.is_enabled && - object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_plug_cb(&pm->acpi_regs, pm->irq, &pm->acpi_memory_hotplug, - dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - acpi_cpu_plug_cb(&pm->acpi_regs, pm->irq, &pm->gpe_cpu, dev, errp); - } else { - error_setg(errp, "acpi: device plug request for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); - } -} - -void ich9_pm_device_unplug_request_cb(ICH9LPCPMRegs *pm, DeviceState *dev, - Error **errp) -{ - if (pm->acpi_memory_hotplug.is_enabled && - object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_unplug_request_cb(&pm->acpi_regs, pm->irq, - &pm->acpi_memory_hotplug, dev, errp); - } else { - error_setg(errp, "acpi: device unplug request for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); - } -} - -void ich9_pm_device_unplug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, - Error **errp) -{ - if (pm->acpi_memory_hotplug.is_enabled && - object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_unplug_cb(&pm->acpi_memory_hotplug, dev, errp); - } else { - error_setg(errp, "acpi: device unplug for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); - } -} - -void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) -{ - ICH9LPCState *s = ICH9_LPC_DEVICE(adev); - - acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); -} diff --git a/qemu/hw/acpi/memory_hotplug.c b/qemu/hw/acpi/memory_hotplug.c deleted file mode 100644 index f65a3a21e..000000000 --- a/qemu/hw/acpi/memory_hotplug.c +++ /dev/null @@ -1,312 +0,0 @@ -#include "qemu/osdep.h" -#include "hw/acpi/memory_hotplug.h" -#include "hw/acpi/pc-hotplug.h" -#include "hw/mem/pc-dimm.h" -#include "hw/boards.h" -#include "hw/qdev-core.h" -#include "trace.h" -#include "qapi-event.h" - -static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev) -{ - ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1); - - info->slot_type = ACPI_SLOT_TYPE_DIMM; - info->slot = g_strdup_printf("%d", slot); - info->source = mdev->ost_event; - info->status = mdev->ost_status; - if (mdev->dimm) { - DeviceState *dev = DEVICE(mdev->dimm); - if (dev->id) { - info->device = g_strdup(dev->id); - info->has_device = true; - } - } - return info; -} - -void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list) -{ - int i; - - for (i = 0; i < mem_st->dev_count; i++) { - ACPIOSTInfoList *elem = g_new0(ACPIOSTInfoList, 1); - elem->value = acpi_memory_device_status(i, &mem_st->devs[i]); - elem->next = NULL; - **list = elem; - *list = &elem->next; - } -} - -static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr, - unsigned int size) -{ - uint32_t val = 0; - MemHotplugState *mem_st = opaque; - MemStatus *mdev; - Object *o; - - if (mem_st->selector >= mem_st->dev_count) { - trace_mhp_acpi_invalid_slot_selected(mem_st->selector); - return 0; - } - - mdev = &mem_st->devs[mem_st->selector]; - o = OBJECT(mdev->dimm); - switch (addr) { - case 0x0: /* Lo part of phys address where DIMM is mapped */ - val = o ? object_property_get_int(o, PC_DIMM_ADDR_PROP, NULL) : 0; - trace_mhp_acpi_read_addr_lo(mem_st->selector, val); - break; - case 0x4: /* Hi part of phys address where DIMM is mapped */ - val = o ? object_property_get_int(o, PC_DIMM_ADDR_PROP, NULL) >> 32 : 0; - trace_mhp_acpi_read_addr_hi(mem_st->selector, val); - break; - case 0x8: /* Lo part of DIMM size */ - val = o ? object_property_get_int(o, PC_DIMM_SIZE_PROP, NULL) : 0; - trace_mhp_acpi_read_size_lo(mem_st->selector, val); - break; - case 0xc: /* Hi part of DIMM size */ - val = o ? object_property_get_int(o, PC_DIMM_SIZE_PROP, NULL) >> 32 : 0; - trace_mhp_acpi_read_size_hi(mem_st->selector, val); - break; - case 0x10: /* node proximity for _PXM method */ - val = o ? object_property_get_int(o, PC_DIMM_NODE_PROP, NULL) : 0; - trace_mhp_acpi_read_pxm(mem_st->selector, val); - break; - case 0x14: /* pack and return is_* fields */ - val |= mdev->is_enabled ? 1 : 0; - val |= mdev->is_inserting ? 2 : 0; - val |= mdev->is_removing ? 4 : 0; - trace_mhp_acpi_read_flags(mem_st->selector, val); - break; - default: - val = ~0; - break; - } - return val; -} - -static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) -{ - MemHotplugState *mem_st = opaque; - MemStatus *mdev; - ACPIOSTInfo *info; - DeviceState *dev = NULL; - HotplugHandler *hotplug_ctrl = NULL; - Error *local_err = NULL; - - if (!mem_st->dev_count) { - return; - } - - if (addr) { - if (mem_st->selector >= mem_st->dev_count) { - trace_mhp_acpi_invalid_slot_selected(mem_st->selector); - return; - } - } - - switch (addr) { - case 0x0: /* DIMM slot selector */ - mem_st->selector = data; - trace_mhp_acpi_write_slot(mem_st->selector); - break; - case 0x4: /* _OST event */ - mdev = &mem_st->devs[mem_st->selector]; - if (data == 1) { - /* TODO: handle device insert OST event */ - } else if (data == 3) { - /* TODO: handle device remove OST event */ - } - mdev->ost_event = data; - trace_mhp_acpi_write_ost_ev(mem_st->selector, mdev->ost_event); - break; - case 0x8: /* _OST status */ - mdev = &mem_st->devs[mem_st->selector]; - mdev->ost_status = data; - trace_mhp_acpi_write_ost_status(mem_st->selector, mdev->ost_status); - /* TODO: implement memory removal on guest signal */ - - info = acpi_memory_device_status(mem_st->selector, mdev); - qapi_event_send_acpi_device_ost(info, &error_abort); - qapi_free_ACPIOSTInfo(info); - break; - case 0x14: /* set is_* fields */ - mdev = &mem_st->devs[mem_st->selector]; - if (data & 2) { /* clear insert event */ - mdev->is_inserting = false; - trace_mhp_acpi_clear_insert_evt(mem_st->selector); - } else if (data & 4) { - mdev->is_removing = false; - trace_mhp_acpi_clear_remove_evt(mem_st->selector); - } else if (data & 8) { - if (!mdev->is_enabled) { - trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector); - break; - } - - dev = DEVICE(mdev->dimm); - hotplug_ctrl = qdev_get_hotplug_handler(dev); - /* call pc-dimm unplug cb */ - hotplug_handler_unplug(hotplug_ctrl, dev, &local_err); - if (local_err) { - trace_mhp_acpi_pc_dimm_delete_failed(mem_st->selector); - qapi_event_send_mem_unplug_error(dev->id, - error_get_pretty(local_err), - &error_abort); - error_free(local_err); - break; - } - trace_mhp_acpi_pc_dimm_deleted(mem_st->selector); - } - break; - default: - break; - } - -} -static const MemoryRegionOps acpi_memory_hotplug_ops = { - .read = acpi_memory_hotplug_read, - .write = acpi_memory_hotplug_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, - MemHotplugState *state) -{ - MachineState *machine = MACHINE(qdev_get_machine()); - - state->dev_count = machine->ram_slots; - if (!state->dev_count) { - return; - } - - state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count); - memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state, - "acpi-mem-hotplug", ACPI_MEMORY_HOTPLUG_IO_LEN); - memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io); -} - -/** - * acpi_memory_slot_status: - * @mem_st: memory hotplug state - * @dev: device - * @errp: set in case of an error - * - * Obtain a single memory slot status. - * - * This function will be called by memory unplug request cb and unplug cb. - */ -static MemStatus * -acpi_memory_slot_status(MemHotplugState *mem_st, - DeviceState *dev, Error **errp) -{ - Error *local_err = NULL; - int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, - &local_err); - - if (local_err) { - error_propagate(errp, local_err); - return NULL; - } - - if (slot >= mem_st->dev_count) { - char *dev_path = object_get_canonical_path(OBJECT(dev)); - error_setg(errp, "acpi_memory_slot_status: " - "device [%s] returned invalid memory slot[%d]", - dev_path, slot); - g_free(dev_path); - return NULL; - } - - return &mem_st->devs[slot]; -} - -void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, - DeviceState *dev, Error **errp) -{ - MemStatus *mdev; - DeviceClass *dc = DEVICE_GET_CLASS(dev); - - if (!dc->hotpluggable) { - return; - } - - mdev = acpi_memory_slot_status(mem_st, dev, errp); - if (!mdev) { - return; - } - - mdev->dimm = dev; - mdev->is_enabled = true; - if (dev->hotplugged) { - mdev->is_inserting = true; - - /* do ACPI magic */ - acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS); - } -} - -void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq, - MemHotplugState *mem_st, - DeviceState *dev, Error **errp) -{ - MemStatus *mdev; - - mdev = acpi_memory_slot_status(mem_st, dev, errp); - if (!mdev) { - return; - } - - mdev->is_removing = true; - - /* Do ACPI magic */ - acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS); -} - -void acpi_memory_unplug_cb(MemHotplugState *mem_st, - DeviceState *dev, Error **errp) -{ - MemStatus *mdev; - - mdev = acpi_memory_slot_status(mem_st, dev, errp); - if (!mdev) { - return; - } - - mdev->is_enabled = false; - mdev->dimm = NULL; -} - -static const VMStateDescription vmstate_memhp_sts = { - .name = "memory hotplug device state", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_BOOL(is_enabled, MemStatus), - VMSTATE_BOOL(is_inserting, MemStatus), - VMSTATE_UINT32(ost_event, MemStatus), - VMSTATE_UINT32(ost_status, MemStatus), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_memory_hotplug = { - .name = "memory hotplug state", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(selector, MemHotplugState), - VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, MemHotplugState, dev_count, - vmstate_memhp_sts, MemStatus), - VMSTATE_END_OF_LIST() - } -}; diff --git a/qemu/hw/acpi/memory_hotplug_acpi_table.c b/qemu/hw/acpi/memory_hotplug_acpi_table.c deleted file mode 100644 index c75660215..000000000 --- a/qemu/hw/acpi/memory_hotplug_acpi_table.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Memory hotplug AML code of DSDT ACPI table - * - * Copyright (C) 2015 Red Hat Inc - * - * Author: Igor Mammedov <imammedo@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/acpi/memory_hotplug.h" -#include "include/hw/acpi/pc-hotplug.h" -#include "hw/boards.h" - -void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, - uint16_t io_base, uint16_t io_len) -{ - Aml *ifctx; - Aml *method; - Aml *pci_scope; - Aml *mem_ctrl_dev; - - /* scope for memory hotplug controller device node */ - pci_scope = aml_scope("_SB.PCI0"); - mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE); - { - Aml *one = aml_int(1); - Aml *zero = aml_int(0); - Aml *ret_val = aml_local(0); - Aml *slot_arg0 = aml_arg(0); - Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER); - Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK); - Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR); - - aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06"))); - aml_append(mem_ctrl_dev, - aml_name_decl("_UID", aml_string("Memory hotplug resources"))); - - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - ifctx = aml_if(aml_equal(slots_nr, zero)); - { - aml_append(ifctx, aml_return(zero)); - } - aml_append(method, ifctx); - /* present, functioning, decoding, not shown in UI */ - aml_append(method, aml_return(aml_int(0xB))); - aml_append(mem_ctrl_dev, method); - - aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0)); - - method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED); - { - Aml *else_ctx; - Aml *while_ctx; - Aml *idx = aml_local(0); - Aml *eject_req = aml_int(3); - Aml *dev_chk = aml_int(1); - - ifctx = aml_if(aml_equal(slots_nr, zero)); - { - aml_append(ifctx, aml_return(zero)); - } - aml_append(method, ifctx); - - aml_append(method, aml_store(zero, idx)); - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - /* build AML that: - * loops over all slots and Notifies DIMMs with - * Device Check or Eject Request notifications if - * slot has corresponding status bit set and clears - * slot status. - */ - while_ctx = aml_while(aml_lless(idx, slots_nr)); - { - Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT); - Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT); - - aml_append(while_ctx, aml_store(idx, slot_selector)); - ifctx = aml_if(aml_equal(ins_evt, one)); - { - aml_append(ifctx, - aml_call2(MEMORY_SLOT_NOTIFY_METHOD, - idx, dev_chk)); - aml_append(ifctx, aml_store(one, ins_evt)); - } - aml_append(while_ctx, ifctx); - - else_ctx = aml_else(); - ifctx = aml_if(aml_equal(rm_evt, one)); - { - aml_append(ifctx, - aml_call2(MEMORY_SLOT_NOTIFY_METHOD, - idx, eject_req)); - aml_append(ifctx, aml_store(one, rm_evt)); - } - aml_append(else_ctx, ifctx); - aml_append(while_ctx, else_ctx); - - aml_append(while_ctx, aml_add(idx, one, idx)); - } - aml_append(method, while_ctx); - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(one)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED); - { - Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED); - - aml_append(method, aml_store(zero, ret_val)); - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, - aml_store(aml_to_integer(slot_arg0), slot_selector)); - - ifctx = aml_if(aml_equal(slot_enabled, one)); - { - aml_append(ifctx, aml_store(aml_int(0xF), ret_val)); - } - aml_append(method, ifctx); - - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(ret_val)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED); - { - Aml *mr64 = aml_name("MR64"); - Aml *mr32 = aml_name("MR32"); - Aml *crs_tmpl = aml_resource_template(); - Aml *minl = aml_name("MINL"); - Aml *minh = aml_name("MINH"); - Aml *maxl = aml_name("MAXL"); - Aml *maxh = aml_name("MAXH"); - Aml *lenl = aml_name("LENL"); - Aml *lenh = aml_name("LENH"); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(aml_to_integer(slot_arg0), - slot_selector)); - - aml_append(crs_tmpl, - aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, - AML_CACHEABLE, AML_READ_WRITE, - 0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0, - 0xFFFFFFFFFFFFFFFFULL)); - aml_append(method, aml_name_decl("MR64", crs_tmpl)); - aml_append(method, - aml_create_dword_field(mr64, aml_int(14), "MINL")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(18), "MINH")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(38), "LENL")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(42), "LENH")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(22), "MAXL")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(26), "MAXH")); - - aml_append(method, - aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh)); - aml_append(method, - aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl)); - aml_append(method, - aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh)); - aml_append(method, - aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl)); - - /* 64-bit math: MAX = MIN + LEN - 1 */ - aml_append(method, aml_add(minl, lenl, maxl)); - aml_append(method, aml_add(minh, lenh, maxh)); - ifctx = aml_if(aml_lless(maxl, minl)); - { - aml_append(ifctx, aml_add(maxh, one, maxh)); - } - aml_append(method, ifctx); - ifctx = aml_if(aml_lless(maxl, one)); - { - aml_append(ifctx, aml_subtract(maxh, one, maxh)); - } - aml_append(method, ifctx); - aml_append(method, aml_subtract(maxl, one, maxl)); - - /* return 32-bit _CRS if addr/size is in low mem */ - /* TODO: remove it since all hotplugged DIMMs are in high mem */ - ifctx = aml_if(aml_equal(maxh, zero)); - { - crs_tmpl = aml_resource_template(); - aml_append(crs_tmpl, - aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, - AML_MAX_FIXED, AML_CACHEABLE, - AML_READ_WRITE, - 0, 0x0, 0xFFFFFFFE, 0, - 0xFFFFFFFF)); - aml_append(ifctx, aml_name_decl("MR32", crs_tmpl)); - aml_append(ifctx, - aml_create_dword_field(mr32, aml_int(10), "MIN")); - aml_append(ifctx, - aml_create_dword_field(mr32, aml_int(14), "MAX")); - aml_append(ifctx, - aml_create_dword_field(mr32, aml_int(22), "LEN")); - aml_append(ifctx, aml_store(minl, aml_name("MIN"))); - aml_append(ifctx, aml_store(maxl, aml_name("MAX"))); - aml_append(ifctx, aml_store(lenl, aml_name("LEN"))); - - aml_append(ifctx, aml_release(ctrl_lock)); - aml_append(ifctx, aml_return(mr32)); - } - aml_append(method, ifctx); - - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(mr64)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1, - AML_NOTSERIALIZED); - { - Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(aml_to_integer(slot_arg0), - slot_selector)); - aml_append(method, aml_store(proximity, ret_val)); - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(ret_val)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED); - { - Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT); - Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(aml_to_integer(slot_arg0), - slot_selector)); - aml_append(method, aml_store(aml_arg(1), ost_evt)); - aml_append(method, aml_store(aml_arg(2), ost_status)); - aml_append(method, aml_release(ctrl_lock)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED); - { - Aml *eject = aml_name(MEMORY_SLOT_EJECT); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(aml_to_integer(slot_arg0), - slot_selector)); - aml_append(method, aml_store(one, eject)); - aml_append(method, aml_release(ctrl_lock)); - } - aml_append(mem_ctrl_dev, method); - } - aml_append(pci_scope, mem_ctrl_dev); - aml_append(ctx, pci_scope); -} diff --git a/qemu/hw/acpi/nvdimm.c b/qemu/hw/acpi/nvdimm.c deleted file mode 100644 index 9531340e5..000000000 --- a/qemu/hw/acpi/nvdimm.c +++ /dev/null @@ -1,706 +0,0 @@ -/* - * NVDIMM ACPI Implementation - * - * Copyright(C) 2015 Intel Corporation. - * - * Author: - * Xiao Guangrong <guangrong.xiao@linux.intel.com> - * - * NFIT is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT) - * and the DSM specification can be found at: - * http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf - * - * Currently, it only supports PMEM Virtualization. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "hw/acpi/acpi.h" -#include "hw/acpi/aml-build.h" -#include "hw/acpi/bios-linker-loader.h" -#include "hw/nvram/fw_cfg.h" -#include "hw/mem/nvdimm.h" - -static int nvdimm_plugged_device_list(Object *obj, void *opaque) -{ - GSList **list = opaque; - - if (object_dynamic_cast(obj, TYPE_NVDIMM)) { - DeviceState *dev = DEVICE(obj); - - if (dev->realized) { /* only realized NVDIMMs matter */ - *list = g_slist_append(*list, DEVICE(obj)); - } - } - - object_child_foreach(obj, nvdimm_plugged_device_list, opaque); - return 0; -} - -/* - * inquire plugged NVDIMM devices and link them into the list which is - * returned to the caller. - * - * Note: it is the caller's responsibility to free the list to avoid - * memory leak. - */ -static GSList *nvdimm_get_plugged_device_list(void) -{ - GSList *list = NULL; - - object_child_foreach(qdev_get_machine(), nvdimm_plugged_device_list, - &list); - return list; -} - -#define NVDIMM_UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ - { (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ - (b) & 0xff, ((b) >> 8) & 0xff, (c) & 0xff, ((c) >> 8) & 0xff, \ - (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } - -/* - * define Byte Addressable Persistent Memory (PM) Region according to - * ACPI 6.0: 5.2.25.1 System Physical Address Range Structure. - */ -static const uint8_t nvdimm_nfit_spa_uuid[] = - NVDIMM_UUID_LE(0x66f0d379, 0xb4f3, 0x4074, 0xac, 0x43, 0x0d, 0x33, - 0x18, 0xb7, 0x8c, 0xdb); - -/* - * NVDIMM Firmware Interface Table - * @signature: "NFIT" - * - * It provides information that allows OSPM to enumerate NVDIMM present in - * the platform and associate system physical address ranges created by the - * NVDIMMs. - * - * It is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT) - */ -struct NvdimmNfitHeader { - ACPI_TABLE_HEADER_DEF - uint32_t reserved; -} QEMU_PACKED; -typedef struct NvdimmNfitHeader NvdimmNfitHeader; - -/* - * define NFIT structures according to ACPI 6.0: 5.2.25 NVDIMM Firmware - * Interface Table (NFIT). - */ - -/* - * System Physical Address Range Structure - * - * It describes the system physical address ranges occupied by NVDIMMs and - * the types of the regions. - */ -struct NvdimmNfitSpa { - uint16_t type; - uint16_t length; - uint16_t spa_index; - uint16_t flags; - uint32_t reserved; - uint32_t proximity_domain; - uint8_t type_guid[16]; - uint64_t spa_base; - uint64_t spa_length; - uint64_t mem_attr; -} QEMU_PACKED; -typedef struct NvdimmNfitSpa NvdimmNfitSpa; - -/* - * Memory Device to System Physical Address Range Mapping Structure - * - * It enables identifying each NVDIMM region and the corresponding SPA - * describing the memory interleave - */ -struct NvdimmNfitMemDev { - uint16_t type; - uint16_t length; - uint32_t nfit_handle; - uint16_t phys_id; - uint16_t region_id; - uint16_t spa_index; - uint16_t dcr_index; - uint64_t region_len; - uint64_t region_offset; - uint64_t region_dpa; - uint16_t interleave_index; - uint16_t interleave_ways; - uint16_t flags; - uint16_t reserved; -} QEMU_PACKED; -typedef struct NvdimmNfitMemDev NvdimmNfitMemDev; - -/* - * NVDIMM Control Region Structure - * - * It describes the NVDIMM and if applicable, Block Control Window. - */ -struct NvdimmNfitControlRegion { - uint16_t type; - uint16_t length; - uint16_t dcr_index; - uint16_t vendor_id; - uint16_t device_id; - uint16_t revision_id; - uint16_t sub_vendor_id; - uint16_t sub_device_id; - uint16_t sub_revision_id; - uint8_t reserved[6]; - uint32_t serial_number; - uint16_t fic; - uint16_t num_bcw; - uint64_t bcw_size; - uint64_t cmd_offset; - uint64_t cmd_size; - uint64_t status_offset; - uint64_t status_size; - uint16_t flags; - uint8_t reserved2[6]; -} QEMU_PACKED; -typedef struct NvdimmNfitControlRegion NvdimmNfitControlRegion; - -/* - * Module serial number is a unique number for each device. We use the - * slot id of NVDIMM device to generate this number so that each device - * associates with a different number. - * - * 0x123456 is a magic number we arbitrarily chose. - */ -static uint32_t nvdimm_slot_to_sn(int slot) -{ - return 0x123456 + slot; -} - -/* - * handle is used to uniquely associate nfit_memdev structure with NVDIMM - * ACPI device - nfit_memdev.nfit_handle matches with the value returned - * by ACPI device _ADR method. - * - * We generate the handle with the slot id of NVDIMM device and reserve - * 0 for NVDIMM root device. - */ -static uint32_t nvdimm_slot_to_handle(int slot) -{ - return slot + 1; -} - -/* - * index uniquely identifies the structure, 0 is reserved which indicates - * that the structure is not valid or the associated structure is not - * present. - * - * Each NVDIMM device needs two indexes, one for nfit_spa and another for - * nfit_dc which are generated by the slot id of NVDIMM device. - */ -static uint16_t nvdimm_slot_to_spa_index(int slot) -{ - return (slot + 1) << 1; -} - -/* See the comments of nvdimm_slot_to_spa_index(). */ -static uint32_t nvdimm_slot_to_dcr_index(int slot) -{ - return nvdimm_slot_to_spa_index(slot) + 1; -} - -/* ACPI 6.0: 5.2.25.1 System Physical Address Range Structure */ -static void -nvdimm_build_structure_spa(GArray *structures, DeviceState *dev) -{ - NvdimmNfitSpa *nfit_spa; - uint64_t addr = object_property_get_int(OBJECT(dev), PC_DIMM_ADDR_PROP, - NULL); - uint64_t size = object_property_get_int(OBJECT(dev), PC_DIMM_SIZE_PROP, - NULL); - uint32_t node = object_property_get_int(OBJECT(dev), PC_DIMM_NODE_PROP, - NULL); - int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, - NULL); - - nfit_spa = acpi_data_push(structures, sizeof(*nfit_spa)); - - nfit_spa->type = cpu_to_le16(0 /* System Physical Address Range - Structure */); - nfit_spa->length = cpu_to_le16(sizeof(*nfit_spa)); - nfit_spa->spa_index = cpu_to_le16(nvdimm_slot_to_spa_index(slot)); - - /* - * Control region is strict as all the device info, such as SN, index, - * is associated with slot id. - */ - nfit_spa->flags = cpu_to_le16(1 /* Control region is strictly for - management during hot add/online - operation */ | - 2 /* Data in Proximity Domain field is - valid*/); - - /* NUMA node. */ - nfit_spa->proximity_domain = cpu_to_le32(node); - /* the region reported as PMEM. */ - memcpy(nfit_spa->type_guid, nvdimm_nfit_spa_uuid, - sizeof(nvdimm_nfit_spa_uuid)); - - nfit_spa->spa_base = cpu_to_le64(addr); - nfit_spa->spa_length = cpu_to_le64(size); - - /* It is the PMEM and can be cached as writeback. */ - nfit_spa->mem_attr = cpu_to_le64(0x8ULL /* EFI_MEMORY_WB */ | - 0x8000ULL /* EFI_MEMORY_NV */); -} - -/* - * ACPI 6.0: 5.2.25.2 Memory Device to System Physical Address Range Mapping - * Structure - */ -static void -nvdimm_build_structure_memdev(GArray *structures, DeviceState *dev) -{ - NvdimmNfitMemDev *nfit_memdev; - uint64_t addr = object_property_get_int(OBJECT(dev), PC_DIMM_ADDR_PROP, - NULL); - uint64_t size = object_property_get_int(OBJECT(dev), PC_DIMM_SIZE_PROP, - NULL); - int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, - NULL); - uint32_t handle = nvdimm_slot_to_handle(slot); - - nfit_memdev = acpi_data_push(structures, sizeof(*nfit_memdev)); - - nfit_memdev->type = cpu_to_le16(1 /* Memory Device to System Address - Range Map Structure*/); - nfit_memdev->length = cpu_to_le16(sizeof(*nfit_memdev)); - nfit_memdev->nfit_handle = cpu_to_le32(handle); - - /* - * associate memory device with System Physical Address Range - * Structure. - */ - nfit_memdev->spa_index = cpu_to_le16(nvdimm_slot_to_spa_index(slot)); - /* associate memory device with Control Region Structure. */ - nfit_memdev->dcr_index = cpu_to_le16(nvdimm_slot_to_dcr_index(slot)); - - /* The memory region on the device. */ - nfit_memdev->region_len = cpu_to_le64(size); - nfit_memdev->region_dpa = cpu_to_le64(addr); - - /* Only one interleave for PMEM. */ - nfit_memdev->interleave_ways = cpu_to_le16(1); -} - -/* - * ACPI 6.0: 5.2.25.5 NVDIMM Control Region Structure. - */ -static void nvdimm_build_structure_dcr(GArray *structures, DeviceState *dev) -{ - NvdimmNfitControlRegion *nfit_dcr; - int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, - NULL); - uint32_t sn = nvdimm_slot_to_sn(slot); - - nfit_dcr = acpi_data_push(structures, sizeof(*nfit_dcr)); - - nfit_dcr->type = cpu_to_le16(4 /* NVDIMM Control Region Structure */); - nfit_dcr->length = cpu_to_le16(sizeof(*nfit_dcr)); - nfit_dcr->dcr_index = cpu_to_le16(nvdimm_slot_to_dcr_index(slot)); - - /* vendor: Intel. */ - nfit_dcr->vendor_id = cpu_to_le16(0x8086); - nfit_dcr->device_id = cpu_to_le16(1); - - /* The _DSM method is following Intel's DSM specification. */ - nfit_dcr->revision_id = cpu_to_le16(1 /* Current Revision supported - in ACPI 6.0 is 1. */); - nfit_dcr->serial_number = cpu_to_le32(sn); - nfit_dcr->fic = cpu_to_le16(0x201 /* Format Interface Code. See Chapter - 2: NVDIMM Device Specific Method - (DSM) in DSM Spec Rev1.*/); -} - -static GArray *nvdimm_build_device_structure(GSList *device_list) -{ - GArray *structures = g_array_new(false, true /* clear */, 1); - - for (; device_list; device_list = device_list->next) { - DeviceState *dev = device_list->data; - - /* build System Physical Address Range Structure. */ - nvdimm_build_structure_spa(structures, dev); - - /* - * build Memory Device to System Physical Address Range Mapping - * Structure. - */ - nvdimm_build_structure_memdev(structures, dev); - - /* build NVDIMM Control Region Structure. */ - nvdimm_build_structure_dcr(structures, dev); - } - - return structures; -} - -static void nvdimm_build_nfit(GSList *device_list, GArray *table_offsets, - GArray *table_data, GArray *linker) -{ - GArray *structures = nvdimm_build_device_structure(device_list); - unsigned int header; - - acpi_add_table(table_offsets, table_data); - - /* NFIT header. */ - header = table_data->len; - acpi_data_push(table_data, sizeof(NvdimmNfitHeader)); - /* NVDIMM device structures. */ - g_array_append_vals(table_data, structures->data, structures->len); - - build_header(linker, table_data, - (void *)(table_data->data + header), "NFIT", - sizeof(NvdimmNfitHeader) + structures->len, 1, NULL, NULL); - g_array_free(structures, true); -} - -struct NvdimmDsmIn { - uint32_t handle; - uint32_t revision; - uint32_t function; - /* the remaining size in the page is used by arg3. */ - union { - uint8_t arg3[0]; - }; -} QEMU_PACKED; -typedef struct NvdimmDsmIn NvdimmDsmIn; - -struct NvdimmDsmOut { - /* the size of buffer filled by QEMU. */ - uint32_t len; - uint8_t data[0]; -} QEMU_PACKED; -typedef struct NvdimmDsmOut NvdimmDsmOut; - -struct NvdimmDsmFunc0Out { - /* the size of buffer filled by QEMU. */ - uint32_t len; - uint32_t supported_func; -} QEMU_PACKED; -typedef struct NvdimmDsmFunc0Out NvdimmDsmFunc0Out; - -struct NvdimmDsmFuncNoPayloadOut { - /* the size of buffer filled by QEMU. */ - uint32_t len; - uint32_t func_ret_status; -} QEMU_PACKED; -typedef struct NvdimmDsmFuncNoPayloadOut NvdimmDsmFuncNoPayloadOut; - -static uint64_t -nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size) -{ - nvdimm_debug("BUG: we never read _DSM IO Port.\n"); - return 0; -} - -static void -nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) -{ - NvdimmDsmIn *in; - hwaddr dsm_mem_addr = val; - - nvdimm_debug("dsm memory address %#" HWADDR_PRIx ".\n", dsm_mem_addr); - - /* - * The DSM memory is mapped to guest address space so an evil guest - * can change its content while we are doing DSM emulation. Avoid - * this by copying DSM memory to QEMU local memory. - */ - in = g_malloc(TARGET_PAGE_SIZE); - cpu_physical_memory_read(dsm_mem_addr, in, TARGET_PAGE_SIZE); - - le32_to_cpus(&in->revision); - le32_to_cpus(&in->function); - le32_to_cpus(&in->handle); - - nvdimm_debug("Revision %#x Handler %#x Function %#x.\n", in->revision, - in->handle, in->function); - - /* - * function 0 is called to inquire which functions are supported by - * OSPM - */ - if (in->function == 0) { - NvdimmDsmFunc0Out func0 = { - .len = cpu_to_le32(sizeof(func0)), - /* No function supported other than function 0 */ - .supported_func = cpu_to_le32(0), - }; - cpu_physical_memory_write(dsm_mem_addr, &func0, sizeof func0); - } else { - /* No function except function 0 is supported yet. */ - NvdimmDsmFuncNoPayloadOut out = { - .len = cpu_to_le32(sizeof(out)), - .func_ret_status = cpu_to_le32(1) /* Not Supported */, - }; - cpu_physical_memory_write(dsm_mem_addr, &out, sizeof(out)); - } - - g_free(in); -} - -static const MemoryRegionOps nvdimm_dsm_ops = { - .read = nvdimm_dsm_read, - .write = nvdimm_dsm_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -void nvdimm_init_acpi_state(AcpiNVDIMMState *state, MemoryRegion *io, - FWCfgState *fw_cfg, Object *owner) -{ - memory_region_init_io(&state->io_mr, owner, &nvdimm_dsm_ops, state, - "nvdimm-acpi-io", NVDIMM_ACPI_IO_LEN); - memory_region_add_subregion(io, NVDIMM_ACPI_IO_BASE, &state->io_mr); - - state->dsm_mem = g_array_new(false, true /* clear */, 1); - acpi_data_push(state->dsm_mem, TARGET_PAGE_SIZE); - fw_cfg_add_file(fw_cfg, NVDIMM_DSM_MEM_FILE, state->dsm_mem->data, - state->dsm_mem->len); -} - -#define NVDIMM_COMMON_DSM "NCAL" -#define NVDIMM_ACPI_MEM_ADDR "MEMA" - -static void nvdimm_build_common_dsm(Aml *dev) -{ - Aml *method, *ifctx, *function, *dsm_mem, *unpatched, *result_size; - uint8_t byte_list[1]; - - method = aml_method(NVDIMM_COMMON_DSM, 4, AML_SERIALIZED); - function = aml_arg(2); - dsm_mem = aml_name(NVDIMM_ACPI_MEM_ADDR); - - /* - * do not support any method if DSM memory address has not been - * patched. - */ - unpatched = aml_if(aml_equal(dsm_mem, aml_int(0x0))); - - /* - * function 0 is called to inquire what functions are supported by - * OSPM - */ - ifctx = aml_if(aml_equal(function, aml_int(0))); - byte_list[0] = 0 /* No function Supported */; - aml_append(ifctx, aml_return(aml_buffer(1, byte_list))); - aml_append(unpatched, ifctx); - - /* No function is supported yet. */ - byte_list[0] = 1 /* Not Supported */; - aml_append(unpatched, aml_return(aml_buffer(1, byte_list))); - aml_append(method, unpatched); - - /* - * The HDLE indicates the DSM function is issued from which device, - * it is not used at this time as no function is supported yet. - * Currently we make it always be 0 for all the devices and will set - * the appropriate value once real function is implemented. - */ - aml_append(method, aml_store(aml_int(0x0), aml_name("HDLE"))); - aml_append(method, aml_store(aml_arg(1), aml_name("REVS"))); - aml_append(method, aml_store(aml_arg(2), aml_name("FUNC"))); - - /* - * tell QEMU about the real address of DSM memory, then QEMU - * gets the control and fills the result in DSM memory. - */ - aml_append(method, aml_store(dsm_mem, aml_name("NTFI"))); - - result_size = aml_local(1); - aml_append(method, aml_store(aml_name("RLEN"), result_size)); - aml_append(method, aml_store(aml_shiftleft(result_size, aml_int(3)), - result_size)); - aml_append(method, aml_create_field(aml_name("ODAT"), aml_int(0), - result_size, "OBUF")); - aml_append(method, aml_concatenate(aml_buffer(0, NULL), aml_name("OBUF"), - aml_arg(6))); - aml_append(method, aml_return(aml_arg(6))); - aml_append(dev, method); -} - -static void nvdimm_build_device_dsm(Aml *dev) -{ - Aml *method; - - method = aml_method("_DSM", 4, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_call4(NVDIMM_COMMON_DSM, aml_arg(0), - aml_arg(1), aml_arg(2), aml_arg(3)))); - aml_append(dev, method); -} - -static void nvdimm_build_nvdimm_devices(GSList *device_list, Aml *root_dev) -{ - for (; device_list; device_list = device_list->next) { - DeviceState *dev = device_list->data; - int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, - NULL); - uint32_t handle = nvdimm_slot_to_handle(slot); - Aml *nvdimm_dev; - - nvdimm_dev = aml_device("NV%02X", slot); - - /* - * ACPI 6.0: 9.20 NVDIMM Devices: - * - * _ADR object that is used to supply OSPM with unique address - * of the NVDIMM device. This is done by returning the NFIT Device - * handle that is used to identify the associated entries in ACPI - * table NFIT or _FIT. - */ - aml_append(nvdimm_dev, aml_name_decl("_ADR", aml_int(handle))); - - nvdimm_build_device_dsm(nvdimm_dev); - aml_append(root_dev, nvdimm_dev); - } -} - -static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets, - GArray *table_data, GArray *linker) -{ - Aml *ssdt, *sb_scope, *dev, *field; - int mem_addr_offset, nvdimm_ssdt; - - acpi_add_table(table_offsets, table_data); - - ssdt = init_aml_allocator(); - acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader)); - - sb_scope = aml_scope("\\_SB"); - - dev = aml_device("NVDR"); - - /* - * ACPI 6.0: 9.20 NVDIMM Devices: - * - * The ACPI Name Space device uses _HID of ACPI0012 to identify the root - * NVDIMM interface device. Platform firmware is required to contain one - * such device in _SB scope if NVDIMMs support is exposed by platform to - * OSPM. - * For each NVDIMM present or intended to be supported by platform, - * platform firmware also exposes an ACPI Namespace Device under the - * root device. - */ - aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0012"))); - - /* map DSM memory and IO into ACPI namespace. */ - aml_append(dev, aml_operation_region("NPIO", AML_SYSTEM_IO, - aml_int(NVDIMM_ACPI_IO_BASE), NVDIMM_ACPI_IO_LEN)); - aml_append(dev, aml_operation_region("NRAM", AML_SYSTEM_MEMORY, - aml_name(NVDIMM_ACPI_MEM_ADDR), TARGET_PAGE_SIZE)); - - /* - * DSM notifier: - * NTFI: write the address of DSM memory and notify QEMU to emulate - * the access. - * - * It is the IO port so that accessing them will cause VM-exit, the - * control will be transferred to QEMU. - */ - field = aml_field("NPIO", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("NTFI", - sizeof(uint32_t) * BITS_PER_BYTE)); - aml_append(dev, field); - - /* - * DSM input: - * HDLE: store device's handle, it's zero if the _DSM call happens - * on NVDIMM Root Device. - * REVS: store the Arg1 of _DSM call. - * FUNC: store the Arg2 of _DSM call. - * ARG3: store the Arg3 of _DSM call. - * - * They are RAM mapping on host so that these accesses never cause - * VM-EXIT. - */ - field = aml_field("NRAM", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("HDLE", - sizeof(typeof_field(NvdimmDsmIn, handle)) * BITS_PER_BYTE)); - aml_append(field, aml_named_field("REVS", - sizeof(typeof_field(NvdimmDsmIn, revision)) * BITS_PER_BYTE)); - aml_append(field, aml_named_field("FUNC", - sizeof(typeof_field(NvdimmDsmIn, function)) * BITS_PER_BYTE)); - aml_append(field, aml_named_field("ARG3", - (TARGET_PAGE_SIZE - offsetof(NvdimmDsmIn, arg3)) * - BITS_PER_BYTE)); - aml_append(dev, field); - - /* - * DSM output: - * RLEN: the size of the buffer filled by QEMU. - * ODAT: the buffer QEMU uses to store the result. - * - * Since the page is reused by both input and out, the input data - * will be lost after storing new result into ODAT so we should fetch - * all the input data before writing the result. - */ - field = aml_field("NRAM", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("RLEN", - sizeof(typeof_field(NvdimmDsmOut, len)) * BITS_PER_BYTE)); - aml_append(field, aml_named_field("ODAT", - (TARGET_PAGE_SIZE - offsetof(NvdimmDsmOut, data)) * - BITS_PER_BYTE)); - aml_append(dev, field); - - nvdimm_build_common_dsm(dev); - nvdimm_build_device_dsm(dev); - - nvdimm_build_nvdimm_devices(device_list, dev); - - aml_append(sb_scope, dev); - aml_append(ssdt, sb_scope); - - nvdimm_ssdt = table_data->len; - - /* copy AML table into ACPI tables blob and patch header there */ - g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len); - mem_addr_offset = build_append_named_dword(table_data, - NVDIMM_ACPI_MEM_ADDR); - - bios_linker_loader_alloc(linker, NVDIMM_DSM_MEM_FILE, TARGET_PAGE_SIZE, - false /* high memory */); - bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, - NVDIMM_DSM_MEM_FILE, table_data, - table_data->data + mem_addr_offset, - sizeof(uint32_t)); - build_header(linker, table_data, - (void *)(table_data->data + nvdimm_ssdt), - "SSDT", table_data->len - nvdimm_ssdt, 1, NULL, "NVDIMM"); - free_aml_allocator(); -} - -void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data, - GArray *linker) -{ - GSList *device_list; - - /* no NVDIMM device is plugged. */ - device_list = nvdimm_get_plugged_device_list(); - if (!device_list) { - return; - } - nvdimm_build_nfit(device_list, table_offsets, table_data, linker); - nvdimm_build_ssdt(device_list, table_offsets, table_data, linker); - g_slist_free(device_list); -} diff --git a/qemu/hw/acpi/pcihp.c b/qemu/hw/acpi/pcihp.c deleted file mode 100644 index 71f4c4e14..000000000 --- a/qemu/hw/acpi/pcihp.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * QEMU<->ACPI BIOS PCI hotplug interface - * - * QEMU supports PCI hotplug via ACPI. This module - * implements the interface between QEMU and the ACPI BIOS. - * Interface specification - see docs/specs/acpi_pci_hotplug.txt - * - * Copyright (c) 2013, Red Hat Inc, Michael S. Tsirkin (mst@redhat.com) - * Copyright (c) 2006 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "hw/acpi/pcihp.h" - -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" -#include "hw/acpi/acpi.h" -#include "sysemu/sysemu.h" -#include "exec/ioport.h" -#include "exec/address-spaces.h" -#include "hw/pci/pci_bus.h" -#include "qapi/error.h" -#include "qom/qom-qobject.h" -#include "qapi/qmp/qint.h" - -//#define DEBUG - -#ifdef DEBUG -# define ACPI_PCIHP_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) -#else -# define ACPI_PCIHP_DPRINTF(format, ...) do { } while (0) -#endif - -#define ACPI_PCIHP_ADDR 0xae00 -#define ACPI_PCIHP_SIZE 0x0014 -#define ACPI_PCIHP_LEGACY_SIZE 0x000f -#define PCI_UP_BASE 0x0000 -#define PCI_DOWN_BASE 0x0004 -#define PCI_EJ_BASE 0x0008 -#define PCI_RMV_BASE 0x000c -#define PCI_SEL_BASE 0x0010 - -typedef struct AcpiPciHpFind { - int bsel; - PCIBus *bus; -} AcpiPciHpFind; - -static int acpi_pcihp_get_bsel(PCIBus *bus) -{ - Error *local_err = NULL; - int64_t bsel = object_property_get_int(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, - &local_err); - - if (local_err || bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) { - if (local_err) { - error_free(local_err); - } - return -1; - } else { - return bsel; - } -} - -static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque) -{ - AcpiPciHpFind *find = opaque; - if (find->bsel == acpi_pcihp_get_bsel(bus)) { - find->bus = bus; - } -} - -static PCIBus *acpi_pcihp_find_hotplug_bus(AcpiPciHpState *s, int bsel) -{ - AcpiPciHpFind find = { .bsel = bsel, .bus = NULL }; - - if (bsel < 0) { - return NULL; - } - - pci_for_each_bus(s->root, acpi_pcihp_test_hotplug_bus, &find); - - /* Make bsel 0 eject root bus if bsel property is not set, - * for compatibility with non acpi setups. - * TODO: really needed? - */ - if (!bsel && !find.bus) { - find.bus = s->root; - } - return find.bus; -} - -static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev) -{ - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); - DeviceClass *dc = DEVICE_GET_CLASS(dev); - /* - * ACPI doesn't allow hotplug of bridge devices. Don't allow - * hot-unplug of bridge devices unless they were added by hotplug - * (and so, not described by acpi). - */ - return (pc->is_bridge && !dev->qdev.hotplugged) || !dc->hotpluggable; -} - -static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots) -{ - BusChild *kid, *next; - int slot = ctz32(slots); - PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel); - - if (!bus) { - return; - } - - /* Mark request as complete */ - s->acpi_pcihp_pci_status[bsel].down &= ~(1U << slot); - s->acpi_pcihp_pci_status[bsel].up &= ~(1U << slot); - - QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) { - DeviceState *qdev = kid->child; - PCIDevice *dev = PCI_DEVICE(qdev); - if (PCI_SLOT(dev->devfn) == slot) { - if (!acpi_pcihp_pc_no_hotplug(s, dev)) { - object_unparent(OBJECT(qdev)); - } - } - } -} - -static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel) -{ - BusChild *kid, *next; - PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel); - - /* Execute any pending removes during reset */ - while (s->acpi_pcihp_pci_status[bsel].down) { - acpi_pcihp_eject_slot(s, bsel, s->acpi_pcihp_pci_status[bsel].down); - } - - s->acpi_pcihp_pci_status[bsel].hotplug_enable = ~0; - - if (!bus) { - return; - } - QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) { - DeviceState *qdev = kid->child; - PCIDevice *pdev = PCI_DEVICE(qdev); - int slot = PCI_SLOT(pdev->devfn); - - if (acpi_pcihp_pc_no_hotplug(s, pdev)) { - s->acpi_pcihp_pci_status[bsel].hotplug_enable &= ~(1U << slot); - } - } -} - -static void acpi_pcihp_update(AcpiPciHpState *s) -{ - int i; - - for (i = 0; i < ACPI_PCIHP_MAX_HOTPLUG_BUS; ++i) { - acpi_pcihp_update_hotplug_bus(s, i); - } -} - -void acpi_pcihp_reset(AcpiPciHpState *s) -{ - acpi_pcihp_update(s); -} - -void acpi_pcihp_device_plug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s, - DeviceState *dev, Error **errp) -{ - PCIDevice *pdev = PCI_DEVICE(dev); - int slot = PCI_SLOT(pdev->devfn); - int bsel = acpi_pcihp_get_bsel(pdev->bus); - if (bsel < 0) { - error_setg(errp, "Unsupported bus. Bus doesn't have property '" - ACPI_PCIHP_PROP_BSEL "' set"); - return; - } - - /* Don't send event when device is enabled during qemu machine creation: - * it is present on boot, no hotplug event is necessary. We do send an - * event when the device is disabled later. */ - if (!dev->hotplugged) { - return; - } - - s->acpi_pcihp_pci_status[bsel].up |= (1U << slot); - - acpi_send_gpe_event(ar, irq, ACPI_PCI_HOTPLUG_STATUS); -} - -void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s, - DeviceState *dev, Error **errp) -{ - PCIDevice *pdev = PCI_DEVICE(dev); - int slot = PCI_SLOT(pdev->devfn); - int bsel = acpi_pcihp_get_bsel(pdev->bus); - if (bsel < 0) { - error_setg(errp, "Unsupported bus. Bus doesn't have property '" - ACPI_PCIHP_PROP_BSEL "' set"); - return; - } - - s->acpi_pcihp_pci_status[bsel].down |= (1U << slot); - - acpi_send_gpe_event(ar, irq, ACPI_PCI_HOTPLUG_STATUS); -} - -static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size) -{ - AcpiPciHpState *s = opaque; - uint32_t val = 0; - int bsel = s->hotplug_select; - - if (bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) { - return 0; - } - - switch (addr) { - case PCI_UP_BASE: - val = s->acpi_pcihp_pci_status[bsel].up; - if (!s->legacy_piix) { - s->acpi_pcihp_pci_status[bsel].up = 0; - } - ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val); - break; - case PCI_DOWN_BASE: - val = s->acpi_pcihp_pci_status[bsel].down; - ACPI_PCIHP_DPRINTF("pci_down_read %" PRIu32 "\n", val); - break; - case PCI_EJ_BASE: - /* No feature defined yet */ - ACPI_PCIHP_DPRINTF("pci_features_read %" PRIu32 "\n", val); - break; - case PCI_RMV_BASE: - val = s->acpi_pcihp_pci_status[bsel].hotplug_enable; - ACPI_PCIHP_DPRINTF("pci_rmv_read %" PRIu32 "\n", val); - break; - case PCI_SEL_BASE: - val = s->hotplug_select; - ACPI_PCIHP_DPRINTF("pci_sel_read %" PRIu32 "\n", val); - default: - break; - } - - return val; -} - -static void pci_write(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) -{ - AcpiPciHpState *s = opaque; - switch (addr) { - case PCI_EJ_BASE: - if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) { - break; - } - acpi_pcihp_eject_slot(s, s->hotplug_select, data); - ACPI_PCIHP_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n", - addr, data); - break; - case PCI_SEL_BASE: - s->hotplug_select = data; - ACPI_PCIHP_DPRINTF("pcisel write %" HWADDR_PRIx " <== %" PRIu64 "\n", - addr, data); - default: - break; - } -} - -static const MemoryRegionOps acpi_pcihp_io_ops = { - .read = pci_read, - .write = pci_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, - MemoryRegion *address_space_io, bool bridges_enabled) -{ - s->io_len = ACPI_PCIHP_SIZE; - s->io_base = ACPI_PCIHP_ADDR; - - s->root= root_bus; - s->legacy_piix = !bridges_enabled; - - if (s->legacy_piix) { - unsigned *bus_bsel = g_malloc(sizeof *bus_bsel); - - s->io_len = ACPI_PCIHP_LEGACY_SIZE; - - *bus_bsel = ACPI_PCIHP_BSEL_DEFAULT; - object_property_add_uint32_ptr(OBJECT(root_bus), ACPI_PCIHP_PROP_BSEL, - bus_bsel, NULL); - } - - memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s, - "acpi-pci-hotplug", s->io_len); - memory_region_add_subregion(address_space_io, s->io_base, &s->io); - - object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_BASE_PROP, &s->io_base, - &error_abort); - object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_LEN_PROP, &s->io_len, - &error_abort); -} - -const VMStateDescription vmstate_acpi_pcihp_pci_status = { - .name = "acpi_pcihp_pci_status", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(up, AcpiPciHpPciStatus), - VMSTATE_UINT32(down, AcpiPciHpPciStatus), - VMSTATE_END_OF_LIST() - } -}; diff --git a/qemu/hw/acpi/piix4.c b/qemu/hw/acpi/piix4.c deleted file mode 100644 index 16abdf162..000000000 --- a/qemu/hw/acpi/piix4.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * ACPI implementation - * - * Copyright (c) 2006 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/isa/apm.h" -#include "hw/i2c/pm_smbus.h" -#include "hw/pci/pci.h" -#include "hw/acpi/acpi.h" -#include "sysemu/sysemu.h" -#include "qapi/error.h" -#include "qemu/range.h" -#include "exec/ioport.h" -#include "hw/nvram/fw_cfg.h" -#include "exec/address-spaces.h" -#include "hw/acpi/piix4.h" -#include "hw/acpi/pcihp.h" -#include "hw/acpi/cpu_hotplug.h" -#include "hw/hotplug.h" -#include "hw/mem/pc-dimm.h" -#include "hw/acpi/memory_hotplug.h" -#include "hw/acpi/acpi_dev_interface.h" -#include "hw/xen/xen.h" - -//#define DEBUG - -#ifdef DEBUG -# define PIIX4_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) -#else -# define PIIX4_DPRINTF(format, ...) do { } while (0) -#endif - -#define GPE_BASE 0xafe0 -#define GPE_LEN 4 - -struct pci_status { - uint32_t up; /* deprecated, maintained for migration compatibility */ - uint32_t down; -}; - -typedef struct PIIX4PMState { - /*< private >*/ - PCIDevice parent_obj; - /*< public >*/ - - MemoryRegion io; - uint32_t io_base; - - MemoryRegion io_gpe; - ACPIREGS ar; - - APMState apm; - - PMSMBus smb; - uint32_t smb_io_base; - - qemu_irq irq; - qemu_irq smi_irq; - int smm_enabled; - Notifier machine_ready; - Notifier powerdown_notifier; - - AcpiPciHpState acpi_pci_hotplug; - bool use_acpi_pci_hotplug; - - uint8_t disable_s3; - uint8_t disable_s4; - uint8_t s4_val; - - AcpiCpuHotplug gpe_cpu; - - MemHotplugState acpi_memory_hotplug; -} PIIX4PMState; - -#define TYPE_PIIX4_PM "PIIX4_PM" - -#define PIIX4_PM(obj) \ - OBJECT_CHECK(PIIX4PMState, (obj), TYPE_PIIX4_PM) - -static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, - PCIBus *bus, PIIX4PMState *s); - -#define ACPI_ENABLE 0xf1 -#define ACPI_DISABLE 0xf0 - -static void pm_tmr_timer(ACPIREGS *ar) -{ - PIIX4PMState *s = container_of(ar, PIIX4PMState, ar); - acpi_update_sci(&s->ar, s->irq); -} - -static void apm_ctrl_changed(uint32_t val, void *arg) -{ - PIIX4PMState *s = arg; - PCIDevice *d = PCI_DEVICE(s); - - /* ACPI specs 3.0, 4.7.2.5 */ - acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE); - if (val == ACPI_ENABLE || val == ACPI_DISABLE) { - return; - } - - if (d->config[0x5b] & (1 << 1)) { - if (s->smi_irq) { - qemu_irq_raise(s->smi_irq); - } - } -} - -static void pm_io_space_update(PIIX4PMState *s) -{ - PCIDevice *d = PCI_DEVICE(s); - - s->io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40)); - s->io_base &= 0xffc0; - - memory_region_transaction_begin(); - memory_region_set_enabled(&s->io, d->config[0x80] & 1); - memory_region_set_address(&s->io, s->io_base); - memory_region_transaction_commit(); -} - -static void smbus_io_space_update(PIIX4PMState *s) -{ - PCIDevice *d = PCI_DEVICE(s); - - s->smb_io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x90)); - s->smb_io_base &= 0xffc0; - - memory_region_transaction_begin(); - memory_region_set_enabled(&s->smb.io, d->config[0xd2] & 1); - memory_region_set_address(&s->smb.io, s->smb_io_base); - memory_region_transaction_commit(); -} - -static void pm_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len) -{ - pci_default_write_config(d, address, val, len); - if (range_covers_byte(address, len, 0x80) || - ranges_overlap(address, len, 0x40, 4)) { - pm_io_space_update((PIIX4PMState *)d); - } - if (range_covers_byte(address, len, 0xd2) || - ranges_overlap(address, len, 0x90, 4)) { - smbus_io_space_update((PIIX4PMState *)d); - } -} - -static int vmstate_acpi_post_load(void *opaque, int version_id) -{ - PIIX4PMState *s = opaque; - - pm_io_space_update(s); - return 0; -} - -#define VMSTATE_GPE_ARRAY(_field, _state) \ - { \ - .name = (stringify(_field)), \ - .version_id = 0, \ - .info = &vmstate_info_uint16, \ - .size = sizeof(uint16_t), \ - .flags = VMS_SINGLE | VMS_POINTER, \ - .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ - } - -static const VMStateDescription vmstate_gpe = { - .name = "gpe", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_GPE_ARRAY(sts, ACPIGPE), - VMSTATE_GPE_ARRAY(en, ACPIGPE), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_pci_status = { - .name = "pci_status", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(up, struct AcpiPciHpPciStatus), - VMSTATE_UINT32(down, struct AcpiPciHpPciStatus), - VMSTATE_END_OF_LIST() - } -}; - -static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) -{ - PIIX4PMState *s = opaque; - int ret, i; - uint16_t temp; - - ret = pci_device_load(PCI_DEVICE(s), f); - if (ret < 0) { - return ret; - } - qemu_get_be16s(f, &s->ar.pm1.evt.sts); - qemu_get_be16s(f, &s->ar.pm1.evt.en); - qemu_get_be16s(f, &s->ar.pm1.cnt.cnt); - - ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1); - if (ret) { - return ret; - } - - timer_get(f, s->ar.tmr.timer); - qemu_get_sbe64s(f, &s->ar.tmr.overflow_time); - - qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts); - for (i = 0; i < 3; i++) { - qemu_get_be16s(f, &temp); - } - - qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en); - for (i = 0; i < 3; i++) { - qemu_get_be16s(f, &temp); - } - - ret = vmstate_load_state(f, &vmstate_pci_status, - &s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1); - return ret; -} - -static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id) -{ - PIIX4PMState *s = opaque; - return s->use_acpi_pci_hotplug; -} - -static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id) -{ - PIIX4PMState *s = opaque; - return !s->use_acpi_pci_hotplug; -} - -static bool vmstate_test_use_memhp(void *opaque) -{ - PIIX4PMState *s = opaque; - return s->acpi_memory_hotplug.is_enabled; -} - -static const VMStateDescription vmstate_memhp_state = { - .name = "piix4_pm/memhp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .needed = vmstate_test_use_memhp, - .fields = (VMStateField[]) { - VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState), - VMSTATE_END_OF_LIST() - } -}; - -/* qemu-kvm 1.2 uses version 3 but advertised as 2 - * To support incoming qemu-kvm 1.2 migration, change version_id - * and minimum_version_id to 2 below (which breaks migration from - * qemu 1.2). - * - */ -static const VMStateDescription vmstate_acpi = { - .name = "piix4_pm", - .version_id = 3, - .minimum_version_id = 3, - .minimum_version_id_old = 1, - .load_state_old = acpi_load_old, - .post_load = vmstate_acpi_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState), - VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState), - VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState), - VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState), - VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState), - VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState), - VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), - VMSTATE_STRUCT_TEST( - acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], - PIIX4PMState, - vmstate_test_no_use_acpi_pci_hotplug, - 2, vmstate_pci_status, - struct AcpiPciHpPciStatus), - VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState, - vmstate_test_use_acpi_pci_hotplug), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_memhp_state, - NULL - } -}; - -static void piix4_reset(void *opaque) -{ - PIIX4PMState *s = opaque; - PCIDevice *d = PCI_DEVICE(s); - uint8_t *pci_conf = d->config; - - pci_conf[0x58] = 0; - pci_conf[0x59] = 0; - pci_conf[0x5a] = 0; - pci_conf[0x5b] = 0; - - pci_conf[0x40] = 0x01; /* PM io base read only bit */ - pci_conf[0x80] = 0; - - if (!s->smm_enabled) { - /* Mark SMM as already inited (until KVM supports SMM). */ - pci_conf[0x5B] = 0x02; - } - pm_io_space_update(s); - acpi_pcihp_reset(&s->acpi_pci_hotplug); -} - -static void piix4_pm_powerdown_req(Notifier *n, void *opaque) -{ - PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier); - - assert(s != NULL); - acpi_pm1_evt_power_down(&s->ar); -} - -static void piix4_device_plug_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - PIIX4PMState *s = PIIX4_PM(hotplug_dev); - - if (s->acpi_memory_hotplug.is_enabled && - object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_plug_cb(&s->ar, s->irq, &s->acpi_memory_hotplug, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { - acpi_pcihp_device_plug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev, - errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - acpi_cpu_plug_cb(&s->ar, s->irq, &s->gpe_cpu, dev, errp); - } else { - error_setg(errp, "acpi: device plug request for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); - } -} - -static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - PIIX4PMState *s = PIIX4_PM(hotplug_dev); - - if (s->acpi_memory_hotplug.is_enabled && - object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_unplug_request_cb(&s->ar, s->irq, &s->acpi_memory_hotplug, - dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { - acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev, - errp); - } else { - error_setg(errp, "acpi: device unplug request for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); - } -} - -static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - PIIX4PMState *s = PIIX4_PM(hotplug_dev); - - if (s->acpi_memory_hotplug.is_enabled && - object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp); - } else { - error_setg(errp, "acpi: device unplug for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); - } -} - -static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque) -{ - PIIX4PMState *s = opaque; - - qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort); -} - -static void piix4_pm_machine_ready(Notifier *n, void *opaque) -{ - PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready); - PCIDevice *d = PCI_DEVICE(s); - MemoryRegion *io_as = pci_address_space_io(d); - uint8_t *pci_conf; - - pci_conf = d->config; - pci_conf[0x5f] = 0x10 | - (memory_region_present(io_as, 0x378) ? 0x80 : 0); - pci_conf[0x63] = 0x60; - pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) | - (memory_region_present(io_as, 0x2f8) ? 0x90 : 0); - - if (s->use_acpi_pci_hotplug) { - pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s); - } else { - piix4_update_bus_hotplug(d->bus, s); - } -} - -static void piix4_pm_add_propeties(PIIX4PMState *s) -{ - static const uint8_t acpi_enable_cmd = ACPI_ENABLE; - static const uint8_t acpi_disable_cmd = ACPI_DISABLE; - static const uint32_t gpe0_blk = GPE_BASE; - static const uint32_t gpe0_blk_len = GPE_LEN; - static const uint16_t sci_int = 9; - - object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_ENABLE_CMD, - &acpi_enable_cmd, NULL); - object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_DISABLE_CMD, - &acpi_disable_cmd, NULL); - object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK, - &gpe0_blk, NULL); - object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK_LEN, - &gpe0_blk_len, NULL); - object_property_add_uint16_ptr(OBJECT(s), ACPI_PM_PROP_SCI_INT, - &sci_int, NULL); - object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_PM_IO_BASE, - &s->io_base, NULL); -} - -static void piix4_pm_realize(PCIDevice *dev, Error **errp) -{ - PIIX4PMState *s = PIIX4_PM(dev); - uint8_t *pci_conf; - - pci_conf = dev->config; - pci_conf[0x06] = 0x80; - pci_conf[0x07] = 0x02; - pci_conf[0x09] = 0x00; - pci_conf[0x3d] = 0x01; // interrupt pin 1 - - /* APM */ - apm_init(dev, &s->apm, apm_ctrl_changed, s); - - if (!s->smm_enabled) { - /* Mark SMM as already inited to prevent SMM from running. KVM does not - * support SMM mode. */ - pci_conf[0x5B] = 0x02; - } - - /* XXX: which specification is used ? The i82731AB has different - mappings */ - pci_conf[0x90] = s->smb_io_base | 1; - pci_conf[0x91] = s->smb_io_base >> 8; - pci_conf[0xd2] = 0x09; - pm_smbus_init(DEVICE(dev), &s->smb); - memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1); - memory_region_add_subregion(pci_address_space_io(dev), - s->smb_io_base, &s->smb.io); - - memory_region_init(&s->io, OBJECT(s), "piix4-pm", 64); - memory_region_set_enabled(&s->io, false); - memory_region_add_subregion(pci_address_space_io(dev), - 0, &s->io); - - acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); - acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); - acpi_pm1_cnt_init(&s->ar, &s->io, s->disable_s3, s->disable_s4, s->s4_val); - acpi_gpe_init(&s->ar, GPE_LEN); - - s->powerdown_notifier.notify = piix4_pm_powerdown_req; - qemu_register_powerdown_notifier(&s->powerdown_notifier); - - s->machine_ready.notify = piix4_pm_machine_ready; - qemu_add_machine_init_done_notifier(&s->machine_ready); - qemu_register_reset(piix4_reset, s); - - piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s); - - piix4_pm_add_propeties(s); -} - -Object *piix4_pm_find(void) -{ - bool ambig; - Object *o = object_resolve_path_type("", TYPE_PIIX4_PM, &ambig); - - if (ambig || !o) { - return NULL; - } - return o; -} - -I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, - qemu_irq sci_irq, qemu_irq smi_irq, - int smm_enabled, DeviceState **piix4_pm) -{ - DeviceState *dev; - PIIX4PMState *s; - - dev = DEVICE(pci_create(bus, devfn, TYPE_PIIX4_PM)); - qdev_prop_set_uint32(dev, "smb_io_base", smb_io_base); - if (piix4_pm) { - *piix4_pm = dev; - } - - s = PIIX4_PM(dev); - s->irq = sci_irq; - s->smi_irq = smi_irq; - s->smm_enabled = smm_enabled; - if (xen_enabled()) { - s->use_acpi_pci_hotplug = false; - } - - qdev_init_nofail(dev); - - return s->smb.smbus; -} - -static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width) -{ - PIIX4PMState *s = opaque; - uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); - - PIIX4_DPRINTF("gpe read %" HWADDR_PRIx " == %" PRIu32 "\n", addr, val); - return val; -} - -static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - PIIX4PMState *s = opaque; - - acpi_gpe_ioport_writeb(&s->ar, addr, val); - acpi_update_sci(&s->ar, s->irq); - - PIIX4_DPRINTF("gpe write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, val); -} - -static const MemoryRegionOps piix4_gpe_ops = { - .read = gpe_readb, - .write = gpe_writeb, - .valid.min_access_size = 1, - .valid.max_access_size = 4, - .impl.min_access_size = 1, - .impl.max_access_size = 1, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, - PCIBus *bus, PIIX4PMState *s) -{ - memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s, - "acpi-gpe0", GPE_LEN); - memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe); - - acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent, - s->use_acpi_pci_hotplug); - - acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu, - PIIX4_CPU_HOTPLUG_IO_BASE); - - if (s->acpi_memory_hotplug.is_enabled) { - acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug); - } -} - -static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) -{ - PIIX4PMState *s = PIIX4_PM(adev); - - acpi_memory_ospm_status(&s->acpi_memory_hotplug, list); -} - -static Property piix4_pm_properties[] = { - DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), - DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0), - DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0), - DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2), - DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState, - use_acpi_pci_hotplug, true), - DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState, - acpi_memory_hotplug.is_enabled, true), - DEFINE_PROP_END_OF_LIST(), -}; - -static void piix4_pm_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass); - - k->realize = piix4_pm_realize; - k->config_write = pm_write_config; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3; - k->revision = 0x03; - k->class_id = PCI_CLASS_BRIDGE_OTHER; - dc->desc = "PM"; - dc->vmsd = &vmstate_acpi; - dc->props = piix4_pm_properties; - /* - * Reason: part of PIIX4 southbridge, needs to be wired up, - * e.g. by mips_malta_init() - */ - dc->cannot_instantiate_with_device_add_yet = true; - dc->hotpluggable = false; - hc->plug = piix4_device_plug_cb; - hc->unplug_request = piix4_device_unplug_request_cb; - hc->unplug = piix4_device_unplug_cb; - adevc->ospm_status = piix4_ospm_status; -} - -static const TypeInfo piix4_pm_info = { - .name = TYPE_PIIX4_PM, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX4PMState), - .class_init = piix4_pm_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { TYPE_ACPI_DEVICE_IF }, - { } - } -}; - -static void piix4_pm_register_types(void) -{ - type_register_static(&piix4_pm_info); -} - -type_init(piix4_pm_register_types) diff --git a/qemu/hw/acpi/tco.c b/qemu/hw/acpi/tco.c deleted file mode 100644 index 8ce7daf23..000000000 --- a/qemu/hw/acpi/tco.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * QEMU ICH9 TCO emulation - * - * Copyright (c) 2015 Paulo Alcantara <pcacjr@zytor.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "sysemu/watchdog.h" -#include "hw/i386/ich9.h" - -#include "hw/acpi/tco.h" - -//#define DEBUG - -#ifdef DEBUG -#define TCO_DEBUG(fmt, ...) \ - do { \ - fprintf(stderr, "%s "fmt, __func__, ## __VA_ARGS__); \ - } while (0) -#else -#define TCO_DEBUG(fmt, ...) do { } while (0) -#endif - -enum { - TCO_RLD_DEFAULT = 0x0000, - TCO_DAT_IN_DEFAULT = 0x00, - TCO_DAT_OUT_DEFAULT = 0x00, - TCO1_STS_DEFAULT = 0x0000, - TCO2_STS_DEFAULT = 0x0000, - TCO1_CNT_DEFAULT = 0x0000, - TCO2_CNT_DEFAULT = 0x0008, - TCO_MESSAGE1_DEFAULT = 0x00, - TCO_MESSAGE2_DEFAULT = 0x00, - TCO_WDCNT_DEFAULT = 0x00, - TCO_TMR_DEFAULT = 0x0004, - SW_IRQ_GEN_DEFAULT = 0x03, -}; - -static inline void tco_timer_reload(TCOIORegs *tr) -{ - tr->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - ((int64_t)(tr->tco.tmr & TCO_TMR_MASK) * TCO_TICK_NSEC); - timer_mod(tr->tco_timer, tr->expire_time); -} - -static inline void tco_timer_stop(TCOIORegs *tr) -{ - tr->expire_time = -1; -} - -static void tco_timer_expired(void *opaque) -{ - TCOIORegs *tr = opaque; - ICH9LPCPMRegs *pm = container_of(tr, ICH9LPCPMRegs, tco_regs); - ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm); - uint32_t gcs = pci_get_long(lpc->chip_config + ICH9_CC_GCS); - - tr->tco.rld = 0; - tr->tco.sts1 |= TCO_TIMEOUT; - if (++tr->timeouts_no == 2) { - tr->tco.sts2 |= TCO_SECOND_TO_STS; - tr->tco.sts2 |= TCO_BOOT_STS; - tr->timeouts_no = 0; - - if (!lpc->pin_strap.spkr_hi && !(gcs & ICH9_CC_GCS_NO_REBOOT)) { - watchdog_perform_action(); - tco_timer_stop(tr); - return; - } - } - - if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) { - ich9_generate_smi(); - } else { - ich9_generate_nmi(); - } - tr->tco.rld = tr->tco.tmr; - tco_timer_reload(tr); -} - -/* NOTE: values of 0 or 1 will be ignored by ICH */ -static inline int can_start_tco_timer(TCOIORegs *tr) -{ - return !(tr->tco.cnt1 & TCO_TMR_HLT) && tr->tco.tmr > 1; -} - -static uint32_t tco_ioport_readw(TCOIORegs *tr, uint32_t addr) -{ - uint16_t rld; - - switch (addr) { - case TCO_RLD: - if (tr->expire_time != -1) { - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int64_t elapsed = (tr->expire_time - now) / TCO_TICK_NSEC; - rld = (uint16_t)elapsed | (tr->tco.rld & ~TCO_RLD_MASK); - } else { - rld = tr->tco.rld; - } - return rld; - case TCO_DAT_IN: - return tr->tco.din; - case TCO_DAT_OUT: - return tr->tco.dout; - case TCO1_STS: - return tr->tco.sts1; - case TCO2_STS: - return tr->tco.sts2; - case TCO1_CNT: - return tr->tco.cnt1; - case TCO2_CNT: - return tr->tco.cnt2; - case TCO_MESSAGE1: - return tr->tco.msg1; - case TCO_MESSAGE2: - return tr->tco.msg2; - case TCO_WDCNT: - return tr->tco.wdcnt; - case TCO_TMR: - return tr->tco.tmr; - case SW_IRQ_GEN: - return tr->sw_irq_gen; - } - return 0; -} - -static void tco_ioport_writew(TCOIORegs *tr, uint32_t addr, uint32_t val) -{ - switch (addr) { - case TCO_RLD: - tr->timeouts_no = 0; - if (can_start_tco_timer(tr)) { - tr->tco.rld = tr->tco.tmr; - tco_timer_reload(tr); - } else { - tr->tco.rld = val; - } - break; - case TCO_DAT_IN: - tr->tco.din = val; - tr->tco.sts1 |= SW_TCO_SMI; - ich9_generate_smi(); - break; - case TCO_DAT_OUT: - tr->tco.dout = val; - tr->tco.sts1 |= TCO_INT_STS; - /* TODO: cause an interrupt, as selected by the TCO_INT_SEL bits */ - break; - case TCO1_STS: - tr->tco.sts1 = val & TCO1_STS_MASK; - break; - case TCO2_STS: - tr->tco.sts2 = val & TCO2_STS_MASK; - break; - case TCO1_CNT: - val &= TCO1_CNT_MASK; - /* - * once TCO_LOCK bit is set, it can not be cleared by software. a reset - * is required to change this bit from 1 to 0 -- it defaults to 0. - */ - tr->tco.cnt1 = val | (tr->tco.cnt1 & TCO_LOCK); - if (can_start_tco_timer(tr)) { - tr->tco.rld = tr->tco.tmr; - tco_timer_reload(tr); - } else { - tco_timer_stop(tr); - } - break; - case TCO2_CNT: - tr->tco.cnt2 = val; - break; - case TCO_MESSAGE1: - tr->tco.msg1 = val; - break; - case TCO_MESSAGE2: - tr->tco.msg2 = val; - break; - case TCO_WDCNT: - tr->tco.wdcnt = val; - break; - case TCO_TMR: - tr->tco.tmr = val; - break; - case SW_IRQ_GEN: - tr->sw_irq_gen = val; - break; - } -} - -static uint64_t tco_io_readw(void *opaque, hwaddr addr, unsigned width) -{ - TCOIORegs *tr = opaque; - return tco_ioport_readw(tr, addr); -} - -static void tco_io_writew(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - TCOIORegs *tr = opaque; - tco_ioport_writew(tr, addr, val); -} - -static const MemoryRegionOps tco_io_ops = { - .read = tco_io_readw, - .write = tco_io_writew, - .valid.min_access_size = 1, - .valid.max_access_size = 4, - .impl.min_access_size = 1, - .impl.max_access_size = 2, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent) -{ - *tr = (TCOIORegs) { - .tco = { - .rld = TCO_RLD_DEFAULT, - .din = TCO_DAT_IN_DEFAULT, - .dout = TCO_DAT_OUT_DEFAULT, - .sts1 = TCO1_STS_DEFAULT, - .sts2 = TCO2_STS_DEFAULT, - .cnt1 = TCO1_CNT_DEFAULT, - .cnt2 = TCO2_CNT_DEFAULT, - .msg1 = TCO_MESSAGE1_DEFAULT, - .msg2 = TCO_MESSAGE2_DEFAULT, - .wdcnt = TCO_WDCNT_DEFAULT, - .tmr = TCO_TMR_DEFAULT, - }, - .sw_irq_gen = SW_IRQ_GEN_DEFAULT, - .tco_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tco_timer_expired, tr), - .expire_time = -1, - .timeouts_no = 0, - }; - memory_region_init_io(&tr->io, memory_region_owner(parent), - &tco_io_ops, tr, "sm-tco", ICH9_PMIO_TCO_LEN); - memory_region_add_subregion(parent, ICH9_PMIO_TCO_RLD, &tr->io); -} - -const VMStateDescription vmstate_tco_io_sts = { - .name = "tco io device status", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT16(tco.rld, TCOIORegs), - VMSTATE_UINT8(tco.din, TCOIORegs), - VMSTATE_UINT8(tco.dout, TCOIORegs), - VMSTATE_UINT16(tco.sts1, TCOIORegs), - VMSTATE_UINT16(tco.sts2, TCOIORegs), - VMSTATE_UINT16(tco.cnt1, TCOIORegs), - VMSTATE_UINT16(tco.cnt2, TCOIORegs), - VMSTATE_UINT8(tco.msg1, TCOIORegs), - VMSTATE_UINT8(tco.msg2, TCOIORegs), - VMSTATE_UINT8(tco.wdcnt, TCOIORegs), - VMSTATE_UINT16(tco.tmr, TCOIORegs), - VMSTATE_UINT8(sw_irq_gen, TCOIORegs), - VMSTATE_TIMER_PTR(tco_timer, TCOIORegs), - VMSTATE_INT64(expire_time, TCOIORegs), - VMSTATE_UINT8(timeouts_no, TCOIORegs), - VMSTATE_END_OF_LIST() - } -}; |