* [PATCH V3 1/3] mm: add utility for early copy from unmapped ram
2015-08-16 20:49 [PATCH V3 0/3] mm: Add generic copy from early unmapped RAM Mark Salter
@ 2015-08-16 20:49 ` Mark Salter
2015-08-16 20:49 ` [PATCH V3 2/3] arm64: support initrd outside kernel linear map Mark Salter
2015-08-16 20:49 ` [PATCH V3 3/3] x86: use generic early mem copy Mark Salter
2 siblings, 0 replies; 6+ messages in thread
From: Mark Salter @ 2015-08-16 20:49 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, x86
Cc: Andrew Morton, Arnd Bergmann, Ard Biesheuvel, Mark Rutland,
linux-kernel, linux-arm-kernel, linux-mm, linux-arch, Mark Salter
In some early boot circumstances, it may be necessary to copy
from RAM outside the kernel linear mapping to mapped RAM. The
need to relocate an initrd is one example in the x86 code. This
patch creates a helper function based on current x86 code.
Signed-off-by: Mark Salter <msalter@redhat.com>
---
include/asm-generic/early_ioremap.h | 6 ++++++
mm/early_ioremap.c | 22 ++++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/include/asm-generic/early_ioremap.h b/include/asm-generic/early_ioremap.h
index a5de55c..e539f27 100644
--- a/include/asm-generic/early_ioremap.h
+++ b/include/asm-generic/early_ioremap.h
@@ -33,6 +33,12 @@ extern void early_ioremap_setup(void);
*/
extern void early_ioremap_reset(void);
+/*
+ * Early copy from unmapped memory to kernel mapped memory.
+ */
+extern void copy_from_early_mem(void *dest, phys_addr_t src,
+ unsigned long size);
+
#else
static inline void early_ioremap_init(void) { }
static inline void early_ioremap_setup(void) { }
diff --git a/mm/early_ioremap.c b/mm/early_ioremap.c
index e10ccd2..a0baeb4 100644
--- a/mm/early_ioremap.c
+++ b/mm/early_ioremap.c
@@ -217,6 +217,28 @@ early_memremap(resource_size_t phys_addr, unsigned long size)
return (__force void *)__early_ioremap(phys_addr, size,
FIXMAP_PAGE_NORMAL);
}
+
+#define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT)
+
+void __init copy_from_early_mem(void *dest, phys_addr_t src, unsigned long size)
+{
+ unsigned long slop, clen;
+ char *p;
+
+ while (size) {
+ slop = src & ~PAGE_MASK;
+ clen = size;
+ if (clen > MAX_MAP_CHUNK - slop)
+ clen = MAX_MAP_CHUNK - slop;
+ p = early_memremap(src & PAGE_MASK, clen + slop);
+ memcpy(dest, p + slop, clen);
+ early_memunmap(p, clen + slop);
+ dest += clen;
+ src += clen;
+ size -= clen;
+ }
+}
+
#else /* CONFIG_MMU */
void __init __iomem *
--
2.4.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH V3 2/3] arm64: support initrd outside kernel linear map
2015-08-16 20:49 [PATCH V3 0/3] mm: Add generic copy from early unmapped RAM Mark Salter
2015-08-16 20:49 ` [PATCH V3 1/3] mm: add utility for early copy from unmapped ram Mark Salter
@ 2015-08-16 20:49 ` Mark Salter
2015-08-17 11:22 ` Will Deacon
2015-08-16 20:49 ` [PATCH V3 3/3] x86: use generic early mem copy Mark Salter
2 siblings, 1 reply; 6+ messages in thread
From: Mark Salter @ 2015-08-16 20:49 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, x86
Cc: Andrew Morton, Arnd Bergmann, Ard Biesheuvel, Mark Rutland,
linux-kernel, linux-arm-kernel, linux-mm, linux-arch, Mark Salter
The use of mem= could leave part or all of the initrd outside of
the kernel linear map. This will lead to an error when unpacking
the initrd and a probable failure to boot. This patch catches that
situation and relocates the initrd to be fully within the linear
map.
Signed-off-by: Mark Salter <msalter@redhat.com>
---
arch/arm64/kernel/setup.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index f3067d4..5f45fd9 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -359,6 +359,64 @@ static void __init request_standard_resources(void)
}
}
+#ifdef CONFIG_BLK_DEV_INITRD
+/*
+ * 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.
+ */
+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;
+ unsigned long size, to_free = 0;
+ void *dest;
+
+ if (orig_end <= ram_end)
+ return;
+
+ /* Note if any of original initrd will freeing below */
+ if (orig_start < ram_end)
+ to_free = ram_end - orig_start;
+
+ size = orig_end - orig_start;
+
+ /* initrd needs to be relocated completely inside linear mapping */
+ new_start = memblock_find_in_range(0, PFN_PHYS(max_pfn),
+ 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",
+ orig_start, orig_start + size - 1,
+ new_start, new_start + size - 1);
+
+ dest = (void *)initrd_start;
+
+ if (to_free) {
+ memcpy(dest, (void *)__phys_to_virt(orig_start), to_free);
+ dest += to_free;
+ }
+
+ copy_from_early_mem(dest, orig_start + to_free, size - to_free);
+
+ if (to_free) {
+ pr_info("Freeing original RAMDISK from [%llx-%llx]\n",
+ orig_start, orig_start + to_free - 1);
+ memblock_free(orig_start, to_free);
+ }
+}
+#else
+static inline void __init reserve_initrd(void)
+{
+}
+#endif
+
u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
void __init setup_arch(char **cmdline_p)
@@ -392,6 +450,7 @@ void __init setup_arch(char **cmdline_p)
acpi_boot_table_init();
paging_init();
+ relocate_initrd();
request_standard_resources();
early_ioremap_reset();
--
2.4.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH V3 2/3] arm64: support initrd outside kernel linear map
2015-08-16 20:49 ` [PATCH V3 2/3] arm64: support initrd outside kernel linear map Mark Salter
@ 2015-08-17 11:22 ` Will Deacon
2015-08-17 13:32 ` Mark Salter
0 siblings, 1 reply; 6+ messages in thread
From: Will Deacon @ 2015-08-17 11:22 UTC (permalink / raw)
To: Mark Salter
Cc: Catalin Marinas, x86@kernel.org, Andrew Morton, Arnd Bergmann,
Ard Biesheuvel, Mark Rutland, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org,
linux-arch@vger.kernel.org
Hi Mark,
On Sun, Aug 16, 2015 at 09:49:27PM +0100, Mark Salter wrote:
> The use of mem= could leave part or all of the initrd outside of
> the kernel linear map. This will lead to an error when unpacking
> the initrd and a probable failure to boot. This patch catches that
> situation and relocates the initrd to be fully within the linear
> map.
>
> Signed-off-by: Mark Salter <msalter@redhat.com>
> ---
> arch/arm64/kernel/setup.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
> index f3067d4..5f45fd9 100644
> --- a/arch/arm64/kernel/setup.c
> +++ b/arch/arm64/kernel/setup.c
> @@ -359,6 +359,64 @@ static void __init request_standard_resources(void)
> }
> }
>
> +#ifdef CONFIG_BLK_DEV_INITRD
> +/*
> + * 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.
> + */
> +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);
Any particular reason to use the __* variants here?
> + phys_addr_t ram_end = memblock_end_of_DRAM();
> + phys_addr_t new_start;
> + unsigned long size, to_free = 0;
> + void *dest;
> +
> + if (orig_end <= ram_end)
> + return;
> +
> + /* Note if any of original initrd will freeing below */
The comment doesn't make sense.
> + if (orig_start < ram_end)
> + to_free = ram_end - orig_start;
> +
> + size = orig_end - orig_start;
> +
> + /* initrd needs to be relocated completely inside linear mapping */
> + new_start = memblock_find_in_range(0, PFN_PHYS(max_pfn),
> + 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",
> + orig_start, orig_start + size - 1,
> + new_start, new_start + size - 1);
> +
> + dest = (void *)initrd_start;
> +
> + if (to_free) {
> + memcpy(dest, (void *)__phys_to_virt(orig_start), to_free);
> + dest += to_free;
> + }
> +
> + copy_from_early_mem(dest, orig_start + to_free, size - to_free);
> +
> + if (to_free) {
> + pr_info("Freeing original RAMDISK from [%llx-%llx]\n",
> + orig_start, orig_start + to_free - 1);
> + memblock_free(orig_start, to_free);
> + }
> +}
> +#else
> +static inline void __init reserve_initrd(void)
relocate_initrd ?
Will
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH V3 2/3] arm64: support initrd outside kernel linear map
2015-08-17 11:22 ` Will Deacon
@ 2015-08-17 13:32 ` Mark Salter
0 siblings, 0 replies; 6+ messages in thread
From: Mark Salter @ 2015-08-17 13:32 UTC (permalink / raw)
To: Will Deacon
Cc: Catalin Marinas, x86@kernel.org, Andrew Morton, Arnd Bergmann,
Ard Biesheuvel, Mark Rutland, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org,
linux-arch@vger.kernel.org
On Mon, 2015-08-17 at 12:22 +0100, Will Deacon wrote:
> Hi Mark,
>
> On Sun, Aug 16, 2015 at 09:49:27PM +0100, Mark Salter wrote:
> > The use of mem= could leave part or all of the initrd outside of
> > the kernel linear map. This will lead to an error when unpacking
> > the initrd and a probable failure to boot. This patch catches that
> > situation and relocates the initrd to be fully within the linear
> > map.
> >
> > Signed-off-by: Mark Salter <msalter@redhat.com>
> > ---
> > arch/arm64/kernel/setup.c | 59
> > +++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 59 insertions(+)
> >
> > diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
> > index f3067d4..5f45fd9 100644
> > --- a/arch/arm64/kernel/setup.c
> > +++ b/arch/arm64/kernel/setup.c
> > @@ -359,6 +359,64 @@ static void __init
> > request_standard_resources(void)
> > }
> > }
> >
> > +#ifdef CONFIG_BLK_DEV_INITRD
> > +/*
> > + * 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.
> > + */
> > +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);
>
> Any particular reason to use the __* variants here?
To avoid need to cast initrd_{start,end} to pointer.
>
> > + phys_addr_t ram_end = memblock_end_of_DRAM();
> > + phys_addr_t new_start;
> > + unsigned long size, to_free = 0;
> > + void *dest;
> > +
> > + if (orig_end <= ram_end)
> > + return;
> > +
> > + /* Note if any of original initrd will freeing below */
>
> The comment doesn't make sense.
No it doesn't.
>
> > + if (orig_start < ram_end)
> > + to_free = ram_end - orig_start;
> > +
> > + size = orig_end - orig_start;
> > +
> > + /* initrd needs to be relocated completely inside linear
> > mapping */
> > + new_start = memblock_find_in_range(0, PFN_PHYS(max_pfn),
> > + 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",
> > + orig_start, orig_start + size - 1,
> > + new_start, new_start + size - 1);
> > +
> > + dest = (void *)initrd_start;
> > +
> > + if (to_free) {
> > + memcpy(dest, (void *)__phys_to_virt(orig_start),
> > to_free);
> > + dest += to_free;
> > + }
> > +
> > + copy_from_early_mem(dest, orig_start + to_free, size -
> > to_free);
> > +
> > + if (to_free) {
> > + pr_info("Freeing original RAMDISK from [%llx-%llx]\n",
> > + orig_start, orig_start + to_free - 1);
> > + memblock_free(orig_start, to_free);
> > + }
> > +}
> > +#else
> > +static inline void __init reserve_initrd(void)
>
> relocate_initrd ?
Yes
Thanks, will fix that and the comment.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH V3 3/3] x86: use generic early mem copy
2015-08-16 20:49 [PATCH V3 0/3] mm: Add generic copy from early unmapped RAM Mark Salter
2015-08-16 20:49 ` [PATCH V3 1/3] mm: add utility for early copy from unmapped ram Mark Salter
2015-08-16 20:49 ` [PATCH V3 2/3] arm64: support initrd outside kernel linear map Mark Salter
@ 2015-08-16 20:49 ` Mark Salter
2 siblings, 0 replies; 6+ messages in thread
From: Mark Salter @ 2015-08-16 20:49 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, x86
Cc: Andrew Morton, Arnd Bergmann, Ard Biesheuvel, Mark Rutland,
linux-kernel, linux-arm-kernel, linux-mm, linux-arch, Mark Salter
The early_ioremap library now has a generic copy_from_early_mem()
function. Use the generic copy function for x86 relocate_initrd().
Signed-off-by: Mark Salter <msalter@redhat.com>
---
arch/x86/kernel/setup.c | 22 +---------------------
1 file changed, 1 insertion(+), 21 deletions(-)
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 80f874b..21fa9a3 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -317,15 +317,12 @@ static u64 __init get_ramdisk_size(void)
return ramdisk_size;
}
-#define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT)
static void __init relocate_initrd(void)
{
/* Assume only end is not page aligned */
u64 ramdisk_image = get_ramdisk_image();
u64 ramdisk_size = get_ramdisk_size();
u64 area_size = PAGE_ALIGN(ramdisk_size);
- unsigned long slop, clen, mapaddr;
- char *p, *q;
/* We need to move the initrd down into directly mapped mem */
relocated_ramdisk = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped),
@@ -343,25 +340,8 @@ static void __init relocate_initrd(void)
printk(KERN_INFO "Allocated new RAMDISK: [mem %#010llx-%#010llx]\n",
relocated_ramdisk, relocated_ramdisk + ramdisk_size - 1);
- q = (char *)initrd_start;
-
- /* Copy the initrd */
- while (ramdisk_size) {
- slop = ramdisk_image & ~PAGE_MASK;
- clen = ramdisk_size;
- if (clen > MAX_MAP_CHUNK-slop)
- clen = MAX_MAP_CHUNK-slop;
- mapaddr = ramdisk_image & PAGE_MASK;
- p = early_memremap(mapaddr, clen+slop);
- memcpy(q, p+slop, clen);
- early_memunmap(p, clen+slop);
- q += clen;
- ramdisk_image += clen;
- ramdisk_size -= clen;
- }
+ copy_from_early_mem((void *)initrd_start, ramdisk_image, ramdisk_size);
- ramdisk_image = get_ramdisk_image();
- ramdisk_size = get_ramdisk_size();
printk(KERN_INFO "Move RAMDISK from [mem %#010llx-%#010llx] to"
" [mem %#010llx-%#010llx]\n",
ramdisk_image, ramdisk_image + ramdisk_size - 1,
--
2.4.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 6+ messages in thread