xref: /illumos-gate/usr/src/uts/sun4/os/machdep.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/kstat.h>
31 #include <sys/param.h>
32 #include <sys/stack.h>
33 #include <sys/regset.h>
34 #include <sys/thread.h>
35 #include <sys/proc.h>
36 #include <sys/procfs_isa.h>
37 #include <sys/kmem.h>
38 #include <sys/cpuvar.h>
39 #include <sys/systm.h>
40 #include <sys/machpcb.h>
41 #include <sys/machasi.h>
42 #include <sys/vis.h>
43 #include <sys/fpu/fpusystm.h>
44 #include <sys/cpu_module.h>
45 #include <sys/privregs.h>
46 #include <sys/archsystm.h>
47 #include <sys/atomic.h>
48 #include <sys/cmn_err.h>
49 #include <sys/time.h>
50 #include <sys/clock.h>
51 #include <sys/chip.h>
52 #include <sys/cmp.h>
53 #include <sys/platform_module.h>
54 #include <sys/bl.h>
55 #include <sys/nvpair.h>
56 #include <sys/kdi_impl.h>
57 #include <sys/machsystm.h>
58 #include <sys/sysmacros.h>
59 #include <sys/promif.h>
60 #include <sys/pool_pset.h>
61 
62 int maxphys = MMU_PAGESIZE * 16;	/* 128k */
63 int klustsize = MMU_PAGESIZE * 16;	/* 128k */
64 
65 /*
66  * Initialize kernel thread's stack.
67  */
68 caddr_t
69 thread_stk_init(caddr_t stk)
70 {
71 	kfpu_t *fp;
72 	ulong_t align;
73 
74 	/* allocate extra space for floating point state */
75 	stk -= SA(sizeof (kfpu_t) + GSR_SIZE);
76 	align = (uintptr_t)stk & 0x3f;
77 	stk -= align;		/* force v9_fpu to be 16 byte aligned */
78 	fp = (kfpu_t *)stk;
79 	fp->fpu_fprs = 0;
80 
81 	stk -= SA(MINFRAME);
82 	return (stk);
83 }
84 
85 /*
86  * Initialize lwp's kernel stack.
87  * Note that now that the floating point register save area (kfpu_t)
88  * has been broken out from machpcb and aligned on a 64 byte boundary so that
89  * we can do block load/stores to/from it, there are a couple of potential
90  * optimizations to save stack space. 1. The floating point register save
91  * area could be aligned on a 16 byte boundary, and the floating point code
92  * changed to (a) check the alignment and (b) use different save/restore
93  * macros depending upon the alignment. 2. The lwp_stk_init code below
94  * could be changed to calculate if less space would be wasted if machpcb
95  * was first instead of second. However there is a REGOFF macro used in
96  * locore, syscall_trap, machdep and mlsetup that assumes that the saved
97  * register area is a fixed distance from the %sp, and would have to be
98  * changed to a pointer or something...JJ said later.
99  */
100 caddr_t
101 lwp_stk_init(klwp_t *lwp, caddr_t stk)
102 {
103 	struct machpcb *mpcb;
104 	kfpu_t *fp;
105 	uintptr_t aln;
106 
107 	stk -= SA(sizeof (kfpu_t) + GSR_SIZE);
108 	aln = (uintptr_t)stk & 0x3F;
109 	stk -= aln;
110 	fp = (kfpu_t *)stk;
111 	stk -= SA(sizeof (struct machpcb));
112 	mpcb = (struct machpcb *)stk;
113 	bzero(mpcb, sizeof (struct machpcb));
114 	bzero(fp, sizeof (kfpu_t) + GSR_SIZE);
115 	lwp->lwp_regs = (void *)&mpcb->mpcb_regs;
116 	lwp->lwp_fpu = (void *)fp;
117 	mpcb->mpcb_fpu = fp;
118 	mpcb->mpcb_fpu->fpu_q = mpcb->mpcb_fpu_q;
119 	mpcb->mpcb_thread = lwp->lwp_thread;
120 	mpcb->mpcb_wbcnt = 0;
121 	if (lwp->lwp_procp->p_model == DATAMODEL_ILP32) {
122 		mpcb->mpcb_wstate = WSTATE_USER32;
123 		mpcb->mpcb_wbuf = kmem_alloc(MAXWIN * sizeof (struct rwindow32),
124 		    KM_SLEEP);
125 	} else {
126 		mpcb->mpcb_wstate = WSTATE_USER64;
127 		mpcb->mpcb_wbuf = kmem_alloc(MAXWIN * sizeof (struct rwindow64),
128 		    KM_SLEEP);
129 	}
130 	ASSERT(((uintptr_t)mpcb->mpcb_wbuf & 7) == 0);
131 	mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf);
132 	mpcb->mpcb_pa = va_to_pa(mpcb);
133 	return (stk);
134 }
135 
136 void
137 lwp_stk_fini(klwp_t *lwp)
138 {
139 	struct machpcb *mpcb = lwptompcb(lwp);
140 
141 	/*
142 	 * there might be windows still in the wbuf due to unmapped
143 	 * stack, misaligned stack pointer, etc.  We just free it.
144 	 */
145 	mpcb->mpcb_wbcnt = 0;
146 	if (mpcb->mpcb_wstate == WSTATE_USER32)
147 		kmem_free(mpcb->mpcb_wbuf, MAXWIN * sizeof (struct rwindow32));
148 	else
149 		kmem_free(mpcb->mpcb_wbuf, MAXWIN * sizeof (struct rwindow64));
150 	mpcb->mpcb_wbuf = NULL;
151 	mpcb->mpcb_wbuf_pa = -1;
152 }
153 
154 
155 /*
156  * Copy regs from parent to child.
157  */
158 void
159 lwp_forkregs(klwp_t *lwp, klwp_t *clwp)
160 {
161 	kthread_t *t, *pt = lwptot(lwp);
162 	struct machpcb *mpcb = lwptompcb(clwp);
163 	struct machpcb *pmpcb = lwptompcb(lwp);
164 	kfpu_t *fp, *pfp = lwptofpu(lwp);
165 	caddr_t wbuf;
166 	uint_t wstate;
167 
168 	t = mpcb->mpcb_thread;
169 	/*
170 	 * remember child's fp and wbuf since they will get erased during
171 	 * the bcopy.
172 	 */
173 	fp = mpcb->mpcb_fpu;
174 	wbuf = mpcb->mpcb_wbuf;
175 	wstate = mpcb->mpcb_wstate;
176 	/*
177 	 * Don't copy mpcb_frame since we hand-crafted it
178 	 * in thread_load().
179 	 */
180 	bcopy(lwp->lwp_regs, clwp->lwp_regs, sizeof (struct machpcb) - REGOFF);
181 	mpcb->mpcb_thread = t;
182 	mpcb->mpcb_fpu = fp;
183 	fp->fpu_q = mpcb->mpcb_fpu_q;
184 
185 	/*
186 	 * It is theoretically possibly for the lwp's wstate to
187 	 * be different from its value assigned in lwp_stk_init,
188 	 * since lwp_stk_init assumed the data model of the process.
189 	 * Here, we took on the data model of the cloned lwp.
190 	 */
191 	if (mpcb->mpcb_wstate != wstate) {
192 		size_t osize, size;
193 
194 		if (wstate == WSTATE_USER32) {
195 			osize = MAXWIN * sizeof (struct rwindow32);
196 			size = MAXWIN * sizeof (struct rwindow64);
197 			wstate = WSTATE_USER64;
198 		} else {
199 			osize = MAXWIN * sizeof (struct rwindow64);
200 			size = MAXWIN * sizeof (struct rwindow32);
201 			wstate = WSTATE_USER32;
202 		}
203 		kmem_free(wbuf, osize);
204 		wbuf = kmem_alloc(size, KM_SLEEP);
205 	}
206 
207 	mpcb->mpcb_pa = va_to_pa(mpcb);
208 	mpcb->mpcb_wbuf = wbuf;
209 	mpcb->mpcb_wbuf_pa = va_to_pa(wbuf);
210 
211 	ASSERT(mpcb->mpcb_wstate == wstate);
212 
213 	if (mpcb->mpcb_wbcnt != 0) {
214 		bcopy(pmpcb->mpcb_wbuf, mpcb->mpcb_wbuf,
215 		    mpcb->mpcb_wbcnt * ((mpcb->mpcb_wstate == WSTATE_USER32) ?
216 		    sizeof (struct rwindow32) : sizeof (struct rwindow64)));
217 	}
218 
219 	if (pt == curthread)
220 		pfp->fpu_fprs = _fp_read_fprs();
221 	if ((pfp->fpu_en) || (pfp->fpu_fprs & FPRS_FEF)) {
222 		if (pt == curthread && fpu_exists) {
223 			save_gsr(clwp->lwp_fpu);
224 		} else {
225 			uint64_t gsr;
226 			gsr = get_gsr(lwp->lwp_fpu);
227 			set_gsr(gsr, clwp->lwp_fpu);
228 		}
229 		fp_fork(lwp, clwp);
230 	}
231 }
232 
233 /*
234  * Free lwp fpu regs.
235  */
236 void
237 lwp_freeregs(klwp_t *lwp, int isexec)
238 {
239 	kfpu_t *fp = lwptofpu(lwp);
240 
241 	if (lwptot(lwp) == curthread)
242 		fp->fpu_fprs = _fp_read_fprs();
243 	if ((fp->fpu_en) || (fp->fpu_fprs & FPRS_FEF))
244 		fp_free(fp, isexec);
245 }
246 
247 /*
248  * fill in the extra register state area specified with the
249  * specified lwp's platform-dependent non-floating-point extra
250  * register state information
251  */
252 /* ARGSUSED */
253 void
254 xregs_getgfiller(klwp_id_t lwp, caddr_t xrp)
255 {
256 	/* for sun4u nothing to do here, added for symmetry */
257 }
258 
259 /*
260  * fill in the extra register state area specified with the specified lwp's
261  * platform-dependent floating-point extra register state information.
262  * NOTE:  'lwp' might not correspond to 'curthread' since this is
263  * called from code in /proc to get the registers of another lwp.
264  */
265 void
266 xregs_getfpfiller(klwp_id_t lwp, caddr_t xrp)
267 {
268 	prxregset_t *xregs = (prxregset_t *)xrp;
269 	kfpu_t *fp = lwptofpu(lwp);
270 	uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
271 	uint64_t gsr;
272 
273 	/*
274 	 * fp_fksave() does not flush the GSR register into
275 	 * the lwp area, so do it now
276 	 */
277 	kpreempt_disable();
278 	if (ttolwp(curthread) == lwp && fpu_exists) {
279 		fp->fpu_fprs = _fp_read_fprs();
280 		if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
281 			_fp_write_fprs(fprs);
282 			fp->fpu_fprs = (V9_FPU_FPRS_TYPE)fprs;
283 		}
284 		save_gsr(fp);
285 	}
286 	gsr = get_gsr(fp);
287 	kpreempt_enable();
288 	PRXREG_GSR(xregs) = gsr;
289 }
290 
291 /*
292  * set the specified lwp's platform-dependent non-floating-point
293  * extra register state based on the specified input
294  */
295 /* ARGSUSED */
296 void
297 xregs_setgfiller(klwp_id_t lwp, caddr_t xrp)
298 {
299 	/* for sun4u nothing to do here, added for symmetry */
300 }
301 
302 /*
303  * set the specified lwp's platform-dependent floating-point
304  * extra register state based on the specified input
305  */
306 void
307 xregs_setfpfiller(klwp_id_t lwp, caddr_t xrp)
308 {
309 	prxregset_t *xregs = (prxregset_t *)xrp;
310 	kfpu_t *fp = lwptofpu(lwp);
311 	uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
312 	uint64_t gsr = PRXREG_GSR(xregs);
313 
314 	kpreempt_disable();
315 	set_gsr(gsr, lwptofpu(lwp));
316 
317 	if ((lwp == ttolwp(curthread)) && fpu_exists) {
318 		fp->fpu_fprs = _fp_read_fprs();
319 		if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
320 			_fp_write_fprs(fprs);
321 			fp->fpu_fprs = (V9_FPU_FPRS_TYPE)fprs;
322 		}
323 		restore_gsr(lwptofpu(lwp));
324 	}
325 	kpreempt_enable();
326 }
327 
328 /*
329  * fill in the sun4u asrs, ie, the lwp's platform-dependent
330  * non-floating-point extra register state information
331  */
332 /* ARGSUSED */
333 void
334 getasrs(klwp_t *lwp, asrset_t asr)
335 {
336 	/* for sun4u nothing to do here, added for symmetry */
337 }
338 
339 /*
340  * fill in the sun4u asrs, ie, the lwp's platform-dependent
341  * floating-point extra register state information
342  */
343 void
344 getfpasrs(klwp_t *lwp, asrset_t asr)
345 {
346 	kfpu_t *fp = lwptofpu(lwp);
347 	uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
348 
349 	kpreempt_disable();
350 	if (ttolwp(curthread) == lwp)
351 		fp->fpu_fprs = _fp_read_fprs();
352 	if ((fp->fpu_en) || (fp->fpu_fprs & FPRS_FEF)) {
353 		if (fpu_exists && ttolwp(curthread) == lwp) {
354 			if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
355 				_fp_write_fprs(fprs);
356 				fp->fpu_fprs = (V9_FPU_FPRS_TYPE)fprs;
357 			}
358 			save_gsr(fp);
359 		}
360 		asr[ASR_GSR] = (int64_t)get_gsr(fp);
361 	}
362 	kpreempt_enable();
363 }
364 
365 /*
366  * set the sun4u asrs, ie, the lwp's platform-dependent
367  * non-floating-point extra register state information
368  */
369 /* ARGSUSED */
370 void
371 setasrs(klwp_t *lwp, asrset_t asr)
372 {
373 	/* for sun4u nothing to do here, added for symmetry */
374 }
375 
376 void
377 setfpasrs(klwp_t *lwp, asrset_t asr)
378 {
379 	kfpu_t *fp = lwptofpu(lwp);
380 	uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
381 
382 	kpreempt_disable();
383 	if (ttolwp(curthread) == lwp)
384 		fp->fpu_fprs = _fp_read_fprs();
385 	if ((fp->fpu_en) || (fp->fpu_fprs & FPRS_FEF)) {
386 		set_gsr(asr[ASR_GSR], fp);
387 		if (fpu_exists && ttolwp(curthread) == lwp) {
388 			if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
389 				_fp_write_fprs(fprs);
390 				fp->fpu_fprs = (V9_FPU_FPRS_TYPE)fprs;
391 			}
392 			restore_gsr(fp);
393 		}
394 	}
395 	kpreempt_enable();
396 }
397 
398 /*
399  * Create interrupt kstats for this CPU.
400  */
401 void
402 cpu_create_intrstat(cpu_t *cp)
403 {
404 	int		i;
405 	kstat_t		*intr_ksp;
406 	kstat_named_t	*knp;
407 	char		name[KSTAT_STRLEN];
408 	zoneid_t	zoneid;
409 
410 	ASSERT(MUTEX_HELD(&cpu_lock));
411 
412 	if (pool_pset_enabled())
413 		zoneid = GLOBAL_ZONEID;
414 	else
415 		zoneid = ALL_ZONES;
416 
417 	intr_ksp = kstat_create_zone("cpu", cp->cpu_id, "intrstat", "misc",
418 	    KSTAT_TYPE_NAMED, PIL_MAX * 2, NULL, zoneid);
419 
420 	/*
421 	 * Initialize each PIL's named kstat
422 	 */
423 	if (intr_ksp != NULL) {
424 		intr_ksp->ks_update = cpu_kstat_intrstat_update;
425 		knp = (kstat_named_t *)intr_ksp->ks_data;
426 		intr_ksp->ks_private = cp;
427 		for (i = 0; i < PIL_MAX; i++) {
428 			(void) snprintf(name, KSTAT_STRLEN, "level-%d-time",
429 			    i + 1);
430 			kstat_named_init(&knp[i * 2], name, KSTAT_DATA_UINT64);
431 			(void) snprintf(name, KSTAT_STRLEN, "level-%d-count",
432 			    i + 1);
433 			kstat_named_init(&knp[(i * 2) + 1], name,
434 			    KSTAT_DATA_UINT64);
435 		}
436 		kstat_install(intr_ksp);
437 	}
438 }
439 
440 /*
441  * Delete interrupt kstats for this CPU.
442  */
443 void
444 cpu_delete_intrstat(cpu_t *cp)
445 {
446 	kstat_delete_byname_zone("cpu", cp->cpu_id, "intrstat", ALL_ZONES);
447 }
448 
449 /*
450  * Convert interrupt statistics from CPU ticks to nanoseconds and
451  * update kstat.
452  */
453 int
454 cpu_kstat_intrstat_update(kstat_t *ksp, int rw)
455 {
456 	kstat_named_t	*knp = ksp->ks_data;
457 	cpu_t		*cpup = (cpu_t *)ksp->ks_private;
458 	int		i;
459 
460 	if (rw == KSTAT_WRITE)
461 		return (EACCES);
462 
463 	/*
464 	 * We use separate passes to copy and convert the statistics to
465 	 * nanoseconds. This assures that the snapshot of the data is as
466 	 * self-consistent as possible.
467 	 */
468 
469 	for (i = 0; i < PIL_MAX; i++) {
470 		knp[i * 2].value.ui64 = cpup->cpu_m.intrstat[i + 1][0];
471 		knp[(i * 2) + 1].value.ui64 = cpup->cpu_stats.sys.intr[i];
472 	}
473 
474 	for (i = 0; i < PIL_MAX; i++) {
475 		knp[i * 2].value.ui64 =
476 		    (uint64_t)tick2ns((hrtime_t)knp[i * 2].value.ui64,
477 			cpup->cpu_id);
478 	}
479 
480 	return (0);
481 }
482 
483 /*
484  * Called by common/os/cpu.c for psrinfo(1m) kstats
485  */
486 char *
487 cpu_fru_fmri(cpu_t *cp)
488 {
489 	return (cpunodes[cp->cpu_id].fru_fmri);
490 }
491 
492 /*
493  * An interrupt thread is ending a time slice, so compute the interval it
494  * ran for and update the statistic for its PIL.
495  */
496 void
497 cpu_intr_swtch_enter(kthread_id_t t)
498 {
499 	uint64_t	interval;
500 	uint64_t	start;
501 
502 	ASSERT((t->t_flag & T_INTR_THREAD) != 0);
503 	ASSERT(t->t_pil > 0 && t->t_pil <= LOCK_LEVEL);
504 
505 	/*
506 	 * We could be here with a zero timestamp. This could happen if:
507 	 * an interrupt thread which no longer has a pinned thread underneath
508 	 * it (i.e. it blocked at some point in its past) has finished running
509 	 * its handler. intr_thread() updated the interrupt statistic for its
510 	 * PIL and zeroed its timestamp. Since there was no pinned thread to
511 	 * return to, swtch() gets called and we end up here.
512 	 *
513 	 * It can also happen if an interrupt thread in intr_thread() calls
514 	 * preempt. It will have already taken care of updating stats. In
515 	 * this event, the interrupt thread will be runnable.
516 	 */
517 	if (t->t_intr_start) {
518 		do {
519 			start = t->t_intr_start;
520 			interval = gettick_counter() - start;
521 		} while (cas64(&t->t_intr_start, start, 0) != start);
522 		if (CPU->cpu_m.divisor > 1)
523 			interval *= CPU->cpu_m.divisor;
524 		CPU->cpu_m.intrstat[t->t_pil][0] += interval;
525 	} else
526 		ASSERT(t->t_intr == NULL || t->t_state == TS_RUN);
527 }
528 
529 
530 /*
531  * An interrupt thread is returning from swtch(). Place a starting timestamp
532  * in its thread structure.
533  */
534 void
535 cpu_intr_swtch_exit(kthread_id_t t)
536 {
537 	uint64_t ts;
538 
539 	ASSERT((t->t_flag & T_INTR_THREAD) != 0);
540 	ASSERT(t->t_pil > 0 && t->t_pil <= LOCK_LEVEL);
541 
542 	do {
543 		ts = t->t_intr_start;
544 	} while (cas64(&t->t_intr_start, ts, gettick_counter()) != ts);
545 }
546 
547 
548 int
549 blacklist(int cmd, const char *scheme, nvlist_t *fmri, const char *class)
550 {
551 	if (&plat_blacklist)
552 		return (plat_blacklist(cmd, scheme, fmri, class));
553 
554 	return (ENOTSUP);
555 }
556 
557 int
558 kdi_pread(caddr_t buf, size_t nbytes, uint64_t addr, size_t *ncopiedp)
559 {
560 	extern void kdi_flush_caches(void);
561 	size_t nread = 0;
562 	uint32_t word;
563 	int slop, i;
564 
565 	kdi_flush_caches();
566 	membar_enter();
567 
568 	/* We might not begin on a word boundary. */
569 	if ((slop = addr & 3) != 0) {
570 		word = ldphys(addr & ~3);
571 		for (i = slop; i < 4 && nbytes > 0; i++, nbytes--, nread++)
572 			*buf++ = ((uchar_t *)&word)[i];
573 		addr = roundup(addr, 4);
574 	}
575 
576 	while (nbytes > 0) {
577 		word = ldphys(addr);
578 		for (i = 0; i < 4 && nbytes > 0; i++, nbytes--, nread++, addr++)
579 			*buf++ = ((uchar_t *)&word)[i];
580 	}
581 
582 	kdi_flush_caches();
583 
584 	*ncopiedp = nread;
585 	return (0);
586 }
587 
588 int
589 kdi_pwrite(caddr_t buf, size_t nbytes, uint64_t addr, size_t *ncopiedp)
590 {
591 	extern void kdi_flush_caches(void);
592 	size_t nwritten = 0;
593 	uint32_t word;
594 	int slop, i;
595 
596 	kdi_flush_caches();
597 
598 	/* We might not begin on a word boundary. */
599 	if ((slop = addr & 3) != 0) {
600 		word = ldphys(addr & ~3);
601 		for (i = slop; i < 4 && nbytes > 0; i++, nbytes--, nwritten++)
602 			((uchar_t *)&word)[i] = *buf++;
603 		stphys(addr & ~3, word);
604 		addr = roundup(addr, 4);
605 	}
606 
607 	while (nbytes > 3) {
608 		for (word = 0, i = 0; i < 4; i++, nbytes--, nwritten++)
609 			((uchar_t *)&word)[i] = *buf++;
610 		stphys(addr, word);
611 		addr += 4;
612 	}
613 
614 	/* We might not end with a whole word. */
615 	if (nbytes > 0) {
616 		word = ldphys(addr);
617 		for (i = 0; nbytes > 0; i++, nbytes--, nwritten++)
618 			((uchar_t *)&word)[i] = *buf++;
619 		stphys(addr, word);
620 	}
621 
622 	membar_enter();
623 	kdi_flush_caches();
624 
625 	*ncopiedp = nwritten;
626 	return (0);
627 }
628 
629 static void
630 kdi_kernpanic(struct regs *regs, uint_t tt)
631 {
632 	sync_reg_buf = *regs;
633 	sync_tt = tt;
634 
635 	sync_handler();
636 }
637 
638 static void
639 kdi_plat_call(void (*platfn)(void))
640 {
641 	if (platfn != NULL) {
642 		prom_suspend_prepost();
643 		platfn();
644 		prom_resume_prepost();
645 	}
646 }
647 
648 void
649 mach_kdi_init(kdi_t *kdi)
650 {
651 	kdi->kdi_plat_call = kdi_plat_call;
652 	kdi->mkdi_cpu_index = kdi_cpu_index;
653 	kdi->mkdi_trap_vatotte = kdi_trap_vatotte;
654 	kdi->mkdi_kernpanic = kdi_kernpanic;
655 }
656