2023-01-09 09:42:56

by Youling Tang

[permalink] [raw]
Subject: [PATCH 0/4] LoongArch: Add kernel relocation and KASLR support

This patch series to support kernel relocation and KASLR (only 64bit).

Both old[1] and new[2] toolchains support this feature, and the test results
are as follows:
1) Enable CONFING_RELOCATABLE
# cat /proc/iomem
00000000-0fffffff : System RAM
00000000-002c3fff : Reserved
002c4000-008c3fff : Reserved
02000000-02f4ffff : Kernel code
02f50000-0381cbff : Kernel data
0381cc00-0394ae37 : Kernel bss

2) Enable CONFING_RANDOMIZE_BASE (KASLR)
first:
# cat /proc/iomem
00000000-0fffffff : System RAM
00000000-002c3fff : Reserved
002c4000-008c3fff : Reserved
02550000-0349ffff : Kernel code
034a0000-03d6cbff : Kernel data
03d6cc00-03e9ae37 : Kernel bss

second:
# cat /proc/iomem
00000000-0fffffff : System RAM
00000000-002c3fff : Reserved
002c4000-008c3fff : Reserved
02ad0000-03a1ffff : Kernel code
03a20000-042ecbff : Kernel data
042ecc00-0441ae37 : Kernel bss

Thanks to @Ruoyao's and @Jinyang's for their help and suggestions.

Links:
[1]: https://github.com/sunhaiyong1978/CLFS-for-LoongArch/releases/download/5.0/loongarch64-clfs-5.1-cross-tools-c-only.tar.xz
[2]: https://github.com/sunhaiyong1978/CLFS-for-LoongArch/releases/download/6.0/loongarch64-clfs-6.3-cross-tools-c-only.tar.xz

Xi Ruoyao (1):
LoongArch: Use trampoline for exception handlers and kill la.abs

Youling Tang (3):
LoongArch: Add JUMP_LINK_ADDR macro implementation to avoid using
la.abs
LoongArch: Add support for kernel relocation
LoongArch: Add support for kernel address space layout randomization
(KASLR)

arch/loongarch/Kconfig | 37 +++++
arch/loongarch/Makefile | 5 +
arch/loongarch/include/asm/page.h | 6 +
arch/loongarch/include/asm/stackframe.h | 16 +-
arch/loongarch/include/asm/uaccess.h | 1 -
arch/loongarch/kernel/Makefile | 2 +
arch/loongarch/kernel/entry.S | 6 +-
arch/loongarch/kernel/genex.S | 20 +--
arch/loongarch/kernel/head.S | 30 +++-
arch/loongarch/kernel/relocate.c | 210 ++++++++++++++++++++++++
arch/loongarch/kernel/setup.c | 3 +
arch/loongarch/kernel/traps.c | 4 +-
arch/loongarch/kernel/vmlinux.lds.S | 11 +-
arch/loongarch/mm/tlbex.S | 28 +---
arch/loongarch/power/suspend_asm.S | 5 +-
15 files changed, 333 insertions(+), 51 deletions(-)
create mode 100644 arch/loongarch/kernel/relocate.c

--
2.37.1


2023-01-09 09:51:54

by Youling Tang

[permalink] [raw]
Subject: [PATCH 3/4] LoongArch: Add support for kernel relocation

arch/loongarch/kernel/relocate.c contains the functions necessary to
relocate the kernel elsewhere in memory.

The kernel makes a copy of itself at the new address. It uses the
relocation table inserted by the relocs tool to fix symbol references
within the new image.

If copy/relocation is successful then the entry point of the new kernel
is returned, otherwise fall back to starting the kernel in place.

Signed-off-by: Youling Tang <[email protected]>
---
arch/loongarch/Kconfig | 15 +++++
arch/loongarch/Makefile | 5 ++
arch/loongarch/kernel/Makefile | 2 +
arch/loongarch/kernel/head.S | 18 ++++++
arch/loongarch/kernel/relocate.c | 96 +++++++++++++++++++++++++++++
arch/loongarch/kernel/vmlinux.lds.S | 11 +++-
6 files changed, 145 insertions(+), 2 deletions(-)
create mode 100644 arch/loongarch/kernel/relocate.c

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 9cc8b84f7eb0..089a4695b1b3 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -48,6 +48,7 @@ config LOONGARCH
select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_HUGETLBFS
select ARCH_SUPPORTS_NUMA_BALANCING
+ select SYS_SUPPORTS_RELOCATABLE
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_USE_QUEUED_RWLOCKS
@@ -229,6 +230,11 @@ config SCHED_OMIT_FRAME_POINTER
config AS_HAS_EXPLICIT_RELOCS
def_bool $(as-instr,x:pcalau12i \$t0$(comma)%pc_hi20(x))

+config SYS_SUPPORTS_RELOCATABLE
+ bool
+ help
+ Selected if the platform supports relocating the kernel.
+
menu "Kernel type and options"

source "kernel/Kconfig.hz"
@@ -474,6 +480,15 @@ config PHYSICAL_START
specified in the "crashkernel=YM@XM" command line boot parameter
passed to the panic-ed kernel).

+config RELOCATABLE
+ bool "Relocatable kernel"
+ depends on SYS_SUPPORTS_RELOCATABLE
+ help
+ This builds the kernel as a Position Independent Executable (PIE),
+ which retains all relocation metadata required to relocate the
+ kernel binary at runtime to a different virtual address than the
+ address it was linked at.
+
config SECCOMP
bool "Enable seccomp to safely compute untrusted bytecode"
depends on PROC_FS
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index 4402387d2755..27b5a70ff31c 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -71,6 +71,11 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs
KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
endif

+ifeq ($(CONFIG_RELOCATABLE),y)
+LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext
+KBUILD_CFLAGS_KERNEL += -fPIE
+endif
+
cflags-y += -ffreestanding
cflags-y += $(call cc-option, -mno-check-zero-division)

diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index fcaa024a685e..33787d22e6f4 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -31,6 +31,8 @@ endif
obj-$(CONFIG_MODULES) += module.o module-sections.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o

+obj-$(CONFIG_RELOCATABLE) += relocate.o
+
obj-$(CONFIG_PROC_FS) += proc.o

obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index e8a4bf9d7599..6db1549177ad 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -88,7 +88,25 @@ SYM_CODE_START(kernel_entry) # kernel entry point
PTR_ADD sp, sp, tp
set_saved_sp sp, t0, t1

+#ifdef CONFIG_RELOCATABLE
+ /* Copy kernel and apply the relocations */
+ bl relocate_kernel
+
+ /* Repoint the sp into the new kernel image */
+ PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE)
+ PTR_ADD sp, sp, tp
+ set_saved_sp sp, t0, t1
+ PTR_ADDI sp, sp, -4 * SZREG # init stack pointer
+
+ /*
+ * relocate_kernel returns the entry point either
+ * in the relocated kernel or the original if for
+ * some reason relocation failed.
+ */
+ jr a0
+#else
bl start_kernel
+#endif
ASM_BUG()

SYM_CODE_END(kernel_entry)
diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
new file mode 100644
index 000000000000..a58551c0698d
--- /dev/null
+++ b/arch/loongarch/kernel/relocate.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for Kernel relocation at boot time
+ *
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/start_kernel.h>
+#include <linux/printk.h>
+#include <linux/panic_notifier.h>
+#include <asm/bootinfo.h>
+#include <asm/inst.h>
+#include <asm/sections.h>
+
+#define RELOCATED(x) ((void *)((long)x + offset))
+
+extern long __rela_dyn_start;
+extern long __rela_dyn_end;
+
+/*
+ * Choose a new address for the kernel, for now we'll hard
+ * code the destination.
+ */
+static inline void __init *determine_relocation_address(void)
+{
+ return (void *)(CACHE_BASE + 0x02000000);
+}
+
+static inline int __init relocation_addr_valid(void *loc_new)
+{
+ if ((unsigned long)loc_new & 0x0000ffff) {
+ /* Inappropriately aligned new location */
+ return 0;
+ }
+ if ((unsigned long)loc_new < (unsigned long)_end) {
+ /* New location overlaps original kernel */
+ return 0;
+ }
+ return 1;
+}
+
+void *__init relocate_kernel(void)
+{
+ Elf64_Rela *rela, *rela_end;
+ void *loc_new;
+ unsigned long kernel_length;
+ long offset = 0;
+ int res = 1;
+ /* Default to original kernel entry point */
+ void *kernel_entry = start_kernel;
+
+ kernel_length = (long)(_end) - (long)(_text);
+
+ loc_new = determine_relocation_address();
+
+ /* Sanity check relocation address */
+ if (relocation_addr_valid(loc_new))
+ offset = (unsigned long)loc_new - (unsigned long)(_text);
+
+ if (offset) {
+ /* Copy the kernel to it's new location */
+ memcpy(loc_new, _text, kernel_length);
+
+ /* Sync the caches ready for execution of new kernel */
+ __asm__ __volatile__ (
+ "ibar 0 \t\n"
+ "dbar 0 \t\n");
+
+ rela = (Elf64_Rela *)RELOCATED(&__rela_dyn_start);
+ rela_end = (Elf64_Rela *)RELOCATED(&__rela_dyn_end);
+
+ for ( ; rela < rela_end; rela++) {
+ Elf64_Addr addr = rela->r_offset;
+ Elf64_Addr relocated_addr = rela->r_addend;
+
+ if (rela->r_info != R_LARCH_RELATIVE)
+ continue;
+
+ if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
+ relocated_addr = RELOCATED(relocated_addr);
+
+ *(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
+
+ }
+
+ /* The current thread is now within the relocated image */
+ __current_thread_info = RELOCATED(__current_thread_info);
+
+ /* Return the new kernel's entry point */
+ kernel_entry = RELOCATED(start_kernel);
+ }
+out:
+ return kernel_entry;
+}
diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
index 733b16e8d55d..aec0b6567d24 100644
--- a/arch/loongarch/kernel/vmlinux.lds.S
+++ b/arch/loongarch/kernel/vmlinux.lds.S
@@ -70,6 +70,8 @@ SECTIONS
.plt : ALIGN(16) { *(.plt) }
.got.plt : ALIGN(16) { *(.got.plt) }

+ .data.rel : { *(.data.rel*) }
+
. = ALIGN(PECOFF_SEGMENT_ALIGN);
__init_begin = .;
__inittext_begin = .;
@@ -93,8 +95,6 @@ SECTIONS
PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
#endif

- .rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
-
.init.bss : {
*(.init.bss)
}
@@ -107,6 +107,12 @@ SECTIONS
RO_DATA(4096)
RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)

+ .rela.dyn : ALIGN(8) {
+ __rela_dyn_start = .;
+ *(.rela.dyn) *(.rela*)
+ __rela_dyn_end = .;
+ }
+
.sdata : {
*(.sdata)
}
@@ -133,6 +139,7 @@ SECTIONS

