2021-06-29 09:15:55

by Alexandre Ghiti

[permalink] [raw]
Subject: [PATCH 1/3] riscv: Fix memory_limit for 64-bit kernel

As described in Documentation/riscv/vm-layout.rst, the end of the
virtual address space for 64-bit kernel is occupied by the modules/BPF/
kernel mappings so this actually reduces the amount of memory we are able
to map and then use in the linear mapping. So make sure this limit is
correctly set.

Fixes: c9811e379b21 ("riscv: Add mem kernel parameter support")
Signed-off-by: Alexandre Ghiti <[email protected]>
---
arch/riscv/mm/init.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 12f956b3a674..04a5db3a9788 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -124,10 +124,17 @@ void __init mem_init(void)
}

/*
- * The default maximal physical memory size is -PAGE_OFFSET,
- * limit the memory size via mem.
+ * The default maximal physical memory size is -PAGE_OFFSET for 32-bit kernel,
+ * whereas for 64-bit kernel, the end of the virtual address space is occupied
+ * by the modules/BPF/kernel mappings which reduces the available size of the
+ * linear mapping.
+ * Limit the memory size via mem.
*/
+#ifdef CONFIG_64BIT
+static phys_addr_t memory_limit = -PAGE_OFFSET - SZ_4G;
+#else
static phys_addr_t memory_limit = -PAGE_OFFSET;
+#endif

