diff options
-rw-r--r-- | arch/parisc/kernel/entry.S | 141 | ||||
-rw-r--r-- | arch/parisc/kernel/signal.c | 72 | ||||
-rw-r--r-- | arch/parisc/kernel/syscall_table.S | 6 | ||||
-rw-r--r-- | include/asm-parisc/thread_info.h | 4 | ||||
-rw-r--r-- | include/asm-parisc/unistd.h | 2 |
5 files changed, 88 insertions, 137 deletions
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 39a12c1fc6f5..f965673e6863 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S | |||
@@ -978,11 +978,39 @@ intr_check_resched: | |||
978 | LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */ | 978 | LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */ |
979 | bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */ | 979 | bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */ |
980 | 980 | ||
981 | .import do_notify_resume,code | ||
981 | intr_check_sig: | 982 | intr_check_sig: |
982 | /* As above */ | 983 | /* As above */ |
983 | mfctl %cr30,%r1 | 984 | mfctl %cr30,%r1 |
984 | LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_SIGPENDING */ | 985 | LDREG TI_FLAGS(%r1),%r19 |
985 | bb,<,n %r19, 31-TIF_SIGPENDING, intr_do_signal /* forward */ | 986 | load32 (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r20 |
987 | and,COND(<>) %r19, %r20, %r0 | ||
988 | b,n intr_restore /* skip past if we've nothing to do */ | ||
989 | |||
990 | /* This check is critical to having LWS | ||
991 | * working. The IASQ is zero on the gateway | ||
992 | * page and we cannot deliver any signals until | ||
993 | * we get off the gateway page. | ||
994 | * | ||
995 | * Only do signals if we are returning to user space | ||
996 | */ | ||
997 | LDREG PT_IASQ0(%r16), %r20 | ||
998 | CMPIB= 0,%r20,intr_restore /* backward */ | ||
999 | nop | ||
1000 | LDREG PT_IASQ1(%r16), %r20 | ||
1001 | CMPIB= 0,%r20,intr_restore /* backward */ | ||
1002 | nop | ||
1003 | |||
1004 | copy %r0, %r25 /* long in_syscall = 0 */ | ||
1005 | #ifdef CONFIG_64BIT | ||
1006 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
1007 | #endif | ||
1008 | |||
1009 | BL do_notify_resume,%r2 | ||
1010 | copy %r16, %r26 /* struct pt_regs *regs */ | ||
1011 | |||
1012 | b intr_check_sig | ||
1013 | nop | ||
986 | 1014 | ||
987 | intr_restore: | 1015 | intr_restore: |
988 | copy %r16,%r29 | 1016 | copy %r16,%r29 |
@@ -1072,35 +1100,6 @@ intr_do_preempt: | |||
1072 | b,n intr_restore /* ssm PSW_SM_I done by intr_restore */ | 1100 | b,n intr_restore /* ssm PSW_SM_I done by intr_restore */ |
1073 | #endif /* CONFIG_PREEMPT */ | 1101 | #endif /* CONFIG_PREEMPT */ |
1074 | 1102 | ||
1075 | .import do_signal,code | ||
1076 | intr_do_signal: | ||
1077 | /* | ||
1078 | This check is critical to having LWS | ||
1079 | working. The IASQ is zero on the gateway | ||
1080 | page and we cannot deliver any signals until | ||
1081 | we get off the gateway page. | ||
1082 | |||
1083 | Only do signals if we are returning to user space | ||
1084 | */ | ||
1085 | LDREG PT_IASQ0(%r16), %r20 | ||
1086 | CMPIB= 0,%r20,intr_restore /* backward */ | ||
1087 | nop | ||
1088 | LDREG PT_IASQ1(%r16), %r20 | ||
1089 | CMPIB= 0,%r20,intr_restore /* backward */ | ||
1090 | nop | ||
1091 | |||
1092 | copy %r0, %r24 /* unsigned long in_syscall */ | ||
1093 | copy %r16, %r25 /* struct pt_regs *regs */ | ||
1094 | #ifdef CONFIG_64BIT | ||
1095 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
1096 | #endif | ||
1097 | |||
1098 | BL do_signal,%r2 | ||
1099 | copy %r0, %r26 /* sigset_t *oldset = NULL */ | ||
1100 | |||
1101 | b intr_check_sig | ||
1102 | nop | ||
1103 | |||
1104 | /* | 1103 | /* |
1105 | * External interrupts. | 1104 | * External interrupts. |
1106 | */ | 1105 | */ |
@@ -2024,32 +2023,6 @@ sys32_sigaltstack_wrapper: | |||
2024 | nop | 2023 | nop |
2025 | #endif | 2024 | #endif |
2026 | 2025 | ||
2027 | .export sys_rt_sigsuspend_wrapper | ||
2028 | sys_rt_sigsuspend_wrapper: | ||
2029 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 | ||
2030 | ldo TASK_REGS(%r1),%r24 | ||
2031 | reg_save %r24 | ||
2032 | |||
2033 | STREG %r2, -RP_OFFSET(%r30) | ||
2034 | #ifdef CONFIG_64BIT | ||
2035 | ldo FRAME_SIZE(%r30), %r30 | ||
2036 | BL sys_rt_sigsuspend,%r2 | ||
2037 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
2038 | #else | ||
2039 | BL sys_rt_sigsuspend,%r2 | ||
2040 | ldo FRAME_SIZE(%r30), %r30 | ||
2041 | #endif | ||
2042 | |||
2043 | ldo -FRAME_SIZE(%r30), %r30 | ||
2044 | LDREG -RP_OFFSET(%r30), %r2 | ||
2045 | |||
2046 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 | ||
2047 | ldo TASK_REGS(%r1),%r1 | ||
2048 | reg_restore %r1 | ||
2049 | |||
2050 | bv %r0(%r2) | ||
2051 | nop | ||
2052 | |||
2053 | .export syscall_exit | 2026 | .export syscall_exit |
2054 | syscall_exit: | 2027 | syscall_exit: |
2055 | 2028 | ||
@@ -2115,9 +2088,35 @@ syscall_check_resched: | |||
2115 | LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */ | 2088 | LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */ |
2116 | bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */ | 2089 | bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */ |
2117 | 2090 | ||
2091 | .import do_signal,code | ||
2118 | syscall_check_sig: | 2092 | syscall_check_sig: |
2119 | LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* get ti flags */ | 2093 | LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 |
2120 | bb,<,n %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */ | 2094 | load32 (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r26 |
2095 | and,COND(<>) %r19, %r26, %r0 | ||
2096 | b,n syscall_restore /* skip past if we've nothing to do */ | ||
2097 | |||
2098 | syscall_do_signal: | ||
2099 | /* Save callee-save registers (for sigcontext). | ||
2100 | * FIXME: After this point the process structure should be | ||
2101 | * consistent with all the relevant state of the process | ||
2102 | * before the syscall. We need to verify this. | ||
2103 | */ | ||
2104 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 | ||
2105 | ldo TASK_REGS(%r1), %r26 /* struct pt_regs *regs */ | ||
2106 | reg_save %r26 | ||
2107 | |||
2108 | #ifdef CONFIG_64BIT | ||
2109 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
2110 | #endif | ||
2111 | |||
2112 | BL do_notify_resume,%r2 | ||
2113 | ldi 1, %r25 /* long in_syscall = 1 */ | ||
2114 | |||
2115 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 | ||
2116 | ldo TASK_REGS(%r1), %r20 /* reload pt_regs */ | ||
2117 | reg_restore %r20 | ||
2118 | |||
2119 | b,n syscall_check_sig | ||
2121 | 2120 | ||
2122 | syscall_restore: | 2121 | syscall_restore: |
2123 | /* Are we being ptraced? */ | 2122 | /* Are we being ptraced? */ |
@@ -2256,30 +2255,6 @@ syscall_do_resched: | |||
2256 | b syscall_check_bh /* if resched, we start over again */ | 2255 | b syscall_check_bh /* if resched, we start over again */ |
2257 | nop | 2256 | nop |
2258 | 2257 | ||
2259 | .import do_signal,code | ||
2260 | syscall_do_signal: | ||
2261 | /* Save callee-save registers (for sigcontext). | ||
2262 | FIXME: After this point the process structure should be | ||
2263 | consistent with all the relevant state of the process | ||
2264 | before the syscall. We need to verify this. */ | ||
2265 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 | ||
2266 | ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */ | ||
2267 | reg_save %r25 | ||
2268 | |||
2269 | ldi 1, %r24 /* unsigned long in_syscall */ | ||
2270 | |||
2271 | #ifdef CONFIG_64BIT | ||
2272 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
2273 | #endif | ||
2274 | BL do_signal,%r2 | ||
2275 | copy %r0, %r26 /* sigset_t *oldset = NULL */ | ||
2276 | |||
2277 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 | ||
2278 | ldo TASK_REGS(%r1), %r20 /* reload pt_regs */ | ||
2279 | reg_restore %r20 | ||
2280 | |||
2281 | b,n syscall_check_sig | ||
2282 | |||
2283 | /* | 2258 | /* |
2284 | * get_register is used by the non access tlb miss handlers to | 2259 | * get_register is used by the non access tlb miss handlers to |
2285 | * copy the value of the general register specified in r8 into | 2260 | * copy the value of the general register specified in r8 into |
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index ee6653edeb7a..8d781b0e668b 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c | |||
@@ -59,8 +59,6 @@ | |||
59 | * this. */ | 59 | * this. */ |
60 | #define A(__x) ((unsigned long)(__x)) | 60 | #define A(__x) ((unsigned long)(__x)) |
61 | 61 | ||
62 | int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall); | ||
63 | |||
64 | /* | 62 | /* |
65 | * Atomically swap in the new signal mask, and wait for a signal. | 63 | * Atomically swap in the new signal mask, and wait for a signal. |
66 | */ | 64 | */ |
@@ -68,49 +66,6 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall); | |||
68 | #include "sys32.h" | 66 | #include "sys32.h" |
69 | #endif | 67 | #endif |
70 | 68 | ||
71 | asmlinkage int | ||
72 | sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs) | ||
73 | { | ||
74 | sigset_t saveset, newset; | ||
75 | #ifdef __LP64__ | ||
76 | compat_sigset_t newset32; | ||
77 | |||
78 | if (is_compat_task()) { | ||
79 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
80 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
81 | return -EINVAL; | ||
82 | if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32))) | ||
83 | return -EFAULT; | ||
84 | sigset_32to64(&newset,&newset32); | ||
85 | |||
86 | } else | ||
87 | #endif | ||
88 | { | ||
89 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
90 | if (sigsetsize != sizeof(sigset_t)) | ||
91 | return -EINVAL; | ||
92 | |||
93 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
94 | return -EFAULT; | ||
95 | } | ||
96 | |||
97 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
98 | |||
99 | spin_lock_irq(¤t->sighand->siglock); | ||
100 | saveset = current->blocked; | ||
101 | current->blocked = newset; | ||
102 | recalc_sigpending(); | ||
103 | spin_unlock_irq(¤t->sighand->siglock); | ||
104 | |||
105 | regs->gr[28] = -EINTR; | ||
106 | while (1) { | ||
107 | current->state = TASK_INTERRUPTIBLE; | ||
108 | schedule(); | ||
109 | if (do_signal(&saveset, regs, 1)) | ||
110 | return -EINTR; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | /* | 69 | /* |
115 | * Do a signal return - restore sigcontext. | 70 | * Do a signal return - restore sigcontext. |
116 | */ | 71 | */ |
@@ -528,12 +483,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
528 | * us due to the magic of delayed branching. | 483 | * us due to the magic of delayed branching. |
529 | */ | 484 | */ |
530 | 485 | ||
531 | asmlinkage int | 486 | asmlinkage void |
532 | do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) | 487 | do_signal(struct pt_regs *regs, long in_syscall) |
533 | { | 488 | { |
534 | siginfo_t info; | 489 | siginfo_t info; |
535 | struct k_sigaction ka; | 490 | struct k_sigaction ka; |
536 | int signr; | 491 | int signr; |
492 | sigset_t *oldset; | ||
537 | 493 | ||
538 | DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n", | 494 | DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n", |
539 | oldset, regs, regs->sr[7], in_syscall); | 495 | oldset, regs, regs->sr[7], in_syscall); |
@@ -543,7 +499,9 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) | |||
543 | we would be called in that case, but for some reason we | 499 | we would be called in that case, but for some reason we |
544 | are. */ | 500 | are. */ |
545 | 501 | ||
546 | if (!oldset) | 502 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
503 | oldset = ¤t->saved_sigmask; | ||
504 | else | ||
547 | oldset = ¤t->blocked; | 505 | oldset = ¤t->blocked; |
548 | 506 | ||
549 | DBG(1,"do_signal: oldset %08lx / %08lx\n", | 507 | DBG(1,"do_signal: oldset %08lx / %08lx\n", |
@@ -592,7 +550,9 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) | |||
592 | if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) { | 550 | if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) { |
593 | DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", | 551 | DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", |
594 | regs->gr[28]); | 552 | regs->gr[28]); |
595 | return 1; | 553 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
554 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
555 | return; | ||
596 | } | 556 | } |
597 | } | 557 | } |
598 | /* end of while(1) looping forever if we can't force a signal */ | 558 | /* end of while(1) looping forever if we can't force a signal */ |
@@ -653,5 +613,17 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) | |||
653 | DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", | 613 | DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", |
654 | regs->gr[28]); | 614 | regs->gr[28]); |
655 | 615 | ||
656 | return 0; | 616 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |
617 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
618 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
619 | } | ||
620 | |||
621 | return; | ||
622 | } | ||
623 | |||
624 | void do_notify_resume(struct pt_regs *regs, long in_syscall) | ||
625 | { | ||
626 | if (test_thread_flag(TIF_SIGPENDING) || | ||
627 | test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
628 | do_signal(regs, in_syscall); | ||
657 | } | 629 | } |
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 15d9c635d6a6..7f037b72ad03 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S | |||
@@ -283,7 +283,7 @@ | |||
283 | * struct from a 32-bit user-space app. | 283 | * struct from a 32-bit user-space app. |
284 | */ | 284 | */ |
285 | ENTRY_SAME(rt_sigqueueinfo) | 285 | ENTRY_SAME(rt_sigqueueinfo) |
286 | ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */ | 286 | ENTRY_COMP(rt_sigsuspend) |
287 | ENTRY_SAME(chown) /* 180 */ | 287 | ENTRY_SAME(chown) /* 180 */ |
288 | /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */ | 288 | /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */ |
289 | ENTRY_COMP(setsockopt) | 289 | ENTRY_COMP(setsockopt) |
@@ -377,8 +377,8 @@ | |||
377 | ENTRY_SAME(inotify_init) | 377 | ENTRY_SAME(inotify_init) |
378 | ENTRY_SAME(inotify_add_watch) /* 270 */ | 378 | ENTRY_SAME(inotify_add_watch) /* 270 */ |
379 | ENTRY_SAME(inotify_rm_watch) | 379 | ENTRY_SAME(inotify_rm_watch) |
380 | ENTRY_SAME(ni_syscall) /* 271 ENTRY_COMP(pselect6) */ | 380 | ENTRY_COMP(pselect6) |
381 | ENTRY_SAME(ni_syscall) /* 272 ENTRY_COMP(ppoll) */ | 381 | ENTRY_COMP(ppoll) |
382 | ENTRY_SAME(migrate_pages) | 382 | ENTRY_SAME(migrate_pages) |
383 | ENTRY_COMP(openat) /* 275 */ | 383 | ENTRY_COMP(openat) /* 275 */ |
384 | ENTRY_SAME(mkdirat) | 384 | ENTRY_SAME(mkdirat) |
diff --git a/include/asm-parisc/thread_info.h b/include/asm-parisc/thread_info.h index f2f83b04cd8b..949314cf6188 100644 --- a/include/asm-parisc/thread_info.h +++ b/include/asm-parisc/thread_info.h | |||
@@ -62,6 +62,7 @@ struct thread_info { | |||
62 | #define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling TIF_NEED_RESCHED */ | 62 | #define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling TIF_NEED_RESCHED */ |
63 | #define TIF_32BIT 5 /* 32 bit binary */ | 63 | #define TIF_32BIT 5 /* 32 bit binary */ |
64 | #define TIF_MEMDIE 6 | 64 | #define TIF_MEMDIE 6 |
65 | #define TIF_RESTORE_SIGMASK 7 /* restore saved signal mask */ | ||
65 | 66 | ||
66 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | 67 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) |
67 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | 68 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) |
@@ -69,9 +70,10 @@ struct thread_info { | |||
69 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 70 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
70 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | 71 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) |
71 | #define _TIF_32BIT (1 << TIF_32BIT) | 72 | #define _TIF_32BIT (1 << TIF_32BIT) |
73 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | ||
72 | 74 | ||
73 | #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ | 75 | #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ |
74 | _TIF_NEED_RESCHED) | 76 | _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK) |
75 | 77 | ||
76 | #endif /* __KERNEL__ */ | 78 | #endif /* __KERNEL__ */ |
77 | 79 | ||
diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h index 3fb37cfcb864..7c1bb8b0a96b 100644 --- a/include/asm-parisc/unistd.h +++ b/include/asm-parisc/unistd.h | |||
@@ -955,6 +955,8 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ | |||
955 | #define __ARCH_WANT_SYS_SIGPENDING | 955 | #define __ARCH_WANT_SYS_SIGPENDING |
956 | #define __ARCH_WANT_SYS_SIGPROCMASK | 956 | #define __ARCH_WANT_SYS_SIGPROCMASK |
957 | #define __ARCH_WANT_SYS_RT_SIGACTION | 957 | #define __ARCH_WANT_SYS_RT_SIGACTION |
958 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | ||
959 | #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND | ||
958 | 960 | ||
959 | #endif /* __ASSEMBLY__ */ | 961 | #endif /* __ASSEMBLY__ */ |
960 | 962 | ||