#define DBGBCR_EXEC    (0x0 << 3)
 #define DBGBCR_EL1     (0x1 << 1)
 #define DBGBCR_E       (0x1 << 0)
+#define DBGBCR_LBN_SHIFT       16
+#define DBGBCR_BT_SHIFT                20
+#define DBGBCR_BT_ADDR_LINK_CTX        (0x1 << DBGBCR_BT_SHIFT)
+#define DBGBCR_BT_CTX_LINK     (0x3 << DBGBCR_BT_SHIFT)
 
 #define DBGWCR_LEN8    (0xff << 5)
 #define DBGWCR_RD      (0x1 << 3)
 #define SPSR_D         (1 << 9)
 #define SPSR_SS                (1 << 21)
 
-extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start;
+extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start, hw_bp_ctx;
 extern unsigned char iter_ss_begin, iter_ss_end;
 static volatile uint64_t sw_bp_addr, hw_bp_addr;
 static volatile uint64_t wp_addr, wp_data_addr;
        isb();
 
        write_sysreg(0, mdscr_el1);
+       write_sysreg(0, contextidr_el1);
 
        /* Reset all bcr/bvr/wcr/wvr registers */
        dfr0 = read_sysreg(id_aa64dfr0_el1);
        enable_monitor_debug_exceptions();
 }
 
+void install_hw_bp_ctx(uint8_t addr_bp, uint8_t ctx_bp, uint64_t addr,
+                      uint64_t ctx)
+{
+       uint32_t addr_bcr, ctx_bcr;
+
+       /* 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();
+
+       enable_monitor_debug_exceptions();
+}
+
 static void install_ss(void)
 {
        uint32_t mdscr;
 
 static volatile char write_data;
 
-static void guest_code(uint8_t bpn, uint8_t wpn)
+static void guest_code(uint8_t bpn, uint8_t wpn, uint8_t ctx_bpn)
 {
+       uint64_t ctx = 0xabcdef;        /* a random context number */
+
        /* Software-breakpoint */
        reset_debug_state();
        asm volatile("sw_bp: brk #0");
                     : : : "x0");
        GUEST_ASSERT_EQ(ss_addr[0], 0);
 
+       /* Linked hardware-breakpoint */
+       hw_bp_addr = 0;
+       reset_debug_state();
+       install_hw_bp_ctx(bpn, ctx_bpn, PC(hw_bp_ctx), ctx);
+       /* Set context id */
+       write_sysreg(ctx, contextidr_el1);
+       isb();
+       asm volatile("hw_bp_ctx: nop");
+       write_sysreg(0, contextidr_el1);
+       GUEST_ASSERT_EQ(hw_bp_addr, PC(hw_bp_ctx));
+
        GUEST_DONE();
 }
 
        return FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER), id_aa64dfr0);
 }
 
-static void test_guest_debug_exceptions(void)
+static void test_guest_debug_exceptions(uint64_t aa64dfr0)
 {
        struct kvm_vcpu *vcpu;
        struct kvm_vm *vm;
        struct ucall uc;
+       uint8_t brp_num;
 
        vm = vm_create_with_one_vcpu(&vcpu, guest_code);
        ucall_init(vm, NULL);
        vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
                                ESR_EC_SVC64, guest_svc_handler);
 
-       /* Run tests with breakpoint#0 and watchpoint#0. */
-       vcpu_args_set(vcpu, 2, 0, 0);
+       /* Number of breakpoints */
+       brp_num = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_BRPS), aa64dfr0) + 1;
+       __TEST_REQUIRE(brp_num >= 2, "At least two breakpoints are required");
+
+       /*
+        * Run tests with breakpoint#0, watchpoint#0, and the higiest
+        * numbered (context-aware) breakpoint.
+        */
+       vcpu_args_set(vcpu, 3, 0, 0, brp_num - 1);
 
        vcpu_run(vcpu);
        switch (get_ucall(vcpu, &uc)) {
                }
        }
 
-       test_guest_debug_exceptions();
+       test_guest_debug_exceptions(aa64dfr0);
        test_single_step_from_userspace(ss_iteration);
 
        return 0;