/* Setup a context-aware breakpoint for Linked Context ID Match */
ctx_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E |
DBGBCR_BT_CTX_LINK;
write_dbgbcr(ctx_bp, ctx_bcr);
write_dbgbvr(ctx_bp, ctx);
/* * Setup a normal breakpoint for Linked Address Match, and link it * to the context-aware breakpoint.
*/
addr_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E |
DBGBCR_BT_ADDR_LINK_CTX |
((uint32_t)ctx_bp << DBGBCR_LBN_SHIFT);
write_dbgbcr(addr_bp, addr_bcr);
write_dbgbvr(addr_bp, addr);
isb();
for (i = 0; i < test_cnt; i++) { /* Bits [1:0] of dbg{b,w}vr are RES0 */
w_bvr = i << 2;
w_wvr = i << 2;
/* * Enable Single Step execution. Note! This _must_ be a bare * ucall as the ucall() path uses atomic operations to manage * the ucall structures, and the built-in "atomics" are usually * implemented via exclusive access instructions. The exlusive * monitor is cleared on ERET, and so taking debug exceptions * during a LDREX=>STREX sequence will prevent forward progress * and hang the guest/test.
*/
GUEST_UCALL_NONE();
/* * The userspace will verify that the pc is as expected during * single step execution between iter_ss_begin and iter_ss_end.
*/ asmvolatile("iter_ss_begin:nop\n");
/* 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 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 >= (uint64_t)&iter_ss_begin) &&
(pc < (uint64_t)&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(uint64_t aa64dfr0)
{
uint8_t 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;
/* 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);
}
}
}
staticvoid help(char *name)
{
puts("");
printf("Usage: %s [-h] [-i iterations of the single step test]\n", name);
puts(""); exit(0);
}
int main(int argc, char *argv[])
{ struct kvm_vcpu *vcpu; struct kvm_vm *vm; int opt; int ss_iteration = 10000;
uint64_t aa64dfr0;
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
aa64dfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1));
__TEST_REQUIRE(debug_version(aa64dfr0) >= 6, "Armv8 debug architecture not supported.");
kvm_vm_free(vm);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.11Bemerkung:
(vorverarbeitet am 2026-06-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.