DISCARDS
/DISCARD/ : {
+ *(.dynamic .dynsym .dynstr .hash .gnu.hash)
*(.gnu.attributes)
*(.options)
*(.eh_frame)
--
2.37.1

2023-01-09 09:55:36

by Youling Tang

[permalink] [raw]
Subject: [PATCH 1/4] LoongArch: Use trampoline for exception handlers and kill la.abs

From: Xi Ruoyao <[email protected]>

Use a trampoline as an exception handlers, which can kill some use of
la.abs in preparation for the subsequent support of the PIE kernel.

Signed-off-by: Xi Ruoyao <[email protected]>
Signed-off-by: Youling Tang <[email protected]>
---
arch/loongarch/include/asm/stackframe.h | 8 +++----
arch/loongarch/include/asm/uaccess.h | 1 -
arch/loongarch/kernel/entry.S | 6 +++---
arch/loongarch/kernel/genex.S | 20 +++++++++---------
arch/loongarch/kernel/head.S | 2 +-
arch/loongarch/kernel/traps.c | 4 +++-
arch/loongarch/mm/tlbex.S | 28 +++++++------------------
7 files changed, 29 insertions(+), 40 deletions(-)

diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
index 4ca953062b5b..96c94035b5d0 100644
--- a/arch/loongarch/include/asm/stackframe.h
+++ b/arch/loongarch/include/asm/stackframe.h
@@ -76,8 +76,8 @@
* kernelsp array for it. It stores the current sp in t0 and loads the
* new value in sp.
*/
- .macro get_saved_sp docfi=0
- la.abs t1, kernelsp
+ .macro get_saved_sp docfi=0
+ la.pcrel t1, kernelsp
#ifdef CONFIG_SMP
csrrd t0, PERCPU_BASE_KS
LONG_ADD t1, t1, t0
@@ -89,8 +89,8 @@
LONG_L sp, t1, 0
.endm

- .macro set_saved_sp stackp temp temp2
- la.abs \temp, kernelsp
+ .macro set_saved_sp stackp temp temp2
+ la.pcrel \temp, kernelsp
#ifdef CONFIG_SMP
LONG_ADD \temp, \temp, u0
#endif
diff --git a/arch/loongarch/include/asm/uaccess.h b/arch/loongarch/include/asm/uaccess.h
index 255899d4a7c3..0d22991ae430 100644
--- a/arch/loongarch/include/asm/uaccess.h
+++ b/arch/loongarch/include/asm/uaccess.h
@@ -22,7 +22,6 @@
extern u64 __ua_limit;

#define __UA_ADDR ".dword"
-#define __UA_LA "la.abs"
#define __UA_LIMIT __ua_limit

/*
diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S
index d53b631c9022..ca01afdbec3f 100644
--- a/arch/loongarch/kernel/entry.S
+++ b/arch/loongarch/kernel/entry.S
@@ -18,9 +18,9 @@
.text
.cfi_sections .debug_frame
.align 5
-SYM_FUNC_START(handle_syscall)
+SYM_FUNC_START(handle_sys)
csrrd t0, PERCPU_BASE_KS
- la.abs t1, kernelsp
+ la.pcrel t1, kernelsp
add.d t1, t1, t0
move t2, sp
ld.d sp, t1, 0
@@ -66,7 +66,7 @@ SYM_FUNC_START(handle_syscall)
bl do_syscall

RESTORE_ALL_AND_RET
-SYM_FUNC_END(handle_syscall)
+SYM_FUNC_END(handle_sys)

SYM_CODE_START(ret_from_fork)
bl schedule_tail # a0 = struct task_struct *prev
diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S
index 75e5be807a0d..d3df0fa725a2 100644
--- a/arch/loongarch/kernel/genex.S
+++ b/arch/loongarch/kernel/genex.S
@@ -32,9 +32,8 @@ SYM_FUNC_START(__arch_cpu_idle)
SYM_FUNC_END(__arch_cpu_idle)

SYM_FUNC_START(handle_vint)
- BACKUP_T0T1
SAVE_ALL
- la.abs t1, __arch_cpu_idle
+ la.pcrel t1, __arch_cpu_idle
LONG_L t0, sp, PT_ERA
/* 32 byte rollback region */
ori t0, t0, 0x1f
@@ -43,8 +42,7 @@ SYM_FUNC_START(handle_vint)
LONG_S t0, sp, PT_ERA
1: move a0, sp
move a1, sp
- la.abs t0, do_vint
- jirl ra, t0, 0
+ bl do_vint
RESTORE_ALL_AND_RET
SYM_FUNC_END(handle_vint)

@@ -67,12 +65,10 @@ SYM_FUNC_END(except_vec_cex)
.macro BUILD_HANDLER exception handler prep
.align 5
SYM_FUNC_START(handle_\exception)
- BACKUP_T0T1
SAVE_ALL
build_prep_\prep
move a0, sp
- la.abs t0, do_\handler
- jirl ra, t0, 0
+ bl do_\handler
RESTORE_ALL_AND_RET
SYM_FUNC_END(handle_\exception)
.endm
@@ -89,7 +85,11 @@ SYM_FUNC_END(except_vec_cex)
BUILD_HANDLER watch watch none
BUILD_HANDLER reserved reserved none /* others */

-SYM_FUNC_START(handle_sys)
- la.abs t0, handle_syscall
+SYM_FUNC_START(handler_trampoline)
+ csrwr t0, EXCEPTION_KS0
+ csrwr t1, EXCEPTION_KS1
+ pcaddi t0, 0
+ ld.d t0, t0, 16
jr t0
-SYM_FUNC_END(handle_sys)
+ nop
+SYM_FUNC_END(handler_trampoline)
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index 57bada6b4e93..aa6181714ec3 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -117,7 +117,7 @@ SYM_CODE_START(smpboot_entry)
li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
csrwr t0, LOONGARCH_CSR_EUEN

- la.abs t0, cpuboot_data
+ la.pcrel t0, cpuboot_data
ld.d sp, t0, CPU_BOOT_STACK
ld.d tp, t0, CPU_BOOT_TINFO

diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
index 7ea62faeeadb..0e8faaca3679 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -61,6 +61,7 @@ extern asmlinkage void handle_lasx(void);
extern asmlinkage void handle_reserved(void);
extern asmlinkage void handle_watch(void);
extern asmlinkage void handle_vint(void);
+extern asmlinkage void handler_trampoline(void);

static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
const char *loglvl, bool user)
@@ -716,7 +717,8 @@ void per_cpu_trap_init(int cpu)
/* Install CPU exception handler */
void set_handler(unsigned long offset, void *addr, unsigned long size)
{
- memcpy((void *)(eentry + offset), addr, size);
+ memcpy((void *)(eentry + offset), &handler_trampoline, 24);
+ memcpy((void *)(eentry + offset + 24), &addr, 8);
local_flush_icache_range(eentry + offset, eentry + offset + size);
}

diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S
index 58781c6e4191..cfaacdac518c 100644
--- a/arch/loongarch/mm/tlbex.S
+++ b/arch/loongarch/mm/tlbex.S
@@ -24,8 +24,7 @@
move a0, sp
REG_S a2, sp, PT_BVADDR
li.w a1, \write
- la.abs t0, do_page_fault
- jirl ra, t0, 0
+ bl do_page_fault
RESTORE_ALL_AND_RET
SYM_FUNC_END(tlb_do_page_fault_\write)
.endm
@@ -34,20 +33,16 @@
tlb_do_page_fault 1

SYM_FUNC_START(handle_tlb_protect)
- BACKUP_T0T1
SAVE_ALL
move a0, sp
move a1, zero
csrrd a2, LOONGARCH_CSR_BADV
REG_S a2, sp, PT_BVADDR
- la.abs t0, do_page_fault
- jirl ra, t0, 0
+ bl do_page_fault
RESTORE_ALL_AND_RET
SYM_FUNC_END(handle_tlb_protect)

SYM_FUNC_START(handle_tlb_load)
- csrwr t0, EXCEPTION_KS0
- csrwr t1, EXCEPTION_KS1
csrwr ra, EXCEPTION_KS2

/*
@@ -116,7 +111,7 @@ smp_pgtable_change_load:

#ifdef CONFIG_64BIT
vmalloc_load:
- la.abs t1, swapper_pg_dir
+ la.pcrel t1, swapper_pg_dir
b vmalloc_done_load
#endif

@@ -187,13 +182,10 @@ tlb_huge_update_load:
nopage_tlb_load:
dbar 0
csrrd ra, EXCEPTION_KS2
- la.abs t0, tlb_do_page_fault_0
- jr t0
+ b tlb_do_page_fault_0
SYM_FUNC_END(handle_tlb_load)

SYM_FUNC_START(handle_tlb_store)
- csrwr t0, EXCEPTION_KS0
- csrwr t1, EXCEPTION_KS1
csrwr ra, EXCEPTION_KS2

/*
@@ -263,7 +255,7 @@ smp_pgtable_change_store:

#ifdef CONFIG_64BIT
vmalloc_store:
- la.abs t1, swapper_pg_dir
+ la.pcrel t1, swapper_pg_dir
b vmalloc_done_store
#endif

@@ -336,13 +328,10 @@ tlb_huge_update_store:
nopage_tlb_store:
dbar 0
csrrd ra, EXCEPTION_KS2
- la.abs t0, tlb_do_page_fault_1
- jr t0
+ b tlb_do_page_fault_1
SYM_FUNC_END(handle_tlb_store)

SYM_FUNC_START(handle_tlb_modify)
- csrwr t0, EXCEPTION_KS0
- csrwr t1, EXCEPTION_KS1
csrwr ra, EXCEPTION_KS2

/*
@@ -411,7 +400,7 @@ smp_pgtable_change_modify:

#ifdef CONFIG_64BIT
vmalloc_modify:
- la.abs t1, swapper_pg_dir
+ la.pcrel t1, swapper_pg_dir
b vmalloc_done_modify
#endif

@@ -483,8 +472,7 @@ tlb_huge_update_modify:
nopage_tlb_modify:
dbar 0
csrrd ra, EXCEPTION_KS2
- la.abs t0, tlb_do_page_fault_1
- jr t0
+ b tlb_do_page_fault_1
SYM_FUNC_END(handle_tlb_modify)

SYM_FUNC_START(handle_tlb_refill)
--
2.37.1

2023-01-09 22:04:40

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 3/4] LoongArch: Add support for kernel relocation

Hi Youling,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.2-rc3 next-20230109]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Youling-Tang/LoongArch-Use-trampoline-for-exception-handlers-and-kill-la-abs/20230109-171344
patch link: https://lore.kernel.org/r/1673255274-18238-4-git-send-email-tangyouling%40loongson.cn
patch subject: [PATCH 3/4] LoongArch: Add support for kernel relocation
config: loongarch-allmodconfig
compiler: loongarch64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/35b3031ab84fc4832dd66a381f37fb2dcec8e5c1
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Youling-Tang/LoongArch-Use-trampoline-for-exception-handlers-and-kill-la-abs/20230109-171344
git checkout 35b3031ab84fc4832dd66a381f37fb2dcec8e5c1
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=loongarch olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=loongarch SHELL=/bin/bash arch/loongarch/kernel/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

Note: functions only called from assembly code should be annotated with the asmlinkage attribute
All warnings (new ones prefixed by >>):

>> arch/loongarch/kernel/relocate.c:44:14: warning: no previous prototype for 'relocate_kernel' [-Wmissing-prototypes]
44 | void *__init relocate_kernel(void)
| ^~~~~~~~~~~~~~~
arch/loongarch/kernel/relocate.c: In function 'relocate_kernel':
>> arch/loongarch/kernel/relocate.c:82:48: warning: assignment to 'Elf64_Addr' {aka 'long long unsigned int'} from 'void *' makes integer from pointer without a cast [-Wint-conversion]
82 | relocated_addr = RELOCATED(relocated_addr);
| ^
arch/loongarch/kernel/relocate.c:94:1: warning: label 'out' defined but not used [-Wunused-label]
94 | out:
| ^~~
arch/loongarch/kernel/relocate.c:50:13: warning: unused variable 'res' [-Wunused-variable]
50 | int res = 1;
| ^~~


vim +/relocate_kernel +44 arch/loongarch/kernel/relocate.c

43
> 44 void *__init relocate_kernel(void)
45 {
46 Elf64_Rela *rela, *rela_end;
47 void *loc_new;
48 unsigned long kernel_length;
49 long offset = 0;
50 int res = 1;
51 /* Default to original kernel entry point */
52 void *kernel_entry = start_kernel;
53
54 kernel_length = (long)(_end) - (long)(_text);
55
56 loc_new = determine_relocation_address();
57
58 /* Sanity check relocation address */
59 if (relocation_addr_valid(loc_new))
60 offset = (unsigned long)loc_new - (unsigned long)(_text);
61
62 if (offset) {
63 /* Copy the kernel to it's new location */
64 memcpy(loc_new, _text, kernel_length);
65
66 /* Sync the caches ready for execution of new kernel */
67 __asm__ __volatile__ (
68 "ibar 0 \t\n"
69 "dbar 0 \t\n");
70
71 rela = (Elf64_Rela *)RELOCATED(&__rela_dyn_start);
72 rela_end = (Elf64_Rela *)RELOCATED(&__rela_dyn_end);
73
74 for ( ; rela < rela_end; rela++) {
75 Elf64_Addr addr = rela->r_offset;
76 Elf64_Addr relocated_addr = rela->r_addend;
77
78 if (rela->r_info != R_LARCH_RELATIVE)
79 continue;
80
81 if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
> 82 relocated_addr = RELOCATED(relocated_addr);

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests


Attachments:
(No filename) (4.26 kB)
config (333.17 kB)
Download all attachments

2023-01-11 03:28:33

by Youling Tang

[permalink] [raw]
Subject: Re: [PATCH 3/4] LoongArch: Add support for kernel relocation



On 01/09/2023 05:07 PM, Youling Tang wrote:
> arch/loongarch/kernel/relocate.c contains the functions necessary to
> relocate the kernel elsewhere in memory.
>
> The kernel makes a copy of itself at the new address. It uses the
> relocation table inserted by the relocs tool to fix symbol references
> within the new image.
>
> If copy/relocation is successful then the entry point of the new kernel
> is returned, otherwise fall back to starting the kernel in place.
>
> Signed-off-by: Youling Tang <[email protected]>
> ---
> arch/loongarch/Kconfig | 15 +++++
> arch/loongarch/Makefile | 5 ++
> arch/loongarch/kernel/Makefile | 2 +
> arch/loongarch/kernel/head.S | 18 ++++++
> arch/loongarch/kernel/relocate.c | 96 +++++++++++++++++++++++++++++
> arch/loongarch/kernel/vmlinux.lds.S | 11 +++-
> 6 files changed, 145 insertions(+), 2 deletions(-)
> create mode 100644 arch/loongarch/kernel/relocate.c
>
> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> index 9cc8b84f7eb0..089a4695b1b3 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -48,6 +48,7 @@ config LOONGARCH
> select ARCH_SUPPORTS_ATOMIC_RMW
> select ARCH_SUPPORTS_HUGETLBFS
> select ARCH_SUPPORTS_NUMA_BALANCING
> + select SYS_SUPPORTS_RELOCATABLE
> select ARCH_USE_BUILTIN_BSWAP
> select ARCH_USE_CMPXCHG_LOCKREF
> select ARCH_USE_QUEUED_RWLOCKS
> @@ -229,6 +230,11 @@ config SCHED_OMIT_FRAME_POINTER
> config AS_HAS_EXPLICIT_RELOCS
> def_bool $(as-instr,x:pcalau12i \$t0$(comma)%pc_hi20(x))
>
> +config SYS_SUPPORTS_RELOCATABLE
> + bool
> + help
> + Selected if the platform supports relocating the kernel.
> +
> menu "Kernel type and options"
>
> source "kernel/Kconfig.hz"
> @@ -474,6 +480,15 @@ config PHYSICAL_START
> specified in the "crashkernel=YM@XM" command line boot parameter
> passed to the panic-ed kernel).
>
> +config RELOCATABLE
> + bool "Relocatable kernel"
> + depends on SYS_SUPPORTS_RELOCATABLE
> + help
> + This builds the kernel as a Position Independent Executable (PIE),
> + which retains all relocation metadata required to relocate the
> + kernel binary at runtime to a different virtual address than the
> + address it was linked at.
> +
> config SECCOMP
> bool "Enable seccomp to safely compute untrusted bytecode"
> depends on PROC_FS
> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> index 4402387d2755..27b5a70ff31c 100644
> --- a/arch/loongarch/Makefile
> +++ b/arch/loongarch/Makefile
> @@ -71,6 +71,11 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs
> KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
> endif
>
> +ifeq ($(CONFIG_RELOCATABLE),y)
> +LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext
> +KBUILD_CFLAGS_KERNEL += -fPIE
> +endif
> +
> cflags-y += -ffreestanding
> cflags-y += $(call cc-option, -mno-check-zero-division)
>
> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
> index fcaa024a685e..33787d22e6f4 100644
> --- a/arch/loongarch/kernel/Makefile
> +++ b/arch/loongarch/kernel/Makefile
> @@ -31,6 +31,8 @@ endif
> obj-$(CONFIG_MODULES) += module.o module-sections.o
> obj-$(CONFIG_STACKTRACE) += stacktrace.o
>
> +obj-$(CONFIG_RELOCATABLE) += relocate.o
> +
> obj-$(CONFIG_PROC_FS) += proc.o
>
> obj-$(CONFIG_SMP) += smp.o
> diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> index e8a4bf9d7599..6db1549177ad 100644
> --- a/arch/loongarch/kernel/head.S
> +++ b/arch/loongarch/kernel/head.S
> @@ -88,7 +88,25 @@ SYM_CODE_START(kernel_entry) # kernel entry point
> PTR_ADD sp, sp, tp
> set_saved_sp sp, t0, t1
>
> +#ifdef CONFIG_RELOCATABLE
> + /* Copy kernel and apply the relocations */
> + bl relocate_kernel
> +
> + /* Repoint the sp into the new kernel image */
> + PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE)
> + PTR_ADD sp, sp, tp
> + set_saved_sp sp, t0, t1
> + PTR_ADDI sp, sp, -4 * SZREG # init stack pointer
PTR_ADDI sp, sp, -4 * SZREG # init stack pointer

