1

Merge remote-tracking branch 'palmer/fixes' into for-next

I don't usually merge these in, but I missed sending a PR due to the
holidays.

* palmer/fixes:
  riscv: Fix set_direct_map_default_noflush() to reset _PAGE_EXEC
  riscv: Fix module_alloc() that did not reset the linear mapping permissions
  riscv: Fix wrong usage of lm_alias() when splitting a huge linear mapping
  riscv: Check if the code to patch lies in the exit section
  riscv: errata: andes: Probe for IOCP only once in boot stage
  riscv: Fix SMP when shadow call stacks are enabled
  dt-bindings: perf: riscv,pmu: drop unneeded quotes
  riscv: fix misaligned access handling of C.SWSP and C.SDSP
  RISC-V: hwprobe: Always use u64 for extension bits
  Support rv32 ULEB128 test
  riscv: Correct type casting in module loading
  riscv: Safely remove entries from relocation list

Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
This commit is contained in:
Palmer Dabbelt 2024-01-09 20:10:32 -08:00
commit 5c89186a32
No known key found for this signature in database
GPG Key ID: 2E1319F35FBB1889
11 changed files with 130 additions and 52 deletions

View File

@ -90,7 +90,7 @@ properties:
bitmap of all MHPMCOUNTERx that can monitor the range of events
dependencies:
"riscv,event-to-mhpmevent": [ "riscv,event-to-mhpmcounters" ]
riscv,event-to-mhpmevent: [ "riscv,event-to-mhpmcounters" ]
required:
- compatible

View File

@ -38,29 +38,35 @@ static long ax45mp_iocp_sw_workaround(void)
return ret.error ? 0 : ret.value;
}
static bool errata_probe_iocp(unsigned int stage, unsigned long arch_id, unsigned long impid)
static void errata_probe_iocp(unsigned int stage, unsigned long arch_id, unsigned long impid)
{
static bool done;
if (!IS_ENABLED(CONFIG_ERRATA_ANDES_CMO))
return false;
return;
if (done)
return;
done = true;
if (arch_id != ANDESTECH_AX45MP_MARCHID || impid != ANDESTECH_AX45MP_MIMPID)
return false;
return;
if (!ax45mp_iocp_sw_workaround())
return false;
return;
/* Set this just to make core cbo code happy */
riscv_cbom_block_size = 1;
riscv_noncoherent_supported();
return true;
}
void __init_or_module andes_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid,
unsigned int stage)
{
errata_probe_iocp(stage, archid, impid);
if (stage == RISCV_ALTERNATIVES_BOOT)
errata_probe_iocp(stage, archid, impid);
/* we have nothing to patch here ATM so just return back */
}

View File

