From d28a87ced0f521c83cc9022884d34745ce9ceb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Polyos=20Project=20=28=E9=99=88=E8=8D=A3=29?= Date: Thu, 21 Dec 2023 13:30:50 +0800 Subject: [PATCH] add patch for riscv64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch is to support build kernel with clang, and some fixes should be backported to avoid issue "relocation R_RISCV_PCREL_HI20 out of range". fde9c59aebaf riscv: explicitly use symbol offsets for VDSO 2bfc6cd81bd1 riscv: Move kernel mapping outside of linear mapping Signed-off-by: Polyos Project (陈荣) --- .../qemu-riscv64-linux.patch | 1121 +++++++++++++++++ 1 file changed, 1121 insertions(+) create mode 100644 linux-5.10/qemu-riscv64-linux_patch/qemu-riscv64-linux.patch diff --git a/linux-5.10/qemu-riscv64-linux_patch/qemu-riscv64-linux.patch b/linux-5.10/qemu-riscv64-linux_patch/qemu-riscv64-linux.patch new file mode 100644 index 0000000..04077e1 --- /dev/null +++ b/linux-5.10/qemu-riscv64-linux_patch/qemu-riscv64-linux.patch @@ -0,0 +1,1121 @@ +diff --git a/Makefile b/Makefile +index d9509eba5701..66064517be12 100644 +--- a/Makefile ++++ b/Makefile +@@ -572,22 +572,7 @@ ifdef building_out_of_srctree + endif + + ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),) +-ifneq ($(CROSS_COMPILE),) +-CLANG_FLAGS += --target=$(notdir $(CROSS_COMPILE:%-=%)) +-GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)elfedit)) +-CLANG_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE)) +-GCC_TOOLCHAIN := $(realpath $(GCC_TOOLCHAIN_DIR)/..) +-endif +-ifneq ($(GCC_TOOLCHAIN),) +-CLANG_FLAGS += --gcc-toolchain=$(GCC_TOOLCHAIN) +-endif +-ifneq ($(LLVM_IAS),1) +-CLANG_FLAGS += -no-integrated-as +-endif +-CLANG_FLAGS += -Werror=unknown-warning-option +-KBUILD_CFLAGS += $(CLANG_FLAGS) +-KBUILD_AFLAGS += $(CLANG_FLAGS) +-export CLANG_FLAGS ++include $(srctree)/scripts/Makefile.clang + endif + + # The expansion should be delayed until arch/$(SRCARCH)/Makefile is included. +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index 557c4a8c4087..77dc1ef95503 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -14,6 +14,7 @@ config RISCV + def_bool y + select ARCH_CLOCKSOURCE_INIT + select ARCH_SUPPORTS_ATOMIC_RMW ++ select ARCH_STACKWALK + select ARCH_HAS_BINFMT_FLAT + select ARCH_HAS_DEBUG_VM_PGTABLE + select ARCH_HAS_DEBUG_VIRTUAL if MMU +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index 9446282b52ba..6f97496b309b 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -104,7 +104,11 @@ PHONY += vdso_install + vdso_install: + $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@ + +-ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_KENDRYTE),yy) ++prepare: vdso_prepare ++vdso_prepare: prepare0 ++ $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso include/generated/vdso-offsets.h ++ ++ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_CANAAN),yy) + KBUILD_IMAGE := $(boot)/loader.bin + else + KBUILD_IMAGE := $(boot)/Image.gz +diff --git a/arch/riscv/boot/loader.lds.S b/arch/riscv/boot/loader.lds.S +index 47a5003c2e28..62d94696a19c 100644 +--- a/arch/riscv/boot/loader.lds.S ++++ b/arch/riscv/boot/loader.lds.S +@@ -1,13 +1,14 @@ + /* SPDX-License-Identifier: GPL-2.0 */ + + #include ++#include + + OUTPUT_ARCH(riscv) + ENTRY(_start) + + SECTIONS + { +- . = PAGE_OFFSET; ++ . = KERNEL_LINK_ADDR; + + .payload : { + *(.payload) +diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h +index 64a675c5c30a..44eb46cc4ef7 100644 +--- a/arch/riscv/include/asm/page.h ++++ b/arch/riscv/include/asm/page.h +@@ -90,18 +90,40 @@ typedef struct page *pgtable_t; + + #ifdef CONFIG_MMU + extern unsigned long va_pa_offset; ++#ifdef CONFIG_64BIT ++extern unsigned long va_kernel_pa_offset; ++#endif + extern unsigned long pfn_base; + #define ARCH_PFN_OFFSET (pfn_base) + #else + #define va_pa_offset 0 ++#ifdef CONFIG_64BIT ++#define va_kernel_pa_offset 0 ++#endif + #define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) + #endif /* CONFIG_MMU */ + + extern unsigned long max_low_pfn; + extern unsigned long min_low_pfn; + +-#define __pa_to_va_nodebug(x) ((void *)((unsigned long) (x) + va_pa_offset)) +-#define __va_to_pa_nodebug(x) ((unsigned long)(x) - va_pa_offset) ++extern unsigned long kernel_virt_addr; ++ ++#ifdef CONFIG_64BIT ++#define linear_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + va_pa_offset)) ++#define kernel_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + va_kernel_pa_offset)) ++#define __pa_to_va_nodebug(x) linear_mapping_pa_to_va(x) ++ ++#define linear_mapping_va_to_pa(x) ((unsigned long)(x) - va_pa_offset) ++#define kernel_mapping_va_to_pa(x) ((unsigned long)(x) - va_kernel_pa_offset) ++#define __va_to_pa_nodebug(x) ({ \ ++ unsigned long _x = x; \ ++ (_x < kernel_virt_addr) ? \ ++ linear_mapping_va_to_pa(_x) : kernel_mapping_va_to_pa(_x); \ ++ }) ++#else ++#define __pa_to_va_nodebug(x) ((void *)((unsigned long) (x) + va_pa_offset)) ++#define __va_to_pa_nodebug(x) ((unsigned long)(x) - va_pa_offset) ++#endif + + #ifdef CONFIG_DEBUG_VIRTUAL + extern phys_addr_t __virt_to_phys(unsigned long x); +diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h +index b16304fdf448..9d407dc7f2bf 100644 +--- a/arch/riscv/include/asm/pgtable.h ++++ b/arch/riscv/include/asm/pgtable.h +@@ -11,23 +11,38 @@ + + #include + +-#ifndef __ASSEMBLY__ ++#ifndef CONFIG_MMU ++#define KERNEL_LINK_ADDR PAGE_OFFSET ++#else + +-/* Page Upper Directory not used in RISC-V */ +-#include +-#include +-#include +-#include ++#define ADDRESS_SPACE_END (UL(-1)) + +-#ifdef CONFIG_MMU ++#ifdef CONFIG_64BIT ++/* Leave 2GB for kernel and BPF at the end of the address space */ ++#define KERNEL_LINK_ADDR (ADDRESS_SPACE_END - SZ_2G + 1) ++#else ++#define KERNEL_LINK_ADDR PAGE_OFFSET ++#endif + + #define VMALLOC_SIZE (KERN_VIRT_SIZE >> 1) + #define VMALLOC_END (PAGE_OFFSET - 1) + #define VMALLOC_START (PAGE_OFFSET - VMALLOC_SIZE) + + #define BPF_JIT_REGION_SIZE (SZ_128M) ++#ifdef CONFIG_64BIT ++/* KASLR should leave at least 128MB for BPF after the kernel */ ++#define BPF_JIT_REGION_START PFN_ALIGN((unsigned long)&_end) ++#define BPF_JIT_REGION_END (BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE) ++#else + #define BPF_JIT_REGION_START (PAGE_OFFSET - BPF_JIT_REGION_SIZE) + #define BPF_JIT_REGION_END (VMALLOC_END) ++#endif ++ ++/* Modules always live before the kernel */ ++#ifdef CONFIG_64BIT ++#define MODULES_VADDR (PFN_ALIGN((unsigned long)&_end) - SZ_2G) ++#define MODULES_END (PFN_ALIGN((unsigned long)&_start)) ++#endif + + /* + * Roughly size the vmemmap space to be large enough to fit enough +@@ -57,9 +72,16 @@ + #define FIXADDR_SIZE PGDIR_SIZE + #endif + #define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) +- + #endif + ++#ifndef __ASSEMBLY__ ++ ++/* Page Upper Directory not used in RISC-V */ ++#include ++#include ++#include ++#include ++ + #ifdef CONFIG_64BIT + #include + #else +@@ -466,6 +488,7 @@ static inline void __kernel_map_pages(struct page *page, int numpages, int enabl + + #define kern_addr_valid(addr) (1) /* FIXME */ + ++extern char _start[]; + extern void *dtb_early_va; + extern uintptr_t dtb_early_pa; + void setup_bootmem(void); +diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h +index 3a9971b1210f..1595c5b60cfd 100644 +--- a/arch/riscv/include/asm/sections.h ++++ b/arch/riscv/include/asm/sections.h +@@ -9,5 +9,7 @@ + + extern char _start[]; + extern char _start_kernel[]; ++extern char __init_data_begin[], __init_data_end[]; ++extern char __init_text_begin[], __init_text_end[]; + + #endif /* __ASM_SECTIONS_H */ +diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h +index 4c5bae7ca01c..f71a9d4aefd1 100644 +--- a/arch/riscv/include/asm/set_memory.h ++++ b/arch/riscv/include/asm/set_memory.h +@@ -15,11 +15,16 @@ int set_memory_ro(unsigned long addr, int numpages); + int set_memory_rw(unsigned long addr, int numpages); + int set_memory_x(unsigned long addr, int numpages); + int set_memory_nx(unsigned long addr, int numpages); ++int set_memory_rw_nx(unsigned long addr, int numpages); ++void protect_kernel_text_data(void); ++void protect_kernel_linear_mapping_text_rodata(void); + #else + static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; } + static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; } + static inline int set_memory_x(unsigned long addr, int numpages) { return 0; } + static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } ++static inline void protect_kernel_text_data(void) {}; ++static inline int set_memory_rw_nx(unsigned long addr, int numpages) { return 0; } + #endif + + int set_direct_map_invalid_noflush(struct page *page); +diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h +new file mode 100644 +index 000000000000..470a65c4ccdc +--- /dev/null ++++ b/arch/riscv/include/asm/stacktrace.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef _ASM_RISCV_STACKTRACE_H ++#define _ASM_RISCV_STACKTRACE_H ++ ++#include ++#include ++ ++struct stackframe { ++ unsigned long fp; ++ unsigned long ra; ++}; ++ ++extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, ++ bool (*fn)(void *, unsigned long), void *arg); ++ ++#endif /* _ASM_RISCV_STACKTRACE_H */ +diff --git a/arch/riscv/include/asm/vdso.h b/arch/riscv/include/asm/vdso.h +index 1453a2f563bc..d8d003c2b5a3 100644 +--- a/arch/riscv/include/asm/vdso.h ++++ b/arch/riscv/include/asm/vdso.h +@@ -9,25 +9,15 @@ + #define _ASM_RISCV_VDSO_H + + #include ++#include + + #ifndef CONFIG_GENERIC_TIME_VSYSCALL + struct vdso_data { + }; + #endif + +-/* +- * The VDSO symbols are mapped into Linux so we can just use regular symbol +- * addressing to get their offsets in userspace. The symbols are mapped at an +- * offset of 0, but since the linker must support setting weak undefined +- * symbols to the absolute address 0 it also happens to support other low +- * addresses even when the code model suggests those low addresses would not +- * otherwise be availiable. +- */ + #define VDSO_SYMBOL(base, name) \ +-({ \ +- extern const char __vdso_##name[]; \ +- (void __user *)((unsigned long)(base) + __vdso_##name); \ +-}) ++ (void __user *)((unsigned long)(base) + __vdso_##name##_offset) + + asmlinkage long sys_riscv_flush_icache(uintptr_t, uintptr_t, uintptr_t); + +diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S +index 47d1411db0a9..4de926dbbe02 100644 +--- a/arch/riscv/kernel/head.S ++++ b/arch/riscv/kernel/head.S +@@ -69,7 +69,8 @@ pe_head_start: + #ifdef CONFIG_MMU + relocate: + /* Relocate return address */ +- li a1, PAGE_OFFSET ++ la a1, kernel_virt_addr ++ REG_L a1, 0(a1) + la a2, _start + sub a1, a1, a2 + add ra, ra, a1 +@@ -183,7 +184,6 @@ setup_trap_vector: + + END(_start) + +- __INIT + ENTRY(_start_kernel) + /* Mask all interrupts */ + csrw CSR_IE, zero +diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c +index c3310a68ac46..91fa71b80f25 100644 +--- a/arch/riscv/kernel/module.c ++++ b/arch/riscv/kernel/module.c +@@ -419,12 +419,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, + } + + #if defined(CONFIG_MMU) && defined(CONFIG_64BIT) +-#define VMALLOC_MODULE_START \ +- max(PFN_ALIGN((unsigned long)&_end - SZ_2G), VMALLOC_START) + void *module_alloc(unsigned long size) + { +- return __vmalloc_node_range(size, 1, VMALLOC_MODULE_START, +- VMALLOC_END, GFP_KERNEL, ++ return __vmalloc_node_range(size, 1, MODULES_VADDR, ++ MODULES_END, GFP_KERNEL, + PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, + __builtin_return_address(0)); + } +diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c +index fb02811df714..357f985041cb 100644 +--- a/arch/riscv/kernel/perf_callchain.c ++++ b/arch/riscv/kernel/perf_callchain.c +@@ -4,11 +4,7 @@ + #include + #include + +-/* Kernel callchain */ +-struct stackframe { +- unsigned long fp; +- unsigned long ra; +-}; ++#include + + /* + * Get the return address for a single stackframe and return a pointer to the +@@ -75,13 +71,11 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, + fp = user_backtrace(entry, fp, 0); + } + +-bool fill_callchain(unsigned long pc, void *entry) ++static bool fill_callchain(void *entry, unsigned long pc) + { + return perf_callchain_store(entry, pc) == 0; + } + +-void notrace walk_stackframe(struct task_struct *task, +- struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg); + void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) + { +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index 8e78a8ab6a34..af8e5c205309 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -99,6 +100,16 @@ void __init setup_arch(char **cmdline_p) + early_init_fdt_scan_reserved_mem(); + misc_mem_init(); + ++ if (IS_ENABLED(CONFIG_RISCV_SBI)) ++ sbi_init(); ++ ++ if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) { ++ protect_kernel_text_data(); ++#if defined(CONFIG_64BIT) && defined(CONFIG_MMU) ++ protect_kernel_linear_mapping_text_rodata(); ++#endif ++ } ++ + #ifdef CONFIG_SWIOTLB + swiotlb_init(1); + #endif +@@ -107,10 +118,6 @@ void __init setup_arch(char **cmdline_p) + kasan_init(); + #endif + +-#if IS_ENABLED(CONFIG_RISCV_SBI) +- sbi_init(); +-#endif +- + #ifdef CONFIG_SMP + setup_smp(); + #endif +@@ -132,3 +139,12 @@ static int __init topology_init(void) + return 0; + } + subsys_initcall(topology_init); ++ ++void free_initmem(void) ++{ ++ unsigned long init_begin = (unsigned long)__init_begin; ++ unsigned long init_end = (unsigned long)__init_end; ++ ++ set_memory_rw_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT); ++ free_initmem_default(POISON_FREE_INITMEM); ++} +diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c +index 9c34735c1e77..4d324c1fbf24 100644 +--- a/arch/riscv/kernel/stacktrace.c ++++ b/arch/riscv/kernel/stacktrace.c +@@ -12,17 +12,14 @@ + #include + #include + ++#include ++ + register unsigned long sp_in_global __asm__("sp"); + + #ifdef CONFIG_FRAME_POINTER + +-struct stackframe { +- unsigned long fp; +- unsigned long ra; +-}; +- + void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, +- bool (*fn)(unsigned long, void *), void *arg) ++ bool (*fn)(void *, unsigned long), void *arg) + { + unsigned long fp, sp, pc; + +@@ -46,7 +43,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, + unsigned long low, high; + struct stackframe *frame; + +- if (unlikely(!__kernel_text_address(pc) || fn(pc, arg))) ++ if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc))) + break; + + /* Validate frame pointer */ +@@ -72,7 +69,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, + #else /* !CONFIG_FRAME_POINTER */ + + void notrace walk_stackframe(struct task_struct *task, +- struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg) ++ struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *arg) + { + unsigned long sp, pc; + unsigned long *ksp; +@@ -94,7 +91,7 @@ void notrace walk_stackframe(struct task_struct *task, + + ksp = (unsigned long *)sp; + while (!kstack_end(ksp)) { +- if (__kernel_text_address(pc) && unlikely(fn(pc, arg))) ++ if (__kernel_text_address(pc) && unlikely(!fn(arg, pc))) + break; + pc = READ_ONCE_NOCHECK(*ksp++) - 0x4; + } +@@ -102,13 +99,12 @@ void notrace walk_stackframe(struct task_struct *task, + + #endif /* CONFIG_FRAME_POINTER */ + +- +-static bool print_trace_address(unsigned long pc, void *arg) ++static bool print_trace_address(void *arg, unsigned long pc) + { + const char *loglvl = arg; + + print_ip_sym(loglvl, pc); +- return false; ++ return true; + } + + void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) +@@ -117,14 +113,14 @@ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) + walk_stackframe(task, NULL, print_trace_address, (void *)loglvl); + } + +-static bool save_wchan(unsigned long pc, void *arg) ++static bool save_wchan(void *arg, unsigned long pc) + { + if (!in_sched_functions(pc)) { + unsigned long *p = arg; + *p = pc; +- return true; ++ return false; + } +- return false; ++ return true; + } + + unsigned long get_wchan(struct task_struct *task) +@@ -136,42 +132,12 @@ unsigned long get_wchan(struct task_struct *task) + return pc; + } + +- + #ifdef CONFIG_STACKTRACE + +-static bool __save_trace(unsigned long pc, void *arg, bool nosched) +-{ +- struct stack_trace *trace = arg; +- +- if (unlikely(nosched && in_sched_functions(pc))) +- return false; +- if (unlikely(trace->skip > 0)) { +- trace->skip--; +- return false; +- } +- +- trace->entries[trace->nr_entries++] = pc; +- return (trace->nr_entries >= trace->max_entries); +-} +- +-static bool save_trace(unsigned long pc, void *arg) +-{ +- return __save_trace(pc, arg, false); +-} +- +-/* +- * Save stack-backtrace addresses into a stack_trace buffer. +- */ +-void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +-{ +- walk_stackframe(tsk, NULL, save_trace, trace); +-} +-EXPORT_SYMBOL_GPL(save_stack_trace_tsk); +- +-void save_stack_trace(struct stack_trace *trace) ++void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, ++ struct task_struct *task, struct pt_regs *regs) + { +- save_stack_trace_tsk(NULL, trace); ++ walk_stackframe(task, regs, consume_entry, cookie); + } +-EXPORT_SYMBOL_GPL(save_stack_trace); + + #endif /* CONFIG_STACKTRACE */ +diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile +index f4ac7ff56bce..be1c2ee4a564 100644 +--- a/arch/riscv/kernel/vdso/Makefile ++++ b/arch/riscv/kernel/vdso/Makefile +@@ -24,10 +24,10 @@ ifneq ($(c-gettimeofday-y),) + endif + + # Build rules +-targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-syms.S ++targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds + obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) + +-obj-y += vdso.o vdso-syms.o ++obj-y += vdso.o + CPPFLAGS_vdso.lds += -P -C -U$(ARCH) + ifneq ($(filter vgettimeofday, $(vdso-syms)),) + CPPFLAGS_vdso.lds += -DHAS_VGETTIMEOFDAY +@@ -47,20 +47,22 @@ $(obj)/vdso.o: $(obj)/vdso.so + # link rule for the .so file, .lds has to be first + $(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE + $(call if_changed,vdsold) +-LDFLAGS_vdso.so.dbg = -shared -s -soname=linux-vdso.so.1 \ ++LDFLAGS_vdso.so.dbg = -shared -S -soname=linux-vdso.so.1 \ + --build-id=sha1 --hash-style=both --eh-frame-hdr + +-# We also create a special relocatable object that should mirror the symbol +-# table and layout of the linked DSO. With ld --just-symbols we can then +-# refer to these symbols in the kernel code rather than hand-coded addresses. +-$(obj)/vdso-syms.S: $(obj)/vdso.so FORCE +- $(call if_changed,so2s) +- + # strip rule for the .so file + $(obj)/%.so: OBJCOPYFLAGS := -S + $(obj)/%.so: $(obj)/%.so.dbg FORCE + $(call if_changed,objcopy) + ++# Generate VDSO offsets using helper script ++gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh ++quiet_cmd_vdsosym = VDSOSYM $@ ++ cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ ++ ++include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE ++ $(call if_changed,vdsosym) ++ + # actual build commands + # The DSO images are built using a special linker script + # Make sure only to export the intended __vdso_xxx symbol offsets. +diff --git a/arch/riscv/kernel/vdso/gen_vdso_offsets.sh b/arch/riscv/kernel/vdso/gen_vdso_offsets.sh +new file mode 100755 +index 000000000000..c2e5613f3495 +--- /dev/null ++++ b/arch/riscv/kernel/vdso/gen_vdso_offsets.sh +@@ -0,0 +1,5 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++ ++LC_ALL=C ++sed -n -e 's/^[0]\+\(0[0-9a-fA-F]*\) . \(__vdso_[a-zA-Z0-9_]*\)$/\#define \2_offset\t0x\1/p' +diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S +index 3ffbd6cbdb86..89fc7ef96bde 100644 +--- a/arch/riscv/kernel/vmlinux.lds.S ++++ b/arch/riscv/kernel/vmlinux.lds.S +@@ -4,7 +4,8 @@ + * Copyright (C) 2017 SiFive + */ + +-#define LOAD_OFFSET PAGE_OFFSET ++#include ++#define LOAD_OFFSET KERNEL_LINK_ADDR + #include + #include + #include +@@ -29,8 +30,30 @@ SECTIONS + HEAD_TEXT_SECTION + . = ALIGN(PAGE_SIZE); + ++ .text : { ++ _text = .; ++ _stext = .; ++ TEXT_TEXT ++ SCHED_TEXT ++ CPUIDLE_TEXT ++ LOCK_TEXT ++ KPROBES_TEXT ++ ENTRY_TEXT ++ IRQENTRY_TEXT ++ SOFTIRQENTRY_TEXT ++ *(.fixup) ++ _etext = .; ++ } ++ ++ . = ALIGN(SECTION_ALIGN); + __init_begin = .; +- INIT_TEXT_SECTION(PAGE_SIZE) ++ __init_text_begin = .; ++ .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) ALIGN(SECTION_ALIGN) { \ ++ _sinittext = .; \ ++ INIT_TEXT \ ++ _einittext = .; \ ++ } ++ + . = ALIGN(8); + __soc_early_init_table : { + __soc_early_init_table_start = .; +@@ -47,35 +70,24 @@ SECTIONS + { + EXIT_TEXT + } +- .exit.data : +- { +- EXIT_DATA +- } +- PERCPU_SECTION(L1_CACHE_BYTES) +- __init_end = .; + ++ __init_text_end = .; + . = ALIGN(SECTION_ALIGN); +- .text : { +- _text = .; +- _stext = .; +- TEXT_TEXT +- SCHED_TEXT +- CPUIDLE_TEXT +- LOCK_TEXT +- KPROBES_TEXT +- ENTRY_TEXT +- IRQENTRY_TEXT +- SOFTIRQENTRY_TEXT +- *(.fixup) +- _etext = .; +- } +- + #ifdef CONFIG_EFI + . = ALIGN(PECOFF_SECTION_ALIGNMENT); + __pecoff_text_end = .; + #endif +- ++ /* Start of init data section */ ++ __init_data_begin = .; + INIT_DATA_SECTION(16) ++ .exit.data : ++ { ++ EXIT_DATA ++ } ++ PERCPU_SECTION(L1_CACHE_BYTES) ++ ++ __init_data_end = .; ++ __init_end = .; + + /* Start of data section */ + _sdata = .; +diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c +index 54b12943cc7b..bbf08f7d0fb3 100644 +--- a/arch/riscv/mm/fault.c ++++ b/arch/riscv/mm/fault.c +@@ -217,6 +217,19 @@ asmlinkage void do_page_fault(struct pt_regs *regs) + return; + } + ++#ifdef CONFIG_64BIT ++ /* ++ * Modules in 64bit kernels lie in their own virtual region which is not ++ * in the vmalloc region, but dealing with page faults in this region ++ * or the vmalloc region amounts to doing the same thing: checking that ++ * the mapping exists in init_mm.pgd and updating user page table, so ++ * just use vmalloc_fault. ++ */ ++ if (unlikely(addr >= MODULES_VADDR && addr < MODULES_END)) { ++ vmalloc_fault(regs, code, addr); ++ return; ++ } ++#endif + /* Enable interrupts if they were enabled in the parent context. */ + if (likely(regs->status & SR_PIE)) + local_irq_enable(); +diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c +index 6c2f38aac544..1c1774e86a65 100644 +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -24,6 +24,9 @@ + + #include "../kernel/head.h" + ++unsigned long kernel_virt_addr = KERNEL_LINK_ADDR; ++EXPORT_SYMBOL(kernel_virt_addr); ++ + unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] + __page_aligned_bss; + EXPORT_SYMBOL(empty_zero_page); +@@ -87,6 +90,10 @@ static void print_vm_layout(void) + (unsigned long)VMALLOC_END); + print_mlm("lowmem", (unsigned long)PAGE_OFFSET, + (unsigned long)high_memory); ++#ifdef CONFIG_64BIT ++ print_mlm("kernel", (unsigned long)KERNEL_LINK_ADDR, ++ (unsigned long)ADDRESS_SPACE_END); ++#endif + } + #else + static void print_vm_layout(void) { } +@@ -163,14 +170,18 @@ void __init setup_bootmem(void) + phys_addr_t max_mapped_addr = __pa(~(ulong)0); + u64 i; + +- /* Find the memory region containing the kernel */ +- for_each_mem_range(i, &start, &end) { +- phys_addr_t size = end - start; +- if (!mem_start) +- mem_start = start; +- if (start <= vmlinux_start && vmlinux_end <= end) +- BUG_ON(size == 0); +- } ++ /* ++ * Reserve from the start of the kernel to the end of the kernel ++ */ ++#if defined(CONFIG_64BIT) && defined(CONFIG_STRICT_KERNEL_RWX) ++ /* ++ * Make sure we align the reservation on PMD_SIZE since we will ++ * map the kernel in the linear mapping as read-only: we do not want ++ * any allocation to happen between _end and the next pmd aligned page. ++ */ ++ vmlinux_end = (vmlinux_end + PMD_SIZE - 1) & PMD_MASK; ++#endif ++ memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start); + + /* + * The maximal physical memory size is -PAGE_OFFSET. +@@ -216,8 +227,14 @@ void __init setup_bootmem(void) + #ifdef CONFIG_MMU + static struct pt_alloc_ops pt_ops; + ++/* Offset between linear mapping virtual address and kernel load address */ + unsigned long va_pa_offset; + EXPORT_SYMBOL(va_pa_offset); ++#ifdef CONFIG_64BIT ++/* Offset between kernel mapping virtual address and kernel load address */ ++unsigned long va_kernel_pa_offset; ++EXPORT_SYMBOL(va_kernel_pa_offset); ++#endif + unsigned long pfn_base; + EXPORT_SYMBOL(pfn_base); + +@@ -321,8 +338,7 @@ static pmd_t *get_pmd_virt_late(phys_addr_t pa) + + static phys_addr_t __init alloc_pmd_early(uintptr_t va) + { +- BUG_ON((va - PAGE_OFFSET) >> PGDIR_SHIFT); +- ++ BUG_ON((va - kernel_virt_addr) >> PGDIR_SHIFT); + return (uintptr_t)early_pmd; + } + +@@ -436,17 +452,34 @@ static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size) + #error "setup_vm() is called from head.S before relocate so it should not use absolute addressing." + #endif + ++uintptr_t load_pa, load_sz; ++ ++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), ++ map_size, PAGE_KERNEL_EXEC); ++} ++ + asmlinkage void __init setup_vm(uintptr_t dtb_pa) + { +- uintptr_t va, pa, end_va; +- uintptr_t load_pa = (uintptr_t)(&_start); +- uintptr_t load_sz = (uintptr_t)(&_end) - load_pa; ++ uintptr_t pa; + uintptr_t map_size; + #ifndef __PAGETABLE_PMD_FOLDED + pmd_t fix_bmap_spmd, fix_bmap_epmd; + #endif ++ load_pa = (uintptr_t)(&_start); ++ load_sz = (uintptr_t)(&_end) - load_pa; + + va_pa_offset = PAGE_OFFSET - load_pa; ++#ifdef CONFIG_64BIT ++ va_kernel_pa_offset = kernel_virt_addr - load_pa; ++#endif ++ + pfn_base = PFN_DOWN(load_pa); + + /* +@@ -474,31 +507,28 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) + create_pmd_mapping(fixmap_pmd, FIXADDR_START, + (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE); + /* Setup trampoline PGD and PMD */ +- create_pgd_mapping(trampoline_pg_dir, PAGE_OFFSET, ++ create_pgd_mapping(trampoline_pg_dir, kernel_virt_addr, + (uintptr_t)trampoline_pmd, PGDIR_SIZE, PAGE_TABLE); +- create_pmd_mapping(trampoline_pmd, PAGE_OFFSET, ++ create_pmd_mapping(trampoline_pmd, kernel_virt_addr, + load_pa, PMD_SIZE, PAGE_KERNEL_EXEC); + #else + /* Setup trampoline PGD */ +- create_pgd_mapping(trampoline_pg_dir, PAGE_OFFSET, ++ create_pgd_mapping(trampoline_pg_dir, kernel_virt_addr, + load_pa, PGDIR_SIZE, PAGE_KERNEL_EXEC); + #endif + + /* +- * Setup early PGD covering entire kernel which will allows ++ * Setup early PGD covering entire kernel which will allow + * us to reach paging_init(). We map all memory banks later + * in setup_vm_final() below. + */ +- end_va = PAGE_OFFSET + load_sz; +- for (va = PAGE_OFFSET; va < end_va; va += map_size) +- create_pgd_mapping(early_pg_dir, va, +- load_pa + (va - PAGE_OFFSET), +- map_size, PAGE_KERNEL_EXEC); ++ create_kernel_page_table(early_pg_dir, map_size); + + #ifndef __PAGETABLE_PMD_FOLDED + /* Setup early PMD for DTB */ + create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA, + (uintptr_t)early_dtb_pmd, PGDIR_SIZE, PAGE_TABLE); ++#ifndef CONFIG_BUILTIN_DTB + /* Create two consecutive PMD mappings for FDT early scan */ + pa = dtb_pa & ~(PMD_SIZE - 1); + create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA, +@@ -506,7 +536,20 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) + create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA + PMD_SIZE, + pa + PMD_SIZE, PMD_SIZE, PAGE_KERNEL); + dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PMD_SIZE - 1)); ++#else /* CONFIG_BUILTIN_DTB */ ++#ifdef CONFIG_64BIT ++ /* ++ * __va can't be used since it would return a linear mapping address ++ * whereas dtb_early_va will be used before setup_vm_final installs ++ * the linear mapping. ++ */ ++ dtb_early_va = kernel_mapping_pa_to_va(dtb_pa); ++#else ++ dtb_early_va = __va(dtb_pa); ++#endif /* CONFIG_64BIT */ ++#endif /* CONFIG_BUILTIN_DTB */ + #else ++#ifndef CONFIG_BUILTIN_DTB + /* Create two consecutive PGD mappings for FDT early scan */ + pa = dtb_pa & ~(PGDIR_SIZE - 1); + create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA, +@@ -514,6 +557,13 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) + create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA + PGDIR_SIZE, + pa + PGDIR_SIZE, PGDIR_SIZE, PAGE_KERNEL); + dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PGDIR_SIZE - 1)); ++#else /* CONFIG_BUILTIN_DTB */ ++#ifdef CONFIG_64BIT ++ dtb_early_va = kernel_mapping_pa_to_va(dtb_pa); ++#else ++ dtb_early_va = __va(dtb_pa); ++#endif /* CONFIG_64BIT */ ++#endif /* CONFIG_BUILTIN_DTB */ + #endif + dtb_early_pa = dtb_pa; + +@@ -548,6 +598,22 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) + #endif + } + ++#ifdef CONFIG_64BIT ++void protect_kernel_linear_mapping_text_rodata(void) ++{ ++ unsigned long text_start = (unsigned long)lm_alias(_start); ++ unsigned long init_text_start = (unsigned long)lm_alias(__init_text_begin); ++ unsigned long rodata_start = (unsigned long)lm_alias(__start_rodata); ++ unsigned long data_start = (unsigned long)lm_alias(_data); ++ ++ set_memory_ro(text_start, (init_text_start - text_start) >> PAGE_SHIFT); ++ set_memory_nx(text_start, (init_text_start - text_start) >> PAGE_SHIFT); ++ ++ set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); ++ set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); ++} ++#endif ++ + static void __init setup_vm_final(void) + { + uintptr_t va, map_size; +@@ -569,7 +635,7 @@ static void __init setup_vm_final(void) + __pa_symbol(fixmap_pgd_next), + PGDIR_SIZE, PAGE_TABLE); + +- /* Map all memory banks */ ++ /* Map all memory banks in the linear mapping */ + for_each_mem_range(i, &start, &end) { + if (start >= end) + break; +@@ -581,10 +647,22 @@ static void __init setup_vm_final(void) + for (pa = start; pa < end; pa += map_size) { + va = (uintptr_t)__va(pa); + create_pgd_mapping(swapper_pg_dir, va, pa, +- map_size, PAGE_KERNEL_EXEC); ++ map_size, ++#ifdef CONFIG_64BIT ++ PAGE_KERNEL ++#else ++ PAGE_KERNEL_EXEC ++#endif ++ ); ++ + } + } + ++#ifdef CONFIG_64BIT ++ /* Map the kernel */ ++ create_kernel_page_table(swapper_pg_dir, PMD_SIZE); ++#endif ++ + /* Clear fixmap PTE and PMD mappings */ + clear_fixmap(FIX_PTE); + clear_fixmap(FIX_PMD); +@@ -622,18 +700,33 @@ static inline void setup_vm_final(void) + #endif /* CONFIG_MMU */ + + #ifdef CONFIG_STRICT_KERNEL_RWX ++void protect_kernel_text_data(void) ++{ ++ unsigned long text_start = (unsigned long)_start; ++ unsigned long init_text_start = (unsigned long)__init_text_begin; ++ unsigned long init_data_start = (unsigned long)__init_data_begin; ++ unsigned long rodata_start = (unsigned long)__start_rodata; ++ unsigned long data_start = (unsigned long)_data; ++#if defined(CONFIG_64BIT) && defined(CONFIG_MMU) ++ unsigned long end_va = kernel_virt_addr + load_sz; ++#else ++ unsigned long end_va = (unsigned long)(__va(PFN_PHYS(max_low_pfn))); ++#endif ++ ++ set_memory_ro(text_start, (init_text_start - text_start) >> PAGE_SHIFT); ++ set_memory_ro(init_text_start, (init_data_start - init_text_start) >> PAGE_SHIFT); ++ set_memory_nx(init_data_start, (rodata_start - init_data_start) >> PAGE_SHIFT); ++ /* rodata section is marked readonly in mark_rodata_ro */ ++ set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); ++ set_memory_nx(data_start, (end_va - data_start) >> PAGE_SHIFT); ++} ++ + void mark_rodata_ro(void) + { +- unsigned long text_start = (unsigned long)_text; +- unsigned long text_end = (unsigned long)_etext; + unsigned long rodata_start = (unsigned long)__start_rodata; + unsigned long data_start = (unsigned long)_data; +- unsigned long max_low = (unsigned long)(__va(PFN_PHYS(max_low_pfn))); + +- set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT); + set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); +- set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); +- set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT); + + debug_checkwx(); + } +diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c +index 2db442701ee2..0d001b60a12f 100644 +--- a/arch/riscv/mm/kasan_init.c ++++ b/arch/riscv/mm/kasan_init.c +@@ -87,16 +87,21 @@ static void __init populate(void *start, void *end) + + void __init kasan_init(void) + { +- phys_addr_t _start, _end; ++ phys_addr_t p_start, p_end; + u64 i; + ++ /* ++ * Populate all kernel virtual address space with kasan_early_shadow_page ++ * except for the linear mapping and the modules/kernel/BPF mapping. ++ */ + kasan_populate_early_shadow((void *)KASAN_SHADOW_START, + (void *)kasan_mem_to_shadow((void *) + VMALLOC_END)); + +- for_each_mem_range(i, &_start, &_end) { +- void *start = (void *)__va(_start); +- void *end = (void *)__va(_end); ++ /* Populate the linear mapping */ ++ for_each_mem_range(i, &p_start, &p_end) { ++ void *start = (void *)__va(p_start); ++ void *end = (void *)__va(p_end); + + if (start >= end) + break; +@@ -104,6 +109,10 @@ void __init kasan_init(void) + populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end)); + }; + ++ /* Populate kernel, BPF, modules mapping */ ++ kasan_populate(kasan_mem_to_shadow((const void *)MODULES_VADDR), ++ kasan_mem_to_shadow((const void *)BPF_JIT_REGION_END)); ++ + for (i = 0; i < PTRS_PER_PTE; i++) + set_pte(&kasan_early_shadow_pte[i], + mk_pte(virt_to_page(kasan_early_shadow_page), +diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c +index 09f6be19ba7b..4bea8f5e3a83 100644 +--- a/arch/riscv/mm/pageattr.c ++++ b/arch/riscv/mm/pageattr.c +@@ -128,6 +128,12 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, + return ret; + } + ++int set_memory_rw_nx(unsigned long addr, int numpages) ++{ ++ return __set_memory(addr, numpages, __pgprot(_PAGE_READ | _PAGE_WRITE), ++ __pgprot(_PAGE_EXEC)); ++} ++ + int set_memory_ro(unsigned long addr, int numpages) + { + return __set_memory(addr, numpages, __pgprot(_PAGE_READ), +diff --git a/arch/riscv/mm/physaddr.c b/arch/riscv/mm/physaddr.c +index e8e4dcd39fed..35703d5ef5fd 100644 +--- a/arch/riscv/mm/physaddr.c ++++ b/arch/riscv/mm/physaddr.c +@@ -23,7 +23,7 @@ EXPORT_SYMBOL(__virt_to_phys); + + phys_addr_t __phys_addr_symbol(unsigned long x) + { +- unsigned long kernel_start = (unsigned long)PAGE_OFFSET; ++ unsigned long kernel_start = (unsigned long)kernel_virt_addr; + unsigned long kernel_end = (unsigned long)_end; + + /* +diff --git a/scripts/Makefile.clang b/scripts/Makefile.clang +new file mode 100644 +index 000000000000..6c23c6af797f +--- /dev/null ++++ b/scripts/Makefile.clang +@@ -0,0 +1,39 @@ ++# Individual arch/{arch}/Makefiles should use -EL/-EB to set intended ++# endianness and -m32/-m64 to set word size based on Kconfigs instead of ++# relying on the target triple. ++CLANG_TARGET_FLAGS_arm := arm-linux-gnueabi ++CLANG_TARGET_FLAGS_arm64 := aarch64-linux-gnu ++CLANG_TARGET_FLAGS_hexagon := hexagon-linux-musl ++CLANG_TARGET_FLAGS_loongarch := loongarch64-linux-gnusf ++CLANG_TARGET_FLAGS_m68k := m68k-linux-gnu ++CLANG_TARGET_FLAGS_mips := mipsel-linux-gnu ++CLANG_TARGET_FLAGS_powerpc := powerpc64le-linux-gnu ++CLANG_TARGET_FLAGS_riscv := riscv64-linux-gnu ++CLANG_TARGET_FLAGS_s390 := s390x-linux-gnu ++CLANG_TARGET_FLAGS_x86 := x86_64-linux-gnu ++CLANG_TARGET_FLAGS_um := $(CLANG_TARGET_FLAGS_$(SUBARCH)) ++CLANG_TARGET_FLAGS := $(CLANG_TARGET_FLAGS_$(SRCARCH)) ++ ++ifeq ($(CLANG_TARGET_FLAGS),) ++$(error add '--target=' option to scripts/Makefile.clang) ++else ++CLANG_FLAGS += --target=$(CLANG_TARGET_FLAGS) ++endif ++ ++ifeq ($(LLVM_IAS),0) ++CLANG_FLAGS += -fno-integrated-as ++GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)elfedit)) ++CLANG_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE)) ++else ++CLANG_FLAGS += -fintegrated-as ++endif ++# By default, clang only warns when it encounters an unknown warning flag or ++# certain optimization flags it knows it has not implemented. ++# Make it behave more like gcc by erroring when these flags are encountered ++# so they can be implemented or wrapped in cc-option. ++CLANG_FLAGS += -Werror=unknown-warning-option ++CLANG_FLAGS += -Werror=ignored-optimization-argument ++CLANG_FLAGS += -Werror=option-ignored ++CLANG_FLAGS += -Werror=unused-command-line-argument ++KBUILD_CPPFLAGS += $(CLANG_FLAGS) ++export CLANG_FLAGS -- Gitee