Commit b51fc88c authored by Palmer Dabbelt's avatar Palmer Dabbelt

Merge patch series "riscv: Add remaining module relocations and tests"

Charlie Jenkins <charlie@rivosinc.com> says:

A handful of module relocations were missing, this patch includes the
remaining ones. I also wrote some test cases to ensure that module
loading works properly. Some relocations cannot be supported in the
kernel, these include the ones that rely on thread local storage and
dynamic linking.

This patch also overhauls the implementation of ADD/SUB/SET/ULEB128
relocations to handle overflow. "Overflow" is different for ULEB128
since it is a variable-length encoding that the compiler can be expected
to generate enough space for. Instead of overflowing, ULEB128 will
expand into the next 8-bit segment of the location.

A psABI proposal [1] was merged that mandates that SET_ULEB128 and
SUB_ULEB128 are paired, however the discussion following the merging of
the pull request revealed that while the pull request was valid, it
would be better for linkers to properly handle this overflow. This patch
proactively implements this methodology for future compatibility.

This can be tested by enabling KUNIT, RUNTIME_KERNEL_TESTING_MENU, and
RISCV_MODULE_LINKING_KUNIT.

[1] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/403

* b4-shazam-merge:
  riscv: Add tests for riscv module loading
  riscv: Add remaining module relocations
  riscv: Avoid unaligned access when relocating modules