@ -13,6 +13,7 @@ extern char _start_kernel[];
extern char __init_data_begin[], __init_data_end[];
extern char __init_text_begin[], __init_text_end[];
extern char __alt_start[], __alt_end[];
extern char __exittext_begin[], __exittext_end[];
static inline bool is_va_kernel_text(uintptr_t va)
{

View File

@ -153,7 +153,6 @@ secondary_start_sbi:
XIP_FIXUP_OFFSET a3
add a3, a3, a1
REG_L sp, (a3)
scs_load_current
.Lsecondary_start_common:
@ -164,6 +163,7 @@ secondary_start_sbi:
call relocate_enable_mmu
#endif
call .Lsetup_trap_vector
scs_load_current
tail smp_callin
#endif /* CONFIG_SMP */

View File

@ -40,15 +40,6 @@ struct relocation_handlers {
long buffer);
};
unsigned int initialize_relocation_hashtable(unsigned int num_relocations);
void process_accumulated_relocations(struct module *me);
int add_relocation_to_accumulate(struct module *me, int type, void *location,
unsigned int hashtable_bits, Elf_Addr v);
struct hlist_head *relocation_hashtable;
struct list_head used_buckets_list;
/*
* The auipc+jalr instruction pair can reach any PC-relative offset
* in the range [-2^31 - 2^11, 2^31 - 2^11)
@ -64,7 +55,7 @@ static bool riscv_insn_valid_32bit_offset(ptrdiff_t val)
static int riscv_insn_rmw(void *location, u32 keep, u32 set)
{
u16 *parcel = location;
__le16 *parcel = location;
u32 insn = (u32)le16_to_cpu(parcel[0]) | (u32)le16_to_cpu(parcel[1]) << 16;
insn &= keep;
@ -77,7 +68,7 @@ static int riscv_insn_rmw(void *location, u32 keep, u32 set)
static int riscv_insn_rvc_rmw(void *location, u16 keep, u16 set)
{
u16 *parcel = location;
__le16 *parcel = location;
u16 insn = le16_to_cpu(*parcel);
insn &= keep;
@ -604,7 +595,10 @@ static const struct relocation_handlers reloc_handlers[] = {
/* 192-255 nonstandard ABI extensions */
};
void process_accumulated_relocations(struct module *me)
static void
process_accumulated_relocations(struct module *me,
struct hlist_head **relocation_hashtable,
struct list_head *used_buckets_list)
{
/*
* Only ADD/SUB/SET/ULEB128 should end up here.
@ -624,18 +618,25 @@ void process_accumulated_relocations(struct module *me)
* - Each relocation entry for a location address
*/
struct used_bucket *bucket_iter;
struct used_bucket *bucket_iter_tmp;
struct relocation_head *rel_head_iter;
struct hlist_node *rel_head_iter_tmp;
struct relocation_entry *rel_entry_iter;
struct relocation_entry *rel_entry_iter_tmp;
int curr_type;
void *location;
long buffer;
list_for_each_entry(bucket_iter, &used_buckets_list, head) {
hlist_for_each_entry(rel_head_iter, bucket_iter->bucket, node) {
list_for_each_entry_safe(bucket_iter, bucket_iter_tmp,
used_buckets_list, head) {
hlist_for_each_entry_safe(rel_head_iter, rel_head_iter_tmp,
bucket_iter->bucket, node) {
buffer = 0;
location = rel_head_iter->location;
list_for_each_entry(rel_entry_iter,
rel_head_iter->rel_entry, head) {
list_for_each_entry_safe(rel_entry_iter,
rel_entry_iter_tmp,
rel_head_iter->rel_entry,
head) {
curr_type = rel_entry_iter->type;
reloc_handlers[curr_type].reloc_handler(
me, &buffer, rel_entry_iter->value);
@ -648,11 +649,14 @@ void process_accumulated_relocations(struct module *me)
kfree(bucket_iter);
}
kfree(relocation_hashtable);
kfree(*relocation_hashtable);
}
int add_relocation_to_accumulate(struct module *me, int type, void *location,
unsigned int hashtable_bits, Elf_Addr v)
static int add_relocation_to_accumulate(struct module *me, int type,
void *location,
unsigned int hashtable_bits, Elf_Addr v,
struct hlist_head *relocation_hashtable,
struct list_head *used_buckets_list)
{
struct relocation_entry *entry;
struct relocation_head *rel_head;
@ -661,6 +665,10 @@ int add_relocation_to_accumulate(struct module *me, int type, void *location,
unsigned long hash;
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
INIT_LIST_HEAD(&entry->head);
entry->type = type;
entry->value = v;
@ -669,7 +677,10 @@ int add_relocation_to_accumulate(struct module *me, int type, void *location,
current_head = &relocation_hashtable[hash];
/* Find matching location (if any) */
/*
* Search for the relocation_head for the relocations that happen at the
* provided location
*/
bool found = false;
struct relocation_head *rel_head_iter;
@ -681,19 +692,45 @@ int add_relocation_to_accumulate(struct module *me, int type, void *location,
}
}
/*
* If there has not yet been any relocations at the provided location,
* create a relocation_head for that location and populate it with this
* relocation_entry.
*/
if (!found) {
rel_head = kmalloc(sizeof(*rel_head), GFP_KERNEL);
if (!rel_head) {
kfree(entry);
return -ENOMEM;
}
rel_head->rel_entry =
kmalloc(sizeof(struct list_head), GFP_KERNEL);
if (!rel_head->rel_entry) {
kfree(entry);
kfree(rel_head);
return -ENOMEM;
}
INIT_LIST_HEAD(rel_head->rel_entry);
rel_head->location = location;
INIT_HLIST_NODE(&rel_head->node);
if (!current_head->first) {
bucket =
kmalloc(sizeof(struct used_bucket), GFP_KERNEL);
if (!bucket) {
kfree(entry);
kfree(rel_head);
kfree(rel_head->rel_entry);
return -ENOMEM;
}
INIT_LIST_HEAD(&bucket->head);
bucket->bucket = current_head;
list_add(&bucket->head, &used_buckets_list);
list_add(&bucket->head, used_buckets_list);
}
hlist_add_head(&rel_head->node, current_head);
}
@ -704,7 +741,9 @@ int add_relocation_to_accumulate(struct module *me, int type, void *location,
return 0;
}
unsigned int initialize_relocation_hashtable(unsigned int num_relocations)
static unsigned int
initialize_relocation_hashtable(unsigned int num_relocations,
struct hlist_head **relocation_hashtable)
{
/* Can safely assume that bits is not greater than sizeof(long) */
unsigned long hashtable_size = roundup_pow_of_two(num_relocations);
@ -720,12 +759,13 @@ unsigned int initialize_relocation_hashtable(unsigned int num_relocations)
hashtable_size <<= should_double_size;
relocation_hashtable = kmalloc_array(hashtable_size,
sizeof(*relocation_hashtable),
GFP_KERNEL);
__hash_init(relocation_hashtable, hashtable_size);
*relocation_hashtable = kmalloc_array(hashtable_size,
sizeof(*relocation_hashtable),
GFP_KERNEL);
if (!*relocation_hashtable)
return -ENOMEM;
INIT_LIST_HEAD(&used_buckets_list);
__hash_init(*relocation_hashtable, hashtable_size);
return hashtable_bits;
}
@ -742,7 +782,17 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
Elf_Addr v;
int res;
unsigned int num_relocations = sechdrs[relsec].sh_size / sizeof(*rel);
unsigned int hashtable_bits = initialize_relocation_hashtable(num_relocations);
struct hlist_head *relocation_hashtable;
struct list_head used_buckets_list;
unsigned int hashtable_bits;
hashtable_bits = initialize_relocation_hashtable(num_relocations,
&relocation_hashtable);
if (hashtable_bits < 0)
return hashtable_bits;
INIT_LIST_HEAD(&used_buckets_list);
pr_debug("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
@ -823,14 +873,18 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
}
if (reloc_handlers[type].accumulate_handler)
res = add_relocation_to_accumulate(me, type, location, hashtable_bits, v);
res = add_relocation_to_accumulate(me, type, location,
hashtable_bits, v,
relocation_hashtable,
&used_buckets_list);
else
res = handler(me, location, v);
if (res)
return res;
}
process_accumulated_relocations(me);
process_accumulated_relocations(me, &relocation_hashtable,
&used_buckets_list);
return 0;
}
@ -840,7 +894,8 @@ void *module_alloc(unsigned long size)
{
return __vmalloc_node_range(size, 1, MODULES_VADDR,
MODULES_END, GFP_KERNEL,
PAGE_KERNEL, 0, NUMA_NO_NODE,
PAGE_KERNEL, VM_FLUSH_RESET_PERMS,
NUMA_NO_NODE,
__builtin_return_address(0));
}
#endif

View File

@ -14,6 +14,7 @@
#include <asm/fixmap.h>
#include <asm/ftrace.h>
#include <asm/patch.h>
#include <asm/sections.h>
struct patch_insn {
void *addr;
@ -25,6 +26,14 @@ struct patch_insn {
int riscv_patch_in_stop_machine = false;
#ifdef CONFIG_MMU
static inline bool is_kernel_exittext(uintptr_t addr)
{
return system_state < SYSTEM_RUNNING &&
addr >= (uintptr_t)__exittext_begin &&
addr < (uintptr_t)__exittext_end;
}
/*
* The fix_to_virt(, idx) needs a const value (not a dynamic variable of
* reg-a0) or BUILD_BUG_ON failed with "idx >= __end_of_fixed_addresses".
@ -35,7 +44,7 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
uintptr_t uintaddr = (uintptr_t) addr;
struct page *page;
if (core_kernel_text(uintaddr))
if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr))
page = phys_to_page(__pa_symbol(addr));
else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
page = vmalloc_to_page(addr);

View File

@ -6,13 +6,13 @@
.text
.global test_uleb_basic
test_uleb_basic:
ld a0, second
lw a0, second
addi a0, a0, -127
ret
.global test_uleb_large
test_uleb_large:
ld a0, fourth
lw a0, fourth
addi a0, a0, -0x07e8
ret
@ -22,10 +22,10 @@ first:
second:
.reloc second, R_RISCV_SET_ULEB128, second
.reloc second, R_RISCV_SUB_ULEB128, first
.dword 0
.word 0
third:
.space 1000
fourth:
.reloc fourth, R_RISCV_SET_ULEB128, fourth
.reloc fourth, R_RISCV_SUB_ULEB128, third
.dword 0
.word 0

View File

@ -550,16 +550,14 @@ int handle_misaligned_store(struct pt_regs *regs)
} else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
len = 8;
val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
((insn >> SH_RD) & 0x1f)) {
} else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP) {
len = 8;
val.data_ulong = GET_RS2C(insn, regs);
#endif
} else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
len = 4;
val.data_ulong = GET_RS2S(insn, regs);
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
((insn >> SH_RD) & 0x1f)) {
} else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP) {
len = 4;
val.data_ulong = GET_RS2C(insn, regs);
} else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {

View File

@ -29,10 +29,12 @@ SECTIONS
HEAD_TEXT_SECTION
INIT_TEXT_SECTION(PAGE_SIZE)
/* we have to discard exit text and such at runtime, not link time */
__exittext_begin = .;
.exit.text :
{
EXIT_TEXT
}
__exittext_end = .;
.text : {
_text = .;

View File

@ -69,10 +69,12 @@ SECTIONS
__soc_builtin_dtb_table_end = .;
}
/* we have to discard exit text and such at runtime, not link time */
__exittext_begin = .;
.exit.text :
{
EXIT_TEXT
}
__exittext_end = .;
__init_text_end = .;
. = ALIGN(SECTION_ALIGN);

View File

@ -305,8 +305,13 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
goto unlock;
}
} else if (is_kernel_mapping(start) || is_linear_mapping(start)) {
lm_start = (unsigned long)lm_alias(start);
lm_end = (unsigned long)lm_alias(end);
if (is_kernel_mapping(start)) {
lm_start = (unsigned long)lm_alias(start);
lm_end = (unsigned long)lm_alias(end);
} else {
lm_start = start;
lm_end = end;
}
ret = split_linear_mapping(lm_start, lm_end);
if (ret)
@ -378,7 +383,7 @@ int set_direct_map_invalid_noflush(struct page *page)
int set_direct_map_default_noflush(struct page *page)
{
return __set_memory((unsigned long)page_address(page), 1,
PAGE_KERNEL, __pgprot(0));
PAGE_KERNEL, __pgprot(_PAGE_EXEC));
}
#ifdef CONFIG_DEBUG_PAGEALLOC