arch/loongarch/kernel/inst.c

Source file repositories/reference/linux-study-clean/arch/loongarch/kernel/inst.c

File Facts

System
Linux kernel
Corpus path
arch/loongarch/kernel/inst.c
Extension
.c
Size
9818 bytes
Lines
444
Domain
Architecture Layer
Bucket
arch/loongarch
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct insn_copy {
	void *dst;
	void *src;
	size_t len;
	unsigned int cpu;
};

static int text_copy_cb(void *data)
{
	int ret = 0;
	struct insn_copy *copy = data;

	if (smp_processor_id() == copy->cpu) {
		ret = copy_to_kernel_nofault(copy->dst, copy->src, copy->len);
		if (ret) {
			pr_err("%s: operation failed\n", __func__);
			return ret;
		}
	}

	flush_icache_range((unsigned long)copy->dst, (unsigned long)copy->dst + copy->len);

	return 0;
}

int larch_insn_text_copy(void *dst, void *src, size_t len)
{
	int ret = 0;
	int err = 0;
	size_t start, end;
	struct insn_copy copy = {
		.dst = dst,
		.src = src,
		.len = len,
		.cpu = raw_smp_processor_id(),
	};

	/*
	 * Ensure copy.cpu won't be hot removed before stop_machine.
	 * If it is removed nobody will really update the text.
	 */
	lockdep_assert_cpus_held();

	start = round_down((size_t)dst, PAGE_SIZE);
	end   = round_up((size_t)dst + len, PAGE_SIZE);

	err = set_memory_rw(start, (end - start) / PAGE_SIZE);
	if (err) {
		pr_info("%s: set_memory_rw() failed\n", __func__);
		return err;
	}

	ret = stop_machine_cpuslocked(text_copy_cb, &copy, cpu_online_mask);

	err = set_memory_rox(start, (end - start) / PAGE_SIZE);
	if (err) {
		pr_info("%s: set_memory_rox() failed\n", __func__);
		return err;
	}

	return ret;
}

u32 larch_insn_gen_nop(void)
{
	return INSN_NOP;
}

u32 larch_insn_gen_b(unsigned long pc, unsigned long dest)
{
	long offset = dest - pc;
	union loongarch_instruction insn;

	if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
		pr_warn("The generated b instruction is out of range.\n");
		return INSN_BREAK;
	}

	emit_b(&insn, offset >> 2);

	return insn.word;
}

u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
{
	long offset = dest - pc;
	union loongarch_instruction insn;

	if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
		pr_warn("The generated bl instruction is out of range.\n");

Annotation

Implementation Notes