Skip to content

Commit f633de4

Browse files
Merge patch series "riscv: Relocatable NOMMU kernels"
Samuel Holland <samuel.holland@sifive.com> says: Currently, RISC-V NOMMU kernels are linked at CONFIG_PAGE_OFFSET, and since they are not relocatable, must be loaded at this address as well. CONFIG_PAGE_OFFSET is not a user-visible Kconfig option, so its value is not obvious, and users must patch the kernel source if they want to load it at a different address. Make NOMMU kernels more portable by making them relocatable by default. This allows a single kernel binary to work when loaded at any address. * b4-shazam-merge: riscv: Remove CONFIG_PAGE_OFFSET riscv: Support CONFIG_RELOCATABLE on riscv32 asm-generic: Always define Elf_Rel and Elf_Rela riscv: Support CONFIG_RELOCATABLE on NOMMU riscv: Allow NOMMU kernels to access all of RAM riscv: Remove duplicate CONFIG_PAGE_OFFSET definition Link: https://lore.kernel.org/r/20241026171441.3047904-1-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
2 parents df02351 + e1cf2d0 commit f633de4

File tree

7 files changed

+73
-82
lines changed

7 files changed

+73
-82
lines changed

arch/riscv/Kconfig

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ config RISCV
202202
select PCI_DOMAINS_GENERIC if PCI
203203
select PCI_ECAM if (ACPI && PCI)
204204
select PCI_MSI if PCI
205+
select RELOCATABLE if !MMU && !PHYS_RAM_BASE_FIXED
205206
select RISCV_ALTERNATIVE if !XIP_KERNEL
206207
select RISCV_APLIC
207208
select RISCV_IMSIC
@@ -289,13 +290,6 @@ config MMU
289290
Select if you want MMU-based virtualised addressing space
290291
support by paged memory management. If unsure, say 'Y'.
291292

292-
config PAGE_OFFSET
293-
hex
294-
default 0x80000000 if !MMU && RISCV_M_MODE
295-
default 0x80200000 if !MMU
296-
default 0xc0000000 if 32BIT
297-
default 0xff60000000000000 if 64BIT
298-
299293
config KASAN_SHADOW_OFFSET
300294
hex
301295
depends on KASAN_GENERIC
@@ -1100,7 +1094,7 @@ config PARAVIRT_TIME_ACCOUNTING
11001094

11011095
config RELOCATABLE
11021096
bool "Build a relocatable kernel"
1103-
depends on MMU && 64BIT && !XIP_KERNEL
1097+
depends on !XIP_KERNEL
11041098
select MODULE_SECTIONS if MODULES
11051099
help
11061100
This builds a kernel as a Position Independent Executable (PIE),

arch/riscv/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ KBUILD_AFLAGS += -march=$(riscv-march-y)
9898
CC_FLAGS_FPU := -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64ima)([^v_]*)v?/\1\2/')
9999

100100
KBUILD_CFLAGS += -mno-save-restore
101-
KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET)
102101

103102
ifeq ($(CONFIG_CMODEL_MEDLOW),y)
104103
KBUILD_CFLAGS += -mcmodel=medlow

arch/riscv/errata/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
ifdef CONFIG_RELOCATABLE
2-
KBUILD_CFLAGS += -fno-pie
2+
# We can't use PIC/PIE when handling early-boot errata parsing, as the kernel
3+
# doesn't have a GOT setup at that point. So instead just use medany: it's
4+
# usually position-independent, so it should be good enough for the errata
5+
# handling.
6+
KBUILD_CFLAGS += -fno-pie -mcmodel=medany
37
endif
48

59
ifdef CONFIG_RISCV_ALTERNATIVE_EARLY

arch/riscv/include/asm/page.h

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,22 @@
2424
* When not using MMU this corresponds to the first free page in
2525
* physical memory (aligned on a page boundary).
2626
*/
27-
#ifdef CONFIG_64BIT
2827
#ifdef CONFIG_MMU
29-
#define PAGE_OFFSET kernel_map.page_offset
30-
#else
31-
#define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL)
32-
#endif
33-
/*
34-
* By default, CONFIG_PAGE_OFFSET value corresponds to SV57 address space so
35-
* define the PAGE_OFFSET value for SV48 and SV39.
36-
*/
28+
#ifdef CONFIG_64BIT
29+
#define PAGE_OFFSET_L5 _AC(0xff60000000000000, UL)
3730
#define PAGE_OFFSET_L4 _AC(0xffffaf8000000000, UL)
3831
#define PAGE_OFFSET_L3 _AC(0xffffffd600000000, UL)
32+
#ifdef CONFIG_XIP_KERNEL
33+
#define PAGE_OFFSET PAGE_OFFSET_L3
3934
#else
40-
#define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL)
35+
#define PAGE_OFFSET kernel_map.page_offset
36+
#endif /* CONFIG_XIP_KERNEL */
37+
#else
38+
#define PAGE_OFFSET _AC(0xc0000000, UL)
4139
#endif /* CONFIG_64BIT */
40+
#else
41+
#define PAGE_OFFSET ((unsigned long)phys_ram_base)
42+
#endif /* CONFIG_MMU */
4243

4344
#ifndef __ASSEMBLY__
4445

@@ -95,14 +96,9 @@ typedef struct page *pgtable_t;
9596
#define MIN_MEMBLOCK_ADDR 0
9697
#endif
9798

98-
#ifdef CONFIG_MMU
9999
#define ARCH_PFN_OFFSET (PFN_DOWN((unsigned long)phys_ram_base))
100-
#else
101-
#define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT)
102-
#endif /* CONFIG_MMU */
103100

104101
struct kernel_mapping {
105-
unsigned long page_offset;
106102
unsigned long virt_addr;
107103
unsigned long virt_offset;
108104
uintptr_t phys_addr;
@@ -116,6 +112,7 @@ struct kernel_mapping {
116112
uintptr_t xiprom;
117113
uintptr_t xiprom_sz;
118114
#else
115+
unsigned long page_offset;
119116
unsigned long va_kernel_pa_offset;
120117
#endif
121118
};

arch/riscv/include/asm/pgtable.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
#include <asm/pgtable-bits.h>
1313

1414
#ifndef CONFIG_MMU
15-
#define KERNEL_LINK_ADDR PAGE_OFFSET
15+
#ifdef CONFIG_RELOCATABLE
16+
#define KERNEL_LINK_ADDR UL(0)
17+
#else
18+
#define KERNEL_LINK_ADDR _AC(CONFIG_PHYS_RAM_BASE, UL)
19+
#endif
1620
#define KERN_VIRT_SIZE (UL(-1))
1721
#else
1822

arch/riscv/mm/init.c

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,13 @@
2020
#include <linux/dma-map-ops.h>
2121
#include <linux/crash_dump.h>
2222
#include <linux/hugetlb.h>
23-
#ifdef CONFIG_RELOCATABLE
24-
#include <linux/elf.h>
25-
#endif
2623
#include <linux/kfence.h>
2724
#include <linux/execmem.h>
2825

2926
#include <asm/fixmap.h>
3027
#include <asm/io.h>
3128
#include <asm/kasan.h>
29+
#include <asm/module.h>
3230
#include <asm/numa.h>
3331
#include <asm/pgtable.h>
3432
#include <asm/sections.h>
@@ -323,6 +321,44 @@ static void __init setup_bootmem(void)
323321
hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT);
324322
}
325323

