arch/powerpc/kernel/module_64.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kernel/module_64.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kernel/module_64.c
Extension
.c
Size
32241 bytes
Lines
1163
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration 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 ppc64_stub_entry {
	/*
	 * 28 byte jump instruction sequence (7 instructions) that can
	 * hold ppc64_stub_insns or stub_insns. Must be 8-byte aligned
	 * with PCREL kernels that use prefix instructions in the stub.
	 */
	u32 jump[7];
	/* Used by ftrace to identify stubs */
	u32 magic;
	/* Data for the above code */
	func_desc_t funcdata;
} __aligned(8);

struct ppc64_got_entry {
	u64 addr;
};

/*
 * PPC64 uses 24 bit jumps, but we need to jump into other modules or
 * the kernel which may be further.  So we jump to a stub.
 *
 * Target address and TOC are loaded from function descriptor in the
 * ppc64_stub_entry.
 *
 * r12 is used to generate the target address, which is required for the
 * ELFv2 global entry point calling convention.
 *
 * TOC handling:
 * - PCREL does not have a TOC.
 * - ELFv2 non-PCREL just has to save r2, the callee is responsible for
 *   setting its own TOC pointer at the global entry address.
 * - ELFv1 must load the new TOC pointer from the function descriptor.
 */
static u32 ppc64_stub_insns[] = {
#ifdef CONFIG_PPC_KERNEL_PCREL
	/* pld r12,addr */
	PPC_PREFIX_8LS | __PPC_PRFX_R(1),
	PPC_INST_PLD | ___PPC_RT(_R12),
#else
	PPC_RAW_ADDIS(_R11, _R2, 0),
	PPC_RAW_ADDI(_R11, _R11, 0),
	/* Save current r2 value in magic place on the stack. */
	PPC_RAW_STD(_R2, _R1, R2_STACK_OFFSET),
	PPC_RAW_LD(_R12, _R11, 32),
#ifdef CONFIG_PPC64_ELF_ABI_V1
	/* Set up new r2 from function descriptor */
	PPC_RAW_LD(_R2, _R11, 40),
#endif
#endif
	PPC_RAW_MTCTR(_R12),
	PPC_RAW_BCTR(),
};

/*
 * Count how many different r_type relocations (different symbol,
 * different addend).
 */
static unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num,
				 unsigned long r_type)
{
	unsigned int i, r_info, r_addend, _count_relocs;

	/* FIXME: Only count external ones --RR */
	_count_relocs = 0;
	r_info = 0;
	r_addend = 0;
	for (i = 0; i < num; i++)
		/* Only count r_type relocs, others don't need stubs */
		if (ELF64_R_TYPE(rela[i].r_info) == r_type &&
		    (r_info != ELF64_R_SYM(rela[i].r_info) ||
		     r_addend != rela[i].r_addend)) {
			_count_relocs++;
			r_info = ELF64_R_SYM(rela[i].r_info);
			r_addend = rela[i].r_addend;
		}

	return _count_relocs;
}

static int relacmp(const void *_x, const void *_y)
{
	const Elf64_Rela *x, *y;

	y = (Elf64_Rela *)_x;
	x = (Elf64_Rela *)_y;

	/* Compare the entire r_info (as opposed to ELF64_R_SYM(r_info) only) to
	 * make the comparison cheaper/faster. It won't affect the sorting or
	 * the counting algorithms' performance
	 */

Annotation

Implementation Notes