Link: https://lore.kernel.org/r/20231101-module_relocations-v9-0-8dfa3483c400@rivosinc.comSigned-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parents 946bb33d af71bc19
source "arch/riscv/kernel/tests/Kconfig.debug"
......@@ -49,6 +49,7 @@ typedef union __riscv_fp_state elf_fpregset_t;
#define R_RISCV_TLS_DTPREL64 9
#define R_RISCV_TLS_TPREL32 10
#define R_RISCV_TLS_TPREL64 11
#define R_RISCV_IRELATIVE 58
/* Relocation types not used by the dynamic linker */
#define R_RISCV_BRANCH 16
......@@ -81,7 +82,6 @@ typedef union __riscv_fp_state elf_fpregset_t;
#define R_RISCV_ALIGN 43
#define R_RISCV_RVC_BRANCH 44
#define R_RISCV_RVC_JUMP 45
#define R_RISCV_LUI 46
#define R_RISCV_GPREL_I 47
#define R_RISCV_GPREL_S 48
#define R_RISCV_TPREL_I 49
......@@ -93,6 +93,9 @@ typedef union __riscv_fp_state elf_fpregset_t;
#define R_RISCV_SET16 55
#define R_RISCV_SET32 56
#define R_RISCV_32_PCREL 57
#define R_RISCV_PLT32 59
#define R_RISCV_SET_ULEB128 60
#define R_RISCV_SUB_ULEB128 61
#endif /* _UAPI_ASM_RISCV_ELF_H */
......@@ -57,6 +57,7 @@ obj-y += stacktrace.o
obj-y += cacheinfo.o
obj-y += patch.o
obj-y += probes/
obj-y += tests/
obj-$(CONFIG_MMU) += vdso.o vdso/
obj-$(CONFIG_RISCV_MISALIGNED) += traps_misaligned.o
......
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0-only
menu "arch/riscv/kernel Testing and Coverage"
config AS_HAS_ULEB128
def_bool $(as-instr,.reloc label$(comma) R_RISCV_SET_ULEB128$(comma) 127\n.reloc label$(comma) R_RISCV_SUB_ULEB128$(comma) 127\nlabel:\n.word 0)
menuconfig RUNTIME_KERNEL_TESTING_MENU
bool "arch/riscv/kernel runtime Testing"
def_bool y
help
Enable riscv kernel runtime testing.
if RUNTIME_KERNEL_TESTING_MENU
config RISCV_MODULE_LINKING_KUNIT
bool "KUnit test riscv module linking at runtime" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
help
Enable this option to test riscv module linking at boot. This will
enable a module called "test_module_linking".
KUnit tests run during boot and output the results to the debug log
in TAP format (http://testanything.org/). Only useful for kernel devs
running the KUnit test harness, and not intended for inclusion into a
production build.
For more information on KUnit and unit tests in general please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
endif # RUNTIME_TESTING_MENU
endmenu # "arch/riscv/kernel runtime Testing"
obj-$(CONFIG_RISCV_MODULE_LINKING_KUNIT) += module_test/
obj-m += test_module_linking.o
test_sub := test_sub6.o test_sub8.o test_sub16.o test_sub32.o test_sub64.o
test_set := test_set6.o test_set8.o test_set16.o test_set32.o
test_module_linking-objs += $(test_sub)
test_module_linking-objs += $(test_set)
ifeq ($(CONFIG_AS_HAS_ULEB128),y)
test_module_linking-objs += test_uleb128.o
endif
test_module_linking-objs += test_module_linking_main.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2023 Rivos Inc.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <kunit/test.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Test module linking");
extern int test_set32(void);
extern int test_set16(void);
extern int test_set8(void);
extern int test_set6(void);
extern long test_sub64(void);
extern int test_sub32(void);
extern int test_sub16(void);
extern int test_sub8(void);
extern int test_sub6(void);
#ifdef CONFIG_AS_HAS_ULEB128
extern int test_uleb_basic(void);
extern int test_uleb_large(void);
#endif
#define CHECK_EQ(lhs, rhs) KUNIT_ASSERT_EQ(test, lhs, rhs)
void run_test_set(struct kunit *test);
void run_test_sub(struct kunit *test);
void run_test_uleb(struct kunit *test);
void run_test_set(struct kunit *test)
{
int val32 = test_set32();
int val16 = test_set16();
int val8 = test_set8();
int val6 = test_set6();
CHECK_EQ(val32, 0);
CHECK_EQ(val16, 0);
CHECK_EQ(val8, 0);
CHECK_EQ(val6, 0);
}
void run_test_sub(struct kunit *test)
{
int val64 = test_sub64();
int val32 = test_sub32();
int val16 = test_sub16();
int val8 = test_sub8();
int val6 = test_sub6();
CHECK_EQ(val64, 0);
CHECK_EQ(val32, 0);
CHECK_EQ(val16, 0);
CHECK_EQ(val8, 0);
CHECK_EQ(val6, 0);
}
#ifdef CONFIG_AS_HAS_ULEB128
void run_test_uleb(struct kunit *test)
{
int val_uleb = test_uleb_basic();
int val_uleb2 = test_uleb_large();
CHECK_EQ(val_uleb, 0);
CHECK_EQ(val_uleb2, 0);
}
#endif
static struct kunit_case __refdata riscv_module_linking_test_cases[] = {
KUNIT_CASE(run_test_set),
KUNIT_CASE(run_test_sub),
#ifdef CONFIG_AS_HAS_ULEB128
KUNIT_CASE(run_test_uleb),
#endif
{}
};
static struct kunit_suite riscv_module_linking_test_suite = {
.name = "riscv_checksum",
.test_cases = riscv_module_linking_test_cases,
};
kunit_test_suites(&riscv_module_linking_test_suite);
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_set16
test_set16:
lw a0, set16
la t0, set16
#ifdef CONFIG_32BIT
slli t0, t0, 16
srli t0, t0, 16
#else
slli t0, t0, 48
srli t0, t0, 48
#endif
sub a0, a0, t0
ret
.data
set16:
.reloc set16, R_RISCV_SET16, set16
.word 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_set32
test_set32:
lw a0, set32
la t0, set32
#ifndef CONFIG_32BIT
slli t0, t0, 32
srli t0, t0, 32
#endif
sub a0, a0, t0
ret
.data
set32:
.reloc set32, R_RISCV_SET32, set32
.word 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_set6
test_set6:
lw a0, set6
la t0, set6
#ifdef CONFIG_32BIT
slli t0, t0, 26
srli t0, t0, 26
#else
slli t0, t0, 58
srli t0, t0, 58
#endif
sub a0, a0, t0
ret
.data
set6:
.reloc set6, R_RISCV_SET6, set6
.word 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_set8
test_set8:
lw a0, set8
la t0, set8
#ifdef CONFIG_32BIT
slli t0, t0, 24
srli t0, t0, 24
#else
slli t0, t0, 56
srli t0, t0, 56
#endif
sub a0, a0, t0
ret
.data
set8:
.reloc set8, R_RISCV_SET8, set8
.word 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_sub16
test_sub16:
lh a0, sub16
addi a0, a0, -32
ret
first:
.space 32
second:
.data
sub16:
.reloc sub16, R_RISCV_ADD16, second
.reloc sub16, R_RISCV_SUB16, first
.half 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_sub32
test_sub32:
lw a0, sub32
addi a0, a0, -32
ret
first:
.space 32
second:
.data
sub32:
.reloc sub32, R_RISCV_ADD32, second
.reloc sub32, R_RISCV_SUB32, first
.word 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_sub6
test_sub6:
lb a0, sub6
addi a0, a0, -32
ret
first:
.space 32
second:
.data
sub6:
.reloc sub6, R_RISCV_SET6, second
.reloc sub6, R_RISCV_SUB6, first
.byte 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_sub64
test_sub64:
#ifdef CONFIG_32BIT
lw a0, sub64
#else
ld a0, sub64
#endif
addi a0, a0, -32
ret
first:
.space 32
second:
.data
sub64:
.reloc sub64, R_RISCV_ADD64, second
.reloc sub64, R_RISCV_SUB64, first
.word 0
.word 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_sub8
test_sub8:
lb a0, sub8
addi a0, a0, -32
ret
first:
.space 32
second:
.data
sub8:
.reloc sub8, R_RISCV_ADD8, second
.reloc sub8, R_RISCV_SUB8, first
.byte 0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Rivos Inc.
*/
.text
.global test_uleb_basic
test_uleb_basic:
ld a0, second
addi a0, a0, -127
ret
.global test_uleb_large
test_uleb_large:
ld a0, fourth
addi a0, a0, -0x07e8
ret
.data
first:
.space 127
second:
.reloc second, R_RISCV_SET_ULEB128, second
.reloc second, R_RISCV_SUB_ULEB128, first
.dword 0
third:
.space 1000
fourth:
.reloc fourth, R_RISCV_SET_ULEB128, fourth
.reloc fourth, R_RISCV_SUB_ULEB128, third
.dword 0
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment