Commit 4df7c5fd authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'riscv-for-linus-6.7-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux

Pull RISC-V fixes from Palmer Dabbelt:

 - A pair of fixes to the new module load-time relocation code

 - A fix for hwprobe overflowing on rv32

 - A fix for to correctly decode C.SWSP and C.SDSP, which manifests in
   misaligned access handling

 - A fix for a boot-time shadow call stack initialization ordering issue

 - A fix for Andes' errata probing, which was calling
   riscv_noncoherent_supported() too late in the boot process and
   triggering an oops

* tag 'riscv-for-linus-6.7-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
  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
parents a6adef89 ed5b7cfd
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+13 −7
Original line number Diff line number Diff line
@@ -38,28 +38,34 @@ 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)
{
	if (stage == RISCV_ALTERNATIVES_BOOT)
		errata_probe_iocp(stage, archid, impid);

	/* we have nothing to patch here ATM so just return back */
+1 −1
Original line number Diff line number Diff line
@@ -154,7 +154,6 @@ secondary_start_sbi:
	XIP_FIXUP_OFFSET a3
	add a3, a3, a1
	REG_L sp, (a3)
	scs_load_current

.Lsecondary_start_common:

@@ -165,6 +164,7 @@ secondary_start_sbi:
	call relocate_enable_mmu
#endif
	call .Lsetup_trap_vector
	scs_load_current
	tail smp_callin
#endif /* CONFIG_SMP */

+84 −30
Original line number Diff line number Diff line
@@ -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,
	*relocation_hashtable = kmalloc_array(hashtable_size,
					      sizeof(*relocation_hashtable),
					      GFP_KERNEL);
	__hash_init(relocation_hashtable, hashtable_size);
	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;
}
+1 −1
Original line number Diff line number Diff line
@@ -169,7 +169,7 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair,
	pair->value &= ~missing;
}

static bool hwprobe_ext0_has(const struct cpumask *cpus, unsigned long ext)
static bool hwprobe_ext0_has(const struct cpumask *cpus, u64 ext)
{
	struct riscv_hwprobe pair;

Loading