324+
#ifdef CONFIG_RELOCATABLE
325+
extern unsigned long __rela_dyn_start, __rela_dyn_end;
326+
327+
static void __init relocate_kernel(void)
328+
{
329+
Elf_Rela *rela = (Elf_Rela *)&__rela_dyn_start;
330+
/*
331+
* This holds the offset between the linked virtual address and the
332+
* relocated virtual address.
333+
*/
334+
uintptr_t reloc_offset = kernel_map.virt_addr - KERNEL_LINK_ADDR;
335+
/*
336+
* This holds the offset between kernel linked virtual address and
337+
* physical address.
338+
*/
339+
uintptr_t va_kernel_link_pa_offset = KERNEL_LINK_ADDR - kernel_map.phys_addr;
340+
341+
for ( ; rela < (Elf_Rela *)&__rela_dyn_end; rela++) {
342+
Elf_Addr addr = (rela->r_offset - va_kernel_link_pa_offset);
343+
Elf_Addr relocated_addr = rela->r_addend;
344+
345+
if (rela->r_info != R_RISCV_RELATIVE)
346+
continue;
347+
348+
/*
349+
* Make sure to not relocate vdso symbols like rt_sigreturn
350+
* which are linked from the address 0 in vmlinux since
351+
* vdso symbol addresses are actually used as an offset from
352+
* mm->context.vdso in VDSO_OFFSET macro.
353+
*/
354+
if (relocated_addr >= KERNEL_LINK_ADDR)
355+
relocated_addr += reloc_offset;
356+
357+
*(Elf_Addr *)addr = relocated_addr;
358+
}
359+
}
360+
#endif /* CONFIG_RELOCATABLE */
361+
326362
#ifdef CONFIG_MMU
327363
struct pt_alloc_ops pt_ops __meminitdata;
328364

@@ -823,6 +859,8 @@ static __init void set_satp_mode(uintptr_t dtb_pa)
823859
uintptr_t set_satp_mode_pmd = ((unsigned long)set_satp_mode) & PMD_MASK;
824860
u64 satp_mode_cmdline = __pi_set_satp_mode_from_cmdline(dtb_pa);
825861

862+
kernel_map.page_offset = PAGE_OFFSET_L5;
863+
826864
if (satp_mode_cmdline == SATP_MODE_57) {
827865
disable_pgtable_l5();
828866
} else if (satp_mode_cmdline == SATP_MODE_48) {
@@ -893,44 +931,6 @@ static __init void set_satp_mode(uintptr_t dtb_pa)
893931
#error "setup_vm() is called from head.S before relocate so it should not use absolute addressing."
894932
#endif
895933

896-
#ifdef CONFIG_RELOCATABLE
897-
extern unsigned long __rela_dyn_start, __rela_dyn_end;
898-
899-
static void __init relocate_kernel(void)
900-
{
901-
Elf64_Rela *rela = (Elf64_Rela *)&__rela_dyn_start;
902-
/*
903-
* This holds the offset between the linked virtual address and the
904-
* relocated virtual address.
905-
*/
906-
uintptr_t reloc_offset = kernel_map.virt_addr - KERNEL_LINK_ADDR;
907-
/*
908-
* This holds the offset between kernel linked virtual address and
909-
* physical address.
910-
*/
911-
uintptr_t va_kernel_link_pa_offset = KERNEL_LINK_ADDR - kernel_map.phys_addr;
912-
913-
for ( ; rela < (Elf64_Rela *)&__rela_dyn_end; rela++) {
914-
Elf64_Addr addr = (rela->r_offset - va_kernel_link_pa_offset);
915-
Elf64_Addr relocated_addr = rela->r_addend;
916-
917-
if (rela->r_info != R_RISCV_RELATIVE)
918-
continue;
919-
920-
/*
921-
* Make sure to not relocate vdso symbols like rt_sigreturn
922-
* which are linked from the address 0 in vmlinux since
923-
* vdso symbol addresses are actually used as an offset from
924-
* mm->context.vdso in VDSO_OFFSET macro.
925-
*/
926-
if (relocated_addr >= KERNEL_LINK_ADDR)
927-
relocated_addr += reloc_offset;
928-
929-
*(Elf64_Addr *)addr = relocated_addr;
930-
}
931-
}
932-
#endif /* CONFIG_RELOCATABLE */
933-
934934
#ifdef CONFIG_XIP_KERNEL
935935
static void __init create_kernel_page_table(pgd_t *pgdir,
936936
__always_unused bool early)
@@ -1108,11 +1108,6 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
11081108
kernel_map.virt_addr = KERNEL_LINK_ADDR + kernel_map.virt_offset;
11091109

11101110
#ifdef CONFIG_XIP_KERNEL
1111-
#ifdef CONFIG_64BIT
1112-
kernel_map.page_offset = PAGE_OFFSET_L3;
1113-
#else
1114-
kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL);
1115-
#endif
11161111
kernel_map.xiprom = (uintptr_t)CONFIG_XIP_PHYS_ADDR;
11171112
kernel_map.xiprom_sz = (uintptr_t)(&_exiprom) - (uintptr_t)(&_xiprom);
11181113

@@ -1127,7 +1122,6 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
11271122
kernel_map.va_kernel_xip_data_pa_offset = kernel_map.virt_addr - kernel_map.phys_addr
11281123
+ (uintptr_t)&_sdata - (uintptr_t)&_start;
11291124
#else
1130-
kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL);
11311125
kernel_map.phys_addr = (uintptr_t)(&_start);
11321126
kernel_map.size = (uintptr_t)(&_end) - kernel_map.phys_addr;
11331127
kernel_map.va_kernel_pa_offset = kernel_map.virt_addr - kernel_map.phys_addr;
@@ -1174,7 +1168,8 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
11741168
* makes the kernel cross over a PUD_SIZE boundary, raise a bug
11751169
* since a part of the kernel would not get mapped.
11761170
*/
1177-
BUG_ON(PUD_SIZE - (kernel_map.virt_addr & (PUD_SIZE - 1)) < kernel_map.size);
1171+
if (IS_ENABLED(CONFIG_64BIT))
1172+
BUG_ON(PUD_SIZE - (kernel_map.virt_addr & (PUD_SIZE - 1)) < kernel_map.size);
11781173
relocate_kernel();
11791174
#endif
11801175

@@ -1378,6 +1373,12 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
13781373
{
13791374
dtb_early_va = (void *)dtb_pa;
13801375
dtb_early_pa = dtb_pa;
1376+
1377+
#ifdef CONFIG_RELOCATABLE
1378+
kernel_map.virt_addr = (uintptr_t)_start;
1379+
kernel_map.phys_addr = (uintptr_t)_start;
1380+
relocate_kernel();
1381+
#endif
13811382
}
13821383

13831384
static inline void setup_vm_final(void)

include/asm-generic/module.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,8 @@ struct mod_arch_specific
1919
#define Elf_Dyn Elf64_Dyn
2020
#define Elf_Ehdr Elf64_Ehdr
2121
#define Elf_Addr Elf64_Addr
22-
#ifdef CONFIG_MODULES_USE_ELF_REL
2322
#define Elf_Rel Elf64_Rel
24-
#endif
25-
#ifdef CONFIG_MODULES_USE_ELF_RELA
2623
#define Elf_Rela Elf64_Rela
27-
#endif
2824
#define ELF_R_TYPE(X) ELF64_R_TYPE(X)
2925
#define ELF_R_SYM(X) ELF64_R_SYM(X)
3026

@@ -36,12 +32,8 @@ struct mod_arch_specific
3632
#define Elf_Dyn Elf32_Dyn
3733
#define Elf_Ehdr Elf32_Ehdr
3834
#define Elf_Addr Elf32_Addr
39-
#ifdef CONFIG_MODULES_USE_ELF_REL
4035
#define Elf_Rel Elf32_Rel
41-
#endif
42-
#ifdef CONFIG_MODULES_USE_ELF_RELA
4336
#define Elf_Rela Elf32_Rela
44-
#endif
4537
#define ELF_R_TYPE(X) ELF32_R_TYPE(X)
4638
#define ELF_R_SYM(X) ELF32_R_SYM(X)
4739
#endif

0 commit comments

Comments
 (0)