1179237Sjb/* 2179237Sjb * CDDL HEADER START 3179237Sjb * 4179237Sjb * The contents of this file are subject to the terms of the 5179237Sjb * Common Development and Distribution License, Version 1.0 only 6179237Sjb * (the "License"). You may not use this file except in compliance 7179237Sjb * with the License. 8179237Sjb * 9179237Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10179237Sjb * or http://www.opensolaris.org/os/licensing. 11179237Sjb * See the License for the specific language governing permissions 12179237Sjb * and limitations under the License. 13179237Sjb * 14179237Sjb * When distributing Covered Code, include this CDDL HEADER in each 15179237Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16179237Sjb * If applicable, add the following below this CDDL HEADER, with the 17179237Sjb * fields enclosed by brackets "[]" replaced with your own identifying 18179237Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 19179237Sjb * 20179237Sjb * CDDL HEADER END 21179237Sjb * 22179237Sjb * $FreeBSD$ 23179237Sjb * 24179237Sjb */ 25179237Sjb/* 26179237Sjb * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 27179237Sjb * Use is subject to license terms. 28179237Sjb */ 29179237Sjb 30251666Sgnn/* 31251666Sgnn * Copyright (c) 2011, Joyent, Inc. All rights reserved. 32251666Sgnn */ 33251666Sgnn 34179237Sjb#include <sys/param.h> 35179237Sjb#include <sys/systm.h> 36179237Sjb#include <sys/types.h> 37222813Sattilio#include <sys/cpuset.h> 38179237Sjb#include <sys/kernel.h> 39179237Sjb#include <sys/malloc.h> 40179237Sjb#include <sys/kmem.h> 41179237Sjb#include <sys/smp.h> 42179237Sjb#include <sys/dtrace_impl.h> 43179237Sjb#include <sys/dtrace_bsd.h> 44179237Sjb#include <machine/clock.h> 45179237Sjb#include <machine/frame.h> 46179237Sjb#include <vm/pmap.h> 47179237Sjb 48179237Sjbextern uintptr_t kernelbase; 49179237Sjbextern uintptr_t dtrace_in_probe_addr; 50179237Sjbextern int dtrace_in_probe; 51179237Sjb 52244093Sgnnextern void dtrace_getnanotime(struct timespec *tsp); 53244093Sgnn 54179237Sjbint dtrace_invop(uintptr_t, uintptr_t *, uintptr_t); 55179237Sjb 56179237Sjbtypedef struct dtrace_invop_hdlr { 57179237Sjb int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t); 58179237Sjb struct dtrace_invop_hdlr *dtih_next; 59179237Sjb} dtrace_invop_hdlr_t; 60179237Sjb 61179237Sjbdtrace_invop_hdlr_t *dtrace_invop_hdlr; 62179237Sjb 63179237Sjbint 64179237Sjbdtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) 65179237Sjb{ 66179237Sjb dtrace_invop_hdlr_t *hdlr; 67179237Sjb int rval; 68179237Sjb 69179237Sjb for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) 70179237Sjb if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) 71179237Sjb return (rval); 72179237Sjb 73179237Sjb return (0); 74179237Sjb} 75179237Sjb 76179237Sjbvoid 77179237Sjbdtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) 78179237Sjb{ 79179237Sjb dtrace_invop_hdlr_t *hdlr; 80179237Sjb 81179237Sjb hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP); 82179237Sjb hdlr->dtih_func = func; 83179237Sjb hdlr->dtih_next = dtrace_invop_hdlr; 84179237Sjb dtrace_invop_hdlr = hdlr; 85179237Sjb} 86179237Sjb 87179237Sjbvoid 88179237Sjbdtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) 89179237Sjb{ 90179237Sjb dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL; 91179237Sjb 92179237Sjb for (;;) { 93179237Sjb if (hdlr == NULL) 94179237Sjb panic("attempt to remove non-existent invop handler"); 95179237Sjb 96179237Sjb if (hdlr->dtih_func == func) 97179237Sjb break; 98179237Sjb 99179237Sjb prev = hdlr; 100179237Sjb hdlr = hdlr->dtih_next; 101179237Sjb } 102179237Sjb 103179237Sjb if (prev == NULL) { 104179237Sjb ASSERT(dtrace_invop_hdlr == hdlr); 105179237Sjb dtrace_invop_hdlr = hdlr->dtih_next; 106179237Sjb } else { 107179237Sjb ASSERT(dtrace_invop_hdlr != hdlr); 108179237Sjb prev->dtih_next = hdlr->dtih_next; 109179237Sjb } 110179237Sjb 111179237Sjb kmem_free(hdlr, 0); 112179237Sjb} 113179237Sjb 114179237Sjbvoid 115179237Sjbdtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) 116179237Sjb{ 117179237Sjb (*func)(0, kernelbase); 118179237Sjb} 119179237Sjb 120179237Sjbvoid 121179237Sjbdtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) 122179237Sjb{ 123222813Sattilio cpuset_t cpus; 124179237Sjb 125179237Sjb if (cpu == DTRACE_CPUALL) 126179237Sjb cpus = all_cpus; 127179237Sjb else 128222813Sattilio CPU_SETOF(cpu, &cpus); 129179237Sjb 130216251Savg smp_rendezvous_cpus(cpus, smp_no_rendevous_barrier, func, 131216251Savg smp_no_rendevous_barrier, arg); 132179237Sjb} 133179237Sjb 134179237Sjbstatic void 135179237Sjbdtrace_sync_func(void) 136179237Sjb{ 137179237Sjb} 138179237Sjb 139179237Sjbvoid 140179237Sjbdtrace_sync(void) 141179237Sjb{ 142179237Sjb dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); 143179237Sjb} 144179237Sjb 145179237Sjb#ifdef notyet 146179237Sjbint (*dtrace_fasttrap_probe_ptr)(struct regs *); 147179237Sjbint (*dtrace_pid_probe_ptr)(struct regs *); 148179237Sjbint (*dtrace_return_probe_ptr)(struct regs *); 149179237Sjb 150179237Sjbvoid 151179237Sjbdtrace_user_probe(struct regs *rp, caddr_t addr, processorid_t cpuid) 152179237Sjb{ 153179237Sjb krwlock_t *rwp; 154179237Sjb proc_t *p = curproc; 155179237Sjb extern void trap(struct regs *, caddr_t, processorid_t); 156179237Sjb 157179237Sjb if (USERMODE(rp->r_cs) || (rp->r_ps & PS_VM)) { 158179237Sjb if (curthread->t_cred != p->p_cred) { 159179237Sjb cred_t *oldcred = curthread->t_cred; 160179237Sjb /* 161179237Sjb * DTrace accesses t_cred in probe context. t_cred 162179237Sjb * must always be either NULL, or point to a valid, 163179237Sjb * allocated cred structure. 164179237Sjb */ 165179237Sjb curthread->t_cred = crgetcred(); 166179237Sjb crfree(oldcred); 167179237Sjb } 168179237Sjb } 169179237Sjb 170179237Sjb if (rp->r_trapno == T_DTRACE_RET) { 171179237Sjb uint8_t step = curthread->t_dtrace_step; 172179237Sjb uint8_t ret = curthread->t_dtrace_ret; 173179237Sjb uintptr_t npc = curthread->t_dtrace_npc; 174179237Sjb 175179237Sjb if (curthread->t_dtrace_ast) { 176179237Sjb aston(curthread); 177179237Sjb curthread->t_sig_check = 1; 178179237Sjb } 179179237Sjb 180179237Sjb /* 181179237Sjb * Clear all user tracing flags. 182179237Sjb */ 183179237Sjb curthread->t_dtrace_ft = 0; 184179237Sjb 185179237Sjb /* 186179237Sjb * If we weren't expecting to take a return probe trap, kill 187179237Sjb * the process as though it had just executed an unassigned 188179237Sjb * trap instruction. 189179237Sjb */ 190179237Sjb if (step == 0) { 191179237Sjb tsignal(curthread, SIGILL); 192179237Sjb return; 193179237Sjb } 194179237Sjb 195179237Sjb /* 196179237Sjb * If we hit this trap unrelated to a return probe, we're 197179237Sjb * just here to reset the AST flag since we deferred a signal 198179237Sjb * until after we logically single-stepped the instruction we 199179237Sjb * copied out. 200179237Sjb */ 201179237Sjb if (ret == 0) { 202179237Sjb rp->r_pc = npc; 203179237Sjb return; 204179237Sjb } 205179237Sjb 206179237Sjb /* 207179237Sjb * We need to wait until after we've called the 208179237Sjb * dtrace_return_probe_ptr function pointer to set %pc. 209179237Sjb */ 210179237Sjb rwp = &CPU->cpu_ft_lock; 211179237Sjb rw_enter(rwp, RW_READER); 212179237Sjb if (dtrace_return_probe_ptr != NULL) 213179237Sjb (void) (*dtrace_return_probe_ptr)(rp); 214179237Sjb rw_exit(rwp); 215179237Sjb rp->r_pc = npc; 216179237Sjb 217179237Sjb } else if (rp->r_trapno == T_DTRACE_PROBE) { 218179237Sjb rwp = &CPU->cpu_ft_lock; 219179237Sjb rw_enter(rwp, RW_READER); 220179237Sjb if (dtrace_fasttrap_probe_ptr != NULL) 221179237Sjb (void) (*dtrace_fasttrap_probe_ptr)(rp); 222179237Sjb rw_exit(rwp); 223179237Sjb 224179237Sjb } else if (rp->r_trapno == T_BPTFLT) { 225179237Sjb uint8_t instr; 226179237Sjb rwp = &CPU->cpu_ft_lock; 227179237Sjb 228179237Sjb /* 229179237Sjb * The DTrace fasttrap provider uses the breakpoint trap 230179237Sjb * (int 3). We let DTrace take the first crack at handling 231179237Sjb * this trap; if it's not a probe that DTrace knowns about, 232179237Sjb * we call into the trap() routine to handle it like a 233179237Sjb * breakpoint placed by a conventional debugger. 234179237Sjb */ 235179237Sjb rw_enter(rwp, RW_READER); 236179237Sjb if (dtrace_pid_probe_ptr != NULL && 237179237Sjb (*dtrace_pid_probe_ptr)(rp) == 0) { 238179237Sjb rw_exit(rwp); 239179237Sjb return; 240179237Sjb } 241179237Sjb rw_exit(rwp); 242179237Sjb 243179237Sjb /* 244179237Sjb * If the instruction that caused the breakpoint trap doesn't 245179237Sjb * look like an int 3 anymore, it may be that this tracepoint 246179237Sjb * was removed just after the user thread executed it. In 247179237Sjb * that case, return to user land to retry the instuction. 248179237Sjb */ 249179237Sjb if (fuword8((void *)(rp->r_pc - 1), &instr) == 0 && 250179237Sjb instr != FASTTRAP_INSTR) { 251179237Sjb rp->r_pc--; 252179237Sjb return; 253179237Sjb } 254179237Sjb 255179237Sjb trap(rp, addr, cpuid); 256179237Sjb 257179237Sjb } else { 258179237Sjb trap(rp, addr, cpuid); 259179237Sjb } 260179237Sjb} 261179237Sjb 262179237Sjbvoid 263179237Sjbdtrace_safe_synchronous_signal(void) 264179237Sjb{ 265179237Sjb kthread_t *t = curthread; 266179237Sjb struct regs *rp = lwptoregs(ttolwp(t)); 267179237Sjb size_t isz = t->t_dtrace_npc - t->t_dtrace_pc; 268179237Sjb 269179237Sjb ASSERT(t->t_dtrace_on); 270179237Sjb 271179237Sjb /* 272179237Sjb * If we're not in the range of scratch addresses, we're not actually 273179237Sjb * tracing user instructions so turn off the flags. If the instruction 274179237Sjb * we copied out caused a synchonous trap, reset the pc back to its 275179237Sjb * original value and turn off the flags. 276179237Sjb */ 277179237Sjb if (rp->r_pc < t->t_dtrace_scrpc || 278179237Sjb rp->r_pc > t->t_dtrace_astpc + isz) { 279179237Sjb t->t_dtrace_ft = 0; 280179237Sjb } else if (rp->r_pc == t->t_dtrace_scrpc || 281179237Sjb rp->r_pc == t->t_dtrace_astpc) { 282179237Sjb rp->r_pc = t->t_dtrace_pc; 283179237Sjb t->t_dtrace_ft = 0; 284179237Sjb } 285179237Sjb} 286179237Sjb 287179237Sjbint 288179237Sjbdtrace_safe_defer_signal(void) 289179237Sjb{ 290179237Sjb kthread_t *t = curthread; 291179237Sjb struct regs *rp = lwptoregs(ttolwp(t)); 292179237Sjb size_t isz = t->t_dtrace_npc - t->t_dtrace_pc; 293179237Sjb 294179237Sjb ASSERT(t->t_dtrace_on); 295179237Sjb 296179237Sjb /* 297179237Sjb * If we're not in the range of scratch addresses, we're not actually 298179237Sjb * tracing user instructions so turn off the flags. 299179237Sjb */ 300179237Sjb if (rp->r_pc < t->t_dtrace_scrpc || 301179237Sjb rp->r_pc > t->t_dtrace_astpc + isz) { 302179237Sjb t->t_dtrace_ft = 0; 303179237Sjb return (0); 304179237Sjb } 305179237Sjb 306179237Sjb /* 307251666Sgnn * If we have executed the original instruction, but we have performed 308251666Sgnn * neither the jmp back to t->t_dtrace_npc nor the clean up of any 309251666Sgnn * registers used to emulate %rip-relative instructions in 64-bit mode, 310251666Sgnn * we'll save ourselves some effort by doing that here and taking the 311251666Sgnn * signal right away. We detect this condition by seeing if the program 312251666Sgnn * counter is the range [scrpc + isz, astpc). 313179237Sjb */ 314251666Sgnn if (rp->r_pc >= t->t_dtrace_scrpc + isz && 315251666Sgnn rp->r_pc < t->t_dtrace_astpc) { 316179237Sjb#ifdef __amd64 317179237Sjb /* 318179237Sjb * If there is a scratch register and we're on the 319179237Sjb * instruction immediately after the modified instruction, 320179237Sjb * restore the value of that scratch register. 321179237Sjb */ 322179237Sjb if (t->t_dtrace_reg != 0 && 323179237Sjb rp->r_pc == t->t_dtrace_scrpc + isz) { 324179237Sjb switch (t->t_dtrace_reg) { 325179237Sjb case REG_RAX: 326179237Sjb rp->r_rax = t->t_dtrace_regv; 327179237Sjb break; 328179237Sjb case REG_RCX: 329179237Sjb rp->r_rcx = t->t_dtrace_regv; 330179237Sjb break; 331179237Sjb case REG_R8: 332179237Sjb rp->r_r8 = t->t_dtrace_regv; 333179237Sjb break; 334179237Sjb case REG_R9: 335179237Sjb rp->r_r9 = t->t_dtrace_regv; 336179237Sjb break; 337179237Sjb } 338179237Sjb } 339179237Sjb#endif 340179237Sjb rp->r_pc = t->t_dtrace_npc; 341179237Sjb t->t_dtrace_ft = 0; 342179237Sjb return (0); 343179237Sjb } 344179237Sjb 345179237Sjb /* 346179237Sjb * Otherwise, make sure we'll return to the kernel after executing 347179237Sjb * the copied out instruction and defer the signal. 348179237Sjb */ 349179237Sjb if (!t->t_dtrace_step) { 350179237Sjb ASSERT(rp->r_pc < t->t_dtrace_astpc); 351179237Sjb rp->r_pc += t->t_dtrace_astpc - t->t_dtrace_scrpc; 352179237Sjb t->t_dtrace_step = 1; 353179237Sjb } 354179237Sjb 355179237Sjb t->t_dtrace_ast = 1; 356179237Sjb 357179237Sjb return (1); 358179237Sjb} 359179237Sjb#endif 360179237Sjb 361179237Sjbstatic int64_t tgt_cpu_tsc; 362179237Sjbstatic int64_t hst_cpu_tsc; 363179237Sjbstatic int64_t tsc_skew[MAXCPU]; 364195710Savgstatic uint64_t nsec_scale; 365179237Sjb 366195710Savg/* See below for the explanation of this macro. */ 367195710Savg#define SCALE_SHIFT 28 368195710Savg 369179237Sjbstatic void 370179237Sjbdtrace_gethrtime_init_cpu(void *arg) 371179237Sjb{ 372179237Sjb uintptr_t cpu = (uintptr_t) arg; 373179237Sjb 374179237Sjb if (cpu == curcpu) 375179237Sjb tgt_cpu_tsc = rdtsc(); 376179237Sjb else 377179237Sjb hst_cpu_tsc = rdtsc(); 378179237Sjb} 379179237Sjb 380179237Sjbstatic void 381179237Sjbdtrace_gethrtime_init(void *arg) 382179237Sjb{ 383222813Sattilio cpuset_t map; 384216250Savg struct pcpu *pc; 385195710Savg uint64_t tsc_f; 386179237Sjb int i; 387179237Sjb 388195710Savg /* 389195710Savg * Get TSC frequency known at this moment. 390195710Savg * This should be constant if TSC is invariant. 391195710Savg * Otherwise tick->time conversion will be inaccurate, but 392195710Savg * will preserve monotonic property of TSC. 393195710Savg */ 394220433Sjkim tsc_f = atomic_load_acq_64(&tsc_freq); 395195710Savg 396195710Savg /* 397195710Savg * The following line checks that nsec_scale calculated below 398195710Savg * doesn't overflow 32-bit unsigned integer, so that it can multiply 399195710Savg * another 32-bit integer without overflowing 64-bit. 400195710Savg * Thus minimum supported TSC frequency is 62.5MHz. 401195710Savg */ 402195710Savg KASSERT(tsc_f > (NANOSEC >> (32 - SCALE_SHIFT)), ("TSC frequency is too low")); 403195710Savg 404195710Savg /* 405195710Savg * We scale up NANOSEC/tsc_f ratio to preserve as much precision 406195710Savg * as possible. 407195710Savg * 2^28 factor was chosen quite arbitrarily from practical 408195710Savg * considerations: 409195710Savg * - it supports TSC frequencies as low as 62.5MHz (see above); 410195710Savg * - it provides quite good precision (e < 0.01%) up to THz 411195710Savg * (terahertz) values; 412195710Savg */ 413195710Savg nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tsc_f; 414195710Savg 415179237Sjb /* The current CPU is the reference one. */ 416216250Savg sched_pin(); 417179237Sjb tsc_skew[curcpu] = 0; 418209059Sjhb CPU_FOREACH(i) { 419179237Sjb if (i == curcpu) 420179237Sjb continue; 421179237Sjb 422216250Savg pc = pcpu_find(i); 423223758Sattilio CPU_SETOF(PCPU_GET(cpuid), &map); 424223758Sattilio CPU_SET(pc->pc_cpuid, &map); 425179237Sjb 426221740Savg smp_rendezvous_cpus(map, NULL, 427179237Sjb dtrace_gethrtime_init_cpu, 428179237Sjb smp_no_rendevous_barrier, (void *)(uintptr_t) i); 429179237Sjb 430179237Sjb tsc_skew[i] = tgt_cpu_tsc - hst_cpu_tsc; 431179237Sjb } 432216250Savg sched_unpin(); 433179237Sjb} 434179237Sjb 435179237SjbSYSINIT(dtrace_gethrtime_init, SI_SUB_SMP, SI_ORDER_ANY, dtrace_gethrtime_init, NULL); 436179237Sjb 437179237Sjb/* 438179237Sjb * DTrace needs a high resolution time function which can 439179237Sjb * be called from a probe context and guaranteed not to have 440179237Sjb * instrumented with probes itself. 441179237Sjb * 442179237Sjb * Returns nanoseconds since boot. 443179237Sjb */ 444179237Sjbuint64_t 445179237Sjbdtrace_gethrtime() 446179237Sjb{ 447195710Savg uint64_t tsc; 448195710Savg uint32_t lo; 449195710Savg uint32_t hi; 450195710Savg 451195710Savg /* 452195710Savg * We split TSC value into lower and higher 32-bit halves and separately 453195710Savg * scale them with nsec_scale, then we scale them down by 2^28 454195710Savg * (see nsec_scale calculations) taking into account 32-bit shift of 455195710Savg * the higher half and finally add. 456195710Savg */ 457265882Smarkj tsc = rdtsc() - tsc_skew[curcpu]; 458195710Savg lo = tsc; 459195710Savg hi = tsc >> 32; 460195710Savg return (((lo * nsec_scale) >> SCALE_SHIFT) + 461195710Savg ((hi * nsec_scale) << (32 - SCALE_SHIFT))); 462179237Sjb} 463179237Sjb 464179237Sjbuint64_t 465179237Sjbdtrace_gethrestime(void) 466179237Sjb{ 467244093Sgnn struct timespec current_time; 468244093Sgnn 469244093Sgnn dtrace_getnanotime(¤t_time); 470244093Sgnn 471244093Sgnn return (current_time.tv_sec * 1000000000ULL + current_time.tv_nsec); 472179237Sjb} 473179237Sjb 474179237Sjb/* Function to handle DTrace traps during probes. See i386/i386/trap.c */ 475179237Sjbint 476179237Sjbdtrace_trap(struct trapframe *frame, u_int type) 477179237Sjb{ 478179237Sjb /* 479179237Sjb * A trap can occur while DTrace executes a probe. Before 480179237Sjb * executing the probe, DTrace blocks re-scheduling and sets 481179237Sjb * a flag in it's per-cpu flags to indicate that it doesn't 482218909Sbrucec * want to fault. On returning from the probe, the no-fault 483179237Sjb * flag is cleared and finally re-scheduling is enabled. 484179237Sjb * 485179237Sjb * Check if DTrace has enabled 'no-fault' mode: 486179237Sjb * 487179237Sjb */ 488179237Sjb if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { 489179237Sjb /* 490179237Sjb * There are only a couple of trap types that are expected. 491179237Sjb * All the rest will be handled in the usual way. 492179237Sjb */ 493179237Sjb switch (type) { 494179237Sjb /* General protection fault. */ 495179237Sjb case T_PROTFLT: 496179237Sjb /* Flag an illegal operation. */ 497179237Sjb cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; 498179237Sjb 499179237Sjb /* 500179237Sjb * Offset the instruction pointer to the instruction 501179237Sjb * following the one causing the fault. 502179237Sjb */ 503179237Sjb frame->tf_eip += dtrace_instr_size((u_char *) frame->tf_eip); 504179237Sjb return (1); 505179237Sjb /* Page fault. */ 506179237Sjb case T_PAGEFLT: 507179237Sjb /* Flag a bad address. */ 508179237Sjb cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; 509179237Sjb cpu_core[curcpu].cpuc_dtrace_illval = rcr2(); 510179237Sjb 511179237Sjb /* 512179237Sjb * Offset the instruction pointer to the instruction 513179237Sjb * following the one causing the fault. 514179237Sjb */ 515179237Sjb frame->tf_eip += dtrace_instr_size((u_char *) frame->tf_eip); 516179237Sjb return (1); 517179237Sjb default: 518179237Sjb /* Handle all other traps in the usual way. */ 519179237Sjb break; 520179237Sjb } 521179237Sjb } 522179237Sjb 523179237Sjb /* Handle the trap in the usual way. */ 524179237Sjb return (0); 525179237Sjb} 526