Commit 0eb4ef88 authored by Johan Almbladh's avatar Johan Almbladh Committed by Daniel Borkmann
Browse files

bpf, tests: Add more LD_IMM64 tests



This patch adds new tests for the two-instruction LD_IMM64. The new tests
verify the operation with immediate values of different byte patterns.
Mainly intended to cover JITs that want to be clever when loading 64-bit
constants.

Signed-off-by: default avatarJohan Almbladh <johan.almbladh@anyfinetworks.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20211007143006.634308-1-johan.almbladh@anyfinetworks.com
parent bbf731b3
Loading
Loading
Loading
Loading
+117 −3
Original line number Diff line number Diff line
@@ -2134,7 +2134,7 @@ static int bpf_fill_atomic32_cmpxchg_reg_pairs(struct bpf_test *self)
 * of the immediate value. This is often the case if the native instruction
 * immediate field width is narrower than 32 bits.
 */
static int bpf_fill_ld_imm64(struct bpf_test *self)
static int bpf_fill_ld_imm64_magn(struct bpf_test *self)
{
	int block = 64; /* Increase for more tests per MSB position */
	int len = 3 + 8 * 63 * block * 2;
@@ -2180,6 +2180,88 @@ static int bpf_fill_ld_imm64(struct bpf_test *self)
	return 0;
}

/*
 * Test the two-instruction 64-bit immediate load operation for different
 * combinations of bytes. Each byte in the 64-bit word is constructed as
 * (base & mask) | (rand() & ~mask), where rand() is a deterministic LCG.
 * All patterns (base1, mask1) and (base2, mask2) bytes are tested.
 */
static int __bpf_fill_ld_imm64_bytes(struct bpf_test *self,
				     u8 base1, u8 mask1,
				     u8 base2, u8 mask2)
{
	struct bpf_insn *insn;
	int len = 3 + 8 * BIT(8);
	int pattern, index;
	u32 rand = 1;
	int i = 0;

	insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
	if (!insn)
		return -ENOMEM;

	insn[i++] = BPF_ALU64_IMM(BPF_MOV, R0, 0);

	for (pattern = 0; pattern < BIT(8); pattern++) {
		u64 imm = 0;

		for (index = 0; index < 8; index++) {
			int byte;

			if (pattern & BIT(index))
				byte = (base1 & mask1) | (rand & ~mask1);
			else
				byte = (base2 & mask2) | (rand & ~mask2);
			imm = (imm << 8) | byte;
		}

		/* Update our LCG */
		rand = rand * 1664525 + 1013904223;

		/* Perform operation */
		i += __bpf_ld_imm64(&insn[i], R1, imm);

		/* Load reference */
		insn[i++] = BPF_ALU32_IMM(BPF_MOV, R2, imm);
		insn[i++] = BPF_ALU32_IMM(BPF_MOV, R3, (u32)(imm >> 32));
		insn[i++] = BPF_ALU64_IMM(BPF_LSH, R3, 32);
		insn[i++] = BPF_ALU64_REG(BPF_OR, R2, R3);

		/* Check result */
		insn[i++] = BPF_JMP_REG(BPF_JEQ, R1, R2, 1);
		insn[i++] = BPF_EXIT_INSN();
	}

	insn[i++] = BPF_ALU64_IMM(BPF_MOV, R0, 1);
	insn[i++] = BPF_EXIT_INSN();

	self->u.ptr.insns = insn;
	self->u.ptr.len = len;
	BUG_ON(i != len);

	return 0;
}

static int bpf_fill_ld_imm64_checker(struct bpf_test *self)
{
	return __bpf_fill_ld_imm64_bytes(self, 0, 0xff, 0xff, 0xff);
}

static int bpf_fill_ld_imm64_pos_neg(struct bpf_test *self)
{
	return __bpf_fill_ld_imm64_bytes(self, 1, 0x81, 0x80, 0x80);
}

static int bpf_fill_ld_imm64_pos_zero(struct bpf_test *self)
{
	return __bpf_fill_ld_imm64_bytes(self, 1, 0x81, 0, 0xff);
}

static int bpf_fill_ld_imm64_neg_zero(struct bpf_test *self)
{
	return __bpf_fill_ld_imm64_bytes(self, 0x80, 0x80, 0, 0xff);
}

/*
 * Exhaustive tests of JMP operations for all combinations of power-of-two
 * magnitudes of the operands, both for positive and negative values. The
@@ -12401,14 +12483,46 @@ static struct bpf_test tests[] = {
		.fill_helper = bpf_fill_alu32_mod_reg,
		.nr_testruns = NR_PATTERN_RUNS,
	},
	/* LD_IMM64 immediate magnitudes */
	/* LD_IMM64 immediate magnitudes and byte patterns */
	{
		"LD_IMM64: all immediate value magnitudes",
		{ },
		INTERNAL | FLAG_NO_DATA,
		{ },
		{ { 0, 1 } },
		.fill_helper = bpf_fill_ld_imm64,
		.fill_helper = bpf_fill_ld_imm64_magn,
	},
	{
		"LD_IMM64: checker byte patterns",
		{ },
		INTERNAL | FLAG_NO_DATA,
		{ },
		{ { 0, 1 } },
		.fill_helper = bpf_fill_ld_imm64_checker,
	},
	{
		"LD_IMM64: random positive and zero byte patterns",
		{ },
		INTERNAL | FLAG_NO_DATA,
		{ },
		{ { 0, 1 } },
		.fill_helper = bpf_fill_ld_imm64_pos_zero,
	},
	{
		"LD_IMM64: random negative and zero byte patterns",
		{ },
		INTERNAL | FLAG_NO_DATA,
		{ },
		{ { 0, 1 } },
		.fill_helper = bpf_fill_ld_imm64_neg_zero,
	},
	{
		"LD_IMM64: random positive and negative byte patterns",
		{ },
		INTERNAL | FLAG_NO_DATA,
		{ },
		{ { 0, 1 } },
		.fill_helper = bpf_fill_ld_imm64_pos_neg,
	},
	/* 64-bit ATOMIC register combinations */
	{