The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm64/arm64/debug_monitor.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2014 The FreeBSD Foundation
    3  *
    4  * This software was developed by Semihalf under
    5  * the sponsorship of the FreeBSD Foundation.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include "opt_ddb.h"
   30 #include "opt_gdb.h"
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <sys/param.h>
   36 #include <sys/types.h>
   37 #include <sys/kdb.h>
   38 #include <sys/pcpu.h>
   39 #include <sys/proc.h>
   40 #include <sys/systm.h>
   41 #include <sys/sysent.h>
   42 
   43 #include <machine/armreg.h>
   44 #include <machine/cpu.h>
   45 #include <machine/debug_monitor.h>
   46 #include <machine/kdb.h>
   47 
   48 #ifdef DDB
   49 #include <ddb/ddb.h>
   50 #include <ddb/db_sym.h>
   51 #endif
   52 
   53 enum dbg_t {
   54         DBG_TYPE_BREAKPOINT = 0,
   55         DBG_TYPE_WATCHPOINT = 1,
   56 };
   57 
   58 static int dbg_watchpoint_num;
   59 static int dbg_breakpoint_num;
   60 static struct debug_monitor_state kernel_monitor = {
   61         .dbg_flags = DBGMON_KERNEL
   62 };
   63 
   64 /* Called from the exception handlers */
   65 void dbg_monitor_enter(struct thread *);
   66 void dbg_monitor_exit(struct thread *, struct trapframe *);
   67 
   68 /* Watchpoints/breakpoints control register bitfields */
   69 #define DBG_WATCH_CTRL_LEN_1            (0x1 << 5)
   70 #define DBG_WATCH_CTRL_LEN_2            (0x3 << 5)
   71 #define DBG_WATCH_CTRL_LEN_4            (0xf << 5)
   72 #define DBG_WATCH_CTRL_LEN_8            (0xff << 5)
   73 #define DBG_WATCH_CTRL_LEN_MASK(x)      ((x) & (0xff << 5))
   74 #define DBG_WATCH_CTRL_EXEC             (0x0 << 3)
   75 #define DBG_WATCH_CTRL_LOAD             (0x1 << 3)
   76 #define DBG_WATCH_CTRL_STORE            (0x2 << 3)
   77 #define DBG_WATCH_CTRL_ACCESS_MASK(x)   ((x) & (0x3 << 3))
   78 
   79 /* Common for breakpoint and watchpoint */
   80 #define DBG_WB_CTRL_EL1         (0x1 << 1)
   81 #define DBG_WB_CTRL_EL0         (0x2 << 1)
   82 #define DBG_WB_CTRL_ELX_MASK(x) ((x) & (0x3 << 1))
   83 #define DBG_WB_CTRL_E           (0x1 << 0)
   84 
   85 #define DBG_REG_BASE_BVR        0
   86 #define DBG_REG_BASE_BCR        (DBG_REG_BASE_BVR + 16)
   87 #define DBG_REG_BASE_WVR        (DBG_REG_BASE_BCR + 16)
   88 #define DBG_REG_BASE_WCR        (DBG_REG_BASE_WVR + 16)
   89 
   90 /* Watchpoint/breakpoint helpers */
   91 #define DBG_WB_WVR      "wvr"
   92 #define DBG_WB_WCR      "wcr"
   93 #define DBG_WB_BVR      "bvr"
   94 #define DBG_WB_BCR      "bcr"
   95 
   96 #define DBG_WB_READ(reg, num, val) do {                                 \
   97         __asm __volatile("mrs %0, dbg" reg #num "_el1" : "=r" (val));   \
   98 } while (0)
   99 
  100 #define DBG_WB_WRITE(reg, num, val) do {                                \
  101         __asm __volatile("msr dbg" reg #num "_el1, %0" :: "r" (val));   \
  102 } while (0)
  103 
  104 #define READ_WB_REG_CASE(reg, num, offset, val)         \
  105         case (num + offset):                            \
  106                 DBG_WB_READ(reg, num, val);             \
  107                 break
  108 
  109 #define WRITE_WB_REG_CASE(reg, num, offset, val)        \
  110         case (num + offset):                            \
  111                 DBG_WB_WRITE(reg, num, val);            \
  112                 break
  113 
  114 #define SWITCH_CASES_READ_WB_REG(reg, offset, val)      \
  115         READ_WB_REG_CASE(reg,  0, offset, val);         \
  116         READ_WB_REG_CASE(reg,  1, offset, val);         \
  117         READ_WB_REG_CASE(reg,  2, offset, val);         \
  118         READ_WB_REG_CASE(reg,  3, offset, val);         \
  119         READ_WB_REG_CASE(reg,  4, offset, val);         \
  120         READ_WB_REG_CASE(reg,  5, offset, val);         \
  121         READ_WB_REG_CASE(reg,  6, offset, val);         \
  122         READ_WB_REG_CASE(reg,  7, offset, val);         \
  123         READ_WB_REG_CASE(reg,  8, offset, val);         \
  124         READ_WB_REG_CASE(reg,  9, offset, val);         \
  125         READ_WB_REG_CASE(reg, 10, offset, val);         \
  126         READ_WB_REG_CASE(reg, 11, offset, val);         \
  127         READ_WB_REG_CASE(reg, 12, offset, val);         \
  128         READ_WB_REG_CASE(reg, 13, offset, val);         \
  129         READ_WB_REG_CASE(reg, 14, offset, val);         \
  130         READ_WB_REG_CASE(reg, 15, offset, val)
  131 
  132 #define SWITCH_CASES_WRITE_WB_REG(reg, offset, val)     \
  133         WRITE_WB_REG_CASE(reg,  0, offset, val);        \
  134         WRITE_WB_REG_CASE(reg,  1, offset, val);        \
  135         WRITE_WB_REG_CASE(reg,  2, offset, val);        \
  136         WRITE_WB_REG_CASE(reg,  3, offset, val);        \
  137         WRITE_WB_REG_CASE(reg,  4, offset, val);        \
  138         WRITE_WB_REG_CASE(reg,  5, offset, val);        \
  139         WRITE_WB_REG_CASE(reg,  6, offset, val);        \
  140         WRITE_WB_REG_CASE(reg,  7, offset, val);        \
  141         WRITE_WB_REG_CASE(reg,  8, offset, val);        \
  142         WRITE_WB_REG_CASE(reg,  9, offset, val);        \
  143         WRITE_WB_REG_CASE(reg, 10, offset, val);        \
  144         WRITE_WB_REG_CASE(reg, 11, offset, val);        \
  145         WRITE_WB_REG_CASE(reg, 12, offset, val);        \
  146         WRITE_WB_REG_CASE(reg, 13, offset, val);        \
  147         WRITE_WB_REG_CASE(reg, 14, offset, val);        \
  148         WRITE_WB_REG_CASE(reg, 15, offset, val)
  149 
  150 #ifdef DDB
  151 static uint64_t
  152 dbg_wb_read_reg(int reg, int n)
  153 {
  154         uint64_t val = 0;
  155 
  156         switch (reg + n) {
  157         SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
  158         SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
  159         SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
  160         SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
  161         default:
  162                 printf("trying to read from wrong debug register %d\n", n);
  163         }
  164 
  165         return val;
  166 }
  167 #endif /* DDB */
  168 
  169 static void
  170 dbg_wb_write_reg(int reg, int n, uint64_t val)
  171 {
  172         switch (reg + n) {
  173         SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
  174         SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
  175         SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
  176         SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
  177         default:
  178                 printf("trying to write to wrong debug register %d\n", n);
  179                 return;
  180         }
  181         isb();
  182 }
  183 
  184 #if defined(DDB) || defined(GDB)
  185 void
  186 kdb_cpu_set_singlestep(void)
  187 {
  188 
  189         KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D,
  190             ("%s: debug exceptions are not masked", __func__));
  191 
  192         kdb_frame->tf_spsr |= PSR_SS;
  193         WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) |
  194             MDSCR_SS | MDSCR_KDE);
  195 
  196         /*
  197          * Disable breakpoints and watchpoints, e.g. stepping
  198          * over watched instruction will trigger break exception instead of
  199          * single-step exception and locks CPU on that instruction for ever.
  200          */
  201         if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
  202                 WRITE_SPECIALREG(mdscr_el1,
  203                     READ_SPECIALREG(mdscr_el1) & ~MDSCR_MDE);
  204         }
  205 }
  206 
  207 void
  208 kdb_cpu_clear_singlestep(void)
  209 {
  210 
  211         KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D,
  212             ("%s: debug exceptions are not masked", __func__));
  213 
  214         WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) &
  215             ~(MDSCR_SS | MDSCR_KDE));
  216 
  217         /* Restore breakpoints and watchpoints */
  218         if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
  219                 WRITE_SPECIALREG(mdscr_el1,
  220                     READ_SPECIALREG(mdscr_el1) | MDSCR_MDE);
  221 
  222                 if ((kernel_monitor.dbg_flags & DBGMON_KERNEL) != 0) {
  223                         WRITE_SPECIALREG(mdscr_el1,
  224                             READ_SPECIALREG(mdscr_el1) | MDSCR_KDE);
  225                 }
  226         }
  227 }
  228 
  229 int
  230 kdb_cpu_set_watchpoint(vm_offset_t addr, vm_size_t size, int access)
  231 {
  232         enum dbg_access_t dbg_access;
  233 
  234         switch (access) {
  235         case KDB_DBG_ACCESS_R:
  236                 dbg_access = HW_BREAKPOINT_R;
  237                 break;
  238         case KDB_DBG_ACCESS_W:
  239                 dbg_access = HW_BREAKPOINT_W;
  240                 break;
  241         case KDB_DBG_ACCESS_RW:
  242                 dbg_access = HW_BREAKPOINT_RW;
  243                 break;
  244         default:
  245                 return (EINVAL);
  246         }
  247 
  248         return (dbg_setup_watchpoint(NULL, addr, size, dbg_access));
  249 }
  250 
  251 int
  252 kdb_cpu_clr_watchpoint(vm_offset_t addr, vm_size_t size)
  253 {
  254 
  255         return (dbg_remove_watchpoint(NULL, addr, size));
  256 }
  257 #endif /* DDB || GDB */
  258 
  259 #ifdef DDB
  260 static const char *
  261 dbg_watchtype_str(uint32_t type)
  262 {
  263         switch (type) {
  264                 case DBG_WATCH_CTRL_EXEC:
  265                         return ("execute");
  266                 case DBG_WATCH_CTRL_STORE:
  267                         return ("write");
  268                 case DBG_WATCH_CTRL_LOAD:
  269                         return ("read");
  270                 case DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE:
  271                         return ("read/write");
  272                 default:
  273                         return ("invalid");
  274         }
  275 }
  276 
  277 static int
  278 dbg_watchtype_len(uint32_t len)
  279 {
  280         switch (len) {
  281         case DBG_WATCH_CTRL_LEN_1:
  282                 return (1);
  283         case DBG_WATCH_CTRL_LEN_2:
  284                 return (2);
  285         case DBG_WATCH_CTRL_LEN_4:
  286                 return (4);
  287         case DBG_WATCH_CTRL_LEN_8:
  288                 return (8);
  289         default:
  290                 return (0);
  291         }
  292 }
  293 
  294 void
  295 dbg_show_watchpoint(void)
  296 {
  297         uint32_t wcr, len, type;
  298         uint64_t addr;
  299         int i;
  300 
  301         db_printf("\nhardware watchpoints:\n");
  302         db_printf("  watch    status        type  len             address              symbol\n");
  303         db_printf("  -----  --------  ----------  ---  ------------------  ------------------\n");
  304         for (i = 0; i < dbg_watchpoint_num; i++) {
  305                 wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
  306                 if ((wcr & DBG_WB_CTRL_E) != 0) {
  307                         type = DBG_WATCH_CTRL_ACCESS_MASK(wcr);
  308                         len = DBG_WATCH_CTRL_LEN_MASK(wcr);
  309                         addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i);
  310                         db_printf("  %-5d  %-8s  %10s  %3d  0x%16lx  ",
  311                             i, "enabled", dbg_watchtype_str(type),
  312                             dbg_watchtype_len(len), addr);
  313                         db_printsym((db_addr_t)addr, DB_STGY_ANY);
  314                         db_printf("\n");
  315                 } else {
  316                         db_printf("  %-5d  disabled\n", i);
  317                 }
  318         }
  319 }
  320 #endif /* DDB */
  321 
  322 static int
  323 dbg_find_free_slot(struct debug_monitor_state *monitor, enum dbg_t type)
  324 {
  325         uint64_t *reg;
  326         u_int max, i;
  327 
  328         switch(type) {
  329         case DBG_TYPE_BREAKPOINT:
  330                 max = dbg_breakpoint_num;
  331                 reg = monitor->dbg_bcr;
  332                 break;
  333         case DBG_TYPE_WATCHPOINT:
  334                 max = dbg_watchpoint_num;
  335                 reg = monitor->dbg_wcr;
  336                 break;
  337         default:
  338                 printf("Unsupported debug type\n");
  339                 return (i);
  340         }
  341 
  342         for (i = 0; i < max; i++) {
  343                 if ((reg[i] & DBG_WB_CTRL_E) == 0)
  344                         return (i);
  345         }
  346 
  347         return (-1);
  348 }
  349 
  350 static int
  351 dbg_find_slot(struct debug_monitor_state *monitor, enum dbg_t type,
  352     vm_offset_t addr)
  353 {
  354         uint64_t *reg_addr, *reg_ctrl;
  355         u_int max, i;
  356 
  357         switch(type) {
  358         case DBG_TYPE_BREAKPOINT:
  359                 max = dbg_breakpoint_num;
  360                 reg_addr = monitor->dbg_bvr;
  361                 reg_ctrl = monitor->dbg_bcr;
  362                 break;
  363         case DBG_TYPE_WATCHPOINT:
  364                 max = dbg_watchpoint_num;
  365                 reg_addr = monitor->dbg_wvr;
  366                 reg_ctrl = monitor->dbg_wcr;
  367                 break;
  368         default:
  369                 printf("Unsupported debug type\n");
  370                 return (i);
  371         }
  372 
  373         for (i = 0; i < max; i++) {
  374                 if (reg_addr[i] == addr &&
  375                     (reg_ctrl[i] & DBG_WB_CTRL_E) != 0)
  376                         return (i);
  377         }
  378 
  379         return (-1);
  380 }
  381 
  382 int
  383 dbg_setup_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
  384     vm_size_t size, enum dbg_access_t access)
  385 {
  386         uint64_t wcr_size, wcr_priv, wcr_access;
  387         u_int i;
  388 
  389         if (monitor == NULL)
  390                 monitor = &kernel_monitor;
  391 
  392         i = dbg_find_free_slot(monitor, DBG_TYPE_WATCHPOINT);
  393         if (i == -1) {
  394                 printf("Can not find slot for watchpoint, max %d"
  395                     " watchpoints supported\n", dbg_watchpoint_num);
  396                 return (EBUSY);
  397         }
  398 
  399         switch(size) {
  400         case 1:
  401                 wcr_size = DBG_WATCH_CTRL_LEN_1;
  402                 break;
  403         case 2:
  404                 wcr_size = DBG_WATCH_CTRL_LEN_2;
  405                 break;
  406         case 4:
  407                 wcr_size = DBG_WATCH_CTRL_LEN_4;
  408                 break;
  409         case 8:
  410                 wcr_size = DBG_WATCH_CTRL_LEN_8;
  411                 break;
  412         default:
  413                 printf("Unsupported address size for watchpoint: %zu\n", size);
  414                 return (EINVAL);
  415         }
  416 
  417         if ((monitor->dbg_flags & DBGMON_KERNEL) == 0)
  418                 wcr_priv = DBG_WB_CTRL_EL0;
  419         else
  420                 wcr_priv = DBG_WB_CTRL_EL1;
  421 
  422         switch(access) {
  423         case HW_BREAKPOINT_X:
  424                 wcr_access = DBG_WATCH_CTRL_EXEC;
  425                 break;
  426         case HW_BREAKPOINT_R:
  427                 wcr_access = DBG_WATCH_CTRL_LOAD;
  428                 break;
  429         case HW_BREAKPOINT_W:
  430                 wcr_access = DBG_WATCH_CTRL_STORE;
  431                 break;
  432         case HW_BREAKPOINT_RW:
  433                 wcr_access = DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE;
  434                 break;
  435         default:
  436                 printf("Unsupported access type for watchpoint: %d\n", access);
  437                 return (EINVAL);
  438         }
  439 
  440         monitor->dbg_wvr[i] = addr;
  441         monitor->dbg_wcr[i] = wcr_size | wcr_access | wcr_priv | DBG_WB_CTRL_E;
  442         monitor->dbg_enable_count++;
  443         monitor->dbg_flags |= DBGMON_ENABLED;
  444 
  445         dbg_register_sync(monitor);
  446         return (0);
  447 }
  448 
  449 int
  450 dbg_remove_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
  451     vm_size_t size)
  452 {
  453         u_int i;
  454 
  455         if (monitor == NULL)
  456                 monitor = &kernel_monitor;
  457 
  458         i = dbg_find_slot(monitor, DBG_TYPE_WATCHPOINT, addr);
  459         if (i == -1) {
  460                 printf("Can not find watchpoint for address 0%lx\n", addr);
  461                 return (EINVAL);
  462         }
  463 
  464         monitor->dbg_wvr[i] = 0;
  465         monitor->dbg_wcr[i] = 0;
  466         monitor->dbg_enable_count--;
  467         if (monitor->dbg_enable_count == 0)
  468                 monitor->dbg_flags &= ~DBGMON_ENABLED;
  469 
  470         dbg_register_sync(monitor);
  471         return (0);
  472 }
  473 
  474 void
  475 dbg_register_sync(struct debug_monitor_state *monitor)
  476 {
  477         uint64_t mdscr;
  478         int i;
  479 
  480         if (monitor == NULL)
  481                 monitor = &kernel_monitor;
  482 
  483         mdscr = READ_SPECIALREG(mdscr_el1);
  484         if ((monitor->dbg_flags & DBGMON_ENABLED) == 0) {
  485                 mdscr &= ~(MDSCR_MDE | MDSCR_KDE);
  486         } else {
  487                 for (i = 0; i < dbg_breakpoint_num; i++) {
  488                         dbg_wb_write_reg(DBG_REG_BASE_BCR, i,
  489                             monitor->dbg_bcr[i]);
  490                         dbg_wb_write_reg(DBG_REG_BASE_BVR, i,
  491                             monitor->dbg_bvr[i]);
  492                 }
  493 
  494                 for (i = 0; i < dbg_watchpoint_num; i++) {
  495                         dbg_wb_write_reg(DBG_REG_BASE_WCR, i,
  496                             monitor->dbg_wcr[i]);
  497                         dbg_wb_write_reg(DBG_REG_BASE_WVR, i,
  498                             monitor->dbg_wvr[i]);
  499                 }
  500                 mdscr |= MDSCR_MDE;
  501                 if ((monitor->dbg_flags & DBGMON_KERNEL) == DBGMON_KERNEL)
  502                         mdscr |= MDSCR_KDE;
  503         }
  504         WRITE_SPECIALREG(mdscr_el1, mdscr);
  505         isb();
  506 }
  507 
  508 void
  509 dbg_monitor_init(void)
  510 {
  511         uint64_t aa64dfr0;
  512         u_int i;
  513 
  514         /* Find out many breakpoints and watchpoints we can use */
  515         aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
  516         dbg_watchpoint_num = ID_AA64DFR0_WRPs_VAL(aa64dfr0);
  517         dbg_breakpoint_num = ID_AA64DFR0_BRPs_VAL(aa64dfr0);
  518 
  519         if (bootverbose && PCPU_GET(cpuid) == 0) {
  520                 printf("%d watchpoints and %d breakpoints supported\n",
  521                     dbg_watchpoint_num, dbg_breakpoint_num);
  522         }
  523 
  524         /*
  525          * We have limited number of {watch,break}points, each consists of
  526          * two registers:
  527          * - wcr/bcr regsiter configurates corresponding {watch,break}point
  528          *   behaviour
  529          * - wvr/bvr register keeps address we are hunting for
  530          *
  531          * Reset all breakpoints and watchpoints.
  532          */
  533         for (i = 0; i < dbg_watchpoint_num; i++) {
  534                 dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
  535                 dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
  536         }
  537 
  538         for (i = 0; i < dbg_breakpoint_num; i++) {
  539                 dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
  540                 dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
  541         }
  542 
  543         dbg_enable();
  544 }
  545 
  546 void
  547 dbg_monitor_enter(struct thread *thread)
  548 {
  549         int i;
  550 
  551         if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
  552                 /* Install the kernel version of the registers */
  553                 dbg_register_sync(&kernel_monitor);
  554         } else if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
  555                 /* Disable the user breakpoints until we return to userspace */
  556                 for (i = 0; i < dbg_watchpoint_num; i++) {
  557                         dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
  558                         dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
  559                 }
  560 
  561                 for (i = 0; i < dbg_breakpoint_num; ++i) {
  562                         dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
  563                         dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
  564                 }
  565                 WRITE_SPECIALREG(mdscr_el1,
  566                     READ_SPECIALREG(mdscr_el1) & ~(MDSCR_MDE | MDSCR_KDE));
  567                 isb();
  568         }
  569 }
  570 
  571 void
  572 dbg_monitor_exit(struct thread *thread, struct trapframe *frame)
  573 {
  574         int i;
  575 
  576         /*
  577          * PSR_D is an aarch64-only flag. On aarch32, it switches
  578          * the processor to big-endian, so avoid setting it for
  579          * 32bits binaries.
  580          */
  581         if (!(SV_PROC_FLAG(thread->td_proc, SV_ILP32)))
  582                 frame->tf_spsr |= PSR_D;
  583         if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
  584                 /* Install the thread's version of the registers */
  585                 dbg_register_sync(&thread->td_pcb->pcb_dbg_regs);
  586                 frame->tf_spsr &= ~PSR_D;
  587         } else if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
  588                 /* Disable the kernel breakpoints until we re-enter */
  589                 for (i = 0; i < dbg_watchpoint_num; i++) {
  590                         dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
  591                         dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
  592                 }
  593 
  594                 for (i = 0; i < dbg_breakpoint_num; ++i) {
  595                         dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
  596                         dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
  597                 }
  598                 WRITE_SPECIALREG(mdscr_el1,
  599                     READ_SPECIALREG(mdscr_el1) & ~(MDSCR_MDE | MDSCR_KDE));
  600                 isb();
  601         }
  602 }

Cache object: d515af335b5855050c724dd456a8ef6c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.