tools/testing/selftests/kvm/arm64/debug-exceptions.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/arm64/debug-exceptions.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/arm64/debug-exceptions.c
Extension
.c
Size
14794 bytes
Lines
606
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

if (run->exit_reason != KVM_EXIT_DEBUG) {
			cmd = get_ucall(vcpu, &uc);
			if (cmd == UCALL_ABORT) {
				REPORT_GUEST_ASSERT(uc);
				/* NOT REACHED */
			} else if (cmd == UCALL_DONE) {
				break;
			}

			TEST_ASSERT(cmd == UCALL_NONE,
				    "Unexpected ucall cmd 0x%lx", cmd);

			debug.control = KVM_GUESTDBG_ENABLE |
					KVM_GUESTDBG_SINGLESTEP;
			ss_enable = true;
			vcpu_guest_debug_set(vcpu, &debug);
			continue;
		}

		TEST_ASSERT(ss_enable, "Unexpected KVM_EXIT_DEBUG");

		/* Check if the current pc is expected. */
		pc = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc));
		TEST_ASSERT(!test_pc || pc == test_pc,
			    "Unexpected pc 0x%lx (expected 0x%lx)",
			    pc, test_pc);

		if ((pc + 4) == (u64)&iter_ss_end) {
			test_pc = 0;
			debug.control = KVM_GUESTDBG_ENABLE;
			ss_enable = false;
			vcpu_guest_debug_set(vcpu, &debug);
			continue;
		}

		/*
		 * If the current pc is between iter_ss_bgin and
		 * iter_ss_end, the pc for the next KVM_EXIT_DEBUG should
		 * be the current pc + 4.
		 */
		if ((pc >= (u64)&iter_ss_begin) &&
		    (pc < (u64)&iter_ss_end))
			test_pc = pc + 4;
		else
			test_pc = 0;
	}

	kvm_vm_free(vm);
}

/*
 * Run debug testing using the various breakpoint#, watchpoint# and
 * context-aware breakpoint# with the given ID_AA64DFR0_EL1 configuration.
 */
void test_guest_debug_exceptions_all(u64 aa64dfr0)
{
	u8 brp_num, wrp_num, ctx_brp_num, normal_brp_num, ctx_brp_base;
	int b, w, c;

	/* Number of breakpoints */
	brp_num = FIELD_GET(ID_AA64DFR0_EL1_BRPs, aa64dfr0) + 1;
	__TEST_REQUIRE(brp_num >= 2, "At least two breakpoints are required");

	/* Number of watchpoints */
	wrp_num = FIELD_GET(ID_AA64DFR0_EL1_WRPs, aa64dfr0) + 1;

	/* Number of context aware breakpoints */
	ctx_brp_num = FIELD_GET(ID_AA64DFR0_EL1_CTX_CMPs, aa64dfr0) + 1;

	pr_debug("%s brp_num:%d, wrp_num:%d, ctx_brp_num:%d\n", __func__,
		 brp_num, wrp_num, ctx_brp_num);

	/* Number of normal (non-context aware) breakpoints */
	normal_brp_num = brp_num - ctx_brp_num;

	/* Lowest context aware breakpoint number */
	ctx_brp_base = normal_brp_num;

	/* Run tests with all supported breakpoints/watchpoints */
	for (c = ctx_brp_base; c < ctx_brp_base + ctx_brp_num; c++) {
		for (b = 0; b < normal_brp_num; b++) {
			for (w = 0; w < wrp_num; w++)
				test_guest_debug_exceptions(b, w, c);
		}
	}
}

static void help(char *name)
{
	puts("");

Annotation

Implementation Notes