From patchwork Wed Sep 2 15:45:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geert Uytterhoeven X-Patchwork-Id: 11751059 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2F40E138A for ; Wed, 2 Sep 2020 15:46:04 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (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 027A4204FD for ; Wed, 2 Sep 2020 15:46:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="1caVnnDF" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 027A4204FD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=glider.be Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Owner; bh=zKSIDP6Fct5tZuuSBbOC7EVeJCHkcOrcFs+yaWfbSBo=; b=1caVnnDFqQs72LUIMXrqKFhJ1W uDMRjTdB1y+6vckAKsegbK8PIlxPzQKTOU/bkgGCg828Y5kESCJcKLJOyfon9x5f7bY09tmIBpXeq dUY3BbBlx4tpJDyFci3zzi3PKpaw52eyhEmSDONiRVPI/sU8jwA/rBQvm9VHv6r/TFzbTtTQI8+0H 0XZJSG+4impa6+Gmck0OEeQoO0WiXyD0/72YXG8Zxl7UQiqIzj6EMUc4sjehOyuhP8B1B99CGLq8q 1U554gF8INCGtG25ql3jBTcVmLUu2ZYY8tAq+zE+PlESRH0qhyVrXlO7L+G8gMipP0+1w8vzoqc9i H9NOLJmQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kDUxO-0008JR-03; Wed, 02 Sep 2020 15:45:54 +0000 Received: from michel.telenet-ops.be ([2a02:1800:110:4::f00:18]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kDUxK-0008Hp-3J for linux-arm-kernel@lists.infradead.org; Wed, 02 Sep 2020 15:45:51 +0000 Received: from ramsan ([84.195.186.194]) by michel.telenet-ops.be with bizsmtp id P3lg2300P4C55Sk063lhm2; Wed, 02 Sep 2020 17:45:48 +0200 Received: from rox.of.borg ([192.168.97.57]) by ramsan with esmtp (Exim 4.90_1) (envelope-from ) id 1kDUxA-0006dV-SC; Wed, 02 Sep 2020 17:45:40 +0200 Received: from geert by rox.of.borg with local (Exim 4.90_1) (envelope-from ) id 1kDUxA-0001mW-QF; Wed, 02 Sep 2020 17:45:40 +0200 From: Geert Uytterhoeven To: Dmitry Osipenko , Nicolas Pitre , Arnd Bergmann , Eric Miao , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Lukasz Stelmach Subject: [PATCH] ARM: Parse kdump DT properties Date: Wed, 2 Sep 2020 17:45:38 +0200 Message-Id: <20200902154538.6807-1-geert+renesas@glider.be> X-Mailer: git-send-email 2.17.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200902_114550_308319_9AEA825D X-CRM114-Status: GOOD ( 26.47 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [2a02:1800:110:4:0:0:f00:18 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Geert Uytterhoeven , kexec@lists.infradead.org, Russell King , linux-renesas-soc@vger.kernel.org, Akashi Takahiro , Simon Horman , Ard Biesheuvel , linux-arm-kernel@lists.infradead.org, Marek Szyprowski MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Parse the following DT properties in the crash dump kernel, to provide a modern interface between kexec and the crash dump kernel: - linux,elfcorehdr: ELF core header segment, similar to the "elfcorehdr=" kernel parameter. - linux,usable-memory-range: Usable memory reserved for the crash dump kernel. This makes the memory reservation explicit. If present, Linux no longer needs to mask the program counter, and rely on the "mem=" kernel parameter to obtain the start and size of usable memory. For backwards compatibility, the traditional method to derive the start of memory is still used if "linux,usable-memory-range" is absent, and the "elfcorehdr=" and "mem=" kernel parameters are still parsed. Loosely based on the ARM64 version by Akashi Takahiro. Signed-off-by: Geert Uytterhoeven --- This depends on "[PATCH v9] ARM: boot: Validate start of physical memory against DTB" (https://lore.kernel.org/r/20200902153606.13652-1-geert+renesas@glider.be) The counterpart patch for kexec-tools is "PATCH] arm: kdump: Add DT properties to crash dump kernel's DTB" (https://lore.kernel.org/r/20200902154129.6358-1-geert+renesas@glider.be) Documentation/devicetree/bindings/chosen.txt | 4 +- arch/arm/boot/compressed/fdt_get_mem_start.c | 18 +++- arch/arm/mm/init.c | 90 ++++++++++++++++++++ 3 files changed, 107 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt index 45e79172a646c537..ba75c58413667760 100644 --- a/Documentation/devicetree/bindings/chosen.txt +++ b/Documentation/devicetree/bindings/chosen.txt @@ -79,7 +79,7 @@ a different secondary CPU release mechanism) linux,usable-memory-range ------------------------- -This property (arm64 only) holds a base address and size, describing a +This property (arm and arm64 only) holds a base address and size, describing a limited region in which memory may be considered available for use by the kernel. Memory outside of this range is not available for use. @@ -106,7 +106,7 @@ respectively, of the root node. linux,elfcorehdr ---------------- -This property (currently used only on arm64) holds the memory range, +This property (currently used only on arm and arm64) holds the memory range, the address and the size, of the elf core header which mainly describes the panicked kernel's memory layout as PT_LOAD segments of elf format. e.g. diff --git a/arch/arm/boot/compressed/fdt_get_mem_start.c b/arch/arm/boot/compressed/fdt_get_mem_start.c index fd501ec3c14b4ae4..344fee8bfc7ab438 100644 --- a/arch/arm/boot/compressed/fdt_get_mem_start.c +++ b/arch/arm/boot/compressed/fdt_get_mem_start.c @@ -40,7 +40,7 @@ static uint32_t get_size(const void *fdt, const char *name) unsigned long fdt_get_mem_start(const void *fdt) { uint32_t addr_size, size_size, mem_start, masked_pc; - const __be32 *memory; + const __be32 *usable, *memory; if (!fdt) return -1; @@ -52,8 +52,16 @@ unsigned long fdt_get_mem_start(const void *fdt) addr_size = get_size(fdt, "#address-cells"); size_size = get_size(fdt, "#size-cells"); - /* Find the first memory node */ - memory = get_prop(fdt, "/memory", "reg", addr_size + size_size); + /* + * Find start of memory, either from "linux,usable-memory-range" (for + * crashkernel), or from the first memory node + */ + usable = get_prop(fdt, "/chosen", "linux,usable-memory-range", + addr_size + size_size); + if (usable) + memory = usable; + else + memory = get_prop(fdt, "/memory", "reg", addr_size + size_size); if (!memory) return -1; @@ -62,6 +70,10 @@ unsigned long fdt_get_mem_start(const void *fdt) /* Must be a multiple of 16 MiB for phys/virt patching */ mem_start = round_up(mem_start, SZ_16M); + /* "linux,usable-memory-range" is considered authoritative */ + if (usable) + return mem_start; + /* * Traditionally, the start of memory is obtained by masking the * program counter. Prefer that method, unless it would yield an diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 000c1b48e9734f4e..407fd847dbfc9280 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -4,6 +4,7 @@ * * Copyright (C) 1995-2005 Russell King */ +#include #include #include #include @@ -210,8 +211,95 @@ void check_cpu_icache_size(int cpuid) } #endif +#ifdef CONFIG_OF_EARLY_FLATTREE +static int __init early_init_dt_scan_usablemem(unsigned long node, + const char *uname, int depth, void *data) +{ + struct memblock_region *usablemem = data; + const __be32 *reg; + int len; + + if (depth != 1 || strcmp(uname, "chosen") != 0) + return 0; + + reg = of_get_flat_dt_prop(node, "linux,usable-memory-range", &len); + if (!reg || (len < (dt_root_addr_cells + dt_root_size_cells))) + return 1; + + usablemem->base = dt_mem_next_cell(dt_root_addr_cells, ®); + usablemem->size = dt_mem_next_cell(dt_root_size_cells, ®); + return 1; +} + +static void __init fdt_enforce_memory_region(void) +{ + struct memblock_region reg = { + .size = 0, + }; + + of_scan_flat_dt(early_init_dt_scan_usablemem, ®); + + if (reg.size) + memblock_cap_memory_range(reg.base, reg.size); +} + +#else +static inline void fdt_enforce_memory_region(void) { } +#endif + +#if defined(CONFIG_CRASH_DUMP) && defined(CONFIG_OF_EARLY_FLATTREE) +static int __init early_init_dt_scan_elfcorehdr(unsigned long node, + const char *uname, int depth, void *data) +{ + const __be32 *reg; + int len; + + if (depth != 1 || strcmp(uname, "chosen") != 0) + return 0; + + reg = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len); + if (!reg || (len < (dt_root_addr_cells + dt_root_size_cells))) + return 1; + + elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, ®); + elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, ®); + return 1; +} + +/* + * reserve_elfcorehdr() - reserves memory for elf core header + * + * This function reserves the memory occupied by an elf core header + * described in the device tree. This region contains all the + * information about primary kernel's core image and is used by a dump + * capture kernel to access the system memory on primary kernel. + */ +static void __init reserve_elfcorehdr(void) +{ + of_scan_flat_dt(early_init_dt_scan_elfcorehdr, NULL); + + if (!elfcorehdr_size) + return; + + if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) { + pr_warn("elfcorehdr is overlapped\n"); + return; + } + + memblock_reserve(elfcorehdr_addr, elfcorehdr_size); + + pr_info("Reserving %llu KiB of memory at 0x%llx for elfcorehdr\n", + elfcorehdr_size >> 10, elfcorehdr_addr); +} +#else +static inline void reserve_elfcorehdr(void) { } +#endif + void __init arm_memblock_init(const struct machine_desc *mdesc) { + /* Handle linux,usable-memory-range property */ + fdt_enforce_memory_region(); + /* Register the kernel text, kernel data and initrd with memblock. */ memblock_reserve(__pa(KERNEL_START), KERNEL_END - KERNEL_START); @@ -226,6 +314,8 @@ void __init arm_memblock_init(const struct machine_desc *mdesc) early_init_fdt_reserve_self(); early_init_fdt_scan_reserved_mem(); + reserve_elfcorehdr(); + /* reserve memory for DMA contiguous allocations */ dma_contiguous_reserve(arm_dma_limit);