This line needs to be removed.

> +
> + /*
> + * relocate_kernel returns the entry point either
> + * in the relocated kernel or the original if for
> + * some reason relocation failed.
> + */
> + jr a0
> +#else
> bl start_kernel
> +#endif
> ASM_BUG()
>
> SYM_CODE_END(kernel_entry)
> diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
> new file mode 100644
> index 000000000000..a58551c0698d
> --- /dev/null
> +++ b/arch/loongarch/kernel/relocate.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Support for Kernel relocation at boot time
> + *
> + * Copyright (C) 2023 Loongson Technology Corporation Limited
> + */
> +
> +#include <linux/elf.h>
> +#include <linux/kernel.h>
> +#include <linux/start_kernel.h>
> +#include <linux/printk.h>
> +#include <linux/panic_notifier.h>
> +#include <asm/bootinfo.h>
> +#include <asm/inst.h>
> +#include <asm/sections.h>
> +
> +#define RELOCATED(x) ((void *)((long)x + offset))
> +
> +extern long __rela_dyn_start;
> +extern long __rela_dyn_end;
> +
> +/*
> + * Choose a new address for the kernel, for now we'll hard
> + * code the destination.
> + */
> +static inline void __init *determine_relocation_address(void)
> +{
> + return (void *)(CACHE_BASE + 0x02000000);
> +}
> +
> +static inline int __init relocation_addr_valid(void *loc_new)
> +{
> + if ((unsigned long)loc_new & 0x0000ffff) {
> + /* Inappropriately aligned new location */
> + return 0;
> + }
> + if ((unsigned long)loc_new < (unsigned long)_end) {
> + /* New location overlaps original kernel */
> + return 0;
> + }
> + return 1;
> +}
> +
> +void *__init relocate_kernel(void)
> +{
> + Elf64_Rela *rela, *rela_end;
> + void *loc_new;
> + unsigned long kernel_length;
> + long offset = 0;
> + int res = 1;
> + /* Default to original kernel entry point */
> + void *kernel_entry = start_kernel;
> +
> + kernel_length = (long)(_end) - (long)(_text);
> +
> + loc_new = determine_relocation_address();
> +
> + /* Sanity check relocation address */
> + if (relocation_addr_valid(loc_new))
> + offset = (unsigned long)loc_new - (unsigned long)(_text);
> +
> + if (offset) {
> + /* Copy the kernel to it's new location */
> + memcpy(loc_new, _text, kernel_length);
> +
> + /* Sync the caches ready for execution of new kernel */
> + __asm__ __volatile__ (
> + "ibar 0 \t\n"
> + "dbar 0 \t\n");
> +
> + rela = (Elf64_Rela *)RELOCATED(&__rela_dyn_start);
> + rela_end = (Elf64_Rela *)RELOCATED(&__rela_dyn_end);
> +
> + for ( ; rela < rela_end; rela++) {
> + Elf64_Addr addr = rela->r_offset;
> + Elf64_Addr relocated_addr = rela->r_addend;
> +
> + if (rela->r_info != R_LARCH_RELATIVE)
> + continue;
> +
> + if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
> + relocated_addr = RELOCATED(relocated_addr);
> +
> + *(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
> +
> + }
> +
> + /* The current thread is now within the relocated image */
> + __current_thread_info = RELOCATED(__current_thread_info);
> +
> + /* Return the new kernel's entry point */
> + kernel_entry = RELOCATED(start_kernel);
> + }
> +out:
> + return kernel_entry;
> +}
> diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
> index 733b16e8d55d..aec0b6567d24 100644
> --- a/arch/loongarch/kernel/vmlinux.lds.S
> +++ b/arch/loongarch/kernel/vmlinux.lds.S
> @@ -70,6 +70,8 @@ SECTIONS
> .plt : ALIGN(16) { *(.plt) }
> .got.plt : ALIGN(16) { *(.got.plt) }
>
> + .data.rel : { *(.data.rel*) }
> +
> . = ALIGN(PECOFF_SEGMENT_ALIGN);
> __init_begin = .;
> __inittext_begin = .;
> @@ -93,8 +95,6 @@ SECTIONS
> PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
> #endif
>
> - .rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
> -
> .init.bss : {
> *(.init.bss)
> }
> @@ -107,6 +107,12 @@ SECTIONS
> RO_DATA(4096)
> RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)
>
> + .rela.dyn : ALIGN(8) {
> + __rela_dyn_start = .;
> + *(.rela.dyn) *(.rela*)
> + __rela_dyn_end = .;
> + }
> +
> .sdata : {
> *(.sdata)
> }
> @@ -133,6 +139,7 @@ SECTIONS
>
> DISCARDS
> /DISCARD/ : {
> + *(.dynamic .dynsym .dynstr .hash .gnu.hash)
> *(.gnu.attributes)
> *(.options)
> *(.eh_frame)
>

2023-01-13 07:15:32

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH 0/4] LoongArch: Add kernel relocation and KASLR support

Hi, Ruoyao and Jinyang,

Could you please take some time to review this patchset?

Huacai

On Mon, Jan 9, 2023 at 5:08 PM Youling Tang <[email protected]> wrote:
>
> This patch series to support kernel relocation and KASLR (only 64bit).
>
> Both old[1] and new[2] toolchains support this feature, and the test results
> are as follows:
> 1) Enable CONFING_RELOCATABLE
> # cat /proc/iomem
> 00000000-0fffffff : System RAM
> 00000000-002c3fff : Reserved
> 002c4000-008c3fff : Reserved
> 02000000-02f4ffff : Kernel code
> 02f50000-0381cbff : Kernel data
> 0381cc00-0394ae37 : Kernel bss
>
> 2) Enable CONFING_RANDOMIZE_BASE (KASLR)
> first:
> # cat /proc/iomem
> 00000000-0fffffff : System RAM
> 00000000-002c3fff : Reserved
> 002c4000-008c3fff : Reserved
> 02550000-0349ffff : Kernel code
> 034a0000-03d6cbff : Kernel data
> 03d6cc00-03e9ae37 : Kernel bss
>
> second:
> # cat /proc/iomem
> 00000000-0fffffff : System RAM
> 00000000-002c3fff : Reserved
> 002c4000-008c3fff : Reserved
> 02ad0000-03a1ffff : Kernel code
> 03a20000-042ecbff : Kernel data
> 042ecc00-0441ae37 : Kernel bss
>
> Thanks to @Ruoyao's and @Jinyang's for their help and suggestions.
>
> Links:
> [1]: https://github.com/sunhaiyong1978/CLFS-for-LoongArch/releases/download/5.0/loongarch64-clfs-5.1-cross-tools-c-only.tar.xz
> [2]: https://github.com/sunhaiyong1978/CLFS-for-LoongArch/releases/download/6.0/loongarch64-clfs-6.3-cross-tools-c-only.tar.xz
>
> Xi Ruoyao (1):
> LoongArch: Use trampoline for exception handlers and kill la.abs
>
> Youling Tang (3):
> LoongArch: Add JUMP_LINK_ADDR macro implementation to avoid using
> la.abs
> LoongArch: Add support for kernel relocation
> LoongArch: Add support for kernel address space layout randomization
> (KASLR)
>
> arch/loongarch/Kconfig | 37 +++++
> arch/loongarch/Makefile | 5 +
> arch/loongarch/include/asm/page.h | 6 +
> arch/loongarch/include/asm/stackframe.h | 16 +-
> arch/loongarch/include/asm/uaccess.h | 1 -
> arch/loongarch/kernel/Makefile | 2 +
> arch/loongarch/kernel/entry.S | 6 +-
> arch/loongarch/kernel/genex.S | 20 +--
> arch/loongarch/kernel/head.S | 30 +++-
> arch/loongarch/kernel/relocate.c | 210 ++++++++++++++++++++++++
> arch/loongarch/kernel/setup.c | 3 +
> arch/loongarch/kernel/traps.c | 4 +-
> arch/loongarch/kernel/vmlinux.lds.S | 11 +-
> arch/loongarch/mm/tlbex.S | 28 +---
> arch/loongarch/power/suspend_asm.S | 5 +-
> 15 files changed, 333 insertions(+), 51 deletions(-)
> create mode 100644 arch/loongarch/kernel/relocate.c
>
> --
> 2.37.1
>

2023-01-14 06:46:28

by Jinyang He

[permalink] [raw]
Subject: Re: [PATCH 1/4] LoongArch: Use trampoline for exception handlers and kill la.abs

Hi, Ruoyao and Youling,

I care about the performance when NUMA enabled. We set CSR.EENTRY
for each possible cpus where is NUMA-relative. So, I guess the more
codes in NUMA-relative memory makes more performance. If we just set
handler_trampoline as exception handler, the performance may be
influenced.


Thanks,

Jinyang


