ARM64 hw watchpoint、breakpoint注冊與注銷


ARM64 hw watchpoint、breakpoint注冊與注銷

 write_wb_reg()里的switch macro展開

4.19\arch\arm64\kernel\Hw_breakpoint.c

static void write_wb_reg(int reg, int n, u64 val)
{

switch (reg + n) {

GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);

GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);

GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val);

GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val);

default:

pr_warning("attempt to write to unknown breakpoint register %d\n", n);

}

isb();

}

above switch expanding as below:

switch (reg + n) {

/* wvr(breakpoint value register) */

case (0): \

do {\

write_sysreg(val, dbgbvr0_el1);\

} while (0); \

break;

case (1): \

do {\

write_sysreg(val, dbgbvr1_el1);\

} while (0); \

break;

case (15): \

do {\

write_sysreg(val, dbgbvr15_el1);\

} while (0); \

break;

/* wvr(breakpoint ctrl register) */

case (16 + 0): \

do {\

write_sysreg(VAL, dbgbcr0_el1);\

} while (0); \

break

case (16 + 1): \

do {\

write_sysreg(VAL, dbgbcr1_el1);\

} while (0); \

break

case (16 + 15): \

do {\

write_sysreg(VAL, dbgbcr15_el1);\

} while (0); \

break

/* wvr(watchpoint value register) */

case (32 + 0): \

do {\

write_sysreg(VAL, dbgwvr0_el1);\

} while (0); \

break

case (32 + 1): \

do {\

write_sysreg(VAL, dbgwvr1_el1);\

} while (0); \

break

case (32 + 15): \

do {\

write_sysreg(VAL, dbgwvr15_el1);\

} while (0); \

break

/* wvr(watchpoint ctrl register) */

case (48 + 0): \

do {\

write_sysreg(VAL, dbgwcr0_el1);\

} while (0); \

break

case (48 + 1): \

do {\

write_sysreg(VAL, dbgwcr1_el1);\

} while (0); \

break

case (48 + 15): \

do {\

write_sysreg(VAL, dbgwcr15_el1);\

} while (0); \

break

}

 bvr/bcr/wvr/wcr寄存器分別為breakpoint value register/breakpoint ctrl register/watchpoint value register/watchpoint ctrl register

這些寄存器描述見下面鏈接:

https://developer.arm.com/documentation/ddi0500/e/debug/memory-mapped-register-summary

注冊watchpoint callstack

設置watchpoint、breakpoint需要設置CPU寄存器,設置寄存器是通過上述write_wb_reg()來設置的,它的示例設置callstack如下:

[   28.809660] CPU: 1 PID: 34 Comm: kworker/1:1 Tainted: P           O      4.19.116+ #49
[   28.817581] Hardware name: test_mach (DT)
[   28.821261] Workqueue: events watch_point_delayed_work_func
[   28.826841] Call trace:
[   28.829293]  dump_backtrace+0x0/0x4
[   28.832786]  dump_stack+0xf4/0x134
[   28.836192]  write_wb_reg+0x3c/0x284
[   28.839769]  hw_breakpoint_control+0x18c/0x264
[   28.844216]  hw_breakpoint_add+0x80/0x8c
[   28.848143]  event_sched_in+0x44c/0x718
[   28.851981]  group_sched_in+0x6c/0x218
[   28.855732]  pinned_sched_in+0x158/0x264
[   28.859656]  visit_groups_merge+0x140/0x1fc
[   28.863842]  ctx_sched_in+0x1a4/0x1ec
[   28.867507]  ctx_resched+0xdc/0x1e4
[   28.870998]  __perf_event_enable+0x1d0/0x2c4
[   28.875271]  event_function.9346+0x128/0x224
[   28.879543]  remote_function+0x74/0xb4
[   28.883297]  generic_exec_single+0x7c/0x1a4
[   28.887483]  smp_call_function_single+0xc0/0x1e8
[   28.892104]  event_function_call+0x84/0x274
[   28.896289]  perf_event_enable+0xec/0x158
[   28.900301]  _register_wp_bp+0x408/0x4b8
[   28.904228]  watch_point_delayed_work_func+0x68/0xcc
[   28.909197]  process_one_work+0x3c0/0x670
[   28.913210]  worker_thread+0x32c/0x6d0
[   28.916962]  kthread+0x130/0x140
[   28.920194]  ret_from_fork+0x10/0x18

 

 

arm64 CPU支持的watchpoint、breakpoint max num

4.19\arch\arm64\include\asm\Hw_breakpoint.h

/* Determine number of BRP registers available. */
static inline int get_num_brps(void)

{

u64 dfr0 = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);

return 1 +

cpuid_feature_extract_unsigned_field(dfr0,

ID_AA64DFR0_BRPS_SHIFT);

}

/* Determine number of WRP registers available. */

static inline int get_num_wrps(void)

{

u64 dfr0 = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);

return 1 +

cpuid_feature_extract_unsigned_field(dfr0,

ID_AA64DFR0_WRPS_SHIFT);

}

確定CPU支持的watchpoint、breakpoint max num: 

arch/arm64/kernel/hw_breakpoint.c

 

static int __init arch_hw_breakpoint_init(void)
{
    int ret;

    core_num_brps = get_num_brps();
    core_num_wrps = get_num_wrps();

    pr_info("found %d breakpoint and %d watchpoint registers.\n",
        core_num_brps, core_num_wrps);

 比如我這邊平台CPU支持的max watchpoint、breakpoint num分別為4、6:

[    1.399866] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.

 

以watchpoint為例,如果當前已經注冊了4個,如果再繼續注冊,則會注冊fail,返回-ENOSPC(-28)

arch/arm64/kernel/hw_breakpoint.c

static int hw_breakpoint_control(struct perf_event *bp,
                 enum hw_breakpoint_ops ops)
{
    struct arch_hw_breakpoint *info = counter_arch_bp(bp);
    struct perf_event **slots;
    struct debug_info *debug_info = &current->thread.debug;
    int i, max_slots, ctrl_reg, val_reg, reg_enable;
    enum dbg_active_el dbg_el = debug_exception_level(info->ctrl.privilege);
    u32 ctrl;

    if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
        /* Breakpoint */
        ctrl_reg = AARCH64_DBG_REG_BCR;
        val_reg = AARCH64_DBG_REG_BVR;
        slots = this_cpu_ptr(bp_on_reg);
        max_slots = core_num_brps;
        reg_enable = !debug_info->bps_disabled;
    } else {
        /* Watchpoint */
        ctrl_reg = AARCH64_DBG_REG_WCR;
        val_reg = AARCH64_DBG_REG_WVR;
        slots = this_cpu_ptr(wp_on_reg);
        max_slots = core_num_wrps;
        reg_enable = !debug_info->wps_disabled;
    }

    i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops);

 

static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
                    struct perf_event *bp,
                    enum hw_breakpoint_ops ops)
{
    int i;
    struct perf_event **slot;

    for (i = 0; i < max_slots; ++i) {
        slot = &slots[i];
        switch (ops) {
        case HW_BREAKPOINT_INSTALL:
            if (!*slot) {
                *slot = bp;
                return i;
            }
            break;
        case HW_BREAKPOINT_UNINSTALL:
            if (*slot == bp) {
                *slot = NULL;
                return i;
            }
            break;
        case HW_BREAKPOINT_RESTORE:
            if (*slot == bp)
                return i;
            break;
        default:
            pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
            return -EINVAL;
        }
    }
    return -ENOSPC;
}

 

注銷watch point callstack

注銷一個watchpoint callstack如下,call到hw_breakpoint_control()將ctrl reg設置為0,ops為HW_BREAKPOINT_UNINSTALL:

復制代碼
[   49.043918] hw-breakpoint: ops: 1, reg_enable: 1.
[   49.043925] CPU: 0 PID: 3237 Comm: mali-cmar-backe Tainted: P           O      4.19.116+ #19
[   49.043927] Hardware name: xxx_mach (DT)
[   49.043931] Call trace:
[   49.043942]  dump_backtrace+0x0/0x4
[   49.043949]  dump_stack+0xf4/0x134
[   49.043957]  hw_breakpoint_control+0x184/0x29c
[   49.043963]  hw_breakpoint_del+0x20/0x2c
[   49.043968]  event_sched_out+0xe0/0x344
[   49.043973]  __perf_remove_from_context+0xfc/0x16c
[   49.043977]  event_function.9234+0x128/0x224
[   49.043981]  remote_function+0x74/0xb4
[   49.043988]  generic_exec_single+0x7c/0x1a4
[   49.043992]  smp_call_function_single+0xc0/0x1e8
[   49.043996]  event_function_call+0x84/0x274
[   49.044000]  perf_event_release_kernel+0x1b8/0x794
[   49.044004]  unregister_wide_hw_breakpoint+0x90/0xf4
[   49.044010]  _unregister_wp_bp+0x10c/0x198
[   49.044016]  exit_files+0x1a0/0x1d8
[   49.044020]  do_exit+0x8ec/0x1420
[   49.044024]  do_group_exit+0x0/0x160
[   49.044027]  __se_sys_exit+0x0/0x20
[   49.044031]  el0_svc_common+0xb8/0x1b8
[   49.044035]  el0_svc_handler+0x74/0x90
[   49.044040]  el0_svc+0x8/0x340
復制代碼

 

 4.19\arch\arm64\kernel\Hw_breakpoint.c

復制代碼

static int hw_breakpoint_control(struct perf_event *bp,
enum hw_breakpoint_ops ops)

case HW_BREAKPOINT_UNINSTALL:
        /* Reset the control register. */
        write_wb_reg(ctrl_reg, i, 0);

        /*
         * Release the debug monitors for the correct exception
         * level.
         */
        disable_debug_monitors(dbg_el);
        break;
復制代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM