Nam Cao <namcao@xxxxxxxxxxxxx> writes: > On riscv32, it is possible for the last page in virtual address space > (0xfffff000) to be allocated. This page overlaps with PTR_ERR, so that > shouldn't happen. > > There is already some code to ensure memblock won't allocate the last page. > However, buddy allocator is left unchecked. > > Fix this by reserving physical memory that would be mapped at virtual > addresses greater than 0xfffff000. > > Reported-by: Björn Töpel <bjorn@xxxxxxxxxx> > Closes: https://lore.kernel.org/linux-riscv/878r1ibpdn.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx > Fixes: 76d2a0493a17 ("RISC-V: Init and Halt Code") > Signed-off-by: Nam Cao <namcao@xxxxxxxxxxxxx> > Cc: <stable@xxxxxxxxxxxxxxx> Thanks for picking it up again, Nam. This passes my test: Tested-by: Björn Töpel <bjorn@xxxxxxxxxxxx> > --- > arch/riscv/mm/init.c | 21 +++++++++++---------- > 1 file changed, 11 insertions(+), 10 deletions(-) > > diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c > index 968761843203..7c985435b3fc 100644 > --- a/arch/riscv/mm/init.c > +++ b/arch/riscv/mm/init.c > @@ -235,18 +235,19 @@ static void __init setup_bootmem(void) > kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base; > > /* > - * 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. 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 as soon as the kernel mapping base address is determined. > + * Reserve physical address space that would be mapped to virtual > + * addresses greater than (void *)(-PAGE_SIZE) because: > + * - This memory would overlap with ERR_PTR > + * - This memory belongs to high memory, which is not supported > + * > + * This is not applicable to 64-bit kernel, because virtual addresses > + * after (void *)(-PAGE_SIZE) are not linearly mapped: they are > + * occupied by kernel mapping. Also it is unrealistic for high memory > + * to exist on 64-bit platforms. > */ > if (!IS_ENABLED(CONFIG_64BIT)) { > - max_mapped_addr = __pa(~(ulong)0); > - if (max_mapped_addr == (phys_ram_end - 1)) > - memblock_set_current_limit(max_mapped_addr - 4096); > + max_mapped_addr = __va_to_pa_nodebug(-PAGE_SIZE); > + memblock_reserve(max_mapped_addr, (phys_addr_t)-max_mapped_addr); Nit (and only if you respin for some reason): Move max_mapped_addr into the if-clause, or simply get rid of it (all on one line). Regardless: Reviewed-by: Björn Töpel <bjorn@xxxxxxxxxxxx> Björn