static int __init early_mem(char *p)
{
--
2.30.2


2021-06-29 09:16:52

by Alexandre Ghiti

[permalink] [raw]
Subject: [PATCH 3/3] riscv: Make sure the kernel mapping does not overlap with IS_ERR_VALUE

The check that is done in setup_bootmem currently only works for 32-bit
kernel since the kernel mapping has been moved outside of the linear
mapping for 64-bit kernel. So make sure that for 64-bit kernel, the kernel
mapping does not overlap with the last 4K of the addressable memory.

Signed-off-by: Alexandre Ghiti <[email protected]>
---
arch/riscv/mm/init.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index a1a0c4afa80f..a90c41bc9485 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -156,7 +156,7 @@ static void __init setup_bootmem(void)
{
phys_addr_t vmlinux_end = __pa_symbol(&_end);
phys_addr_t vmlinux_start = __pa_symbol(&_start);
- phys_addr_t max_mapped_addr = __pa(~(ulong)0);
+ phys_addr_t __maybe_unused max_mapped_addr;
phys_addr_t dram_end;

#ifdef CONFIG_XIP_KERNEL
@@ -179,14 +179,20 @@ static void __init setup_bootmem(void)
memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);

dram_end = memblock_end_of_DRAM();
+#ifndef CONFIG_64BIT
/*
* memblock allocator is not aware of the fact that last 4K bytes of
* the addressable memory can not be mapped because of IS_ERR_VALUE
* macro. Make sure that last 4k bytes are not usable by memblock
- * if end of dram is equal to maximum addressable memory.
+ * if end of dram is equal to maximum addressable memory. For 64-bit
+ * kernel, this problem can't happen here as the end of the virtual
+ * address space is occupied by the kernel mapping then this check must
+ * be done in create_kernel_page_table.
*/
+ max_mapped_addr = __pa(~(ulong)0);
if (max_mapped_addr == (dram_end - 1))
memblock_set_current_limit(max_mapped_addr - 4096);
+#endif

min_low_pfn = PFN_UP(memblock_start_of_DRAM());
max_low_pfn = max_pfn = PFN_DOWN(dram_end);
@@ -556,6 +562,7 @@ static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size,
uintptr_t va, end_va;

end_va = kernel_virt_addr + load_sz;
+
for (va = kernel_virt_addr; va < end_va; va += map_size)
create_pgd_mapping(pgdir, va,
load_pa + (va - kernel_virt_addr),
@@ -602,6 +609,13 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
/* Sanity check alignment and size */
BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
BUG_ON((load_pa % map_size) != 0);
+#ifdef CONFIG_64BIT
+ /*
+ * The last 4K bytes of the addressable memory can not be mapped because
+ * of IS_ERR_VALUE macro.
+ */
+ BUG_ON((kernel_virt_addr + load_sz) > ADDRESS_SPACE_END - SZ_4K);
+#endif

pt_ops.alloc_pte = alloc_pte_early;
pt_ops.get_pte_virt = get_pte_virt_early;
--
2.30.2

2021-06-29 09:19:17

by Alexandre Ghiti

[permalink] [raw]
Subject: [PATCH 2/3] riscv: Make sure the linear mapping does not use the kernel mapping

For 64-bit kernel, the end of the address space is occupied by the
kernel mapping and currently, the functions to populate the kernel page
tables (i.e. create_p*d_mapping) do not override existing mapping so we
must make sure the linear mapping does not map memory in the kernel mapping
by clipping the memory above the memory limit.

Signed-off-by: Alexandre Ghiti <[email protected]>
---
arch/riscv/mm/init.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 04a5db3a9788..a1a0c4afa80f 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -742,6 +742,8 @@ static void __init setup_vm_final(void)
if (start <= __pa(PAGE_OFFSET) &&
__pa(PAGE_OFFSET) < end)
start = __pa(PAGE_OFFSET);
+ if (end >= __pa(PAGE_OFFSET) + memory_limit)
+ end = __pa(PAGE_OFFSET) + memory_limit;

map_size = best_map_size(start, end - start);
for (pa = start; pa < end; pa += map_size) {
--
2.30.2

2021-07-01 10:47:07

by Kefeng Wang

[permalink] [raw]
Subject: Re: [PATCH 1/3] riscv: Fix memory_limit for 64-bit kernel


On 2021/6/29 17:13, Alexandre Ghiti wrote:
> As described in Documentation/riscv/vm-layout.rst, the end of the
> virtual address space for 64-bit kernel is occupied by the modules/BPF/
> kernel mappings so this actually reduces the amount of memory we are able
> to map and then use in the linear mapping. So make sure this limit is
> correctly set.
>
> Fixes: c9811e379b21 ("riscv: Add mem kernel parameter support")


Should the Fixes tag be de043da0b9e7 (“RISC-V: Fix usage of
memblock_enforce_memory_limit“),

The -PAGE_OFFSET is set to the maximal physical memory from this point :)

> Signed-off-by: Alexandre Ghiti <[email protected]>
> ---
> arch/riscv/mm/init.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 12f956b3a674..04a5db3a9788 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -124,10 +124,17 @@ void __init mem_init(void)
> }
>
> /*
> - * The default maximal physical memory size is -PAGE_OFFSET,
> - * limit the memory size via mem.
> + * The default maximal physical memory size is -PAGE_OFFSET for 32-bit kernel,
> + * whereas for 64-bit kernel, the end of the virtual address space is occupied
> + * by the modules/BPF/kernel mappings which reduces the available size of the
> + * linear mapping.
> + * Limit the memory size via mem.
> */
> +#ifdef CONFIG_64BIT
> +static phys_addr_t memory_limit = -PAGE_OFFSET - SZ_4G;
> +#else
> static phys_addr_t memory_limit = -PAGE_OFFSET;
> +#endif
>
> static int __init early_mem(char *p)
> {

2021-07-01 19:09:19

by Alexandre Ghiti

[permalink] [raw]
Subject: Re: [PATCH 1/3] riscv: Fix memory_limit for 64-bit kernel

Le 1/07/2021 à 12:44, Kefeng Wang a écrit :
>
> On 2021/6/29 17:13, Alexandre Ghiti wrote:
>> As described in Documentation/riscv/vm-layout.rst, the end of the
>> virtual address space for 64-bit kernel is occupied by the modules/BPF/
>> kernel mappings so this actually reduces the amount of memory we are able
>> to map and then use in the linear mapping. So make sure this limit is
>> correctly set.
>>
>> Fixes: c9811e379b21 ("riscv: Add mem kernel parameter support")
>
>
> Should the Fixes tag be de043da0b9e7 (“RISC-V: Fix usage of
> memblock_enforce_memory_limit“),
>
> The -PAGE_OFFSET is set to the maximal physical memory from this point :)

Oops, thank you!

Alex

>
>> Signed-off-by: Alexandre Ghiti <[email protected]>
>> ---
>>   arch/riscv/mm/init.c | 11 +++++++++--
>>   1 file changed, 9 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
>> index 12f956b3a674..04a5db3a9788 100644
>> --- a/arch/riscv/mm/init.c
>> +++ b/arch/riscv/mm/init.c
>> @@ -124,10 +124,17 @@ void __init mem_init(void)
>>   }
>>   /*
>> - * The default maximal physical memory size is -PAGE_OFFSET,
>> - * limit the memory size via mem.
>> + * The default maximal physical memory size is -PAGE_OFFSET for
>> 32-bit kernel,
>> + * whereas for 64-bit kernel, the end of the virtual address space is
>> occupied
>> + * by the modules/BPF/kernel mappings which reduces the available
>> size of the
>> + * linear mapping.
>> + * Limit the memory size via mem.
>>    */
>> +#ifdef CONFIG_64BIT
>> +static phys_addr_t memory_limit = -PAGE_OFFSET - SZ_4G;
>> +#else
>>   static phys_addr_t memory_limit = -PAGE_OFFSET;
>> +#endif
>>   static int __init early_mem(char *p)
>>   {
>
> _______________________________________________
> linux-riscv mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-riscv

2021-07-01 19:10:10

by Alexandre Ghiti

[permalink] [raw]
Subject: Re: [PATCH 1/3] riscv: Fix memory_limit for 64-bit kernel

Le 1/07/2021 à 21:01, Alex Ghiti a écrit :
> Le 1/07/2021 à 12:44, Kefeng Wang a écrit :
>>
>> On 2021/6/29 17:13, Alexandre Ghiti wrote:
>>> As described in Documentation/riscv/vm-layout.rst, the end of the
>>> virtual address space for 64-bit kernel is occupied by the modules/BPF/
>>> kernel mappings so this actually reduces the amount of memory we are
>>> able
>>> to map and then use in the linear mapping. So make sure this limit is
>>> correctly set.
>>>
>>> Fixes: c9811e379b21 ("riscv: Add mem kernel parameter support")
>>
>>
>> Should the Fixes tag be de043da0b9e7 (“RISC-V: Fix usage of
>> memblock_enforce_memory_limit“),
>>
>> The -PAGE_OFFSET is set to the maximal physical memory from this point :)
>
> Oops, thank you!

