arch/riscv/kernel/module.c

Source file repositories/reference/linux-study-clean/arch/riscv/kernel/module.c

File Facts

System
Linux kernel
Corpus path
arch/riscv/kernel/module.c
Extension
.c
Size
25675 bytes
Lines
907
Domain
Architecture Layer
Bucket
arch/riscv
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 used_bucket {
	struct list_head head;
	struct hlist_head *bucket;
};

struct relocation_head {
	struct hlist_node node;
	struct list_head rel_entry;
	void *location;
};

struct relocation_entry {
	struct list_head head;
	Elf_Addr value;
	unsigned int type;
};

struct relocation_handlers {
	int (*reloc_handler)(struct module *me, void *location, Elf_Addr v);
	int (*accumulate_handler)(struct module *me, void *location,
				  long buffer);
};

/*
 * The auipc+jalr instruction pair can reach any PC-relative offset
 * in the range [-2^31 - 2^11, 2^31 - 2^11)
 */
static bool riscv_insn_valid_32bit_offset(ptrdiff_t val)
{
#ifdef CONFIG_32BIT
	return true;
#else
	return (-(1L << 31) - (1L << 11)) <= val && val < ((1L << 31) - (1L << 11));
#endif
}

static int riscv_insn_rmw(void *location, u32 keep, u32 set)
{
	__le16 *parcel = location;
	u32 insn = (u32)le16_to_cpu(parcel[0]) | (u32)le16_to_cpu(parcel[1]) << 16;

	insn &= keep;
	insn |= set;

	parcel[0] = cpu_to_le16(insn);
	parcel[1] = cpu_to_le16(insn >> 16);
	return 0;
}

static int riscv_insn_rvc_rmw(void *location, u16 keep, u16 set)
{
	__le16 *parcel = location;
	u16 insn = le16_to_cpu(*parcel);

	insn &= keep;
	insn |= set;

	*parcel = cpu_to_le16(insn);
	return 0;
}

static int apply_r_riscv_32_rela(struct module *me, void *location, Elf_Addr v)
{
	if (v != (u32)v) {
		pr_err("%s: value %016llx out of range for 32-bit field\n",
		       me->name, (long long)v);
		return -EINVAL;
	}
	*(u32 *)location = v;
	return 0;
}

static int apply_r_riscv_64_rela(struct module *me, void *location, Elf_Addr v)
{
	*(u64 *)location = v;
	return 0;
}

static int apply_r_riscv_branch_rela(struct module *me, void *location,
				     Elf_Addr v)
{
	ptrdiff_t offset = (void *)v - location;
	u32 imm12 = (offset & 0x1000) << (31 - 12);
	u32 imm11 = (offset & 0x800) >> (11 - 7);
	u32 imm10_5 = (offset & 0x7e0) << (30 - 10);
	u32 imm4_1 = (offset & 0x1e) << (11 - 4);

	return riscv_insn_rmw(location, 0x1fff07f, imm12 | imm11 | imm10_5 | imm4_1);
}

Annotation

Implementation Notes