From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 CA3603B71B2; Tue, 15 Sep 2026 12:54:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476852; cv=none; b=ZPREgijl2KuhVPmaEA+I5xqtpIo2PfPU8Lb8GQrA0xbNJoxgAb+3iaS5lPFpsU33nRV785q9ZmXVrSIlmv96USfIV4nxsAyAL1owWKpZdXSUcA86DIrJlfd+yio45ITh/ELQ6I5p7sPoaq8TXg1d3sPgfYZR3P49pwYeNT638M4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476852; c=relaxed/simple; bh=QndDTWh5bGLYFpgTzNsBMcjtlSoq6B2ZnR6/EP1pCQo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PTZJEMiQZXwnZiutAzBHljys5DXx3asz2i/p8NdfeQoNxe3gENm+4eXLzEe/w4CINXz2zgXZM0sStAzkUzOl66HfZLyzchKKlwvuyqrR4iZw4+SPv7n0Iflq1Hyhp15lD3A+qq5NYDpNWGsOK6gBYiyV+rWk8JOwktdS0FTcgGc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=QY0GrUg+; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="QY0GrUg+" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=txqh/4dMVNkv3jAnEFkWYzpJcEFlwoVpdz1x6TA4rUQ=; b=QY0GrUg+hg2FpxWgJ8xxZXb26i a40KcG1CY1FLiZgOkpyJzp7DOw1gx1xQpWXRtn5i+i0aRmh548I+laXxHuxipkTKTvSiRNGRa5cCa 15eEcGqTe1tBJvKRukwl9HWsRnOCulnpK4y+qO0fhIOzcDFrlMZl+0CfRcEvuSOcPBgro4LJ8Yp5T +W95tZNqEZYj0PJvLqiJ78uIB6UGaw0dgkHbkpn2unqZVyAM2xLbbEbzam7ULQANjEZAiAHBDlgK7 ZG96j8aQrDleLqQAt/XRd2xXSUxwLy+Qib1h43v3kLn4zpG6CtscsiWn1xAmBwv68+/Wm51M3Kvks hdLJbdeA==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6Sfl-004P5U-0I; Tue, 15 Sep 2026 12:54:05 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:35 -0700 Subject: [PATCH v5 1/9] mm/page_alloc: factor out the accept-and-free tail of __free_pages_core() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-1-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=2075; i=leitao@debian.org; h=from:subject:message-id; bh=QndDTWh5bGLYFpgTzNsBMcjtlSoq6B2ZnR6/EP1pCQo=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/e/q5/cYr405F2RzQcKhfWFrisnYG55iAgq UvT/67s8SiJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 bceTEACgTXdW1ZYLhwiIgzpNy3/tIJlO0t6mQw1xMfw4l9nQV4a9dvbY/XfEh5CoXZ1SxwevYyr jYhT3krAmc4hkLt0U0WC3K64jg+VIQ1OpVudj7jjOnaFTFoQCk+Wco/JApTvPg0TXGejrmXZnAA 7bmbJKaGYUBr0k+GH132hy4tzAGPNsbMghbh0+ZOx+CUZOLCAJ1OW+tW8seGCZ1H1iOZb33i/cN yfqd5+3JA5PFya4Rq4iDZ+h+fhXelxujWlvkWhenA1TReHsfprrwXMK5NAlwxaOUqqy2mhKpzfd WWyC+BjxTCT1RAF47MCnkAAi3/QAS8UDySy7+N26+WFvGImkuhmkRHw+Fb+yqxmn9erNjh6i2Da pkX0o7jatRDIeeA0Tc6nEDsHerPH/Ao+Ph2vjQVWkC42Hy0Criep/Mi5EcLHD16RcBqgbyGCVHZ Zmh4ahHaN07+XvCyatxhM9P3MiIQK+etSZDTegputerYeHbzVpCcMCTOkBz2i3R7GmpRoq/7IGf u3uZYqGtBbqF5p5463cbsewXIL75U79WBO5rTMPMvegvHF85MkpAbTtQK5N/RZckds3O02TLBIY ttKp3I2XptzsAjyHnmWewT1GB5fAUo2ahpu2ryFEAHzvDUf6GoZMUUMxTP39H4en8Sr4iglVSmT l5jNgyb+RfmoLoQ== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao __free_pages_core() ends by accepting the block if it is still unaccepted and then handing it to the allocator. The poisoned-memory replay later in this series needs that same tail for the parts of a block it does not withhold. Move it into accept_and_free_block(). This will be used later, when we need to accept and free a subset of a order-block that is not-poisioned. Signed-off-by: Breno Leitao --- mm/page_alloc.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 404896b53003ef..b07b5f4751cb95 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1579,6 +1579,24 @@ static void __free_pages_ok(struct page *page, unsig= ned int order, free_one_page(zone, page, pfn, order, fpi_flags); } =20 +/* Accept the block if it needs it, then hand it to the allocator. */ +static void __meminit accept_and_free_block(struct page *page, + unsigned int order) +{ + if (page_contains_unaccepted(page, order)) { + if (order =3D=3D MAX_PAGE_ORDER && __free_unaccepted(page)) + return; + + accept_memory(page_to_phys(page), PAGE_SIZE << order); + } + + /* + * Bypass PCP and place fresh pages right to the tail, primarily + * relevant for memory onlining. + */ + __free_pages_ok(page, order, FPI_TO_TAIL); +} + void __meminit __free_pages_core(struct page *page, unsigned int order, enum meminit_context context) { @@ -1613,18 +1631,7 @@ void __meminit __free_pages_core(struct page *page, = unsigned int order, atomic_long_add(nr_pages, &page_zone(page)->managed_pages); } =20 - if (page_contains_unaccepted(page, order)) { - if (order =3D=3D MAX_PAGE_ORDER && __free_unaccepted(page)) - return; - - accept_memory(page_to_phys(page), PAGE_SIZE << order); - } - - /* - * Bypass PCP and place fresh pages right to the tail, primarily - * relevant for memory onlining. - */ - __free_pages_ok(page, order, FPI_TO_TAIL); + accept_and_free_block(page, order); } =20 /* --=20 2.53.0-Meta From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 EFEBC3ACA75; Tue, 15 Sep 2026 12:54:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476860; cv=none; b=pDpoEsPnmkvPbk7587Xl4LgpyAvQRfp27heHfqnCxwj0avS3X1ZDHDj1cHVv+Opo0FiMZBSdypNI1RZSN5ZYNmSa84A809HYX4crr9KNBavTIGsfbTCGA0BTFTNM7RH7mBs/gjm7qxHHhPeagX+nx4jid7yh0lGdAfc3rr8g3yU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476860; c=relaxed/simple; bh=AqqrzDwvc5MieVXiS3iD5LzjloIqKvWhbrV6lDlbLag=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RODkwgvBaXzXXqvaPvW2ffL5wCCMIZADOpD/n3V/uFKHeryvBh2kcvJ3kbIcBRlnI2iZkaGFsSYn/FMK88jM/IKH1zFv6aYTxhP3LOaVnctNU4UlpOv5OOnijJsb/ZE2tQbBVW9/1Xyc7qYe2M5nQ0rnxhyolYMVnTKTnisRxZ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=iXcy6Tsu; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="iXcy6Tsu" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=B+tK3N9OC3DgiaZPAlElq9MFzx15HQwmHJhT/Ff/E3M=; b=iXcy6Tsu4E2gUOJhWKNmz46wyn j8KCuzQ79nYieItGrULajQC97IcqWS3bvkfNXmIJvM/NJs4V+TUzuSX1lf5W1k7Fe+VSY4kkHe1UW kcas4ivklz/UdeuhAx7MZ3qwMvqmjqLvfEKUN+7iAuXjbPmqDDAuVgJ66hfNQDiZ8vYY7S0nBQdPa EeBsBwEMICPU6QnM5o9r3fYXWpNwc4q37LfHUbC70MXiI6qN1D73Tvlq98+LqSBXwm6ILeXu5+7aH SnSZ1bQPFgSIXA4Kgszy+tHrqXy0x6qMv2B/EJn3A6mbBL3RIDdwV7ZoRMuAu4/03wWOmX2kS6WD6 zPJcFW1Q==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6Sfs-004P67-2y; Tue, 15 Sep 2026 12:54:13 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:36 -0700 Subject: [PATCH v5 2/9] mm/memory-failure: efi: add the LINUX_EFI_POISONED_MEMORY configuration table Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-2-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=6084; i=leitao@debian.org; h=from:subject:message-id; bh=AqqrzDwvc5MieVXiS3iD5LzjloIqKvWhbrV6lDlbLag=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/euxNu+DRCZyF1ohaG+nebuwCeABPm1r8aj f8rbyS7PSKJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 bRDED/9SRfQJpN5EaEHA8oM9G+IsH8O95d4MBCMZv9Fi3wTOikNftEJiLe5JcLeyxav8twY5kb2 Ne2uryKuAdsJN30KDWqtaZgMeIc7UTen/jI5dVa3LWjKSP2sgZsjmQGYkvqOdBKyh1JwD9tGiSJ 0RKYsAwo0JzSYLLtjX9BjxMKuO6fWCKmQ7c8cRJgwQYRHeMuj91zAQ/A/BnMFVWAZ+oMvceK8Ao XYi0KWsWljHuNiBMn3fHwDnn2OplNqF1tozG7FlztC3sfWfcJeDc6qsqlWoOvTdZrj/tVQZ1sQt eGM1Ybs2oWX6F9Xz5Zo8eTpVD2Fnyf9cXWIT6nA3aTDsEmE9+h5IwXNqD0QvTtBP4W5SoVeUQd0 eQvK6q1GM0gT2Ylwz5Aq0CmETyFu/prJNnCw+FKHWK1W7Pir9O9TBl6Ip4vKFtgtKOURIMDRLXY CXpcYHYjEPR4eY+5MQgTjlrNA2pBDhy3BExq1OB98d1NJyqfTBSgPUcQo1X3iu6bjVfdwGKJ1xp dPEe84Bi5TDJoQu5iOkT+Z9DfL//uZWkL6ikqPNhSJdOG3zwV9r9jzsTfRDySNTAQctCoyiHeHW uDBXhaCZZ3IuuQB2jMzcNFcDnFs2+Z1BRVaQeNVqxgMK35Y2a0Nlvu7FJmGgRaafWcdG1etXWn+ szkfnoFKPkxekEw== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao Hardware-poisoned page frames are tracked only in the running kernel's data structures, so a kexec loses them and the next kernel doesn't have this information, thus, tripping into them again. Add an EFI configuration table to carry that information across kexec. It is a bitmap with one bit per EFI_POISON_UNIT_SIZE (2MiB) of physical memory starting at phys_base, modeled on the LINUX_EFI_UNACCEPTED_MEMORY table, and it rides the EFI system table to every kernel in the chain. Basing the bitmap keeps a machine whose RAM starts high from paying for the hole below it. List the table in the x86 efi_tables[] too, so an SME host maps it unencrypted like every other EFI table. The Kconfig symbol has no prompt. There is nothing for a user to decide, so it is on wherever it can be, and it only costs 64K per TiB of RAM on a kernel that already has the EFI stub and MEMORY_FAILURE. It is restricted to 64BIT because the unit arithmetic divides by a runtime unit_size, which needs div_u64() on 32-bit. That combination is reachable, X86_32 with FLATMEM selects ARCH_SUPPORTS_MEMORY_FAILURE and has an EFI stub, so the dependency is what keeps the division out rather than a config nobody can build. The bitmap is an unsigned long array reached with the native bitops, like the unaccepted memory table it copies. That is endian dependent, but EFI_STUB && 64BIT is little-endian everywhere: arm64 turns EFI off under CPU_BIG_ENDIAN, and no other architecture with the stub is big-endian. This is a similar approach as used as unaccepted memory. Suggested-by: Kiryl Shutsemau Signed-off-by: Breno Leitao --- arch/x86/platform/efi/efi.c | 3 +++ drivers/firmware/efi/Kconfig | 8 ++++++++ drivers/firmware/efi/efi.c | 6 ++++++ include/linux/efi.h | 14 ++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 0c39adb96b912b..2b37b96a36e099 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -93,6 +93,9 @@ static const unsigned long * const efi_tables[] =3D { #ifdef CONFIG_UNACCEPTED_MEMORY &efi.unaccepted, #endif +#ifdef CONFIG_EFI_POISONED_MEMORY + &efi.poisoned_memory, +#endif }; =20 u64 efi_setup; /* efi setup_data physical address */ diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 29e0729299f5bd..aafcd41bc00630 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -263,6 +263,14 @@ config EFI_COCO_SECRET virt/coco/efi_secret module to access the secrets, which in turn allows userspace programs to access the injected secrets. =20 +config EFI_POISONED_MEMORY + def_bool y + depends on EFI_STUB && MEMORY_FAILURE && 64BIT + help + Record page frames that are hardware-poisoned while this kernel runs + into an EFI configuration table, and honor that table early on the + next kernel so a kexec does not hand known-bad RAM back out. + config OVMF_DEBUG_LOG bool "Expose OVMF firmware debug log via sysfs" depends on EFI diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 6d987d7f97781f..af1fa443839c4d 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -55,6 +55,9 @@ struct efi __read_mostly efi =3D { #ifdef CONFIG_UNACCEPTED_MEMORY .unaccepted =3D EFI_INVALID_TABLE_ADDR, #endif +#ifdef CONFIG_EFI_POISONED_MEMORY + .poisoned_memory =3D EFI_INVALID_TABLE_ADDR, +#endif }; EXPORT_SYMBOL(efi); =20 @@ -677,6 +680,9 @@ static const efi_config_table_type_t common_tables[] __= initconst =3D { #ifdef CONFIG_UNACCEPTED_MEMORY {LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID, &efi.unaccepted, "Unaccepted" }, #endif +#ifdef CONFIG_EFI_POISONED_MEMORY + {LINUX_EFI_POISONED_MEMORY_TABLE_GUID, &efi.poisoned_memory, "POISON" }, +#endif #ifdef CONFIG_EFI_GENERIC_STUB {LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID, &primary_display_table }, #endif diff --git a/include/linux/efi.h b/include/linux/efi.h index c35446a0b66fac..efaf63f9a54edd 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -23,6 +23,7 @@ #include #include #include +#include #include =20 #include @@ -422,6 +423,7 @@ void efi_native_runtime_setup(void); #define LINUX_EFI_COCO_SECRET_AREA_GUID EFI_GUID(0xadf956ad, 0xe98c, 0x48= 4c, 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47) #define LINUX_EFI_BOOT_MEMMAP_GUID EFI_GUID(0x800f683f, 0xd08b, 0x423a, = 0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4) #define LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID EFI_GUID(0xd5d1de3c, 0x105c, 0= x44f9, 0x9e, 0xa9, 0xbc, 0xef, 0x98, 0x12, 0x00, 0x31) +#define LINUX_EFI_POISONED_MEMORY_TABLE_GUID EFI_GUID(0xaf828a15, 0x0ef4, = 0x439a, 0xb8, 0x6a, 0xd6, 0xd6, 0x9e, 0xaf, 0xba, 0xfa) =20 #define RISCV_EFI_BOOT_PROTOCOL_GUID EFI_GUID(0xccd15fec, 0x6f73, 0x4eec,= 0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf) =20 @@ -650,6 +652,7 @@ extern struct efi { unsigned long mokvar_table; /* MOK variable config table */ unsigned long coco_secret; /* Confidential computing secret table */ unsigned long unaccepted; /* Unaccepted memory table */ + unsigned long poisoned_memory; /* Hardware-poisoned memory table */ =20 efi_get_time_t *get_time; efi_set_time_t *set_time; @@ -1272,6 +1275,17 @@ struct linux_efi_memreserve { #define EFI_MEMRESERVE_COUNT(size) (((size) - sizeof(struct linux_efi_memr= eserve)) \ / sizeof_field(struct linux_efi_memreserve, entry[0])) =20 +/* Bit N covers the unit at @phys_base + N * @unit_size. */ +struct linux_efi_poisoned_memory { + u32 version; + u32 unit_size; /* bytes of phys space per bitmap bit */ + u64 phys_base; /* address the first bit covers */ + u64 size; /* bitmap size in bytes */ + unsigned long bitmap[]; +}; + +#define EFI_POISON_UNIT_SIZE SZ_2M + void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size); =20 /* --=20 2.53.0-Meta From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 DA7863BCD2E; Tue, 15 Sep 2026 12:54:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476867; cv=none; b=uNrMiJRDZ/YAuYfdMPtbOagl2QkenhKT7Fq8bOY6m5XkytHqs/jFRx8GH9J9PjIucwyjowJhbbXWxTY7VWeG6BeTxFCGciXKjbxrqOM54O9j0M1+I4RbcOXiDlz4LpqFDe7OlU4evrpBxwkYXHrHhRI13NLm7Lpkr7HCHOhDvdU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476867; c=relaxed/simple; bh=sLHT+4xqfDFZam/oooAorDETruuddEAL1m7pml8eFaM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HAw+1YtY1TqvapqEuRLZ1O5VfcSk1y24jqYW9BitS4NA/p/2pEZ08LWf/7HyPXxqO/CZcoqT+bs63xgIzFMU4kTl0rqQhvCWbkI+Z2PjrKDgkoFwoWXIYdYM5cfhWZEbLSnonxe/V9PezSON38Hbed4WJckmXLHhmUfsJ+GqLJg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=fzls2op0; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="fzls2op0" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=6sbKIdMXcwwn7L1BaySMDKOdtYe9fziacJ6jCoPK7kY=; b=fzls2op0NmrUJGvLS3Apt9OLKB QhDOGb7fV/aVpQjgfJJiu6YLatzow2J1R5kpV7NrljaEmKOdbaTc5KxiAeYVbdm95QDSXcyOMpRdK LqTRhT+I1tgmyv54A5EV7z1XpmwImfT6/sSEWCjwoOmHs9cH+l/JaCqV2ezWwnBSKH6ZxPMEsVsX7 4yIjBHN5/ZPFGBfxSpTCZrDPn8PriJRzma71RDcQ6diQqx0dbGTFs32pGcgDZN2BHKhRAYqkWvbQ1 WTwnsWO83STeYn7LG4c2+V74a/G7q0dqF4cVTpTDdVcc4gPatL/gDeFbnh3tpNZ6x3KZaikfHun/i cWEoQpgg==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6Sg0-004P6i-2R; Tue, 15 Sep 2026 12:54:21 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:37 -0700 Subject: [PATCH v5 3/9] mm/memory-failure: libstub: install the poisoned-memory EFI table Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-3-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=6897; i=leitao@debian.org; h=from:subject:message-id; bh=sLHT+4xqfDFZam/oooAorDETruuddEAL1m7pml8eFaM=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/e1zXAaiv2HwVTbVYoxnE6rSOAIQJI/r/qd 3gK45gDUdqJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 bd+uD/9UJeIaTyr/JhRDZz04VltzrfTU4SQt7/Y+5CC6OgL8wR0o3SYAmos2ZOqxmHYzrF0Suq/ y17CAuPnRUHzKCbsRshDiePc99PAw0lVxe7umBwfqiBWxDwT8omkVaBqCb6FYibVVXttDicgYxK wFu5ORfC2P2FTvy+SvWmI8wbNHlViMeLqu2bWUDAVZhqxIEbkoZVr8XMnWWiBpi4ndgg6L/UC2f Cu/9WMAhhxqTLGE0f+NarOz0XjU1Qew0YwQ92OP9rNcZ6Pz2R2Wtuw0/7Q/e3C8Fpb1CcachTLL Y0qFq7BHoT5MOmrf7+obAFw3sAYJBB9vt9PUjFy979RtrF28uBXthaqO394dIW2jmvPcmeZzfwZ SEO4NpjYF133SAif3uTZIRB2ilq4CCDILemOgbOm8pfIXyS0quSuKdeyOoeOQI5thTGWhr0TMM+ HHfuKNDstaMOBE9wEMbiYptbfckDqxHL00oRWSRQOJKieLj1GvUxQX7QLytbhWx5m5PTj3KOht5 HtxnQQgBdI+Gj2tZ9TqyB4mQiEn+mk0ZUcCfwbKrCHybaXmji0maIs9Xs1BMulLklwAJTAfOpS1 MIoqO7LWGUnWV+eULPcnxNsUwY2h4aeK0728LaSA74SwBNxGC6dC3WHIjN98sQUqBnbLXy/QbVP PyWsMZmQQ6rtWbQ== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao A EFI config table can only be installed while boot services are still up, so the stub has to create it; the running kernel can only flip bits in a table that already exists. Size the bitmap from the span the UEFI memory map describes, which efi_get_ram_range() walks since the stub has no max_pfn. Bit 0 covers the bottom of that span, recorded in phys_base, so a machine whose RAM starts high does not pay for the hole below it. Memory the firmware hot-adds later sits outside the span and is not carried across a kexec. One table has to serve every architecture, and what they agree on is the attribute: setup_e820() takes a descriptor as RAM only if it is writeback cacheable, and so does is_usable_memory() on arm64. The bitmap spans from the lowest to the highest descriptor that is write-back cacheable or unaccepted memory, as discussed with Kiryl. That leaves out the MMIO apertures, which sit high enough to stretch it far past the RAM it needs to describe. At one bit per 2M that is 64K per TiB, and 256M at the 4PB x86 architectural maximum. The 2M granule is called "unit" here, and the table carries it so the granule can change later without breaking the kernels already reading it. Allocate it as EFI_ACPI_RECLAIM_MEMORY so the next kernel does not take it for free RAM, and install it empty. A table installed by an earlier boot rides the system table across kexec and is reused as-is. Signed-off-by: Breno Leitao --- drivers/firmware/efi/libstub/efi-stub-helper.c | 103 +++++++++++++++++++++= ++++ drivers/firmware/efi/libstub/efi-stub.c | 1 + drivers/firmware/efi/libstub/efistub.h | 6 ++ drivers/firmware/efi/libstub/x86-stub.c | 2 + 4 files changed, 112 insertions(+) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmw= are/efi/libstub/efi-stub-helper.c index 48f93f7758e9e9..9c66e06c972c5a 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -774,3 +774,106 @@ void efi_remap_image(unsigned long image_base, unsign= ed alloc_size, efi_warn("Failed to remap data region non-executable\n"); } } + +#ifdef CONFIG_EFI_POISONED_MEMORY +/* + * Find the base and top of the memory, so, we can create the bitmap for + * the full range. + */ +static efi_status_t efi_get_ram_range(u64 *base, u64 *top) +{ + struct efi_boot_memmap *map __free(efi_pool) =3D NULL; + u64 ram_base =3D ULLONG_MAX, ram_top =3D 0; + efi_status_t status; + int i, nr_desc; + + status =3D efi_get_memory_map(&map, false); + if (status !=3D EFI_SUCCESS) + return status; + + nr_desc =3D map->map_size / map->desc_size; + for (i =3D 0; i < nr_desc; i++) { + efi_memory_desc_t *d; + + d =3D efi_memdesc_ptr((unsigned long)map->map, map->desc_size, i); + if (!(d->attribute & EFI_MEMORY_WB) && + d->type !=3D EFI_UNACCEPTED_MEMORY) + continue; + ram_base =3D min(ram_base, d->phys_addr); + ram_top =3D max(ram_top, + d->phys_addr + d->num_pages * EFI_PAGE_SIZE); + } + if (!ram_top || ram_base =3D=3D ULLONG_MAX) + return EFI_NOT_FOUND; + + *base =3D round_down(ram_base, EFI_POISON_UNIT_SIZE); + *top =3D round_up(ram_top, EFI_POISON_UNIT_SIZE); + + return EFI_SUCCESS; +} + +/* The size of the bitmap */ +static u64 efi_poison_bitmap_size(u64 span) +{ + u64 bytes =3D DIV_ROUND_UP(DIV_ROUND_UP(span, EFI_POISON_UNIT_SIZE), + BITS_PER_BYTE); + + return round_up(bytes, sizeof(unsigned long)); +} + +static struct linux_efi_poisoned_memory *efi_poison_alloc(u64 phys_base, + u64 bitmap_size) +{ + struct linux_efi_poisoned_memory *pm; + efi_status_t status; + + status =3D efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, + sizeof(*pm) + bitmap_size, (void **)&pm); + if (status !=3D EFI_SUCCESS) + return NULL; + + pm->version =3D 1; + pm->unit_size =3D EFI_POISON_UNIT_SIZE; + pm->phys_base =3D phys_base; + pm->size =3D bitmap_size; + memset(pm->bitmap, 0, bitmap_size); + + return pm; +} + +/* This needs to be done while boot service is still active */ +void install_poisoned_memory_table(void) +{ + efi_guid_t poisoned_memory_table_guid =3D LINUX_EFI_POISONED_MEMORY_TABLE= _GUID; + struct linux_efi_poisoned_memory *pm; + u64 ram_base, ram_top, bitmap_size; + efi_status_t status; + + /* A table installed by an earlier boot rides the system table across kex= ec. */ + pm =3D get_efi_config_table(poisoned_memory_table_guid); + if (pm) { + if (pm->version !=3D 1) + efi_err("Unknown version of poisoned-memory table\n"); + return; + } + + if (efi_get_ram_range(&ram_base, &ram_top) !=3D EFI_SUCCESS) { + efi_err("Failed to size the poisoned-memory table!\n"); + return; + } + + bitmap_size =3D efi_poison_bitmap_size(ram_top - ram_base); + pm =3D efi_poison_alloc(ram_base, bitmap_size); + if (!pm) { + efi_err("Failed to allocate poisoned-memory table!\n"); + return; + } + + status =3D efi_bs_call(install_configuration_table, + &poisoned_memory_table_guid, pm); + if (status !=3D EFI_SUCCESS) { + efi_bs_call(free_pool, pm); + efi_err("Failed to install poisoned-memory config table!\n"); + } +} +#endif diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi= /libstub/efi-stub.c index 235c9738da2d63..22a315e2814a1a 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -179,6 +179,7 @@ efi_status_t efi_stub_common(efi_handle_t handle, EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP); =20 install_memreserve_table(); + install_poisoned_memory_table(); =20 status =3D efi_boot_kernel(handle, image, image_addr, cmdline_ptr); =20 diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/= libstub/efistub.h index fd91fc15ec810b..44436869c4efe1 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1169,6 +1169,12 @@ efi_enable_reset_attack_mitigation(void) { } =20 void efi_retrieve_eventlog(void); =20 +#ifdef CONFIG_EFI_POISONED_MEMORY +void install_poisoned_memory_table(void); +#else +static inline void install_poisoned_memory_table(void) { } +#endif + struct sysfb_display_info *alloc_primary_display(void); struct sysfb_display_info *__alloc_primary_display(void); void free_primary_display(struct sysfb_display_info *dpy); diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi= /libstub/x86-stub.c index 0bae0f06b6763a..3136132b9628ab 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -1024,6 +1024,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle, =20 setup_unaccepted_memory(); =20 + install_poisoned_memory_table(); + status =3D exit_boot(boot_params, handle); if (status !=3D EFI_SUCCESS) { efi_err("exit_boot() failed!\n"); --=20 2.53.0-Meta From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 103943BCD2C; Tue, 15 Sep 2026 12:54:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476874; cv=none; b=UvnJAKCm1ekq4sz6n6hRbBuNii9xwKCmqmDh4D2bgq1stOra0QRbW6LitGdHr2q+doutyfdCW3aBeWAnDuYmFAPKhbsHpDaPwVUzu6TWx1ZpdOKvZ70E8Uvzq5tuVMy6hbpvoZ6P0ym7nrjHK2FUqzuw0CZoq3D25DvW2BkKTvk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476874; c=relaxed/simple; bh=p4TA3mGY17xjFk2/w08zQcue/vtEofhamWwCnuZ5N5A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=OGYXbhPbepLZnGDScRCZz1uf7+DEXfsuPa7mTgblLCJX9gCGckkwBZpzZ1qxTp5mGloyeWzdVeAoFcHnFJyBWHNr63usKHv7n2P9qBoeKQKUegymMTh+jVnbVu1dpt/KU+hpL8WFqthrhBf+9RsVHWdJTK6zG0XF4hX4HgeK98U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=D165baFu; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="D165baFu" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=vQYv3IK3nKz4VGXfXkL0jqV1c+L3rNS2Cu4FByGZSzQ=; b=D165baFugE5ebahFxkHKeCtu69 isvlYunXRrZ/8h5RSqDs/k7VkHz6E1lmtMvEeE+ivLExqwk8r76X2r2ATXCDPUDsWFkhVjeL/fAI6 iZmtLQbG04bSv2LbMeFhi4IBYwkpl5gNsbVtxaVNr0I9swAzDTh1uYcrYqHOtWyZ0Z4yLCQBt6dMi q9hbn+HbX5q5ymNepSaFJRWx0+VFm4fmaQ6VRmNYhkNVz6JSQV85WknT888e4QEuVvNnYl/fI5qbW 0z3LXQ79Iale7SbpKC6gAdYX+bXSlx8PrLKmc75gAZOFoVzmhcei1RHe5ueUSIKK8NESIuB23E5gf EiIsdYCg==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6Sg8-004P71-12; Tue, 15 Sep 2026 12:54:28 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:38 -0700 Subject: [PATCH v5 4/9] mm/memory-failure: efi: adopt the inherited poisoned-memory table Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-4-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=5602; i=leitao@debian.org; h=from:subject:message-id; bh=p4TA3mGY17xjFk2/w08zQcue/vtEofhamWwCnuZ5N5A=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/e1t7ibvkUKJ2Ehd30snyR4Ejp44hDVq5P1 Cmn9fCJS+6JAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 bVMHEACluIfazKFZBsLVFzWJZNmi4R+tYXhf7Y8Ou4PotT0vf2Jfg1Anf637yriPAyRYiYw2VI8 +tXqoWdTDh6rNDHzGNRlQTC3ICpfBaEORTg07oCS1SItgKpBYajALVtu0QJdINjz8FDCPFSRSuP rTcWZTpUy0VWRyCxGp9djsnQaXIxIJ0977vocCfwDfBnVdyYmx9XppOYol6bADrhCmVuMR+m64Z dbWiol7VMlBKGlKpbHfQU1NQg5f1PpdPc2sOTUBzS8Vk0cGkeuLRSTGU/Mz3P8tCfUMpvCBW9m1 aKNwiMoFygDnVi/qYdiy8FlxAT88V4gcPlHGxfd6dvGg1w1j9aebDpz+fSqdZFVn+uPf2p5/YdY gCpm0ZA5lh8aYev08tibz57fqhc5jOT18sofrI5/uY1yMYPuX052Kdpe3SZlzBIuDU36R63Mqju 5Lr6EhgQwL/ypaPRB2ppnVu0YdPUjZvH+E+x9++OJ0/U06fZ7/2fTCuE9S1Gw3j92cLq4hJkaup qq/0W1WEKnUdbml/vFnDSgA+AZlWFOPyd1KaTpbufF3OUSDIa3erk7h9oBXVORZKP1sLs4iuIzv /eCjX0tehKPXuyV/QfyX/M4lmuY64i8s7qgiv6M5f7DIpG0P5zmIq/wqoU4lJWKTCYoh4/x3lMy 9g7PPs96Q6n7AFA== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao A table installed by an earlier boot rides the EFI system table into this kernel, but nothing looks at it yet. Take it into use from efi_config_parse_tables(). The table can come from any kernel further up the kexec chain, so vet the header first: the version, whole-word bitmap size, a bit count and a footprint that can be taken without wrapping, and a power-of-two unit the base is aligned to. A table that fails any of those is dropped rather than trusted. The table is EFI ACPI reclaim memory, which x86 turns into E820_TYPE_ACPI and leaves out of memblock, so it never reaches the direct map and touching it later faults. Hand its pages to memblock the way commit 8dbe33956d96 ("efi/unaccepted: Make sure unaccepted table is mapped") does for the unaccepted memory table, so everything afterwards can reach it with phys_to_virt(). Signed-off-by: Breno Leitao --- drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/efi.c | 2 + drivers/firmware/efi/poison.c | 93 +++++++++++++++++++++++++++++++++++++++= ++++ include/linux/efi.h | 6 +++ 4 files changed, 102 insertions(+) diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 8efbcf699e4ff9..05d0a490923e56 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -43,4 +43,5 @@ obj-$(CONFIG_EFI_EARLYCON) +=3D earlycon.o obj-$(CONFIG_UEFI_CPER_ARM) +=3D cper-arm.o obj-$(CONFIG_UEFI_CPER_X86) +=3D cper-x86.o obj-$(CONFIG_UNACCEPTED_MEMORY) +=3D unaccepted_memory.o +obj-$(CONFIG_EFI_POISONED_MEMORY) +=3D poison.o obj-$(CONFIG_TEE_STMM_EFI) +=3D stmm/tee_stmm_efi.o diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index af1fa443839c4d..55b2ee53fc2688 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -883,6 +883,8 @@ int __init efi_config_parse_tables(const efi_config_tab= le_t *config_tables, } } =20 + efi_poisoned_memory_reserve(); + return 0; } =20 diff --git a/drivers/firmware/efi/poison.c b/drivers/firmware/efi/poison.c new file mode 100644 index 00000000000000..3f12db3dc9b844 --- /dev/null +++ b/drivers/firmware/efi/poison.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Runtime side of the LINUX_EFI_POISONED_MEMORY table: one bit per + * EFI_POISON_UNIT_SIZE, set here as frames go bad, honored by the next ke= rnel. + * + * Copyright (c) 2026 Meta Platforms, Inc. and affiliates. + * Copyright (c) 2026 Breno Leitao + */ + +#define pr_fmt(fmt) "efi: " fmt + +#include +#include +#include +#include +#include +#include +#include + +static bool __init +efi_poison_geometry_valid(const struct linux_efi_poisoned_memory *pm) +{ + u64 nbits, end; + + /* Whole words, and a bit count that can be taken without wrapping. */ + if (!pm->size || !IS_ALIGNED(pm->size, sizeof(unsigned long)) || + check_mul_overflow(pm->size, (u64)BITS_PER_BYTE, &nbits)) + return false; + + /* And a footprint that can be page aligned without wrapping either. */ + if (check_add_overflow(efi.poisoned_memory, sizeof(*pm) + pm->size, + &end) || end > PHYS_ADDR_MAX - PAGE_SIZE) + return false; + + if (pm->unit_size < PAGE_SIZE || !is_power_of_2(pm->unit_size)) + return false; + + return IS_ALIGNED(pm->phys_base, pm->unit_size); +} + +/* The table may come from an earlier kernel, so vet it before using it. */ +static bool __init +efi_poison_table_valid(const struct linux_efi_poisoned_memory *pm) +{ + if (pm->version !=3D 1) { + pr_warn("Ignoring poisoned-memory table with version %u\n", + pm->version); + return false; + } + + if (!efi_poison_geometry_valid(pm)) { + pr_warn("Ignoring malformed poisoned-memory table\n"); + return false; + } + + return true; +} + +/* + * Vet the inherited table and hand its pages to memblock, the way the + * unaccepted memory table is handled. It is EFI ACPI reclaim memory, which + * becomes E820_TYPE_ACPI and would otherwise stay out of the direct map, = and + * touching it then faults. Called from efi_config_parse_tables(), so + * everything later can reach it with efi_poisoned_memory(). + */ +void __init efi_poisoned_memory_reserve(void) +{ + struct linux_efi_poisoned_memory *pm; + phys_addr_t start, end; + + if (efi.poisoned_memory =3D=3D EFI_INVALID_TABLE_ADDR) + return; + + pm =3D early_memremap(efi.poisoned_memory, sizeof(*pm)); + if (!pm) { + pr_warn("Could not map poisoned-memory table\n"); + efi.poisoned_memory =3D EFI_INVALID_TABLE_ADDR; + return; + } + + if (!efi_poison_table_valid(pm)) { + efi.poisoned_memory =3D EFI_INVALID_TABLE_ADDR; + early_memunmap(pm, sizeof(*pm)); + return; + } + + start =3D PAGE_ALIGN_DOWN(efi.poisoned_memory); + end =3D PAGE_ALIGN(efi.poisoned_memory + sizeof(*pm) + pm->size); + early_memunmap(pm, sizeof(*pm)); + + memblock_add(start, end - start); + memblock_reserve(start, end - start); +} diff --git a/include/linux/efi.h b/include/linux/efi.h index efaf63f9a54edd..dd3263456dd4a3 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1286,6 +1286,12 @@ struct linux_efi_poisoned_memory { =20 #define EFI_POISON_UNIT_SIZE SZ_2M =20 +#ifdef CONFIG_EFI_POISONED_MEMORY +void __init efi_poisoned_memory_reserve(void); +#else +static inline void efi_poisoned_memory_reserve(void) { } +#endif + void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size); =20 /* --=20 2.53.0-Meta From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 3C63A3BCD2C; Tue, 15 Sep 2026 12:54:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476882; cv=none; b=Zm+5EvRGigJJWwD+DGDW2Uv5zFFwW2y3ymgTJrhVn+sAnuoNitc1zo6MEwm5AmOkAzTNa0kCxqNN9KbOnhUoHm6V6YS+8I7dKH7G+0Z+ShptaiWZo/BEC8ZtW+38JWW/q+bdN4PW/fGXr8gWzRa6cOB82CpRQ92ceDPGpuirunQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476882; c=relaxed/simple; bh=OD6lOfDsuQ3Gx0O3nG+lnSFgQ/uCyiBdpWhEzT0xs4w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Aq/6idR+uR1reyRfEwmhhnotd6mpt+r3wIslewq+1R6qWZSFDCqyK0g7xKbcrgwlAUnyAZrk988DvnkeQuCC91u1lDZe/3Znh+si7PjkA168fupoQRRlgPC5eyv37Q8M/mmt5sfJYbuVWI9QwW5pXTupkCe1NuckUNIjmG+Lw3s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=Qcf3QIz5; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="Qcf3QIz5" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=06TheYrO+RqVpiOeLZzO2sVZrEIqfAB0lq+jheypzUY=; b=Qcf3QIz55CcoaSldbU3zzTlL9y IesoBAEM54qeIhRkKwKFUEMm4nfEKwbtnDTM2Kwd/9YFqHwXxGoIriQlWqoQ7M5qGa7U48T1BTx8M DG1/EIn4i/N3wGOau9uP2DnOL3mq9IE36OTH+ACyOXN/gBOSOmzbXk9ZVPvdlo96o0jM8zTSCTRAZ w/lj1lQEIxmzspaxPkyvhiAs5vTFOfO4ATfnvHd+Ral4CQZ+gLnhbwATUF1OJc1jr457gY66mVZr9 AqOKMoDcCVXOb6Tff4axnEA1/l9sQiiL4HEI2zrLGLxVnHMLBEzeJRxf24fQ868QdNF9UqbHy4YMW ghNx9N7Q==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6SgG-004P7U-0N; Tue, 15 Sep 2026 12:54:36 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:39 -0700 Subject: [PATCH v5 5/9] mm/memory-failure: efi: record hardware-poisoned frames into the poisoned-memory table Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-5-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=3575; i=leitao@debian.org; h=from:subject:message-id; bh=OD6lOfDsuQ3Gx0O3nG+lnSFgQ/uCyiBdpWhEzT0xs4w=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/e9fGRdv2ojIBIylpv+WGyoKgen1RPvA/py wfutQvXLwSJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 bcZOD/9tYa5c1xoSwHHUjr+PBSVX2GYqBV2gH0IMO8Np0WO5iyG9Uz1fsyag/5SdmAC3g8xbHCi SU49YEZF/BxnxWXcegM8Hq2aRQQ/PsZzDmwpiOVkh1Yd0+m23cgfkxAHTeObj79QrvrpupuB0ZN ZfenMCr6f9nmRuuyXJgGAdN3SqmKKkHp/0pLf9jhrJVQppAmkL21OL/dcIL7MUn4ViSzT5ay1rg 9bKerw/vl7i3oNZKiblmKUgY1iOw28hN1BLbiZ5OJAiotlCciX210WGqifZUCnD8F4v9XbMcL88 GkxIZrs8wOD30AS0yt1/Hp6DziMWkY2qmOjX+0oLGASCVf77CT1Ki6jFrVtp6AwYJhTqVaTTviz VObWrgN1tVtc491/NDobzNW8fcbhu6gPkS6kU9dTdpXBMGlSjBGkdkhrmyZuarbh9+yY4cgwe+6 lGdYm1vtptAfuVdrjaBkWTSEO0HaYCWL6UfQ1TBPZbU3oPBsjerrrMSO8RiB0OVDgkaTbgFHvMY 1XsGOXMKOJm1ZBfnZ5E06uWG8cxlbQMS47XSWNyLn95gNQKRh2W9OwNwfvFxN/B5oyjgx0tmbmx aeFo0YF6GMWpENLcwZT/pidl1kpqjp6Tc/kh6QxZA3JoXkPIZMg0nTE2piBle5FZW0X0wk4m2kJ hAkVzZhu0+0Hnxg== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao action_result() is where memory_failure() reports the outcome of a hard offline, so hook it to set the frame's bit in the LINUX_EFI_POISONED_MEMORY bitmap. Soft-offlined pages reach num_poisoned_pages_inc() through page_handle_poison() and are deliberately left out: they are still functional and were offlined predictively, so recording them would turn a prediction into a permanent loss for every kernel further down the kexec chain. A bit is only ever set, never cleared, given that multiple pages can set the same bit, and it is not trivial to decide if the bit should be unset when a page is unrecorded. Unpoisoning a frame therefore does not hand its unit back to the next kernel. That is a known limitation. memory_failure() has already taken the frame out of this kernel's allocator, so only the cross-kexec record happens here. Signed-off-by: Breno Leitao --- drivers/firmware/efi/poison.c | 27 +++++++++++++++++++++++++++ include/linux/efi.h | 2 ++ mm/memory-failure.c | 3 +++ 3 files changed, 32 insertions(+) diff --git a/drivers/firmware/efi/poison.c b/drivers/firmware/efi/poison.c index 3f12db3dc9b844..847592862f01d3 100644 --- a/drivers/firmware/efi/poison.c +++ b/drivers/firmware/efi/poison.c @@ -91,3 +91,30 @@ void __init efi_poisoned_memory_reserve(void) memblock_add(start, end - start); memblock_reserve(start, end - start); } + +/* The table, vetted at parse time, or NULL if this boot has none. */ +static struct linux_efi_poisoned_memory *efi_poisoned_memory(void) +{ + if (efi.poisoned_memory =3D=3D EFI_INVALID_TABLE_ADDR) + return NULL; + + return phys_to_virt(efi.poisoned_memory); +} + +/* + * A bit is never cleared: it stands for a whole EFI_POISON_UNIT_SIZE, so = an + * unpoison cannot tell whether the unit as a whole is good again. + */ +void efi_hwpoison_record_pfn(unsigned long pfn) +{ + struct linux_efi_poisoned_memory *pm =3D efi_poisoned_memory(); + phys_addr_t addr =3D PFN_PHYS(pfn); + u64 unit; + + if (!pm || addr < pm->phys_base) + return; + + unit =3D (addr - pm->phys_base) / pm->unit_size; + if (unit < pm->size * BITS_PER_BYTE) + set_bit(unit, pm->bitmap); +} diff --git a/include/linux/efi.h b/include/linux/efi.h index dd3263456dd4a3..56402fdccd1149 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1288,8 +1288,10 @@ struct linux_efi_poisoned_memory { =20 #ifdef CONFIG_EFI_POISONED_MEMORY void __init efi_poisoned_memory_reserve(void); +void efi_hwpoison_record_pfn(unsigned long pfn); #else static inline void efi_poisoned_memory_reserve(void) { } +static inline void efi_hwpoison_record_pfn(unsigned long pfn) { } #endif =20 void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index a2ca8df501caee..d9b8be696aac38 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1326,6 +1327,8 @@ static int action_result(unsigned long pfn, enum mf_a= ction_page_type type, if (type !=3D MF_MSG_ALREADY_POISONED && type !=3D MF_MSG_PFN_MAP) { num_poisoned_pages_inc(pfn); update_per_node_mf_stats(pfn, result); + /* Only hard offlines are carried over to the next kernel. */ + efi_hwpoison_record_pfn(pfn); } =20 pr_err("%#lx: recovery action for %s: %s\n", --=20 2.53.0-Meta From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 7AE833C8C48; Tue, 15 Sep 2026 12:54:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476890; cv=none; b=PLzgXr1FotukE3z1wu8GaqcDjF4Agxnu0q0yAphsDQ1cKnsYK74ST7Q0pcR1n4czlha1Le7VjlLF2NY+bZPGV+we9n468esu28IEUkg08Z/Atolk4hTCowhMrtrOZ/vr92DAKYyzZlCPZYpwwRtOOeU3dxCcrQ3MXiUFqscXKsc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476890; c=relaxed/simple; bh=i08dYaHI1fvoon+7eeYigKp4zMx+PElqpyXpuKwzxk8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=M5j5rCX99+/NXJ/XzpYbidvuTWgQQaEopAtVkd5Sjuw43pbBvprrLvRRAg+cb3mVFpB+8/qkBnDBak84c8H5b4ZNVQluq1vC6KHZjVnd81OeFKo1TKUSP2+Y7//93EhK+mnEfc1Kx1tRPSveNCkADFNkmu/A9LSiO8EeKWe0cT4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=tthTfBN4; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="tthTfBN4" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=KFGAjcgsBNZUtMlZjlNuj+eLmu5d+vEUzhR99IX1VDA=; b=tthTfBN4x7zCU7oGsVV6Szsvt3 jvEGAStFY3aByDpkFQ5VIXyHuEyyUNEGE8yGXVKQj1L8z+KaXwyg9EwFNjUaUaS/AtU47uM1fItm4 WNYOH43FOfWuHSCwAI6seskU41IGUBS/s2Nvdv9mmSkUX2gx+A48JVhqafzaIwX5Q2o0gmOCa7J6/ ITl+/NOqiGF+m9GDu6J2gzFRWbEEFJe8Yp1cuELMtoUWTSWgdja9ke2cHVwcb85jm09nAmp0vav+i UbM7uQ1VJHTBD86CwMtdGVcHr78GZTF07OnczSRjppPZmBpNj6OTeGtxnvfGyEs2Qc0UU1b69cwPg 15mtXdIg==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6SgN-004P8C-3B; Tue, 15 Sep 2026 12:54:44 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:40 -0700 Subject: [PATCH v5 6/9] mm/memory-failure: efi: answer whether a range is poisoned Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-6-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=2450; i=leitao@debian.org; h=from:subject:message-id; bh=i08dYaHI1fvoon+7eeYigKp4zMx+PElqpyXpuKwzxk8=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/embGYYuss6ak1wnwb0KANA/8FHnDgmX1h4 yqoOR7u5/GJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 bdAqD/9H0G93KgtP4UxtzgrruldA6BytJMy0AZ6jAhasSf8Xy51dKJbfJUkHr7TKK2A/9p/lW5m jws0OZ2Jh1HezfvwYd+6NvlKCOa+QGaJnDmH6HqzVpJC2ZlumNgcZ3RNcfpfw+4W+mh6vny5/iZ 0fvgOwqc+HRut7kUs/auiQbJGbqAU2fCfUSdkKIRVUPSgw1nNzJyir+kgdj4l1k5h/xt630UA0E j0CbE9MU7zcmubN03NhUszPfN16ZKJTuxCjS7i2ZjLsnbWNJyzIJ16ILdTbVwPw7Fb2EgLJzFXS 3pIug07eedNDCbACtksMxD1viJqIoeGbS8a+1ltS6rbYv06jp6kghZjmPViI+rTWQrBD79maXZt ZUMgXjcdw+MhWAxCbeLoreCBlQcOKru/nzd/T10zivH86oljN2CnnTDe3s/uUhVqJqmIL5MqaBU WI2IkZreup6BBbcP7ECZFUW9EWEGEdV4JeU02oE/OqL+tucY2LGyeurRFz34tQs+bJl7hepbsO+ 2Z7o3h3vo52+4AEnCR44nK7x6TkZSDgVEF+0/sF2ay4niRqriVVCTDeazUUcTCf2GjooHeBWvt6 yuXaXrYH6gutAekaiv1f3EOttoKg1VkUvmDxRic4Rm1mQq5MbrIAloJxWAKRhUlKq941oiT4yU7 LHTs6WyqCVbzWDQ== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao The bitmap an earlier kernel filled in gets in this one through EFI, but nothing reads it back yet. Introduce range_contains_poisoned_memory(), which the page allocator will use to ask about a block before handing it out. Signed-off-by: Breno Leitao --- drivers/firmware/efi/poison.c | 29 +++++++++++++++++++++++++++++ include/linux/mm.h | 14 ++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/drivers/firmware/efi/poison.c b/drivers/firmware/efi/poison.c index 847592862f01d3..4e5cad0d1b9b65 100644 --- a/drivers/firmware/efi/poison.c +++ b/drivers/firmware/efi/poison.c @@ -101,6 +101,35 @@ static struct linux_efi_poisoned_memory *efi_poisoned_= memory(void) return phys_to_virt(efi.poisoned_memory); } =20 +/* Does the range cover a unit an earlier kernel recorded as bad? */ +bool range_contains_poisoned_memory(phys_addr_t start, unsigned long size) +{ + struct linux_efi_poisoned_memory *pm =3D efi_poisoned_memory(); + u64 first, last, nbits; + phys_addr_t end; + + if (!pm) + return false; + + nbits =3D pm->size * BITS_PER_BYTE; + end =3D start + size - 1; + + /* Clamp the start into the table, but keep the caller's end. */ + if (end < pm->phys_base) + return false; + if (start < pm->phys_base) + start =3D pm->phys_base; + + first =3D (start - pm->phys_base) / pm->unit_size; + if (first >=3D nbits) + return false; + + last =3D (end - pm->phys_base) / pm->unit_size; + last =3D min(last, nbits - 1); + + return find_next_bit(pm->bitmap, last + 1, first) <=3D last; +} + /* * A bit is never cleared: it stands for a whole EFI_POISON_UNIT_SIZE, so = an * unpoison cannot tell whether the unit as a whole is good again. diff --git a/include/linux/mm.h b/include/linux/mm.h index 274fa880077c54..b68824fcfbef19 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -5387,6 +5387,20 @@ static inline bool pfn_is_unaccepted_memory(unsigned= long pfn) return range_contains_unaccepted_memory(pfn << PAGE_SHIFT, PAGE_SIZE); } =20 +#ifdef CONFIG_EFI_POISONED_MEMORY + +bool range_contains_poisoned_memory(phys_addr_t start, unsigned long size); + +#else + +static inline bool range_contains_poisoned_memory(phys_addr_t start, + unsigned long size) +{ + return false; +} + +#endif + void vma_pgtable_walk_begin(struct vm_area_struct *vma); void vma_pgtable_walk_end(struct vm_area_struct *vma); =20 --=20 2.53.0-Meta From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 9796237BE81; Tue, 15 Sep 2026 12:54:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476897; cv=none; b=us0pl3816LYO/342c1NThEsl6sMFQBqMR2un+nyOATymkY1fIM08oaQOmm6YyIhueyVL1Q3bhM9fgTQsFs31NA4kNHtkzjWnxtuOfvJ+LWMgqzLFBHB0cjRJkFIel4mVABY4eWsEGANFQNJ1sh/EWLISJVRf6HnbA/TPbCF8QWk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476897; c=relaxed/simple; bh=T3mL/3Kc07p9K/MT4mso5EEMI4eOaZY0yANJdmvBvvE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZvaRcbzCMceB8IX5K2DpP3lUWsu4SJCjNmKj58AB/wEqG8rhZ+oGVqMxgjRPpoOzZ5P93VA1eUl9QnnTG9gm1JG+oFSOLhjymVR2GWnsQj4y15065UDtPAIhgTGvBGNV+JUDan6WmIREOS0aIjS0+EkaxJ3a7nWzy4JipRuNn6U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=WCLWVJs9; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="WCLWVJs9" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=K8v/C9O0g8FUjKOQ0TaIzosy3/qX+2dVro7BLtwLk5M=; b=WCLWVJs990HuIGJZ4x6CqmQCWg uyMV8BszXqdZPcU9jgOKeQm8wtjSV8Koco5/z+PrAKYJu4BryqdfOOcNsgFsbIgJMWh9EzoXRryPa H7dTU+tzAHUV00L56XsX0kLjyfH7qdxfIFnS2uNKDR7vnMsFW/X10qma/qPFVJbUls3KOTsRRSYWi kdY4yJNGj7qWA6Z4zOqwdLgXUbBfH1qW6X1+qt5nF+zzLWXObNMkHR/QwRo9b84yo5qgY6tyxyext mpraWHuEA0CgqcOfTj+XhyG/sbXtj8oecs4/BXDaT2m7WraT67ft2Vg2EmcfB02x6oJGikzUSrxwr 7ZdSBIaw==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6SgV-004P8h-0Y; Tue, 15 Sep 2026 12:54:51 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:41 -0700 Subject: [PATCH v5 7/9] drivers/base/memory: count inherited poisoned frames into the block Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-7-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=2728; i=leitao@debian.org; h=from:subject:message-id; bh=T3mL/3Kc07p9K/MT4mso5EEMI4eOaZY0yANJdmvBvvE=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/e53Hu0gqe5cHhpqQNe7hv0ZP42+UV0B6bQ Vl11UrXA/WJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 baWYD/9D8jAr4oQzhn8Bl3b7Tmy0SS3Ar8i9wUTDGHUSVH8aR9qkR16ztxsU8oNKXkkIQQVbY6C +h4QevMxbRjtvsOyHkX4Kt8/hP+r9ytz2g7Ak3tWpPL/J3kXu4SrJb5o5hRcVhjXvHpW6HIq3Ws bFRMMbgL6xFVx7f5KFd8vjnYa6UStxqQKihP9INLA+VS4NYodrQCJ7T7q8udy/4fvLq4uT5eYqE HA7DXM5U2+fn5Rg8NKhxjJltesF5EqwqvrJtW8VPYYS6zuuConb9ZqLqsz8EfMSpTa8oliYbe1c TGVWNkeMvmBCRv8HaZYXW5cIVAHOzcf/FveCy7/ZZsi49Vc3IeVgNEr+nJwZaXpEYoieTgE7c6V LxDER8G4X1yzf8uxvPb37xayi4WN5h5/Dg4Ez6bj+3GRWjwWWY3f9PrMP5mhNt4ER9SSqpIASl5 JB2Dd1a1891Yf823Bcovd8GMrQySGGIZVKVSMDcqBgPSLZItIzNFgHMV2peT+GVz/CTiyVvJoBe gVDkX8elv/o9EQAJ91RlR8W/sBlCXJC7iOi7ilK1upHfZAOFdeIBO+dayDenszq6c6rfWbCrW5p 4Q3IQ7FqWebTAaOsGRql4aFJv87VAW7MKQ+gOHvxPtlBXRL2BTAg3au44y9iTOBYqZ8etixQJtO aI8MzCIkOTUGhRw== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao A frame a kexec handed over is flagged as it reaches the allocator, long before its memory block exists, so memblk_nr_poison_inc() had nowhere to count it. Walk the block once when it is created and take the count from the page flag instead. Without it an unpoison later subtracts from a counter that was never incremented and wraps it, which then refuses memory_block_online() for good. Only a block created online needs the walk. A hotplugged one is created before its pages are, so there is nothing to find, and its frames are counted by num_poisoned_pages_inc() as they are flagged. Signed-off-by: Breno Leitao --- drivers/base/memory.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 5eead3346f1e32..49a33ddbb2e717 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -220,11 +220,16 @@ int memory_notify(enum memory_block_state state, void= *v) =20 #if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_MEMORY_HOTPLUG) static unsigned long memblk_nr_poison(struct memory_block *mem); +static void memblk_nr_poison_init(struct memory_block *mem); #else static inline unsigned long memblk_nr_poison(struct memory_block *mem) { return 0; } + +static inline void memblk_nr_poison_init(struct memory_block *mem) +{ +} #endif =20 /* @@ -807,6 +812,7 @@ static int add_memory_block(unsigned long block_id, int= nid, unsigned long state mem->state =3D state; mem->nid =3D nid; INIT_LIST_HEAD(&mem->group_next); + memblk_nr_poison_init(mem); =20 #ifndef CONFIG_NUMA if (state =3D=3D MEM_ONLINE) @@ -1251,4 +1257,33 @@ static unsigned long memblk_nr_poison(struct memory_= block *mem) { return atomic_long_read(&mem->nr_hwpoison); } + +/* + * Frames a kexec handed over are flagged as they reach the allocator, long + * before this block exists, so memblk_nr_poison_inc() had nowhere to count + * them. Take them from the page flag instead. + */ +static void memblk_nr_poison_init(struct memory_block *mem) +{ + unsigned long pfn =3D section_nr_to_pfn(mem->start_section_nr); + unsigned long nr_pages =3D PAGES_PER_SECTION * sections_per_block; + unsigned long i, nr_poison =3D 0; + + /* A hotplugged block is created before its pages are online. */ + if (mem->state !=3D MEM_ONLINE) + return; + + if (!range_contains_poisoned_memory(PFN_PHYS(pfn), + nr_pages << PAGE_SHIFT)) + return; + + for (i =3D 0; i < nr_pages; i++) { + struct page *page =3D pfn_to_online_page(pfn + i); + + if (page && PageHWPoison(page)) + nr_poison++; + } + + atomic_long_set(&mem->nr_hwpoison, nr_poison); +} #endif --=20 2.53.0-Meta From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 07B6538F928; Tue, 15 Sep 2026 12:55:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476905; cv=none; b=meUuURaMsKJDmgo5bkmc0ie3NGoFmYJqI+RNNmqTCdYsL1c7dVhhCsSQqbV7hF5oxy9CbvITo8uEiKO6tmkcD5YBwcwCMJsowp3/PHU+WHsqPzcO6swPfLYrCxjUGL22BymnOt4iolygWE26+d8LarB2Y9aqHshoIbKStcqLK34= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476905; c=relaxed/simple; bh=pkvLVOtl/wJxWCab4MZWos3IO2QmqKMvCWQXOQFBXcc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EHJam23AcUwduOFhu8eoHlwe9PEuWLw16eLwz8Yqiy7s9K+aXQS/Mg7I4tHgBSPUJ5NjzBzK+c06H5mzZwxui9n65lOgcF0/kUgFwkgf4rhsHtuRnbl0QhwrUWn4PWZzxrKjbYCzrf0rUsr1BqbirG3zHsLHkxPKk0PhKQJLV+g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=peho1MiS; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="peho1MiS" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=nJQHvGBJYwJr3F/aktnOoCOR2Bfx83QmvxSaOEex9rc=; b=peho1MiSPxeM5E9y6ZkJnHD3Ac ENhbZZIxpw7yPwYcbEI1X27MJfJtisrsN896BxohWU9hGrJtHupzLBnfbm4DthteXHHreNWnt9Y5C 8QS67ouHGUb8vn4m7JblIDmUdx8G8Tbq1ljQQFyC5VZJH4+0zEoMry+Cg+W+fLVO3JLBqhXxHMz21 G8aYg3DxyZ+70H3BZqt2ucu+76cl8M0D5evcCm2m7AbyGfDpkKcp0ON6jHuIPa1JO41TWuoiDOdJs wCJ2/NXYJ3k2TrxgelPLDMwcY8BwBtdD41XbfHfuA5/SgPYSwl3p+LEVrAnV1biPV8+pa8risBmSL ZygLzG/A==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6Sgc-004P9J-34; Tue, 15 Sep 2026 12:54:59 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:42 -0700 Subject: [PATCH v5 8/9] mm/memory-failure: add hwpoison_boot_page() to flag an inherited frame Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-8-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=3014; i=leitao@debian.org; h=from:subject:message-id; bh=pkvLVOtl/wJxWCab4MZWos3IO2QmqKMvCWQXOQFBXcc=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/ejMXIQjF5HQn3VxXq+6Zy/+n0FqXVKhxTp P11aWC3wMmJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 bY+/EACFlIZZKCGkeF1D4pH+3gCLk17ltEVj4rCRVqtzUt3BEHbKX02a5iBOQC/tfTUtE95ecVK lOWKniPGfAbmnAp2TL4aXXUneo8dI4f/STXSJo9qHWYK/Ry9cDgT1xPzvPYj0YDbdp+okn4MT8e Tuti3cA3W+IdRnIsAuJMv1FoGqcEMrsOKnyyODshHbHg29gADtUKTLc5J7ccFlVbejrCjPHu1lG SboVxR+tnbt3la37O7iBxy8VmdO9Tf69BtvNUmkPuXB452agmhtTAt7EwdfBwIQfmyyrM2yThfP rmqSmnXOL/D9MQFjSABsdm/5MrDZOJ8sBY7xpVhGrpBjiFD9Dp6jWC3wFCfuGlSjhONjnYUb3xT 5J/EuMM2Jg4CJpW9GDxeomC6qbiJXOVuMVdzQfDKMwn7aPdPL2JArr6UkKKVAL7J2eina1oP7Iz Og5kFNxhLig6XpPc//LGzKXEXdCESf6B39F/UKPWabHLHJz9Od9S7Q8eNl5KmGoUrANCyGOQvzE cKokqpD7Cz/cXHDBief0J6Y3wE/JnD7y0D6fpIYHs/K5GKXf4j+oyf+LEhf0EsjKhRm8GMFXP88 Nk20+jo7Z/87cujzF69coCuRzBORUnpsor0dJA+DFLKUabKCfDz/ikqi6sCv6YCO1fAnwSKgakI RD8ZDEpMLOGVIkQ== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao A frame the previous kernel recorded as poisoned has to be flagged before it reaches the allocator, which is long before memory_failure() can run. Add a helper that leaves it in the state a frame poisoned by this kernel would be in, so everything that already understands PG_hwpoison covers it, the kexec segment placement check included. num_poisoned_pages_inc() does not work at boot: its per memory block half looks the block up by pfn, and memory_dev_init() has not run, so it divides by zero. Take only the global counter there. A hotplugged block is already there, so that path takes both counters as usual. The caller comes later in this series. Signed-off-by: Breno Leitao --- include/linux/mm.h | 7 +++++++ mm/memory-failure.c | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index b68824fcfbef19..8039830998dd4b 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -5225,6 +5225,8 @@ extern const struct attribute_group memory_failure_at= tr_group; extern void memory_failure_queue(unsigned long pfn, int flags); void num_poisoned_pages_inc(unsigned long pfn); void num_poisoned_pages_sub(unsigned long pfn, long i); +void __meminit hwpoison_boot_page(struct page *page, + enum meminit_context context); phys_addr_t range_first_hwpoison(phys_addr_t start, unsigned long size); phys_addr_t range_last_hwpoison(phys_addr_t start, unsigned long size); #else @@ -5232,6 +5234,11 @@ static inline void memory_failure_queue(unsigned lon= g pfn, int flags) { } =20 +static inline void hwpoison_boot_page(struct page *page, + enum meminit_context context) +{ +} + static inline void num_poisoned_pages_inc(unsigned long pfn) { } diff --git a/mm/memory-failure.c b/mm/memory-failure.c index d9b8be696aac38..60e9682434700b 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -137,6 +137,32 @@ phys_addr_t range_last_hwpoison(phys_addr_t start, uns= igned long size) return range_hwpoison(start, size, false); } =20 +static void update_per_node_mf_stats(unsigned long pfn, enum mf_result res= ult); + +void __meminit hwpoison_boot_page(struct page *page, + enum meminit_context context) +{ + unsigned long pfn =3D page_to_pfn(page); + + if (PageHWPoison(page)) + return; + + SetPageHWPoison(page); + set_page_count(page, 1); + /* The page has been completely isolated =3D=3D MF_RECOVERED */ + update_per_node_mf_stats(pfn, MF_RECOVERED); + + /* + * The per memory block half of num_poisoned_pages_inc() has no block to + * find at boot, and divides by zero looking for one. A hotplugged block + * is already there. + */ + if (context =3D=3D MEMINIT_HOTPLUG) + num_poisoned_pages_inc(pfn); + else + atomic_long_inc(&num_poisoned_pages); +} + /** * MF_ATTR_RO - Create sysfs entry for each memory failure statistics. * @_name: name of the file in the per NUMA sysfs directory. --=20 2.53.0-Meta From nobody Fri Sep 25 07:22:58 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 8EBFA3B058F; Tue, 15 Sep 2026 12:55:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476913; cv=none; b=rUk+jZntBgMf6Z28KiSiJNizF73f8j+UckzBtpG5ALOuVRCas0E8EfTIzSCfBvZUl/OfWxy3UfnxyDhQN29UsG5dil3dEu7Vzxo/4VmKWd+ZJt1oxxxfMbBLkATH7Sqf0tMLI3F6tYn2Y/cOYQ7G7hk891WcfzR0eNWl69SOw40= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789476913; c=relaxed/simple; bh=4RHv2TayObkVu1Jypz4zcft6A7ZuNLPLOYHN84tQgBw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fAubvWLeUBqlKoYfhf+Q4ds6P+fzB2biDJvsgNwJxc166xYOZ8Y3OYzCjp/PQNapEzVrfJg1H+B5ByajfUpcXQjMPtXdB8Kkd4g5xQMwjcOqkTRbO8O2VmUBPEF4haj3Wd0PIZQ8zIx/PekC1ie3otE4sz8XxzyxPAA5wxdoUhs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=jjRG63PV; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="jjRG63PV" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=m/nkeRu2bKSmAi9Kfn/9bTVutjRevdYEH4ZRY/DxYx8=; b=jjRG63PVcCTPlnZu0EydQH6jUd EYH8/bn9jdy5AWDlRoLf7iD89DjjfwIQAGfuojuTPEskJprAuvanYlTK5R95nqfME/mvW/9LpLmS8 U4zPpj7h99Y+LbhtfppTBy6GTB9MGjlO2Y/FWqQeavpXMMZwRh1BnzrYDu7xzElaqH00l+Cb6+16W 3y9zzFaFTJnmobPEY+7/kHb4qr7wXmLMDCPbjq2EXLHLEx6rtGjPJxT+d8gBUOFeL6TJ9SEh8td+5 s8S2vc4183hCzl6wkeyCVGezw31O4/b29yfMLQQQomllGczRwoAI84j4GEGlbewvgYf3F/Tskkw7Y UImVzECg==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x6Sgk-004P9q-1G; Tue, 15 Sep 2026 12:55:06 +0000 From: Breno Leitao Date: Tue, 15 Sep 2026 05:53:43 -0700 Subject: [PATCH v5 9/9] mm/memory-failure: keep inherited poisoned frames out of the buddy allocator Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260915-hwpoison-kho-v5-9-3bc7a57bd503@debian.org> References: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> In-Reply-To: <20260915-hwpoison-kho-v5-0-3bc7a57bd503@debian.org> To: Ard Biesheuvel , Ilias Apalodimas , Miaohe Lin , Naoya Horiguchi , Andrew Morton , kas@kernel.org, kexec@lists.infradead.org, David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Brendan Jackman , Johannes Weiner , Zi Yan , Oscar Salvador , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , hannes@cmpxchg.or, shakeel.butt@linux.dev Cc: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, rmikey@meta.com, riel@surriel.com, Breno Leitao , harry@kernel.org, linux-cxl@vger.kernel.org, driver-core@lists.linux.dev, kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=2342; i=leitao@debian.org; h=from:subject:message-id; bh=4RHv2TayObkVu1Jypz4zcft6A7ZuNLPLOYHN84tQgBw=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqqT/eICMsY4l6GHi03IIM8MfD8gNmgSWIlOY/K iWYaIFog0yJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqk/3gAKCRA1o5Of/Hh3 beArD/91EKxjfaH0PJcX5tV47c0OR63POIWuptnAdq2ZMAnwIyJuXdqccB0buApoQ+unH4Fz1yM DgN18xOTuIUyU4w2lOzhj9QGuc0jLQ/Y3aYjxgPqrpP/hZXsqpiLQl+8MrFbwZ5+5tUkPvjsqQU qXDCQi+HyxPG8h/97OAnvi4goH90bAGaxUY66I8c6RW/HUHAjvqdwARlIw97g1dDHkfg5mTBkXE 8EJdEjolj8X+Ne2bnEi/Wq2ydA6G9AePNg9pQ77bCq/P7+FOHWb1V9MKG/QbKTxFTMeVTCNDDZM HAE4OH+PATf67ofo+M7M4prlAwL8mRo0yfy2b+Sr9vGnO8zQIP+uRFW16H2+gCG6YNG8p8hx0wT DwUkPP5ltN6k4hf+q3jtnfQkb6WZUz5hwMY2kO5rYUWawRGll8yckWmSJfXCpADIcJxmMyBrsf+ 6L/mnF8ZmuzDsXZzswJvd9p1wc6Xeoh28jDinPgcKPYZmJj+gDaQf5fFJtUR/cSec3NMHcXv7Ma bkIKRrFMIQUqgyGfcEHuEtaN9IN+j3B/ZgDwUi/VF8P01m41M34JETR0uq86SpTzoojGjWAOMO0 9vHeBTxiNOHq3jfx0SPr6Hu1CPuws7AAunT4VHmB1D6vqXgFHCtZKtQSmiWpnNjVA8kaQo6+/7e 3q2cuVbNVfB9iYw== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao When the pages are being given to the allocator, check if they are poisoned, and mark them as such. Similar to unaccepted memory, hook it in __free_pages_core(), and thus the frames never enter the allocator, rather than being taken back out of it. A block runs up to MAX_PAGE_ORDER and a unit is 2MB, so hold back only the frames the table covers and free the rest one at a time. The allocator merges them back up, so a unit costs the frames it names, not the whole block. The frames that are freed go back through accept_and_free_block(), so a clean frame in a block that is still unaccepted is accepted first. A frame is flagged before its memory block exists, so the per block counter is seeded from the page flag when the block is created rather than incremented here. Suggested-by: Kiryl Shutsemau Signed-off-by: Breno Leitao Acked-by: Vlastimil Babka (SUSE) --- mm/page_alloc.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index b07b5f4751cb95..cca67a2702a421 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1597,6 +1597,25 @@ static void __meminit accept_and_free_block(struct p= age *page, __free_pages_ok(page, order, FPI_TO_TAIL); } =20 +static void __meminit free_poisoned_block(struct page *page, unsigned int = order, + enum meminit_context context) +{ + unsigned long i, nr_pages =3D 1UL << order; + + for (i =3D 0; i < nr_pages; i++) { + struct page *p =3D page + i; + phys_addr_t phys =3D page_to_phys(p); + + if (range_contains_poisoned_memory(phys, PAGE_SIZE)) { + hwpoison_boot_page(p, context); + continue; + } + + /* this part of the block is not poisoned */ + accept_and_free_block(p, 0); + } +} + void __meminit __free_pages_core(struct page *page, unsigned int order, enum meminit_context context) { @@ -1631,6 +1650,13 @@ void __meminit __free_pages_core(struct page *page, = unsigned int order, atomic_long_add(nr_pages, &page_zone(page)->managed_pages); } =20 + /* First: a block parked by __free_unaccepted() never returns here. */ + if (range_contains_poisoned_memory(page_to_phys(page), + PAGE_SIZE << order)) { + free_poisoned_block(page, order, context); + return; + } + accept_and_free_block(page, order); } =20 --=20 2.53.0-Meta