On 2023-01-09 17:07, Youling Tang wrote:
> From: Xi Ruoyao <[email protected]>
>
> Use a trampoline as an exception handlers, which can kill some use of
> la.abs in preparation for the subsequent support of the PIE kernel.
>
> Signed-off-by: Xi Ruoyao <[email protected]>
> Signed-off-by: Youling Tang <[email protected]>
> ---
> arch/loongarch/include/asm/stackframe.h | 8 +++----
> arch/loongarch/include/asm/uaccess.h | 1 -
> arch/loongarch/kernel/entry.S | 6 +++---
> arch/loongarch/kernel/genex.S | 20 +++++++++---------
> arch/loongarch/kernel/head.S | 2 +-
> arch/loongarch/kernel/traps.c | 4 +++-
> arch/loongarch/mm/tlbex.S | 28 +++++++------------------
> 7 files changed, 29 insertions(+), 40 deletions(-)
>
> diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
> index 4ca953062b5b..96c94035b5d0 100644
> --- a/arch/loongarch/include/asm/stackframe.h
> +++ b/arch/loongarch/include/asm/stackframe.h
> @@ -76,8 +76,8 @@
> * kernelsp array for it. It stores the current sp in t0 and loads the
> * new value in sp.
> */
> - .macro get_saved_sp docfi=0
> - la.abs t1, kernelsp
> + .macro get_saved_sp docfi=0
> + la.pcrel t1, kernelsp
> #ifdef CONFIG_SMP
> csrrd t0, PERCPU_BASE_KS
> LONG_ADD t1, t1, t0
> @@ -89,8 +89,8 @@
> LONG_L sp, t1, 0
> .endm
>
> - .macro set_saved_sp stackp temp temp2
> - la.abs \temp, kernelsp
> + .macro set_saved_sp stackp temp temp2
> + la.pcrel \temp, kernelsp
> #ifdef CONFIG_SMP
> LONG_ADD \temp, \temp, u0
> #endif
> diff --git a/arch/loongarch/include/asm/uaccess.h b/arch/loongarch/include/asm/uaccess.h
> index 255899d4a7c3..0d22991ae430 100644
> --- a/arch/loongarch/include/asm/uaccess.h
> +++ b/arch/loongarch/include/asm/uaccess.h
> @@ -22,7 +22,6 @@
> extern u64 __ua_limit;
>
> #define __UA_ADDR ".dword"
> -#define __UA_LA "la.abs"
> #define __UA_LIMIT __ua_limit
>
> /*
> diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S
> index d53b631c9022..ca01afdbec3f 100644
> --- a/arch/loongarch/kernel/entry.S
> +++ b/arch/loongarch/kernel/entry.S
> @@ -18,9 +18,9 @@
> .text
> .cfi_sections .debug_frame
> .align 5
> -SYM_FUNC_START(handle_syscall)
> +SYM_FUNC_START(handle_sys)
> csrrd t0, PERCPU_BASE_KS
> - la.abs t1, kernelsp
> + la.pcrel t1, kernelsp
> add.d t1, t1, t0
> move t2, sp
> ld.d sp, t1, 0
> @@ -66,7 +66,7 @@ SYM_FUNC_START(handle_syscall)
> bl do_syscall
>
> RESTORE_ALL_AND_RET
> -SYM_FUNC_END(handle_syscall)
> +SYM_FUNC_END(handle_sys)
>
> SYM_CODE_START(ret_from_fork)
> bl schedule_tail # a0 = struct task_struct *prev
> diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S
> index 75e5be807a0d..d3df0fa725a2 100644
> --- a/arch/loongarch/kernel/genex.S
> +++ b/arch/loongarch/kernel/genex.S
> @@ -32,9 +32,8 @@ SYM_FUNC_START(__arch_cpu_idle)
> SYM_FUNC_END(__arch_cpu_idle)
>
> SYM_FUNC_START(handle_vint)
> - BACKUP_T0T1
> SAVE_ALL
> - la.abs t1, __arch_cpu_idle
> + la.pcrel t1, __arch_cpu_idle
> LONG_L t0, sp, PT_ERA
> /* 32 byte rollback region */
> ori t0, t0, 0x1f
> @@ -43,8 +42,7 @@ SYM_FUNC_START(handle_vint)
> LONG_S t0, sp, PT_ERA
> 1: move a0, sp
> move a1, sp
> - la.abs t0, do_vint
> - jirl ra, t0, 0
> + bl do_vint
> RESTORE_ALL_AND_RET
> SYM_FUNC_END(handle_vint)
>
> @@ -67,12 +65,10 @@ SYM_FUNC_END(except_vec_cex)
> .macro BUILD_HANDLER exception handler prep
> .align 5
> SYM_FUNC_START(handle_\exception)
> - BACKUP_T0T1
> SAVE_ALL
> build_prep_\prep
> move a0, sp
> - la.abs t0, do_\handler
> - jirl ra, t0, 0
> + bl do_\handler
> RESTORE_ALL_AND_RET
> SYM_FUNC_END(handle_\exception)
> .endm
> @@ -89,7 +85,11 @@ SYM_FUNC_END(except_vec_cex)
> BUILD_HANDLER watch watch none
> BUILD_HANDLER reserved reserved none /* others */
>
> -SYM_FUNC_START(handle_sys)
> - la.abs t0, handle_syscall
> +SYM_FUNC_START(handler_trampoline)
> + csrwr t0, EXCEPTION_KS0
> + csrwr t1, EXCEPTION_KS1
> + pcaddi t0, 0
> + ld.d t0, t0, 16
> jr t0
> -SYM_FUNC_END(handle_sys)
> + nop
> +SYM_FUNC_END(handler_trampoline)
> diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> index 57bada6b4e93..aa6181714ec3 100644
> --- a/arch/loongarch/kernel/head.S
> +++ b/arch/loongarch/kernel/head.S
> @@ -117,7 +117,7 @@ SYM_CODE_START(smpboot_entry)
> li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
> csrwr t0, LOONGARCH_CSR_EUEN
>
> - la.abs t0, cpuboot_data
> + la.pcrel t0, cpuboot_data
> ld.d sp, t0, CPU_BOOT_STACK
> ld.d tp, t0, CPU_BOOT_TINFO
>
> diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
> index 7ea62faeeadb..0e8faaca3679 100644
> --- a/arch/loongarch/kernel/traps.c
> +++ b/arch/loongarch/kernel/traps.c
> @@ -61,6 +61,7 @@ extern asmlinkage void handle_lasx(void);
> extern asmlinkage void handle_reserved(void);
> extern asmlinkage void handle_watch(void);
> extern asmlinkage void handle_vint(void);
> +extern asmlinkage void handler_trampoline(void);
>
> static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
> const char *loglvl, bool user)
> @@ -716,7 +717,8 @@ void per_cpu_trap_init(int cpu)
> /* Install CPU exception handler */
> void set_handler(unsigned long offset, void *addr, unsigned long size)
> {
> - memcpy((void *)(eentry + offset), addr, size);
> + memcpy((void *)(eentry + offset), &handler_trampoline, 24);
> + memcpy((void *)(eentry + offset + 24), &addr, 8);
> local_flush_icache_range(eentry + offset, eentry + offset + size);
> }
>
> diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S
> index 58781c6e4191..cfaacdac518c 100644
> --- a/arch/loongarch/mm/tlbex.S
> +++ b/arch/loongarch/mm/tlbex.S
> @@ -24,8 +24,7 @@
> move a0, sp
> REG_S a2, sp, PT_BVADDR
> li.w a1, \write
> - la.abs t0, do_page_fault
> - jirl ra, t0, 0
> + bl do_page_fault
> RESTORE_ALL_AND_RET
> SYM_FUNC_END(tlb_do_page_fault_\write)
> .endm
> @@ -34,20 +33,16 @@
> tlb_do_page_fault 1
>
> SYM_FUNC_START(handle_tlb_protect)
> - BACKUP_T0T1
> SAVE_ALL
> move a0, sp
> move a1, zero
> csrrd a2, LOONGARCH_CSR_BADV
> REG_S a2, sp, PT_BVADDR
> - la.abs t0, do_page_fault
> - jirl ra, t0, 0
> + bl do_page_fault
> RESTORE_ALL_AND_RET
> SYM_FUNC_END(handle_tlb_protect)
>
> SYM_FUNC_START(handle_tlb_load)
> - csrwr t0, EXCEPTION_KS0
> - csrwr t1, EXCEPTION_KS1
> csrwr ra, EXCEPTION_KS2
>
> /*
> @@ -116,7 +111,7 @@ smp_pgtable_change_load:
>
> #ifdef CONFIG_64BIT
> vmalloc_load:
> - la.abs t1, swapper_pg_dir
> + la.pcrel t1, swapper_pg_dir
> b vmalloc_done_load
> #endif
>
> @@ -187,13 +182,10 @@ tlb_huge_update_load:
> nopage_tlb_load:
> dbar 0
> csrrd ra, EXCEPTION_KS2
> - la.abs t0, tlb_do_page_fault_0
> - jr t0
> + b tlb_do_page_fault_0
> SYM_FUNC_END(handle_tlb_load)
>
> SYM_FUNC_START(handle_tlb_store)
> - csrwr t0, EXCEPTION_KS0
> - csrwr t1, EXCEPTION_KS1
> csrwr ra, EXCEPTION_KS2
>
> /*
> @@ -263,7 +255,7 @@ smp_pgtable_change_store:
>
> #ifdef CONFIG_64BIT
> vmalloc_store:
> - la.abs t1, swapper_pg_dir
> + la.pcrel t1, swapper_pg_dir
> b vmalloc_done_store
> #endif
>
> @@ -336,13 +328,10 @@ tlb_huge_update_store:
> nopage_tlb_store:
> dbar 0
> csrrd ra, EXCEPTION_KS2
> - la.abs t0, tlb_do_page_fault_1
> - jr t0
> + b tlb_do_page_fault_1
> SYM_FUNC_END(handle_tlb_store)
>
> SYM_FUNC_START(handle_tlb_modify)
> - csrwr t0, EXCEPTION_KS0
> - csrwr t1, EXCEPTION_KS1
> csrwr ra, EXCEPTION_KS2
>
> /*
> @@ -411,7 +400,7 @@ smp_pgtable_change_modify:
>
> #ifdef CONFIG_64BIT
> vmalloc_modify:
> - la.abs t1, swapper_pg_dir
> + la.pcrel t1, swapper_pg_dir
> b vmalloc_done_modify
> #endif
>
> @@ -483,8 +472,7 @@ tlb_huge_update_modify:
> nopage_tlb_modify:
> dbar 0
> csrrd ra, EXCEPTION_KS2
> - la.abs t0, tlb_do_page_fault_1
> - jr t0
> + b tlb_do_page_fault_1
> SYM_FUNC_END(handle_tlb_modify)
>
> SYM_FUNC_START(handle_tlb_refill)

2023-01-14 07:27:01

by Jinyang He

[permalink] [raw]
Subject: Re: [PATCH 3/4] LoongArch: Add support for kernel relocation


On 2023-01-09 17:07, Youling Tang wrote:
> arch/loongarch/kernel/relocate.c contains the functions necessary to
> relocate the kernel elsewhere in memory.
>
> The kernel makes a copy of itself at the new address. It uses the
> relocation table inserted by the relocs tool to fix symbol references
> within the new image.
>
> If copy/relocation is successful then the entry point of the new kernel
> is returned, otherwise fall back to starting the kernel in place.
>
> Signed-off-by: Youling Tang <[email protected]>
> ---
> arch/loongarch/Kconfig | 15 +++++
> arch/loongarch/Makefile | 5 ++
> arch/loongarch/kernel/Makefile | 2 +
> arch/loongarch/kernel/head.S | 18 ++++++
> arch/loongarch/kernel/relocate.c | 96 +++++++++++++++++++++++++++++
> arch/loongarch/kernel/vmlinux.lds.S | 11 +++-
> 6 files changed, 145 insertions(+), 2 deletions(-)
> create mode 100644 arch/loongarch/kernel/relocate.c
>
> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> index 9cc8b84f7eb0..089a4695b1b3 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -48,6 +48,7 @@ config LOONGARCH
> select ARCH_SUPPORTS_ATOMIC_RMW
> select ARCH_SUPPORTS_HUGETLBFS
> select ARCH_SUPPORTS_NUMA_BALANCING
> + select SYS_SUPPORTS_RELOCATABLE
> select ARCH_USE_BUILTIN_BSWAP
> select ARCH_USE_CMPXCHG_LOCKREF
> select ARCH_USE_QUEUED_RWLOCKS
> @@ -229,6 +230,11 @@ config SCHED_OMIT_FRAME_POINTER
> config AS_HAS_EXPLICIT_RELOCS
> def_bool $(as-instr,x:pcalau12i \$t0$(comma)%pc_hi20(x))
>
> +config SYS_SUPPORTS_RELOCATABLE
> + bool
> + help
> + Selected if the platform supports relocating the kernel.
> +
> menu "Kernel type and options"
>
> source "kernel/Kconfig.hz"
> @@ -474,6 +480,15 @@ config PHYSICAL_START
> specified in the "crashkernel=YM@XM" command line boot parameter
> passed to the panic-ed kernel).
>
> +config RELOCATABLE
> + bool "Relocatable kernel"
> + depends on SYS_SUPPORTS_RELOCATABLE
> + help
> + This builds the kernel as a Position Independent Executable (PIE),
> + which retains all relocation metadata required to relocate the
> + kernel binary at runtime to a different virtual address than the
> + address it was linked at.
> +
> config SECCOMP
> bool "Enable seccomp to safely compute untrusted bytecode"
> depends on PROC_FS
> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> index 4402387d2755..27b5a70ff31c 100644
> --- a/arch/loongarch/Makefile
> +++ b/arch/loongarch/Makefile
> @@ -71,6 +71,11 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs
> KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
> endif
>
> +ifeq ($(CONFIG_RELOCATABLE),y)
> +LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext
> +KBUILD_CFLAGS_KERNEL += -fPIE
> +endif
> +
> cflags-y += -ffreestanding
> cflags-y += $(call cc-option, -mno-check-zero-division)
>
> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
> index fcaa024a685e..33787d22e6f4 100644
> --- a/arch/loongarch/kernel/Makefile
> +++ b/arch/loongarch/kernel/Makefile
> @@ -31,6 +31,8 @@ endif
> obj-$(CONFIG_MODULES) += module.o module-sections.o
> obj-$(CONFIG_STACKTRACE) += stacktrace.o
>
> +obj-$(CONFIG_RELOCATABLE) += relocate.o
> +
> obj-$(CONFIG_PROC_FS) += proc.o
>
> obj-$(CONFIG_SMP) += smp.o
> diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> index e8a4bf9d7599..6db1549177ad 100644
> --- a/arch/loongarch/kernel/head.S
> +++ b/arch/loongarch/kernel/head.S
> @@ -88,7 +88,25 @@ SYM_CODE_START(kernel_entry) # kernel entry point
> PTR_ADD sp, sp, tp
> set_saved_sp sp, t0, t1
>
> +#ifdef CONFIG_RELOCATABLE
> + /* Copy kernel and apply the relocations */
> + bl relocate_kernel
> +
> + /* Repoint the sp into the new kernel image */
> + PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE)
> + PTR_ADD sp, sp, tp
> + set_saved_sp sp, t0, t1
> + PTR_ADDI sp, sp, -4 * SZREG # init stack pointer
> +
> + /*
> + * relocate_kernel returns the entry point either
> + * in the relocated kernel or the original if for
> + * some reason relocation failed.
> + */
> + jr a0
> +#else
> bl start_kernel
> +#endif
> ASM_BUG()
>
> SYM_CODE_END(kernel_entry)
> diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
> new file mode 100644
> index 000000000000..a58551c0698d
> --- /dev/null
> +++ b/arch/loongarch/kernel/relocate.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Support for Kernel relocation at boot time
> + *
> + * Copyright (C) 2023 Loongson Technology Corporation Limited
> + */
> +
> +#include <linux/elf.h>
> +#include <linux/kernel.h>
> +#include <linux/start_kernel.h>
> +#include <linux/printk.h>
> +#include <linux/panic_notifier.h>
> +#include <asm/bootinfo.h>
> +#include <asm/inst.h>
> +#include <asm/sections.h>
> +
> +#define RELOCATED(x) ((void *)((long)x + offset))
> +
> +extern long __rela_dyn_start;
> +extern long __rela_dyn_end;
> +
> +/*
> + * Choose a new address for the kernel, for now we'll hard
> + * code the destination.
> + */
> +static inline void __init *determine_relocation_address(void)
> +{
> + return (void *)(CACHE_BASE + 0x02000000);
> +}
> +
> +static inline int __init relocation_addr_valid(void *loc_new)
> +{
> + if ((unsigned long)loc_new & 0x0000ffff) {

Hi, Youling,


12bits-aligned is OK as actually R_LARCH_PCALA_LO12 is absolute.


BTW, I think the relocation of kernel looks like the '.so' solve its
Relocs at user space so that it can be placed any legal address. The
address is determined first, and relocation make it works on that address.
Thus, this patch always relocate kernel to 'CACHE_BASE + 0x02000000'
makes me puzzled. I think the relocation only works when the kernel
runtime address is different from the link-time address.


Thanks,
Jinyang


> + /* Inappropriately aligned new location */
> + return 0;
> + }
> + if ((unsigned long)loc_new < (unsigned long)_end) {
> + /* New location overlaps original kernel */
> + return 0;
> + }
> + return 1;
> +}
> +
> +void *__init relocate_kernel(void)
> +{
> + Elf64_Rela *rela, *rela_end;
> + void *loc_new;
> + unsigned long kernel_length;
> + long offset = 0;
> + int res = 1;
> + /* Default to original kernel entry point */
> + void *kernel_entry = start_kernel;
> +
> + kernel_length = (long)(_end) - (long)(_text);
> +
> + loc_new = determine_relocation_address();
> +
> + /* Sanity check relocation address */
> + if (relocation_addr_valid(loc_new))
> + offset = (unsigned long)loc_new - (unsigned long)(_text);
> +
> + if (offset) {
> + /* Copy the kernel to it's new location */
> + memcpy(loc_new, _text, kernel_length);
> +
> + /* Sync the caches ready for execution of new kernel */
> + __asm__ __volatile__ (
> + "ibar 0 \t\n"
> + "dbar 0 \t\n");
> +
> + rela = (Elf64_Rela *)RELOCATED(&__rela_dyn_start);
> + rela_end = (Elf64_Rela *)RELOCATED(&__rela_dyn_end);
> +
> + for ( ; rela < rela_end; rela++) {
> + Elf64_Addr addr = rela->r_offset;
> + Elf64_Addr relocated_addr = rela->r_addend;
> +
> + if (rela->r_info != R_LARCH_RELATIVE)
> + continue;
> +
> + if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
> + relocated_addr = RELOCATED(relocated_addr);
> +
> + *(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
> +
> + }
> +
> + /* The current thread is now within the relocated image */
> + __current_thread_info = RELOCATED(__current_thread_info);
> +
> + /* Return the new kernel's entry point */
> + kernel_entry = RELOCATED(start_kernel);
> + }
> +out:
> + return kernel_entry;
> +}
> diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
> index 733b16e8d55d..aec0b6567d24 100644
> --- a/arch/loongarch/kernel/vmlinux.lds.S
> +++ b/arch/loongarch/kernel/vmlinux.lds.S
> @@ -70,6 +70,8 @@ SECTIONS
> .plt : ALIGN(16) { *(.plt) }
> .got.plt : ALIGN(16) { *(.got.plt) }
>
> + .data.rel : { *(.data.rel*) }
> +
> . = ALIGN(PECOFF_SEGMENT_ALIGN);
> __init_begin = .;
> __inittext_begin = .;
> @@ -93,8 +95,6 @@ SECTIONS
> PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
> #endif
>
> - .rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
> -
> .init.bss : {
> *(.init.bss)
> }
> @@ -107,6 +107,12 @@ SECTIONS
> RO_DATA(4096)
> RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)
>
> + .rela.dyn : ALIGN(8) {
> + __rela_dyn_start = .;
> + *(.rela.dyn) *(.rela*)
> + __rela_dyn_end = .;
> + }
> +
> .sdata : {
> *(.sdata)
> }
> @@ -133,6 +139,7 @@ SECTIONS
>
> DISCARDS
> /DISCARD/ : {
> + *(.dynamic .dynsym .dynstr .hash .gnu.hash)
> *(.gnu.attributes)
> *(.options)
> *(.eh_frame)

2023-01-14 08:22:45

by Youling Tang

[permalink] [raw]
Subject: Re: [PATCH 3/4] LoongArch: Add support for kernel relocation

Hi, Jinyang

On 01/14/2023 02:54 PM, Jinyang He wrote:
>
> On 2023-01-09 17:07, Youling Tang wrote:
>> arch/loongarch/kernel/relocate.c contains the functions necessary to
>> relocate the kernel elsewhere in memory.
>>
>> The kernel makes a copy of itself at the new address. It uses the
>> relocation table inserted by the relocs tool to fix symbol references
>> within the new image.
>>
>> If copy/relocation is successful then the entry point of the new kernel
>> is returned, otherwise fall back to starting the kernel in place.
>>
>> Signed-off-by: Youling Tang <[email protected]>
>> ---
>> arch/loongarch/Kconfig | 15 +++++
>> arch/loongarch/Makefile | 5 ++
>> arch/loongarch/kernel/Makefile | 2 +
>> arch/loongarch/kernel/head.S | 18 ++++++
>> arch/loongarch/kernel/relocate.c | 96 +++++++++++++++++++++++++++++
>> arch/loongarch/kernel/vmlinux.lds.S | 11 +++-
>> 6 files changed, 145 insertions(+), 2 deletions(-)
>> create mode 100644 arch/loongarch/kernel/relocate.c
>>
>> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
>> index 9cc8b84f7eb0..089a4695b1b3 100644
>> --- a/arch/loongarch/Kconfig
>> +++ b/arch/loongarch/Kconfig
>> @@ -48,6 +48,7 @@ config LOONGARCH
>> select ARCH_SUPPORTS_ATOMIC_RMW
>> select ARCH_SUPPORTS_HUGETLBFS
>> select ARCH_SUPPORTS_NUMA_BALANCING
>> + select SYS_SUPPORTS_RELOCATABLE
>> select ARCH_USE_BUILTIN_BSWAP
>> select ARCH_USE_CMPXCHG_LOCKREF
>> select ARCH_USE_QUEUED_RWLOCKS
>> @@ -229,6 +230,11 @@ config SCHED_OMIT_FRAME_POINTER
>> config AS_HAS_EXPLICIT_RELOCS
>> def_bool $(as-instr,x:pcalau12i \$t0$(comma)%pc_hi20(x))
>> +config SYS_SUPPORTS_RELOCATABLE
>> + bool
>> + help
>> + Selected if the platform supports relocating the kernel.
>> +
>> menu "Kernel type and options"
>> source "kernel/Kconfig.hz"
>> @@ -474,6 +480,15 @@ config PHYSICAL_START
>> specified in the "crashkernel=YM@XM" command line boot parameter
>> passed to the panic-ed kernel).
>> +config RELOCATABLE
>> + bool "Relocatable kernel"
>> + depends on SYS_SUPPORTS_RELOCATABLE
>> + help
>> + This builds the kernel as a Position Independent Executable (PIE),
>> + which retains all relocation metadata required to relocate the
>> + kernel binary at runtime to a different virtual address than the
>> + address it was linked at.
>> +
>> config SECCOMP
>> bool "Enable seccomp to safely compute untrusted bytecode"
>> depends on PROC_FS
>> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
>> index 4402387d2755..27b5a70ff31c 100644
>> --- a/arch/loongarch/Makefile
>> +++ b/arch/loongarch/Makefile
>> @@ -71,6 +71,11 @@ KBUILD_AFLAGS_MODULE +=
>> -Wa,-mla-global-with-abs
>> KBUILD_CFLAGS_MODULE += -fplt
>> -Wa,-mla-global-with-abs,-mla-local-with-abs
>> endif
>> +ifeq ($(CONFIG_RELOCATABLE),y)
>> +LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext
>> +KBUILD_CFLAGS_KERNEL += -fPIE
>> +endif
>> +
>> cflags-y += -ffreestanding
>> cflags-y += $(call cc-option, -mno-check-zero-division)
>> diff --git a/arch/loongarch/kernel/Makefile
>> b/arch/loongarch/kernel/Makefile
>> index fcaa024a685e..33787d22e6f4 100644
>> --- a/arch/loongarch/kernel/Makefile
>> +++ b/arch/loongarch/kernel/Makefile
>> @@ -31,6 +31,8 @@ endif
>> obj-$(CONFIG_MODULES) += module.o module-sections.o
>> obj-$(CONFIG_STACKTRACE) += stacktrace.o
>> +obj-$(CONFIG_RELOCATABLE) += relocate.o
>> +
>> obj-$(CONFIG_PROC_FS) += proc.o
>> obj-$(CONFIG_SMP) += smp.o
>> diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
>> index e8a4bf9d7599..6db1549177ad 100644
>> --- a/arch/loongarch/kernel/head.S
>> +++ b/arch/loongarch/kernel/head.S
>> @@ -88,7 +88,25 @@ SYM_CODE_START(kernel_entry) # kernel
>> entry point
>> PTR_ADD sp, sp, tp
>> set_saved_sp sp, t0, t1
>> +#ifdef CONFIG_RELOCATABLE
>> + /* Copy kernel and apply the relocations */
>> + bl relocate_kernel
>> +
>> + /* Repoint the sp into the new kernel image */
>> + PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE)
>> + PTR_ADD sp, sp, tp
>> + set_saved_sp sp, t0, t1
>> + PTR_ADDI sp, sp, -4 * SZREG # init stack pointer
>> +
>> + /*
>> + * relocate_kernel returns the entry point either
>> + * in the relocated kernel or the original if for
>> + * some reason relocation failed.
>> + */
>> + jr a0
>> +#else
>> bl start_kernel
>> +#endif
>> ASM_BUG()
>> SYM_CODE_END(kernel_entry)
>> diff --git a/arch/loongarch/kernel/relocate.c
>> b/arch/loongarch/kernel/relocate.c
>> new file mode 100644
>> index 000000000000..a58551c0698d
>> --- /dev/null
>> +++ b/arch/loongarch/kernel/relocate.c
>> @@ -0,0 +1,96 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Support for Kernel relocation at boot time
>> + *
>> + * Copyright (C) 2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#include <linux/elf.h>
>> +#include <linux/kernel.h>
>> +#include <linux/start_kernel.h>
>> +#include <linux/printk.h>
>> +#include <linux/panic_notifier.h>
>> +#include <asm/bootinfo.h>
>> +#include <asm/inst.h>
>> +#include <asm/sections.h>
>> +
>> +#define RELOCATED(x) ((void *)((long)x + offset))
>> +
>> +extern long __rela_dyn_start;
>> +extern long __rela_dyn_end;
>> +
>> +/*
>> + * Choose a new address for the kernel, for now we'll hard
>> + * code the destination.
>> + */
>> +static inline void __init *determine_relocation_address(void)
>> +{
>> + return (void *)(CACHE_BASE + 0x02000000);
>> +}
>> +
>> +static inline int __init relocation_addr_valid(void *loc_new)
>> +{
>> + if ((unsigned long)loc_new & 0x0000ffff) {
>
> Hi, Youling,
>
>
> 12bits-aligned is OK as actually R_LARCH_PCALA_LO12 is absolute.

Yes, 12bits-aligned is enough.

But for the convenience of debugging, is __kaslr_offset more friendly
to align with 1M? (For example, use objdump -d vmlinux --start-address=
(real_addr - __kaslr_offset)).

>
>
> BTW, I think the relocation of kernel looks like the '.so' solve its
> Relocs at user space so that it can be placed any legal address. The
> address is determined first, and relocation make it works on that address.
> Thus, this patch always relocate kernel to 'CACHE_BASE + 0x02000000'
> makes me puzzled. I think the relocation only works when the kernel
> runtime address is different from the link-time address.

IMHO, an immutable offset (eg: 0x1e00000) for the relocation kernel may
not make much sense, it may only be used during debugging to confirm
whether the relocation kernel offset is as expected. (We can remove the
immutable offset code if you think it is unnecessary) A random offset
will be generated when KASLR is enabled.

Thanks,
Youling

>
>
> Thanks,
> Jinyang
>
>
>> + /* Inappropriately aligned new location */
>> + return 0;
>> + }
>> + if ((unsigned long)loc_new < (unsigned long)_end) {
>> + /* New location overlaps original kernel */
>> + return 0;
>> + }
>> + return 1;
>> +}
>> +
>> +void *__init relocate_kernel(void)
>> +{
>> + Elf64_Rela *rela, *rela_end;
>> + void *loc_new;
>> + unsigned long kernel_length;
>> + long offset = 0;
>> + int res = 1;
>> + /* Default to original kernel entry point */
>> + void *kernel_entry = start_kernel;
>> +
>> + kernel_length = (long)(_end) - (long)(_text);
>> +
>> + loc_new = determine_relocation_address();
>> +
>> + /* Sanity check relocation address */
>> + if (relocation_addr_valid(loc_new))
>> + offset = (unsigned long)loc_new - (unsigned long)(_text);
>> +
>> + if (offset) {
>> + /* Copy the kernel to it's new location */
>> + memcpy(loc_new, _text, kernel_length);
>> +
>> + /* Sync the caches ready for execution of new kernel */
>> + __asm__ __volatile__ (
>> + "ibar 0 \t\n"
>> + "dbar 0 \t\n");
>> +
>> + rela = (Elf64_Rela *)RELOCATED(&__rela_dyn_start);
>> + rela_end = (Elf64_Rela *)RELOCATED(&__rela_dyn_end);
>> +
>> + for ( ; rela < rela_end; rela++) {
>> + Elf64_Addr addr = rela->r_offset;
>> + Elf64_Addr relocated_addr = rela->r_addend;
>> +
>> + if (rela->r_info != R_LARCH_RELATIVE)
>> + continue;
>> +
>> + if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
>> + relocated_addr = RELOCATED(relocated_addr);
>> +
>> + *(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
>> +
>> + }
>> +
>> + /* The current thread is now within the relocated image */
>> + __current_thread_info = RELOCATED(__current_thread_info);
>> +
>> + /* Return the new kernel's entry point */
>> + kernel_entry = RELOCATED(start_kernel);
>> + }
>> +out:
>> + return kernel_entry;
>> +}
>> diff --git a/arch/loongarch/kernel/vmlinux.lds.S
>> b/arch/loongarch/kernel/vmlinux.lds.S
>> index 733b16e8d55d..aec0b6567d24 100644
>> --- a/arch/loongarch/kernel/vmlinux.lds.S
>> +++ b/arch/loongarch/kernel/vmlinux.lds.S
>> @@ -70,6 +70,8 @@ SECTIONS
>> .plt : ALIGN(16) { *(.plt) }
>> .got.plt : ALIGN(16) { *(.got.plt) }
>> + .data.rel : { *(.data.rel*) }
>> +
>> . = ALIGN(PECOFF_SEGMENT_ALIGN);
>> __init_begin = .;
>> __inittext_begin = .;
>> @@ -93,8 +95,6 @@ SECTIONS
>> PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
>> #endif
>> - .rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
>> -
>> .init.bss : {
>> *(.init.bss)
>> }
>> @@ -107,6 +107,12 @@ SECTIONS
>> RO_DATA(4096)
>> RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)
>> + .rela.dyn : ALIGN(8) {
>> + __rela_dyn_start = .;
>> + *(.rela.dyn) *(.rela*)
>> + __rela_dyn_end = .;
>> + }
>> +
>> .sdata : {
>> *(.sdata)
>> }
>> @@ -133,6 +139,7 @@ SECTIONS
>> DISCARDS
>> /DISCARD/ : {
>> + *(.dynamic .dynsym .dynstr .hash .gnu.hash)
>> *(.gnu.attributes)
>> *(.options)
>> *(.eh_frame)

2023-01-14 08:37:11

by Jinyang He

[permalink] [raw]
Subject: Re: [PATCH 3/4] LoongArch: Add support for kernel relocation


On 2023-01-14 15:50, Youling Tang wrote:
> Hi, Jinyang
>
> On 01/14/2023 02:54 PM, Jinyang He wrote:
>>
>> On 2023-01-09 17:07, Youling Tang wrote:
>>> arch/loongarch/kernel/relocate.c contains the functions necessary to
>>> relocate the kernel elsewhere in memory.
>>>
>>> The kernel makes a copy of itself at the new address. It uses the
>>> relocation table inserted by the relocs tool to fix symbol references
>>> within the new image.
>>>
>>> If copy/relocation is successful then the entry point of the new kernel
>>> is returned, otherwise fall back to starting the kernel in place.
>>>
>>> Signed-off-by: Youling Tang <[email protected]>
>>> ---
>>>   arch/loongarch/Kconfig              | 15 +++++
>>>   arch/loongarch/Makefile             |  5 ++
>>>   arch/loongarch/kernel/Makefile      |  2 +
>>>   arch/loongarch/kernel/head.S        | 18 ++++++
>>>   arch/loongarch/kernel/relocate.c    | 96
>>> +++++++++++++++++++++++++++++
>>>   arch/loongarch/kernel/vmlinux.lds.S | 11 +++-
>>>   6 files changed, 145 insertions(+), 2 deletions(-)
>>>   create mode 100644 arch/loongarch/kernel/relocate.c
>>>
>>> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
>>> index 9cc8b84f7eb0..089a4695b1b3 100644
>>> --- a/arch/loongarch/Kconfig
>>> +++ b/arch/loongarch/Kconfig
>>> @@ -48,6 +48,7 @@ config LOONGARCH
>>>       select ARCH_SUPPORTS_ATOMIC_RMW
>>>       select ARCH_SUPPORTS_HUGETLBFS
>>>       select ARCH_SUPPORTS_NUMA_BALANCING
>>> +    select SYS_SUPPORTS_RELOCATABLE
>>>       select ARCH_USE_BUILTIN_BSWAP
>>>       select ARCH_USE_CMPXCHG_LOCKREF
>>>       select ARCH_USE_QUEUED_RWLOCKS
>>> @@ -229,6 +230,11 @@ config SCHED_OMIT_FRAME_POINTER
>>>   config AS_HAS_EXPLICIT_RELOCS
>>>       def_bool $(as-instr,x:pcalau12i \$t0$(comma)%pc_hi20(x))
>>>   +config SYS_SUPPORTS_RELOCATABLE
>>> +    bool
>>> +    help
>>> +      Selected if the platform supports relocating the kernel.
>>> +
>>>   menu "Kernel type and options"
>>>     source "kernel/Kconfig.hz"
>>> @@ -474,6 +480,15 @@ config PHYSICAL_START
>>>         specified in the "crashkernel=YM@XM" command line boot
>>> parameter
>>>         passed to the panic-ed kernel).
>>>   +config RELOCATABLE
>>> +    bool "Relocatable kernel"
>>> +    depends on SYS_SUPPORTS_RELOCATABLE
>>> +    help
>>> +      This builds the kernel as a Position Independent Executable
>>> (PIE),
>>> +      which retains all relocation metadata required to relocate the
>>> +      kernel binary at runtime to a different virtual address than the
>>> +      address it was linked at.
>>> +
>>>   config SECCOMP
>>>       bool "Enable seccomp to safely compute untrusted bytecode"
>>>       depends on PROC_FS
>>> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
>>> index 4402387d2755..27b5a70ff31c 100644
>>> --- a/arch/loongarch/Makefile
>>> +++ b/arch/loongarch/Makefile
>>> @@ -71,6 +71,11 @@ KBUILD_AFLAGS_MODULE        +=
>>> -Wa,-mla-global-with-abs
>>>   KBUILD_CFLAGS_MODULE        += -fplt
>>> -Wa,-mla-global-with-abs,-mla-local-with-abs
>>>   endif
>>>   +ifeq ($(CONFIG_RELOCATABLE),y)
>>> +LDFLAGS_vmlinux            += -static -pie --no-dynamic-linker -z
>>> notext
>>> +KBUILD_CFLAGS_KERNEL        += -fPIE
>>> +endif
>>> +
>>>   cflags-y += -ffreestanding
>>>   cflags-y += $(call cc-option, -mno-check-zero-division)
>>>   diff --git a/arch/loongarch/kernel/Makefile
>>> b/arch/loongarch/kernel/Makefile
>>> index fcaa024a685e..33787d22e6f4 100644
>>> --- a/arch/loongarch/kernel/Makefile
>>> +++ b/arch/loongarch/kernel/Makefile
>>> @@ -31,6 +31,8 @@ endif
>>>   obj-$(CONFIG_MODULES)        += module.o module-sections.o
>>>   obj-$(CONFIG_STACKTRACE)    += stacktrace.o
>>>   +obj-$(CONFIG_RELOCATABLE)    += relocate.o
>>> +
>>>   obj-$(CONFIG_PROC_FS)        += proc.o
>>>     obj-$(CONFIG_SMP)        += smp.o
>>> diff --git a/arch/loongarch/kernel/head.S
>>> b/arch/loongarch/kernel/head.S
>>> index e8a4bf9d7599..6db1549177ad 100644
>>> --- a/arch/loongarch/kernel/head.S
>>> +++ b/arch/loongarch/kernel/head.S
>>> @@ -88,7 +88,25 @@ SYM_CODE_START(kernel_entry)            # kernel
>>> entry point
>>>       PTR_ADD        sp, sp, tp
>>>       set_saved_sp    sp, t0, t1
>>>   +#ifdef CONFIG_RELOCATABLE
>>> +    /* Copy kernel and apply the relocations */
>>> +    bl        relocate_kernel
>>> +
>>> +    /* Repoint the sp into the new kernel image */
>>> +    PTR_LI        sp, (_THREAD_SIZE - 32 - PT_SIZE)
>>> +    PTR_ADD        sp, sp, tp
>>> +    set_saved_sp    sp, t0, t1
>>> +    PTR_ADDI    sp, sp, -4 * SZREG      # init stack pointer
>>> +
>>> +    /*
>>> +     * relocate_kernel returns the entry point either
>>> +     * in the relocated kernel or the original if for
>>> +     * some reason relocation failed.
>>> +    */
>>> +    jr        a0
>>> +#else
>>>       bl        start_kernel
>>> +#endif
>>>       ASM_BUG()
>>>     SYM_CODE_END(kernel_entry)
>>> diff --git a/arch/loongarch/kernel/relocate.c
>>> b/arch/loongarch/kernel/relocate.c
>>> new file mode 100644
>>> index 000000000000..a58551c0698d
>>> --- /dev/null
>>> +++ b/arch/loongarch/kernel/relocate.c
>>> @@ -0,0 +1,96 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Support for Kernel relocation at boot time
>>> + *
>>> + * Copyright (C) 2023 Loongson Technology Corporation Limited
>>> + */
>>> +
>>> +#include <linux/elf.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/start_kernel.h>
>>> +#include <linux/printk.h>
>>> +#include <linux/panic_notifier.h>
>>> +#include <asm/bootinfo.h>
>>> +#include <asm/inst.h>
>>> +#include <asm/sections.h>
>>> +
>>> +#define RELOCATED(x) ((void *)((long)x + offset))
>>> +
>>> +extern long __rela_dyn_start;
>>> +extern long __rela_dyn_end;
>>> +
>>> +/*
>>> + * Choose a new address for the kernel, for now we'll hard
>>> + * code the destination.
>>> + */
>>> +static inline void __init *determine_relocation_address(void)
>>> +{
>>> +    return (void *)(CACHE_BASE + 0x02000000);
>>> +}
>>> +
>>> +static inline int __init relocation_addr_valid(void *loc_new)
>>> +{
>>> +    if ((unsigned long)loc_new & 0x0000ffff) {
>>
>> Hi, Youling,
>>
>>
>> 12bits-aligned is OK as actually R_LARCH_PCALA_LO12 is absolute.
>
> Yes, 12bits-aligned is enough.
>
> But for the convenience of debugging, is __kaslr_offset more friendly
> to align with 1M? (For example, use objdump -d vmlinux --start-address=
> (real_addr - __kaslr_offset)).

This will reduce the random range, but it's up to you.


>
>>
>>
>> BTW, I think the relocation of kernel looks like the '.so' solve its
>> Relocs at user space so that it can be placed any legal address. The
>> address is determined first, and relocation make it works on that
>> address.
>> Thus, this patch always relocate kernel to 'CACHE_BASE + 0x02000000'
>> makes me puzzled. I think the relocation only works when the kernel
>> runtime address is different from the link-time address.
>
> IMHO, an immutable offset (eg: 0x1e00000) for the relocation kernel may
> not make much sense, it may only be used during debugging to confirm
> whether the relocation kernel offset is as expected. (We can remove the
> immutable offset code if you think it is unnecessary) A random offset
> will be generated when KASLR is enabled.

What I expected is that when the kernel runtime address is different
from the link-time address, the relocatable kernel can solve its
Relocs so that it can work well again. And the immutable offset is
relocate kernel to another address, that looks like one of random
offsets. Although relocatable and kaslr are similar, they are not the same.


Thanks,

Jinyang


>
> Thanks,
> Youling
>
>>
>>
>> Thanks,
>> Jinyang
>>
>>
>>> +        /* Inappropriately aligned new location */
>>> +        return 0;
>>> +    }
>>> +    if ((unsigned long)loc_new < (unsigned long)_end) {
>>> +        /* New location overlaps original kernel */
>>> +        return 0;
>>> +    }
>>> +    return 1;
>>> +}
>>> +
>>> +void *__init relocate_kernel(void)
>>> +{
>>> +    Elf64_Rela *rela, *rela_end;
>>> +    void *loc_new;
>>> +    unsigned long kernel_length;
>>> +    long offset = 0;
>>> +    int res = 1;
>>> +    /* Default to original kernel entry point */
>>> +    void *kernel_entry = start_kernel;
>>> +
>>> +    kernel_length = (long)(_end) - (long)(_text);
>>> +
>>> +    loc_new = determine_relocation_address();
>>> +
>>> +    /* Sanity check relocation address */
>>> +    if (relocation_addr_valid(loc_new))
>>> +        offset = (unsigned long)loc_new - (unsigned long)(_text);
>>> +
>>> +    if (offset) {
>>> +        /* Copy the kernel to it's new location */
>>> +        memcpy(loc_new, _text, kernel_length);
>>> +
>>> +        /* Sync the caches ready for execution of new kernel */
>>> +        __asm__ __volatile__ (
>>> +            "ibar 0 \t\n"
>>> +            "dbar 0 \t\n");
>>> +
>>> +        rela = (Elf64_Rela *)RELOCATED(&__rela_dyn_start);
>>> +        rela_end = (Elf64_Rela *)RELOCATED(&__rela_dyn_end);
>>> +
>>> +        for ( ; rela < rela_end; rela++) {
>>> +            Elf64_Addr addr = rela->r_offset;
>>> +            Elf64_Addr relocated_addr = rela->r_addend;
>>> +
>>> +            if (rela->r_info != R_LARCH_RELATIVE)
>>> +                continue;
>>> +
>>> +            if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
>>> +                relocated_addr = RELOCATED(relocated_addr);
>>> +
>>> +            *(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
>>> +
>>> +        }
>>> +
>>> +        /* The current thread is now within the relocated image */
>>> +        __current_thread_info = RELOCATED(__current_thread_info);
>>> +
>>> +        /* Return the new kernel's entry point */
>>> +        kernel_entry = RELOCATED(start_kernel);
>>> +    }
>>> +out:
>>> +    return kernel_entry;
>>> +}
>>> diff --git a/arch/loongarch/kernel/vmlinux.lds.S
>>> b/arch/loongarch/kernel/vmlinux.lds.S
>>> index 733b16e8d55d..aec0b6567d24 100644
>>> --- a/arch/loongarch/kernel/vmlinux.lds.S
>>> +++ b/arch/loongarch/kernel/vmlinux.lds.S
>>> @@ -70,6 +70,8 @@ SECTIONS
>>>       .plt : ALIGN(16) { *(.plt) }
>>>       .got.plt : ALIGN(16) { *(.got.plt) }
>>>   +    .data.rel : { *(.data.rel*) }
>>> +
>>>       . = ALIGN(PECOFF_SEGMENT_ALIGN);
>>>       __init_begin = .;
>>>       __inittext_begin = .;
>>> @@ -93,8 +95,6 @@ SECTIONS
>>>       PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
>>>   #endif
>>>   -    .rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
>>> -
>>>       .init.bss : {
>>>           *(.init.bss)
>>>       }
>>> @@ -107,6 +107,12 @@ SECTIONS
>>>       RO_DATA(4096)
>>>       RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)
>>>   +    .rela.dyn : ALIGN(8) {
>>> +        __rela_dyn_start = .;
>>> +         *(.rela.dyn) *(.rela*)
>>> +        __rela_dyn_end = .;
>>> +    }
>>> +
>>>       .sdata : {
>>>           *(.sdata)
>>>       }
>>> @@ -133,6 +139,7 @@ SECTIONS
>>>         DISCARDS
>>>       /DISCARD/ : {
>>> +        *(.dynamic .dynsym .dynstr .hash .gnu.hash)
>>>           *(.gnu.attributes)
>>>           *(.options)
>>>           *(.eh_frame)
>

2023-01-14 09:25:08

by Youling Tang

[permalink] [raw]
Subject: Re: [PATCH 3/4] LoongArch: Add support for kernel relocation



On 01/14/2023 04:30 PM, Jinyang He wrote:
>
> On 2023-01-14 15:50, Youling Tang wrote:
>> Hi, Jinyang
>>
>> On 01/14/2023 02:54 PM, Jinyang He wrote:
>>>
>>> On 2023-01-09 17:07, Youling Tang wrote:
>>>> arch/loongarch/kernel/relocate.c contains the functions necessary to
>>>> relocate the kernel elsewhere in memory.
>>>>
>>>> The kernel makes a copy of itself at the new address. It uses the
>>>> relocation table inserted by the relocs tool to fix symbol references
>>>> within the new image.
>>>>
>>>> If copy/relocation is successful then the entry point of the new kernel
>>>> is returned, otherwise fall back to starting the kernel in place.
>>>>
>>>> Signed-off-by: Youling Tang <[email protected]>
>>>> ---
>>>> arch/loongarch/Kconfig | 15 +++++
>>>> arch/loongarch/Makefile | 5 ++
>>>> arch/loongarch/kernel/Makefile | 2 +
>>>> arch/loongarch/kernel/head.S | 18 ++++++
>>>> arch/loongarch/kernel/relocate.c | 96
>>>> +++++++++++++++++++++++++++++
>>>> arch/loongarch/kernel/vmlinux.lds.S | 11 +++-
>>>> 6 files changed, 145 insertions(+), 2 deletions(-)
>>>> create mode 100644 arch/loongarch/kernel/relocate.c
>>>>
>>>> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
>>>> index 9cc8b84f7eb0..089a4695b1b3 100644
>>>> --- a/arch/loongarch/Kconfig
>>>> +++ b/arch/loongarch/Kconfig
>>>> @@ -48,6 +48,7 @@ config LOONGARCH
>>>> select ARCH_SUPPORTS_ATOMIC_RMW
>>>> select ARCH_SUPPORTS_HUGETLBFS
>>>> select ARCH_SUPPORTS_NUMA_BALANCING
>>>> + select SYS_SUPPORTS_RELOCATABLE
>>>> select ARCH_USE_BUILTIN_BSWAP
>>>> select ARCH_USE_CMPXCHG_LOCKREF
>>>> select ARCH_USE_QUEUED_RWLOCKS
>>>> @@ -229,6 +230,11 @@ config SCHED_OMIT_FRAME_POINTER
>>>> config AS_HAS_EXPLICIT_RELOCS
>>>> def_bool $(as-instr,x:pcalau12i \$t0$(comma)%pc_hi20(x))
>>>> +config SYS_SUPPORTS_RELOCATABLE
>>>> + bool
>>>> + help
>>>> + Selected if the platform supports relocating the kernel.
>>>> +
>>>> menu "Kernel type and options"
>>>> source "kernel/Kconfig.hz"
>>>> @@ -474,6 +480,15 @@ config PHYSICAL_START
>>>> specified in the "crashkernel=YM@XM" command line boot
>>>> parameter
>>>> passed to the panic-ed kernel).
>>>> +config RELOCATABLE
>>>> + bool "Relocatable kernel"
>>>> + depends on SYS_SUPPORTS_RELOCATABLE
>>>> + help
>>>> + This builds the kernel as a Position Independent Executable
>>>> (PIE),
>>>> + which retains all relocation metadata required to relocate the
>>>> + kernel binary at runtime to a different virtual address than the
>>>> + address it was linked at.
>>>> +
>>>> config SECCOMP
>>>> bool "Enable seccomp to safely compute untrusted bytecode"
>>>> depends on PROC_FS
>>>> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
>>>> index 4402387d2755..27b5a70ff31c 100644
>>>> --- a/arch/loongarch/Makefile
>>>> +++ b/arch/loongarch/Makefile
>>>> @@ -71,6 +71,11 @@ KBUILD_AFLAGS_MODULE +=
>>>> -Wa,-mla-global-with-abs
>>>> KBUILD_CFLAGS_MODULE += -fplt
>>>> -Wa,-mla-global-with-abs,-mla-local-with-abs
>>>> endif
>>>> +ifeq ($(CONFIG_RELOCATABLE),y)
>>>> +LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z
>>>> notext
>>>> +KBUILD_CFLAGS_KERNEL += -fPIE
>>>> +endif
>>>> +
>>>> cflags-y += -ffreestanding
>>>> cflags-y += $(call cc-option, -mno-check-zero-division)
>>>> diff --git a/arch/loongarch/kernel/Makefile
>>>> b/arch/loongarch/kernel/Makefile
>>>> index fcaa024a685e..33787d22e6f4 100644
>>>> --- a/arch/loongarch/kernel/Makefile
>>>> +++ b/arch/loongarch/kernel/Makefile
>>>> @@ -31,6 +31,8 @@ endif
>>>> obj-$(CONFIG_MODULES) += module.o module-sections.o
>>>> obj-$(CONFIG_STACKTRACE) += stacktrace.o
>>>> +obj-$(CONFIG_RELOCATABLE) += relocate.o
>>>> +
>>>> obj-$(CONFIG_PROC_FS) += proc.o
>>>> obj-$(CONFIG_SMP) += smp.o
>>>> diff --git a/arch/loongarch/kernel/head.S
>>>> b/arch/loongarch/kernel/head.S
>>>> index e8a4bf9d7599..6db1549177ad 100644
>>>> --- a/arch/loongarch/kernel/head.S
>>>> +++ b/arch/loongarch/kernel/head.S
>>>> @@ -88,7 +88,25 @@ SYM_CODE_START(kernel_entry) # kernel
>>>> entry point
>>>> PTR_ADD sp, sp, tp
>>>> set_saved_sp sp, t0, t1
>>>> +#ifdef CONFIG_RELOCATABLE
>>>> + /* Copy kernel and apply the relocations */
>>>> + bl relocate_kernel
>>>> +
>>>> + /* Repoint the sp into the new kernel image */
>>>> + PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE)
>>>> + PTR_ADD sp, sp, tp
>>>> + set_saved_sp sp, t0, t1
>>>> + PTR_ADDI sp, sp, -4 * SZREG # init stack pointer
>>>> +
>>>> + /*
>>>> + * relocate_kernel returns the entry point either
>>>> + * in the relocated kernel or the original if for
>>>> + * some reason relocation failed.
>>>> + */
>>>> + jr a0
>>>> +#else
>>>> bl start_kernel
>>>> +#endif
>>>> ASM_BUG()
>>>> SYM_CODE_END(kernel_entry)
>>>> diff --git a/arch/loongarch/kernel/relocate.c
>>>> b/arch/loongarch/kernel/relocate.c
>>>> new file mode 100644
>>>> index 000000000000..a58551c0698d
>>>> --- /dev/null
>>>> +++ b/arch/loongarch/kernel/relocate.c
>>>> @@ -0,0 +1,96 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * Support for Kernel relocation at boot time
>>>> + *
>>>> + * Copyright (C) 2023 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#include <linux/elf.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/start_kernel.h>
>>>> +#include <linux/printk.h>
>>>> +#include <linux/panic_notifier.h>
>>>> +#include <asm/bootinfo.h>
>>>> +#include <asm/inst.h>
>>>> +#include <asm/sections.h>
>>>> +
>>>> +#define RELOCATED(x) ((void *)((long)x + offset))
>>>> +
>>>> +extern long __rela_dyn_start;
>>>> +extern long __rela_dyn_end;
>>>> +
>>>> +/*
>>>> + * Choose a new address for the kernel, for now we'll hard
>>>> + * code the destination.
>>>> + */
>>>> +static inline void __init *determine_relocation_address(void)
>>>> +{
>>>> + return (void *)(CACHE_BASE + 0x02000000);
>>>> +}
>>>> +
>>>> +static inline int __init relocation_addr_valid(void *loc_new)
>>>> +{
>>>> + if ((unsigned long)loc_new & 0x0000ffff) {
>>>
>>> Hi, Youling,
>>>
>>>
>>> 12bits-aligned is OK as actually R_LARCH_PCALA_LO12 is absolute.
>>
>> Yes, 12bits-aligned is enough.
>>
>> But for the convenience of debugging, is __kaslr_offset more friendly
>> to align with 1M? (For example, use objdump -d vmlinux --start-address=
>> (real_addr - __kaslr_offset)).
>
> This will reduce the random range, but it's up to you.
>
>
>>
>>>
>>>
>>> BTW, I think the relocation of kernel looks like the '.so' solve its
>>> Relocs at user space so that it can be placed any legal address. The
>>> address is determined first, and relocation make it works on that
>>> address.
>>> Thus, this patch always relocate kernel to 'CACHE_BASE + 0x02000000'
>>> makes me puzzled. I think the relocation only works when the kernel
>>> runtime address is different from the link-time address.
>>
>> IMHO, an immutable offset (eg: 0x1e00000) for the relocation kernel may
>> not make much sense, it may only be used during debugging to confirm
>> whether the relocation kernel offset is as expected. (We can remove the
>> immutable offset code if you think it is unnecessary) A random offset
>> will be generated when KASLR is enabled.
>
> What I expected is that when the kernel runtime address is different
> from the link-time address, the relocatable kernel can solve its
> Relocs so that it can work well again. And the immutable offset is
> relocate kernel to another address, that looks like one of random
> offsets. Although relocatable and kaslr are similar, they are not the same.

Yes, this solution is better. The kernel can perform adaptive
operations (for example, the same set of binary features of kdump to be
implemented later).

At present, the existing implementation scheme may be used. When the
same set of binary features of kdump is implemented later, this new
scheme can be used to improve the implementation of the relocation
kernel.

Thanks,
Youling

>
>
> Thanks,
>
> Jinyang
>
>
>>
>> Thanks,
>> Youling
>>
>>>
>>>
>>> Thanks,
>>> Jinyang
>>>
>>>
>>>> + /* Inappropriately aligned new location */
>>>> + return 0;
>>>> + }
>>>> + if ((unsigned long)loc_new < (unsigned long)_end) {
>>>> + /* New location overlaps original kernel */
>>>> + return 0;
>>>> + }
>>>> + return 1;
>>>> +}
>>>> +
>>>> +void *__init relocate_kernel(void)
>>>> +{
>>>> + Elf64_Rela *rela, *rela_end;
>>>> + void *loc_new;
>>>> + unsigned long kernel_length;
>>>> + long offset = 0;
>>>> + int res = 1;
>>>> + /* Default to original kernel entry point */
>>>> + void *kernel_entry = start_kernel;
>>>> +
>>>> + kernel_length = (long)(_end) - (long)(_text);
>>>> +
>>>> + loc_new = determine_relocation_address();
>>>> +
>>>> + /* Sanity check relocation address */
>>>> + if (relocation_addr_valid(loc_new))
>>>> + offset = (unsigned long)loc_new - (unsigned long)(_text);
>>>> +
>>>> + if (offset) {
>>>> + /* Copy the kernel to it's new location */
>>>> + memcpy(loc_new, _text, kernel_length);
>>>> +
>>>> + /* Sync the caches ready for execution of new kernel */
>>>> + __asm__ __volatile__ (
>>>> + "ibar 0 \t\n"
>>>> + "dbar 0 \t\n");
>>>> +
>>>> + rela = (Elf64_Rela *)RELOCATED(&__rela_dyn_start);
>>>> + rela_end = (Elf64_Rela *)RELOCATED(&__rela_dyn_end);
>>>> +
>>>> + for ( ; rela < rela_end; rela++) {
>>>> + Elf64_Addr addr = rela->r_offset;
>>>> + Elf64_Addr relocated_addr = rela->r_addend;
>>>> +
>>>> + if (rela->r_info != R_LARCH_RELATIVE)
>>>> + continue;
>>>> +
>>>> + if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
>>>> + relocated_addr = RELOCATED(relocated_addr);
>>>> +
>>>> + *(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
>>>> +
>>>> + }
>>>> +
>>>> + /* The current thread is now within the relocated image */
>>>> + __current_thread_info = RELOCATED(__current_thread_info);
>>>> +
>>>> + /* Return the new kernel's entry point */
>>>> + kernel_entry = RELOCATED(start_kernel);
>>>> + }
>>>> +out:
>>>> + return kernel_entry;
>>>> +}
>>>> diff --git a/arch/loongarch/kernel/vmlinux.lds.S
>>>> b/arch/loongarch/kernel/vmlinux.lds.S
>>>> index 733b16e8d55d..aec0b6567d24 100644
>>>> --- a/arch/loongarch/kernel/vmlinux.lds.S
>>>> +++ b/arch/loongarch/kernel/vmlinux.lds.S
>>>> @@ -70,6 +70,8 @@ SECTIONS
>>>> .plt : ALIGN(16) { *(.plt) }
>>>> .got.plt : ALIGN(16) { *(.got.plt) }
>>>> + .data.rel : { *(.data.rel*) }
>>>> +
>>>> . = ALIGN(PECOFF_SEGMENT_ALIGN);
>>>> __init_begin = .;
>>>> __inittext_begin = .;
>>>> @@ -93,8 +95,6 @@ SECTIONS
>>>> PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
>>>> #endif
>>>> - .rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
>>>> -
>>>> .init.bss : {
>>>> *(.init.bss)
>>>> }
>>>> @@ -107,6 +107,12 @@ SECTIONS
>>>> RO_DATA(4096)
>>>> RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)
>>>> + .rela.dyn : ALIGN(8) {
>>>> + __rela_dyn_start = .;
>>>> + *(.rela.dyn) *(.rela*)
>>>> + __rela_dyn_end = .;
>>>> + }
>>>> +
>>>> .sdata : {
>>>> *(.sdata)
>>>> }
>>>> @@ -133,6 +139,7 @@ SECTIONS
>>>> DISCARDS
>>>> /DISCARD/ : {
>>>> + *(.dynamic .dynsym .dynstr .hash .gnu.hash)
>>>> *(.gnu.attributes)
>>>> *(.options)
>>>> *(.eh_frame)
>>
>

2023-01-16 02:04:27

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH 1/4] LoongArch: Use trampoline for exception handlers and kill la.abs

