1 /*-
2 * Copyright (c) 2001 Jake Burkholder.
3 * Copyright (c) 1992 Terrence R. Lambert.
4 * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * William Jolitz.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
39 * from: FreeBSD: src/sys/i386/i386/machdep.c,v 1.477 2001/08/27
40 * $FreeBSD: releng/5.0/sys/sparc64/sparc64/machdep.c 109037 2003-01-10 00:58:11Z jake $
41 */
42
43 #include "opt_compat.h"
44 #include "opt_ddb.h"
45 #include "opt_msgbuf.h"
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/cons.h>
50 #include <sys/imgact.h>
51 #include <sys/kernel.h>
52 #include <sys/ktr.h>
53 #include <sys/linker.h>
54 #include <sys/lock.h>
55 #include <sys/malloc.h>
56 #include <sys/msgbuf.h>
57 #include <sys/mutex.h>
58 #include <sys/pcpu.h>
59 #include <sys/proc.h>
60 #include <sys/reboot.h>
61 #include <sys/bio.h>
62 #include <sys/buf.h>
63 #include <sys/bus.h>
64 #include <sys/eventhandler.h>
65 #include <sys/interrupt.h>
66 #include <sys/ptrace.h>
67 #include <sys/signalvar.h>
68 #include <sys/smp.h>
69 #include <sys/sysent.h>
70 #include <sys/sysproto.h>
71 #include <sys/timetc.h>
72 #include <sys/user.h>
73 #include <sys/ucontext.h>
74 #include <sys/user.h>
75 #include <sys/ucontext.h>
76 #include <sys/exec.h>
77
78 #include <dev/ofw/openfirm.h>
79
80 #include <vm/vm.h>
81 #include <vm/vm_param.h>
82 #include <vm/vm_kern.h>
83 #include <vm/vm_object.h>
84 #include <vm/vm_page.h>
85 #include <vm/vm_map.h>
86 #include <vm/vm_pager.h>
87 #include <vm/vm_extern.h>
88
89 #include <ddb/ddb.h>
90
91 #include <machine/cache.h>
92 #include <machine/clock.h>
93 #include <machine/cpu.h>
94 #include <machine/fp.h>
95 #include <machine/intr_machdep.h>
96 #include <machine/md_var.h>
97 #include <machine/metadata.h>
98 #include <machine/ofw_machdep.h>
99 #include <machine/smp.h>
100 #include <machine/pmap.h>
101 #include <machine/pstate.h>
102 #include <machine/reg.h>
103 #include <machine/sigframe.h>
104 #include <machine/tick.h>
105 #include <machine/tlb.h>
106 #include <machine/tstate.h>
107 #include <machine/upa.h>
108 #include <machine/ver.h>
109
110 typedef int ofw_vec_t(void *);
111
112 struct tlb_entry *kernel_tlbs;
113 int kernel_tlb_slots;
114
115 int cold = 1;
116 long Maxmem;
117
118 char pcpu0[PCPU_PAGES * PAGE_SIZE];
119 char uarea0[UAREA_PAGES * PAGE_SIZE];
120 struct trapframe frame0;
121
122 vm_offset_t kstack0;
123 vm_offset_t kstack0_phys;
124
125 struct kva_md_info kmi;
126
127 u_long ofw_vec;
128 u_long ofw_tba;
129
130 static struct timecounter tick_tc;
131
132 char sparc64_model[32];
133
134 static timecounter_get_t tick_get_timecount;
135 void sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3,
136 ofw_vec_t *vec);
137 void sparc64_shutdown_final(void *dummy, int howto);
138
139 static void cpu_startup(void *);
140 SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
141
142 CTASSERT((1 << INT_SHIFT) == sizeof(int));
143 CTASSERT((1 << PTR_SHIFT) == sizeof(char *));
144
145 CTASSERT(sizeof(struct reg) == 256);
146 CTASSERT(sizeof(struct fpreg) == 272);
147 CTASSERT(sizeof(struct __mcontext) == 512);
148
149 CTASSERT(sizeof(struct pcpu) <= ((PCPU_PAGES * PAGE_SIZE) / 2));
150
151 static void
152 cpu_startup(void *arg)
153 {
154
155 tick_tc.tc_get_timecount = tick_get_timecount;
156 tick_tc.tc_poll_pps = NULL;
157 tick_tc.tc_counter_mask = ~0u;
158 tick_tc.tc_frequency = tick_freq;
159 tick_tc.tc_name = "tick";
160 tc_init(&tick_tc);
161
162 cpu_identify(rdpr(ver), tick_freq, PCPU_GET(cpuid));
163 printf("Model: %s\n", sparc64_model);
164
165 vm_ksubmap_init(&kmi);
166
167 bufinit();
168 vm_pager_bufferinit();
169
170 EVENTHANDLER_REGISTER(shutdown_final, sparc64_shutdown_final, NULL,
171 SHUTDOWN_PRI_LAST);
172 }
173
174 void
175 cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
176 {
177 struct intr_request *ir;
178 int i;
179
180 pcpu->pc_irtail = &pcpu->pc_irhead;
181 for (i = 0; i < IR_FREE; i++) {
182 ir = &pcpu->pc_irpool[i];
183 ir->ir_next = pcpu->pc_irfree;
184 pcpu->pc_irfree = ir;
185 }
186 }
187
188 unsigned
189 tick_get_timecount(struct timecounter *tc)
190 {
191 return ((unsigned)rd(tick));
192 }
193
194 void
195 sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec)
196 {
197 phandle_t child;
198 phandle_t root;
199 struct pcpu *pc;
200 vm_offset_t end;
201 vm_offset_t va;
202 caddr_t kmdp;
203 u_int clock;
204 char *env;
205 char type[8];
206
207 end = 0;
208 kmdp = NULL;
209
210 /*
211 * Initialize openfirmware (needed for console).
212 */
213 OF_init(vec);
214
215 /*
216 * Parse metadata if present and fetch parameters. Must be before the
217 * console is inited so cninit gets the right value of boothowto.
218 */
219 if (mdp != NULL) {
220 preload_metadata = mdp;
221 kmdp = preload_search_by_type("elf kernel");
222 if (kmdp != NULL) {
223 boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
224 kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
225 end = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
226 kernel_tlb_slots = MD_FETCH(kmdp, MODINFOMD_DTLB_SLOTS,
227 int);
228 kernel_tlbs = (void *)preload_search_info(kmdp,
229 MODINFO_METADATA | MODINFOMD_DTLB);
230 }
231 }
232
233 /*
234 * Initialize the console before printing anything.
235 */
236 cninit();
237
238 /*
239 * Panic is there is no metadata. Most likely the kernel was booted
240 * directly, instead of through loader(8).
241 */
242 if (mdp == NULL || kmdp == NULL) {
243 printf("sparc64_init: no loader metadata.\n"
244 "This probably means you are not using loader(8).\n");
245 panic("sparc64_init");
246 }
247
248 /*
249 * Sanity check the kernel end, which is important.
250 */
251 if (end == 0) {
252 printf("sparc64_init: warning, kernel end not specified.\n"
253 "Attempting to continue anyway.\n");
254 end = (vm_offset_t)_end;
255 }
256
257 root = OF_peer(0);
258 for (child = OF_child(root); child != 0; child = OF_peer(child)) {
259 OF_getprop(child, "device_type", type, sizeof(type));
260 if (strcmp(type, "cpu") == 0)
261 break;
262 }
263 if (child == 0)
264 panic("cpu_startup: no cpu\n");
265 OF_getprop(child, "#dtlb-entries", &tlb_dtlb_entries,
266 sizeof(tlb_dtlb_entries));
267 OF_getprop(child, "#itlb-entries", &tlb_itlb_entries,
268 sizeof(tlb_itlb_entries));
269
270 cache_init(child);
271
272 #ifdef DDB
273 kdb_init();
274 #endif
275
276 #ifdef SMP
277 mp_tramp = mp_tramp_alloc();
278 #endif
279
280 /*
281 * Initialize virtual memory and calculate physmem.
282 */
283 pmap_bootstrap(end);
284
285 /*
286 * Initialize tunables.
287 */
288 init_param1();
289 init_param2(physmem);
290 env = getenv("kernelname");
291 if (env != NULL) {
292 strlcpy(kernelname, env, sizeof(kernelname));
293 freeenv(env);
294 }
295
296 /*
297 * Disable tick for now.
298 */
299 tick_stop();
300
301 /*
302 * Initialize the interrupt tables.
303 */
304 intr_init1();
305
306 /*
307 * Initialize proc0 stuff (p_contested needs to be done early).
308 */
309 proc_linkup(&proc0, &ksegrp0, &kse0, &thread0);
310 proc0.p_md.md_sigtramp = NULL;
311 proc0.p_md.md_utrap = NULL;
312 proc0.p_uarea = (struct user *)uarea0;
313 proc0.p_stats = &proc0.p_uarea->u_stats;
314 thread0.td_kstack = kstack0;
315 thread0.td_pcb = (struct pcb *)
316 (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
317 frame0.tf_tstate = TSTATE_IE | TSTATE_PEF | TSTATE_PRIV;
318 thread0.td_frame = &frame0;
319
320 /*
321 * Prime our per-cpu data page for use. Note, we are using it for our
322 * stack, so don't pass the real size (PAGE_SIZE) to pcpu_init or
323 * it'll zero it out from under us.
324 */
325 pc = (struct pcpu *)(pcpu0 + (PCPU_PAGES * PAGE_SIZE)) - 1;
326 pcpu_init(pc, 0, sizeof(struct pcpu));
327 pc->pc_curthread = &thread0;
328 pc->pc_curpcb = thread0.td_pcb;
329 pc->pc_mid = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG));
330 pc->pc_addr = (vm_offset_t)pcpu0;
331 pc->pc_node = child;
332 pc->pc_tlb_ctx = TLB_CTX_USER_MIN;
333 pc->pc_tlb_ctx_min = TLB_CTX_USER_MIN;
334 pc->pc_tlb_ctx_max = TLB_CTX_USER_MAX;
335
336 /*
337 * Initialize global registers.
338 */
339 cpu_setregs(pc);
340
341 /*
342 * Map and initialize the message buffer (after setting trap table).
343 */
344 va = (vm_offset_t)msgbufp;
345 pmap_map(&va, msgbuf_phys, msgbuf_phys + MSGBUF_SIZE, 0);
346 msgbufinit(msgbufp, MSGBUF_SIZE);
347
348 mutex_init();
349 intr_init2();
350
351 OF_getprop(PCPU_GET(node), "clock-frequency", &clock, sizeof(clock));
352 tick_init(clock);
353
354 OF_getprop(root, "name", sparc64_model, sizeof(sparc64_model) - 1);
355 }
356
357 void
358 set_openfirm_callback(ofw_vec_t *vec)
359 {
360 ofw_tba = rdpr(tba);
361 ofw_vec = (u_long)vec;
362 }
363
364 void
365 sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
366 {
367 struct trapframe *tf;
368 struct sigframe *sfp;
369 struct sigacts *psp;
370 struct sigframe sf;
371 struct thread *td;
372 struct frame *fp;
373 struct proc *p;
374 int oonstack;
375 u_long sp;
376
377 oonstack = 0;
378 td = curthread;
379 p = td->td_proc;
380 psp = p->p_sigacts;
381 tf = td->td_frame;
382 sp = tf->tf_sp + SPOFF;
383 oonstack = sigonstack(sp);
384
385 CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
386 catcher, sig);
387
388 /* Make sure we have a signal trampoline to return to. */
389 if (p->p_md.md_sigtramp == NULL) {
390 /*
391 * No signal tramoline... kill the process.
392 */
393 CTR0(KTR_SIG, "sendsig: no sigtramp");
394 printf("sendsig: %s is too old, rebuild it\n", p->p_comm);
395 sigexit(td, sig);
396 /* NOTREACHED */
397 }
398
399 /* Save user context. */
400 bzero(&sf, sizeof(sf));
401 sf.sf_uc.uc_sigmask = *mask;
402 sf.sf_uc.uc_stack = p->p_sigstk;
403 sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
404 ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
405 bcopy(tf, &sf.sf_uc.uc_mcontext, sizeof(*tf));
406
407 /* Allocate and validate space for the signal handler context. */
408 if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack &&
409 SIGISMEMBER(psp->ps_sigonstack, sig)) {
410 sfp = (struct sigframe *)(p->p_sigstk.ss_sp +
411 p->p_sigstk.ss_size - sizeof(struct sigframe));
412 } else
413 sfp = (struct sigframe *)sp - 1;
414 PROC_UNLOCK(p);
415
416 fp = (struct frame *)sfp - 1;
417
418 /* Translate the signal if appropriate. */
419 if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
420 sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
421
422 /* Build the argument list for the signal handler. */
423 tf->tf_out[0] = sig;
424 tf->tf_out[1] = (register_t)&sfp->sf_si;
425 tf->tf_out[2] = (register_t)&sfp->sf_uc;
426 tf->tf_out[4] = (register_t)catcher;
427 /* Fill siginfo structure. */
428 sf.sf_si.si_signo = sig;
429 sf.sf_si.si_code = code;
430 sf.sf_si.si_addr = (void *)tf->tf_sfar;
431
432 /* Copy the sigframe out to the user's stack. */
433 if (rwindow_save(td) != 0 || copyout(&sf, sfp, sizeof(*sfp)) != 0 ||
434 suword(&fp->fr_in[6], tf->tf_out[6]) != 0) {
435 /*
436 * Something is wrong with the stack pointer.
437 * ...Kill the process.
438 */
439 CTR2(KTR_SIG, "sendsig: sigexit td=%p sfp=%p", td, sfp);
440 PROC_LOCK(p);
441 sigexit(td, SIGILL);
442 /* NOTREACHED */
443 }
444
445 tf->tf_tpc = (u_long)p->p_md.md_sigtramp;
446 tf->tf_tnpc = tf->tf_tpc + 4;
447 tf->tf_sp = (u_long)fp - SPOFF;
448
449 CTR3(KTR_SIG, "sendsig: return td=%p pc=%#lx sp=%#lx", td, tf->tf_tpc,
450 tf->tf_sp);
451
452 PROC_LOCK(p);
453 }
454
455 #ifndef _SYS_SYSPROTO_H_
456 struct sigreturn_args {
457 ucontext_t *ucp;
458 };
459 #endif
460
461 /*
462 * MPSAFE
463 */
464 int
465 sigreturn(struct thread *td, struct sigreturn_args *uap)
466 {
467 struct trapframe *tf;
468 struct proc *p;
469 mcontext_t *mc;
470 ucontext_t uc;
471
472 p = td->td_proc;
473 if (rwindow_save(td)) {
474 PROC_LOCK(p);
475 sigexit(td, SIGILL);
476 }
477
478 CTR2(KTR_SIG, "sigreturn: td=%p ucp=%p", td, uap->sigcntxp);
479 if (copyin(uap->sigcntxp, &uc, sizeof(uc)) != 0) {
480 CTR1(KTR_SIG, "sigreturn: efault td=%p", td);
481 return (EFAULT);
482 }
483
484 mc = &uc.uc_mcontext;
485 tf = td->td_frame;
486 if (!TSTATE_SECURE(mc->mc_tstate))
487 return (EINVAL);
488 mc->mc_wstate = tf->tf_wstate;
489 bcopy(mc, tf, sizeof(*tf));
490
491 PROC_LOCK(p);
492 p->p_sigmask = uc.uc_sigmask;
493 SIG_CANTMASK(p->p_sigmask);
494 signotify(p);
495 PROC_UNLOCK(p);
496
497 CTR4(KTR_SIG, "sigreturn: return td=%p pc=%#lx sp=%#lx tstate=%#lx",
498 td, tf->tf_tpc, tf->tf_sp, tf->tf_tstate);
499 return (EJUSTRETURN);
500 }
501
502 #ifdef COMPAT_FREEBSD4
503 int
504 freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
505 {
506
507 return sigreturn(td, (struct sigreturn_args *)uap);
508 }
509 #endif
510
511 int
512 get_mcontext(struct thread *td, mcontext_t *mcp)
513 {
514
515 return (ENOSYS);
516 }
517
518 int
519 set_mcontext(struct thread *td, const mcontext_t *mcp)
520 {
521
522 return (ENOSYS);
523 }
524
525 /*
526 * Exit the kernel and execute a firmware call that will not return, as
527 * specified by the arguments.
528 */
529 void
530 cpu_shutdown(void *args)
531 {
532
533 #ifdef SMP
534 cpu_mp_shutdown();
535 #endif
536 openfirmware_exit(args);
537 }
538
539 /*
540 * Duplicate OF_exit() with a different firmware call function that restores
541 * the trap table, otherwise a RED state exception is triggered in at least
542 * some firmware versions.
543 */
544 void
545 cpu_halt(void)
546 {
547 static struct {
548 cell_t name;
549 cell_t nargs;
550 cell_t nreturns;
551 } args = {
552 (cell_t)"exit",
553 0,
554 0
555 };
556
557 cpu_shutdown(&args);
558 }
559
560 void
561 sparc64_shutdown_final(void *dummy, int howto)
562 {
563 static struct {
564 cell_t name;
565 cell_t nargs;
566 cell_t nreturns;
567 } args = {
568 (cell_t)"SUNW,power-off",
569 0,
570 0
571 };
572
573 /* Turn the power off? */
574 if ((howto & RB_POWEROFF) != 0)
575 cpu_shutdown(&args);
576 /* In case of halt, return to the firmware */
577 if ((howto & RB_HALT) != 0)
578 cpu_halt();
579 }
580
581 int
582 ptrace_set_pc(struct thread *td, u_long addr)
583 {
584
585 td->td_frame->tf_tpc = addr;
586 td->td_frame->tf_tnpc = addr + 4;
587 return (0);
588 }
589
590 int
591 ptrace_single_step(struct thread *td)
592 {
593 /* TODO; */
594 return (0);
595 }
596
597 void
598 exec_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings)
599 {
600 struct trapframe *tf;
601 struct md_utrap *ut;
602 struct pcb *pcb;
603 struct proc *p;
604 u_long sp;
605
606 /* XXX no cpu_exec */
607 p = td->td_proc;
608 p->p_md.md_sigtramp = NULL;
609 if ((ut = p->p_md.md_utrap) != NULL) {
610 ut->ut_refcnt--;
611 if (ut->ut_refcnt == 0)
612 free(ut, M_SUBPROC);
613 p->p_md.md_utrap = NULL;
614 }
615
616 pcb = td->td_pcb;
617 tf = td->td_frame;
618 sp = rounddown(stack, 16);
619 bzero(pcb, sizeof(*pcb));
620 bzero(tf, sizeof(*tf));
621 tf->tf_out[0] = stack;
622 tf->tf_out[3] = p->p_sysent->sv_psstrings;
623 tf->tf_out[6] = sp - SPOFF - sizeof(struct frame);
624 tf->tf_tnpc = entry + 4;
625 tf->tf_tpc = entry;
626 tf->tf_tstate = TSTATE_IE | TSTATE_PEF | TSTATE_MM_TSO;
627
628 td->td_retval[0] = tf->tf_out[0];
629 td->td_retval[1] = tf->tf_out[1];
630 }
631
632 void
633 Debugger(const char *msg)
634 {
635
636 printf("Debugger(\"%s\")\n", msg);
637 critical_enter();
638 breakpoint();
639 critical_exit();
640 }
641
642 int
643 fill_regs(struct thread *td, struct reg *regs)
644 {
645
646 bcopy(td->td_frame, regs, sizeof(*regs));
647 return (0);
648 }
649
650 int
651 set_regs(struct thread *td, struct reg *regs)
652 {
653
654 if (!TSTATE_SECURE(regs->r_tstate))
655 return (EINVAL);
656 bcopy(regs, td->td_frame, sizeof(*regs));
657 return (0);
658 }
659
660 int
661 fill_dbregs(struct thread *td, struct dbreg *dbregs)
662 {
663
664 return (ENOSYS);
665 }
666
667 int
668 set_dbregs(struct thread *td, struct dbreg *dbregs)
669 {
670
671 return (ENOSYS);
672 }
673
674 int
675 fill_fpregs(struct thread *td, struct fpreg *fpregs)
676 {
677 struct trapframe *tf;
678 struct pcb *pcb;
679
680 pcb = td->td_pcb;
681 tf = td->td_frame;
682 bcopy(pcb->pcb_fpstate.fp_fb, fpregs->fr_regs,
683 sizeof(pcb->pcb_fpstate.fp_fb));
684 fpregs->fr_fsr = tf->tf_fsr;
685 fpregs->fr_gsr = tf->tf_gsr;
686 return (0);
687 }
688
689 int
690 set_fpregs(struct thread *td, struct fpreg *fpregs)
691 {
692 struct trapframe *tf;
693 struct pcb *pcb;
694
695 pcb = td->td_pcb;
696 tf = td->td_frame;
697 bcopy(fpregs->fr_regs, pcb->pcb_fpstate.fp_fb,
698 sizeof(fpregs->fr_regs));
699 tf->tf_fsr = fpregs->fr_fsr;
700 tf->tf_gsr = fpregs->fr_gsr;
701 return (0);
702 }
Cache object: c57f55ac0d252210f517e23b9eea5f7a
|