From patchwork Thu Aug 28 02:07:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 159 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756346896; bh=hlon67LNBzK1Zo4RaW2QtgyKunlikCdowyoSXxuoTmA=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=IZuI0KHKEiaRPRqxdapu7aUSTlqvBvkAnwYAcwhCv2VFgPECEOyA59CI8y+ugw3d/ hNtOTRtVm5CB24YcQpVbQq3d1Krnv+1Pm9HcPqjCLfhg04TIljAy7eeb2HEJFbSmmA 9Yxe4RFKGffHQ6D/aSLvFWxVTQQsBBooSnwePjbeNuEyRH+z4X7SR9gTvoTvCpUCQZ 14NV5IDPhdkwgq3bqwB1HvdRWm7q1Y2U4ILzBStVCG3sbMWVBAcIKA3pv/1bsh+CrH /NnEdiqcGEqX/mx99qWmJb7i1tQRkox9RK2HBe91MuWkuSckxCHtjGP3DLZDlHg9iR 9wCpki/DG8tDg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B70E1677B6 for ; Wed, 27 Aug 2025 20:08:16 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id ZtzOB4Cq4Z2u for ; Wed, 27 Aug 2025 20:08:16 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756346896; bh=hlon67LNBzK1Zo4RaW2QtgyKunlikCdowyoSXxuoTmA=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=IZuI0KHKEiaRPRqxdapu7aUSTlqvBvkAnwYAcwhCv2VFgPECEOyA59CI8y+ugw3d/ hNtOTRtVm5CB24YcQpVbQq3d1Krnv+1Pm9HcPqjCLfhg04TIljAy7eeb2HEJFbSmmA 9Yxe4RFKGffHQ6D/aSLvFWxVTQQsBBooSnwePjbeNuEyRH+z4X7SR9gTvoTvCpUCQZ 14NV5IDPhdkwgq3bqwB1HvdRWm7q1Y2U4ILzBStVCG3sbMWVBAcIKA3pv/1bsh+CrH /NnEdiqcGEqX/mx99qWmJb7i1tQRkox9RK2HBe91MuWkuSckxCHtjGP3DLZDlHg9iR 9wCpki/DG8tDg== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 95D0B6777A for ; Wed, 27 Aug 2025 20:08:16 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756346894; bh=XqONq9aPipkpZICfXhHcjP18+OjmWFHSk2gze8nWTsQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dHZ5K6aupyDMs1PJ7sc6P+zlspo5UTl5dlW6Nv8rH/IJxAj4Xq8+m7lknHeAna/oi diqYHMhpbSEipwFQLgZ5PEzscgUZQASBplesR722vdtP7fOHPegAiN08xa/D0CNZw7 PNMYgBe6HQQOrg3b8hS3ZtNR8Ntb5RA7eyNuuPtvzrhca7r03DxToUam6wOjLI6gXG H3QEPimLv/LwRkzLGtPALrcangK99buKq/rhEvvJRoILUMHsSkLgj0n1hHRciQ8SCm JEejpKumfAxwSPZVPC2qVcq78I8HmwNs5M/rOLYdKPqjedd4M1AvpilBVMubV6KFTp vENBV1JzK2IbA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7CB796776F; Wed, 27 Aug 2025 20:08:14 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id Ja1N9wohMJMI; Wed, 27 Aug 2025 20:08:14 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756346890; bh=AjZydVfi0wQEywkR9uKesm/mv6oiiHeZ+iPbj4ZV1O4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k+sVi0KJklxZ1JpI1y/OqdJT/aakc6JGUoxc4AxvPierxolnxwblzppH+bmtSgi4p ixHr7Q0lml3hHj6Pl/jPC5sAjpGXu5lMKTPYtg0nq4lwEL44ZK1b2zzM+wq+Fw6B2C 4cWbREMULKkG+Yku9BwxozOB/IM/owXTrpg6jluOxct/86Zw6G9lHF3mvSNm3QVNf/ 1uO0M3zvaMavKBD63knsuk3qcwRkHX3fz7azw1C41+nvBgO23CUp111SayZbdWja7Y lKFyfWfbQzlKcayU9n/vKAK8jErDcuAWP86ppVfhuUud1k94fxo3a5StexoLVVcB1R ohBinVVXzt0hA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id EB0FB67833; Wed, 27 Aug 2025 20:08:09 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Wed, 27 Aug 2025 20:07:20 -0600 Message-ID: <20250828020732.981415-18-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250828020732.981415-1-sjg@u-boot.org> References: <20250828020732.981415-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 3KPUNKP35AKKILLVENOSH3NHHBA4UTYE X-Message-ID-Hash: 3KPUNKP35AKKILLVENOSH3NHHBA4UTYE X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 17/20] efi: Provide a way to sync EFI reserved-memory to fdt List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass When booting Linux with EFI the devicetree memory-map is ignored and Linux calls through EFI to obtain the real memory map. When booting Linux from the EFI app, without EFI, we must pass the reserved memory onto Linux using the devicetree. Add a function to support this. It reads the EFI memory-map and adds any missing regions to the reserved-memory node. Co-developed-by: Claude Signed-off-by: Simon Glass --- include/efi.h | 16 +++ lib/efi_client/efi.c | 249 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 263 insertions(+), 2 deletions(-) diff --git a/include/efi.h b/include/efi.h index 530b127bde4..b3f9c0b694f 100644 --- a/include/efi.h +++ b/include/efi.h @@ -794,6 +794,22 @@ static inline bool efi_mem_is_boot_services(int type) */ const char *efi_mem_type_name(enum efi_memory_type type); +/** + * efi_mem_reserved_sync() - Sync EFI memory map with DT reserved-memory nodes + * + * This function compares the EFI memory map with the device tree's reserved-memory + * nodes and prints out regions that are reserved in EFI but not mentioned in the + * device tree's /reserved-memory node. This helps identify memory regions that + * EFI considers reserved but which Linux might try to use. + * + * Note: This only works with #address-cells and #size-cells of 2 + * + * @fdt: Pointer to the device tree blob + * @verbose: If true, show detailed output; if false, only show errors + * Return: Number of regions synced, or -ve on error + */ +int efi_mem_reserved_sync(void *fdt, bool verbose); + /** * efi_dump_mem_table() - Dump out the EFI memory map * diff --git a/lib/efi_client/efi.c b/lib/efi_client/efi.c index 12a646a36b7..9d064484dbf 100644 --- a/lib/efi_client/efi.c +++ b/lib/efi_client/efi.c @@ -13,10 +13,13 @@ #include #include #include -#include -#include #include #include +#include +#include +#include +#include +#include enum { /* magic number to trigger gdb breakpoint */ @@ -213,3 +216,245 @@ uint16_t *efi_dp_str(struct efi_device_path *dp) return val; } + +/** + * is_reserved() - Check if EFI memory type should be preserved + * + * @type: EFI memory type + * Return: true if memory type should be preserved, false otherwise + */ +static bool is_reserved(u32 type) +{ + switch (type) { + case EFI_RESERVED_MEMORY_TYPE: + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_UNUSABLE_MEMORY: + case EFI_ACPI_RECLAIM_MEMORY: + case EFI_ACPI_MEMORY_NVS: + return true; + default: + return false; + } +} + +/** + * dt_region_exists() - Check if memory region is covered by DT reserved-memory + * + * @fdt: Device tree blob + * @start: Start address of region to check + * @end: End address of region to check + * Return: true if region overlaps with any reserved-memory node, else false + */ +static bool dt_region_exists(void *fdt, u64 start, u64 end) +{ + int node, reserved; + + reserved = fdt_path_offset(fdt, "/reserved-memory"); + if (reserved < 0) + return false; + + fdt_for_each_subnode(node, fdt, reserved) { + const fdt32_t *reg; + u64 start, size, end; + int len; + + reg = fdt_getprop(fdt, node, "reg", &len); + if (!reg || len < sizeof(u32) * 2) + continue; + + /* Parse reg property - assuming #address-cells=2, #size-cells=2 */ + start = fdt64_to_cpu(*(fdt64_t *)reg); + size = fdt64_to_cpu(*((fdt64_t *)reg + 1)); + end = start + size - 1; + + /* Check for overlap */ + if (!(end < start || start > end)) + return true; + } + + return false; +} + +/** + * dt_add_reserved() - Add EFI reserved region to device tree reserved-memory + * + * @fdt: Device tree blob + * @start: Start address of region + * @size: Size of region + * @type_name: EFI memory type name for node naming + * Return: 0 on success, negative error code on failure + */ +static int dt_add_reserved(void *fdt, u64 start, u64 size, + const char *type_name) +{ + int reserved, node; + char node_name[64]; + fdt32_t reg_prop[4]; + char *p; + int ret; + + /* Find or create /reserved-memory node */ + reserved = fdt_path_offset(fdt, "/reserved-memory"); + if (reserved < 0) { + /* Create /reserved-memory node */ + reserved = fdt_add_subnode(fdt, 0, "reserved-memory"); + if (reserved < 0) { + printf("Failed to create /reserved-memory node: %s\n", + fdt_strerror(reserved)); + return reserved; + } + + ret = fdt_setprop_u64(fdt, reserved, "#address-cells", 2); + if (ret) + return ret; + + ret = fdt_setprop_u64(fdt, reserved, "#size-cells", 2); + if (ret) + return ret; + + ret = fdt_setprop(fdt, reserved, "ranges", NULL, 0); + if (ret) + return ret; + } + + /* Create node name based on type and address */ + snprintf(node_name, sizeof(node_name), "efi-%s@%llx", type_name, start); + + /* Convert spaces and underscores to hyphens for a valid node name */ + for (p = node_name; *p; p++) { + if (*p == ' ' || *p == '_') + *p = '-'; + } + + /* Add new subnode */ + node = fdt_add_subnode(fdt, reserved, node_name); + if (node < 0) { + printf("Failed to create node %s: %s\n", node_name, + fdt_strerror(node)); + return node; + } + + /* Set reg property - #address-cells=2, #size-cells=2 */ + reg_prop[0] = cpu_to_fdt32(start >> 32); + reg_prop[1] = cpu_to_fdt32(start & 0xffffffff); + reg_prop[2] = cpu_to_fdt32(size >> 32); + reg_prop[3] = cpu_to_fdt32(size & 0xffffffff); + + ret = fdt_setprop(fdt, node, "reg", reg_prop, sizeof(reg_prop)); + if (ret) { + printf("Failed to set reg property: %s\n", fdt_strerror(ret)); + return ret; + } + + /* Add no-map property to prevent Linux from using this memory */ + ret = fdt_setprop(fdt, node, "no-map", NULL, 0); + if (ret) { + printf("Failed to set no-map property: %s\n", + fdt_strerror(ret)); + return ret; + } + + printf("added reserved-memory node: %s (0x%llx - 0x%llx)\n", + node_name, start, start + size - 1); + + return 0; +} + +/** + * sync_to_dt() - Print EFI reserved regions and add missing ones to DT + * + * @fdt: Device tree blob + * Return: true if any uncovered regions found, false otherwise + */ +static int sync_to_dt(void *fdt, bool verbose) +{ + struct efi_mem_desc *map, *desc, *end; + int desc_size, size, upto; + uint version, key; + int synced = 0; + int ret; + + /* Get the EFI memory map */ + ret = efi_get_mmap(&map, &size, &key, &desc_size, &version); + if (ret) { + printf("Failed to get EFI memory map: %d\n", ret); + return ret; + } + + if (verbose) { + printf("EFI Memory Map Analysis:\n"); + printf("%-4s %-18s %-18s %-18s %s\n", "ID", "Type", "Start", + "End", "In DT?"); + printf("-------------------------------------------------------" + "-----------------\n"); + } + + end = (void *)map + size; + for (upto = 0, desc = map; desc < end; + desc = efi_get_next_mem_desc(desc, desc_size), upto++) { + u64 start = desc->physical_start; + u64 end_addr = start + (desc->num_pages << EFI_PAGE_SHIFT) - 1; + u64 region_size = desc->num_pages << EFI_PAGE_SHIFT; + bool present; + + if (!is_reserved(desc->type)) + continue; + + present = dt_region_exists(fdt, start, end_addr); + + /* Print the region */ + if (verbose) { + printf("%-4d %-18s 0x%-16llx 0x%-16llx %s", upto, + efi_mem_type_name(desc->type), start, end_addr, + present ? "yes" : "no"); + } + + if (!present) { + const char *type_name; + int ret; + + if (verbose) + printf(" -> adding\n"); + + /* Add this region to device tree */ + type_name = efi_mem_type_name(desc->type); + ret = dt_add_reserved(fdt, start, region_size, + type_name); + if (ret) { + printf("Failed to add region: %s\n", + fdt_strerror(ret)); + free(map); + return ret; + } + synced++; + } else if (verbose) { + printf("\n"); + } + } + free(map); + + return synced; +} + +int efi_mem_reserved_sync(void *fdt, bool verbose) +{ + int synced; + + if (verbose) + printf("Comparing EFI memory-map with reserved-memory\n"); + + synced = sync_to_dt(fdt, verbose); + if (synced < 0) { + printf("Failed to sync EFI reserved regions: error %d\n", + synced); + return synced; + } + + if (verbose) { + printf("Regions added: %d\n", synced); + fdt_print_reserved(fdt); + } + + return synced; +}