Unverified Commit 51b766c7 authored by Samuel Holland's avatar Samuel Holland Committed by Palmer Dabbelt
Browse files

riscv: Support CONFIG_RELOCATABLE on NOMMU



Move relocate_kernel() out of the CONFIG_MMU block so it can be called
from the NOMMU version of setup_vm(). Set some offsets in kernel_map so
relocate_kernel() does not need to be modified. Relocatable NOMMU
kernels can be loaded to any physical memory address; they no longer
depend on CONFIG_PAGE_OFFSET.

Signed-off-by: default avatarSamuel Holland <samuel.holland@sifive.com>
Link: https://lore.kernel.org/r/20241026171441.3047904-4-samuel.holland@sifive.com


Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent 2c0391b2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1075,7 +1075,7 @@ config PARAVIRT_TIME_ACCOUNTING

config RELOCATABLE
	bool "Build a relocatable kernel"
	depends on MMU && 64BIT && !XIP_KERNEL
	depends on 64BIT && !XIP_KERNEL
	select MODULE_SECTIONS if MODULES
	help
          This builds a kernel as a Position Independent Executable (PIE),
+4 −0
Original line number Diff line number Diff line
@@ -12,7 +12,11 @@
#include <asm/pgtable-bits.h>

#ifndef CONFIG_MMU
#ifdef CONFIG_RELOCATABLE
#define KERNEL_LINK_ADDR	UL(0)
#else
#define KERNEL_LINK_ADDR	_AC(CONFIG_PAGE_OFFSET, UL)
#endif
#define KERN_VIRT_SIZE		(UL(-1))
#else

+44 −38
Original line number Diff line number Diff line
@@ -323,6 +323,44 @@ static void __init setup_bootmem(void)
		hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT);
}

#ifdef CONFIG_RELOCATABLE
extern unsigned long __rela_dyn_start, __rela_dyn_end;

static void __init relocate_kernel(void)
{
	Elf64_Rela *rela = (Elf64_Rela *)&__rela_dyn_start;
	/*
	 * This holds the offset between the linked virtual address and the
	 * relocated virtual address.
	 */
	uintptr_t reloc_offset = kernel_map.virt_addr - KERNEL_LINK_ADDR;
	/*
	 * This holds the offset between kernel linked virtual address and
	 * physical address.
	 */
	uintptr_t va_kernel_link_pa_offset = KERNEL_LINK_ADDR - kernel_map.phys_addr;

	for ( ; rela < (Elf64_Rela *)&__rela_dyn_end; rela++) {
		Elf64_Addr addr = (rela->r_offset - va_kernel_link_pa_offset);
		Elf64_Addr relocated_addr = rela->r_addend;

		if (rela->r_info != R_RISCV_RELATIVE)
			continue;

		/*
		 * Make sure to not relocate vdso symbols like rt_sigreturn
		 * which are linked from the address 0 in vmlinux since
		 * vdso symbol addresses are actually used as an offset from
		 * mm->context.vdso in VDSO_OFFSET macro.
		 */
		if (relocated_addr >= KERNEL_LINK_ADDR)
			relocated_addr += reloc_offset;

		*(Elf64_Addr *)addr = relocated_addr;
	}
}
#endif /* CONFIG_RELOCATABLE */

#ifdef CONFIG_MMU
struct pt_alloc_ops pt_ops __meminitdata;

@@ -893,44 +931,6 @@ static __init void set_satp_mode(uintptr_t dtb_pa)
#error "setup_vm() is called from head.S before relocate so it should not use absolute addressing."
#endif

#ifdef CONFIG_RELOCATABLE
extern unsigned long __rela_dyn_start, __rela_dyn_end;

static void __init relocate_kernel(void)
{
	Elf64_Rela *rela = (Elf64_Rela *)&__rela_dyn_start;
	/*
	 * This holds the offset between the linked virtual address and the
	 * relocated virtual address.
	 */
	uintptr_t reloc_offset = kernel_map.virt_addr - KERNEL_LINK_ADDR;
	/*
	 * This holds the offset between kernel linked virtual address and
	 * physical address.
	 */
	uintptr_t va_kernel_link_pa_offset = KERNEL_LINK_ADDR - kernel_map.phys_addr;

	for ( ; rela < (Elf64_Rela *)&__rela_dyn_end; rela++) {
		Elf64_Addr addr = (rela->r_offset - va_kernel_link_pa_offset);
		Elf64_Addr relocated_addr = rela->r_addend;

		if (rela->r_info != R_RISCV_RELATIVE)
			continue;

		/*
		 * Make sure to not relocate vdso symbols like rt_sigreturn
		 * which are linked from the address 0 in vmlinux since
		 * vdso symbol addresses are actually used as an offset from
		 * mm->context.vdso in VDSO_OFFSET macro.
		 */
		if (relocated_addr >= KERNEL_LINK_ADDR)
			relocated_addr += reloc_offset;

		*(Elf64_Addr *)addr = relocated_addr;
	}
}
#endif /* CONFIG_RELOCATABLE */

#ifdef CONFIG_XIP_KERNEL
static void __init create_kernel_page_table(pgd_t *pgdir,
					    __always_unused bool early)
@@ -1378,6 +1378,12 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
{
	dtb_early_va = (void *)dtb_pa;
	dtb_early_pa = dtb_pa;

#ifdef CONFIG_RELOCATABLE
	kernel_map.virt_addr = (uintptr_t)_start;
	kernel_map.phys_addr = (uintptr_t)_start;
	relocate_kernel();
#endif
}

static inline void setup_vm_final(void)