arch/parisc/net/bpf_jit_comp32.c

Source file repositories/reference/linux-study-clean/arch/parisc/net/bpf_jit_comp32.c

File Facts

System
Linux kernel
Corpus path
arch/parisc/net/bpf_jit_comp32.c
Extension
.c
Size
44841 bytes
Lines
1616
Domain
Architecture Layer
Bucket
arch/parisc
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

if (1 && !ctx->prog->aux->verifier_zext) {
			REG_SET_SEEN(ctx, hi(reg));
			emit(hppa_stw(HPPA_REG_ZERO, REG_SIZE * hi(reg), HPPA_REG_SP), ctx);
		}
	} else if (1 && !ctx->prog->aux->verifier_zext) {
		REG_SET_SEEN(ctx, hi(reg));
		emit_hppa_copy(HPPA_REG_ZERO, hi(reg), ctx);
	}
}

/* extern hppa millicode functions */
extern void $$mulI(void);
extern void $$divU(void);
extern void $$remU(void);

static void emit_call_millicode(void *func, const s8 arg0,
		const s8 arg1, u8 opcode, struct hppa_jit_context *ctx)
{
	u32 func_addr;

	emit_hppa_copy(arg0, HPPA_REG_ARG0, ctx);
	emit_hppa_copy(arg1, HPPA_REG_ARG1, ctx);

	/* libcgcc overwrites HPPA_REG_RET0/1, save temp. in dest. */
	if (arg0 != HPPA_REG_RET1)
		bpf_save_R0(ctx);

	func_addr = (uintptr_t) dereference_function_descriptor(func);
	emit(hppa_ldil(func_addr, HPPA_REG_R31), ctx);
	/* skip the following be_l instruction if divisor is zero. */
	if (BPF_OP(opcode) == BPF_DIV || BPF_OP(opcode) == BPF_MOD) {
		if (BPF_OP(opcode) == BPF_DIV)
			emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET1, ctx);
		else
			emit_hppa_copy(HPPA_REG_ARG0, HPPA_REG_RET1, ctx);
		emit(hppa_or_cond(HPPA_REG_ARG1, HPPA_REG_ZERO, 1, 0, HPPA_REG_ZERO), ctx);
	}
	/* Note: millicode functions use r31 as return pointer instead of rp */
	emit(hppa_be_l(im11(func_addr) >> 2, HPPA_REG_R31, NOP_NEXT_INSTR), ctx);
	emit(hppa_nop(), ctx); /* this nop is needed here for delay slot */

	/* Note: millicode functions return result in RET1, not RET0 */
	emit_hppa_copy(HPPA_REG_RET1, arg0, ctx);

	/* restore HPPA_REG_RET0/1, temp. save in dest. */
	if (arg0 != HPPA_REG_RET1)
		bpf_restore_R0(ctx);
}

static void emit_call_libgcc_ll(void *func, const s8 *arg0,
		const s8 *arg1, u8 opcode, struct hppa_jit_context *ctx)
{
	u32 func_addr;

	emit_hppa_copy(lo(arg0), HPPA_REG_ARG0, ctx);
	emit_hppa_copy(hi(arg0), HPPA_REG_ARG1, ctx);
	emit_hppa_copy(lo(arg1), HPPA_REG_ARG2, ctx);
	emit_hppa_copy(hi(arg1), HPPA_REG_ARG3, ctx);

	/* libcgcc overwrites HPPA_REG_RET0/_RET1, so keep copy of R0 on stack */
	if (hi(arg0) != HPPA_REG_RET0)
		bpf_save_R0(ctx);

	/* prepare stack */
	emit(hppa_ldo(2 * FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);

	func_addr = (uintptr_t) dereference_function_descriptor(func);
	emit(hppa_ldil(func_addr, HPPA_REG_R31), ctx);
        /* zero out the following be_l instruction if divisor is 0 (and set default values) */
	if (BPF_OP(opcode) == BPF_DIV || BPF_OP(opcode) == BPF_MOD) {
		emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET0, ctx);
		if (BPF_OP(opcode) == BPF_DIV)
			emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET1, ctx);
		else
			emit_hppa_copy(HPPA_REG_ARG0, HPPA_REG_RET1, ctx);
		emit(hppa_or_cond(HPPA_REG_ARG2, HPPA_REG_ARG3, 1, 0, HPPA_REG_ZERO), ctx);
	}
	emit(hppa_be_l(im11(func_addr) >> 2, HPPA_REG_R31, EXEC_NEXT_INSTR), ctx);
	emit_hppa_copy(HPPA_REG_R31, HPPA_REG_RP, ctx);

	/* restore stack */
	emit(hppa_ldo(-2 * FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);

	emit_hppa_copy(HPPA_REG_RET0, hi(arg0), ctx);
	emit_hppa_copy(HPPA_REG_RET1, lo(arg0), ctx);

	/* restore HPPA_REG_RET0/_RET1 */
	if (hi(arg0) != HPPA_REG_RET0)
		bpf_restore_R0(ctx);
}

Annotation

Implementation Notes