linux/arch/arm64/kernel/traps.c
<<
>>
Prefs
   1/*
   2 * Based on arch/arm/kernel/traps.c
   3 *
   4 * Copyright (C) 1995-2009 Russell King
   5 * Copyright (C) 2012 ARM Ltd.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include <linux/bug.h>
  21#include <linux/signal.h>
  22#include <linux/personality.h>
  23#include <linux/kallsyms.h>
  24#include <linux/spinlock.h>
  25#include <linux/uaccess.h>
  26#include <linux/hardirq.h>
  27#include <linux/kdebug.h>
  28#include <linux/module.h>
  29#include <linux/kexec.h>
  30#include <linux/delay.h>
  31#include <linux/init.h>
  32#include <linux/sched.h>
  33#include <linux/syscalls.h>
  34
  35#include <asm/atomic.h>
  36#include <asm/bug.h>
  37#include <asm/debug-monitors.h>
  38#include <asm/esr.h>
  39#include <asm/insn.h>
  40#include <asm/traps.h>
  41#include <asm/stacktrace.h>
  42#include <asm/exception.h>
  43#include <asm/system_misc.h>
  44#include <asm/sysreg.h>
  45
  46static const char *handler[]= {
  47        "Synchronous Abort",
  48        "IRQ",
  49        "FIQ",
  50        "Error"
  51};
  52
  53int show_unhandled_signals = 1;
  54
  55/*
  56 * Dump out the contents of some kernel memory nicely...
  57 */
  58static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
  59                     unsigned long top)
  60{
  61        unsigned long first;
  62        mm_segment_t fs;
  63        int i;
  64
  65        /*
  66         * We need to switch to kernel mode so that we can use __get_user
  67         * to safely read from kernel space.
  68         */
  69        fs = get_fs();
  70        set_fs(KERNEL_DS);
  71
  72        printk("%s%s(0x%016lx to 0x%016lx)\n", lvl, str, bottom, top);
  73
  74        for (first = bottom & ~31; first < top; first += 32) {
  75                unsigned long p;
  76                char str[sizeof(" 12345678") * 8 + 1];
  77
  78                memset(str, ' ', sizeof(str));
  79                str[sizeof(str) - 1] = '\0';
  80
  81                for (p = first, i = 0; i < (32 / 8)
  82                                        && p < top; i++, p += 8) {
  83                        if (p >= bottom && p < top) {
  84                                unsigned long val;
  85
  86                                if (__get_user(val, (unsigned long *)p) == 0)
  87                                        sprintf(str + i * 17, " %016lx", val);
  88                                else
  89                                        sprintf(str + i * 17, " ????????????????");
  90                        }
  91                }
  92                printk("%s%04lx:%s\n", lvl, first & 0xffff, str);
  93        }
  94
  95        set_fs(fs);
  96}
  97
  98static void dump_backtrace_entry(unsigned long where)
  99{
 100        /*
 101         * Note that 'where' can have a physical address, but it's not handled.
 102         */
 103        print_ip_sym(where);
 104}
 105
 106static void __dump_instr(const char *lvl, struct pt_regs *regs)
 107{
 108        unsigned long addr = instruction_pointer(regs);
 109        char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
 110        int i;
 111
 112        for (i = -4; i < 1; i++) {
 113                unsigned int val, bad;
 114
 115                bad = __get_user(val, &((u32 *)addr)[i]);
 116
 117                if (!bad)
 118                        p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val);
 119                else {
 120                        p += sprintf(p, "bad PC value");
 121                        break;
 122                }
 123        }
 124        printk("%sCode: %s\n", lvl, str);
 125}
 126
 127static void dump_instr(const char *lvl, struct pt_regs *regs)
 128{
 129        if (!user_mode(regs)) {
 130                mm_segment_t fs = get_fs();
 131                set_fs(KERNEL_DS);
 132                __dump_instr(lvl, regs);
 133                set_fs(fs);
 134        } else {
 135                __dump_instr(lvl, regs);
 136        }
 137}
 138
 139static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 140{
 141        struct stackframe frame;
 142        unsigned long irq_stack_ptr;
 143        int skip;
 144
 145        /*
 146         * Switching between stacks is valid when tracing current and in
 147         * non-preemptible context.
 148         */
 149        if (tsk == current && !preemptible())
 150                irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
 151        else
 152                irq_stack_ptr = 0;
 153
 154        pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 155
 156        if (!tsk)
 157                tsk = current;
 158
 159        if (tsk == current) {
 160                frame.fp = (unsigned long)__builtin_frame_address(0);
 161                frame.sp = current_stack_pointer;
 162                frame.pc = (unsigned long)dump_backtrace;
 163        } else {
 164                /*
 165                 * task blocked in __switch_to
 166                 */
 167                frame.fp = thread_saved_fp(tsk);
 168                frame.sp = thread_saved_sp(tsk);
 169                frame.pc = thread_saved_pc(tsk);
 170        }
 171#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 172        frame.graph = tsk->curr_ret_stack;
 173#endif
 174
 175        skip = !!regs;
 176        printk("Call trace:\n");
 177        while (1) {
 178                unsigned long where = frame.pc;
 179                unsigned long stack;
 180                int ret;
 181
 182                /* skip until specified stack frame */
 183                if (!skip) {
 184                        dump_backtrace_entry(where);
 185                } else if (frame.fp == regs->regs[29]) {
 186                        skip = 0;
 187                        /*
 188                         * Mostly, this is the case where this function is
 189                         * called in panic/abort. As exception handler's
 190                         * stack frame does not contain the corresponding pc
 191                         * at which an exception has taken place, use regs->pc
 192                         * instead.
 193                         */
 194                        dump_backtrace_entry(regs->pc);
 195                }
 196                ret = unwind_frame(tsk, &frame);
 197                if (ret < 0)
 198                        break;
 199                stack = frame.sp;
 200                if (in_exception_text(where)) {
 201                        /*
 202                         * If we switched to the irq_stack before calling this
 203                         * exception handler, then the pt_regs will be on the
 204                         * task stack. The easiest way to tell is if the large
 205                         * pt_regs would overlap with the end of the irq_stack.
 206                         */
 207                        if (stack < irq_stack_ptr &&
 208                            (stack + sizeof(struct pt_regs)) > irq_stack_ptr)
 209                                stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
 210
 211                        dump_mem("", "Exception stack", stack,
 212                                 stack + sizeof(struct pt_regs));
 213                }
 214        }
 215}
 216
 217void show_stack(struct task_struct *tsk, unsigned long *sp)
 218{
 219        dump_backtrace(NULL, tsk);
 220        barrier();
 221}
 222
 223#ifdef CONFIG_PREEMPT
 224#define S_PREEMPT " PREEMPT"
 225#else
 226#define S_PREEMPT ""
 227#endif
 228#define S_SMP " SMP"
 229
 230static int __die(const char *str, int err, struct thread_info *thread,
 231                 struct pt_regs *regs)
 232{
 233        struct task_struct *tsk = thread->task;
 234        static int die_counter;
 235        int ret;
 236
 237        pr_emerg("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
 238                 str, err, ++die_counter);
 239
 240        /* trap and error numbers are mostly meaningless on ARM */
 241        ret = notify_die(DIE_OOPS, str, regs, err, 0, SIGSEGV);
 242        if (ret == NOTIFY_STOP)
 243                return ret;
 244
 245        print_modules();
 246        __show_regs(regs);
 247        pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n",
 248                 TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1);
 249
 250        if (!user_mode(regs)) {
 251                dump_mem(KERN_EMERG, "Stack: ", regs->sp,
 252                         THREAD_SIZE + (unsigned long)task_stack_page(tsk));
 253                dump_backtrace(regs, tsk);
 254                dump_instr(KERN_EMERG, regs);
 255        }
 256
 257        return ret;
 258}
 259
 260static DEFINE_RAW_SPINLOCK(die_lock);
 261
 262/*
 263 * This function is protected against re-entrancy.
 264 */
 265void die(const char *str, struct pt_regs *regs, int err)
 266{
 267        struct thread_info *thread = current_thread_info();
 268        int ret;
 269
 270        oops_enter();
 271
 272        raw_spin_lock_irq(&die_lock);
 273        console_verbose();
 274        bust_spinlocks(1);
 275        ret = __die(str, err, thread, regs);
 276
 277        if (regs && kexec_should_crash(thread->task))
 278                crash_kexec(regs);
 279
 280        bust_spinlocks(0);
 281        add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
 282        raw_spin_unlock_irq(&die_lock);
 283        oops_exit();
 284
 285        if (in_interrupt())
 286                panic("Fatal exception in interrupt");
 287        if (panic_on_oops)
 288                panic("Fatal exception");
 289        if (ret != NOTIFY_STOP)
 290                do_exit(SIGSEGV);
 291}
 292
 293void arm64_notify_die(const char *str, struct pt_regs *regs,
 294                      struct siginfo *info, int err)
 295{
 296        if (user_mode(regs)) {
 297                current->thread.fault_address = 0;
 298                current->thread.fault_code = err;
 299                force_sig_info(info->si_signo, info, current);
 300        } else {
 301                die(str, regs, err);
 302        }
 303}
 304
 305static LIST_HEAD(undef_hook);
 306static DEFINE_RAW_SPINLOCK(undef_lock);
 307
 308void register_undef_hook(struct undef_hook *hook)
 309{
 310        unsigned long flags;
 311
 312        raw_spin_lock_irqsave(&undef_lock, flags);
 313        list_add(&hook->node, &undef_hook);
 314        raw_spin_unlock_irqrestore(&undef_lock, flags);
 315}
 316
 317void unregister_undef_hook(struct undef_hook *hook)
 318{
 319        unsigned long flags;
 320
 321        raw_spin_lock_irqsave(&undef_lock, flags);
 322        list_del(&hook->node);
 323        raw_spin_unlock_irqrestore(&undef_lock, flags);
 324}
 325
 326static int call_undef_hook(struct pt_regs *regs)
 327{
 328        struct undef_hook *hook;
 329        unsigned long flags;
 330        u32 instr;
 331        int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
 332        void __user *pc = (void __user *)instruction_pointer(regs);
 333
 334        if (!user_mode(regs))
 335                return 1;
 336
 337        if (compat_thumb_mode(regs)) {
 338                /* 16-bit Thumb instruction */
 339                if (get_user(instr, (u16 __user *)pc))
 340                        goto exit;
 341                instr = le16_to_cpu(instr);
 342                if (aarch32_insn_is_wide(instr)) {
 343                        u32 instr2;
 344
 345                        if (get_user(instr2, (u16 __user *)(pc + 2)))
 346                                goto exit;
 347                        instr2 = le16_to_cpu(instr2);
 348                        instr = (instr << 16) | instr2;
 349                }
 350        } else {
 351                /* 32-bit ARM instruction */
 352                if (get_user(instr, (u32 __user *)pc))
 353                        goto exit;
 354                instr = le32_to_cpu(instr);
 355        }
 356
 357        raw_spin_lock_irqsave(&undef_lock, flags);
 358        list_for_each_entry(hook, &undef_hook, node)
 359                if ((instr & hook->instr_mask) == hook->instr_val &&
 360                        (regs->pstate & hook->pstate_mask) == hook->pstate_val)
 361                        fn = hook->fn;
 362
 363        raw_spin_unlock_irqrestore(&undef_lock, flags);
 364exit:
 365        return fn ? fn(regs, instr) : 1;
 366}
 367
 368static void force_signal_inject(int signal, int code, struct pt_regs *regs,
 369                                unsigned long address)
 370{
 371        siginfo_t info;
 372        void __user *pc = (void __user *)instruction_pointer(regs);
 373        const char *desc;
 374
 375        switch (signal) {
 376        case SIGILL:
 377                desc = "undefined instruction";
 378                break;
 379        case SIGSEGV:
 380                desc = "illegal memory access";
 381                break;
 382        default:
 383                desc = "bad mode";
 384                break;
 385        }
 386
 387        if (unhandled_signal(current, signal) &&
 388            show_unhandled_signals_ratelimited()) {
 389                pr_info("%s[%d]: %s: pc=%p\n",
 390                        current->comm, task_pid_nr(current), desc, pc);
 391                dump_instr(KERN_INFO, regs);
 392        }
 393
 394        info.si_signo = signal;
 395        info.si_errno = 0;
 396        info.si_code  = code;
 397        info.si_addr  = pc;
 398
 399        arm64_notify_die(desc, regs, &info, 0);
 400}
 401
 402/*
 403 * Set up process info to signal segmentation fault - called on access error.
 404 */
 405void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr)
 406{
 407        int code;
 408
 409        down_read(&current->mm->mmap_sem);
 410        if (find_vma(current->mm, addr) == NULL)
 411                code = SEGV_MAPERR;
 412        else
 413                code = SEGV_ACCERR;
 414        up_read(&current->mm->mmap_sem);
 415
 416        force_signal_inject(SIGSEGV, code, regs, addr);
 417}
 418
 419asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 420{
 421        /* check for AArch32 breakpoint instructions */
 422        if (!aarch32_break_handler(regs))
 423                return;
 424
 425        if (call_undef_hook(regs) == 0)
 426                return;
 427
 428        force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
 429}
 430
 431void cpu_enable_cache_maint_trap(void *__unused)
 432{
 433        config_sctlr_el1(SCTLR_EL1_UCI, 0);
 434}
 435
 436#define __user_cache_maint(insn, address, res)                  \
 437        asm volatile (                                          \
 438                "1:     " insn ", %1\n"                         \
 439                "       mov     %w0, #0\n"                      \
 440                "2:\n"                                          \
 441                "       .pushsection .fixup,\"ax\"\n"           \
 442                "       .align  2\n"                            \
 443                "3:     mov     %w0, %w2\n"                     \
 444                "       b       2b\n"                           \
 445                "       .popsection\n"                          \
 446                _ASM_EXTABLE(1b, 3b)                            \
 447                : "=r" (res)                                    \
 448                : "r" (address), "i" (-EFAULT) )
 449
 450asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
 451{
 452        unsigned long address;
 453        int ret;
 454
 455        /* if this is a write with: Op0=1, Op2=1, Op1=3, CRn=7 */
 456        if ((esr & 0x01fffc01) == 0x0012dc00) {
 457                int rt = (esr >> 5) & 0x1f;
 458                int crm = (esr >> 1) & 0x0f;
 459
 460                address = (rt == 31) ? 0 : regs->regs[rt];
 461
 462                switch (crm) {
 463                case 11:                /* DC CVAU, gets promoted */
 464                        __user_cache_maint("dc civac", address, ret);
 465                        break;
 466                case 10:                /* DC CVAC, gets promoted */
 467                        __user_cache_maint("dc civac", address, ret);
 468                        break;
 469                case 14:                /* DC CIVAC */
 470                        __user_cache_maint("dc civac", address, ret);
 471                        break;
 472                case 5:                 /* IC IVAU */
 473                        __user_cache_maint("ic ivau", address, ret);
 474                        break;
 475                default:
 476                        force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
 477                        return;
 478                }
 479        } else {
 480                force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
 481                return;
 482        }
 483
 484        if (ret)
 485                arm64_notify_segfault(regs, address);
 486        else
 487                regs->pc += 4;
 488}
 489
 490long compat_arm_syscall(struct pt_regs *regs);
 491
 492asmlinkage long do_ni_syscall(struct pt_regs *regs)
 493{
 494#ifdef CONFIG_COMPAT
 495        long ret;
 496        if (is_compat_task()) {
 497                ret = compat_arm_syscall(regs);
 498                if (ret != -ENOSYS)
 499                        return ret;
 500        }
 501#endif
 502
 503        if (show_unhandled_signals_ratelimited()) {
 504                pr_info("%s[%d]: syscall %d\n", current->comm,
 505                        task_pid_nr(current), (int)regs->syscallno);
 506                dump_instr("", regs);
 507                if (user_mode(regs))
 508                        __show_regs(regs);
 509        }
 510
 511        return sys_ni_syscall();
 512}
 513
 514static const char *esr_class_str[] = {
 515        [0 ... ESR_ELx_EC_MAX]          = "UNRECOGNIZED EC",
 516        [ESR_ELx_EC_UNKNOWN]            = "Unknown/Uncategorized",
 517        [ESR_ELx_EC_WFx]                = "WFI/WFE",
 518        [ESR_ELx_EC_CP15_32]            = "CP15 MCR/MRC",
 519        [ESR_ELx_EC_CP15_64]            = "CP15 MCRR/MRRC",
 520        [ESR_ELx_EC_CP14_MR]            = "CP14 MCR/MRC",
 521        [ESR_ELx_EC_CP14_LS]            = "CP14 LDC/STC",
 522        [ESR_ELx_EC_FP_ASIMD]           = "ASIMD",
 523        [ESR_ELx_EC_CP10_ID]            = "CP10 MRC/VMRS",
 524        [ESR_ELx_EC_CP14_64]            = "CP14 MCRR/MRRC",
 525        [ESR_ELx_EC_ILL]                = "PSTATE.IL",
 526        [ESR_ELx_EC_SVC32]              = "SVC (AArch32)",
 527        [ESR_ELx_EC_HVC32]              = "HVC (AArch32)",
 528        [ESR_ELx_EC_SMC32]              = "SMC (AArch32)",
 529        [ESR_ELx_EC_SVC64]              = "SVC (AArch64)",
 530        [ESR_ELx_EC_HVC64]              = "HVC (AArch64)",
 531        [ESR_ELx_EC_SMC64]              = "SMC (AArch64)",
 532        [ESR_ELx_EC_SYS64]              = "MSR/MRS (AArch64)",
 533        [ESR_ELx_EC_IMP_DEF]            = "EL3 IMP DEF",
 534        [ESR_ELx_EC_IABT_LOW]           = "IABT (lower EL)",
 535        [ESR_ELx_EC_IABT_CUR]           = "IABT (current EL)",
 536        [ESR_ELx_EC_PC_ALIGN]           = "PC Alignment",
 537        [ESR_ELx_EC_DABT_LOW]           = "DABT (lower EL)",
 538        [ESR_ELx_EC_DABT_CUR]           = "DABT (current EL)",
 539        [ESR_ELx_EC_SP_ALIGN]           = "SP Alignment",
 540        [ESR_ELx_EC_FP_EXC32]           = "FP (AArch32)",
 541        [ESR_ELx_EC_FP_EXC64]           = "FP (AArch64)",
 542        [ESR_ELx_EC_SERROR]             = "SError",
 543        [ESR_ELx_EC_BREAKPT_LOW]        = "Breakpoint (lower EL)",
 544        [ESR_ELx_EC_BREAKPT_CUR]        = "Breakpoint (current EL)",
 545        [ESR_ELx_EC_SOFTSTP_LOW]        = "Software Step (lower EL)",
 546        [ESR_ELx_EC_SOFTSTP_CUR]        = "Software Step (current EL)",
 547        [ESR_ELx_EC_WATCHPT_LOW]        = "Watchpoint (lower EL)",
 548        [ESR_ELx_EC_WATCHPT_CUR]        = "Watchpoint (current EL)",
 549        [ESR_ELx_EC_BKPT32]             = "BKPT (AArch32)",
 550        [ESR_ELx_EC_VECTOR32]           = "Vector catch (AArch32)",
 551        [ESR_ELx_EC_BRK64]              = "BRK (AArch64)",
 552};
 553
 554const char *esr_get_class_string(u32 esr)
 555{
 556        return esr_class_str[ESR_ELx_EC(esr)];
 557}
 558
 559/*
 560 * bad_mode handles the impossible case in the exception vector.
 561 */
 562asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
 563{
 564        siginfo_t info;
 565        void __user *pc = (void __user *)instruction_pointer(regs);
 566        console_verbose();
 567
 568        pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %s\n",
 569                handler[reason], smp_processor_id(), esr,
 570                esr_get_class_string(esr));
 571        __show_regs(regs);
 572
 573        info.si_signo = SIGILL;
 574        info.si_errno = 0;
 575        info.si_code  = ILL_ILLOPC;
 576        info.si_addr  = pc;
 577
 578        arm64_notify_die("Oops - bad mode", regs, &info, 0);
 579}
 580
 581void __pte_error(const char *file, int line, unsigned long val)
 582{
 583        pr_err("%s:%d: bad pte %016lx.\n", file, line, val);
 584}
 585
 586void __pmd_error(const char *file, int line, unsigned long val)
 587{
 588        pr_err("%s:%d: bad pmd %016lx.\n", file, line, val);
 589}
 590
 591void __pud_error(const char *file, int line, unsigned long val)
 592{
 593        pr_err("%s:%d: bad pud %016lx.\n", file, line, val);
 594}
 595
 596void __pgd_error(const char *file, int line, unsigned long val)
 597{
 598        pr_err("%s:%d: bad pgd %016lx.\n", file, line, val);
 599}
 600
 601/* GENERIC_BUG traps */
 602
 603int is_valid_bugaddr(unsigned long addr)
 604{
 605        /*
 606         * bug_handler() only called for BRK #BUG_BRK_IMM.
 607         * So the answer is trivial -- any spurious instances with no
 608         * bug table entry will be rejected by report_bug() and passed
 609         * back to the debug-monitors code and handled as a fatal
 610         * unexpected debug exception.
 611         */
 612        return 1;
 613}
 614
 615static int bug_handler(struct pt_regs *regs, unsigned int esr)
 616{
 617        if (user_mode(regs))
 618                return DBG_HOOK_ERROR;
 619
 620        switch (report_bug(regs->pc, regs)) {
 621        case BUG_TRAP_TYPE_BUG:
 622                die("Oops - BUG", regs, 0);
 623                break;
 624
 625        case BUG_TRAP_TYPE_WARN:
 626                /* Ideally, report_bug() should backtrace for us... but no. */
 627                dump_backtrace(regs, NULL);
 628                break;
 629
 630        default:
 631                /* unknown/unrecognised bug trap type */
 632                return DBG_HOOK_ERROR;
 633        }
 634
 635        /* If thread survives, skip over the BUG instruction and continue: */
 636        regs->pc += AARCH64_INSN_SIZE;  /* skip BRK and resume */
 637        return DBG_HOOK_HANDLED;
 638}
 639
 640static struct break_hook bug_break_hook = {
 641        .esr_val = 0xf2000000 | BUG_BRK_IMM,
 642        .esr_mask = 0xffffffff,
 643        .fn = bug_handler,
 644};
 645
 646/*
 647 * Initial handler for AArch64 BRK exceptions
 648 * This handler only used until debug_traps_init().
 649 */
 650int __init early_brk64(unsigned long addr, unsigned int esr,
 651                struct pt_regs *regs)
 652{
 653        return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
 654}
 655
 656/* This registration must happen early, before debug_traps_init(). */
 657void __init trap_init(void)
 658{
 659        register_break_hook(&bug_break_hook);
 660}
 661