mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC] arm: add relocate initrd support
@ 2015-10-09 15:55 yalin wang
  2015-10-09 16:10 ` Russell King - ARM Linux
  0 siblings, 1 reply; 3+ messages in thread
From: yalin wang @ 2015-10-09 15:55 UTC (permalink / raw)
  To: linux, nico, keescook, robh, stefan, yalin.wang2010, rabin,
	msalter, ard.biesheuvel, will.deacon, ssantosh, yamada.m, sboyd,
	contact, pavel, slash.tmp, linux-arm-kernel, linux-kernel

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 <yalin.wang2010@gmail.com>
---
 arch/arm/include/asm/fixmap.h |  1 +
 arch/arm/kernel/setup.c       | 72 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 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..4260d59 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -811,6 +811,77 @@ 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 orig_start = __virt_to_phys(initrd_start);
+	phys_addr_t orig_end = __virt_to_phys(initrd_end);
+	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 (orig_end <= memblock_get_current_limit())
+		return;
+
+	/*
+	 * Any of the original initrd which overlaps the linear map should
+	 * be freed after relocating.
+	 */
+	if (orig_start < ram_end)
+		to_free = min(ram_end, orig_end) - orig_start;
+
+	size = orig_end - orig_start;
+
+	/* 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)orig_start,
+		(unsigned long long)(orig_start + size - 1),
+		(unsigned long long)new_start,
+		(unsigned long long)(new_start + size - 1));
+
+	dest = (void *)initrd_start;
+
+	src = orig_start;
+	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)orig_start,
+			(unsigned long long)(orig_start + to_free - 1));
+		memblock_free(orig_start, 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 +1040,7 @@ void __init setup_arch(char **cmdline_p)
 	arm_memblock_init(mdesc);
 
 	paging_init(mdesc);
+	relocate_initrd();
 	request_standard_resources(mdesc);
 
 	if (mdesc->restart)
-- 
1.9.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC] arm: add relocate initrd support
  2015-10-09 15:55 [RFC] arm: add relocate initrd support yalin wang
@ 2015-10-09 16:10 ` Russell King - ARM Linux
  2015-10-10  2:03   ` yalin wang
  0 siblings, 1 reply; 3+ messages in thread
From: Russell King - ARM Linux @ 2015-10-09 16:10 UTC (permalink / raw)
  To: yalin wang
  Cc: nico, keescook, robh, stefan, rabin, msalter, ard.biesheuvel,
	will.deacon, ssantosh, yamada.m, sboyd, contact, pavel,
	slash.tmp, linux-arm-kernel, linux-kernel

On Fri, Oct 09, 2015 at 11:55:09PM +0800, yalin wang wrote:
> 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 <yalin.wang2010@gmail.com>
> ---
>  arch/arm/include/asm/fixmap.h |  1 +
>  arch/arm/kernel/setup.c       | 72 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 73 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..4260d59 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -811,6 +811,77 @@ 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 orig_start = __virt_to_phys(initrd_start);
> +	phys_addr_t orig_end = __virt_to_phys(initrd_end);

If initrd_start or initrd_end are outside of the lowmem region, it's
quite possible for these to return incorrect physical addresses.
The generic kernel's idea of using virtual addresses for the initrd
stuff is painfully wrong IMHO.

The unfortunate thing is that the DT code propagates this stuff:

        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);

and even this can give wrong results for the virtual address when the
physical is outside of lowmem.  For addresses outside of lowmem,
__virt_to_phys(__va(start)) is not guaranteed to return 'start'.

This is why I've said that if we want to support ramdisks outside of
the lowmem mapping, we need to get rid of the initrd_start/initrd_end
virtual addresses.

I'm sorry, but we need much wider code changes before we can cope with
this.

> +	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 (orig_end <= memblock_get_current_limit())
> +		return;
> +
> +	/*
> +	 * Any of the original initrd which overlaps the linear map should
> +	 * be freed after relocating.

How does this work?  The code in arm_memblock_init() will have already
reserved the physical addresses for the ramdisk:

	memblock_reserve(phys_initrd_start, phys_initrd_size);

So any new allocation shouldn't overlap the existing ramdisk - unless
this is wrong.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC] arm: add relocate initrd support
  2015-10-09 16:10 ` Russell King - ARM Linux
@ 2015-10-10  2:03   ` yalin wang
  0 siblings, 0 replies; 3+ messages in thread
From: yalin wang @ 2015-10-10  2:03 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: nico, keescook, robh, stefan, rabin, msalter, ard.biesheuvel,
	will.deacon, ssantosh, yamada.m, sboyd, contact, pavel,
	slash.tmp, linux-arm-kernel, linux-kernel


> On Oct 10, 2015, at 00:10, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> 
> On Fri, Oct 09, 2015 at 11:55:09PM +0800, yalin wang wrote:
>> 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 <yalin.wang2010@gmail.com>
>> ---
>> arch/arm/include/asm/fixmap.h |  1 +
>> arch/arm/kernel/setup.c       | 72 +++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 73 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..4260d59 100644
>> --- a/arch/arm/kernel/setup.c
>> +++ b/arch/arm/kernel/setup.c
>> @@ -811,6 +811,77 @@ 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 orig_start = __virt_to_phys(initrd_start);
>> +	phys_addr_t orig_end = __virt_to_phys(initrd_end);
> 
> If initrd_start or initrd_end are outside of the lowmem region, it's
> quite possible for these to return incorrect physical addresses.
> The generic kernel's idea of using virtual addresses for the initrd
> stuff is painfully wrong IMHO.
> 
> The unfortunate thing is that the DT code propagates this stuff:
> 
>        initrd_start = (unsigned long)__va(start);
>        initrd_end = (unsigned long)__va(end);
> 
> and even this can give wrong results for the virtual address when the
> physical is outside of lowmem.  For addresses outside of lowmem,
> __virt_to_phys(__va(start)) is not guaranteed to return 'start'.
> 
> This is why I've said that if we want to support ramdisks outside of
> the lowmem mapping, we need to get rid of the initrd_start/initrd_end
> virtual addresses.
> 
> I'm sorry, but we need much wider code changes before we can cope with
> this.
> 
>> +	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 (orig_end <= memblock_get_current_limit())
>> +		return;
>> +
>> +	/*
>> +	 * Any of the original initrd which overlaps the linear map should
>> +	 * be freed after relocating.
> 
> How does this work?  The code in arm_memblock_init() will have already
> reserved the physical addresses for the ramdisk:
> 
> 	memblock_reserve(phys_initrd_start, phys_initrd_size);
> 
> So any new allocation shouldn't overlap the existing ramdisk - unless
> this is wrong.
>  
i see, i will send a V2 patch for review .

Thanks





^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2015-10-10  2:03 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-09 15:55 [RFC] arm: add relocate initrd support yalin wang
2015-10-09 16:10 ` Russell King - ARM Linux
2015-10-10  2:03   ` yalin wang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome