arch/arm64/kernel/pi/patch-scs.c

Source file repositories/reference/linux-study-clean/arch/arm64/kernel/pi/patch-scs.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kernel/pi/patch-scs.c
Extension
.c
Size
7950 bytes
Lines
302
Domain
Architecture Layer
Bucket
arch/arm64
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 eh_frame {
	/*
	 * The size of this frame if 0 < size < U32_MAX, 0 terminates the list.
	 */
	u32	size;

	/*
	 * The first frame is a Common Information Entry (CIE) frame, followed
	 * by one or more Frame Description Entry (FDE) frames. In the former
	 * case, this field is 0, otherwise it is the negated offset relative
	 * to the associated CIE frame.
	 */
	u32	cie_id_or_pointer;

	union {
		struct { // CIE
			u8	version;
			u8	augmentation_string[3];
			u8	code_alignment_factor;
			u8	data_alignment_factor;
			u8	return_address_register;
			u8	augmentation_data_size;
			u8	fde_pointer_format;
		};

		struct { // FDE
			s32	initial_loc;
			s32	range;
			u8	opcodes[];
		};

		struct { // FDE
			s64	initial_loc64;
			s64	range64;
			u8	opcodes64[];
		};
	};
};

static int scs_handle_fde_frame(const struct eh_frame *frame,
				int code_alignment_factor,
				bool use_sdata8,
				bool dry_run)
{
	int size = frame->size - offsetof(struct eh_frame, opcodes) + 4;
	u64 loc = (u64)offset_to_ptr(&frame->initial_loc);
	const u8 *opcode = frame->opcodes;
	int l;

	if (use_sdata8) {
		loc = (u64)&frame->initial_loc64 + frame->initial_loc64;
		opcode = frame->opcodes64;
		size -= 8;
	}

	// assume single byte uleb128_t for augmentation data size
	if (*opcode & BIT(7))
		return EDYNSCS_INVALID_FDE_AUGM_DATA_SIZE;

	l = *opcode++;
	opcode += l;
	size -= l + 1;

	/*
	 * Starting from 'loc', apply the CFA opcodes that advance the location
	 * pointer, and identify the locations of the PAC instructions.
	 */
	while (size-- > 0) {
		switch (*opcode++) {
		case DW_CFA_nop:
		case DW_CFA_remember_state:
		case DW_CFA_restore_state:
			break;

		case DW_CFA_advance_loc1:
			loc += *opcode++ * code_alignment_factor;
			size--;
			break;

		case DW_CFA_advance_loc2:
			loc += *opcode++ * code_alignment_factor;
			loc += (*opcode++ << 8) * code_alignment_factor;
			size -= 2;
			break;

		case DW_CFA_advance_loc4:
			loc += *opcode++ * code_alignment_factor;
			loc += (*opcode++ << 8) * code_alignment_factor;
			loc += (*opcode++ << 16) * code_alignment_factor;
			loc += ((u64)*opcode++ << 24) * code_alignment_factor;

Annotation

Implementation Notes