From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 684C3214805 for ; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=g4eYrq5uYOrxtVH3KJN40Tdp020v6elBn40pMD8z35P5SJrVHbef0Bj4d5oUs4cN1HWKxrc12CWehaQp4SSHe2OB6VWyWnXMi+43apNSOjQmgFIPKdUo6IcSKrs7gWdRjoK9U15+zOFweUp/kC8DZGMIWQwaXPrG6ZsJULw9mDQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=JFEsCrZJXfeUrVql42hGAUplnUlBcbOKU8n7z+cwh6o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GhmjYsrwng5ov9prassKlrJqd5kG25usWYvuoAt/aY+CbUa58D2oMjY7UIOIdLmARkCY2R5Eb0n4TVUtx6JyeuPZqXOHIfxUHOdf8CbmptM6NC7pfwa3G0dxGP/EqnilaqrAB7dxbHTlLTTwBfMRy88AbBcxZ0d6EPQA3L6Nplc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AmUtGTRe; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AmUtGTRe" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D4D0AC4AF09; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560800; bh=JFEsCrZJXfeUrVql42hGAUplnUlBcbOKU8n7z+cwh6o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AmUtGTRe42ShMb+rIe/trm1wS9tIzDMNVoNBopCd7mSsNUB1Y55T6+KB0qqR/NJnu YC6uPuDnkAbkMOvtmq/lsCes4nHzXm30eqY7ItT6z6TPi+z/sLm+35c1yPYppMH6Ex BPPA8gEMYxXO6i7bnnJYvSMsCXriyaeqhycKVgSXQSv3McMMiu3mu8N76VpGQmjqpt ewwSqRH2c+0QP/JrG6ITf+s3ym2MUeC7RRlm7rSHoU2RXXG8y0FqttqNQKJ/W4/pLK GDDRsFP/8DRYaEL06L6H+vllLOGsr6n07qlThvSE4r7ASWZzzdXlu4O00g9euXisU+ OUcfwL20Op1GQ== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogH-3I4M; Wed, 22 Jan 2025 16:46:37 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , Dongjiu Geng , Peter Maydell , Shannon Zhao , linux-kernel@vger.kernel.org Subject: [PATCH 01/11] acpi/ghes: Prepare to support multiple sources on ghes Date: Wed, 22 Jan 2025 16:46:18 +0100 Message-ID: <781c65c9188c4649821885a62b6f6370ff7874d2.1737560101.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" The current code is actually dependent on having just one error structure with a single source. As the number of sources should be arch-dependent, as it will depend on what kind of synchronous/assynchronous notifications will exist, change the logic to dynamically build the table. Yet, for a proper support, we need to get the number of sources by reading the number from the HEST table. However, bios currently doesn't store a pointer to it. For now just change the logic at table build time, while enforcing that it will behave like before with a single source ID. A future patch will add a HEST table bios pointer and change the logic at acpi_ghes_record_errors() to dynamically use the new size. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Jonathan Cameron --- hw/acpi/ghes.c | 43 ++++++++++++++++++++++++++-------------- hw/arm/virt-acpi-build.c | 5 +++++ include/hw/acpi/ghes.h | 21 +++++++++++++------- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index b709c177cdea..3f519ccab90d 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -206,17 +206,26 @@ ghes_gen_err_data_uncorrectable_recoverable(GArray *b= lock, * Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg = blobs. * See docs/specs/acpi_hest_ghes.rst for blobs format. */ -static void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *li= nker) +static void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *li= nker, + int num_sources) { int i, error_status_block_offset; =20 + /* + * TODO: Current version supports only one source. + * A further patch will drop this check, after adding a proper migrati= on + * code, as, for the code to work, we need to store a bios pointer to = the + * HEST table. + */ + assert(num_sources =3D=3D 1); + /* Build error_block_address */ - for (i =3D 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { + for (i =3D 0; i < num_sources; i++) { build_append_int_noprefix(hardware_errors, 0, sizeof(uint64_t)); } =20 /* Build read_ack_register */ - for (i =3D 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { + for (i =3D 0; i < num_sources; i++) { /* * Initialize the value of read_ack_register to 1, so GHES can be * writable after (re)boot. @@ -231,13 +240,13 @@ static void build_ghes_error_table(GArray *hardware_e= rrors, BIOSLinker *linker) =20 /* Reserve space for Error Status Data Block */ acpi_data_push(hardware_errors, - ACPI_GHES_MAX_RAW_DATA_LENGTH * ACPI_GHES_ERROR_SOURCE_COUNT); + ACPI_GHES_MAX_RAW_DATA_LENGTH * num_sources); =20 /* Tell guest firmware to place hardware_errors blob into RAM */ bios_linker_loader_alloc(linker, ACPI_HW_ERROR_FW_CFG_FILE, hardware_errors, sizeof(uint64_t), false); =20 - for (i =3D 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) { + for (i =3D 0; i < num_sources; i++) { /* * Tell firmware to patch error_block_address entries to point to * corresponding "Generic Error Status Block" @@ -263,10 +272,12 @@ static void build_ghes_error_table(GArray *hardware_e= rrors, BIOSLinker *linker) /* Build Generic Hardware Error Source version 2 (GHESv2) */ static void build_ghes_v2(GArray *table_data, BIOSLinker *linker, - enum AcpiGhesNotifyType notify, - uint16_t source_id) + const AcpiNotificationSourceId *notif_src, + uint16_t index, int num_sources) { uint64_t address_offset; + const uint16_t notify =3D notif_src->notify; + const uint16_t source_id =3D notif_src->source_id; =20 /* * Type: @@ -297,7 +308,7 @@ static void build_ghes_v2(GArray *table_data, address_offset + GAS_ADDR_OFFSET, sizeof(uint64_t), ACPI_HW_ERROR_FW_CFG_FILE, - source_id * sizeof(uint64_t)); + index * sizeof(uint64_t)); =20 /* Notification Structure */ build_ghes_hw_error_notification(table_data, notify); @@ -317,8 +328,7 @@ static void build_ghes_v2(GArray *table_data, address_offset + GAS_ADDR_OFFSET, sizeof(uint64_t), ACPI_HW_ERROR_FW_CFG_FILE, - (ACPI_GHES_ERROR_SOURCE_COUNT + source_= id) - * sizeof(uint64_t)); + (num_sources + index) * sizeof(uint64_t= )); =20 /* * Read Ack Preserve field @@ -333,19 +343,23 @@ static void build_ghes_v2(GArray *table_data, /* Build Hardware Error Source Table */ void acpi_build_hest(GArray *table_data, GArray *hardware_errors, BIOSLinker *linker, + const AcpiNotificationSourceId * const notif_source, + int num_sources, const char *oem_id, const char *oem_table_id) { AcpiTable table =3D { .sig =3D "HEST", .rev =3D 1, .oem_id =3D oem_id, .oem_table_id =3D oem_table_id= }; + int i; =20 - build_ghes_error_table(hardware_errors, linker); + build_ghes_error_table(hardware_errors, linker, num_sources); =20 acpi_table_begin(&table, table_data); =20 /* Error Source Count */ - build_append_int_noprefix(table_data, ACPI_GHES_ERROR_SOURCE_COUNT, 4); - build_ghes_v2(table_data, linker, - ACPI_GHES_NOTIFY_SEA, ACPI_HEST_SRC_ID_SEA); + build_append_int_noprefix(table_data, num_sources, 4); + for (i =3D 0; i < num_sources; i++) { + build_ghes_v2(table_data, linker, ¬if_source[i], i, num_sources= ); + } =20 acpi_table_end(linker, &table); } @@ -410,7 +424,6 @@ void ghes_record_cper_errors(const void *cper, size_t l= en, } ags =3D &acpi_ged_state->ghes_state; =20 - assert(ACPI_GHES_ERROR_SOURCE_COUNT =3D=3D 1); get_hw_error_offsets(le64_to_cpu(ags->hw_error_le), &cper_addr, &read_ack_register_addr); =20 diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 3ac8f8e17861..3d411787fc37 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -893,6 +893,10 @@ static void acpi_align_size(GArray *blob, unsigned ali= gn) g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); } =20 +static const AcpiNotificationSourceId hest_ghes_notify[] =3D { + { ACPI_HEST_SRC_ID_SYNC, ACPI_GHES_NOTIFY_SEA }, +}; + static void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) { @@ -948,6 +952,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTa= bles *tables) if (vms->ras) { acpi_add_table(table_offsets, tables_blob); acpi_build_hest(tables_blob, tables->hardware_errors, tables->link= er, + hest_ghes_notify, ARRAY_SIZE(hest_ghes_notify), vms->oem_id, vms->oem_table_id); } =20 diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 39619a2457cb..9f0120d0d596 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -57,20 +57,27 @@ enum AcpiGhesNotifyType { ACPI_GHES_NOTIFY_RESERVED =3D 12 }; =20 -enum { - ACPI_HEST_SRC_ID_SEA =3D 0, - /* future ids go here */ - - ACPI_GHES_ERROR_SOURCE_COUNT -}; - typedef struct AcpiGhesState { uint64_t hw_error_le; bool present; /* True if GHES is present at all on this board */ } AcpiGhesState; =20 +/* + * ID numbers used to fill HEST source ID field + */ +enum AcpiGhesSourceID { + ACPI_HEST_SRC_ID_SYNC, +}; + +typedef struct AcpiNotificationSourceId { + enum AcpiGhesSourceID source_id; + enum AcpiGhesNotifyType notify; +} AcpiNotificationSourceId; + void acpi_build_hest(GArray *table_data, GArray *hardware_errors, BIOSLinker *linker, + const AcpiNotificationSourceId * const notif_source, + int num_sources, const char *oem_id, const char *oem_table_id); void acpi_ghes_add_fw_cfg(AcpiGhesState *vms, FWCfgState *s, GArray *hardware_errors); --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 45BAB2147E5 for ; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=DmroLu06FBNBtjyyQdC9PghEhXXncr4JMV0G16a8yfh+9NZPbQRsxEyXWPjIr9s65M4KjpDtBLw40V4FansEvpYvRiL1SFO6Z4zk7II2bXApXVM16dsIGrIQG67MF6K8NkkXE/SODuhgPUeowlSP0rDYdp/5Co14FCmeGc67Rgs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=dVoyxElY60NM8RK48eYr47WE+kDPX7wZDrmsKdOm7/M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=u0g8MiSB3Va0MumIRtQbyhMrFFmTsko61+/D49zzPY6lr32Lcxct/LT5YByEsZ/p9yQ1tYBhHYLil5N8bQRXc7t3LqbnwBosEoCK/9ZmIzRAuazk6ojpSaPZP+YNq2WjUrWr9DdmCNHP/18XCEuyrLidIST2bCq4vkdFkPsCAVg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qLVcpd2/; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qLVcpd2/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CEEF4C4CEE2; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560799; bh=dVoyxElY60NM8RK48eYr47WE+kDPX7wZDrmsKdOm7/M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qLVcpd2/p4QC6Ntez29y1wRk/1Q4Xt8+eExqhreF8BAuUQ8B5D/H3eQxW5vxuxEN0 FkwzP6TLLeuPIZZhLa5pNlTeIHE1NBUwlINEsaEAIXvEnLMHAKh2snSZAQwKY+M1mY twOxHjJeDWxkm1Olv0YeODk9gtq6INdEsgKKoQj3tdPd8NgJxY+KtmxeOvHvOIgobs 8wNzW+kcxCTzl4B/eH3eA3tmHTp07drdsmgI8lV9FO5g8cQglFHSluC7Ndd3W8/iCQ puWHcCK1hMvYe0pThmR41Ywv3oKLPSKDrCQ21EAZMyed/yNlrq2vXqZrvNz3Mrg+xl F4BifeGeDoJVA== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogM-3OqU; Wed, 22 Jan 2025 16:46:37 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , Dongjiu Geng , linux-kernel@vger.kernel.org Subject: [PATCH 02/11] acpi/ghes: add a firmware file with HEST address Date: Wed, 22 Jan 2025 16:46:19 +0100 Message-ID: X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Store HEST table address at GPA, placing its content at hest_addr_le variable. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Jonathan Cameron --- Change from v8: - hest_addr_lr is now pointing to the error source size and data. Signed-off-by: Mauro Carvalho Chehab --- hw/acpi/ghes.c | 17 ++++++++++++++++- include/hw/acpi/ghes.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 3f519ccab90d..34e3364d3fd8 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -30,6 +30,7 @@ =20 #define ACPI_HW_ERROR_FW_CFG_FILE "etc/hardware_errors" #define ACPI_HW_ERROR_ADDR_FW_CFG_FILE "etc/hardware_errors_addr" +#define ACPI_HEST_ADDR_FW_CFG_FILE "etc/acpi_table_hest_addr" =20 /* The max size in bytes for one error block */ #define ACPI_GHES_MAX_RAW_DATA_LENGTH (1 * KiB) @@ -261,7 +262,7 @@ static void build_ghes_error_table(GArray *hardware_err= ors, BIOSLinker *linker, } =20 /* - * tell firmware to write hardware_errors GPA into + * Tell firmware to write hardware_errors GPA into * hardware_errors_addr fw_cfg, once the former has been initialized. */ bios_linker_loader_write_pointer(linker, ACPI_HW_ERROR_ADDR_FW_CFG_FIL= E, 0, @@ -355,6 +356,8 @@ void acpi_build_hest(GArray *table_data, GArray *hardwa= re_errors, =20 acpi_table_begin(&table, table_data); =20 + int hest_offset =3D table_data->len; + /* Error Source Count */ build_append_int_noprefix(table_data, num_sources, 4); for (i =3D 0; i < num_sources; i++) { @@ -362,6 +365,15 @@ void acpi_build_hest(GArray *table_data, GArray *hardw= are_errors, } =20 acpi_table_end(linker, &table); + + /* + * tell firmware to write into GPA the address of HEST via fw_cfg, + * once initialized. + */ + bios_linker_loader_write_pointer(linker, + ACPI_HEST_ADDR_FW_CFG_FILE, 0, + sizeof(uint64_t), + ACPI_BUILD_TABLE_FILE, hest_offset); } =20 void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s, @@ -375,6 +387,9 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgStat= e *s, fw_cfg_add_file_callback(s, ACPI_HW_ERROR_ADDR_FW_CFG_FILE, NULL, NULL, NULL, &(ags->hw_error_le), sizeof(ags->hw_error_le), false); =20 + fw_cfg_add_file_callback(s, ACPI_HEST_ADDR_FW_CFG_FILE, NULL, NULL, + NULL, &(ags->hest_addr_le), sizeof(ags->hest_addr_le), false); + ags->present =3D true; } =20 diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 9f0120d0d596..237721fec0a2 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -58,6 +58,7 @@ enum AcpiGhesNotifyType { }; =20 typedef struct AcpiGhesState { + uint64_t hest_addr_le; uint64_t hw_error_le; bool present; /* True if GHES is present at all on this board */ } AcpiGhesState; --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 45B4C2144D9 for ; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=sidvgnVI/s3fPLk2P1i4FCqAq6I4l81mmRiqYk/8k4T07CeJ2Jy/l3VAEkaxEAyweOXbfS/jQcQ5RNw71fyY0MEvlY8cKFQ6tb/FyUPsRzD1fRLaq1wm9qAHgVTC7Gdv4dRDNxDZxkBufh0UfmNe2pWpuEnHWMakk4SalcWMptY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=7dDlOu+j2EkHoixFygEQpxqk4U+9+v1WbJNIzodNoG4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=juUOUIPRjQgq3Y1bBjJEs36es8yA/zW5jYPCLPoDUYRDkcOwRTRZ0IIDoUQztSPvVI1ffzbesejNUwJ36lICZKvGf8UNKSYCZgSdKcFKQ1KrJ/vj6l2cj2dzc8ewbKhRApqVNeGHTOIffn77sRZP1iW/NMEu3OIbx4JTDLFSKSg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kcXHpCzs; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kcXHpCzs" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C4C8AC4CED2; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560799; bh=7dDlOu+j2EkHoixFygEQpxqk4U+9+v1WbJNIzodNoG4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kcXHpCzsC9illiZAaQq90RTCjF9DrLxytusdORPnmH6c19a5nzETdIQZuDAF9VS9l IBfrdlepBFFAawy9MkNyw4OelbjkaXiLVBleOw387c9oBbeuAHHDXKqphbvnCArjgK ecYJsxYq+mbQ8osIiFqV02sulPRWAxQdViJQMpPN7LreZXoTqb1HmB+kjQue5p5kO0 y5gHTLw/NUO2Iy+mCBKri9uYrQcuUDNdwUUF7zqPe56qVQMlhRexplqk/eX+xSDy/4 hrDWKClGK0gfnvplQ9mmvY+Lkys9DW5lrtM+TBYRhRkl9J0jr3PbRDJy3yGwfl+FuP Hd9ZK3Rk9JDQQ== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogQ-3VaS; Wed, 22 Jan 2025 16:46:37 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , Dongjiu Geng , linux-kernel@vger.kernel.org Subject: [PATCH 03/11] acpi/ghes: Use HEST table offsets when preparing GHES records Date: Wed, 22 Jan 2025 16:46:20 +0100 Message-ID: <10a8a913862c9cc894235d32b10bbf2f992340ff.1737560101.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" There are two pointers that are needed during error injection: 1. The start address of the CPER block to be stored; 2. The address of the ack, which needs a reset before next error. It is preferable to calculate them from the HEST table. This allows checking the source ID, the size of the table and the type of the HEST error block structures. Yet, keep the old code, as this is needed for migration purposes. Signed-off-by: Mauro Carvalho Chehab --- hw/acpi/ghes.c | 98 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 34e3364d3fd8..b46b563bcaf8 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -61,6 +61,23 @@ */ #define ACPI_GHES_GESB_SIZE 20 =20 +/* + * Offsets with regards to the start of the HEST table stored at + * ags->hest_addr_le, according with the memory layout map at + * docs/specs/acpi_hest_ghes.rst. + */ + +/* ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2 + * Table 18-382 Generic Hardware Error Source version 2 (GHESv2) Structure + */ +#define HEST_GHES_V2_TABLE_SIZE 92 +#define GHES_ACK_OFFSET (64 + GAS_ADDR_OFFSET) + +/* ACPI 6.2: 18.3.2.7: Generic Hardware Error Source + * Table 18-380: 'Error Status Address' field + */ +#define GHES_ERR_ST_ADDR_OFFSET (20 + GAS_ADDR_OFFSET) + /* * Values for error_severity field */ @@ -212,14 +229,6 @@ static void build_ghes_error_table(GArray *hardware_er= rors, BIOSLinker *linker, { int i, error_status_block_offset; =20 - /* - * TODO: Current version supports only one source. - * A further patch will drop this check, after adding a proper migrati= on - * code, as, for the code to work, we need to store a bios pointer to = the - * HEST table. - */ - assert(num_sources =3D=3D 1); - /* Build error_block_address */ for (i =3D 0; i < num_sources; i++) { build_append_int_noprefix(hardware_errors, 0, sizeof(uint64_t)); @@ -419,6 +428,70 @@ static void get_hw_error_offsets(uint64_t ghes_addr, *read_ack_register_addr =3D ghes_addr + sizeof(uint64_t); } =20 +static void get_ghes_source_offsets(uint16_t source_id, uint64_t hest_addr, + uint64_t *cper_addr, + uint64_t *read_ack_start_addr, + Error **errp) +{ + uint64_t hest_err_block_addr, hest_read_ack_addr; + uint64_t err_source_struct, error_block_addr; + uint32_t num_sources, i; + + if (!hest_addr) { + return; + } + + cpu_physical_memory_read(hest_addr, &num_sources, sizeof(num_sources)); + num_sources =3D le32_to_cpu(num_sources); + + err_source_struct =3D hest_addr + sizeof(num_sources); + + /* + * Currently, HEST Error source navigates only for GHESv2 tables + */ + + for (i =3D 0; i < num_sources; i++) { + uint64_t addr =3D err_source_struct; + uint16_t type, src_id; + + cpu_physical_memory_read(addr, &type, sizeof(type)); + type =3D le16_to_cpu(type); + + /* For now, we only know the size of GHESv2 table */ + if (type !=3D ACPI_GHES_SOURCE_GENERIC_ERROR_V2) { + error_setg(errp, "HEST: type %d not supported.", type); + return; + } + + /* Compare CPER source address at the GHESv2 structure */ + addr +=3D sizeof(type); + cpu_physical_memory_read(addr, &src_id, sizeof(src_id)); + + if (src_id =3D=3D source_id) { + break; + } + + err_source_struct +=3D HEST_GHES_V2_TABLE_SIZE; + } + if (i =3D=3D num_sources) { + error_setg(errp, "HEST: Source %d not found.", source_id); + return; + } + + /* Navigate though table address pointers */ + hest_err_block_addr =3D err_source_struct + GHES_ERR_ST_ADDR_OFFSET; + hest_read_ack_addr =3D err_source_struct + GHES_ACK_OFFSET; + + cpu_physical_memory_read(hest_err_block_addr, &error_block_addr, + sizeof(error_block_addr)); + + cpu_physical_memory_read(error_block_addr, cper_addr, + sizeof(*cper_addr)); + + cpu_physical_memory_read(hest_read_ack_addr, read_ack_start_addr, + sizeof(*read_ack_start_addr)); +} + void ghes_record_cper_errors(const void *cper, size_t len, uint16_t source_id, Error **errp) { @@ -439,8 +512,13 @@ void ghes_record_cper_errors(const void *cper, size_t = len, } ags =3D &acpi_ged_state->ghes_state; =20 - get_hw_error_offsets(le64_to_cpu(ags->hw_error_le), - &cper_addr, &read_ack_register_addr); + if (!ags->hest_addr_le) { + get_hw_error_offsets(le64_to_cpu(ags->hw_error_le), + &cper_addr, &read_ack_register_addr); + } else { + get_ghes_source_offsets(source_id, le64_to_cpu(ags->hest_addr_le), + &cper_addr, &read_ack_register_addr, errp); + } =20 if (!cper_addr) { error_setg(errp, "can not find Generic Error Status Block"); --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1C5922139C8 for ; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=SUGb9R2f4lmNPYwUvrbcBWaUnsuRzJNTA4OCmPx9mMvYAx6QDelek4/GOWMXr9nEkSyWb6Mpo5R6CzTYorwFrBtVEpEAE/1rKWNzzqXM/9AA0Iz53mA9Ibyr4CGgf7DQLrjRnVMINxfUhPBe9Nb1h72e3dhtrUil9CcStU7BuH4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=g0gfo/yes3890ErorV/wcsHaHmbCCk1aBKfBKpAltNc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mrU9z3qh8rVqlKvyeNlalMrd9atCasAK55W0+LXZo5sA5TJG6hbv4P0VqZCcrMCcSPw1jwzWt8xUbu1wfuUnPixeoy8rPTNIG+C2hgeSJS46cNXH9JiSr0TvKKSlKKWRNLUR0exz7UEf4I1dAcS03n77kKJe70aQvfWjMQ+/aIM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=eDvuiCnz; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="eDvuiCnz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DD3C4C4CED6; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560799; bh=g0gfo/yes3890ErorV/wcsHaHmbCCk1aBKfBKpAltNc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eDvuiCnzALqUN3kUrQ0678xn9PlAkJ117ctXm+03QFQO3Op6yUrozOrDDMnlbDikZ jGdE4F2yEvs8PU1QIEz/bjo6XYB3zu2Q4mHu47EP3mSbj9gT5riPfMxxq07+GlkIZn h4SDct7EZSmFpTOIqyVtDEpRn/pwncwZWUD4X2X9nJGOajvVCMAv1bJxdXUI6nIlq+ 5+tMdimtM1Kb7Ft0gGxEj3+ApTs4Ond9/KfvdbFalGfx0/tAYRRUfFXQ6WVIL39Wu9 6CGHE4sCihONomqlV/DMtcGw+BmS5H0cvsCUppe3Qww2w1FEo+c/XM/63JP9WrhT3P JLHtfNG2KrShQ== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogU-3cZ3; Wed, 22 Jan 2025 16:46:37 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , linux-kernel@vger.kernel.org Subject: [PATCH 04/11] acpi/generic_event_device: Update GHES migration to cover hest addr Date: Wed, 22 Jan 2025 16:46:21 +0100 Message-ID: <6b79da0dbd8d735e93c15c4673bf2af61e8c34a2.1737560101.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" The GHES migration logic at GED should now support HEST table location too. Signed-off-by: Mauro Carvalho Chehab --- hw/acpi/generic_event_device.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index c85d97ca3776..5346cae573b7 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -386,6 +386,34 @@ static const VMStateDescription vmstate_ghes_state =3D= { } }; =20 +static const VMStateDescription vmstate_hest =3D { + .name =3D "acpi-hest", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (const VMStateField[]) { + VMSTATE_UINT64(hest_addr_le, AcpiGhesState), + VMSTATE_END_OF_LIST() + }, +}; + +static bool hest_needed(void *opaque) +{ + AcpiGedState *s =3D opaque; + return s->ghes_state.hest_addr_le; +} + +static const VMStateDescription vmstate_hest_state =3D { + .name =3D "acpi-ged/hest", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D hest_needed, + .fields =3D (const VMStateField[]) { + VMSTATE_STRUCT(ghes_state, AcpiGedState, 1, + vmstate_hest, AcpiGhesState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_acpi_ged =3D { .name =3D "acpi-ged", .version_id =3D 1, @@ -398,6 +426,7 @@ static const VMStateDescription vmstate_acpi_ged =3D { &vmstate_memhp_state, &vmstate_cpuhp_state, &vmstate_ghes_state, + &vmstate_hest_state, NULL } }; --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 68466214802 for ; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=WPxOrYUIM8OOXrxl0WnN+KysWDaWyvJfzOmxcLBoUoLtnKoRxZSsYlp2TUlQBhHP+iEx6AgvYmXCcZqIfSuEnZGz1bMM1vJYH/NJYyK6TZtEE248KmheSFebX3iPhZ4xEirVo5w/+dGBpsh5sjTkytoWPDqoycDq+bfkOo5u1X0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=poG2Yoeg5ZDbOr3TxSAt9ETkPdTI1KltVKwvO+UZqmk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nefHm0ss9gSWIJ6XzTVTAmMnXHauY7sqfpOJyw2l8OyBnKmrZACBhhjER/cT8dnb2PDB25/ET3pHOHrsEHeZdRe0LI80S2d5fTucyh4k4JYLt5zAU9cO4g2SwzfxLaPh5EkJ/JJr2I7ynPW6yz3X91vI+0wgho6X0sBRt+/bl1o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Jl7v4rhU; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Jl7v4rhU" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E31BDC4CEE7; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560800; bh=poG2Yoeg5ZDbOr3TxSAt9ETkPdTI1KltVKwvO+UZqmk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Jl7v4rhU7EydjcJu2/Z4LzVrJJLuZuUxAeA02FP3L8P4tGuq2BsGj4oWzs7iELK+1 ar8qIhU57yXNwuu8ZDSfcPwoWAiTGmVk4Fj7fekoEhqRgfEL5pjTDoFpuFu3HANzFm uwduAPE2/g1uOM4iyy25vZ7e8aL0JnLo1BSPgJvY6fbJaOAWVJriNewuLHXr9njyot yQKdKhyOZFyN1LMVOY17Tg3IwwKTSYsMcfqbGPfR59FGprJNhCGqm9h45RIHgZwz3+ D/SOPj5x1KkdadRX0VAnISWbyjHT2ZMOKLHWnPj4xTpu0LH+A0WMoxRkxPrVbKy0Of KaTgUqraRH5ew== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogY-3jdp; Wed, 22 Jan 2025 16:46:37 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Ani Sinha , Dongjiu Geng , Eduardo Habkost , Marcel Apfelbaum , Peter Maydell , Shannon Zhao , Yanan Wang , Zhao Liu , linux-kernel@vger.kernel.org Subject: [PATCH 05/11] acpi/generic_event_device: add logic to detect if HEST addr is available Date: Wed, 22 Jan 2025 16:46:22 +0100 Message-ID: <556c19c1f3fa907c6cc13b62e060f6baa6faf2cf.1737560101.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Create a new property (x-has-hest-addr) and use it to detect if the GHES table offsets can be calculated from the HEST address (qemu 9.2 and upper) or via the legacy way via an offset obtained from the hardware_errors firmware file. Signed-off-by: Mauro Carvalho Chehab --- hw/acpi/generic_event_device.c | 1 + hw/acpi/ghes.c | 28 +++++++++++++++++++++------- hw/arm/virt-acpi-build.c | 30 ++++++++++++++++++++++++++---- hw/core/machine.c | 2 ++ include/hw/acpi/ghes.h | 1 + 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 5346cae573b7..fe537ed05c66 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -318,6 +318,7 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, Acp= iEventStatusBits ev) =20 static const Property acpi_ged_properties[] =3D { DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0), + DEFINE_PROP_BOOL("x-has-hest-addr", AcpiGedState, ghes_state.hest_look= up, true), }; =20 static const VMStateDescription vmstate_memhp_state =3D { diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index b46b563bcaf8..86c97f60d6a0 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -359,6 +359,8 @@ void acpi_build_hest(GArray *table_data, GArray *hardwa= re_errors, { AcpiTable table =3D { .sig =3D "HEST", .rev =3D 1, .oem_id =3D oem_id, .oem_table_id =3D oem_table_id= }; + AcpiGedState *acpi_ged_state; + AcpiGhesState *ags =3D NULL; int i; =20 build_ghes_error_table(hardware_errors, linker, num_sources); @@ -379,10 +381,20 @@ void acpi_build_hest(GArray *table_data, GArray *hard= ware_errors, * tell firmware to write into GPA the address of HEST via fw_cfg, * once initialized. */ - bios_linker_loader_write_pointer(linker, - ACPI_HEST_ADDR_FW_CFG_FILE, 0, - sizeof(uint64_t), - ACPI_BUILD_TABLE_FILE, hest_offset); + + acpi_ged_state =3D ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, + NULL)); + if (!acpi_ged_state) { + return; + } + + ags =3D &acpi_ged_state->ghes_state; + if (ags->hest_lookup) { + bios_linker_loader_write_pointer(linker, + ACPI_HEST_ADDR_FW_CFG_FILE, 0, + sizeof(uint64_t), + ACPI_BUILD_TABLE_FILE, hest_offse= t); + } } =20 void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s, @@ -396,8 +408,10 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgSta= te *s, fw_cfg_add_file_callback(s, ACPI_HW_ERROR_ADDR_FW_CFG_FILE, NULL, NULL, NULL, &(ags->hw_error_le), sizeof(ags->hw_error_le), false); =20 - fw_cfg_add_file_callback(s, ACPI_HEST_ADDR_FW_CFG_FILE, NULL, NULL, - NULL, &(ags->hest_addr_le), sizeof(ags->hest_addr_le), false); + if (ags && ags->hest_lookup) { + fw_cfg_add_file_callback(s, ACPI_HEST_ADDR_FW_CFG_FILE, NULL, NULL, + NULL, &(ags->hest_addr_le), sizeof(ags->hest_addr_le), false); + } =20 ags->present =3D true; } @@ -512,7 +526,7 @@ void ghes_record_cper_errors(const void *cper, size_t l= en, } ags =3D &acpi_ged_state->ghes_state; =20 - if (!ags->hest_addr_le) { + if (!ags->hest_lookup) { get_hw_error_offsets(le64_to_cpu(ags->hw_error_le), &cper_addr, &read_ack_register_addr); } else { diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 3d411787fc37..ada5d08cfbe7 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -897,6 +897,10 @@ static const AcpiNotificationSourceId hest_ghes_notify= [] =3D { { ACPI_HEST_SRC_ID_SYNC, ACPI_GHES_NOTIFY_SEA }, }; =20 +static const AcpiNotificationSourceId hest_ghes_notify_9_2[] =3D { + { ACPI_HEST_SRC_ID_SYNC, ACPI_GHES_NOTIFY_SEA }, +}; + static void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) { @@ -950,10 +954,28 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuild= Tables *tables) build_dbg2(tables_blob, tables->linker, vms); =20 if (vms->ras) { - acpi_add_table(table_offsets, tables_blob); - acpi_build_hest(tables_blob, tables->hardware_errors, tables->link= er, - hest_ghes_notify, ARRAY_SIZE(hest_ghes_notify), - vms->oem_id, vms->oem_table_id); + AcpiGhesState *ags; + AcpiGedState *acpi_ged_state; + + acpi_ged_state =3D ACPI_GED(object_resolve_path_type("", TYPE_ACPI= _GED, + NULL)); + if (acpi_ged_state) { + ags =3D &acpi_ged_state->ghes_state; + + acpi_add_table(table_offsets, tables_blob); + + if (!ags->hest_lookup) { + acpi_build_hest(tables_blob, tables->hardware_errors, + tables->linker, hest_ghes_notify_9_2, + ARRAY_SIZE(hest_ghes_notify_9_2), + vms->oem_id, vms->oem_table_id); + } else { + acpi_build_hest(tables_blob, tables->hardware_errors, + tables->linker, hest_ghes_notify, + ARRAY_SIZE(hest_ghes_notify), + vms->oem_id, vms->oem_table_id); + } + } } =20 if (ms->numa_state->num_nodes > 0) { diff --git a/hw/core/machine.c b/hw/core/machine.c index c23b39949649..0d0cde481954 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -34,10 +34,12 @@ #include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-iommu.h" +#include "hw/acpi/generic_event_device.h" #include "audio/audio.h" =20 GlobalProperty hw_compat_9_2[] =3D { {"arm-cpu", "backcompat-pauth-default-use-qarma5", "true"}, + { TYPE_ACPI_GED, "x-has-hest-addr", "false" }, }; const size_t hw_compat_9_2_len =3D G_N_ELEMENTS(hw_compat_9_2); =20 diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 237721fec0a2..164ed8b0f9a3 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -61,6 +61,7 @@ typedef struct AcpiGhesState { uint64_t hest_addr_le; uint64_t hw_error_le; bool present; /* True if GHES is present at all on this board */ + bool hest_lookup; /* True if HEST address is present */ } AcpiGhesState; =20 /* --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 175E0211A18 for ; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=hqCPtQBCOav6AH1vbi4xOQPtgRfNcSRei7IHjnFCwbMgU1FF6d8Fm/QsK3eJfQCTfb011atAXgMmqeKhudbNJiKb73uTpscykWwiZYkCixmqRHNadSflzmG0cJtTetJzGhtG8GHpQ6+O5XVsFiLiT4N3N3PNhbOXq/9cbQ13urM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=L9zIZD2Brt7xrZs2jK5Zsf83XHA4Wpm8uMTXvnIC9LU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eY5zLwcijfn+1yDGRUm/sND/NeqrPfIcE5UWUkD8oeZy1gPLMzGkp6nFtXKmPy3dqVOcYTjoPzUyWzDTUQRfjY4gVQi3mp/5UEjcRyXXV2s8JP0jDmH/Is93kjGZsIfHQAJeam0eaGOkmcbU+h/9CWis0leiMhxztHAKiOC5M3s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=d5E5U5/Z; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="d5E5U5/Z" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D76BFC4AF0B; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560799; bh=L9zIZD2Brt7xrZs2jK5Zsf83XHA4Wpm8uMTXvnIC9LU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=d5E5U5/ZnmqZmiZDowtfuTIlDQT1MCfXdiXtVI5lvCLNI46dwlawZceD/klFQ6jRT Od1QHpqsYcRcrZeINQzeP3zaeaIrreL3szF9YCKoT54+9GVGbuEqAC9IjCviFrTzxt ZGe2+yx9276HHaLtXav9Rh+3FUjgPU09/xTlaEhEVzr1RGAvKycLLpSfuXvmlDasA+ V+2OU6yJTxnHaz57CBGFqeinPdqsZ4x5JbBSZWhDSKMGNLfynY5TEyYnRnYW07k9+e nDq32RuM7Z2ywWBLZElTWMFMiDArk+68Qeu1MyFBY7BpiUwPADmxO7hiR+4jh86/bv YKYE4/UJe5Riw== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogc-3qU0; Wed, 22 Jan 2025 16:46:37 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , Dongjiu Geng , linux-kernel@vger.kernel.org Subject: [PATCH 06/11] acpi/ghes: add a notifier to notify when error data is ready Date: Wed, 22 Jan 2025 16:46:23 +0100 Message-ID: X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Some error injection notify methods are async, like GPIO notify. Add a notifier to be used when the error record is ready to be sent to the guest OS. Signed-off-by: Mauro Carvalho Chehab --- hw/acpi/ghes.c | 5 ++++- include/hw/acpi/ghes.h | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 86c97f60d6a0..961fc38ea8f5 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -506,6 +506,9 @@ static void get_ghes_source_offsets(uint16_t source_id,= uint64_t hest_addr, sizeof(*read_ack_start_addr)); } =20 +NotifierList acpi_generic_error_notifiers =3D + NOTIFIER_LIST_INITIALIZER(error_device_notifiers); + void ghes_record_cper_errors(const void *cper, size_t len, uint16_t source_id, Error **errp) { @@ -561,7 +564,7 @@ void ghes_record_cper_errors(const void *cper, size_t l= en, /* Write the generic error data entry into guest memory */ cpu_physical_memory_write(cper_addr, cper, len); =20 - return; + notifier_list_notify(&acpi_generic_error_notifiers, NULL); } =20 int acpi_ghes_memory_errors(uint16_t source_id, uint64_t physical_address) diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 164ed8b0f9a3..2e8405edfe27 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -24,6 +24,9 @@ =20 #include "hw/acpi/bios-linker-loader.h" #include "qapi/error.h" +#include "qemu/notify.h" + +extern NotifierList acpi_generic_error_notifiers; =20 /* * Values for Hardware Error Notification Type field --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 40B86214218; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=NKKLLwagEo0cfGlblYhgFdAocnPbLH+2llIcyecqCFHWOi1cz79HrNLQSitJp9SZ4Q8Y4TVJ8pB2yD1eLVgk7SxpdveAIMZI0Rg9l5G0OjjVi2z0rDAcUwl8yk1W3/1S5pBJy0ddCig5P5Ye8eOb2O2Ah7hei8y1DrNNAZ7aCp4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=SDAM2Hf0+OjvENc78mlriwxC/2c7OGDKK+nhESUWpgE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YGeAgpJpkSVUcmLiRn4BtlbhnQN/QYozxEa9qfFTwN8V+5xKJq41jqzXrqv0Q+qrH3zInPXiQVsbLAb+bVTPGhuDcAs/HFu7wgjBmBgsYlZxjZ7coj3QP8whEO3QDmLh4OeUEn6euOVR3qS2ZcQzvxZ/M9INcoJD1gPoeJmefkA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WoQ5v/Rg; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WoQ5v/Rg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E2B56C4CEE4; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560799; bh=SDAM2Hf0+OjvENc78mlriwxC/2c7OGDKK+nhESUWpgE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WoQ5v/Rg8D57ii/NQ0uNW6JD9BzuQ1V4D89wzL2hK4zrO5HyCWSQef4TqC8edvJM2 lKzhNp4d4kxEG6LYjj0QVncNjsVooYp7GNM93wh4lukvszBIjW+EIHIvemN6taSowR 5n8Uze/3ee/XcI3LeTj/ekV+PV/kmkOI860gil1MjptMK/TisF/w2Dt1PDIAfg6N0X rMqTC+d91EOCD4gcP+kaobSknP6eXoc6/tsnpZlea/8RI+B/Oh11fUfix24YIBA5Np Tq4mwZpcM4RlkiJVUicNVoka8rFN44uuWy6wEl4g6GoIBTsQqbRpd6bgXb8wL0NADK mT3HoOrfAONgA== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogg-3xHu; Wed, 22 Jan 2025 16:46:37 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , Dongjiu Geng , Paolo Bonzini , Peter Maydell , kvm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 07/11] acpi/ghes: Cleanup the code which gets ghes ged state Date: Wed, 22 Jan 2025 16:46:24 +0100 Message-ID: <200501cb372d5121c44128a79b8775e529dc46e6.1737560101.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Move the check logic into a common function and simplify the code which checks if GHES is enabled and was properly setup. Signed-off-by: Mauro Carvalho Chehab --- hw/acpi/ghes-stub.c | 4 ++-- hw/acpi/ghes.c | 33 +++++++++++---------------------- include/hw/acpi/ghes.h | 9 +++++---- target/arm/kvm.c | 2 +- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/hw/acpi/ghes-stub.c b/hw/acpi/ghes-stub.c index 7cec1812dad9..fbabf955155a 100644 --- a/hw/acpi/ghes-stub.c +++ b/hw/acpi/ghes-stub.c @@ -16,7 +16,7 @@ int acpi_ghes_memory_errors(uint16_t source_id, uint64_t = physical_address) return -1; } =20 -bool acpi_ghes_present(void) +AcpiGhesState *acpi_ghes_get_state(void) { - return false; + return NULL; } diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 961fc38ea8f5..5d29db3918dd 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -420,10 +420,6 @@ static void get_hw_error_offsets(uint64_t ghes_addr, uint64_t *cper_addr, uint64_t *read_ack_register_addr) { - if (!ghes_addr) { - return; - } - /* * non-HEST version supports only one source, so no need to change * the start offset based on the source ID. Also, we can't validate @@ -451,10 +447,6 @@ static void get_ghes_source_offsets(uint16_t source_id= , uint64_t hest_addr, uint64_t err_source_struct, error_block_addr; uint32_t num_sources, i; =20 - if (!hest_addr) { - return; - } - cpu_physical_memory_read(hest_addr, &num_sources, sizeof(num_sources)); num_sources =3D le32_to_cpu(num_sources); =20 @@ -513,7 +505,6 @@ void ghes_record_cper_errors(const void *cper, size_t l= en, uint16_t source_id, Error **errp) { uint64_t cper_addr =3D 0, read_ack_register_addr =3D 0, read_ack_regis= ter; - AcpiGedState *acpi_ged_state; AcpiGhesState *ags; =20 if (len > ACPI_GHES_MAX_RAW_DATA_LENGTH) { @@ -521,13 +512,10 @@ void ghes_record_cper_errors(const void *cper, size_t= len, return; } =20 - acpi_ged_state =3D ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, - NULL)); - if (!acpi_ged_state) { - error_setg(errp, "Can't find ACPI_GED object"); + ags =3D acpi_ghes_get_state(); + if (!ags) { return; } - ags =3D &acpi_ged_state->ghes_state; =20 if (!ags->hest_lookup) { get_hw_error_offsets(le64_to_cpu(ags->hw_error_le), @@ -537,11 +525,6 @@ void ghes_record_cper_errors(const void *cper, size_t = len, &cper_addr, &read_ack_register_addr, errp); } =20 - if (!cper_addr) { - error_setg(errp, "can not find Generic Error Status Block"); - return; - } - cpu_physical_memory_read(read_ack_register_addr, &read_ack_register, sizeof(read_ack_register)= ); =20 @@ -605,7 +588,7 @@ int acpi_ghes_memory_errors(uint16_t source_id, uint64_= t physical_address) return 0; } =20 -bool acpi_ghes_present(void) +AcpiGhesState *acpi_ghes_get_state(void) { AcpiGedState *acpi_ged_state; AcpiGhesState *ags; @@ -614,8 +597,14 @@ bool acpi_ghes_present(void) NULL)); =20 if (!acpi_ged_state) { - return false; + return NULL; } ags =3D &acpi_ged_state->ghes_state; - return ags->present; + if (!ags->present) { + return NULL; + } + if (!ags->hw_error_le && !ags->hest_addr_le) { + return NULL; + } + return ags; } diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 2e8405edfe27..64fe2b5bea65 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -91,10 +91,11 @@ void ghes_record_cper_errors(const void *cper, size_t l= en, uint16_t source_id, Error **errp); =20 /** - * acpi_ghes_present: Report whether ACPI GHES table is present + * acpi_ghes_get_state: Get a pointer for ACPI ghes state * - * Returns: true if the system has an ACPI GHES table and it is - * safe to call acpi_ghes_memory_errors() to record a memory error. + * Returns: a pointer to ghes state if the system has an ACPI GHES table, + * it is enabled and it is safe to call acpi_ghes_memory_errors() to record + * a memory error. Returns false, otherwise. */ -bool acpi_ghes_present(void); +AcpiGhesState *acpi_ghes_get_state(void); #endif diff --git a/target/arm/kvm.c b/target/arm/kvm.c index da30bdbb2349..0283089713b9 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -2369,7 +2369,7 @@ void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, v= oid *addr) =20 assert(code =3D=3D BUS_MCEERR_AR || code =3D=3D BUS_MCEERR_AO); =20 - if (acpi_ghes_present() && addr) { + if (acpi_ghes_get_state() && addr) { ram_addr =3D qemu_ram_addr_from_host(addr); if (ram_addr !=3D RAM_ADDR_INVALID && kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)= ) { --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 10A5A4C9F for ; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=m69ywL5c6c26kcQfcwE9ZFQ8Z7466UA/Sik/i1oykh1JdgX6bv2B2hRF4WoXa26L4O+HUH+HtYDvU21BDyR7qjFX5MsB/As07RnZFKbaxkzloH2hE6d5YUbJ3w1fjs4ARhdVgKaCtYrer3Xk1CIbjEiJY6pJpCTjtEebxzq5hNU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=tFI7o0AuinirOGC3zpJxmGsmNVeaqZwelEbX9SK+JLs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sJ6pXCinNj0FvtvrVpR1Goid/ywW0YUidFFUzmWRIj/X0BsIEz/w0MTN7ZYTSjWNrecYgcS+9uHmc1aylEZrYGxZm7bjlIbL5FsYrrG8bo/GTfPXGGrlJKG3KwQUxtzTRBUNGwlelpXn1j3q2RgkFnFzAM2yHR4u4xQHuKMF8QQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pgiKLpo0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pgiKLpo0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D1A2BC4CEE3; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560799; bh=tFI7o0AuinirOGC3zpJxmGsmNVeaqZwelEbX9SK+JLs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pgiKLpo08u4hii690+qAcBPHZVtlwYKNXYV93qKrVPt4vX7zNfQ6yS2uSKByk5syQ vfeaSlMqYr6f8DDyypVpZ8zyqVyT4AvlV+LOf7HTuwb1krVD/axJCylmRSfEa9VmIQ itmMLNNVxFz5+Z9VTLeb2QYXl90el4AC1jh19+ypHGmq9Ito+KUa10OECAMnd9S72M agrB8E79ClTNqXIgLwfzeLjkf+0KwCLjTWgu0bFiM0c5rBTULtx7L9HpfQRZlhXJD4 EuIS0tIPUhzU5PjtcRnfuYzOTz0IiP5wLqZgwtOPn+TOYZ2h1OH8ESJ3A+Cl2zbsTn sppRLoboIhG2A== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogk-443F; Wed, 22 Jan 2025 16:46:37 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , linux-kernel@vger.kernel.org Subject: [PATCH 08/11] acpi/generic_event_device: add an APEI error device Date: Wed, 22 Jan 2025 16:46:25 +0100 Message-ID: <41b6846394154ddac4d00c3644cd2de577d10115.1737560101.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Adds a generic error device to handle generic hardware error events as specified at ACPI 6.5 specification at 18.3.2.7.2: https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#event-not= ification-for-generic-error-sources using HID PNP0C33. The PNP0C33 device is used to report hardware errors to the guest via ACPI APEI Generic Hardware Error Source (GHES). Co-authored-by: Mauro Carvalho Chehab Co-authored-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Igor Mammedov --- hw/acpi/aml-build.c | 10 ++++++++++ hw/acpi/generic_event_device.c | 8 ++++++++ include/hw/acpi/acpi_dev_interface.h | 1 + include/hw/acpi/aml-build.h | 2 ++ include/hw/acpi/generic_event_device.h | 1 + 5 files changed, 22 insertions(+) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index f8f93a9f66c8..e4bd7b611372 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -2614,3 +2614,13 @@ Aml *aml_i2c_serial_bus_device(uint16_t address, con= st char *resource_source) =20 return var; } + +/* ACPI 5.0b: 18.3.2.6.2 Event Notification For Generic Error Sources */ +Aml *aml_error_device(void) +{ + Aml *dev =3D aml_device(ACPI_APEI_ERROR_DEVICE); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C33"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + return dev; +} diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index fe537ed05c66..ce00c80054f4 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -26,6 +26,7 @@ static const uint32_t ged_supported_events[] =3D { ACPI_GED_PWR_DOWN_EVT, ACPI_GED_NVDIMM_HOTPLUG_EVT, ACPI_GED_CPU_HOTPLUG_EVT, + ACPI_GED_ERROR_EVT, }; =20 /* @@ -116,6 +117,11 @@ void build_ged_aml(Aml *table, const char *name, Hotpl= ugHandler *hotplug_dev, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), aml_int(0x80))); break; + case ACPI_GED_ERROR_EVT: + aml_append(if_ctx, + aml_notify(aml_name(ACPI_APEI_ERROR_DEVICE), + aml_int(0x80))); + break; case ACPI_GED_NVDIMM_HOTPLUG_EVT: aml_append(if_ctx, aml_notify(aml_name("\\_SB.NVDR"), @@ -295,6 +301,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, Acp= iEventStatusBits ev) sel =3D ACPI_GED_MEM_HOTPLUG_EVT; } else if (ev & ACPI_POWER_DOWN_STATUS) { sel =3D ACPI_GED_PWR_DOWN_EVT; + } else if (ev & ACPI_GENERIC_ERROR) { + sel =3D ACPI_GED_ERROR_EVT; } else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) { sel =3D ACPI_GED_NVDIMM_HOTPLUG_EVT; } else if (ev & ACPI_CPU_HOTPLUG_STATUS) { diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_de= v_interface.h index 68d9d15f50aa..8294f8f0ccca 100644 --- a/include/hw/acpi/acpi_dev_interface.h +++ b/include/hw/acpi/acpi_dev_interface.h @@ -13,6 +13,7 @@ typedef enum { ACPI_NVDIMM_HOTPLUG_STATUS =3D 16, ACPI_VMGENID_CHANGE_STATUS =3D 32, ACPI_POWER_DOWN_STATUS =3D 64, + ACPI_GENERIC_ERROR =3D 128, } AcpiEventStatusBits; =20 #define TYPE_ACPI_DEVICE_IF "acpi-device-interface" diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index c18f68134246..f38e12971932 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -252,6 +252,7 @@ struct CrsRangeSet { /* Consumer/Producer */ #define AML_SERIAL_BUS_FLAG_CONSUME_ONLY (1 << 1) =20 +#define ACPI_APEI_ERROR_DEVICE "GEDD" /** * init_aml_allocator: * @@ -382,6 +383,7 @@ Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTra= nsferSize sz, uint8_t channel); Aml *aml_sleep(uint64_t msec); Aml *aml_i2c_serial_bus_device(uint16_t address, const char *resource_sour= ce); +Aml *aml_error_device(void); =20 /* Block AML object primitives */ Aml *aml_scope(const char *name_format, ...) G_GNUC_PRINTF(1, 2); diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/gener= ic_event_device.h index d2dac87b4a9f..1c18ac296fcb 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -101,6 +101,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) #define ACPI_GED_PWR_DOWN_EVT 0x2 #define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4 #define ACPI_GED_CPU_HOTPLUG_EVT 0x8 +#define ACPI_GED_ERROR_EVT 0x10 =20 typedef struct GEDState { MemoryRegion evt; --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 430A6214229 for ; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=af02+flU4SzNJ9qmN1adeEqjcKI/ASu2pSCDjC0Db+SVMc84Y0CpKcuTd1HmQmipiS9Jk+yFrVsSOKNuswVFnvIx91usGmeuvCLvOiMuIZmfIbvwd84KDDF+WsG85ogFTzY/N8rq8FfDHHv4xJ6g6LpDXm//99BHnV9L2VsrSA8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=DpBhi2NBE9okKNGNpHnpH+sR4750egcuqhpcUlVucEg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=byxFr6zA9gMVcvfMpKxwHe0u2b2wlZaaCcPN64sfHFyoT2ZzltwSy/bCnzFym/U9WT6hK1lq/1Fuhmyv8kVfK6S/ypuyCoUpN56dJtxN314UiXoSwfzvYzxcdGWr5sC/dT1DHLLNonmzG6ijoN1Z0f4m5V1NeoW4+bMRqS/YaJU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SDhR+R6H; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SDhR+R6H" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DFFAFC4CEE5; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560799; bh=DpBhi2NBE9okKNGNpHnpH+sR4750egcuqhpcUlVucEg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SDhR+R6HG2PV3nuXh/eSW5F46blAoy1ly2F/bhZ1XMgC/zE0IFHSdhT6O/EpUmsNA Xfjs2Wxc9zmMvLxVFbVhb7kC7cVplHsH4d5Hmjtd15/I1nQily3LT18oTU/RiIlowl 0hCqOT0iBLOIYRyviDrXoe9EtPQTW8vXUtxHC+WIa6qTywv3JprGVVWllCnWthVTs8 oKoCcTzjjMc/PCTkoLb1XEfoLkJyaGbaumAri/Yx7a8WVSU/jZxPvhmimEfjSLOOt3 4HHpe7YMOEoqwJh6//WNNXR0bApIthAiL0Xy51CKM9M2e4w8UNHpwLquq4TCJXKB/T 8diHnGDv9SUjg== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacw9-00000008ogo-4BK6; Wed, 22 Jan 2025 16:46:38 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , Peter Maydell , Shannon Zhao , linux-kernel@vger.kernel.org Subject: [PATCH 09/11] arm/virt: Wire up a GED error device for ACPI / GHES Date: Wed, 22 Jan 2025 16:46:26 +0100 Message-ID: X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Adds support to ARM virtualization to allow handling generic error ACPI Event via GED & error source device. It is aligned with Linux Kernel patch: https://lore.kernel.org/lkml/1272350481-27951-8-git-send-email-ying.huang@i= ntel.com/ Co-authored-by: Mauro Carvalho Chehab Co-authored-by: Jonathan Cameron Signed-off-by: Jonathan Cameron Signed-off-by: Mauro Carvalho Chehab Acked-by: Igor Mammedov --- Changes from v8: - Added a call to the function that produces GHES generic records, as this is now added earlier in this series. Signed-off-by: Mauro Carvalho Chehab --- hw/arm/virt-acpi-build.c | 1 + hw/arm/virt.c | 12 +++++++++++- include/hw/arm/virt.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index ada5d08cfbe7..ae60268bdcc2 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -861,6 +861,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, Virt= MachineState *vms) } =20 acpi_dsdt_add_power_button(scope); + aml_append(scope, aml_error_device()); #ifdef CONFIG_TPM acpi_dsdt_add_tpm(scope, vms); #endif diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 99e0a68b6c55..e272b35ea114 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -678,7 +678,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineS= tate *vms) DeviceState *dev; MachineState *ms =3D MACHINE(vms); int irq =3D vms->irqmap[VIRT_ACPI_GED]; - uint32_t event =3D ACPI_GED_PWR_DOWN_EVT; + uint32_t event =3D ACPI_GED_PWR_DOWN_EVT | ACPI_GED_ERROR_EVT; =20 if (ms->ram_slots) { event |=3D ACPI_GED_MEM_HOTPLUG_EVT; @@ -1010,6 +1010,13 @@ static void virt_powerdown_req(Notifier *n, void *op= aque) } } =20 +static void virt_generic_error_req(Notifier *n, void *opaque) +{ + VirtMachineState *s =3D container_of(n, VirtMachineState, generic_erro= r_notifier); + + acpi_send_event(s->acpi_dev, ACPI_GENERIC_ERROR); +} + static void create_gpio_keys(char *fdt, DeviceState *pl061_dev, uint32_t phandle) { @@ -2404,6 +2411,9 @@ static void machvirt_init(MachineState *machine) =20 if (has_ged && aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)= ) { vms->acpi_dev =3D create_acpi_ged(vms); + vms->generic_error_notifier.notify =3D virt_generic_error_req; + notifier_list_add(&acpi_generic_error_notifiers, + &vms->generic_error_notifier); } else { create_gpio_devices(vms, VIRT_GPIO, sysmem); } diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index c8e94e6aedc9..f3cf28436770 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -176,6 +176,7 @@ struct VirtMachineState { DeviceState *gic; DeviceState *acpi_dev; Notifier powerdown_notifier; + Notifier generic_error_notifier; PCIBus *bus; char *oem_id; char *oem_table_id; --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 446EB2144C9 for ; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=ReMVvmQwsOFqfkSRgZnOo0TI1ze/K/L7IsQ7lVH4oWcqXUKHh/EfmALM9h6pVJZDxh1gOabJLZv2fKD1rqiJO3JiIkLkkORyk0ZZT6y1f9KqGDHAN4ENpybt9DQ2cVTxSEspFR3O72lWv1x3uXbp/FP2i3nB/M/L0kG535XA1PY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=gNd/oien5ab4E+a/S+M7dtTjBLqG3TRj5B0MchMTDzs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=a3KuR6Odte+Xgsx60REwma6Cli8NhxqpadwecLD1gyESMKBH4bNxJdUCu8i+9cO+8q0TjtW13u7UpwHdsU7CYuVGrX/lMfDl5z9cx4cOjuXo4vtIHHClz7CJFwzKi4QQ6zx8vvvF0fntIGWkGgUwZwv3/+ah+h4v96j3kVk4Utc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qUHYT1h/; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qUHYT1h/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CBE71C4CED3; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560800; bh=gNd/oien5ab4E+a/S+M7dtTjBLqG3TRj5B0MchMTDzs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qUHYT1h/lO8bI1I3n444Mk5xsRWYWI8spgje0IA/kvf+AU6uS8O3JQwaKbK8kNACU A0MfF3IjTDUutGptDWHO4++z2hdzIQIubS5Jdg6BcdpMXM8tRS//HW2G0bYYx8d6WS opd/kcAXTQ5rYD2yMYlt2mh7g4/5/UQzxUC5SIIT9IzAWiXoLAehQXBBxrOQn8XHcs h4Ez2w6fYpWa4xjF2ZJ90vlHoTv8TdocfCpAPLB93ec583C4UA86909GsN7pjYDILm R3blRpMmolFCl4zD46L/laiFThcvOxgcem3LMCldmTF1E0Ge0z3GzOhaFYxw8GMtHw Zlh0+bzT1iRCg== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacwA-00000008ogs-06Jd; Wed, 22 Jan 2025 16:46:38 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Ani Sinha , Dongjiu Geng , Eric Blake , Markus Armbruster , Michael Roth , Paolo Bonzini , Peter Maydell , Shannon Zhao , linux-kernel@vger.kernel.org Subject: [PATCH 10/11] qapi/acpi-hest: add an interface to do generic CPER error injection Date: Wed, 22 Jan 2025 16:46:27 +0100 Message-ID: <769b68a3192cc921fec4c0e5e925552920fdbe71.1737560101.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Creates a QMP command to be used for generic ACPI APEI hardware error injection (HEST) via GHESv2, and add support for it for ARM guests. Error injection uses ACPI_HEST_SRC_ID_QMP source ID to be platform independent. This is mapped at arch virt bindings, depending on the types supported by QEMU and by the BIOS. So, on ARM, this is supported via ACPI_GHES_NOTIFY_GPIO notification type. This patch is co-authored: - original ghes logic to inject a simple ARM record by Shiju Jose; - generic logic to handle block addresses by Jonathan Cameron; - generic GHESv2 error inject by Mauro Carvalho Chehab; Co-authored-by: Jonathan Cameron Co-authored-by: Shiju Jose Co-authored-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose Signed-off-by: Mauro Carvalho Chehab --- Changes since v9: - ARM source IDs renamed to reflect SYNC/ASYNC; - command name changed to better reflect what it does; - some improvements at JSON documentation; - add a check for QMP source at the notification logic. Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 +++++++ hw/acpi/Kconfig | 5 +++++ hw/acpi/ghes.c | 2 +- hw/acpi/ghes_cper.c | 32 ++++++++++++++++++++++++++++++++ hw/acpi/ghes_cper_stub.c | 19 +++++++++++++++++++ hw/acpi/meson.build | 2 ++ hw/arm/virt-acpi-build.c | 1 + hw/arm/virt.c | 7 +++++++ include/hw/acpi/ghes.h | 1 + include/hw/arm/virt.h | 1 + qapi/acpi-hest.json | 35 +++++++++++++++++++++++++++++++++++ qapi/meson.build | 1 + qapi/qapi-schema.json | 1 + 13 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 hw/acpi/ghes_cper.c create mode 100644 hw/acpi/ghes_cper_stub.c create mode 100644 qapi/acpi-hest.json diff --git a/MAINTAINERS b/MAINTAINERS index 846b81e3ec03..8e1f662fa0e0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2075,6 +2075,13 @@ F: hw/acpi/ghes.c F: include/hw/acpi/ghes.h F: docs/specs/acpi_hest_ghes.rst =20 +ACPI/HEST/GHES/ARM processor CPER +R: Mauro Carvalho Chehab +S: Maintained +F: hw/arm/ghes_cper.c +F: hw/acpi/ghes_cper_stub.c +F: qapi/acpi-hest.json + ppc4xx L: qemu-ppc@nongnu.org S: Orphan diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 1d4e9f0845c0..daabbe6cd11e 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -51,6 +51,11 @@ config ACPI_APEI bool depends on ACPI =20 +config GHES_CPER + bool + depends on ACPI_APEI + default y + config ACPI_PCI bool depends on ACPI && PCI diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 5d29db3918dd..cf83c959b5ef 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -547,7 +547,7 @@ void ghes_record_cper_errors(const void *cper, size_t l= en, /* Write the generic error data entry into guest memory */ cpu_physical_memory_write(cper_addr, cper, len); =20 - notifier_list_notify(&acpi_generic_error_notifiers, NULL); + notifier_list_notify(&acpi_generic_error_notifiers, &source_id); } =20 int acpi_ghes_memory_errors(uint16_t source_id, uint64_t physical_address) diff --git a/hw/acpi/ghes_cper.c b/hw/acpi/ghes_cper.c new file mode 100644 index 000000000000..02c47b41b990 --- /dev/null +++ b/hw/acpi/ghes_cper.c @@ -0,0 +1,32 @@ +/* + * CPER payload parser for error injection + * + * Copyright(C) 2024 Huawei LTD. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "qemu/base64.h" +#include "qemu/error-report.h" +#include "qemu/uuid.h" +#include "qapi/qapi-commands-acpi-hest.h" +#include "hw/acpi/ghes.h" + +void qmp_inject_ghes_error(const char *qmp_cper, Error **errp) +{ + + uint8_t *cper; + size_t len; + + cper =3D qbase64_decode(qmp_cper, -1, &len, errp); + if (!cper) { + error_setg(errp, "missing GHES CPER payload"); + return; + } + + ghes_record_cper_errors(cper, len, ACPI_HEST_SRC_ID_QMP, errp); +} diff --git a/hw/acpi/ghes_cper_stub.c b/hw/acpi/ghes_cper_stub.c new file mode 100644 index 000000000000..8782e2c02fa8 --- /dev/null +++ b/hw/acpi/ghes_cper_stub.c @@ -0,0 +1,19 @@ +/* + * Stub interface for CPER payload parser for error injection + * + * Copyright(C) 2024 Huawei LTD. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-acpi-hest.h" +#include "hw/acpi/ghes.h" + +void qmp_inject_ghes_error(const char *cper, Error **errp) +{ + error_setg(errp, "GHES QMP error inject is not compiled in"); +} diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 73f02b96912b..56b5d1ec9691 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -34,4 +34,6 @@ endif system_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-bui= ld-stub.c', 'ghes-stub.c', 'acpi_interface.c')) system_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-= stub.c')) system_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss) +system_ss.add(when: 'CONFIG_GHES_CPER', if_true: files('ghes_cper.c')) +system_ss.add(when: 'CONFIG_GHES_CPER', if_false: files('ghes_cper_stub.c'= )) system_ss.add(files('acpi-qmp-cmds.c')) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index ae60268bdcc2..d094212ce584 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -896,6 +896,7 @@ static void acpi_align_size(GArray *blob, unsigned alig= n) =20 static const AcpiNotificationSourceId hest_ghes_notify[] =3D { { ACPI_HEST_SRC_ID_SYNC, ACPI_GHES_NOTIFY_SEA }, + { ACPI_HEST_SRC_ID_QMP, ACPI_GHES_NOTIFY_GPIO }, }; =20 static const AcpiNotificationSourceId hest_ghes_notify_9_2[] =3D { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index e272b35ea114..9074a540197d 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1012,6 +1012,13 @@ static void virt_powerdown_req(Notifier *n, void *op= aque) =20 static void virt_generic_error_req(Notifier *n, void *opaque) { + uint16_t *source_id =3D opaque; + + /* Currently, only QMP source ID is async */ + if (*source_id !=3D ACPI_HEST_SRC_ID_QMP) { + return; + } + VirtMachineState *s =3D container_of(n, VirtMachineState, generic_erro= r_notifier); =20 acpi_send_event(s->acpi_dev, ACPI_GENERIC_ERROR); diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 64fe2b5bea65..078d78666f91 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -72,6 +72,7 @@ typedef struct AcpiGhesState { */ enum AcpiGhesSourceID { ACPI_HEST_SRC_ID_SYNC, + ACPI_HEST_SRC_ID_QMP, /* Use it only for QMP injected errors */ }; =20 typedef struct AcpiNotificationSourceId { diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index f3cf28436770..56f270f61cf5 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -33,6 +33,7 @@ #include "exec/hwaddr.h" #include "qemu/notify.h" #include "hw/boards.h" +#include "hw/acpi/ghes.h" #include "hw/arm/boot.h" #include "hw/arm/bsa.h" #include "hw/block/flash.h" diff --git a/qapi/acpi-hest.json b/qapi/acpi-hest.json new file mode 100644 index 000000000000..d58fba485180 --- /dev/null +++ b/qapi/acpi-hest.json @@ -0,0 +1,35 @@ +# -*- Mode: Python -*- +# vim: filetype=3Dpython + +## +# =3D=3D GHESv2 CPER Error Injection +# +# Defined since ACPI Specification 6.1, +# section 18.3.2.8 Generic Hardware Error Source version 2. See: +# +# https://uefi.org/sites/default/files/resources/ACPI_6_1.pdf +## + + +## +# @inject-ghes-error: +# +# Inject an error with additional ACPI 6.1 GHESv2 error information +# +# @cper: contains a base64 encoded string with raw data for a single +# CPER record with Generic Error Status Block, Generic Error Data +# Entry and generic error data payload, as described at +# https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.= html#format +# +# Features: +# +# @unstable: This command is experimental. +# +# Since: 9.2 +## +{ 'command': 'inject-ghes-error', + 'data': { + 'cper': 'str' + }, + 'features': [ 'unstable' ] +} diff --git a/qapi/meson.build b/qapi/meson.build index e7bc54e5d047..35cea6147262 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -59,6 +59,7 @@ qapi_all_modules =3D [ if have_system qapi_all_modules +=3D [ 'acpi', + 'acpi-hest', 'audio', 'cryptodev', 'qdev', diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index b1581988e4eb..baf19ab73afe 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -75,6 +75,7 @@ { 'include': 'misc-target.json' } { 'include': 'audio.json' } { 'include': 'acpi.json' } +{ 'include': 'acpi-hest.json' } { 'include': 'pci.json' } { 'include': 'stats.json' } { 'include': 'virtio.json' } --=20 2.48.1 From nobody Thu Jan 23 03:13:07 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 68520214809 for ; Wed, 22 Jan 2025 15:46:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; cv=none; b=p296DOYAzBWacgdgEJdRREGX4bhSCClW9yp0tT6tCoMXCx+3aOBkGlRSVlVNzpkn6R2cyoQGscSz5uSxFizgPsXt9+xATOP8xHo3sF0EPG+dmT3PfltPNlTWSmD96lnxDnZtXmThjL5+DGcCBAsdu3mAptTfoMf060BJiRSygxY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737560800; c=relaxed/simple; bh=otv/z8G4MplMFSCTH5izmOgZ0qg4k6TUkVjywVoMlEw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sBNDSSnLJi51JFq+lWdD/63/g0h6EUDdFY2vm7gf8T1sZ7BKTeG9RHKQHmaNZM/U1yRXG0tWbBj05whESfCrRMO9Yyi8HJaZhGkRW/5niRExuKfE44zkKzZPqTMtGSj2oCTysFG3aIWk/cAivzl6bkAuAnjKIfPLBWq/gDYskPA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AGgGYn3l; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AGgGYn3l" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DA510C4AF0C; Wed, 22 Jan 2025 15:46:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1737560800; bh=otv/z8G4MplMFSCTH5izmOgZ0qg4k6TUkVjywVoMlEw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AGgGYn3lRElwrSSEiOPIcCUbtuqyv6vjtDmgAjI+KG1Z8eV8VYjWlo4fS/r1mXJZv 3q6+nqcPqEqe9FW/wMKI2TOJoO441GHmdNUOjB9ABYFjPDkz3Qch2Rmbv5yrOTvNd8 tAuVrBXTQMZhrWhnpD2UiC0vhH1qarBFasxowEa1+FTJInqrm8cspf3miveNLcUMMz 6cW6VN8CPVsPDlyMEjmuXrtxVj6hVzh6pdRo2G9AlVp90tkOhC+bRPlFHRexOvHqF+ oJTgsZGtlnvJyvm9tIVyfbI/DXx//IfPTsim5XTpGQi0KRp1JKL19XP38wkO17kF2r /fMJ1eEHQ+SnA== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tacwA-00000008ogw-0Dgk; Wed, 22 Jan 2025 16:46:38 +0100 From: Mauro Carvalho Chehab To: Igor Mammedov , "Michael S . Tsirkin" Cc: Jonathan Cameron , Shiju Jose , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Mauro Carvalho Chehab , Cleber Rosa , John Snow , linux-kernel@vger.kernel.org Subject: [PATCH 11/11] scripts/ghes_inject: add a script to generate GHES error inject Date: Wed, 22 Jan 2025 16:46:28 +0100 Message-ID: <8c1f7e8e85f98aae26811ab88f8a85a3a51ff1f9.1737560101.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Using the QMP GHESv2 API requires preparing a raw data array containing a CPER record. Add a helper script with subcommands to prepare such data. Currently, only ARM Processor error CPER record is supported. Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 3 + scripts/arm_processor_error.py | 377 ++++++++++++++++++ scripts/ghes_inject.py | 51 +++ scripts/qmp_helper.py | 702 +++++++++++++++++++++++++++++++++ 4 files changed, 1133 insertions(+) create mode 100644 scripts/arm_processor_error.py create mode 100755 scripts/ghes_inject.py create mode 100644 scripts/qmp_helper.py diff --git a/MAINTAINERS b/MAINTAINERS index 8e1f662fa0e0..99a9ba5c2ace 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2081,6 +2081,9 @@ S: Maintained F: hw/arm/ghes_cper.c F: hw/acpi/ghes_cper_stub.c F: qapi/acpi-hest.json +F: scripts/ghes_inject.py +F: scripts/arm_processor_error.py +F: scripts/qmp_helper.py =20 ppc4xx L: qemu-ppc@nongnu.org diff --git a/scripts/arm_processor_error.py b/scripts/arm_processor_error.py new file mode 100644 index 000000000000..62e0c5662232 --- /dev/null +++ b/scripts/arm_processor_error.py @@ -0,0 +1,377 @@ +#!/usr/bin/env python3 +# +# pylint: disable=3DC0301,C0114,R0903,R0912,R0913,R0914,R0915,W0511 +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2024 Mauro Carvalho Chehab + +# TODO: current implementation has dummy defaults. +# +# For a better implementation, a QMP addition/call is needed to +# retrieve some data for ARM Processor Error injection: +# +# - ARM registers: power_state, mpidr. + +import argparse +import re + +from qmp_helper import qmp, util, cper_guid + +class ArmProcessorEinj: + """ + Implements ARM Processor Error injection via GHES + """ + + DESC =3D """ + Generates an ARM processor error CPER, compatible with + UEFI 2.9A Errata. + """ + + ACPI_GHES_ARM_CPER_LENGTH =3D 40 + ACPI_GHES_ARM_CPER_PEI_LENGTH =3D 32 + + # Context types + CONTEXT_AARCH32_EL1 =3D 1 + CONTEXT_AARCH64_EL1 =3D 5 + CONTEXT_MISC_REG =3D 8 + + def __init__(self, subparsers): + """Initialize the error injection class and add subparser""" + + # Valid choice values + self.arm_valid_bits =3D { + "mpidr": util.bit(0), + "affinity": util.bit(1), + "running": util.bit(2), + "vendor": util.bit(3), + } + + self.pei_flags =3D { + "first": util.bit(0), + "last": util.bit(1), + "propagated": util.bit(2), + "overflow": util.bit(3), + } + + self.pei_error_types =3D { + "cache": util.bit(1), + "tlb": util.bit(2), + "bus": util.bit(3), + "micro-arch": util.bit(4), + } + + self.pei_valid_bits =3D { + "multiple-error": util.bit(0), + "flags": util.bit(1), + "error-info": util.bit(2), + "virt-addr": util.bit(3), + "phy-addr": util.bit(4), + } + + self.data =3D bytearray() + + parser =3D subparsers.add_parser("arm", description=3Dself.DESC) + + arm_valid_bits =3D ",".join(self.arm_valid_bits.keys()) + flags =3D ",".join(self.pei_flags.keys()) + error_types =3D ",".join(self.pei_error_types.keys()) + pei_valid_bits =3D ",".join(self.pei_valid_bits.keys()) + + # UEFI N.16 ARM Validation bits + g_arm =3D parser.add_argument_group("ARM processor") + g_arm.add_argument("--arm", "--arm-valid", + help=3Df"ARM valid bits: {arm_valid_bits}") + g_arm.add_argument("-a", "--affinity", "--level", "--affinity-lev= el", + type=3Dlambda x: int(x, 0), + help=3D"Affinity level (when multiple levels ap= ply)") + g_arm.add_argument("-l", "--mpidr", type=3Dlambda x: int(x, 0), + help=3D"Multiprocessor Affinity Register") + g_arm.add_argument("-i", "--midr", type=3Dlambda x: int(x, 0), + help=3D"Main ID Register") + g_arm.add_argument("-r", "--running", + action=3Dargparse.BooleanOptionalAction, + default=3DNone, + help=3D"Indicates if the processor is running o= r not") + g_arm.add_argument("--psci", "--psci-state", + type=3Dlambda x: int(x, 0), + help=3D"Power State Coordination Interface - PS= CI state") + + # TODO: Add vendor-specific support + + # UEFI N.17 bitmaps (type and flags) + g_pei =3D parser.add_argument_group("ARM Processor Error Info (PEI= )") + g_pei.add_argument("-t", "--type", nargs=3D"+", + help=3Df"one or more error types: {error_types}") + g_pei.add_argument("-f", "--flags", nargs=3D"*", + help=3Df"zero or more error flags: {flags}") + g_pei.add_argument("-V", "--pei-valid", "--error-valid", nargs=3D"= *", + help=3Df"zero or more PEI valid bits: {pei_valid_b= its}") + + # UEFI N.17 Integer values + g_pei.add_argument("-m", "--multiple-error", nargs=3D"+", + help=3D"Number of errors: 0: Single error, 1: Mult= iple errors, 2-65535: Error count if known") + g_pei.add_argument("-e", "--error-info", nargs=3D"+", + help=3D"Error information (UEFI 2.10 tables N.18 t= o N.20)") + g_pei.add_argument("-p", "--physical-address", nargs=3D"+", + help=3D"Physical address") + g_pei.add_argument("-v", "--virtual-address", nargs=3D"+", + help=3D"Virtual address") + + # UEFI N.21 Context + g_ctx =3D parser.add_argument_group("Processor Context") + g_ctx.add_argument("--ctx-type", "--context-type", nargs=3D"*", + help=3D"Type of the context (0=3DARM32 GPR, 5=3DAR= M64 EL1, other values supported)") + g_ctx.add_argument("--ctx-size", "--context-size", nargs=3D"*", + help=3D"Minimal size of the context") + g_ctx.add_argument("--ctx-array", "--context-array", nargs=3D"*", + help=3D"Comma-separated arrays for each context") + + # Vendor-specific data + g_vendor =3D parser.add_argument_group("Vendor-specific data") + g_vendor.add_argument("--vendor", "--vendor-specific", nargs=3D"+", + help=3D"Vendor-specific byte arrays of data") + + # Add arguments for Generic Error Data + qmp.argparse(parser) + + parser.set_defaults(func=3Dself.send_cper) + + def send_cper(self, args): + """Parse subcommand arguments and send a CPER via QMP""" + + qmp_cmd =3D qmp(args.host, args.port, args.debug) + + # Handle Generic Error Data arguments if any + qmp_cmd.set_args(args) + + is_cpu_type =3D re.compile(r"^([\w+]+\-)?arm\-cpu$") + cpus =3D qmp_cmd.search_qom("/machine/unattached/device", + "type", is_cpu_type) + + cper =3D {} + pei =3D {} + ctx =3D {} + vendor =3D {} + + arg =3D vars(args) + + # Handle global parameters + if args.arm: + arm_valid_init =3D False + cper["valid"] =3D util.get_choice(name=3D"valid", + value=3Dargs.arm, + choices=3Dself.arm_valid_bits, + suffixes=3D["-error", "-err"]) + else: + cper["valid"] =3D 0 + arm_valid_init =3D True + + if "running" in arg: + if args.running: + cper["running-state"] =3D util.bit(0) + else: + cper["running-state"] =3D 0 + else: + cper["running-state"] =3D 0 + + if arm_valid_init: + if args.affinity: + cper["valid"] |=3D self.arm_valid_bits["affinity"] + + if args.mpidr: + cper["valid"] |=3D self.arm_valid_bits["mpidr"] + + if "running-state" in cper: + cper["valid"] |=3D self.arm_valid_bits["running"] + + if args.psci: + cper["valid"] |=3D self.arm_valid_bits["running"] + + # Handle PEI + if not args.type: + args.type =3D ["cache-error"] + + util.get_mult_choices( + pei, + name=3D"valid", + values=3Dargs.pei_valid, + choices=3Dself.pei_valid_bits, + suffixes=3D["-valid", "--addr"], + ) + util.get_mult_choices( + pei, + name=3D"type", + values=3Dargs.type, + choices=3Dself.pei_error_types, + suffixes=3D["-error", "-err"], + ) + util.get_mult_choices( + pei, + name=3D"flags", + values=3Dargs.flags, + choices=3Dself.pei_flags, + suffixes=3D["-error", "-cap"], + ) + util.get_mult_int(pei, "error-info", args.error_info) + util.get_mult_int(pei, "multiple-error", args.multiple_error) + util.get_mult_int(pei, "phy-addr", args.physical_address) + util.get_mult_int(pei, "virt-addr", args.virtual_address) + + # Handle context + util.get_mult_int(ctx, "type", args.ctx_type, allow_zero=3DTrue) + util.get_mult_int(ctx, "minimal-size", args.ctx_size, allow_zero= =3DTrue) + util.get_mult_array(ctx, "register", args.ctx_array, allow_zero=3D= True) + + util.get_mult_array(vendor, "bytes", args.vendor, max_val=3D255) + + # Store PEI + pei_data =3D bytearray() + default_flags =3D self.pei_flags["first"] + default_flags |=3D self.pei_flags["last"] + + error_info_num =3D 0 + + for i, p in pei.items(): # pylint: disable=3DW0612 + error_info_num +=3D 1 + + # UEFI 2.10 doesn't define how to encode error information + # when multiple types are raised. So, provide a default only + # if a single type is there + if "error-info" not in p: + if p["type"] =3D=3D util.bit(1): + p["error-info"] =3D 0x0091000F + if p["type"] =3D=3D util.bit(2): + p["error-info"] =3D 0x0054007F + if p["type"] =3D=3D util.bit(3): + p["error-info"] =3D 0x80D6460FFF + if p["type"] =3D=3D util.bit(4): + p["error-info"] =3D 0x78DA03FF + + if "valid" not in p: + p["valid"] =3D 0 + if "multiple-error" in p: + p["valid"] |=3D self.pei_valid_bits["multiple-error"] + + if "flags" in p: + p["valid"] |=3D self.pei_valid_bits["flags"] + + if "error-info" in p: + p["valid"] |=3D self.pei_valid_bits["error-info"] + + if "phy-addr" in p: + p["valid"] |=3D self.pei_valid_bits["phy-addr"] + + if "virt-addr" in p: + p["valid"] |=3D self.pei_valid_bits["virt-addr"] + + # Version + util.data_add(pei_data, 0, 1) + + util.data_add(pei_data, + self.ACPI_GHES_ARM_CPER_PEI_LENGTH, 1) + + util.data_add(pei_data, p["valid"], 2) + util.data_add(pei_data, p["type"], 1) + util.data_add(pei_data, p.get("multiple-error", 1), 2) + util.data_add(pei_data, p.get("flags", default_flags), 1) + util.data_add(pei_data, p.get("error-info", 0), 8) + util.data_add(pei_data, p.get("virt-addr", 0xDEADBEEF), 8) + util.data_add(pei_data, p.get("phy-addr", 0xABBA0BAD), 8) + + # Store Context + ctx_data =3D bytearray() + context_info_num =3D 0 + + if ctx: + ret =3D qmp_cmd.send_cmd("query-target", may_open=3DTrue) + + default_ctx =3D self.CONTEXT_MISC_REG + + if "arch" in ret: + if ret["arch"] =3D=3D "aarch64": + default_ctx =3D self.CONTEXT_AARCH64_EL1 + elif ret["arch"] =3D=3D "arm": + default_ctx =3D self.CONTEXT_AARCH32_EL1 + + for k in sorted(ctx.keys()): + context_info_num +=3D 1 + + if "type" not in ctx[k]: + ctx[k]["type"] =3D default_ctx + + if "register" not in ctx[k]: + ctx[k]["register"] =3D [] + + reg_size =3D len(ctx[k]["register"]) + size =3D 0 + + if "minimal-size" in ctx: + size =3D ctx[k]["minimal-size"] + + size =3D max(size, reg_size) + + size =3D (size + 1) % 0xFFFE + + # Version + util.data_add(ctx_data, 0, 2) + + util.data_add(ctx_data, ctx[k]["type"], 2) + + util.data_add(ctx_data, 8 * size, 4) + + for r in ctx[k]["register"]: + util.data_add(ctx_data, r, 8) + + for i in range(reg_size, size): # pylint: disable=3DW0612 + util.data_add(ctx_data, 0, 8) + + # Vendor-specific bytes are not grouped + vendor_data =3D bytearray() + if vendor: + for k in sorted(vendor.keys()): + for b in vendor[k]["bytes"]: + util.data_add(vendor_data, b, 1) + + # Encode ARM Processor Error + data =3D bytearray() + + util.data_add(data, cper["valid"], 4) + + util.data_add(data, error_info_num, 2) + util.data_add(data, context_info_num, 2) + + # Calculate the length of the CPER data + cper_length =3D self.ACPI_GHES_ARM_CPER_LENGTH + cper_length +=3D len(pei_data) + cper_length +=3D len(vendor_data) + cper_length +=3D len(ctx_data) + util.data_add(data, cper_length, 4) + + util.data_add(data, arg.get("affinity-level", 0), 1) + + # Reserved + util.data_add(data, 0, 3) + + if "midr-el1" not in arg: + if cpus: + cmd_arg =3D { + 'path': cpus[0], + 'property': "midr" + } + ret =3D qmp_cmd.send_cmd("qom-get", cmd_arg, may_open=3DTr= ue) + if isinstance(ret, int): + arg["midr-el1"] =3D ret + + util.data_add(data, arg.get("mpidr-el1", 0), 8) + util.data_add(data, arg.get("midr-el1", 0), 8) + util.data_add(data, cper["running-state"], 4) + util.data_add(data, arg.get("psci-state", 0), 4) + + # Add PEI + data.extend(pei_data) + data.extend(ctx_data) + data.extend(vendor_data) + + self.data =3D data + + qmp_cmd.send_cper(cper_guid.CPER_PROC_ARM, self.data) diff --git a/scripts/ghes_inject.py b/scripts/ghes_inject.py new file mode 100755 index 000000000000..67cb6077bec8 --- /dev/null +++ b/scripts/ghes_inject.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2024 Mauro Carvalho Chehab + +""" +Handle ACPI GHESv2 error injection logic QEMU QMP interface. +""" + +import argparse +import sys + +from arm_processor_error import ArmProcessorEinj + +EINJ_DESC =3D """ +Handle ACPI GHESv2 error injection logic QEMU QMP interface. + +It allows using UEFI BIOS EINJ features to generate GHES records. + +It helps testing CPER and GHES drivers at the guest OS and how +userspace applications at the guest handle them. +""" + +def main(): + """Main program""" + + # Main parser - handle generic args like QEMU QMP TCP socket options + parser =3D argparse.ArgumentParser(formatter_class=3Dargparse.Argument= DefaultsHelpFormatter, + usage=3D"%(prog)s [options]", + description=3DEINJ_DESC) + + g_options =3D parser.add_argument_group("QEMU QMP socket options") + g_options.add_argument("-H", "--host", default=3D"localhost", type=3Ds= tr, + help=3D"host name") + g_options.add_argument("-P", "--port", default=3D4445, type=3Dint, + help=3D"TCP port number") + g_options.add_argument('-d', '--debug', action=3D'store_true') + + subparsers =3D parser.add_subparsers() + + ArmProcessorEinj(subparsers) + + args =3D parser.parse_args() + if "func" in args: + args.func(args) + else: + sys.exit(f"Please specify a valid command for {sys.argv[0]}") + +if __name__ =3D=3D "__main__": + main() diff --git a/scripts/qmp_helper.py b/scripts/qmp_helper.py new file mode 100644 index 000000000000..357ebc6e8359 --- /dev/null +++ b/scripts/qmp_helper.py @@ -0,0 +1,702 @@ +#!/usr/bin/env python3 +# +# # pylint: disable=3DC0103,E0213,E1135,E1136,E1137,R0902,R0903,R0912,R0913 +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2024 Mauro Carvalho Chehab + +""" +Helper classes to be used by ghes_inject command classes. +""" + +import json +import sys + +from datetime import datetime +from os import path as os_path + +try: + qemu_dir =3D os_path.abspath(os_path.dirname(os_path.dirname(__file__)= )) + sys.path.append(os_path.join(qemu_dir, 'python')) + + from qemu.qmp.legacy import QEMUMonitorProtocol + +except ModuleNotFoundError as exc: + print(f"Module '{exc.name}' not found.") + print("Try export PYTHONPATH=3Dtop-qemu-dir/python or run from top-qem= u-dir") + sys.exit(1) + +from base64 import b64encode + +class util: + """ + Ancillary functions to deal with bitmaps, parse arguments, + generate GUID and encode data on a bytearray buffer. + """ + + # + # Helper routines to handle multiple choice arguments + # + def get_choice(name, value, choices, suffixes=3DNone, bitmask=3DTrue): + """Produce a list from multiple choice argument""" + + new_values =3D 0 + + if not value: + return new_values + + for val in value.split(","): + val =3D val.lower() + + if suffixes: + for suffix in suffixes: + val =3D val.removesuffix(suffix) + + if val not in choices.keys(): + if suffixes: + for suffix in suffixes: + if val + suffix in choices.keys(): + val +=3D suffix + break + + if val not in choices.keys(): + sys.exit(f"Error on '{name}': choice '{val}' is invalid.") + + val =3D choices[val] + + if bitmask: + new_values |=3D val + else: + if new_values: + sys.exit(f"Error on '{name}': only one value is accept= ed.") + + new_values =3D val + + return new_values + + def get_array(name, values, max_val=3DNone): + """Add numbered hashes from integer lists into an array""" + + array =3D [] + + for value in values: + for val in value.split(","): + try: + val =3D int(val, 0) + except ValueError: + sys.exit(f"Error on '{name}': {val} is not an integer") + + if val < 0: + sys.exit(f"Error on '{name}': {val} is not unsigned") + + if max_val and val > max_val: + sys.exit(f"Error on '{name}': {val} is too little") + + array.append(val) + + return array + + def get_mult_array(mult, name, values, allow_zero=3DFalse, max_val=3DN= one): + """Add numbered hashes from integer lists""" + + if not allow_zero: + if not values: + return + else: + if values is None: + return + + if not values: + i =3D 0 + if i not in mult: + mult[i] =3D {} + + mult[i][name] =3D [] + return + + i =3D 0 + for value in values: + for val in value.split(","): + try: + val =3D int(val, 0) + except ValueError: + sys.exit(f"Error on '{name}': {val} is not an integer") + + if val < 0: + sys.exit(f"Error on '{name}': {val} is not unsigned") + + if max_val and val > max_val: + sys.exit(f"Error on '{name}': {val} is too little") + + if i not in mult: + mult[i] =3D {} + + if name not in mult[i]: + mult[i][name] =3D [] + + mult[i][name].append(val) + + i +=3D 1 + + + def get_mult_choices(mult, name, values, choices, + suffixes=3DNone, allow_zero=3DFalse): + """Add numbered hashes from multiple choice arguments""" + + if not allow_zero: + if not values: + return + else: + if values is None: + return + + i =3D 0 + for val in values: + new_values =3D util.get_choice(name, val, choices, suffixes) + + if i not in mult: + mult[i] =3D {} + + mult[i][name] =3D new_values + i +=3D 1 + + + def get_mult_int(mult, name, values, allow_zero=3DFalse): + """Add numbered hashes from integer arguments""" + if not allow_zero: + if not values: + return + else: + if values is None: + return + + i =3D 0 + for val in values: + try: + val =3D int(val, 0) + except ValueError: + sys.exit(f"Error on '{name}': {val} is not an integer") + + if val < 0: + sys.exit(f"Error on '{name}': {val} is not unsigned") + + if i not in mult: + mult[i] =3D {} + + mult[i][name] =3D val + i +=3D 1 + + + # + # Data encode helper functions + # + def bit(b): + """Simple macro to define a bit on a bitmask""" + return 1 << b + + + def data_add(data, value, num_bytes): + """Adds bytes from value inside a bitarray""" + + data.extend(value.to_bytes(num_bytes, byteorder=3D"little")) # py= lint: disable=3DE1101 + + def dump_bytearray(name, data): + """Does an hexdump of a byte array, grouping in bytes""" + + print(f"{name} ({len(data)} bytes):") + + for ln_start in range(0, len(data), 16): + ln_end =3D min(ln_start + 16, len(data)) + print(f" {ln_start:08x} ", end=3D"") + for i in range(ln_start, ln_end): + print(f"{data[i]:02x} ", end=3D"") + for i in range(ln_end, ln_start + 16): + print(" ", end=3D"") + print(" ", end=3D"") + for i in range(ln_start, ln_end): + if data[i] >=3D 32 and data[i] < 127: + print(chr(data[i]), end=3D"") + else: + print(".", end=3D"") + + print() + print() + + def time(string): + """Handle BCD timestamps used on Generic Error Data Block""" + + time =3D None + + # Formats to be used when parsing time stamps + formats =3D [ + "%Y-%m-%d %H:%M:%S", + ] + + if string =3D=3D "now": + time =3D datetime.now() + + if time is None: + for fmt in formats: + try: + time =3D datetime.strptime(string, fmt) + break + except ValueError: + pass + + if time is None: + raise ValueError("Invalid time format") + + return time + +class guid: + """ + Simple class to handle GUID fields. + """ + + def __init__(self, time_low, time_mid, time_high, nodes): + """Initialize a GUID value""" + + assert len(nodes) =3D=3D 8 + + self.time_low =3D time_low + self.time_mid =3D time_mid + self.time_high =3D time_high + self.nodes =3D nodes + + @classmethod + def UUID(cls, guid_str): + """Initialize a GUID using a string on its standard format""" + + if len(guid_str) !=3D 36: + print("Size not 36") + raise ValueError('Invalid GUID size') + + # It is easier to parse without separators. So, drop them + guid_str =3D guid_str.replace('-', '') + + if len(guid_str) !=3D 32: + print("Size not 32", guid_str, len(guid_str)) + raise ValueError('Invalid GUID hex size') + + time_low =3D 0 + time_mid =3D 0 + time_high =3D 0 + nodes =3D [] + + for i in reversed(range(16, 32, 2)): + h =3D guid_str[i:i + 2] + value =3D int(h, 16) + nodes.insert(0, value) + + time_high =3D int(guid_str[12:16], 16) + time_mid =3D int(guid_str[8:12], 16) + time_low =3D int(guid_str[0:8], 16) + + return cls(time_low, time_mid, time_high, nodes) + + def __str__(self): + """Output a GUID value on its default string representation""" + + clock =3D self.nodes[0] << 8 | self.nodes[1] + + node =3D 0 + for i in range(2, len(self.nodes)): + node =3D node << 8 | self.nodes[i] + + s =3D f"{self.time_low:08x}-{self.time_mid:04x}-" + s +=3D f"{self.time_high:04x}-{clock:04x}-{node:012x}" + return s + + def to_bytes(self): + """Output a GUID value in bytes""" + + data =3D bytearray() + + util.data_add(data, self.time_low, 4) + util.data_add(data, self.time_mid, 2) + util.data_add(data, self.time_high, 2) + data.extend(bytearray(self.nodes)) + + return data + +class qmp: + """ + Opens a connection and send/receive QMP commands. + """ + + def send_cmd(self, command, args=3DNone, may_open=3DFalse, return_erro= r=3DTrue): + """Send a command to QMP, optinally opening a connection""" + + if may_open: + self._connect() + elif not self.connected: + return False + + msg =3D { 'execute': command } + if args: + msg['arguments'] =3D args + + try: + obj =3D self.qmp_monitor.cmd_obj(msg) + # Can we use some other exception class here? + except Exception as e: # pylint: disable= =3DW0718 + print(f"Command: {command}") + print(f"Failed to inject error: {e}.") + return None + + if "return" in obj: + if isinstance(obj.get("return"), dict): + if obj["return"]: + return obj["return"] + return "OK" + + return obj["return"] + + if isinstance(obj.get("error"), dict): + error =3D obj["error"] + if return_error: + print(f"Command: {msg}") + print(f'{error["class"]}: {error["desc"]}') + else: + print(json.dumps(obj)) + + return None + + def _close(self): + """Shutdown and close the socket, if opened""" + if not self.connected: + return + + self.qmp_monitor.close() + self.connected =3D False + + def _connect(self): + """Connect to a QMP TCP/IP port, if not connected yet""" + + if self.connected: + return True + + try: + self.qmp_monitor.connect(negotiate=3DTrue) + except ConnectionError: + sys.exit(f"Can't connect to QMP host {self.host}:{self.port}") + + self.connected =3D True + + return True + + BLOCK_STATUS_BITS =3D { + "uncorrectable": util.bit(0), + "correctable": util.bit(1), + "multi-uncorrectable": util.bit(2), + "multi-correctable": util.bit(3), + } + + ERROR_SEVERITY =3D { + "recoverable": 0, + "fatal": 1, + "corrected": 2, + "none": 3, + } + + VALIDATION_BITS =3D { + "fru-id": util.bit(0), + "fru-text": util.bit(1), + "timestamp": util.bit(2), + } + + GEDB_FLAGS_BITS =3D { + "recovered": util.bit(0), + "prev-error": util.bit(1), + "simulated": util.bit(2), + } + + GENERIC_DATA_SIZE =3D 72 + + def argparse(parser): + """Prepare a parser group to query generic error data""" + + block_status_bits =3D ",".join(qmp.BLOCK_STATUS_BITS.keys()) + error_severity_enum =3D ",".join(qmp.ERROR_SEVERITY.keys()) + validation_bits =3D ",".join(qmp.VALIDATION_BITS.keys()) + gedb_flags_bits =3D ",".join(qmp.GEDB_FLAGS_BITS.keys()) + + g_gen =3D parser.add_argument_group("Generic Error Data") # pylin= t: disable=3DE1101 + g_gen.add_argument("--block-status", + help=3Df"block status bits: {block_status_bits}= ") + g_gen.add_argument("--raw-data", nargs=3D"+", + help=3D"Raw data inside the Error Status Block") + g_gen.add_argument("--error-severity", "--severity", + help=3Df"error severity: {error_severity_enum}") + g_gen.add_argument("--gen-err-valid-bits", + "--generic-error-validation-bits", + help=3Df"validation bits: {validation_bits}") + g_gen.add_argument("--fru-id", type=3Dguid.UUID, + help=3D"GUID representing a physical device") + g_gen.add_argument("--fru-text", + help=3D"ASCII string identifying the FRU hardwa= re") + g_gen.add_argument("--timestamp", type=3Dutil.time, + help=3D"Time when the error info was collected") + g_gen.add_argument("--precise", "--precise-timestamp", + action=3D'store_true', + help=3D"Marks the timestamp as precise if --tim= estamp is used") + g_gen.add_argument("--gedb-flags", + help=3Df"General Error Data Block flags: {gedb_= flags_bits}") + + def set_args(self, args): + """Set the arguments optionally defined via self.argparse()""" + + if args.block_status: + self.block_status =3D util.get_choice(name=3D"block-status", + value=3Dargs.block_status, + choices=3Dself.BLOCK_STATU= S_BITS, + bitmask=3DFalse) + if args.raw_data: + self.raw_data =3D util.get_array("raw-data", args.raw_data, + max_val=3D255) + print(self.raw_data) + + if args.error_severity: + self.error_severity =3D util.get_choice(name=3D"error-severity= ", + value=3Dargs.error_sever= ity, + choices=3Dself.ERROR_SEV= ERITY, + bitmask=3DFalse) + + if args.fru_id: + self.fru_id =3D args.fru_id.to_bytes() + if not args.gen_err_valid_bits: + self.validation_bits |=3D self.VALIDATION_BITS["fru-id"] + + if args.fru_text: + text =3D bytearray(args.fru_text.encode('ascii')) + if len(text) > 20: + sys.exit("FRU text is too big to fit") + + self.fru_text =3D text + if not args.gen_err_valid_bits: + self.validation_bits |=3D self.VALIDATION_BITS["fru-text"] + + if args.timestamp: + time =3D args.timestamp + century =3D int(time.year / 100) + + bcd =3D bytearray() + util.data_add(bcd, (time.second // 10) << 4 | (time.second % 1= 0), 1) + util.data_add(bcd, (time.minute // 10) << 4 | (time.minute % 1= 0), 1) + util.data_add(bcd, (time.hour // 10) << 4 | (time.hour % 10), = 1) + + if args.precise: + util.data_add(bcd, 1, 1) + else: + util.data_add(bcd, 0, 1) + + util.data_add(bcd, (time.day // 10) << 4 | (time.day % 10), 1) + util.data_add(bcd, (time.month // 10) << 4 | (time.month % 10)= , 1) + util.data_add(bcd, + ((time.year % 100) // 10) << 4 | (time.year % 10= ), 1) + util.data_add(bcd, ((century % 100) // 10) << 4 | (century % 1= 0), 1) + + self.timestamp =3D bcd + if not args.gen_err_valid_bits: + self.validation_bits |=3D self.VALIDATION_BITS["timestamp"] + + if args.gen_err_valid_bits: + self.validation_bits =3D util.get_choice(name=3D"validation", + value=3Dargs.gen_err_va= lid_bits, + choices=3Dself.VALIDATI= ON_BITS) + + def __init__(self, host, port, debug=3DFalse): + """Initialize variables used by the QMP send logic""" + + self.connected =3D False + self.host =3D host + self.port =3D port + self.debug =3D debug + + # ACPI 6.1: 18.3.2.7.1 Generic Error Data: Generic Error Status Bl= ock + self.block_status =3D self.BLOCK_STATUS_BITS["uncorrectable"] + self.raw_data =3D [] + self.error_severity =3D self.ERROR_SEVERITY["recoverable"] + + # ACPI 6.1: 18.3.2.7.1 Generic Error Data: Generic Error Data Entry + self.validation_bits =3D 0 + self.flags =3D 0 + self.fru_id =3D bytearray(16) + self.fru_text =3D bytearray(20) + self.timestamp =3D bytearray(8) + + self.qmp_monitor =3D QEMUMonitorProtocol(address=3D(self.host, sel= f.port)) + + # + # Socket QMP send command + # + def send_cper_raw(self, cper_data): + """Send a raw CPER data to QEMU though QMP TCP socket""" + + data =3D b64encode(bytes(cper_data)).decode('ascii') + + cmd_arg =3D { + 'cper': data + } + + self._connect() + + if self.send_cmd("inject-ghes-error", cmd_arg): + print("Error injected.") + + def send_cper(self, notif_type, payload): + """Send commands to QEMU though QMP TCP socket""" + + # Fill CPER record header + + # NOTE: bits 4 to 13 of block status contain the number of + # data entries in the data section. This is currently unsupported. + + cper_length =3D len(payload) + data_length =3D cper_length + len(self.raw_data) + self.GENERIC_DA= TA_SIZE + + # Generic Error Data Entry + gede =3D bytearray() + + gede.extend(notif_type.to_bytes()) + util.data_add(gede, self.error_severity, 4) + util.data_add(gede, 0x300, 2) + util.data_add(gede, self.validation_bits, 1) + util.data_add(gede, self.flags, 1) + util.data_add(gede, cper_length, 4) + gede.extend(self.fru_id) + gede.extend(self.fru_text) + gede.extend(self.timestamp) + + # Generic Error Status Block + gebs =3D bytearray() + + if self.raw_data: + raw_data_offset =3D len(gebs) + else: + raw_data_offset =3D 0 + + util.data_add(gebs, self.block_status, 4) + util.data_add(gebs, raw_data_offset, 4) + util.data_add(gebs, len(self.raw_data), 4) + util.data_add(gebs, data_length, 4) + util.data_add(gebs, self.error_severity, 4) + + cper_data =3D bytearray() + cper_data.extend(gebs) + cper_data.extend(gede) + cper_data.extend(bytearray(self.raw_data)) + cper_data.extend(bytearray(payload)) + + if self.debug: + print(f"GUID: {notif_type}") + + util.dump_bytearray("Generic Error Status Block", gebs) + util.dump_bytearray("Generic Error Data Entry", gede) + + if self.raw_data: + util.dump_bytearray("Raw data", bytearray(self.raw_data)) + + util.dump_bytearray("Payload", payload) + + self.send_cper_raw(cper_data) + + + def search_qom(self, path, prop, regex): + """ + Return a list of devices that match path array like: + + /machine/unattached/device + /machine/peripheral-anon/device + ... + """ + + found =3D [] + + i =3D 0 + while 1: + dev =3D f"{path}[{i}]" + args =3D { + 'path': dev, + 'property': prop + } + ret =3D self.send_cmd("qom-get", args, may_open=3DTrue, return= _error=3DFalse) + if not ret: + break + + if isinstance(ret, str): + if regex.search(ret): + found.append(dev) + + i +=3D 1 + if i > 10000: + print("Too many objects returned by qom-get!") + break + + return found + +class cper_guid: + """ + Contains CPER GUID, as per: + https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.ht= ml + """ + + CPER_PROC_GENERIC =3D guid(0x9876CCAD, 0x47B4, 0x4bdb, + [0xB6, 0x5E, 0x16, 0xF1, + 0x93, 0xC4, 0xF3, 0xDB]) + + CPER_PROC_X86 =3D guid(0xDC3EA0B0, 0xA144, 0x4797, + [0xB9, 0x5B, 0x53, 0xFA, + 0x24, 0x2B, 0x6E, 0x1D]) + + CPER_PROC_ITANIUM =3D guid(0xe429faf1, 0x3cb7, 0x11d4, + [0xbc, 0xa7, 0x00, 0x80, + 0xc7, 0x3c, 0x88, 0x81]) + + CPER_PROC_ARM =3D guid(0xE19E3D16, 0xBC11, 0x11E4, + [0x9C, 0xAA, 0xC2, 0x05, + 0x1D, 0x5D, 0x46, 0xB0]) + + CPER_PLATFORM_MEM =3D guid(0xA5BC1114, 0x6F64, 0x4EDE, + [0xB8, 0x63, 0x3E, 0x83, + 0xED, 0x7C, 0x83, 0xB1]) + + CPER_PLATFORM_MEM2 =3D guid(0x61EC04FC, 0x48E6, 0xD813, + [0x25, 0xC9, 0x8D, 0xAA, + 0x44, 0x75, 0x0B, 0x12]) + + CPER_PCIE =3D guid(0xD995E954, 0xBBC1, 0x430F, + [0xAD, 0x91, 0xB4, 0x4D, + 0xCB, 0x3C, 0x6F, 0x35]) + + CPER_PCI_BUS =3D guid(0xC5753963, 0x3B84, 0x4095, + [0xBF, 0x78, 0xED, 0xDA, + 0xD3, 0xF9, 0xC9, 0xDD]) + + CPER_PCI_DEV =3D guid(0xEB5E4685, 0xCA66, 0x4769, + [0xB6, 0xA2, 0x26, 0x06, + 0x8B, 0x00, 0x13, 0x26]) + + CPER_FW_ERROR =3D guid(0x81212A96, 0x09ED, 0x4996, + [0x94, 0x71, 0x8D, 0x72, + 0x9C, 0x8E, 0x69, 0xED]) + + CPER_DMA_GENERIC =3D guid(0x5B51FEF7, 0xC79D, 0x4434, + [0x8F, 0x1B, 0xAA, 0x62, + 0xDE, 0x3E, 0x2C, 0x64]) + + CPER_DMA_VT =3D guid(0x71761D37, 0x32B2, 0x45cd, + [0xA7, 0xD0, 0xB0, 0xFE, + 0xDD, 0x93, 0xE8, 0xCF]) + + CPER_DMA_IOMMU =3D guid(0x036F84E1, 0x7F37, 0x428c, + [0xA7, 0x9E, 0x57, 0x5F, + 0xDF, 0xAA, 0x84, 0xEC]) + + CPER_CCIX_PER =3D guid(0x91335EF6, 0xEBFB, 0x4478, + [0xA6, 0xA6, 0x88, 0xB7, + 0x28, 0xCF, 0x75, 0xD7]) + + CPER_CXL_PROT_ERR =3D guid(0x80B9EFB4, 0x52B5, 0x4DE3, + [0xA7, 0x77, 0x68, 0x78, + 0x4B, 0x77, 0x10, 0x48]) --=20 2.48.1