From patchwork Sat Oct 10 02:01:41 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: yalin wang X-Patchwork-Id: 7365321 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 831D7BEEA4 for ; Sat, 10 Oct 2015 02:04:20 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 81958208CD for ; Sat, 10 Oct 2015 02:04:19 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8B219208C4 for ; Sat, 10 Oct 2015 02:04:18 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZkjUM-00006j-Je; Sat, 10 Oct 2015 02:02:22 +0000 Received: from mail-pa0-x22e.google.com ([2607:f8b0:400e:c03::22e]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZkjUJ-0008Th-NW for linux-arm-kernel@lists.infradead.org; Sat, 10 Oct 2015 02:02:20 +0000 Received: by padhy16 with SMTP id hy16so101498673pad.1 for ; Fri, 09 Oct 2015 19:01:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id; bh=geGeePBT0Yd1BJtW1lizQYnv1pe1mAPlOX9uEeFdYbI=; b=1DifKpDDDR54kN13g40OOD2WQQhLIzHAuqYjmoymIki7CvvdbmQaIe9RCp4g6g4u3M Eu+rmX3cF8WZ+3F/aLEACD7NmHNNXU/9MdP6Vq6HKZIIlQIMHVuQEWd0YaSqhmYwaoO6 W5HgB2izATDOu1dAi7qXNxTmvDnWdiCXHok2TRF0RQXp0zMH8mizPuoVosFx2DSM4lFd 4CTUPLp5oz7kLY/rSxjD+J+XKdNwfeamLSQd6J3995mYSy/C0ESWDi5cpXfJ88p5nhX2 I5lZNgTsnomclqz0r7d3ZQYIzLTNMrqeyjhPvnBF19f01RYw7qmlOzfxAvuG78AO3WJH zUPg== X-Received: by 10.68.190.105 with SMTP id gp9mr19218315pbc.152.1444442517413; Fri, 09 Oct 2015 19:01:57 -0700 (PDT) Received: from ubuntu.localdomain ([17.87.20.100]) by smtp.googlemail.com with ESMTPSA id or6sm4914847pac.32.2015.10.09.19.01.50 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 09 Oct 2015 19:01:56 -0700 (PDT) From: yalin wang To: linux@arm.linux.org.uk, grant.likely@linaro.org, dt@kernel.org, keescook@chromium.org, nico@linaro.org, rabin@rab.in, yalin.wang2010@gmail.com, msalter@redhat.com, stefan@agner.ch, ard.biesheuvel@linaro.org, will.deacon@arm.com, ian.campbell@citrix.com, contact@paulk.fr, pavel@ucw.cz, slash.tmp@free.fr, yamada.m@jp.panasonic.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Subject: [RFC V2] arm: add relocate initrd support Date: Sat, 10 Oct 2015 10:01:41 +0800 Message-Id: <1444442501-17245-1-git-send-email-yalin.wang2010@gmail.com> X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151009_190219_821424_99206543 X-CRM114-Status: GOOD ( 17.84 ) X-Spam-Score: -2.5 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for initrd on ARM arch, in case mem= boot option change the memory size or the initrd are not placed in low memory region, we need copy the initrd to low memory region. Signed-off-by: yalin wang --- arch/arm/include/asm/fixmap.h | 1 + arch/arm/kernel/setup.c | 70 +++++++++++++++++++++++++++++++++++++++++++ drivers/of/fdt.c | 2 ++ include/linux/initrd.h | 1 + init/do_mounts_initrd.c | 2 ++ 5 files changed, 76 insertions(+) diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h index 58cfe9f..18ad90f 100644 --- a/arch/arm/include/asm/fixmap.h +++ b/arch/arm/include/asm/fixmap.h @@ -10,6 +10,7 @@ enum fixed_addresses { FIX_EARLYCON_MEM_BASE, + FIX_RELOCATE_INITRD, __end_of_permanent_fixed_addresses, FIX_KMAP_BEGIN = __end_of_permanent_fixed_addresses, diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 20edd34..036473b 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -811,6 +811,75 @@ static void __init request_standard_resources(const struct machine_desc *mdesc) request_resource(&ioport_resource, &lp2); } +#if defined(CONFIG_BLK_DEV_INITRD) && defined(CONFIG_MMU) +/* + * Relocate initrd if it is not completely within the linear mapping. + * This would be the case if mem= cuts out all or part of it + * or the initrd are not in low mem region place. + */ +static void __init relocate_initrd(void) +{ + phys_addr_t ram_end = memblock_end_of_DRAM(); + phys_addr_t new_start; + phys_addr_t src; + unsigned long size, to_free = 0; + unsigned long slop, clen, p; + void *dest; + + if (initrd_end_phys <= __virt_to_phys(memblock_get_current_limit())) + return; + + /* + * Any of the original initrd which overlaps the linear map should + * be freed after relocating. + */ + if (initrd_start_phys < ram_end) + to_free = min(ram_end, initrd_end_phys) - initrd_start_phys; + + size = initrd_end_phys - initrd_start_phys; + + /* initrd needs to be relocated completely inside linear mapping */ + new_start = memblock_find_in_range(0, 0, size, PAGE_SIZE); + if (!new_start) + panic("Cannot relocate initrd of size %ld\n", size); + memblock_reserve(new_start, size); + + initrd_start = __phys_to_virt(new_start); + initrd_end = initrd_start + size; + + pr_info("Moving initrd from [%llx-%llx] to [%llx-%llx]\n", + (unsigned long long)initrd_start_phys, + (unsigned long long)(initrd_start_phys + size - 1), + (unsigned long long)new_start, + (unsigned long long)(new_start + size - 1)); + + dest = (void *)initrd_start; + + src = initrd_start_phys; + while (size) { + slop = src & ~PAGE_MASK; + clen = min(PAGE_SIZE - slop, size); + p = set_fixmap_offset(FIX_RELOCATE_INITRD, src); + memcpy(dest, (void *)p, clen); + clear_fixmap(FIX_RELOCATE_INITRD); + dest += clen; + src += clen; + size -= clen; + } + + if (to_free) { + pr_info("Freeing original RAMDISK from [%llx-%llx]\n", + (unsigned long long)initrd_start_phys, + (unsigned long long)(initrd_start_phys + to_free - 1)); + memblock_free(initrd_start_phys, to_free); + } +} +#else +static inline void __init relocate_initrd(void) +{ +} +#endif + #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) struct screen_info screen_info = { .orig_video_lines = 30, @@ -969,6 +1038,7 @@ void __init setup_arch(char **cmdline_p) arm_memblock_init(mdesc); paging_init(mdesc); + relocate_initrd(); request_standard_resources(mdesc); if (mdesc->restart) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 0749656..3287ecb 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -777,6 +777,8 @@ static void __init early_init_dt_check_for_initrd(unsigned long node) return; end = of_read_number(prop, len/4); + initrd_start_phys = start; + initrd_end_phys = end; initrd_start = (unsigned long)__va(start); initrd_end = (unsigned long)__va(end); initrd_below_start_ok = 1; diff --git a/include/linux/initrd.h b/include/linux/initrd.h index 55289d2..0698f37 100644 --- a/include/linux/initrd.h +++ b/include/linux/initrd.h @@ -15,6 +15,7 @@ extern int initrd_below_start_ok; /* free_initrd_mem always gets called with the next two as arguments.. */ extern unsigned long initrd_start, initrd_end; +extern phys_addr_t initrd_start_phys, initrd_end_phys; extern void free_initrd_mem(unsigned long, unsigned long); extern unsigned int real_root_dev; diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 3e0878e..cb07338 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -21,6 +21,8 @@ #include "do_mounts.h" unsigned long initrd_start, initrd_end; +phys_addr_t initrd_start_pyhs __initdata; +phys_addr_t initrd_end_phys __initdata; int initrd_below_start_ok; unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ static int __initdata mount_initrd = 1;