From nobody Mon Feb 9 17:36:21 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=intel.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1547221327918179.9108400494099; Fri, 11 Jan 2019 07:42:07 -0800 (PST) Received: from localhost ([127.0.0.1]:54935 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ghywg-0004Xb-JN for importer@patchew.org; Fri, 11 Jan 2019 10:42:06 -0500 Received: from eggs.gnu.org ([209.51.188.92]:38308) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ghyre-0000jp-Gs for qemu-devel@nongnu.org; Fri, 11 Jan 2019 10:36:57 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ghyra-0003xm-ES for qemu-devel@nongnu.org; Fri, 11 Jan 2019 10:36:54 -0500 Received: from mga14.intel.com ([192.55.52.115]:56407) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1ghyrZ-0003i3-Ry for qemu-devel@nongnu.org; Fri, 11 Jan 2019 10:36:50 -0500 Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 Jan 2019 07:36:49 -0800 Received: from vmmtaopc.sh.intel.com ([10.239.13.92]) by orsmga006.jf.intel.com with ESMTP; 11 Jan 2019 07:36:46 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,466,1539673200"; d="scan'208";a="107522662" From: Tao Xu To: mst@redhat.com, imammedo@redhat.com Date: Fri, 11 Jan 2019 23:34:51 +0800 Message-Id: <20190111153451.14304-10-tao3.xu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190111153451.14304-1-tao3.xu@intel.com> References: <20190111153451.14304-1-tao3.xu@intel.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 192.55.52.115 Subject: [Qemu-devel] [PATCH v2 9/9] acpi: rewrite the _FIT method to use it in _HMA method X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: ehabkost@redhat.com, jingqi.liu@intel.com, tao3.xu@intel.com, qemu-devel@nongnu.org, pbonzini@redhat.com, danmei.wei@intel.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Per Igor's comment, rewrite NFIT code to build _HMA method. We rewirte the function nvdimm_build_common_dsm(Aml *dev) and nvdimm_build_fit(Aml *dev) in hw/acpi/nvdimm.c so that we can use method_number as input to decide to generate _FIT or _HMA method. Reviewed-by: Liu Jingqi Signed-off-by: Tao Xu --- hw/acpi/hmat.c | 209 +-------------------- hw/acpi/hmat.h | 2 - hw/acpi/nvdimm.c | 389 ++++++++++++++++++++++++++-------------- hw/i386/acpi-build.c | 2 +- include/hw/mem/nvdimm.h | 11 ++ 5 files changed, 270 insertions(+), 343 deletions(-) diff --git a/hw/acpi/hmat.c b/hw/acpi/hmat.c index 4523e98ef1..37ece80101 100644 --- a/hw/acpi/hmat.c +++ b/hw/acpi/hmat.c @@ -100,10 +100,10 @@ static void classify_proximity_domains(void) =20 static void hmat_build_hma(GArray *hma, PCMachineState *pcms) { -/* - * The Proximity Domain of System Physical Address ranges defined - * in the HMAT, NFIT and SRAT tables shall match each other. - */ + /* + * The Proximity Domain of System Physical Address ranges defined + * in the HMAT, NFIT and SRAT tables shall match each other. + */ =20 GSList *device_list =3D NULL; AcpiHmatLBInfo *hmat_lb; @@ -386,112 +386,6 @@ static void hmat_build_hma_buffer(PCMachineState *pcm= s) hma_buf->dirty =3D true; } =20 -static void hmat_build_common_aml(Aml *dev) -{ - Aml *method, *ifctx, *hmam_mem; - Aml *unsupport; - Aml *pckg, *pckg_index, *pckg_buf, *field; - Aml *hmam_out_buf, *hmam_out_buf_size; - uint8_t byte_list[1]; - - method =3D aml_method(HMA_COMMON_METHOD, 1, AML_SERIALIZED); - hmam_mem =3D aml_local(6); - hmam_out_buf =3D aml_local(7); - - aml_append(method, aml_store(aml_name(HMAM_ACPI_MEM_ADDR), hmam_mem)); - - /* map _HMA memory and IO into ACPI namespace. */ - aml_append(method, aml_operation_region(HMAM_IOPORT, AML_SYSTEM_IO, - aml_int(HMAM_ACPI_IO_BASE), HMAM_ACPI_IO_LEN)); - aml_append(method, aml_operation_region(HMAM_MEMORY, - AML_SYSTEM_MEMORY, hmam_mem, HMAM_MEMORY_SIZE)); - - /* - * _HMAC notifier: - * HMAM_NOTIFY: 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 =3D aml_field(HMAM_IOPORT, AML_DWORD_ACC, AML_NOLOCK, - AML_PRESERVE); - aml_append(field, aml_named_field(HMAM_NOTIFY, - sizeof(uint32_t) * BITS_PER_BYTE)); - aml_append(method, field); - - /* - * _HMAC input: - * HMAM_OFFSET: store the current offset of _HMA buffer. - * - * They are RAM mapping on host so that these accesses never cause VME= xit. - */ - field =3D aml_field(HMAM_MEMORY, AML_DWORD_ACC, AML_NOLOCK, - AML_PRESERVE); - aml_append(field, aml_named_field(HMAM_OFFSET, - sizeof(typeof_field(HmatHmamIn, offset)) * BITS_PER_BYTE)); - aml_append(method, field); - - /* - * _HMAC output: - * HMAM_OUT_BUF_SIZE: the size of the buffer filled by QEMU. - * HMAM_OUT_BUF: 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 =3D aml_field(HMAM_MEMORY, AML_DWORD_ACC, AML_NOLOCK, - AML_PRESERVE); - aml_append(field, aml_named_field(HMAM_OUT_BUF_SIZE, - sizeof(typeof_field(HmatHmamOut, len)) * BITS_PER_BYTE)); - aml_append(field, aml_named_field(HMAM_OUT_BUF, - (sizeof(HmatHmamOut) - sizeof(uint32_t)) * BITS_PER_BYTE)); - aml_append(method, field); - - /* - * do not support any method if HMA memory address has not been - * patched. - */ - unsupport =3D aml_if(aml_equal(hmam_mem, aml_int(0x0))); - byte_list[0] =3D HMAM_RET_STATUS_UNSUPPORT; - aml_append(unsupport, aml_return(aml_buffer(1, byte_list))); - aml_append(method, unsupport); - - /* The parameter (Arg0) of _HMAC is a package which contains a buffer.= */ - pckg =3D aml_arg(0); - ifctx =3D aml_if(aml_and(aml_equal(aml_object_type(pckg), - aml_int(4 /* Package */)) /* It is a Package? */, - aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element */, - NULL)); - - pckg_index =3D aml_local(2); - pckg_buf =3D aml_local(3); - aml_append(ifctx, aml_store(aml_index(pckg, aml_int(0)), pckg_index)); - aml_append(ifctx, aml_store(aml_derefof(pckg_index), pckg_buf)); - aml_append(ifctx, aml_store(pckg_buf, aml_name(HMAM_OFFSET))); - aml_append(method, ifctx); - - /* - * tell QEMU about the real address of HMA memory, then QEMU - * gets the control and fills the result in _HMAC memory. - */ - aml_append(method, aml_store(hmam_mem, aml_name(HMAM_NOTIFY))); - - hmam_out_buf_size =3D aml_local(1); - /* RLEN is not included in the payload returned to guest. */ - aml_append(method, aml_subtract(aml_name(HMAM_OUT_BUF_SIZE), - aml_int(4), hmam_out_buf_size)); - aml_append(method, aml_store(aml_shiftleft(hmam_out_buf_size, aml_int(= 3)), - hmam_out_buf_size)); - aml_append(method, aml_create_field(aml_name(HMAM_OUT_BUF), - aml_int(0), hmam_out_buf_size, "OBUF")); - aml_append(method, aml_concatenate(aml_buffer(0, NULL), aml_name("OBUF= "), - hmam_out_buf)); - aml_append(method, aml_return(hmam_out_buf)); - aml_append(dev, method); -} - void hmat_init_acpi_state(AcpiHmaState *state, MemoryRegion *io, FWCfgState *fw_cfg, Object *owner) { @@ -528,98 +422,3 @@ void hmat_build_acpi(GArray *table_data, BIOSLinker *l= inker, (void *)(table_data->data + hmat_start), "HMAT", hmat_len, 1, NULL, NULL); } - -void hmat_build_aml(Aml *dev) -{ - Aml *method, *pkg, *buf, *buf_size, *offset, *call_result; - Aml *whilectx, *ifcond, *ifctx, *elsectx, *hma; - - hmat_build_common_aml(dev); - - buf =3D aml_local(0); - buf_size =3D aml_local(1); - hma =3D aml_local(2); - - aml_append(dev, aml_name_decl(HMAM_RHMA_STATUS, aml_int(0))); - - /* build helper function, RHMA. */ - method =3D aml_method("RHMA", 1, AML_SERIALIZED); - aml_append(method, aml_name_decl("OFST", aml_int(0))); - - /* prepare input package. */ - pkg =3D aml_package(1); - aml_append(method, aml_store(aml_arg(0), aml_name("OFST"))); - aml_append(pkg, aml_name("OFST")); - - /* call Read HMA function. */ - call_result =3D aml_call1(HMA_COMMON_METHOD, pkg); - aml_append(method, aml_store(call_result, buf)); - - /* handle _HMAC result. */ - aml_append(method, aml_create_dword_field(buf, - aml_int(0) /* offset at byte 0 */, "STAU")); - - aml_append(method, aml_store(aml_name("STAU"), - aml_name(HMAM_RHMA_STATUS))); - - /* if something is wrong during _HMAC. */ - ifcond =3D aml_equal(aml_int(HMAM_RET_STATUS_SUCCESS), - aml_name("STAU")); - ifctx =3D aml_if(aml_lnot(ifcond)); - aml_append(ifctx, aml_return(aml_buffer(0, NULL))); - aml_append(method, ifctx); - - aml_append(method, aml_store(aml_sizeof(buf), buf_size)); - aml_append(method, aml_subtract(buf_size, - aml_int(4) /* the size of "STAU" */, - buf_size)); - - /* if we read the end of hma. */ - ifctx =3D aml_if(aml_equal(buf_size, aml_int(0))); - aml_append(ifctx, aml_return(aml_buffer(0, NULL))); - aml_append(method, ifctx); - - aml_append(method, aml_create_field(buf, - aml_int(4 * BITS_PER_BYTE), /* offset at byte = 4.*/ - aml_shiftleft(buf_size, aml_int(3)), "BUFF")); - aml_append(method, aml_return(aml_name("BUFF"))); - aml_append(dev, method); - - /* build _HMA. */ - method =3D aml_method("_HMA", 0, AML_SERIALIZED); - offset =3D aml_local(3); - - aml_append(method, aml_store(aml_buffer(0, NULL), hma)); - aml_append(method, aml_store(aml_int(0), offset)); - - whilectx =3D aml_while(aml_int(1)); - aml_append(whilectx, aml_store(aml_call1("RHMA", offset), buf)); - aml_append(whilectx, aml_store(aml_sizeof(buf), buf_size)); - - /* - * if hma buffer was changed during RHMA, read from the beginning - * again. - */ - ifctx =3D aml_if(aml_equal(aml_name(HMAM_RHMA_STATUS), - aml_int(HMAM_RET_STATUS_HMA_CHANGED))); - aml_append(ifctx, aml_store(aml_buffer(0, NULL), hma)); - aml_append(ifctx, aml_store(aml_int(0), offset)); - aml_append(whilectx, ifctx); - - elsectx =3D aml_else(); - - /* finish hma read if no data is read out. */ - ifctx =3D aml_if(aml_equal(buf_size, aml_int(0))); - aml_append(ifctx, aml_return(hma)); - aml_append(elsectx, ifctx); - - /* update the offset. */ - aml_append(elsectx, aml_add(offset, buf_size, offset)); - /* append the data we read out to the hma buffer. */ - aml_append(elsectx, aml_concatenate(hma, buf, hma)); - aml_append(whilectx, elsectx); - aml_append(method, whilectx); - - aml_append(dev, method); -} - diff --git a/hw/acpi/hmat.h b/hw/acpi/hmat.h index 2c080a51b8..dd57678816 100644 --- a/hw/acpi/hmat.h +++ b/hw/acpi/hmat.h @@ -31,7 +31,6 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/aml-build.h" =20 -#define ACPI_HMAT_SPA 0 #define ACPI_HMAT_LB_INFO 1 #define ACPI_HMAT_CACHE_INFO 2 =20 @@ -238,7 +237,6 @@ extern struct numa_hmat_cache_info =20 void hmat_build_acpi(GArray *table_data, BIOSLinker *linker, MachineState *machine); -void hmat_build_aml(Aml *dsdt); void hmat_init_acpi_state(AcpiHmaState *state, MemoryRegion *io, FWCfgState *fw_cfg, Object *owner); void hmat_update(PCMachineState *pcms); diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index e53b2cb681..795236bb1b 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -32,6 +32,7 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/nvram/fw_cfg.h" #include "hw/mem/nvdimm.h" +#include "hw/acpi/hmat.h" =20 static int nvdimm_device_list(Object *obj, void *opaque) { @@ -959,26 +960,49 @@ void nvdimm_init_acpi_state(AcpiNVDIMMState *state, M= emoryRegion *io, =20 #define NVDIMM_QEMU_RSVD_UUID "648B9CF2-CDA1-4312-8AD9-49C4AF32BD62" =20 -static void nvdimm_build_common_dsm(Aml *dev) +static void nvdimm_build_common_dsm(Aml *dev, uint16_t method_number) { - Aml *method, *ifctx, *function, *handle, *uuid, *dsm_mem, *elsectx2; + Aml *method =3D NULL, *ifctx =3D NULL, *function =3D NULL; + Aml *handle =3D NULL, *uuid =3D NULL, *dsm_mem, *elsectx2; Aml *elsectx, *unsupport, *unpatched, *expected_uuid, *uuid_invalid; - Aml *pckg, *pckg_index, *pckg_buf, *field, *dsm_out_buf, *dsm_out_buf_= size; + Aml *pckg =3D NULL, *pckg_index, *pckg_buf, *field; + Aml *dsm_out_buf, *dsm_out_buf_size; uint8_t byte_list[1]; + uint16_t acpi_io_base =3D 0; + const char *acpi_mem_addr =3D NULL, *ioport =3D NULL, *memory =3D NULL; + const char *aml_offset =3D NULL; + + switch (method_number) { + case 0: /* build common dsm in _FIT method */ + acpi_mem_addr =3D NVDIMM_ACPI_MEM_ADDR; + ioport =3D NVDIMM_DSM_IOPORT; + acpi_io_base =3D NVDIMM_ACPI_IO_BASE; + memory =3D NVDIMM_DSM_MEMORY; + aml_offset =3D NVDIMM_DSM_ARG3; + method =3D aml_method(NVDIMM_COMMON_DSM, 5, AML_SERIALIZED); + uuid =3D aml_arg(0); + function =3D aml_arg(2); + handle =3D aml_arg(4); + break; + case 1: /* build common dsm in _HMA method */ + acpi_mem_addr =3D HMAM_ACPI_MEM_ADDR; + ioport =3D HMAM_IOPORT; + acpi_io_base =3D HMAM_ACPI_IO_BASE; + memory =3D HMAM_MEMORY; + aml_offset =3D HMAM_OFFSET; + method =3D aml_method(HMA_COMMON_METHOD, 1, AML_SERIALIZED); + break; + } =20 - method =3D aml_method(NVDIMM_COMMON_DSM, 5, AML_SERIALIZED); - uuid =3D aml_arg(0); - function =3D aml_arg(2); - handle =3D aml_arg(4); dsm_mem =3D aml_local(6); dsm_out_buf =3D aml_local(7); =20 - aml_append(method, aml_store(aml_name(NVDIMM_ACPI_MEM_ADDR), dsm_mem)); + aml_append(method, aml_store(aml_name("%s", acpi_mem_addr), dsm_mem)); =20 /* map DSM memory and IO into ACPI namespace. */ - aml_append(method, aml_operation_region(NVDIMM_DSM_IOPORT, AML_SYSTEM_= IO, - aml_int(NVDIMM_ACPI_IO_BASE), NVDIMM_ACPI_IO_LEN)); - aml_append(method, aml_operation_region(NVDIMM_DSM_MEMORY, + aml_append(method, aml_operation_region(ioport, AML_SYSTEM_IO, + aml_int(acpi_io_base), NVDIMM_ACPI_IO_LEN)); + aml_append(method, aml_operation_region(memory, AML_SYSTEM_MEMORY, dsm_mem, sizeof(NvdimmDsmIn))); =20 /* @@ -989,122 +1013,191 @@ static void nvdimm_build_common_dsm(Aml *dev) * It is the IO port so that accessing them will cause VM-exit, the * control will be transferred to QEMU. */ - field =3D aml_field(NVDIMM_DSM_IOPORT, AML_DWORD_ACC, AML_NOLOCK, + field =3D aml_field(ioport, AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); aml_append(field, aml_named_field(NVDIMM_DSM_NOTIFY, sizeof(uint32_t) * BITS_PER_BYTE)); aml_append(method, field); =20 - /* - * DSM input: - * NVDIMM_DSM_HANDLE: store device's handle, it's zero if the _DSM call - * happens on NVDIMM Root Device. - * NVDIMM_DSM_REVISION: store the Arg1 of _DSM call. - * NVDIMM_DSM_FUNCTION: store the Arg2 of _DSM call. - * NVDIMM_DSM_ARG3: store the Arg3 of _DSM call which is a Package - * containing function-specific arguments. - * - * They are RAM mapping on host so that these accesses never cause - * VM-EXIT. - */ - field =3D aml_field(NVDIMM_DSM_MEMORY, AML_DWORD_ACC, AML_NOLOCK, - AML_PRESERVE); - aml_append(field, aml_named_field(NVDIMM_DSM_HANDLE, - sizeof(typeof_field(NvdimmDsmIn, handle)) * BITS_PER_BYTE)); - aml_append(field, aml_named_field(NVDIMM_DSM_REVISION, - sizeof(typeof_field(NvdimmDsmIn, revision)) * BITS_PER_BYTE= )); - aml_append(field, aml_named_field(NVDIMM_DSM_FUNCTION, - sizeof(typeof_field(NvdimmDsmIn, function)) * BITS_PER_BYTE= )); - aml_append(field, aml_named_field(NVDIMM_DSM_ARG3, - (sizeof(NvdimmDsmIn) - offsetof(NvdimmDsmIn, arg3)) * BITS_PER_BY= TE)); - aml_append(method, field); + field =3D aml_field(memory, AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); + switch (method_number) { + case 0: /* build common dsm in _FIT method */ + /* + * DSM input: + * NVDIMM_DSM_HANDLE: store device's handle, it's zero if + * the _DSM call happens on NVDIMM Root + * Device. + * NVDIMM_DSM_REVISION: store the Arg1 of _DSM call. + * NVDIMM_DSM_FUNCTION: store the Arg2 of _DSM call. + * NVDIMM_DSM_ARG3: store the Arg3 of _DSM call which is a + * Package containing function-specific + * arguments. + * + * They are RAM mapping on host so that these accesses + * never cause VM-EXIT. + */ + aml_append(field, aml_named_field(NVDIMM_DSM_HANDLE, + sizeof(typeof_field(NvdimmDsmIn, handle)) * + BITS_PER_BYTE)); + aml_append(field, aml_named_field(NVDIMM_DSM_REVISION, + sizeof(typeof_field(NvdimmDsmIn, revision)) * + BITS_PER_BYTE)); + aml_append(field, aml_named_field(NVDIMM_DSM_FUNCTION, + sizeof(typeof_field(NvdimmDsmIn, function)) * + BITS_PER_BYTE)); + aml_append(field, aml_named_field(NVDIMM_DSM_ARG3, + (sizeof(NvdimmDsmIn) - offsetof(NvdimmDsmIn, arg3)) * + BITS_PER_BYTE)); + aml_append(method, field); =20 - /* - * DSM output: - * NVDIMM_DSM_OUT_BUF_SIZE: the size of the buffer filled by QEMU. - * NVDIMM_DSM_OUT_BUF: 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 =3D aml_field(NVDIMM_DSM_MEMORY, AML_DWORD_ACC, AML_NOLOCK, - AML_PRESERVE); - aml_append(field, aml_named_field(NVDIMM_DSM_OUT_BUF_SIZE, - sizeof(typeof_field(NvdimmDsmOut, len)) * BITS_PER_BYTE)); - aml_append(field, aml_named_field(NVDIMM_DSM_OUT_BUF, - (sizeof(NvdimmDsmOut) - offsetof(NvdimmDsmOut, data)) * BITS_PER_BY= TE)); - aml_append(method, field); + /* + * DSM output: + * NVDIMM_DSM_OUT_BUF_SIZE: the size of the buffer + * filled by QEMU. + * NVDIMM_DSM_OUT_BUF: 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 =3D aml_field(memory, AML_DWORD_ACC, AML_NOLOCK, + AML_PRESERVE); + aml_append(field, aml_named_field(NVDIMM_DSM_OUT_BUF_SIZE, + sizeof(typeof_field(NvdimmDsmOut, len)) * + BITS_PER_BYTE)); + aml_append(field, aml_named_field(NVDIMM_DSM_OUT_BUF, + (sizeof(NvdimmDsmOut) - offsetof(NvdimmDsmOut, data)) * + BITS_PER_BYTE)); + aml_append(method, field); =20 - /* - * do not support any method if DSM memory address has not been - * patched. - */ - unpatched =3D aml_equal(dsm_mem, aml_int(0x0)); + /* + * do not support any method if DSM memory address has not been + * patched. + */ + unpatched =3D aml_equal(dsm_mem, aml_int(0x0)); + + expected_uuid =3D aml_local(0); + + ifctx =3D aml_if(aml_equal(handle, aml_int(0x0))); + aml_append(ifctx, aml_store( + aml_touuid("2F10E7A4-9E91-11E4-89D3-123B93F75CBA") + /* UUID for NVDIMM Root Device */, expected_uuid)); + aml_append(method, ifctx); + elsectx =3D aml_else(); + ifctx =3D aml_if(aml_equal(handle, + aml_int(NVDIMM_QEMU_RSVD_HANDLE_ROOT))); + aml_append(ifctx, aml_store(aml_touuid(NVDIMM_QEMU_RSVD_UUID + /* UUID for QEMU internal use */), expected_uuid)); + aml_append(elsectx, ifctx); + elsectx2 =3D aml_else(); + aml_append(elsectx2, aml_store( + aml_touuid("4309AC30-0D11-11E4-9191-0800200C9A66") + /* UUID for NVDIMM Devices */, expected_uuid)); + aml_append(elsectx, elsectx2); + aml_append(method, elsectx); + + uuid_invalid =3D aml_lnot(aml_equal(uuid, expected_uuid)); + + unsupport =3D aml_if(aml_or(unpatched, uuid_invalid, NULL)); =20 - expected_uuid =3D aml_local(0); + /* + * function 0 is called to inquire what functions are supported by + * OSPM + */ + ifctx =3D aml_if(aml_equal(function, aml_int(0))); + byte_list[0] =3D 0 /* No function Supported */; + aml_append(ifctx, aml_return(aml_buffer(1, byte_list))); + aml_append(unsupport, ifctx); =20 - ifctx =3D aml_if(aml_equal(handle, aml_int(0x0))); - aml_append(ifctx, aml_store( - aml_touuid("2F10E7A4-9E91-11E4-89D3-123B93F75CBA") - /* UUID for NVDIMM Root Device */, expected_uuid)); - aml_append(method, ifctx); - elsectx =3D aml_else(); - ifctx =3D aml_if(aml_equal(handle, aml_int(NVDIMM_QEMU_RSVD_HANDLE_ROO= T))); - aml_append(ifctx, aml_store(aml_touuid(NVDIMM_QEMU_RSVD_UUID - /* UUID for QEMU internal use */), expected_uuid)); - aml_append(elsectx, ifctx); - elsectx2 =3D aml_else(); - aml_append(elsectx2, aml_store( - aml_touuid("4309AC30-0D11-11E4-9191-0800200C9A66") - /* UUID for NVDIMM Devices */, expected_uuid)); - aml_append(elsectx, elsectx2); - aml_append(method, elsectx); + /* No function is supported yet. */ + byte_list[0] =3D NVDIMM_DSM_RET_STATUS_UNSUPPORT; + aml_append(unsupport, aml_return(aml_buffer(1, byte_list))); + aml_append(method, unsupport); + + /* + * The HDLE indicates the DSM function is issued from which device, + * it reserves 0 for root device and is the handle for + * NVDIMM devices. See the comments in nvdimm_slot_to_handle(). + */ + aml_append(method, aml_store(handle, + aml_name(NVDIMM_DSM_HANDLE))); + aml_append(method, aml_store(aml_arg(1), + aml_name(NVDIMM_DSM_REVISION))); + aml_append(method, aml_store(aml_arg(2), + aml_name(NVDIMM_DSM_FUNCTION))); =20 - uuid_invalid =3D aml_lnot(aml_equal(uuid, expected_uuid)); + /* + * The fourth parameter (Arg3) of _DSM is a package which contains + * a buffer, the layout of the buffer is specified by UUID (Arg0), + * Revision ID (Arg1) and Function Index (Arg2) which are document= ed + * in the DSM Spec. + */ + pckg =3D aml_arg(3); + ifctx =3D aml_if(aml_and(aml_equal(aml_object_type(pckg), + aml_int(4 /* Package */)) /* It is a Package? */, + aml_equal(aml_sizeof(pckg), + aml_int(1)) /* 1 element? */, + NULL)); =20 - unsupport =3D aml_if(aml_or(unpatched, uuid_invalid, NULL)); + break; + case 1: /* build common dsm in _HMA method */ + /* + * _HMAC input: + * HMAM_OFFSET: store the current offset of _HMA buffer. + * + * They are RAM mapping on host so that + * these accesses never cause VMExit. + */ + aml_append(field, aml_named_field(HMAM_OFFSET, + sizeof(typeof_field(HmatHmamIn, offset)) * BITS_PER_BYTE)); + aml_append(method, field); =20 - /* - * function 0 is called to inquire what functions are supported by - * OSPM - */ - ifctx =3D aml_if(aml_equal(function, aml_int(0))); - byte_list[0] =3D 0 /* No function Supported */; - aml_append(ifctx, aml_return(aml_buffer(1, byte_list))); - aml_append(unsupport, ifctx); + /* + * _HMAC output: + * HMAM_OUT_BUF_SIZE: the size of the buffer filled by QEMU. + * HMAM_OUT_BUF: 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 =3D aml_field(HMAM_MEMORY, AML_DWORD_ACC, AML_NOLOCK, + AML_PRESERVE); + aml_append(field, aml_named_field(HMAM_OUT_BUF_SIZE, + sizeof(typeof_field(HmatHmamOut, len)) * BITS_PER_BYTE)); + aml_append(field, aml_named_field(HMAM_OUT_BUF, + (sizeof(HmatHmamOut) - sizeof(uint32_t)) * BITS_PER_BYTE)); + aml_append(method, field); =20 - /* No function is supported yet. */ - byte_list[0] =3D NVDIMM_DSM_RET_STATUS_UNSUPPORT; - aml_append(unsupport, aml_return(aml_buffer(1, byte_list))); - aml_append(method, unsupport); + /* + * do not support any method if HMA memory address has not been + * patched. + */ + unsupport =3D aml_if(aml_equal(dsm_mem, aml_int(0x0))); + byte_list[0] =3D HMAM_RET_STATUS_UNSUPPORT; + aml_append(unsupport, aml_return(aml_buffer(1, byte_list))); + aml_append(method, unsupport); =20 - /* - * The HDLE indicates the DSM function is issued from which device, - * it reserves 0 for root device and is the handle for NVDIMM devices. - * See the comments in nvdimm_slot_to_handle(). - */ - aml_append(method, aml_store(handle, aml_name(NVDIMM_DSM_HANDLE))); - aml_append(method, aml_store(aml_arg(1), aml_name(NVDIMM_DSM_REVISION)= )); - aml_append(method, aml_store(aml_arg(2), aml_name(NVDIMM_DSM_FUNCTION)= )); + /* + * The parameter (Arg0) of _HMAC is + * a package which contains a buffer. + */ + pckg =3D aml_arg(0); + ifctx =3D aml_if(aml_and(aml_equal(aml_object_type(pckg), + aml_int(4 /* Package */)) /* It is a Package? */, + aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element *= /, + NULL)); =20 - /* - * The fourth parameter (Arg3) of _DSM is a package which contains - * a buffer, the layout of the buffer is specified by UUID (Arg0), - * Revision ID (Arg1) and Function Index (Arg2) which are documented - * in the DSM Spec. - */ - pckg =3D aml_arg(3); - ifctx =3D aml_if(aml_and(aml_equal(aml_object_type(pckg), - aml_int(4 /* Package */)) /* It is a Package? */, - aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element? *= /, - NULL)); + break; + } =20 pckg_index =3D aml_local(2); pckg_buf =3D aml_local(3); aml_append(ifctx, aml_store(aml_index(pckg, aml_int(0)), pckg_index)); aml_append(ifctx, aml_store(aml_derefof(pckg_index), pckg_buf)); - aml_append(ifctx, aml_store(pckg_buf, aml_name(NVDIMM_DSM_ARG3))); + aml_append(ifctx, aml_store(pckg_buf, aml_name("%s", aml_offset))); aml_append(method, ifctx); =20 /* @@ -1138,19 +1231,37 @@ static void nvdimm_build_device_dsm(Aml *dev, uint3= 2_t handle) aml_append(dev, method); } =20 -static void nvdimm_build_fit(Aml *dev) +void nvdimm_build_fit(Aml *dev, uint16_t method_number) { - Aml *method, *pkg, *buf, *buf_size, *offset, *call_result; - Aml *whilectx, *ifcond, *ifctx, *elsectx, *fit; + Aml *method, *pkg, *buf, *buf_size, *offset, *call_result =3D NULL; + Aml *whilectx, *ifcond, *ifctx, *elsectx, *buf_name; + const char *help_function =3D NULL, *method_name =3D NULL; + int ret_status_success, ret_status_changed; + + switch (method_number) { + case 0: /* _FIT method */ + method_name =3D "_FIT"; + help_function =3D "RFIT"; + ret_status_success =3D NVDIMM_DSM_RET_STATUS_SUCCESS; + ret_status_changed =3D NVDIMM_DSM_RET_STATUS_FIT_CHANGED; + break; + case 1: /* _HMA method */ + method_name =3D "_HMA"; + nvdimm_build_common_dsm(dev, METHOD_NAME_HMA); + help_function =3D "RHMA"; + ret_status_success =3D HMAM_RET_STATUS_SUCCESS; + ret_status_changed =3D HMAM_RET_STATUS_HMA_CHANGED; + break; + } =20 buf =3D aml_local(0); buf_size =3D aml_local(1); - fit =3D aml_local(2); + buf_name =3D aml_local(2); =20 aml_append(dev, aml_name_decl(NVDIMM_DSM_RFIT_STATUS, aml_int(0))); =20 - /* build helper function, RFIT. */ - method =3D aml_method("RFIT", 1, AML_SERIALIZED); + /* build helper function. */ + method =3D aml_method(help_function, 1, AML_SERIALIZED); aml_append(method, aml_name_decl("OFST", aml_int(0))); =20 /* prepare input package. */ @@ -1158,12 +1269,20 @@ static void nvdimm_build_fit(Aml *dev) aml_append(method, aml_store(aml_arg(0), aml_name("OFST"))); aml_append(pkg, aml_name("OFST")); =20 - /* call Read_FIT function. */ - call_result =3D aml_call5(NVDIMM_COMMON_DSM, - aml_touuid(NVDIMM_QEMU_RSVD_UUID), - aml_int(1) /* Revision 1 */, - aml_int(0x1) /* Read FIT */, - pkg, aml_int(NVDIMM_QEMU_RSVD_HANDLE_ROOT)); + /* call Read function. */ + switch (method_number) { + case 0: /* build common dsm in _FIT method */ + call_result =3D aml_call5(NVDIMM_COMMON_DSM, + aml_touuid(NVDIMM_QEMU_RSVD_UUID), + aml_int(1) /* Revision 1 */, + aml_int(0x1) /* Read FIT */, + pkg, aml_int(NVDIMM_QEMU_RSVD_HANDLE_ROOT)= ); + break; + case 1: /* build common dsm in _FIT method */ + call_result =3D aml_call1(HMA_COMMON_METHOD, pkg); + break; + } + aml_append(method, aml_store(call_result, buf)); =20 /* handle _DSM result. */ @@ -1174,7 +1293,7 @@ static void nvdimm_build_fit(Aml *dev) aml_name(NVDIMM_DSM_RFIT_STATUS))); =20 /* if something is wrong during _DSM. */ - ifcond =3D aml_equal(aml_int(NVDIMM_DSM_RET_STATUS_SUCCESS), + ifcond =3D aml_equal(aml_int(ret_status_success), aml_name("STAU")); ifctx =3D aml_if(aml_lnot(ifcond)); aml_append(ifctx, aml_return(aml_buffer(0, NULL))); @@ -1185,7 +1304,7 @@ static void nvdimm_build_fit(Aml *dev) aml_int(4) /* the size of "STAU" */, buf_size)); =20 - /* if we read the end of fit. */ + /* if we read the end of fit or hma. */ ifctx =3D aml_if(aml_equal(buf_size, aml_int(0))); aml_append(ifctx, aml_return(aml_buffer(0, NULL))); aml_append(method, ifctx); @@ -1196,38 +1315,38 @@ static void nvdimm_build_fit(Aml *dev) aml_append(method, aml_return(aml_name("BUFF"))); aml_append(dev, method); =20 - /* build _FIT. */ - method =3D aml_method("_FIT", 0, AML_SERIALIZED); + /* build _FIT or _HMA. */ + method =3D aml_method(method_name, 0, AML_SERIALIZED); offset =3D aml_local(3); =20 - aml_append(method, aml_store(aml_buffer(0, NULL), fit)); + aml_append(method, aml_store(aml_buffer(0, NULL), buf_name)); aml_append(method, aml_store(aml_int(0), offset)); =20 whilectx =3D aml_while(aml_int(1)); - aml_append(whilectx, aml_store(aml_call1("RFIT", offset), buf)); + aml_append(whilectx, aml_store(aml_call1(help_function, offset), buf)); aml_append(whilectx, aml_store(aml_sizeof(buf), buf_size)); =20 /* - * if fit buffer was changed during RFIT, read from the beginning - * again. + * if buffer was changed during RFIT or RHMA, + * read from the beginning again. */ ifctx =3D aml_if(aml_equal(aml_name(NVDIMM_DSM_RFIT_STATUS), - aml_int(NVDIMM_DSM_RET_STATUS_FIT_CHANGED))); - aml_append(ifctx, aml_store(aml_buffer(0, NULL), fit)); + aml_int(ret_status_changed))); + aml_append(ifctx, aml_store(aml_buffer(0, NULL), buf_name)); aml_append(ifctx, aml_store(aml_int(0), offset)); aml_append(whilectx, ifctx); =20 elsectx =3D aml_else(); =20 - /* finish fit read if no data is read out. */ + /* finish fit or hma read if no data is read out. */ ifctx =3D aml_if(aml_equal(buf_size, aml_int(0))); - aml_append(ifctx, aml_return(fit)); + aml_append(ifctx, aml_return(buf_name)); aml_append(elsectx, ifctx); =20 /* update the offset. */ aml_append(elsectx, aml_add(offset, buf_size, offset)); - /* append the data we read out to the fit buffer. */ - aml_append(elsectx, aml_concatenate(fit, buf, fit)); + /* append the data we read out to the fit or hma buffer. */ + aml_append(elsectx, aml_concatenate(buf_name, buf, buf_name)); aml_append(whilectx, elsectx); aml_append(method, whilectx); =20 @@ -1288,11 +1407,11 @@ static void nvdimm_build_ssdt(GArray *table_offsets= , GArray *table_data, */ aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0012"))); =20 - nvdimm_build_common_dsm(dev); + nvdimm_build_common_dsm(dev, METHOD_NAME_FIT); =20 /* 0 is reserved for root device. */ nvdimm_build_device_dsm(dev, 0); - nvdimm_build_fit(dev); + nvdimm_build_fit(dev, METHOD_NAME_FIT); =20 nvdimm_build_nvdimm_devices(dev, ram_slots); =20 diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 729e67e829..3e014b1ead 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1846,7 +1846,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, build_q35_pci0_int(dsdt); } =20 - hmat_build_aml(dsdt); + nvdimm_build_fit(dsdt, METHOD_NAME_HMA); =20 if (pcmc->legacy_cpu_hotplug) { build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base); diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h index c5c9b3c7f8..3bc38735e4 100644 --- a/include/hw/mem/nvdimm.h +++ b/include/hw/mem/nvdimm.h @@ -25,6 +25,7 @@ =20 #include "hw/mem/pc-dimm.h" #include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/aml-build.h" =20 #define NVDIMM_DEBUG 0 #define nvdimm_debug(fmt, ...) \ @@ -110,6 +111,15 @@ typedef struct NVDIMMClass NVDIMMClass; #define NVDIMM_ACPI_IO_BASE 0x0a18 #define NVDIMM_ACPI_IO_LEN 4 =20 +/* + * The ACPI Device Configuration method name used in nvdimm_build_fit, + * use number to representative the name: + * 0 means "_FIT" + * 1 means "_HMA" + */ +#define METHOD_NAME_FIT 0 +#define METHOD_NAME_HMA 1 + /* * NvdimmFitBuffer: * @fit: FIT structures for present NVDIMMs. It is updated when @@ -150,4 +160,5 @@ void nvdimm_build_acpi(GArray *table_offsets, GArray *t= able_data, uint32_t ram_slots); void nvdimm_plug(AcpiNVDIMMState *state); void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev); +void nvdimm_build_fit(Aml *dev, uint16_t method_number); #endif --=20 2.17.1