llext: Add RISC-V arch-specific relocations
This commit introduces architecture-specific ELF relocations for RISC-V, in accordance with the RISC-V PSABI specification: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc Also, the necessary compiler configurations for compiling LLEXT extensions on RISC-V are added, and the llext tests are executed on RISC-V targets. Calling llext extensions from user threads in RISC-V is still unsupported as of this commit. Signed-off-by: Eric Ackermann <eric.ackermann@cispa.de>
This commit is contained in:
parent
73a3438b82
commit
5275d44409
11 changed files with 729 additions and 11 deletions
|
@ -27,3 +27,4 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S)
|
|||
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ARCH_STACKWALK stacktrace.c)
|
||||
zephyr_linker_sources(ROM_START SORT_KEY 0x0vectors vector_table.ld)
|
||||
zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c)
|
||||
|
|
373
arch/riscv/core/elf.c
Normal file
373
arch/riscv/core/elf.c
Normal file
|
@ -0,0 +1,373 @@
|
|||
/** @file
|
||||
* @brief Architecture-specific relocations for RISC-V instruction sets.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2024 CISPA Helmholtz Center for Information Security gGmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr/llext/elf.h>
|
||||
#include <zephyr/llext/llext.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include <zephyr/arch/riscv/elf.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL);
|
||||
|
||||
/*
|
||||
* RISC-V relocations commonly use pairs of U-type and I-type instructions.
|
||||
* U-type instructions have 20-bit immediates, I-type instructions have 12-bit immediates.
|
||||
* Immediates in RISC-V are always sign-extended.
|
||||
* Thereby, this type of relocation can reach any address within a 2^31-1 byte range.
|
||||
*/
|
||||
#define RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE INT32_MAX
|
||||
|
||||
/* S-type has 12-bit signed immediate */
|
||||
#define RISCV_MAX_JUMP_DISTANCE_S_TYPE ((1 << 11) - 1)
|
||||
|
||||
/* I-type has 12-bit signed immediate also */
|
||||
#define RISCV_MAX_JUMP_DISTANCE_I_TYPE ((1 << 11) - 1)
|
||||
|
||||
/* B-type has 13-bit signed immediate */
|
||||
#define RISCV_MAX_JUMP_DISTANCE_B_TYPE ((1 << 12) - 1)
|
||||
|
||||
/* CB-type has 9-bit signed immediate */
|
||||
#define RISCV_MAX_JUMP_DISTANCE_CB_TYPE ((1 << 8) - 1)
|
||||
|
||||
/* CJ-type has 12-bit signed immediate (last bit implicit 0) */
|
||||
#define RISCV_MAX_JUMP_DISTANCE_CJ_TYPE ((1 << 11) - 1)
|
||||
|
||||
static inline int riscv_relocation_fits(long long jump_target, long long max_distance,
|
||||
elf_word reloc_type)
|
||||
{
|
||||
if (llabs(jump_target) > max_distance) {
|
||||
LOG_ERR("%lld byte relocation is not possible for type %" PRIu64 " (max %lld)!",
|
||||
jump_target, (uint64_t)reloc_type, max_distance);
|
||||
return -ENOEXEC; /* jump too far */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long long last_u_type_jump_target;
|
||||
|
||||
/**
|
||||
* @brief RISC-V specific function for relocating partially linked ELF binaries
|
||||
*
|
||||
* This implementation follows the official RISC-V specification:
|
||||
* https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc
|
||||
*
|
||||
*/
|
||||
int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc_unsigned, uintptr_t sym_base_addr_unsigned,
|
||||
const char *sym_name, uintptr_t load_bias)
|
||||
{
|
||||
/* FIXME currently, RISC-V relocations all fit in ELF_32_R_TYPE */
|
||||
elf_word reloc_type = ELF32_R_TYPE(rel->r_info);
|
||||
/*
|
||||
* The RISC-V specification uses the following symbolic names for the relocations:
|
||||
*
|
||||
* A - addend (rel->r_addend)
|
||||
* B - base address (load_bias)
|
||||
* G - global offset table (not supported yet)
|
||||
* P - position of the relocation (loc)
|
||||
* S - symbol value (sym_base_addr)
|
||||
* V - value at the relocation position (*loc)
|
||||
* GP - value of __global_pointer$ (not supported yet)
|
||||
* TLSMODULE - TLS module for the object (not supported yet)
|
||||
* TLSOFFSET - TLS static block for the object (not supported yet)
|
||||
*/
|
||||
intptr_t loc = (intptr_t)loc_unsigned;
|
||||
uint8_t *loc8 = (uint8_t *)loc, tmp8;
|
||||
uint16_t *loc16 = (uint16_t *)loc, tmp16;
|
||||
uint32_t *loc32 = (uint32_t *)loc, tmp32;
|
||||
uint64_t *loc64 = (uint64_t *)loc, tmp64;
|
||||
/* uint32_t or uint64_t */
|
||||
r_riscv_wordclass_t *loc_word = (r_riscv_wordclass_t *)loc;
|
||||
uint32_t modified_operand;
|
||||
uint16_t modified_compressed_operand;
|
||||
int32_t imm8;
|
||||
long long original_imm8, jump_target;
|
||||
int16_t compressed_imm8;
|
||||
__typeof__(rel->r_addend) target_alignment = 1;
|
||||
const intptr_t sym_base_addr = (intptr_t)sym_base_addr_unsigned;
|
||||
|
||||
LOG_DBG("Relocating symbol %s at %p with base address %p load address %p type %" PRIu64,
|
||||
sym_name, (void *)loc, (void *)sym_base_addr, (void *)load_bias,
|
||||
(uint64_t)reloc_type);
|
||||
|
||||
/* FIXME not all types of relocations currently supported, especially TLS */
|
||||
|
||||
switch (reloc_type) {
|
||||
case R_RISCV_NONE:
|
||||
break;
|
||||
case R_RISCV_32:
|
||||
jump_target = sym_base_addr + rel->r_addend; /* S + A */
|
||||
UNALIGNED_PUT((uint32_t)jump_target, loc32);
|
||||
return riscv_relocation_fits(jump_target, INT32_MAX, reloc_type);
|
||||
case R_RISCV_64:
|
||||
/* full 64-bit range, need no range check */
|
||||
UNALIGNED_PUT(sym_base_addr + rel->r_addend, loc64); /* S + A */
|
||||
break;
|
||||
case R_RISCV_RELATIVE:
|
||||
/* either full 32-bit or 64-bit range, need no range check */
|
||||
UNALIGNED_PUT(load_bias + rel->r_addend, loc_word); /* B + A */
|
||||
break;
|
||||
case R_RISCV_JUMP_SLOT:
|
||||
/* either full 32-bit or 64-bit range, need no range check */
|
||||
UNALIGNED_PUT(sym_base_addr, loc_word); /* S */
|
||||
break;
|
||||
case R_RISCV_BRANCH:
|
||||
jump_target = sym_base_addr + rel->r_addend - loc; /* S + A - P */
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
imm8 = jump_target;
|
||||
modified_operand = R_RISCV_CLEAR_BTYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_BTYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_B_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_JAL:
|
||||
jump_target = sym_base_addr + rel->r_addend - loc; /* S + A - P */
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
imm8 = jump_target;
|
||||
modified_operand = R_RISCV_CLEAR_JTYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_JTYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_CALL:
|
||||
case R_RISCV_CALL_PLT:
|
||||
case R_RISCV_PCREL_HI20:
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
jump_target = sym_base_addr + rel->r_addend - loc; /* S + A - P */
|
||||
imm8 = jump_target;
|
||||
/* bit 12 of the immediate goes to I-type instruction and might
|
||||
* change the sign of the number
|
||||
*/
|
||||
/* in order to avoid that, we add 1 to the upper immediate if bit 12 is one */
|
||||
/* see RISC-V la pseudo instruction */
|
||||
imm8 += imm8 & 0x800;
|
||||
|
||||
original_imm8 = imm8;
|
||||
|
||||
modified_operand = R_RISCV_CLEAR_UTYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_UTYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
|
||||
if (reloc_type != R_RISCV_PCREL_HI20) {
|
||||
/* PCREL_HI20 is only U-type, not truly U+I-type */
|
||||
/* for the others, need to also modify following I-type */
|
||||
loc32++;
|
||||
|
||||
imm8 = jump_target;
|
||||
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
modified_operand = R_RISCV_CLEAR_ITYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_ITYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
}
|
||||
|
||||
last_u_type_jump_target = jump_target;
|
||||
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
/* need the same jump target as preceding U-type relocation */
|
||||
if (last_u_type_jump_target == 0) {
|
||||
LOG_ERR("R_RISCV_PCREL_LO12_I relocation without preceding U-type "
|
||||
"relocation!");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
jump_target = last_u_type_jump_target; /* S - P */
|
||||
last_u_type_jump_target = 0;
|
||||
imm8 = jump_target;
|
||||
modified_operand = R_RISCV_CLEAR_ITYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_ITYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE,
|
||||
reloc_type);
|
||||
break;
|
||||
case R_RISCV_PCREL_LO12_S:
|
||||
/* need the same jump target as preceding U-type relocation */
|
||||
if (last_u_type_jump_target == 0) {
|
||||
LOG_ERR("R_RISCV_PCREL_LO12_I relocation without preceding U-type "
|
||||
"relocation!");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
jump_target = last_u_type_jump_target; /* S - P */
|
||||
last_u_type_jump_target = 0;
|
||||
imm8 = jump_target;
|
||||
modified_operand = R_RISCV_CLEAR_STYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_STYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_HI20:
|
||||
jump_target = sym_base_addr + rel->r_addend; /* S + A */
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
imm8 = jump_target;
|
||||
/* bit 12 of the immediate goes to I-type instruction and might
|
||||
* change the sign of the number
|
||||
*/
|
||||
/* in order to avoid that, we add 1 to the upper immediate if bit 12 is one*/
|
||||
/* see RISC-V la pseudo instruction */
|
||||
original_imm8 = imm8;
|
||||
imm8 += imm8 & 0x800;
|
||||
modified_operand = R_RISCV_CLEAR_UTYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_UTYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_LO12_I:
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
jump_target = sym_base_addr + rel->r_addend; /* S + A */
|
||||
imm8 = jump_target;
|
||||
/* this is always used with R_RISCV_HI20 */
|
||||
modified_operand = R_RISCV_CLEAR_ITYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_ITYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_LO12_S:
|
||||
modified_operand = UNALIGNED_GET(loc32);
|
||||
imm8 = sym_base_addr + rel->r_addend; /* S + A */
|
||||
/*
|
||||
* S-type is used for stores/loads etc.
|
||||
* size check is done at compile time, as it depends on the size of
|
||||
* the structure we are trying to load/store
|
||||
*/
|
||||
modified_operand = R_RISCV_CLEAR_STYPE_IMM8(modified_operand);
|
||||
modified_operand = R_RISCV_SET_STYPE_IMM8(modified_operand, imm8);
|
||||
UNALIGNED_PUT(modified_operand, loc32);
|
||||
break;
|
||||
/* for add/sub/set, compiler needs to ensure that the ELF sections are close enough */
|
||||
case R_RISCV_ADD8:
|
||||
tmp8 = UNALIGNED_GET(loc8);
|
||||
tmp8 += sym_base_addr + rel->r_addend; /* V + S + A */
|
||||
UNALIGNED_PUT(tmp8, loc8);
|
||||
break;
|
||||
case R_RISCV_ADD16:
|
||||
tmp16 = UNALIGNED_GET(loc16);
|
||||
tmp16 += sym_base_addr + rel->r_addend; /* V + S + A */
|
||||
UNALIGNED_PUT(tmp16, loc16);
|
||||
break;
|
||||
case R_RISCV_ADD32:
|
||||
tmp32 = UNALIGNED_GET(loc32);
|
||||
tmp32 += sym_base_addr + rel->r_addend; /* V + S + A */
|
||||
UNALIGNED_PUT(tmp32, loc32);
|
||||
break;
|
||||
case R_RISCV_ADD64:
|
||||
tmp64 = UNALIGNED_GET(loc64);
|
||||
tmp64 += sym_base_addr + rel->r_addend; /* V + S + A */
|
||||
UNALIGNED_PUT(tmp64, loc64);
|
||||
break;
|
||||
case R_RISCV_SUB8:
|
||||
tmp8 = UNALIGNED_GET(loc8);
|
||||
tmp8 -= sym_base_addr + rel->r_addend; /* V - S - A */
|
||||
UNALIGNED_PUT(tmp8, loc8);
|
||||
break;
|
||||
case R_RISCV_SUB16:
|
||||
tmp16 = UNALIGNED_GET(loc16);
|
||||
tmp16 -= sym_base_addr + rel->r_addend; /* V - S - A */
|
||||
UNALIGNED_PUT(tmp16, loc16);
|
||||
break;
|
||||
case R_RISCV_SUB32:
|
||||
tmp32 = UNALIGNED_GET(loc32);
|
||||
tmp32 -= sym_base_addr + rel->r_addend; /* V - S - A */
|
||||
UNALIGNED_PUT(tmp32, loc32);
|
||||
break;
|
||||
case R_RISCV_SUB64:
|
||||
tmp64 = UNALIGNED_GET(loc64);
|
||||
tmp64 -= sym_base_addr + rel->r_addend; /* V - S - A */
|
||||
UNALIGNED_PUT(tmp64, loc64);
|
||||
break;
|
||||
case R_RISCV_SUB6:
|
||||
tmp8 = UNALIGNED_GET(loc8) & (0x1F);
|
||||
UNALIGNED_PUT(tmp8, loc8);
|
||||
tmp8 = tmp8 - sym_base_addr - rel->r_addend; /* V - S - A */
|
||||
tmp8 = tmp8 & (0x1F);
|
||||
tmp8 = tmp8 | UNALIGNED_GET(loc8);
|
||||
UNALIGNED_PUT(tmp8, loc8);
|
||||
break;
|
||||
case R_RISCV_SET6:
|
||||
tmp8 = UNALIGNED_GET(loc8) & (0x1F);
|
||||
UNALIGNED_PUT(tmp8, loc8);
|
||||
tmp8 = sym_base_addr + rel->r_addend; /* S + A */
|
||||
tmp8 = tmp8 | UNALIGNED_GET(loc8);
|
||||
UNALIGNED_PUT(tmp8, loc8);
|
||||
break;
|
||||
case R_RISCV_SET8:
|
||||
tmp8 = sym_base_addr + rel->r_addend; /* S + A */
|
||||
UNALIGNED_PUT(tmp8, loc8);
|
||||
break;
|
||||
case R_RISCV_SET16:
|
||||
tmp16 = sym_base_addr + rel->r_addend; /* S + A */
|
||||
UNALIGNED_PUT(tmp16, loc16);
|
||||
break;
|
||||
case R_RISCV_SET32:
|
||||
tmp32 = sym_base_addr + rel->r_addend; /* S + A */
|
||||
UNALIGNED_PUT(tmp32, loc32);
|
||||
break;
|
||||
case R_RISCV_32_PCREL:
|
||||
jump_target = sym_base_addr + rel->r_addend - loc; /* S + A - P */
|
||||
tmp32 = jump_target;
|
||||
UNALIGNED_PUT(tmp32, loc32);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_PLT32:
|
||||
jump_target = sym_base_addr + rel->r_addend - loc; /* S + A - P */
|
||||
tmp32 = jump_target;
|
||||
UNALIGNED_PUT(tmp32, loc32);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_U_PLUS_I_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_RVC_BRANCH:
|
||||
jump_target = sym_base_addr + rel->r_addend - loc; /* S + A - P */
|
||||
modified_compressed_operand = UNALIGNED_GET(loc16);
|
||||
compressed_imm8 = jump_target;
|
||||
modified_compressed_operand =
|
||||
R_RISCV_CLEAR_CBTYPE_IMM8(modified_compressed_operand);
|
||||
modified_compressed_operand =
|
||||
R_RISCV_SET_CBTYPE_IMM8(modified_compressed_operand, compressed_imm8);
|
||||
UNALIGNED_PUT(modified_compressed_operand, loc16);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_CB_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_RVC_JUMP:
|
||||
jump_target = sym_base_addr + rel->r_addend - loc; /* S + A - P */
|
||||
modified_compressed_operand = UNALIGNED_GET(loc16);
|
||||
compressed_imm8 = jump_target;
|
||||
modified_compressed_operand =
|
||||
R_RISCV_CLEAR_CJTYPE_IMM8(modified_compressed_operand);
|
||||
modified_compressed_operand =
|
||||
R_RISCV_SET_CJTYPE_IMM8(modified_compressed_operand, compressed_imm8);
|
||||
UNALIGNED_PUT(modified_compressed_operand, loc16);
|
||||
return riscv_relocation_fits(jump_target, RISCV_MAX_JUMP_DISTANCE_CJ_TYPE,
|
||||
reloc_type);
|
||||
case R_RISCV_ALIGN:
|
||||
/* we are supposed to move the symbol such that it is aligned to the next power of
|
||||
* two >= addend
|
||||
*/
|
||||
/* this involves moving the symbol */
|
||||
while (target_alignment < rel->r_addend) {
|
||||
target_alignment *= 2;
|
||||
}
|
||||
LOG_ERR("Symbol %s with location %p requires alignment to %" PRIu64 " bytes!",
|
||||
sym_name, (void *)loc, (uint64_t)target_alignment);
|
||||
LOG_ERR("Alignment relocation is currently not supported!");
|
||||
return -ENOEXEC;
|
||||
/* ignored, this is primarily intended for removing instructions during link-time
|
||||
* optimization
|
||||
*/
|
||||
case R_RISCV_RELAX:
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unsupported relocation type: %" PRIu64 " for symbol: %s",
|
||||
(uint64_t)reloc_type, sym_name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -71,3 +71,23 @@ endif()
|
|||
|
||||
list(APPEND TOOLCHAIN_C_FLAGS -mabi=${riscv_mabi} -march=${riscv_march})
|
||||
list(APPEND TOOLCHAIN_LD_FLAGS NO_SPLIT -mabi=${riscv_mabi} -march=${riscv_march})
|
||||
|
||||
# Flags not supported by llext linker
|
||||
# (regexps are supported and match whole word)
|
||||
set(LLEXT_REMOVE_FLAGS
|
||||
-fno-pic
|
||||
-fno-pie
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
-g.*
|
||||
-Os
|
||||
)
|
||||
|
||||
# Flags to be added to llext code compilation
|
||||
# mno-relax is needed to stop gcc from generating R_RISCV_ALIGN relocations,
|
||||
# which are currently not supported
|
||||
set(LLEXT_APPEND_FLAGS
|
||||
-mabi=${riscv_mabi}
|
||||
-march=${riscv_march}
|
||||
-mno-relax
|
||||
)
|
|
@ -21,4 +21,4 @@ and introspected to some degree, as well as unloaded when no longer needed.
|
|||
.. note::
|
||||
|
||||
The LLEXT subsystem requires architecture-specific support. It is currently
|
||||
available only on ARM, ARM64 and Xtensa cores.
|
||||
available only on RISC-V, ARM, ARM64 and Xtensa cores.
|
||||
|
|
298
include/zephyr/arch/riscv/elf.h
Normal file
298
include/zephyr/arch/riscv/elf.h
Normal file
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief RISCV-Specific constants for ELF binaries.
|
||||
*
|
||||
* References can be found here:
|
||||
* https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2024 CISPA Helmholtz Center for Information Security gGmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_ARCH_RISCV_ELF_H
|
||||
#define ZEPHYR_ARCH_RISCV_ELF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/sys/util_macro.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Relocation names for RISCV-specific relocations
|
||||
* @cond ignore
|
||||
*/
|
||||
|
||||
#define R_RISCV_NONE 0
|
||||
#define R_RISCV_32 1
|
||||
#define R_RISCV_64 2
|
||||
#define R_RISCV_RELATIVE 3
|
||||
#define R_RISCV_COPY 4
|
||||
#define R_RISCV_JUMP_SLOT 5
|
||||
#define R_RISCV_TLS_DTPMOD32 6
|
||||
#define R_RISCV_TLS_DTPMOD64 7
|
||||
#define R_RISCV_TLS_DTPREL32 8
|
||||
#define R_RISCV_TLS_DTPREL64 9
|
||||
#define R_RISCV_TLS_TPREL32 10
|
||||
#define R_RISCV_TLS_TPREL64 11
|
||||
#define R_RISCV_TLSDESC 12
|
||||
/* 13-15 reserved */
|
||||
#define R_RISCV_BRANCH 16
|
||||
#define R_RISCV_JAL 17
|
||||
#define R_RISCV_CALL 18
|
||||
#define R_RISCV_CALL_PLT 19
|
||||
#define R_RISCV_GOT_HI20 20
|
||||
#define R_RISCV_TLS_GOT_HI20 21
|
||||
#define R_RISCV_TLS_GD_HI20 22
|
||||
#define R_RISCV_PCREL_HI20 23
|
||||
#define R_RISCV_PCREL_LO12_I 24
|
||||
#define R_RISCV_PCREL_LO12_S 25
|
||||
#define R_RISCV_HI20 26
|
||||
#define R_RISCV_LO12_I 27
|
||||
#define R_RISCV_LO12_S 28
|
||||
#define R_RISCV_TPREL_HI20 29
|
||||
#define R_RISCV_TPREL_LO12_I 30
|
||||
#define R_RISCV_TPREL_LO12_S 31
|
||||
#define R_RISCV_TPREL_ADD 32
|
||||
#define R_RISCV_ADD8 33
|
||||
#define R_RISCV_ADD16 34
|
||||
#define R_RISCV_ADD32 35
|
||||
#define R_RISCV_ADD64 36
|
||||
#define R_RISCV_SUB8 37
|
||||
#define R_RISCV_SUB16 38
|
||||
#define R_RISCV_SUB32 39
|
||||
#define R_RISCV_SUB64 40
|
||||
#define R_RISCV_GOT32_PCREL 41
|
||||
/* 42 reserved */
|
||||
#define R_RISCV_ALIGN 43
|
||||
/* next two refer to compressed instructions */
|
||||
#define R_RISCV_RVC_BRANCH 44
|
||||
#define R_RISCV_RVC_JUMP 45
|
||||
/* 46-50 reserved */
|
||||
#define R_RISCV_RELAX 51
|
||||
#define R_RISCV_SUB6 52
|
||||
#define R_RISCV_SET6 53
|
||||
#define R_RISCV_SET8 54
|
||||
#define R_RISCV_SET16 55
|
||||
#define R_RISCV_SET32 56
|
||||
#define R_RISCV_32_PCREL 57
|
||||
#define R_RISCV_IRELATIVE 58
|
||||
#define R_RISCV_PLT32 59
|
||||
#define R_RISCV_SET_ULEB128 60
|
||||
#define R_RISCV_SUB_ULEB128 61
|
||||
#define R_RISCV_TLSDESC_HI20 62
|
||||
#define R_RISCV_TLSDESC_LOAD_LO12 63
|
||||
#define R_RISCV_TLSDESC_ADD_LO12 64
|
||||
#define R_RISCV_TLSDESC_CALL 65
|
||||
/* 66-190 reserved */
|
||||
#define R_RISCV_VENDOR 191
|
||||
/* 192-255 reserved */
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* "wordclass" from RISC-V specification
|
||||
* @cond ignore
|
||||
*/
|
||||
#if defined(CONFIG_64BIT)
|
||||
typedef uint64_t r_riscv_wordclass_t;
|
||||
#else
|
||||
typedef uint32_t r_riscv_wordclass_t;
|
||||
#endif
|
||||
/** @endcond */
|
||||
|
||||
/** @brief Extract bit from immediate
|
||||
*
|
||||
* @param imm8 immediate value (usually upper 20 or lower 12 bit)
|
||||
* @param bit which bit to extract
|
||||
*/
|
||||
#define R_RISCV_IMM8_GET_BIT(imm8, bit) (((imm8) & BIT(bit)) >> (bit))
|
||||
|
||||
/** @brief Generate mask for immediate in B-type RISC-V instruction
|
||||
*
|
||||
* @param imm8 immediate value, lower 12 bits used;
|
||||
* due to alignment requirements, imm8[0] is implicitly 0
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_BTYPE_IMM8_MASK(imm8) \
|
||||
((R_RISCV_IMM8_GET_BIT(imm8, 12) << 31) | (R_RISCV_IMM8_GET_BIT(imm8, 10) << 30) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 9) << 29) | (R_RISCV_IMM8_GET_BIT(imm8, 8) << 28) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 7) << 27) | (R_RISCV_IMM8_GET_BIT(imm8, 6) << 26) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 5) << 25) | (R_RISCV_IMM8_GET_BIT(imm8, 4) << 11) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 3) << 10) | (R_RISCV_IMM8_GET_BIT(imm8, 2) << 9) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 1) << 8) | (R_RISCV_IMM8_GET_BIT(imm8, 11) << 7))
|
||||
|
||||
/** @brief Generate mask for immediate in J-type RISC-V instruction
|
||||
*
|
||||
* @param imm8 immediate value, lower 21 bits used;
|
||||
* due to alignment requirements, imm8[0] is implicitly 0
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_JTYPE_IMM8_MASK(imm8) \
|
||||
((R_RISCV_IMM8_GET_BIT(imm8, 20) << 31) | (R_RISCV_IMM8_GET_BIT(imm8, 10) << 30) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 9) << 29) | (R_RISCV_IMM8_GET_BIT(imm8, 8) << 28) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 7) << 27) | (R_RISCV_IMM8_GET_BIT(imm8, 6) << 26) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 5) << 25) | (R_RISCV_IMM8_GET_BIT(imm8, 4) << 24) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 3) << 23) | (R_RISCV_IMM8_GET_BIT(imm8, 2) << 22) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 1) << 21) | (R_RISCV_IMM8_GET_BIT(imm8, 11) << 20) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 19) << 19) | (R_RISCV_IMM8_GET_BIT(imm8, 18) << 18) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 17) << 17) | (R_RISCV_IMM8_GET_BIT(imm8, 16) << 16) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 15) << 15) | (R_RISCV_IMM8_GET_BIT(imm8, 14) << 14) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 13) << 13) | (R_RISCV_IMM8_GET_BIT(imm8, 12) << 12))
|
||||
|
||||
/** @brief Generate mask for immediate in S-type RISC-V instruction
|
||||
*
|
||||
* @param imm8 immediate value, lower 12 bits used
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_STYPE_IMM8_MASK(imm8) \
|
||||
((R_RISCV_IMM8_GET_BIT(imm8, 11) << 31) | (R_RISCV_IMM8_GET_BIT(imm8, 10) << 30) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 9) << 29) | (R_RISCV_IMM8_GET_BIT(imm8, 8) << 28) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 7) << 27) | (R_RISCV_IMM8_GET_BIT(imm8, 6) << 26) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 5) << 25) | (R_RISCV_IMM8_GET_BIT(imm8, 4) << 11) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 3) << 10) | (R_RISCV_IMM8_GET_BIT(imm8, 2) << 9) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 1) << 8) | (R_RISCV_IMM8_GET_BIT(imm8, 0) << 7))
|
||||
|
||||
/** @brief Generate mask for immediate in compressed J-type RISC-V instruction
|
||||
*
|
||||
* @param imm8 immediate value, lower 12 bits used;
|
||||
* due to alignment requirements, imm8[0] is implicitly 0
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CJTYPE_IMM8_MASK(imm8) \
|
||||
((R_RISCV_IMM8_GET_BIT(imm8, 11) << 12) | (R_RISCV_IMM8_GET_BIT(imm8, 4) << 11) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 9) << 10) | (R_RISCV_IMM8_GET_BIT(imm8, 8) << 9) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 10) << 8) | (R_RISCV_IMM8_GET_BIT(imm8, 6) << 7) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 7) << 6) | (R_RISCV_IMM8_GET_BIT(imm8, 3) << 5) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 2) << 4) | (R_RISCV_IMM8_GET_BIT(imm8, 1) << 3) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 5) << 2))
|
||||
|
||||
/** @brief Generate mask for immediate in compressed B-type RISC-V instruction
|
||||
*
|
||||
* @param imm8 immediate value, lower 9 bits used;
|
||||
* due to alignment requirements, imm8[0] is implicitly 0
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CBTYPE_IMM8_MASK(imm8) \
|
||||
((R_RISCV_IMM8_GET_BIT(imm8, 8) << 12) | (R_RISCV_IMM8_GET_BIT(imm8, 4) << 11) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 3) << 10) | (R_RISCV_IMM8_GET_BIT(imm8, 7) << 6) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 6) << 5) | (R_RISCV_IMM8_GET_BIT(imm8, 2) << 4) | \
|
||||
(R_RISCV_IMM8_GET_BIT(imm8, 1) << 3) | (R_RISCV_IMM8_GET_BIT(imm8, 5) << 2))
|
||||
|
||||
/** @brief Clear immediate bits in B-type instruction.
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, B-type
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CLEAR_BTYPE_IMM8(operand) ((operand) & ~R_RISCV_BTYPE_IMM8_MASK((uint32_t) -1))
|
||||
|
||||
/** @brief Overwrite immediate in B-type instruction
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, B-type
|
||||
* @param imm8 New immediate
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_SET_BTYPE_IMM8(operand, imm8) \
|
||||
((R_RISCV_CLEAR_BTYPE_IMM8(operand)) | R_RISCV_BTYPE_IMM8_MASK(imm8))
|
||||
|
||||
/** @brief Clear immediate bits in J-type instruction.
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, J-type
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CLEAR_JTYPE_IMM8(operand) ((operand) & ~R_RISCV_JTYPE_IMM8_MASK((uint32_t) -1))
|
||||
|
||||
/** @brief Overwrite immediate in J-type instruction
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, J-type
|
||||
* @param imm8 New immediate
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_SET_JTYPE_IMM8(operand, imm8) \
|
||||
((R_RISCV_CLEAR_JTYPE_IMM8(operand)) | R_RISCV_JTYPE_IMM8_MASK(imm8))
|
||||
|
||||
/** @brief Clear immediate bits in S-type instruction.
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, S-type
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CLEAR_STYPE_IMM8(operand) ((operand) & ~R_RISCV_STYPE_IMM8_MASK((uint32_t) -1))
|
||||
|
||||
/** @brief Overwrite immediate in S-type instruction
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, S-type
|
||||
* @param imm8 New immediate
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_SET_STYPE_IMM8(operand, imm8) \
|
||||
((R_RISCV_CLEAR_STYPE_IMM8(operand)) | R_RISCV_STYPE_IMM8_MASK(imm8))
|
||||
|
||||
/** @brief Clear immediate bits in compressed J-type instruction.
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, compressed-J-type
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CLEAR_CJTYPE_IMM8(operand) ((operand) & ~R_RISCV_CJTYPE_IMM8_MASK((uint32_t) -1))
|
||||
|
||||
/** @brief Overwrite immediate in compressed J-type instruction
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, compressed-J-type
|
||||
* @param imm8 New immediate
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_SET_CJTYPE_IMM8(operand, imm8) \
|
||||
((R_RISCV_CLEAR_CJTYPE_IMM8(operand)) | R_RISCV_CJTYPE_IMM8_MASK(imm8))
|
||||
|
||||
/** @brief Clear immediate bits in compressed B-type instruction.
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, compressed-B-type
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CLEAR_CBTYPE_IMM8(operand) ((operand) & ~R_RISCV_CBTYPE_IMM8_MASK((uint32_t) -1))
|
||||
|
||||
/** @brief Overwrite immediate in compressed B-type instruction
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, compressed-B-type
|
||||
* @param imm8 New immediate
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_SET_CBTYPE_IMM8(operand, imm8) \
|
||||
((R_RISCV_CLEAR_CBTYPE_IMM8(operand)) | R_RISCV_CBTYPE_IMM8_MASK(imm8))
|
||||
|
||||
/** @brief Clear immediate bits in U-type instruction.
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, U-type
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CLEAR_UTYPE_IMM8(operand) ((operand) & ~(0xFFFFF000))
|
||||
|
||||
/** @brief Overwrite immediate in U-type instruction
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, U-type
|
||||
* @param imm8 New immediate
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_SET_UTYPE_IMM8(operand, imm8) \
|
||||
((R_RISCV_CLEAR_UTYPE_IMM8(operand)) | ((imm8) & 0xFFFFF000))
|
||||
|
||||
/** @brief Clear immediate bits in I-type instruction.
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, I-type
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_CLEAR_ITYPE_IMM8(operand) ((operand) & ~(0xFFF00000))
|
||||
|
||||
/** @brief Overwrite immediate in I-type instruction
|
||||
*
|
||||
* @param operand Address of RISC-V instruction, I-type
|
||||
* @param imm8 New immediate
|
||||
*
|
||||
*/
|
||||
#define R_RISCV_SET_ITYPE_IMM8(operand, imm8) ((R_RISCV_CLEAR_ITYPE_IMM8(operand)) | ((imm8) << 20))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_ARCH_RISCV_ELF_H */
|
|
@ -17,4 +17,8 @@ if(CONFIG_LLEXT)
|
|||
fs_loader.c
|
||||
)
|
||||
zephyr_library_sources_ifdef(CONFIG_LLEXT_SHELL shell.c)
|
||||
|
||||
if(CONFIG_RISCV AND CONFIG_USERSPACE)
|
||||
message(WARNING "Running LLEXT extensions from user-space threads on RISC-V is not supported!")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -14,15 +14,17 @@ choice LLEXT_BINARY_TYPE
|
|||
prompt "Binary object type for llext"
|
||||
default LLEXT_TYPE_ELF_OBJECT if ARM || ARM64
|
||||
default LLEXT_TYPE_ELF_SHAREDLIB if XTENSA
|
||||
default LLEXT_TYPE_ELF_RELOCATABLE if RISCV
|
||||
help
|
||||
Object type for llext
|
||||
|
||||
config LLEXT_TYPE_ELF_OBJECT
|
||||
bool "Single object ELF file"
|
||||
depends on !RISCV
|
||||
help
|
||||
Build and expect object files as binary object type for the
|
||||
llext subsystem. A single compiler invocation is used to
|
||||
generate the object file.
|
||||
generate the object file. Currently not supported on RISC-V.
|
||||
|
||||
config LLEXT_TYPE_ELF_RELOCATABLE
|
||||
bool "Relocatable ELF file"
|
||||
|
|
|
@ -387,6 +387,14 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext,
|
|||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported symbols region can also overlap
|
||||
* with rodata.
|
||||
*/
|
||||
if (i == LLEXT_MEM_EXPORT || j == LLEXT_MEM_EXPORT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ldr->hdr.e_type == ET_DYN) {
|
||||
/*
|
||||
* Test all merged VMA ranges for overlaps
|
||||
|
|
|
@ -67,7 +67,7 @@ if(NOT CONFIG_LLEXT_TYPE_ELF_OBJECT)
|
|||
)
|
||||
endif()
|
||||
|
||||
if (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE AND NOT CONFIG_ARM)
|
||||
if (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE AND NOT CONFIG_ARM AND NOT CONFIG_RISCV)
|
||||
# Manually fix the pre_located extension's text address at a multiple of 4
|
||||
get_target_property(pre_located_target pre_located_ext lib_target)
|
||||
get_target_property(pre_located_file pre_located_ext pkg_input)
|
||||
|
|
|
@ -421,6 +421,12 @@ ZTEST(llext, test_find_section)
|
|||
uintptr_t symbol_ptr = (uintptr_t)llext_find_sym(&ext->exp_tab, "number");
|
||||
uintptr_t section_ptr = (uintptr_t)find_section_ext + section_ofs;
|
||||
|
||||
/*
|
||||
* FIXME on RISC-V, at least for GCC, the symbols aren't always at the beginning
|
||||
* of the section when CONFIG_LLEXT_TYPE_ELF_OBJECT is used, breaking this assertion.
|
||||
* Currently, CONFIG_LLEXT_TYPE_ELF_OBJECT is not supported on RISC-V.
|
||||
*/
|
||||
|
||||
zassert_equal(symbol_ptr, section_ptr,
|
||||
"symbol at %p != .data section at %p (%zd bytes in the ELF)",
|
||||
symbol_ptr, section_ptr, section_ofs);
|
||||
|
|
|
@ -34,73 +34,79 @@ tests:
|
|||
# Run the suite with all combinations of core Kconfig options for the llext
|
||||
# subsystem (storage type, ELF type, MPU/MMU etc)
|
||||
llext.simple.readonly:
|
||||
arch_allow: arm # Xtensa needs writable storage
|
||||
arch_allow: arm riscv # Xtensa needs writable storage
|
||||
filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE
|
||||
extra_configs:
|
||||
- arch:arm:CONFIG_ARM_MPU=n
|
||||
- arch:arm:CONFIG_ARM_AARCH32_MMU=n
|
||||
- arch:riscv:CONFIG_RISCV_PMP=n
|
||||
- CONFIG_LLEXT_STORAGE_WRITABLE=n
|
||||
llext.simple.readonly_mpu:
|
||||
min_ram: 128
|
||||
arch_allow: arm # Xtensa needs writable storage
|
||||
arch_allow: arm # Xtensa needs writable storage, currently not supported on RISC-V
|
||||
filter: CONFIG_ARCH_HAS_USERSPACE
|
||||
extra_configs:
|
||||
- CONFIG_USERSPACE=y
|
||||
- CONFIG_LLEXT_STORAGE_WRITABLE=n
|
||||
llext.simple.readonly_fs_loader:
|
||||
arch_allow: arm # Xtensa needs writable storage
|
||||
arch_allow: arm riscv # Xtensa needs writable storage
|
||||
filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE
|
||||
extra_configs:
|
||||
- arch:arm:CONFIG_ARM_MPU=n
|
||||
- arch:arm:CONFIG_ARM_AARCH32_MMU=n
|
||||
- arch:riscv:CONFIG_RISCV_PMP=n
|
||||
- CONFIG_LLEXT_STORAGE_WRITABLE=n
|
||||
llext.simple.readonly_mmu:
|
||||
arch_allow: arm64 arm
|
||||
arch_allow: arm64 arm riscv
|
||||
filter: CONFIG_ARM_MMU
|
||||
integration_platforms:
|
||||
- qemu_cortex_a53 # ARM Cortex-A53 (ARMv8-A ISA)
|
||||
extra_configs:
|
||||
- CONFIG_LLEXT_STORAGE_WRITABLE=n
|
||||
llext.simple.writable:
|
||||
arch_allow: arm xtensa
|
||||
arch_allow: arm xtensa riscv
|
||||
integration_platforms:
|
||||
- qemu_xtensa/dc233c # Xtensa ISA
|
||||
filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE
|
||||
extra_configs:
|
||||
- arch:arm:CONFIG_ARM_MPU=n
|
||||
- arch:arm:CONFIG_ARM_AARCH32_MMU=n
|
||||
- arch:riscv:CONFIG_RISCV_PMP=n
|
||||
- CONFIG_LLEXT_STORAGE_WRITABLE=y
|
||||
llext.simple.writable_relocatable:
|
||||
arch_allow: arm xtensa
|
||||
arch_allow: arm xtensa riscv
|
||||
integration_platforms:
|
||||
- qemu_xtensa/dc233c # Xtensa ISA
|
||||
filter: not CONFIG_MPU and not CONFIG_MMU
|
||||
extra_configs:
|
||||
- arch:arm:CONFIG_ARM_MPU=n
|
||||
- arch:arm:CONFIG_ARM_AARCH32_MMU=n
|
||||
- arch:riscv:CONFIG_RISCV_PMP=n
|
||||
- CONFIG_LLEXT_STORAGE_WRITABLE=y
|
||||
- CONFIG_LLEXT_TYPE_ELF_RELOCATABLE=y
|
||||
|
||||
# Test the Symbol Link Identifier (SLID) linking feature on writable
|
||||
# storage to cover both ARM and Xtensa architectures on the same test.
|
||||
llext.simple.writable_slid_linking:
|
||||
arch_allow: arm xtensa
|
||||
arch_allow: arm xtensa riscv
|
||||
integration_platforms:
|
||||
- qemu_xtensa/dc233c # Xtensa ISA
|
||||
filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE
|
||||
extra_configs:
|
||||
- arch:arm:CONFIG_ARM_MPU=n
|
||||
- arch:arm:CONFIG_ARM_AARCH32_MMU=n
|
||||
- arch:riscv:CONFIG_RISCV_PMP=n
|
||||
- CONFIG_LLEXT_STORAGE_WRITABLE=y
|
||||
- CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID=y
|
||||
llext.simple.writable_relocatable_slid_linking:
|
||||
arch_allow: arm xtensa
|
||||
arch_allow: arm xtensa riscv
|
||||
integration_platforms:
|
||||
- qemu_xtensa/dc233c # Xtensa ISA
|
||||
filter: not CONFIG_MPU and not CONFIG_MMU
|
||||
extra_configs:
|
||||
- arch:arm:CONFIG_ARM_MPU=n
|
||||
- arch:arm:CONFIG_ARM_AARCH32_MMU=n
|
||||
- arch:riscv:CONFIG_RISCV_PMP=n
|
||||
- CONFIG_LLEXT_STORAGE_WRITABLE=y
|
||||
- CONFIG_LLEXT_TYPE_ELF_RELOCATABLE=y
|
||||
- CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID=y
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue