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/cddl/dev/dtrace/riscv/dtrace_subr.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  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License, Version 1.0 only
    6  * (the "License").  You may not use this file except in compliance
    7  * with the License.
    8  *
    9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   10  * or http://www.opensolaris.org/os/licensing.
   11  * See the License for the specific language governing permissions
   12  * and limitations under the License.
   13  *
   14  * When distributing Covered Code, include this CDDL HEADER in each
   15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   16  * If applicable, add the following below this CDDL HEADER, with the
   17  * fields enclosed by brackets "[]" replaced with your own identifying
   18  * information: Portions Copyright [yyyy] [name of copyright owner]
   19  *
   20  * CDDL HEADER END
   21  *
   22  * Portions Copyright 2016-2018 Ruslan Bukin <br@bsdpad.com>
   23  *
   24  * $FreeBSD$
   25  *
   26  */
   27 /*
   28  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
   29  * Use is subject to license terms.
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/malloc.h>
   36 #include <sys/kmem.h>
   37 #include <sys/proc.h>
   38 #include <sys/smp.h>
   39 #include <sys/dtrace_impl.h>
   40 #include <sys/dtrace_bsd.h>
   41 #include <cddl/dev/dtrace/dtrace_cddl.h>
   42 #include <machine/vmparam.h>
   43 #include <machine/encoding.h>
   44 #include <machine/riscvreg.h>
   45 #include <machine/clock.h>
   46 #include <machine/frame.h>
   47 #include <machine/trap.h>
   48 #include <vm/pmap.h>
   49 
   50 extern dtrace_id_t      dtrace_probeid_error;
   51 extern int (*dtrace_invop_jump_addr)(struct trapframe *);
   52 extern void dtrace_getnanotime(struct timespec *tsp);
   53 extern void dtrace_getnanouptime(struct timespec *tsp);
   54 
   55 int dtrace_invop(uintptr_t, struct trapframe *);
   56 void dtrace_invop_init(void);
   57 void dtrace_invop_uninit(void);
   58 
   59 typedef struct dtrace_invop_hdlr {
   60         int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
   61         struct dtrace_invop_hdlr *dtih_next;
   62 } dtrace_invop_hdlr_t;
   63 
   64 dtrace_invop_hdlr_t *dtrace_invop_hdlr;
   65 
   66 int
   67 dtrace_invop(uintptr_t addr, struct trapframe *frame)
   68 {
   69         struct thread *td;
   70         dtrace_invop_hdlr_t *hdlr;
   71         int rval;
   72 
   73         rval = 0;
   74         td = curthread;
   75         td->t_dtrace_trapframe = frame;
   76         for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
   77                 if ((rval = hdlr->dtih_func(addr, frame, 0)) != 0)
   78                         break;
   79         td->t_dtrace_trapframe = NULL;
   80         return (rval);
   81 }
   82 
   83 void
   84 dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
   85 {
   86         dtrace_invop_hdlr_t *hdlr;
   87 
   88         hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP);
   89         hdlr->dtih_func = func;
   90         hdlr->dtih_next = dtrace_invop_hdlr;
   91         dtrace_invop_hdlr = hdlr;
   92 }
   93 
   94 void
   95 dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
   96 {
   97         dtrace_invop_hdlr_t *hdlr, *prev;
   98 
   99         hdlr = dtrace_invop_hdlr;
  100         prev = NULL;
  101 
  102         for (;;) {
  103                 if (hdlr == NULL)
  104                         panic("attempt to remove non-existent invop handler");
  105 
  106                 if (hdlr->dtih_func == func)
  107                         break;
  108 
  109                 prev = hdlr;
  110                 hdlr = hdlr->dtih_next;
  111         }
  112 
  113         if (prev == NULL) {
  114                 ASSERT(dtrace_invop_hdlr == hdlr);
  115                 dtrace_invop_hdlr = hdlr->dtih_next;
  116         } else {
  117                 ASSERT(dtrace_invop_hdlr != hdlr);
  118                 prev->dtih_next = hdlr->dtih_next;
  119         }
  120 
  121         kmem_free(hdlr, 0);
  122 }
  123 
  124 /*ARGSUSED*/
  125 void
  126 dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
  127 {
  128 
  129         (*func)(0, (uintptr_t)VM_MIN_KERNEL_ADDRESS);
  130 }
  131 
  132 void
  133 dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
  134 {
  135         cpuset_t cpus;
  136 
  137         if (cpu == DTRACE_CPUALL)
  138                 cpus = all_cpus;
  139         else
  140                 CPU_SETOF(cpu, &cpus);
  141 
  142         smp_rendezvous_cpus(cpus, smp_no_rendezvous_barrier, func,
  143             smp_no_rendezvous_barrier, arg);
  144 }
  145 
  146 static void
  147 dtrace_sync_func(void)
  148 {
  149 
  150 }
  151 
  152 void
  153 dtrace_sync(void)
  154 {
  155 
  156         dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
  157 }
  158 
  159 /*
  160  * DTrace needs a high resolution time function which can
  161  * be called from a probe context and guaranteed not to have
  162  * instrumented with probes itself.
  163  *
  164  * Returns nanoseconds since boot.
  165  */
  166 uint64_t
  167 dtrace_gethrtime(void)
  168 {
  169         struct timespec curtime;
  170 
  171         dtrace_getnanouptime(&curtime);
  172 
  173         return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
  174 
  175 }
  176 
  177 uint64_t
  178 dtrace_gethrestime(void)
  179 {
  180         struct timespec current_time;
  181 
  182         dtrace_getnanotime(&current_time);
  183 
  184         return (current_time.tv_sec * 1000000000UL + current_time.tv_nsec);
  185 }
  186 
  187 /* Function to handle DTrace traps during probes. See riscv/riscv/trap.c */
  188 int
  189 dtrace_trap(struct trapframe *frame, u_int type)
  190 {
  191         /*
  192          * A trap can occur while DTrace executes a probe. Before
  193          * executing the probe, DTrace blocks re-scheduling and sets
  194          * a flag in its per-cpu flags to indicate that it doesn't
  195          * want to fault. On returning from the probe, the no-fault
  196          * flag is cleared and finally re-scheduling is enabled.
  197          *
  198          * Check if DTrace has enabled 'no-fault' mode:
  199          *
  200          */
  201 
  202         if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) {
  203                 /*
  204                  * There are only a couple of trap types that are expected.
  205                  * All the rest will be handled in the usual way.
  206                  */
  207                 switch (type) {
  208                 case SCAUSE_LOAD_ACCESS_FAULT:
  209                 case SCAUSE_STORE_ACCESS_FAULT:
  210                 case SCAUSE_INST_ACCESS_FAULT:
  211                         /* Flag a bad address. */
  212                         cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
  213                         cpu_core[curcpu].cpuc_dtrace_illval = 0;
  214 
  215                         /*
  216                          * Offset the instruction pointer to the instruction
  217                          * following the one causing the fault.
  218                          */
  219                         frame->tf_sepc += 4;
  220 
  221                         return (1);
  222                 default:
  223                         /* Handle all other traps in the usual way. */
  224                         break;
  225                 }
  226         }
  227 
  228         /* Handle the trap in the usual way. */
  229         return (0);
  230 }
  231 
  232 void
  233 dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
  234     int fault, int fltoffs, uintptr_t illval)
  235 {
  236 
  237         dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state,
  238             (uintptr_t)epid,
  239             (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs);
  240 }
  241 
  242 static int
  243 match_opcode(uint32_t insn, int match, int mask)  
  244 {
  245 
  246         if (((insn ^ match) & mask) == 0)
  247                 return (1);
  248 
  249         return (0);
  250 }
  251 
  252 static int
  253 dtrace_invop_start(struct trapframe *frame)
  254 {
  255         register_t *sp;
  256         uint32_t uimm;
  257         uint32_t imm;
  258         int invop;
  259 
  260         invop = dtrace_invop(frame->tf_sepc, frame);
  261         if (invop == 0)
  262                 return (-1);
  263 
  264         if (match_opcode(invop, (MATCH_SD | RS2_RA | RS1_SP),
  265             (MASK_SD | RS2_MASK | RS1_MASK))) {
  266                 /* Non-compressed store of ra to sp */
  267                 imm = (invop >> 7) & 0x1f;
  268                 imm |= ((invop >> 25) & 0x7f) << 5;
  269                 sp = (register_t *)((uint8_t *)frame->tf_sp + imm);
  270                 *sp = frame->tf_ra;
  271                 frame->tf_sepc += INSN_SIZE;
  272                 return (0);
  273         }
  274 
  275         if (match_opcode(invop, (MATCH_JALR | (X_RA << RS1_SHIFT)),
  276             (MASK_JALR | RD_MASK | RS1_MASK | IMM_MASK))) {
  277                 /* Non-compressed ret */
  278                 frame->tf_sepc = frame->tf_ra;
  279                 return (0);
  280         }
  281 
  282         if (match_opcode(invop, (MATCH_C_SDSP | RS2_C_RA),
  283             (MASK_C_SDSP | RS2_C_MASK))) {
  284                 /* 'C'-compressed store of ra to sp */
  285                 uimm = ((invop >> 10) & 0x7) << 3;
  286                 uimm |= ((invop >> 7) & 0x7) << 6;
  287                 sp = (register_t *)((uint8_t *)frame->tf_sp + uimm);
  288                 *sp = frame->tf_ra;
  289                 frame->tf_sepc += INSN_C_SIZE;
  290                 return (0);
  291         }
  292 
  293         if (match_opcode(invop, (MATCH_C_JR | (X_RA << RD_SHIFT)),
  294             (MASK_C_JR | RD_MASK))) {
  295                 /* 'C'-compressed ret */
  296                 frame->tf_sepc = frame->tf_ra;
  297                 return (0);
  298         }
  299 
  300 #ifdef INVARIANTS
  301         panic("Instruction %x doesn't match any opcode.", invop);
  302 #endif
  303 
  304         return (-1);
  305 }
  306 
  307 void
  308 dtrace_invop_init(void)
  309 {
  310 
  311         dtrace_invop_jump_addr = dtrace_invop_start;
  312 }
  313 
  314 void
  315 dtrace_invop_uninit(void)
  316 {
  317 
  318         dtrace_invop_jump_addr = 0;
  319 }

Cache object: 78bc9320fe7b80e8b97992b10333f083


[ 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.