On Sat, Jan 14, 2023 at 2:38 PM Jinyang He <[email protected]> wrote:
>
> Hi, Ruoyao and Youling,
>
> I care about the performance when NUMA enabled. We set CSR.EENTRY
> for each possible cpus where is NUMA-relative. So, I guess the more
> codes in NUMA-relative memory makes more performance. If we just set
> handler_trampoline as exception handler, the performance may be
> influenced.
So copying both the handlers and handler_trampoline can solve the
problem? If that is possible, please do that on top of the latest code
in
https://github.com/loongson/linux/commits/loongarch-next

Huacai
>
>
> Thanks,
>
> Jinyang
>
>
> On 2023-01-09 17:07, Youling Tang wrote:
> > From: Xi Ruoyao <[email protected]>
> >
> > Use a trampoline as an exception handlers, which can kill some use of
> > la.abs in preparation for the subsequent support of the PIE kernel.
> >
> > Signed-off-by: Xi Ruoyao <[email protected]>
> > Signed-off-by: Youling Tang <[email protected]>
> > ---
> > arch/loongarch/include/asm/stackframe.h | 8 +++----
> > arch/loongarch/include/asm/uaccess.h | 1 -
> > arch/loongarch/kernel/entry.S | 6 +++---
> > arch/loongarch/kernel/genex.S | 20 +++++++++---------
> > arch/loongarch/kernel/head.S | 2 +-
> > arch/loongarch/kernel/traps.c | 4 +++-
> > arch/loongarch/mm/tlbex.S | 28 +++++++------------------
> > 7 files changed, 29 insertions(+), 40 deletions(-)
> >
> > diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
> > index 4ca953062b5b..96c94035b5d0 100644
> > --- a/arch/loongarch/include/asm/stackframe.h
> > +++ b/arch/loongarch/include/asm/stackframe.h
> > @@ -76,8 +76,8 @@
> > * kernelsp array for it. It stores the current sp in t0 and loads the
> > * new value in sp.
> > */
> > - .macro get_saved_sp docfi=0
> > - la.abs t1, kernelsp
> > + .macro get_saved_sp docfi=0
> > + la.pcrel t1, kernelsp
> > #ifdef CONFIG_SMP
> > csrrd t0, PERCPU_BASE_KS
> > LONG_ADD t1, t1, t0
> > @@ -89,8 +89,8 @@
> > LONG_L sp, t1, 0
> > .endm
> >
> > - .macro set_saved_sp stackp temp temp2
> > - la.abs \temp, kernelsp
> > + .macro set_saved_sp stackp temp temp2
> > + la.pcrel \temp, kernelsp
> > #ifdef CONFIG_SMP
> > LONG_ADD \temp, \temp, u0
> > #endif
> > diff --git a/arch/loongarch/include/asm/uaccess.h b/arch/loongarch/include/asm/uaccess.h
> > index 255899d4a7c3..0d22991ae430 100644
> > --- a/arch/loongarch/include/asm/uaccess.h
> > +++ b/arch/loongarch/include/asm/uaccess.h
> > @@ -22,7 +22,6 @@
> > extern u64 __ua_limit;
> >
> > #define __UA_ADDR ".dword"
> > -#define __UA_LA "la.abs"
> > #define __UA_LIMIT __ua_limit
> >
> > /*
> > diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S
> > index d53b631c9022..ca01afdbec3f 100644
> > --- a/arch/loongarch/kernel/entry.S
> > +++ b/arch/loongarch/kernel/entry.S
> > @@ -18,9 +18,9 @@
> > .text
> > .cfi_sections .debug_frame
> > .align 5
> > -SYM_FUNC_START(handle_syscall)
> > +SYM_FUNC_START(handle_sys)
> > csrrd t0, PERCPU_BASE_KS
> > - la.abs t1, kernelsp
> > + la.pcrel t1, kernelsp
> > add.d t1, t1, t0
> > move t2, sp
> > ld.d sp, t1, 0
> > @@ -66,7 +66,7 @@ SYM_FUNC_START(handle_syscall)
> > bl do_syscall
> >
> > RESTORE_ALL_AND_RET
> > -SYM_FUNC_END(handle_syscall)
> > +SYM_FUNC_END(handle_sys)
> >
> > SYM_CODE_START(ret_from_fork)
> > bl schedule_tail # a0 = struct task_struct *prev
> > diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S
> > index 75e5be807a0d..d3df0fa725a2 100644
> > --- a/arch/loongarch/kernel/genex.S
> > +++ b/arch/loongarch/kernel/genex.S
> > @@ -32,9 +32,8 @@ SYM_FUNC_START(__arch_cpu_idle)
> > SYM_FUNC_END(__arch_cpu_idle)
> >
> > SYM_FUNC_START(handle_vint)
> > - BACKUP_T0T1
> > SAVE_ALL
> > - la.abs t1, __arch_cpu_idle
> > + la.pcrel t1, __arch_cpu_idle
> > LONG_L t0, sp, PT_ERA
> > /* 32 byte rollback region */
> > ori t0, t0, 0x1f
> > @@ -43,8 +42,7 @@ SYM_FUNC_START(handle_vint)
> > LONG_S t0, sp, PT_ERA
> > 1: move a0, sp
> > move a1, sp
> > - la.abs t0, do_vint
> > - jirl ra, t0, 0
> > + bl do_vint
> > RESTORE_ALL_AND_RET
> > SYM_FUNC_END(handle_vint)
> >
> > @@ -67,12 +65,10 @@ SYM_FUNC_END(except_vec_cex)
> > .macro BUILD_HANDLER exception handler prep
> > .align 5
> > SYM_FUNC_START(handle_\exception)
> > - BACKUP_T0T1
> > SAVE_ALL
> > build_prep_\prep
> > move a0, sp
> > - la.abs t0, do_\handler
> > - jirl ra, t0, 0
> > + bl do_\handler
> > RESTORE_ALL_AND_RET
> > SYM_FUNC_END(handle_\exception)
> > .endm
> > @@ -89,7 +85,11 @@ SYM_FUNC_END(except_vec_cex)
> > BUILD_HANDLER watch watch none
> > BUILD_HANDLER reserved reserved none /* others */
> >
> > -SYM_FUNC_START(handle_sys)
> > - la.abs t0, handle_syscall
> > +SYM_FUNC_START(handler_trampoline)
> > + csrwr t0, EXCEPTION_KS0
> > + csrwr t1, EXCEPTION_KS1
> > + pcaddi t0, 0
> > + ld.d t0, t0, 16
> > jr t0
> > -SYM_FUNC_END(handle_sys)
> > + nop
> > +SYM_FUNC_END(handler_trampoline)
> > diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> > index 57bada6b4e93..aa6181714ec3 100644
> > --- a/arch/loongarch/kernel/head.S
> > +++ b/arch/loongarch/kernel/head.S
> > @@ -117,7 +117,7 @@ SYM_CODE_START(smpboot_entry)
> > li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
> > csrwr t0, LOONGARCH_CSR_EUEN
> >
> > - la.abs t0, cpuboot_data
> > + la.pcrel t0, cpuboot_data
> > ld.d sp, t0, CPU_BOOT_STACK
> > ld.d tp, t0, CPU_BOOT_TINFO
> >
> > diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
> > index 7ea62faeeadb..0e8faaca3679 100644
> > --- a/arch/loongarch/kernel/traps.c
> > +++ b/arch/loongarch/kernel/traps.c
> > @@ -61,6 +61,7 @@ extern asmlinkage void handle_lasx(void);
> > extern asmlinkage void handle_reserved(void);
> > extern asmlinkage void handle_watch(void);
> > extern asmlinkage void handle_vint(void);
> > +extern asmlinkage void handler_trampoline(void);
> >
> > static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
> > const char *loglvl, bool user)
> > @@ -716,7 +717,8 @@ void per_cpu_trap_init(int cpu)
> > /* Install CPU exception handler */
> > void set_handler(unsigned long offset, void *addr, unsigned long size)
> > {
> > - memcpy((void *)(eentry + offset), addr, size);
> > + memcpy((void *)(eentry + offset), &handler_trampoline, 24);
> > + memcpy((void *)(eentry + offset + 24), &addr, 8);
> > local_flush_icache_range(eentry + offset, eentry + offset + size);
> > }
> >
> > diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S
> > index 58781c6e4191..cfaacdac518c 100644
> > --- a/arch/loongarch/mm/tlbex.S
> > +++ b/arch/loongarch/mm/tlbex.S
> > @@ -24,8 +24,7 @@
> > move a0, sp
> > REG_S a2, sp, PT_BVADDR
> > li.w a1, \write
> > - la.abs t0, do_page_fault
> > - jirl ra, t0, 0
> > + bl do_page_fault
> > RESTORE_ALL_AND_RET
> > SYM_FUNC_END(tlb_do_page_fault_\write)
> > .endm
> > @@ -34,20 +33,16 @@
> > tlb_do_page_fault 1
> >
> > SYM_FUNC_START(handle_tlb_protect)
> > - BACKUP_T0T1
> > SAVE_ALL
> > move a0, sp
> > move a1, zero
> > csrrd a2, LOONGARCH_CSR_BADV
> > REG_S a2, sp, PT_BVADDR
> > - la.abs t0, do_page_fault
> > - jirl ra, t0, 0
> > + bl do_page_fault
> > RESTORE_ALL_AND_RET
> > SYM_FUNC_END(handle_tlb_protect)
> >
> > SYM_FUNC_START(handle_tlb_load)
> > - csrwr t0, EXCEPTION_KS0
> > - csrwr t1, EXCEPTION_KS1
> > csrwr ra, EXCEPTION_KS2
> >
> > /*
> > @@ -116,7 +111,7 @@ smp_pgtable_change_load:
> >
> > #ifdef CONFIG_64BIT
> > vmalloc_load:
> > - la.abs t1, swapper_pg_dir
> > + la.pcrel t1, swapper_pg_dir
> > b vmalloc_done_load
> > #endif
> >
> > @@ -187,13 +182,10 @@ tlb_huge_update_load:
> > nopage_tlb_load:
> > dbar 0
> > csrrd ra, EXCEPTION_KS2
> > - la.abs t0, tlb_do_page_fault_0
> > - jr t0
> > + b tlb_do_page_fault_0
> > SYM_FUNC_END(handle_tlb_load)
> >
> > SYM_FUNC_START(handle_tlb_store)
> > - csrwr t0, EXCEPTION_KS0
> > - csrwr t1, EXCEPTION_KS1
> > csrwr ra, EXCEPTION_KS2
> >
> > /*
> > @@ -263,7 +255,7 @@ smp_pgtable_change_store:
> >
> > #ifdef CONFIG_64BIT
> > vmalloc_store:
> > - la.abs t1, swapper_pg_dir
> > + la.pcrel t1, swapper_pg_dir
> > b vmalloc_done_store
> > #endif
> >
> > @@ -336,13 +328,10 @@ tlb_huge_update_store:
> > nopage_tlb_store:
> > dbar 0
> > csrrd ra, EXCEPTION_KS2
> > - la.abs t0, tlb_do_page_fault_1
> > - jr t0
> > + b tlb_do_page_fault_1
> > SYM_FUNC_END(handle_tlb_store)
> >
> > SYM_FUNC_START(handle_tlb_modify)
> > - csrwr t0, EXCEPTION_KS0
> > - csrwr t1, EXCEPTION_KS1
> > csrwr ra, EXCEPTION_KS2
> >
> > /*
> > @@ -411,7 +400,7 @@ smp_pgtable_change_modify:
> >
> > #ifdef CONFIG_64BIT
> > vmalloc_modify:
> > - la.abs t1, swapper_pg_dir
> > + la.pcrel t1, swapper_pg_dir
> > b vmalloc_done_modify
> > #endif
> >
> > @@ -483,8 +472,7 @@ tlb_huge_update_modify:
> > nopage_tlb_modify:
> > dbar 0
> > csrrd ra, EXCEPTION_KS2
> > - la.abs t0, tlb_do_page_fault_1
> > - jr t0
> > + b tlb_do_page_fault_1
> > SYM_FUNC_END(handle_tlb_modify)
> >
> > SYM_FUNC_START(handle_tlb_refill)
>

2023-01-16 06:45:12

by Xi Ruoyao

[permalink] [raw]
Subject: Re: [PATCH 1/4] LoongArch: Use trampoline for exception handlers and kill la.abs

On Mon, 2023-01-16 at 09:30 +0800, Huacai Chen wrote:
> On Sat, Jan 14, 2023 at 2:38 PM Jinyang He <[email protected]>
> wrote:
> >
> > Hi, Ruoyao and Youling,
> >
> > I care about the performance when NUMA enabled. We set CSR.EENTRY
> > for each possible cpus where is NUMA-relative. So, I guess the more
> > codes in NUMA-relative memory makes more performance. If we just set
> > handler_trampoline as exception handler, the performance may be
> > influenced.
> So copying both the handlers and handler_trampoline can solve the
> problem? If that is possible, please do that on top of the latest code
> in
> https://github.com/loongson/linux/commits/loongarch-next

Hi folks,

I just wrote the trampoline code as a PoC to show "relocatable kernel
can work" and there must be some better way. But I'm too sad to write
any serious code in this month, and I don't have access to a LoongArch
NUMA system. So I think it's better to leave the job for you guys now
:).

Best regards

--
Xi Ruoyao <[email protected]>
School of Aerospace Science and Technology, Xidian University

2023-01-17 01:55:44

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH 1/4] LoongArch: Use trampoline for exception handlers and kill la.abs

On Mon, Jan 16, 2023 at 1:41 PM Xi Ruoyao <[email protected]> wrote:
>
> On Mon, 2023-01-16 at 09:30 +0800, Huacai Chen wrote:
> > On Sat, Jan 14, 2023 at 2:38 PM Jinyang He <[email protected]>
> > wrote:
> > >
> > > Hi, Ruoyao and Youling,
> > >
> > > I care about the performance when NUMA enabled. We set CSR.EENTRY
> > > for each possible cpus where is NUMA-relative. So, I guess the more
> > > codes in NUMA-relative memory makes more performance. If we just set
> > > handler_trampoline as exception handler, the performance may be
> > > influenced.
> > So copying both the handlers and handler_trampoline can solve the
> > problem? If that is possible, please do that on top of the latest code
> > in
> > https://github.com/loongson/linux/commits/loongarch-next
>
> Hi folks,
>
> I just wrote the trampoline code as a PoC to show "relocatable kernel
> can work" and there must be some better way. But I'm too sad to write
> any serious code in this month, and I don't have access to a LoongArch
> NUMA system. So I think it's better to leave the job for you guys now
> :).
Hmm, I hope this series can be merged in 6.3. :)

Huacai
>
> Best regards
>
> --
> Xi Ruoyao <[email protected]>
> School of Aerospace Science and Technology, Xidian University