From patchwork Fri Jan 31 17:42:44 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 13955618 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EDF21C02190 for ; Fri, 31 Jan 2025 17:45:38 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tdv3A-0006D4-K2; Fri, 31 Jan 2025 12:43:28 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tdv30-000634-Dk; Fri, 31 Jan 2025 12:43:18 -0500 Received: from nyc.source.kernel.org ([147.75.193.91]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tdv2y-0001nv-M8; Fri, 31 Jan 2025 12:43:18 -0500 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by nyc.source.kernel.org (Postfix) with ESMTP id D5657A420CE; Fri, 31 Jan 2025 17:41:23 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 821A4C4AF0B; Fri, 31 Jan 2025 17:43:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1738345389; bh=YOL6utPDO8TD57N2VE3doKniv0buHMPim3e1kyhvnTA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VwHhHuOoV9XI9fFe1lS1FA/bPhsIw6qYPO4gPc90TyIPBvadXWj+Vc7FQ3Tjqr+ff ArSuyQskILryaQIw0PsviOJONRscJOPR8POsqx8voaOds4wuojMlb1rlFfo6RbDgwE Tdeol0BCqVFsWkhCPr0gM+7sGdE+WyVdp/8K6CJBmf0SBio+BOmhgYqidXS5mVF79T Y9xRxz+QAyQ5ilcyNIB6XKv1OUcVVcqhiSMuW7RDVqZBWDuTIvIoGQismPE8H3vsQ3 Bh76mD5VqZWXp5j6kGWyT8IwfpGWDwe3mAs72qXQhczIQPNoiuoOhxQZ3KYAhVuvWB LyejhoFFOLBVA== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1tdv2p-00000006ggq-0IyC; Fri, 31 Jan 2025 18:43:07 +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 v3 03/14] acpi/ghes: Use HEST table offsets when preparing GHES records Date: Fri, 31 Jan 2025 18:42:44 +0100 Message-ID: <9610ff88cf6fdc59cbfc8871d653fd890391be1e.1738345063.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.48.1 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=147.75.193.91; envelope-from=mchehab+huawei@kernel.org; helo=nyc.source.kernel.org X-Spam_score_int: -56 X-Spam_score: -5.7 X-Spam_bar: ----- X-Spam_report: (-5.7 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.3, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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. 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 | 132 ++++++++++++++++++++++++++++++++++++----- include/hw/acpi/ghes.h | 1 + 2 files changed, 119 insertions(+), 14 deletions(-) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 27478f2d5674..8f284fd191a6 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -41,6 +41,12 @@ /* Address offset in Generic Address Structure(GAS) */ #define GAS_ADDR_OFFSET 4 +/* + * ACPI spec 1.0b + * 5.2.3 System Description Table Header + */ +#define ACPI_DESC_HEADER_OFFSET 36 + /* * The total size of Generic Error Data Entry * ACPI 6.1/6.2: 18.3.2.7.1 Generic Error Data, @@ -61,6 +67,25 @@ */ #define ACPI_GHES_GESB_SIZE 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_READ_ACK_ADDR_OFF 64 + +/* + * ACPI 6.2: 18.3.2.7: Generic Hardware Error Source + * Table 18-380: 'Error Status Address' field + */ +#define GHES_ERR_STATUS_ADDR_OFF 20 + /* * Values for error_severity field */ @@ -212,14 +237,6 @@ static void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker, { int i, error_status_block_offset; - /* - * TODO: Current version supports only one source. - * A further patch will drop this check, after adding a proper migration - * code, as, for the code to work, we need to store a bios pointer to the - * HEST table. - */ - assert(num_sources == 1); - /* Build error_block_address */ for (i = 0; i < num_sources; i++) { build_append_int_noprefix(hardware_errors, 0, sizeof(uint64_t)); @@ -352,6 +369,14 @@ void acpi_build_hest(GArray *table_data, GArray *hardware_errors, .oem_id = oem_id, .oem_table_id = oem_table_id }; uint32_t hest_offset; int i; + AcpiGedState *acpi_ged_state; + AcpiGhesState *ags = NULL; + + acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, + NULL)); + if (acpi_ged_state) { + ags = &acpi_ged_state->ghes_state; + } hest_offset = table_data->len; @@ -371,10 +396,12 @@ void acpi_build_hest(GArray *table_data, GArray *hardware_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); + if (ags->use_hest_addr) { + bios_linker_loader_write_pointer(linker, + ACPI_HEST_ADDR_FW_CFG_FILE, 0, + sizeof(uint64_t), + ACPI_BUILD_TABLE_FILE, hest_offset); + } } void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s, @@ -420,6 +447,78 @@ static void get_hw_error_offsets(uint64_t ghes_addr, *read_ack_register_addr = ghes_addr + sizeof(uint64_t); } +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_entry, error_block_addr; + uint32_t num_sources, i; + + hest_addr += ACPI_DESC_HEADER_OFFSET; + + cpu_physical_memory_read(hest_addr, &num_sources, + sizeof(num_sources)); + num_sources = le32_to_cpu(num_sources); + + err_source_entry = hest_addr + sizeof(num_sources); + + /* + * Currently, HEST Error source navigates only for GHESv2 tables + */ + + for (i = 0; i < num_sources; i++) { + uint64_t addr = err_source_entry; + uint16_t type, src_id; + + cpu_physical_memory_read(addr, &type, sizeof(type)); + type = le16_to_cpu(type); + + /* For now, we only know the size of GHESv2 table */ + if (type != 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 += sizeof(type); + cpu_physical_memory_read(addr, &src_id, sizeof(src_id)); + if (le16_to_cpu(src_id) == source_id) { + break; + } + + err_source_entry += HEST_GHES_V2_TABLE_SIZE; + } + if (i == num_sources) { + error_setg(errp, "HEST: Source %d not found.", source_id); + return; + } + + /* Navigate though table address pointers */ + hest_err_block_addr = err_source_entry + GHES_ERR_STATUS_ADDR_OFF + + GAS_ADDR_OFFSET; + + cpu_physical_memory_read(hest_err_block_addr, &error_block_addr, + sizeof(error_block_addr)); + + error_block_addr = le64_to_cpu(error_block_addr); + + cpu_physical_memory_read(error_block_addr, cper_addr, + sizeof(*cper_addr)); + + *cper_addr = le64_to_cpu(*cper_addr); + + hest_read_ack_addr = err_source_entry + GHES_READ_ACK_ADDR_OFF + + GAS_ADDR_OFFSET; + + cpu_physical_memory_read(hest_read_ack_addr, read_ack_start_addr, + sizeof(*read_ack_start_addr)); + + *read_ack_start_addr = le64_to_cpu(*read_ack_start_addr); +} + void ghes_record_cper_errors(const void *cper, size_t len, uint16_t source_id, Error **errp) { @@ -440,8 +539,13 @@ void ghes_record_cper_errors(const void *cper, size_t len, } ags = &acpi_ged_state->ghes_state; - 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); + } if (!cper_addr) { error_setg(errp, "can not find Generic Error Status Block"); diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 237721fec0a2..6c2e57af0456 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 use_hest_addr; /* True if HEST address is present */ } AcpiGhesState; /*