Actually the commit you mentioned was merged way before I moved the
kernel to the end of the address space, so the proper Fixes tag should be:

Fixes: 2bfc6cd81bd1 ("riscv: Move kernel mapping outside of linear mapping")

Thanks anyway,

>
> Alex
>
>>
>>> Signed-off-by: Alexandre Ghiti <[email protected]>
>>> ---
>>>   arch/riscv/mm/init.c | 11 +++++++++--
>>>   1 file changed, 9 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
>>> index 12f956b3a674..04a5db3a9788 100644
>>> --- a/arch/riscv/mm/init.c
>>> +++ b/arch/riscv/mm/init.c
>>> @@ -124,10 +124,17 @@ void __init mem_init(void)
>>>   }
>>>   /*
>>> - * The default maximal physical memory size is -PAGE_OFFSET,
>>> - * limit the memory size via mem.
>>> + * The default maximal physical memory size is -PAGE_OFFSET for
>>> 32-bit kernel,
>>> + * whereas for 64-bit kernel, the end of the virtual address space
>>> is occupied
>>> + * by the modules/BPF/kernel mappings which reduces the available
>>> size of the
>>> + * linear mapping.
>>> + * Limit the memory size via mem.
>>>    */
>>> +#ifdef CONFIG_64BIT
>>> +static phys_addr_t memory_limit = -PAGE_OFFSET - SZ_4G;
>>> +#else
>>>   static phys_addr_t memory_limit = -PAGE_OFFSET;
>>> +#endif
>>>   static int __init early_mem(char *p)
>>>   {
>>
>> _______________________________________________
>> linux-riscv mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-riscv

2021-07-24 00:59:09

by Palmer Dabbelt

[permalink] [raw]
Subject: Re: [PATCH 3/3] riscv: Make sure the kernel mapping does not overlap with IS_ERR_VALUE

On Tue, 29 Jun 2021 02:13:48 PDT (-0700), [email protected] wrote:
> The check that is done in setup_bootmem currently only works for 32-bit
> kernel since the kernel mapping has been moved outside of the linear
> mapping for 64-bit kernel. So make sure that for 64-bit kernel, the kernel
> mapping does not overlap with the last 4K of the addressable memory.
>
> Signed-off-by: Alexandre Ghiti <[email protected]>
> ---
> arch/riscv/mm/init.c | 18 ++++++++++++++++--
> 1 file changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index a1a0c4afa80f..a90c41bc9485 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -156,7 +156,7 @@ static void __init setup_bootmem(void)
> {
> phys_addr_t vmlinux_end = __pa_symbol(&_end);
> phys_addr_t vmlinux_start = __pa_symbol(&_start);
> - phys_addr_t max_mapped_addr = __pa(~(ulong)0);
> + phys_addr_t __maybe_unused max_mapped_addr;
> phys_addr_t dram_end;
>
> #ifdef CONFIG_XIP_KERNEL
> @@ -179,14 +179,20 @@ static void __init setup_bootmem(void)
> memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
>
> dram_end = memblock_end_of_DRAM();
> +#ifndef CONFIG_64BIT
> /*
> * memblock allocator is not aware of the fact that last 4K bytes of
> * the addressable memory can not be mapped because of IS_ERR_VALUE
> * macro. Make sure that last 4k bytes are not usable by memblock
> - * if end of dram is equal to maximum addressable memory.
> + * if end of dram is equal to maximum addressable memory. For 64-bit
> + * kernel, this problem can't happen here as the end of the virtual
> + * address space is occupied by the kernel mapping then this check must
> + * be done in create_kernel_page_table.
> */
> + max_mapped_addr = __pa(~(ulong)0);
> if (max_mapped_addr == (dram_end - 1))
> memblock_set_current_limit(max_mapped_addr - 4096);
> +#endif
>
> min_low_pfn = PFN_UP(memblock_start_of_DRAM());
> max_low_pfn = max_pfn = PFN_DOWN(dram_end);
> @@ -556,6 +562,7 @@ static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size,
> uintptr_t va, end_va;
>
> end_va = kernel_virt_addr + load_sz;
> +
> for (va = kernel_virt_addr; va < end_va; va += map_size)
> create_pgd_mapping(pgdir, va,
> load_pa + (va - kernel_virt_addr),
> @@ -602,6 +609,13 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
> /* Sanity check alignment and size */
> BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
> BUG_ON((load_pa % map_size) != 0);
> +#ifdef CONFIG_64BIT
> + /*
> + * The last 4K bytes of the addressable memory can not be mapped because
> + * of IS_ERR_VALUE macro.
> + */
> + BUG_ON((kernel_virt_addr + load_sz) > ADDRESS_SPACE_END - SZ_4K);
> +#endif
>
> pt_ops.alloc_pte = alloc_pte_early;
> pt_ops.get_pte_virt = get_pte_virt_early;

Thanks. These are on fixes, with some fixes tags added. This one had
some merge conflicts that I had to fix up, LMK if something went wrong.

2021-07-26 05:49:45

by Alexandre Ghiti

[permalink] [raw]
Subject: Re: [PATCH 3/3] riscv: Make sure the kernel mapping does not overlap with IS_ERR_VALUE

Hi Palmer,

Le 29/06/2021 ? 11:13, Alexandre Ghiti a ?crit?:
> The check that is done in setup_bootmem currently only works for 32-bit
> kernel since the kernel mapping has been moved outside of the linear
> mapping for 64-bit kernel. So make sure that for 64-bit kernel, the kernel
> mapping does not overlap with the last 4K of the addressable memory.
>
> Signed-off-by: Alexandre Ghiti <[email protected]>
> ---
> arch/riscv/mm/init.c | 18 ++++++++++++++++--
> 1 file changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index a1a0c4afa80f..a90c41bc9485 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -156,7 +156,7 @@ static void __init setup_bootmem(void)
> {
> phys_addr_t vmlinux_end = __pa_symbol(&_end);
> phys_addr_t vmlinux_start = __pa_symbol(&_start);
> - phys_addr_t max_mapped_addr = __pa(~(ulong)0);
> + phys_addr_t __maybe_unused max_mapped_addr;
> phys_addr_t dram_end;
>
> #ifdef CONFIG_XIP_KERNEL
> @@ -179,14 +179,20 @@ static void __init setup_bootmem(void)
> memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
>
> dram_end = memblock_end_of_DRAM();
> +#ifndef CONFIG_64BIT
> /*
> * memblock allocator is not aware of the fact that last 4K bytes of
> * the addressable memory can not be mapped because of IS_ERR_VALUE
> * macro. Make sure that last 4k bytes are not usable by memblock
> - * if end of dram is equal to maximum addressable memory.
> + * if end of dram is equal to maximum addressable memory. For 64-bit
> + * kernel, this problem can't happen here as the end of the virtual
> + * address space is occupied by the kernel mapping then this check must
> + * be done in create_kernel_page_table.

This comment is wrong, I have just sent a patch fixing this:

"riscv: Fix comment regarding kernel mapping overlapping with IS_ERR_VALUE"

> */
> + max_mapped_addr = __pa(~(ulong)0);
> if (max_mapped_addr == (dram_end - 1))
> memblock_set_current_limit(max_mapped_addr - 4096);
> +#endif
>
> min_low_pfn = PFN_UP(memblock_start_of_DRAM());
> max_low_pfn = max_pfn = PFN_DOWN(dram_end);
> @@ -556,6 +562,7 @@ static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size,
> uintptr_t va, end_va;
>
> end_va = kernel_virt_addr + load_sz;
> +

I saw that you removed this useless new line, thanks.

> for (va = kernel_virt_addr; va < end_va; va += map_size)
> create_pgd_mapping(pgdir, va,
> load_pa + (va - kernel_virt_addr),
> @@ -602,6 +609,13 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
> /* Sanity check alignment and size */
> BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0);
> BUG_ON((load_pa % map_size) != 0);
> +#ifdef CONFIG_64BIT
> + /*
> + * The last 4K bytes of the addressable memory can not be mapped because
> + * of IS_ERR_VALUE macro.
> + */
> + BUG_ON((kernel_virt_addr + load_sz) > ADDRESS_SPACE_END - SZ_4K);
> +#endif
>
> pt_ops.alloc_pte = alloc_pte_early;
> pt_ops.get_pte_virt = get_pte_virt_early;
>

The merge you have done is correct to me. Sorry about the above
mistakes, should have caught those before.

Thanks,

Alex