From patchwork Sun Aug 29 12:18:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Demi Marie Obenour X-Patchwork-Id: 12463881 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.9 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CC3B8C432BE for ; Sun, 29 Aug 2021 12:19:40 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7477A608FE for ; Sun, 29 Aug 2021 12:19:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 7477A608FE Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=invisiblethingslab.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=lists.xenproject.org Received: from list by lists.xenproject.org with outflank-mailman.174668.318455 (Exim 4.92) (envelope-from ) id 1mKJmW-0000t2-2L; Sun, 29 Aug 2021 12:19:24 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 174668.318455; Sun, 29 Aug 2021 12:19:24 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mKJmV-0000sv-VM; Sun, 29 Aug 2021 12:19:23 +0000 Received: by outflank-mailman (input) for mailman id 174668; Sun, 29 Aug 2021 12:19:22 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1mKJmU-0000sp-Ha for xen-devel@lists.xenproject.org; Sun, 29 Aug 2021 12:19:22 +0000 Received: from wout2-smtp.messagingengine.com (unknown [64.147.123.25]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id ffd4ce76-1eaa-47fd-9b43-cfdd3315ec41; Sun, 29 Aug 2021 12:19:21 +0000 (UTC) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 2904C320082A; Sun, 29 Aug 2021 08:19:19 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Sun, 29 Aug 2021 08:19:19 -0400 Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 29 Aug 2021 08:19:14 -0400 (EDT) X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: ffd4ce76-1eaa-47fd-9b43-cfdd3315ec41 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:message-id :mime-version:subject:to:x-me-proxy:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; bh=2EOZI1kciWaygQyMETTjlMRivpvez UzmahsFnp7e2/w=; b=fU2bs+fu0/CZZW6Z/2JrWvCcn6qiOhBJq1/TpuzNg/9fW +EPMmAVg71nM7nJUxSujz/HoECjed4SYlTPXt5VHv+N0BnTdMCLRDQhqsRHX7lQO ENZ8L6jperWUBgzgXO1fR89pWGmyV3nE/5Ggz+hpv7Wq9GCpXfK2c8lXQU19rBga 7Qh8GcLybj7YA8J8GNeFK7COY9kiwCnGIhF9RJK8zJonmL9FJyPyB3lyatyByzp7 gkT6apyaNuOHaqcje2WelRfkzqRGDuQuDqr0ub5eTOxkJnaxUgpn6m7ZzVTP1xwS MLn7psTqN3pNEclw/20KsYu5ySzGrcMSkn6yURd1Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddruddujedggeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfggtggusehgtderredttddunecuhfhrohhmpeffvghmihcuofgr rhhivgcuqfgsvghnohhurhcuoeguvghmihesihhnvhhishhisghlvghthhhinhhgshhlrg gsrdgtohhmqeenucggtffrrghtthgvrhhnpeeuveeguefgvdeiueejfedugeevleefteek udefheetuddvtdduvefggfeghedtffenucffohhmrghinhepkhgvrhhnvghlrdhorhhgne cuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepuggvmhhi sehinhhvihhsihgslhgvthhhihhnghhslhgrsgdrtghomh X-ME-Proxy: Date: Sun, 29 Aug 2021 08:18:57 -0400 From: Demi Marie Obenour To: xen-devel@lists.xenproject.org Cc: Stefano Stabellini , Julien Grall , Volodymyr Babchuk , Andrew Cooper , George Dunlap , Ian Jackson , Jan Beulich , Wei Liu , Roger Pau =?iso-8859-1?q?Monn=E9?= Subject: [PATCH] Grab the EFI System Reference Table and check it Message-ID: MIME-Version: 1.0 Content-Disposition: inline The EFI System Reference Table (ESRT) is necessary for fwupd to identify firmware updates to install. According to the UEFI specification ยง23.4, the table shall be stored in memory of type EfiBootServicesData. Therefore, Xen must avoid reusing that memory for other purposes, so that Linux can access the ESRT. See https://lore.kernel.org/xen-devel/20200818184018.GN1679@mail-itl/T/ for details. Signed-off-by: Demi Marie Obenour --- xen/arch/arm/efi/efi-boot.h | 9 ++-- xen/arch/x86/efi/efi-boot.h | 5 ++- xen/common/efi/boot.c | 90 +++++++++++++++++++++++++++++++++++-- xen/common/efi/runtime.c | 1 + xen/include/efi/efiapi.h | 3 ++ xen/include/xen/efi.h | 1 + 6 files changed, 101 insertions(+), 8 deletions(-) diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h index cf9c37153f..d8de478022 100644 --- a/xen/arch/arm/efi/efi-boot.h +++ b/xen/arch/arm/efi/efi-boot.h @@ -142,7 +142,8 @@ static bool __init meminfo_add_bank(struct meminfo *mem, static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *map, UINTN mmap_size, - UINTN desc_size) + UINTN desc_size, + const EFI_MEMORY_DESCRIPTOR *const esrt_desc) { int Index; EFI_MEMORY_DESCRIPTOR *desc_ptr = map; @@ -154,6 +155,7 @@ static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR * desc_ptr->Type == EfiLoaderCode || desc_ptr->Type == EfiLoaderData || (!map_bs && + desc != esrt_desc && (desc_ptr->Type == EfiBootServicesCode || desc_ptr->Type == EfiBootServicesData))) ) { @@ -359,11 +361,12 @@ static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable, void *map, UINTN map_size, UINTN desc_size, - UINT32 desc_ver) + UINT32 desc_ver, + const EFI_MEMORY_DESCRIPTOR *const esrt_desc) { EFI_STATUS status; - status = efi_process_memory_map_bootinfo(map, map_size, desc_size); + status = efi_process_memory_map_bootinfo(map, map_size, desc_size, esrt_desc); if ( EFI_ERROR(status) ) blexit(L"EFI memory map processing failed"); diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index fb217031ff..f381855368 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -154,7 +154,8 @@ static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable, void *map, UINTN map_size, UINTN desc_size, - UINT32 desc_ver) + UINT32 desc_ver, + const EFI_MEMORY_DESCRIPTOR *const esrt_desc) { struct e820entry *e; unsigned int i; @@ -171,7 +172,7 @@ static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable, { case EfiBootServicesCode: case EfiBootServicesData: - if ( map_bs ) + if ( map_bs || desc == esrt_desc ) { default: type = E820_RESERVED; diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 758f9d74d2..0603172074 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -93,6 +93,23 @@ typedef struct _EFI_LOAD_OPTION { CHAR16 Description[]; } EFI_LOAD_OPTION; +struct esrt_entry { + EFI_GUID fw_class; + uint32_t fw_type; + uint32_t fw_version; + uint32_t fw_lowest_supported_version; + uint32_t fw_capsule_flags; + uint32_t fw_last_attempt_version; + uint32_t fw_last_attempt_status; +}; + +struct esrt { + uint32_t esrt_count; + uint32_t esrt_max; + uint64_t esrt_version; + struct esrt_entry esrt_entries[]; +}; + #define LOAD_OPTION_ACTIVE 0x00000001 union string { @@ -166,6 +183,41 @@ static void __init PrintErr(const CHAR16 *s) StdErr->OutputString(StdErr, (CHAR16 *)s ); } +enum esrt_status { + ESRT_NOTFOUND = 0, + ESRT_GOOD, + ESRT_BAD, +}; + +static enum esrt_status __init is_esrt_valid( + const EFI_MEMORY_DESCRIPTOR *const desc) { + size_t available_len, esrt_len, len; + const uintptr_t physical_start = desc->PhysicalStart; + const uintptr_t esrt = efi.esrt; + const struct esrt *esrt_ptr; + + len = desc->NumberOfPages << EFI_PAGE_SHIFT; + if ( esrt == EFI_INVALID_TABLE_ADDR ) + return ESRT_BAD; + if ( physical_start > esrt || esrt - physical_start >= len ) + return ESRT_NOTFOUND; + if ( ! ( desc->Attribute & EFI_MEMORY_RUNTIME ) && + ( desc->Type != EfiRuntimeServicesData ) && + ( desc->Type != EfiBootServicesData ) ) + return ESRT_BAD; + available_len = len - (esrt - physical_start); + if ( available_len < offsetof(struct esrt, esrt_entries) ) + return ESRT_BAD; + esrt_ptr = (const struct esrt *) esrt; + if ( esrt_ptr->esrt_count <= 0 || + __builtin_mul_overflow(esrt_ptr->esrt_count, + sizeof(struct esrt_entry), + &esrt_len) || + esrt_len > available_len - offsetof(struct esrt, esrt_entries) ) + return ESRT_BAD; + return ESRT_GOOD; +} + /* * Include architecture specific implementation here, which references the * static globals defined above. @@ -835,6 +887,10 @@ static void __init efi_tables(void) { unsigned int i; + BUILD_BUG_ON(sizeof(struct esrt_entry) != 40); + BUILD_BUG_ON(_Alignof(struct esrt_entry) != 4); + BUILD_BUG_ON(offsetof(struct esrt, esrt_entries) != 16); + /* Obtain basic table pointers. */ for ( i = 0; i < efi_num_ct; ++i ) { @@ -843,6 +899,7 @@ static void __init efi_tables(void) static EFI_GUID __initdata mps_guid = MPS_TABLE_GUID; static EFI_GUID __initdata smbios_guid = SMBIOS_TABLE_GUID; static EFI_GUID __initdata smbios3_guid = SMBIOS3_TABLE_GUID; + static EFI_GUID __initdata esrt_guid = ESRT_GUID; if ( match_guid(&acpi2_guid, &efi_ct[i].VendorGuid) ) efi.acpi20 = (long)efi_ct[i].VendorTable; @@ -854,6 +911,8 @@ static void __init efi_tables(void) efi.smbios = (long)efi_ct[i].VendorTable; if ( match_guid(&smbios3_guid, &efi_ct[i].VendorGuid) ) efi.smbios3 = (long)efi_ct[i].VendorTable; + if ( match_guid(&esrt_guid, &efi_ct[i].VendorGuid) ) + efi.esrt = (long)efi_ct[i].VendorTable; } #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ @@ -1042,9 +1101,7 @@ static void __init efi_exit_boot(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *Syste EFI_STATUS status; UINTN info_size = 0, map_key; bool retry; -#ifdef CONFIG_EFI_SET_VIRTUAL_ADDRESS_MAP unsigned int i; -#endif efi_bs->GetMemoryMap(&info_size, NULL, &map_key, &efi_mdesc_size, &mdesc_ver); @@ -1055,6 +1112,10 @@ static void __init efi_exit_boot(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *Syste for ( retry = false; ; retry = true ) { + enum esrt_status esrt_status = ESRT_NOTFOUND; + const EFI_MEMORY_DESCRIPTOR *esrt_desc = + (const EFI_MEMORY_DESCRIPTOR*) EFI_INVALID_TABLE_ADDR; + efi_memmap_size = info_size; status = SystemTable->BootServices->GetMemoryMap(&efi_memmap_size, efi_memmap, &map_key, @@ -1063,8 +1124,31 @@ static void __init efi_exit_boot(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *Syste if ( EFI_ERROR(status) ) PrintErrMesg(L"Cannot obtain memory map", status); + for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) + { + EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; + switch ( is_esrt_valid(desc) ) + { + case ESRT_NOTFOUND: + break; + case ESRT_GOOD: + esrt_status = ESRT_GOOD; + esrt_desc = desc; + break; + case ESRT_BAD: + esrt_status = ESRT_BAD; + break; + } + } + if ( esrt_status != ESRT_GOOD ) + efi.esrt = EFI_INVALID_TABLE_ADDR; + + /* + * We cannot pass efi.esrt because we need to explicitly compare the + * descriptor pointers for equality. + */ efi_arch_process_memory_map(SystemTable, efi_memmap, efi_memmap_size, - efi_mdesc_size, mdesc_ver); + efi_mdesc_size, mdesc_ver, esrt_desc); efi_arch_pre_exit_boot(); diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c index 375b94229e..8ae086feaa 100644 --- a/xen/common/efi/runtime.c +++ b/xen/common/efi/runtime.c @@ -68,6 +68,7 @@ struct efi __read_mostly efi = { .mps = EFI_INVALID_TABLE_ADDR, .smbios = EFI_INVALID_TABLE_ADDR, .smbios3 = EFI_INVALID_TABLE_ADDR, + .esrt = EFI_INVALID_TABLE_ADDR, }; const struct efi_pci_rom *__read_mostly efi_pci_roms; diff --git a/xen/include/efi/efiapi.h b/xen/include/efi/efiapi.h index a616d1238a..42ef3e1c8c 100644 --- a/xen/include/efi/efiapi.h +++ b/xen/include/efi/efiapi.h @@ -882,6 +882,9 @@ typedef struct _EFI_BOOT_SERVICES { #define SAL_SYSTEM_TABLE_GUID \ { 0xeb9d2d32, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } +#define ESRT_GUID \ + { 0xb122a263, 0x3661, 0x4f68, {0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80} } + typedef struct _EFI_CONFIGURATION_TABLE { EFI_GUID VendorGuid; diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h index 94a7e547f9..bb149fbfb9 100644 --- a/xen/include/xen/efi.h +++ b/xen/include/xen/efi.h @@ -19,6 +19,7 @@ struct efi { unsigned long acpi20; /* ACPI table (ACPI 2.0) */ unsigned long smbios; /* SM BIOS table */ unsigned long smbios3; /* SMBIOS v3 table */ + unsigned long esrt; /* EFI System Reference Table */ }; extern struct efi efi;