cpr_impl.c revision 7240:c4957ab6a78e
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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * Platform specific implementation code
30 */
31
32#define	SUNDDI_IMPL
33
34#include <sys/types.h>
35#include <sys/promif.h>
36#include <sys/prom_isa.h>
37#include <sys/prom_plat.h>
38#include <sys/mmu.h>
39#include <vm/hat_sfmmu.h>
40#include <sys/iommu.h>
41#include <sys/scb.h>
42#include <sys/cpuvar.h>
43#include <sys/intreg.h>
44#include <sys/pte.h>
45#include <vm/hat.h>
46#include <vm/page.h>
47#include <vm/as.h>
48#include <sys/cpr.h>
49#include <sys/kmem.h>
50#include <sys/clock.h>
51#include <sys/kmem.h>
52#include <sys/panic.h>
53#include <vm/seg_kmem.h>
54#include <sys/cpu_module.h>
55#include <sys/callb.h>
56#include <sys/machsystm.h>
57#include <sys/vmsystm.h>
58#include <sys/systm.h>
59#include <sys/archsystm.h>
60#include <sys/stack.h>
61#include <sys/fs/ufs_fs.h>
62#include <sys/memlist.h>
63#include <sys/bootconf.h>
64#include <sys/thread.h>
65#include <vm/vm_dep.h>
66
67extern	void cpr_clear_bitmaps(void);
68extern	int cpr_setbit(pfn_t ppn, int mapflag);
69extern	int cpr_clrbit(pfn_t ppn, int mapflag);
70extern	pgcnt_t cpr_scan_kvseg(int mapflag, bitfunc_t bitfunc, struct seg *seg);
71extern	pgcnt_t cpr_count_seg_pages(int mapflag, bitfunc_t bitfunc);
72extern	void dtlb_wr_entry(uint_t, tte_t *, uint64_t *);
73extern	void itlb_wr_entry(uint_t, tte_t *, uint64_t *);
74
75static	int i_cpr_storage_desc_alloc(csd_t **, pgcnt_t *, csd_t **, int);
76static	void i_cpr_storage_desc_init(csd_t *, pgcnt_t, csd_t *);
77static	caddr_t i_cpr_storage_data_alloc(pgcnt_t, pgcnt_t *, int);
78static	int cpr_dump_sensitive(vnode_t *, csd_t *);
79static	void i_cpr_clear_entries(uint64_t, uint64_t);
80static	void i_cpr_xcall(xcfunc_t);
81
82void	i_cpr_storage_free(void);
83
84extern void *i_cpr_data_page;
85extern int cpr_test_mode;
86extern int cpr_nbitmaps;
87extern char cpr_default_path[];
88extern caddr_t textva, datava;
89
90static struct cpr_map_info cpr_prom_retain[CPR_PROM_RETAIN_CNT];
91caddr_t cpr_vaddr = NULL;
92
93static	uint_t sensitive_pages_saved;
94static	uint_t sensitive_size_saved;
95
96caddr_t	i_cpr_storage_data_base;
97caddr_t	i_cpr_storage_data_end;
98csd_t *i_cpr_storage_desc_base;
99csd_t *i_cpr_storage_desc_end;		/* one byte beyond last used descp */
100csd_t *i_cpr_storage_desc_last_used;	/* last used descriptor */
101caddr_t sensitive_write_ptr;		/* position for next storage write */
102
103size_t	i_cpr_sensitive_bytes_dumped;
104pgcnt_t	i_cpr_sensitive_pgs_dumped;
105pgcnt_t	i_cpr_storage_data_sz;		/* in pages */
106pgcnt_t	i_cpr_storage_desc_pgcnt;	/* in pages */
107
108ushort_t cpr_mach_type = CPR_MACHTYPE_4U;
109static	csu_md_t m_info;
110
111
112#define	MAX_STORAGE_RETRY	3
113#define	MAX_STORAGE_ALLOC_RETRY	3
114#define	INITIAL_ALLOC_PCNT	40	/* starting allocation percentage */
115#define	INTEGRAL		100	/* to get 1% precision */
116
117#define	EXTRA_RATE		2	/* add EXTRA_RATE% extra space */
118#define	EXTRA_DESCS		10
119
120#define	CPR_NO_STORAGE_DESC	1
121#define	CPR_NO_STORAGE_DATA	2
122
123#define	CIF_SPLICE		0
124#define	CIF_UNLINK		1
125
126
127/*
128 * CPR miscellaneous support routines
129 */
130#define	cpr_open(path, mode,  vpp)	(vn_open(path, UIO_SYSSPACE, \
131		mode, 0600, vpp, CRCREAT, 0))
132#define	cpr_rdwr(rw, vp, basep, cnt)	(vn_rdwr(rw, vp,  (caddr_t)(basep), \
133		cnt, 0LL, UIO_SYSSPACE, 0, (rlim64_t)MAXOFF_T, CRED(), \
134		(ssize_t *)NULL))
135
136/*
137 * definitions for saving/restoring prom pages
138 */
139static void	*ppage_buf;
140static pgcnt_t	ppage_count;
141static pfn_t	*pphys_list;
142static size_t	pphys_list_size;
143
144typedef void (*tlb_rw_t)(uint_t, tte_t *, uint64_t *);
145typedef void (*tlb_filter_t)(int, tte_t *, uint64_t, void *);
146
147/*
148 * private struct for tlb handling
149 */
150struct cpr_trans_info {
151	sutlb_t		*dst;
152	sutlb_t		*tail;
153	tlb_rw_t	reader;
154	tlb_rw_t	writer;
155	tlb_filter_t	filter;
156	int		index;
157	uint64_t	skip;		/* assumes TLB <= 64 locked entries */
158};
159typedef struct cpr_trans_info cti_t;
160
161
162/*
163 * special handling for tlb info
164 */
165#define	WITHIN_OFW(va) \
166	(((va) > (uint64_t)OFW_START_ADDR) && ((va) < (uint64_t)OFW_END_ADDR))
167
168#define	WITHIN_NUCLEUS(va, base) \
169	(((va) >= (base)) && \
170	(((va) + MMU_PAGESIZE) <= ((base) + MMU_PAGESIZE4M)))
171
172#define	IS_BIGKTSB(va) \
173	(enable_bigktsb && \
174	((va) >= (uint64_t)ktsb_base) && \
175	((va) < (uint64_t)(ktsb_base + ktsb_sz)))
176
177
178/*
179 * WARNING:
180 * the text from this file is linked to follow cpr_resume_setup.o;
181 * only add text between here and i_cpr_end_jumpback when it needs
182 * to be called during resume before we switch back to the kernel
183 * trap table.  all the text in this range must fit within a page.
184 */
185
186
187/*
188 * each time a machine is reset, the prom uses an inconsistent set of phys
189 * pages and the cif cookie may differ as well.  so prior to restoring the
190 * original prom, we have to use to use the new/tmp prom's translations
191 * when requesting prom services.
192 *
193 * cif_handler starts out as the original prom cookie, and that gets used
194 * by client_handler() to jump into the prom.  here we splice-in a wrapper
195 * routine by writing cif_handler; client_handler() will now jump to the
196 * wrapper which switches the %tba to the new/tmp prom's trap table then
197 * jumps to the new cookie.
198 */
199void
200i_cpr_cif_setup(int action)
201{
202	extern void *i_cpr_orig_cif, *cif_handler;
203	extern int i_cpr_cif_wrapper(void *);
204
205	/*
206	 * save the original cookie and change the current cookie to the
207	 * wrapper routine.  later we just restore the original cookie.
208	 */
209	if (action == CIF_SPLICE) {
210		i_cpr_orig_cif = cif_handler;
211		cif_handler = (void *)i_cpr_cif_wrapper;
212	} else if (action == CIF_UNLINK)
213		cif_handler = i_cpr_orig_cif;
214}
215
216
217/*
218 * launch slave cpus into kernel text, pause them,
219 * and restore the original prom pages
220 */
221void
222i_cpr_mp_setup(void)
223{
224	extern void restart_other_cpu(int);
225	cpu_t *cp;
226
227	uint64_t kctx = kcontextreg;
228
229	/*
230	 * Do not allow setting page size codes in MMU primary context
231	 * register while using cif wrapper. This is needed to work
232	 * around OBP incorrect handling of this MMU register.
233	 */
234	kcontextreg = 0;
235
236	/*
237	 * reset cpu_ready_set so x_calls work properly
238	 */
239	CPUSET_ZERO(cpu_ready_set);
240	CPUSET_ADD(cpu_ready_set, getprocessorid());
241
242	/*
243	 * setup cif to use the cookie from the new/tmp prom
244	 * and setup tmp handling for calling prom services.
245	 */
246	i_cpr_cif_setup(CIF_SPLICE);
247
248	/*
249	 * at this point, only the nucleus and a few cpr pages are
250	 * mapped in.  once we switch to the kernel trap table,
251	 * we can access the rest of kernel space.
252	 */
253	prom_set_traptable(&trap_table);
254
255	if (ncpus > 1) {
256		sfmmu_init_tsbs();
257
258		mutex_enter(&cpu_lock);
259		/*
260		 * All of the slave cpus are not ready at this time,
261		 * yet the cpu structures have various cpu_flags set;
262		 * clear cpu_flags and mutex_ready.
263		 * Since we are coming up from a CPU suspend, the slave cpus
264		 * are frozen.
265		 */
266		for (cp = CPU->cpu_next; cp != CPU; cp = cp->cpu_next) {
267			cp->cpu_flags = CPU_FROZEN;
268			cp->cpu_m.mutex_ready = 0;
269		}
270
271		for (cp = CPU->cpu_next; cp != CPU; cp = cp->cpu_next)
272			restart_other_cpu(cp->cpu_id);
273
274		pause_cpus(NULL);
275		mutex_exit(&cpu_lock);
276
277		i_cpr_xcall(i_cpr_clear_entries);
278	} else
279		i_cpr_clear_entries(0, 0);
280
281	/*
282	 * now unlink the cif wrapper;  WARNING: do not call any
283	 * prom_xxx() routines until after prom pages are restored.
284	 */
285	i_cpr_cif_setup(CIF_UNLINK);
286
287	(void) i_cpr_prom_pages(CPR_PROM_RESTORE);
288
289	/* allow setting page size codes in MMU primary context register */
290	kcontextreg = kctx;
291}
292
293
294/*
295 * end marker for jumpback page;
296 * this symbol is used to check the size of i_cpr_resume_setup()
297 * and the above text.  For simplicity, the Makefile needs to
298 * link i_cpr_resume_setup.o and cpr_impl.o consecutively.
299 */
300void
301i_cpr_end_jumpback(void)
302{
303}
304
305
306/*
307 * scan tlb entries with reader; when valid entries are found,
308 * the filter routine will selectively save/clear them
309 */
310static void
311i_cpr_scan_tlb(cti_t *ctip)
312{
313	uint64_t va_tag;
314	int tlb_index;
315	tte_t tte;
316
317	for (tlb_index = ctip->index; tlb_index >= 0; tlb_index--) {
318		(*ctip->reader)((uint_t)tlb_index, &tte, &va_tag);
319		if (va_tag && TTE_IS_VALID(&tte))
320			(*ctip->filter)(tlb_index, &tte, va_tag, ctip);
321	}
322}
323
324
325/*
326 * filter for locked tlb entries that reference the text/data nucleus
327 * and any bigktsb's; these will be reinstalled by cprboot on all cpus
328 */
329/* ARGSUSED */
330static void
331i_cpr_lnb(int index, tte_t *ttep, uint64_t va_tag, void *ctrans)
332{
333	cti_t *ctip;
334
335	/*
336	 * record tlb data at ctip->dst; the target tlb index starts
337	 * at the highest tlb offset and moves towards 0.  the prom
338	 * reserves both dtlb and itlb index 0.  any selected entry
339	 * also gets marked to prevent being flushed during resume
340	 */
341	if (TTE_IS_LOCKED(ttep) && (va_tag == (uint64_t)textva ||
342	    va_tag == (uint64_t)datava || IS_BIGKTSB(va_tag))) {
343		ctip = ctrans;
344		while ((1 << ctip->index) & ctip->skip)
345			ctip->index--;
346		ASSERT(ctip->index > 0);
347		ASSERT(ctip->dst < ctip->tail);
348		ctip->dst->tte.ll = ttep->ll;
349		ctip->dst->va_tag = va_tag;
350		ctip->dst->index = ctip->index--;
351		ctip->dst->tmp = 0;
352		ctip->dst++;
353	}
354}
355
356
357/*
358 * some tlb entries are stale, filter for unlocked entries
359 * within the prom virt range and clear them
360 */
361static void
362i_cpr_ufw(int index, tte_t *ttep, uint64_t va_tag, void *ctrans)
363{
364	sutlb_t clr;
365	cti_t *ctip;
366
367	if (!TTE_IS_LOCKED(ttep) && WITHIN_OFW(va_tag)) {
368		ctip = ctrans;
369		bzero(&clr, sizeof (clr));
370		(*ctip->writer)((uint_t)index, &clr.tte, &clr.va_tag);
371	}
372}
373
374
375/*
376 * some of the entries installed by cprboot are needed only on a
377 * short-term basis and need to be flushed to avoid clogging the tlbs.
378 * scan the dtte/itte arrays for items marked as temporary and clear
379 * dtlb/itlb entries using wrfunc.
380 */
381static void
382i_cpr_clear_tmp(sutlb_t *listp, int max, tlb_rw_t wrfunc)
383{
384	sutlb_t clr, *tail;
385
386	bzero(&clr, sizeof (clr));
387	for (tail = listp + max; listp < tail && listp->va_tag; listp++) {
388		if (listp->tmp)
389			(*wrfunc)((uint_t)listp->index, &clr.tte, &clr.va_tag);
390	}
391}
392
393
394/* ARGSUSED */
395static void
396i_cpr_clear_entries(uint64_t arg1, uint64_t arg2)
397{
398	extern void demap_all(void);
399	cti_t cti;
400
401	i_cpr_clear_tmp(m_info.dtte, CPR_MAX_TLB, dtlb_wr_entry);
402	i_cpr_clear_tmp(m_info.itte, CPR_MAX_TLB, itlb_wr_entry);
403
404	/*
405	 * for newer cpus that implement DEMAP_ALL_TYPE, demap_all is
406	 * a second label for vtag_flushall.  the call is made using
407	 * vtag_flushall() instead of demap_all() due to runtime and
408	 * krtld results with both older and newer cpu modules.
409	 */
410	if (&demap_all != 0) {
411		vtag_flushall();
412		return;
413	}
414
415	/*
416	 * for older V9 cpus, scan tlbs and clear stale entries
417	 */
418	bzero(&cti, sizeof (cti));
419	cti.filter = i_cpr_ufw;
420
421	cti.index = cpunodes[CPU->cpu_id].dtlb_size - 1;
422	cti.reader = dtlb_rd_entry;
423	cti.writer = dtlb_wr_entry;
424	i_cpr_scan_tlb(&cti);
425
426	cti.index = cpunodes[CPU->cpu_id].itlb_size - 1;
427	cti.reader = itlb_rd_entry;
428	cti.writer = itlb_wr_entry;
429	i_cpr_scan_tlb(&cti);
430}
431
432
433/*
434 * craft tlb info for tmp use during resume; this data gets used by
435 * cprboot to install tlb entries.  we also mark each struct as tmp
436 * so those tlb entries will get flushed after switching to the kernel
437 * trap table.  no data needs to be recorded for vaddr when it falls
438 * within the nucleus since we've already recorded nucleus ttes and
439 * a 8K tte would conflict with a 4MB tte.  eg: the cpr module
440 * text/data may have been loaded into the text/data nucleus.
441 */
442static void
443i_cpr_make_tte(cti_t *ctip, void *vaddr, caddr_t nbase)
444{
445	pfn_t ppn;
446	uint_t rw;
447
448	if (WITHIN_NUCLEUS((caddr_t)vaddr, nbase))
449		return;
450
451	while ((1 << ctip->index) & ctip->skip)
452		ctip->index--;
453	ASSERT(ctip->index > 0);
454	ASSERT(ctip->dst < ctip->tail);
455
456	/*
457	 * without any global service available to lookup
458	 * a tte by vaddr, we craft our own here:
459	 */
460	ppn = va_to_pfn(vaddr);
461	rw = (nbase == datava) ? TTE_HWWR_INT : 0;
462	ctip->dst->tte.tte_inthi = TTE_VALID_INT | TTE_PFN_INTHI(ppn);
463	ctip->dst->tte.tte_intlo = TTE_PFN_INTLO(ppn) | TTE_LCK_INT |
464	    TTE_CP_INT | TTE_PRIV_INT | rw;
465	ctip->dst->va_tag = ((uintptr_t)vaddr & MMU_PAGEMASK);
466	ctip->dst->index = ctip->index--;
467	ctip->dst->tmp = 1;
468	ctip->dst++;
469}
470
471
472static void
473i_cpr_xcall(xcfunc_t func)
474{
475	uint_t pil, reset_pil;
476
477	pil = getpil();
478	if (pil < XCALL_PIL)
479		reset_pil = 0;
480	else {
481		reset_pil = 1;
482		setpil(XCALL_PIL - 1);
483	}
484	xc_some(cpu_ready_set, func, 0, 0);
485	if (reset_pil)
486		setpil(pil);
487}
488
489
490/*
491 * restart paused slave cpus
492 */
493void
494i_cpr_machdep_setup(void)
495{
496	if (ncpus > 1) {
497		CPR_DEBUG(CPR_DEBUG1, "MP restarted...\n");
498		mutex_enter(&cpu_lock);
499		start_cpus();
500		mutex_exit(&cpu_lock);
501	}
502}
503
504
505/*
506 * Stop all interrupt activities in the system
507 */
508void
509i_cpr_stop_intr(void)
510{
511	(void) spl7();
512}
513
514/*
515 * Set machine up to take interrupts
516 */
517void
518i_cpr_enable_intr(void)
519{
520	(void) spl0();
521}
522
523
524/*
525 * record cpu nodes and ids
526 */
527static void
528i_cpr_save_cpu_info(void)
529{
530	struct sun4u_cpu_info *scip;
531	cpu_t *cp;
532
533	scip = m_info.sci;
534	cp = CPU;
535	do {
536		ASSERT(scip < &m_info.sci[NCPU]);
537		scip->cpu_id = cp->cpu_id;
538		scip->node = cpunodes[cp->cpu_id].nodeid;
539		scip++;
540	} while ((cp = cp->cpu_next) != CPU);
541}
542
543
544/*
545 * Write necessary machine dependent information to cpr state file,
546 * eg. sun4u mmu ctx secondary for the current running process (cpr) ...
547 */
548int
549i_cpr_write_machdep(vnode_t *vp)
550{
551	extern uint_t getpstate(), getwstate();
552	extern uint_t i_cpr_tstack_size;
553	const char ustr[] = ": unix-tte 2drop false ;";
554	uintptr_t tinfo;
555	label_t *ltp;
556	cmd_t cmach;
557	char *fmt;
558	int rc;
559
560	/*
561	 * ustr[] is used as temporary forth words during
562	 * slave startup sequence, see sfmmu_mp_startup()
563	 */
564
565	cmach.md_magic = (uint_t)CPR_MACHDEP_MAGIC;
566	cmach.md_size = sizeof (m_info) + sizeof (ustr);
567
568	if (rc = cpr_write(vp, (caddr_t)&cmach, sizeof (cmach))) {
569		cpr_err(CE_WARN, "Failed to write descriptor.");
570		return (rc);
571	}
572
573	/*
574	 * m_info is now cleared in i_cpr_dump_setup()
575	 */
576	m_info.ksb = (uint32_t)STACK_BIAS;
577	m_info.kpstate = (uint16_t)getpstate();
578	m_info.kwstate = (uint16_t)getwstate();
579	CPR_DEBUG(CPR_DEBUG1, "stack bias 0x%x, pstate 0x%x, wstate 0x%x\n",
580	    m_info.ksb, m_info.kpstate, m_info.kwstate);
581
582	ltp = &ttolwp(curthread)->lwp_qsav;
583	m_info.qsav_pc = (cpr_ext)ltp->val[0];
584	m_info.qsav_sp = (cpr_ext)ltp->val[1];
585
586	/*
587	 * Set secondary context to INVALID_CONTEXT to force the HAT
588	 * to re-setup the MMU registers and locked TTEs it needs for
589	 * TLB miss handling.
590	 */
591	m_info.mmu_ctx_sec = INVALID_CONTEXT;
592	m_info.mmu_ctx_pri = KCONTEXT;
593
594	tinfo = (uintptr_t)curthread;
595	m_info.thrp = (cpr_ptr)tinfo;
596
597	tinfo = (uintptr_t)i_cpr_resume_setup;
598	m_info.func = (cpr_ptr)tinfo;
599
600	/*
601	 * i_cpr_data_page is comprised of a 4K stack area and a few
602	 * trailing data symbols; the page is shared by the prom and
603	 * kernel during resume.  the stack size is recorded here
604	 * and used by cprboot to set %sp
605	 */
606	tinfo = (uintptr_t)&i_cpr_data_page;
607	m_info.tmp_stack = (cpr_ptr)tinfo;
608	m_info.tmp_stacksize = i_cpr_tstack_size;
609
610	m_info.test_mode = cpr_test_mode;
611
612	i_cpr_save_cpu_info();
613
614	if (rc = cpr_write(vp, (caddr_t)&m_info, sizeof (m_info))) {
615		cpr_err(CE_WARN, "Failed to write machdep info.");
616		return (rc);
617	}
618
619	fmt = "error writing %s forth info";
620	if (rc = cpr_write(vp, (caddr_t)ustr, sizeof (ustr)))
621		cpr_err(CE_WARN, fmt, "unix-tte");
622
623	return (rc);
624}
625
626
627/*
628 * Save miscellaneous information which needs to be written to the
629 * state file.  This information is required to re-initialize
630 * kernel/prom handshaking.
631 */
632void
633i_cpr_save_machdep_info(void)
634{
635	CPR_DEBUG(CPR_DEBUG5, "jumpback size = 0x%lx\n",
636	    (uintptr_t)&i_cpr_end_jumpback -
637	    (uintptr_t)i_cpr_resume_setup);
638
639	/*
640	 * Verify the jumpback code all falls in one page.
641	 */
642	if (((uintptr_t)&i_cpr_end_jumpback & MMU_PAGEMASK) !=
643	    ((uintptr_t)i_cpr_resume_setup & MMU_PAGEMASK))
644		cpr_err(CE_PANIC, "jumpback code exceeds one page.");
645}
646
647
648/*
649 * cpu0 should contain bootcpu info
650 */
651cpu_t *
652i_cpr_bootcpu(void)
653{
654	return (&cpu0);
655}
656
657processorid_t
658i_cpr_bootcpuid(void)
659{
660	return (0);
661}
662
663/*
664 * Return the virtual address of the mapping area
665 */
666caddr_t
667i_cpr_map_setup(void)
668{
669	/*
670	 * Allocate a virtual memory range spanned by an hmeblk.
671	 * This would be 8 hments or 64k bytes.  Starting VA
672	 * must be 64k (8-page) aligned.
673	 */
674	cpr_vaddr = vmem_xalloc(heap_arena,
675	    mmu_ptob(NHMENTS), mmu_ptob(NHMENTS),
676	    0, 0, NULL, NULL, VM_NOSLEEP);
677	return (cpr_vaddr);
678}
679
680/*
681 * create tmp locked tlb entries for a group of phys pages;
682 *
683 * i_cpr_mapin/i_cpr_mapout should always be called in pairs,
684 * otherwise would fill up a tlb with locked entries
685 */
686void
687i_cpr_mapin(caddr_t vaddr, uint_t pages, pfn_t ppn)
688{
689	tte_t tte;
690	extern pfn_t curthreadpfn;
691	extern int curthreadremapped;
692
693	curthreadremapped = (ppn <= curthreadpfn && curthreadpfn < ppn + pages);
694
695	for (; pages--; ppn++, vaddr += MMU_PAGESIZE) {
696		tte.tte_inthi = TTE_VALID_INT | TTE_PFN_INTHI(ppn);
697		tte.tte_intlo = TTE_PFN_INTLO(ppn) | TTE_LCK_INT |
698		    TTE_CP_INT | TTE_PRIV_INT | TTE_HWWR_INT;
699		sfmmu_dtlb_ld_kva(vaddr, &tte);
700	}
701}
702
703void
704i_cpr_mapout(caddr_t vaddr, uint_t pages)
705{
706	extern int curthreadremapped;
707
708	if (curthreadremapped && vaddr <= (caddr_t)curthread &&
709	    (caddr_t)curthread < vaddr + pages * MMU_PAGESIZE)
710		curthreadremapped = 0;
711
712	for (; pages--; vaddr += MMU_PAGESIZE)
713		vtag_flushpage(vaddr, (uint64_t)ksfmmup);
714}
715
716/*
717 * We're done using the mapping area; release virtual space
718 */
719void
720i_cpr_map_destroy(void)
721{
722	vmem_free(heap_arena, cpr_vaddr, mmu_ptob(NHMENTS));
723	cpr_vaddr = NULL;
724}
725
726/* ARGSUSED */
727void
728i_cpr_handle_xc(int flag)
729{
730}
731
732
733/*
734 * This function takes care of pages which are not in kas or need to be
735 * taken care of in a special way.  For example, panicbuf pages are not
736 * in kas and their pages are allocated via prom_retain().
737 */
738pgcnt_t
739i_cpr_count_special_kpages(int mapflag, bitfunc_t bitfunc)
740{
741	struct cpr_map_info *pri, *tail;
742	pgcnt_t pages, total = 0;
743	pfn_t pfn;
744
745	/*
746	 * Save information about prom retained panicbuf pages
747	 */
748	if (bitfunc == cpr_setbit) {
749		pri = &cpr_prom_retain[CPR_PANICBUF];
750		pri->virt = (cpr_ptr)panicbuf;
751		pri->phys = va_to_pa(panicbuf);
752		pri->size = sizeof (panicbuf);
753	}
754
755	/*
756	 * Go through the prom_retain array to tag those pages.
757	 */
758	tail = &cpr_prom_retain[CPR_PROM_RETAIN_CNT];
759	for (pri = cpr_prom_retain; pri < tail; pri++) {
760		pages = mmu_btopr(pri->size);
761		for (pfn = ADDR_TO_PN(pri->phys); pages--; pfn++) {
762			if (pf_is_memory(pfn)) {
763				if (bitfunc == cpr_setbit) {
764					if ((*bitfunc)(pfn, mapflag) == 0)
765						total++;
766				} else
767					total++;
768			}
769		}
770	}
771
772	return (total);
773}
774
775
776/*
777 * Free up memory-related resources here.  We start by freeing buffers
778 * allocated during suspend initialization.  Also, free up the mapping
779 * resources allocated in cpr_init().
780 */
781void
782i_cpr_free_memory_resources(void)
783{
784	(void) i_cpr_prom_pages(CPR_PROM_FREE);
785	i_cpr_map_destroy();
786	i_cpr_storage_free();
787}
788
789
790/*
791 * Derived from cpr_write_statefile().
792 * Save the sensitive pages to the storage area and do bookkeeping
793 * using the sensitive descriptors. Each descriptor will contain no more
794 * than CPR_MAXCONTIG amount of contiguous pages to match the max amount
795 * of pages that statefile gets written to disk at each write.
796 * XXX The CPR_MAXCONTIG can be changed to the size of the compression
797 * scratch area.
798 */
799static int
800i_cpr_save_to_storage(void)
801{
802	sensitive_size_saved = 0;
803	sensitive_pages_saved = 0;
804	sensitive_write_ptr = i_cpr_storage_data_base;
805	return (cpr_contig_pages(NULL, SAVE_TO_STORAGE));
806}
807
808
809/*
810 * This routine allocates space to save the sensitive kernel pages,
811 * i.e. kernel data nucleus, kvalloc and kvseg segments.
812 * It's assumed that those segments are the only areas that can be
813 * contaminated by memory allocations during statefile dumping.
814 * The space allocated here contains:
815 * 	A list of descriptors describing the saved sensitive pages.
816 * 	The storage area for saving the compressed sensitive kernel pages.
817 * Since storage pages are allocated from segkmem, they need to be
818 * excluded when saving.
819 */
820int
821i_cpr_save_sensitive_kpages(void)
822{
823	static const char pages_fmt[] = "\n%s %s allocs\n"
824	    "	spages %ld, vpages %ld, diff %ld\n";
825	int retry_cnt;
826	int error = 0;
827	pgcnt_t pages, spages, vpages;
828	caddr_t	addr;
829	char *str;
830
831	/*
832	 * Tag sensitive kpages. Allocate space for storage descriptors
833	 * and storage data area based on the resulting bitmaps.
834	 * Note: The storage space will be part of the sensitive
835	 * segment, so we need to tag kpages here before the storage
836	 * is actually allocated just so their space won't be accounted
837	 * for. They will not be part of the statefile although those
838	 * pages will be claimed by cprboot.
839	 */
840	cpr_clear_bitmaps();
841
842	spages = i_cpr_count_sensitive_kpages(REGULAR_BITMAP, cpr_setbit);
843	vpages = cpr_count_volatile_pages(REGULAR_BITMAP, cpr_clrbit);
844	pages = spages - vpages;
845
846	str = "i_cpr_save_sensitive_kpages:";
847	CPR_DEBUG(CPR_DEBUG7, pages_fmt, "before", str, spages, vpages, pages);
848
849	/*
850	 * Allocate space to save the clean sensitive kpages
851	 */
852	for (retry_cnt = 0; retry_cnt < MAX_STORAGE_ALLOC_RETRY; retry_cnt++) {
853		/*
854		 * Alloc on first pass or realloc if we are retrying because
855		 * of insufficient storage for sensitive pages
856		 */
857		if (retry_cnt == 0 || error == ENOMEM) {
858			if (i_cpr_storage_data_base) {
859				kmem_free(i_cpr_storage_data_base,
860				    mmu_ptob(i_cpr_storage_data_sz));
861				i_cpr_storage_data_base = NULL;
862				i_cpr_storage_data_sz = 0;
863			}
864			addr = i_cpr_storage_data_alloc(pages,
865			    &i_cpr_storage_data_sz, retry_cnt);
866			if (addr == NULL) {
867				CPR_DEBUG(CPR_DEBUG7,
868				    "\n%s can't allocate data storage space!\n",
869				    str);
870				return (ENOMEM);
871			}
872			i_cpr_storage_data_base = addr;
873			i_cpr_storage_data_end =
874			    addr + mmu_ptob(i_cpr_storage_data_sz);
875		}
876
877		/*
878		 * Allocate on first pass, only realloc if retry is because of
879		 * insufficient descriptors, but reset contents on each pass
880		 * (desc_alloc resets contents as well)
881		 */
882		if (retry_cnt == 0 || error == -1) {
883			error = i_cpr_storage_desc_alloc(
884			    &i_cpr_storage_desc_base, &i_cpr_storage_desc_pgcnt,
885			    &i_cpr_storage_desc_end, retry_cnt);
886			if (error != 0)
887				return (error);
888		} else {
889			i_cpr_storage_desc_init(i_cpr_storage_desc_base,
890			    i_cpr_storage_desc_pgcnt, i_cpr_storage_desc_end);
891		}
892
893		/*
894		 * We are ready to save the sensitive kpages to storage.
895		 * We cannot trust what's tagged in the bitmaps anymore
896		 * after storage allocations.  Clear up the bitmaps and
897		 * retag the sensitive kpages again.  The storage pages
898		 * should be untagged.
899		 */
900		cpr_clear_bitmaps();
901
902		spages =
903		    i_cpr_count_sensitive_kpages(REGULAR_BITMAP, cpr_setbit);
904		vpages = cpr_count_volatile_pages(REGULAR_BITMAP, cpr_clrbit);
905
906		CPR_DEBUG(CPR_DEBUG7, pages_fmt, "after ", str,
907		    spages, vpages, spages - vpages);
908
909		/*
910		 * Returns 0 on success, -1 if too few descriptors, and
911		 * ENOMEM if not enough space to save sensitive pages
912		 */
913		CPR_DEBUG(CPR_DEBUG1, "compressing pages to storage...\n");
914		error = i_cpr_save_to_storage();
915		if (error == 0) {
916			/* Saving to storage succeeded */
917			CPR_DEBUG(CPR_DEBUG1, "compressed %d pages\n",
918			    sensitive_pages_saved);
919			break;
920		} else if (error == -1)
921			CPR_DEBUG(CPR_DEBUG1, "%s too few descriptors\n", str);
922	}
923	if (error == -1)
924		error = ENOMEM;
925	return (error);
926}
927
928
929/*
930 * Estimate how much memory we will need to save
931 * the sensitive pages with compression.
932 */
933static caddr_t
934i_cpr_storage_data_alloc(pgcnt_t pages, pgcnt_t *alloc_pages, int retry_cnt)
935{
936	pgcnt_t alloc_pcnt, last_pcnt;
937	caddr_t addr;
938	char *str;
939
940	str = "i_cpr_storage_data_alloc:";
941	if (retry_cnt == 0) {
942		/*
943		 * common compression ratio is about 3:1
944		 * initial storage allocation is estimated at 40%
945		 * to cover the majority of cases
946		 */
947		alloc_pcnt = INITIAL_ALLOC_PCNT;
948		*alloc_pages = (pages * alloc_pcnt) / INTEGRAL;
949		CPR_DEBUG(CPR_DEBUG7, "%s sensitive pages: %ld\n", str, pages);
950		CPR_DEBUG(CPR_DEBUG7,
951		    "%s initial est pages: %ld, alloc %ld%%\n",
952		    str, *alloc_pages, alloc_pcnt);
953	} else {
954		/*
955		 * calculate the prior compression percentage (x100)
956		 * from the last attempt to save sensitive pages
957		 */
958		ASSERT(sensitive_pages_saved != 0);
959		last_pcnt = (mmu_btopr(sensitive_size_saved) * INTEGRAL) /
960		    sensitive_pages_saved;
961		CPR_DEBUG(CPR_DEBUG7, "%s last ratio %ld%%\n", str, last_pcnt);
962
963		/*
964		 * new estimated storage size is based on
965		 * the larger ratio + 5% for each retry:
966		 * pages * (last + [5%, 10%])
967		 */
968		alloc_pcnt = MAX(last_pcnt, INITIAL_ALLOC_PCNT) +
969		    (retry_cnt * 5);
970		*alloc_pages = (pages * alloc_pcnt) / INTEGRAL;
971		CPR_DEBUG(CPR_DEBUG7, "%s Retry est pages: %ld, alloc %ld%%\n",
972		    str, *alloc_pages, alloc_pcnt);
973	}
974
975	addr = kmem_alloc(mmu_ptob(*alloc_pages), KM_NOSLEEP);
976	CPR_DEBUG(CPR_DEBUG7, "%s alloc %ld pages\n", str, *alloc_pages);
977	return (addr);
978}
979
980
981void
982i_cpr_storage_free(void)
983{
984	/* Free descriptors */
985	if (i_cpr_storage_desc_base) {
986		kmem_free(i_cpr_storage_desc_base,
987		    mmu_ptob(i_cpr_storage_desc_pgcnt));
988		i_cpr_storage_desc_base = NULL;
989		i_cpr_storage_desc_pgcnt = 0;
990	}
991
992
993	/* Data storage */
994	if (i_cpr_storage_data_base) {
995		kmem_free(i_cpr_storage_data_base,
996		    mmu_ptob(i_cpr_storage_data_sz));
997		i_cpr_storage_data_base = NULL;
998		i_cpr_storage_data_sz = 0;
999	}
1000}
1001
1002
1003/*
1004 * This routine is derived from cpr_compress_and_write().
1005 * 1. Do bookkeeping in the descriptor for the contiguous sensitive chunk.
1006 * 2. Compress and save the clean sensitive pages into the storage area.
1007 */
1008int
1009i_cpr_compress_and_save(int chunks, pfn_t spfn, pgcnt_t pages)
1010{
1011	extern char *cpr_compress_pages(cpd_t *, pgcnt_t, int);
1012	extern caddr_t i_cpr_storage_data_end;
1013	uint_t remaining, datalen;
1014	uint32_t test_usum;
1015	char *datap;
1016	csd_t *descp;
1017	cpd_t cpd;
1018	int error;
1019
1020	/*
1021	 * Fill next empty storage descriptor
1022	 */
1023	descp = i_cpr_storage_desc_base + chunks - 1;
1024	if (descp >= i_cpr_storage_desc_end) {
1025		CPR_DEBUG(CPR_DEBUG1, "ran out of descriptors, base 0x%p, "
1026		    "chunks %d, end 0x%p, descp 0x%p\n",
1027		    (void *)i_cpr_storage_desc_base, chunks,
1028		    (void *)i_cpr_storage_desc_end, (void *)descp);
1029		return (-1);
1030	}
1031	ASSERT(descp->csd_dirty_spfn == (uint_t)-1);
1032	i_cpr_storage_desc_last_used = descp;
1033
1034	descp->csd_dirty_spfn = spfn;
1035	descp->csd_dirty_npages = pages;
1036
1037	i_cpr_mapin(CPR->c_mapping_area, pages, spfn);
1038
1039	/*
1040	 * try compressing pages and copy cpd fields
1041	 * pfn is copied for debug use
1042	 */
1043	cpd.cpd_pfn = spfn;
1044	datap = cpr_compress_pages(&cpd, pages, C_COMPRESSING);
1045	datalen = cpd.cpd_length;
1046	descp->csd_clean_compressed = (cpd.cpd_flag & CPD_COMPRESS);
1047#ifdef DEBUG
1048	descp->csd_usum = cpd.cpd_usum;
1049	descp->csd_csum = cpd.cpd_csum;
1050#endif
1051
1052	error = 0;
1053
1054	/*
1055	 * Save the raw or compressed data to the storage area pointed to by
1056	 * sensitive_write_ptr. Make sure the storage space is big enough to
1057	 * hold the result. Otherwise roll back to increase the storage space.
1058	 */
1059	descp->csd_clean_sva = (cpr_ptr)sensitive_write_ptr;
1060	descp->csd_clean_sz = datalen;
1061	if ((sensitive_write_ptr + datalen) < i_cpr_storage_data_end) {
1062		extern	void cprbcopy(void *, void *, size_t);
1063
1064		cprbcopy(datap, sensitive_write_ptr, datalen);
1065		sensitive_size_saved += datalen;
1066		sensitive_pages_saved += descp->csd_dirty_npages;
1067		sensitive_write_ptr += datalen;
1068	} else {
1069		remaining = (i_cpr_storage_data_end - sensitive_write_ptr);
1070		CPR_DEBUG(CPR_DEBUG1, "i_cpr_compress_and_save: The storage "
1071		    "space is too small!\ngot %d, want %d\n\n",
1072		    remaining, (remaining + datalen));
1073#ifdef	DEBUG
1074		/*
1075		 * Check to see if the content of the sensitive pages that we
1076		 * just copied have changed during this small time window.
1077		 */
1078		test_usum = checksum32(CPR->c_mapping_area, mmu_ptob(pages));
1079		descp->csd_usum = cpd.cpd_usum;
1080		if (test_usum != descp->csd_usum) {
1081			CPR_DEBUG(CPR_DEBUG1, "\nWARNING: "
1082			    "i_cpr_compress_and_save: "
1083			    "Data in the range of pfn 0x%lx to pfn "
1084			    "0x%lx has changed after they are saved "
1085			    "into storage.", spfn, (spfn + pages - 1));
1086		}
1087#endif
1088		error = ENOMEM;
1089	}
1090
1091	i_cpr_mapout(CPR->c_mapping_area, pages);
1092	return (error);
1093}
1094
1095
1096/*
1097 * This routine is derived from cpr_count_kpages().
1098 * It goes through kernel data nucleus and segkmem segments to select
1099 * pages in use and mark them in the corresponding bitmap.
1100 */
1101pgcnt_t
1102i_cpr_count_sensitive_kpages(int mapflag, bitfunc_t bitfunc)
1103{
1104	pgcnt_t kdata_cnt = 0, segkmem_cnt = 0;
1105	extern caddr_t e_moddata;
1106	extern struct seg kvalloc;
1107	extern struct seg kmem64;
1108	size_t size;
1109
1110	/*
1111	 * Kernel data nucleus pages
1112	 */
1113	size = e_moddata - s_data;
1114	kdata_cnt += cpr_count_pages(s_data, size,
1115	    mapflag, bitfunc, DBG_SHOWRANGE);
1116
1117	/*
1118	 * kvseg and kvalloc pages
1119	 */
1120	segkmem_cnt += cpr_scan_kvseg(mapflag, bitfunc, &kvseg);
1121	segkmem_cnt += cpr_count_pages(kvalloc.s_base, kvalloc.s_size,
1122	    mapflag, bitfunc, DBG_SHOWRANGE);
1123
1124	/* segment to support kernel memory usage above 32-bit space (4GB) */
1125	if (kmem64.s_base)
1126		segkmem_cnt += cpr_count_pages(kmem64.s_base, kmem64.s_size,
1127		    mapflag, bitfunc, DBG_SHOWRANGE);
1128
1129	CPR_DEBUG(CPR_DEBUG7, "\ni_cpr_count_sensitive_kpages:\n"
1130	    "\tkdata_cnt %ld + segkmem_cnt %ld = %ld pages\n",
1131	    kdata_cnt, segkmem_cnt, kdata_cnt + segkmem_cnt);
1132
1133	return (kdata_cnt + segkmem_cnt);
1134}
1135
1136
1137pgcnt_t
1138i_cpr_count_storage_pages(int mapflag, bitfunc_t bitfunc)
1139{
1140	pgcnt_t count = 0;
1141
1142	if (i_cpr_storage_desc_base) {
1143		count += cpr_count_pages((caddr_t)i_cpr_storage_desc_base,
1144		    (size_t)mmu_ptob(i_cpr_storage_desc_pgcnt),
1145		    mapflag, bitfunc, DBG_SHOWRANGE);
1146	}
1147	if (i_cpr_storage_data_base) {
1148		count += cpr_count_pages(i_cpr_storage_data_base,
1149		    (size_t)mmu_ptob(i_cpr_storage_data_sz),
1150		    mapflag, bitfunc, DBG_SHOWRANGE);
1151	}
1152	return (count);
1153}
1154
1155
1156/*
1157 * Derived from cpr_write_statefile().
1158 * Allocate (or reallocate after exhausting the supply) descriptors for each
1159 * chunk of contiguous sensitive kpages.
1160 */
1161static int
1162i_cpr_storage_desc_alloc(csd_t **basepp, pgcnt_t *pgsp, csd_t **endpp,
1163    int retry)
1164{
1165	pgcnt_t npages;
1166	int chunks;
1167	csd_t	*descp, *end;
1168	size_t	len;
1169	char *str = "i_cpr_storage_desc_alloc:";
1170
1171	/*
1172	 * On initial allocation, add some extra to cover overhead caused
1173	 * by the allocation for the storage area later.
1174	 */
1175	if (retry == 0) {
1176		chunks = cpr_contig_pages(NULL, STORAGE_DESC_ALLOC) +
1177		    EXTRA_DESCS;
1178		npages = mmu_btopr(sizeof (**basepp) * (pgcnt_t)chunks);
1179		CPR_DEBUG(CPR_DEBUG7, "%s chunks %d, ", str, chunks);
1180	} else {
1181		CPR_DEBUG(CPR_DEBUG7, "%s retry %d: ", str, retry);
1182		npages = *pgsp + 1;
1183	}
1184	/* Free old descriptors, if any */
1185	if (*basepp)
1186		kmem_free((caddr_t)*basepp, mmu_ptob(*pgsp));
1187
1188	descp = *basepp = kmem_alloc(mmu_ptob(npages), KM_NOSLEEP);
1189	if (descp == NULL) {
1190		CPR_DEBUG(CPR_DEBUG7, "%s no space for descriptors!\n", str);
1191		return (ENOMEM);
1192	}
1193
1194	*pgsp = npages;
1195	len = mmu_ptob(npages);
1196	end = *endpp = descp + (len / (sizeof (**basepp)));
1197	CPR_DEBUG(CPR_DEBUG7, "npages 0x%lx, len 0x%lx, items 0x%lx\n\t*basepp "
1198	    "%p, *endpp %p\n", npages, len, (len / (sizeof (**basepp))),
1199	    (void *)*basepp, (void *)*endpp);
1200	i_cpr_storage_desc_init(descp, npages, end);
1201	return (0);
1202}
1203
1204static void
1205i_cpr_storage_desc_init(csd_t *descp, pgcnt_t npages, csd_t *end)
1206{
1207	size_t	len = mmu_ptob(npages);
1208
1209	/* Initialize the descriptors to something impossible. */
1210	bzero(descp, len);
1211#ifdef	DEBUG
1212	/*
1213	 * This condition is tested by an ASSERT
1214	 */
1215	for (; descp < end; descp++)
1216		descp->csd_dirty_spfn = (uint_t)-1;
1217#endif
1218}
1219
1220int
1221i_cpr_dump_sensitive_kpages(vnode_t *vp)
1222{
1223	int	error = 0;
1224	uint_t	spin_cnt = 0;
1225	csd_t	*descp;
1226
1227	/*
1228	 * These following two variables need to be reinitialized
1229	 * for each cpr cycle.
1230	 */
1231	i_cpr_sensitive_bytes_dumped = 0;
1232	i_cpr_sensitive_pgs_dumped = 0;
1233
1234	if (i_cpr_storage_desc_base) {
1235		for (descp = i_cpr_storage_desc_base;
1236		    descp <= i_cpr_storage_desc_last_used; descp++) {
1237			if (error = cpr_dump_sensitive(vp, descp))
1238				return (error);
1239			spin_cnt++;
1240			if ((spin_cnt & 0x5F) == 1)
1241				cpr_spinning_bar();
1242		}
1243		prom_printf(" \b");
1244	}
1245
1246	CPR_DEBUG(CPR_DEBUG7, "\ni_cpr_dump_sensitive_kpages: dumped %ld\n",
1247	    i_cpr_sensitive_pgs_dumped);
1248	return (0);
1249}
1250
1251
1252/*
1253 * 1. Fill the cpr page descriptor with the info of the dirty pages
1254 *    and
1255 *    write the descriptor out. It will be used at resume.
1256 * 2. Write the clean data in stead of the dirty data out.
1257 *    Note: to save space, the clean data is already compressed.
1258 */
1259static int
1260cpr_dump_sensitive(vnode_t *vp, csd_t *descp)
1261{
1262	int error = 0;
1263	caddr_t datap;
1264	cpd_t cpd;	/* cpr page descriptor */
1265	pfn_t	dirty_spfn;
1266	pgcnt_t dirty_npages;
1267	size_t clean_sz;
1268	caddr_t	clean_sva;
1269	int	clean_compressed;
1270	extern uchar_t cpr_pagecopy[];
1271
1272	dirty_spfn = descp->csd_dirty_spfn;
1273	dirty_npages = descp->csd_dirty_npages;
1274	clean_sva = (caddr_t)descp->csd_clean_sva;
1275	clean_sz = descp->csd_clean_sz;
1276	clean_compressed = descp->csd_clean_compressed;
1277
1278	/* Fill cpr page descriptor. */
1279	cpd.cpd_magic = (uint_t)CPR_PAGE_MAGIC;
1280	cpd.cpd_pfn = dirty_spfn;
1281	cpd.cpd_flag = 0;  /* must init to zero */
1282	cpd.cpd_pages = dirty_npages;
1283
1284#ifdef	DEBUG
1285	if ((cpd.cpd_usum = descp->csd_usum) != 0)
1286		cpd.cpd_flag |= CPD_USUM;
1287	if ((cpd.cpd_csum = descp->csd_csum) != 0)
1288		cpd.cpd_flag |= CPD_CSUM;
1289#endif
1290
1291	STAT->cs_dumped_statefsz += mmu_ptob(dirty_npages);
1292
1293	/*
1294	 * The sensitive kpages are usually saved with compression
1295	 * unless compression could not reduce the size of the data.
1296	 * If user choose not to have the statefile compressed,
1297	 * we need to decompress the data back before dumping it to disk.
1298	 */
1299	if (CPR->c_flags & C_COMPRESSING) {
1300		cpd.cpd_length = clean_sz;
1301		datap = clean_sva;
1302		if (clean_compressed)
1303			cpd.cpd_flag |= CPD_COMPRESS;
1304	} else {
1305		if (clean_compressed) {
1306			cpd.cpd_length = decompress(clean_sva, cpr_pagecopy,
1307			    clean_sz, mmu_ptob(dirty_npages));
1308			datap = (caddr_t)cpr_pagecopy;
1309			ASSERT(cpd.cpd_length == mmu_ptob(dirty_npages));
1310		} else {
1311			cpd.cpd_length = clean_sz;
1312			datap = clean_sva;
1313		}
1314		cpd.cpd_csum = 0;
1315	}
1316
1317	/* Write cpr page descriptor */
1318	error = cpr_write(vp, (caddr_t)&cpd, sizeof (cpd));
1319	if (error) {
1320		CPR_DEBUG(CPR_DEBUG7, "descp: %p\n", (void *)descp);
1321#ifdef DEBUG
1322		debug_enter("cpr_dump_sensitive: cpr_write() page "
1323		    "descriptor failed!\n");
1324#endif
1325		return (error);
1326	}
1327
1328	i_cpr_sensitive_bytes_dumped += sizeof (cpd_t);
1329
1330	/* Write page data */
1331	error = cpr_write(vp, (caddr_t)datap, cpd.cpd_length);
1332	if (error) {
1333		CPR_DEBUG(CPR_DEBUG7, "error: %x\n", error);
1334		CPR_DEBUG(CPR_DEBUG7, "descp: %p\n", (void *)descp);
1335		CPR_DEBUG(CPR_DEBUG7, "cpr_write(%p, %p , %lx)\n",
1336		    (void *)vp, (void *)datap, cpd.cpd_length);
1337#ifdef DEBUG
1338		debug_enter("cpr_dump_sensitive: cpr_write() data failed!\n");
1339#endif
1340		return (error);
1341	}
1342
1343	i_cpr_sensitive_bytes_dumped += cpd.cpd_length;
1344	i_cpr_sensitive_pgs_dumped += dirty_npages;
1345
1346	return (error);
1347}
1348
1349
1350/*
1351 * Sanity check to make sure that we have dumped right amount
1352 * of pages from different sources to statefile.
1353 */
1354int
1355i_cpr_check_pgs_dumped(uint_t pgs_expected, uint_t regular_pgs_dumped)
1356{
1357	uint_t total_pgs_dumped;
1358
1359	total_pgs_dumped = regular_pgs_dumped + i_cpr_sensitive_pgs_dumped;
1360
1361	CPR_DEBUG(CPR_DEBUG7, "\ncheck_pgs: reg %d + sens %ld = %d, "
1362	    "expect %d\n\n", regular_pgs_dumped, i_cpr_sensitive_pgs_dumped,
1363	    total_pgs_dumped, pgs_expected);
1364
1365	if (pgs_expected == total_pgs_dumped)
1366		return (0);
1367
1368	return (EINVAL);
1369}
1370
1371
1372int
1373i_cpr_reusefini(void)
1374{
1375	struct vnode *vp;
1376	cdef_t *cdef;
1377	size_t size;
1378	char *bufp;
1379	int rc;
1380
1381	if (cpr_reusable_mode)
1382		cpr_reusable_mode = 0;
1383
1384	if (rc = cpr_open_deffile(FREAD|FWRITE, &vp)) {
1385		if (rc == EROFS) {
1386			cpr_err(CE_CONT, "uadmin A_FREEZE AD_REUSEFINI "
1387			    "(uadmin %d %d)\nmust be done with / mounted "
1388			    "writeable.\n", A_FREEZE, AD_REUSEFINI);
1389		}
1390		return (rc);
1391	}
1392
1393	cdef = kmem_alloc(sizeof (*cdef), KM_SLEEP);
1394	rc = cpr_rdwr(UIO_READ, vp, cdef, sizeof (*cdef));
1395
1396	if (rc) {
1397		cpr_err(CE_WARN, "Failed reading %s, errno = %d",
1398		    cpr_default_path, rc);
1399	} else if (cdef->mini.magic != CPR_DEFAULT_MAGIC) {
1400		cpr_err(CE_WARN, "bad magic number in %s, cannot restore "
1401		    "prom values for %s", cpr_default_path,
1402		    cpr_enumerate_promprops(&bufp, &size));
1403		kmem_free(bufp, size);
1404		rc = EINVAL;
1405	} else {
1406		/*
1407		 * clean up prom properties
1408		 */
1409		rc = cpr_update_nvram(cdef->props);
1410		if (rc == 0) {
1411			/*
1412			 * invalidate the disk copy and turn off reusable
1413			 */
1414			cdef->mini.magic = 0;
1415			cdef->mini.reusable = 0;
1416			if (rc = cpr_rdwr(UIO_WRITE, vp,
1417			    &cdef->mini, sizeof (cdef->mini))) {
1418				cpr_err(CE_WARN, "Failed writing %s, errno %d",
1419				    cpr_default_path, rc);
1420			}
1421		}
1422	}
1423
1424	(void) VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED(), NULL);
1425	VN_RELE(vp);
1426	kmem_free(cdef, sizeof (*cdef));
1427
1428	return (rc);
1429}
1430
1431
1432int
1433i_cpr_reuseinit(void)
1434{
1435	int rc = 0;
1436
1437	if (rc = cpr_default_setup(1))
1438		return (rc);
1439
1440	/*
1441	 * We need to validate default file
1442	 */
1443	rc = cpr_validate_definfo(1);
1444	if (rc == 0)
1445		cpr_reusable_mode = 1;
1446	else if (rc == EROFS) {
1447		cpr_err(CE_NOTE, "reuseinit must be performed "
1448		    "while / is mounted writeable");
1449	}
1450
1451	(void) cpr_default_setup(0);
1452
1453	return (rc);
1454}
1455
1456
1457int
1458i_cpr_check_cprinfo(void)
1459{
1460	struct vnode *vp;
1461	cmini_t mini;
1462	int rc = 0;
1463
1464	if (rc = cpr_open_deffile(FREAD, &vp)) {
1465		if (rc == ENOENT)
1466			cpr_err(CE_NOTE, "cprinfo file does not "
1467			    "exist.  You must run 'uadmin %d %d' "
1468			    "command while / is mounted writeable,\n"
1469			    "then reboot and run 'uadmin %d %d' "
1470			    "to create a reusable statefile",
1471			    A_FREEZE, AD_REUSEINIT, A_FREEZE, AD_REUSABLE);
1472		return (rc);
1473	}
1474
1475	rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini));
1476	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
1477	VN_RELE(vp);
1478
1479	if (rc) {
1480		cpr_err(CE_WARN, "Failed reading %s, errno = %d",
1481		    cpr_default_path, rc);
1482	} else if (mini.magic != CPR_DEFAULT_MAGIC) {
1483		cpr_err(CE_CONT, "bad magic number in cprinfo file.\n"
1484		    "You must run 'uadmin %d %d' while / is mounted "
1485		    "writeable, then reboot and run 'uadmin %d %d' "
1486		    "to create a reusable statefile\n",
1487		    A_FREEZE, AD_REUSEINIT, A_FREEZE, AD_REUSABLE);
1488		rc = EINVAL;
1489	}
1490
1491	return (rc);
1492}
1493
1494
1495int
1496i_cpr_reusable_supported(void)
1497{
1498	return (1);
1499}
1500
1501
1502/*
1503 * find prom phys pages and alloc space for a tmp copy
1504 */
1505static int
1506i_cpr_find_ppages(void)
1507{
1508	extern struct vnode prom_ppages;
1509	struct page *pp;
1510	struct memlist *pmem;
1511	pgcnt_t npages, pcnt, scnt, vcnt;
1512	pfn_t ppn, plast, *dst;
1513	int mapflag;
1514
1515	cpr_clear_bitmaps();
1516	mapflag = REGULAR_BITMAP;
1517
1518	/*
1519	 * there should be a page_t for each phys page used by the kernel;
1520	 * set a bit for each phys page not tracked by a page_t
1521	 */
1522	pcnt = 0;
1523	memlist_read_lock();
1524	for (pmem = phys_install; pmem; pmem = pmem->next) {
1525		npages = mmu_btop(pmem->size);
1526		ppn = mmu_btop(pmem->address);
1527		for (plast = ppn + npages; ppn < plast; ppn++) {
1528			if (page_numtopp_nolock(ppn))
1529				continue;
1530			(void) cpr_setbit(ppn, mapflag);
1531			pcnt++;
1532		}
1533	}
1534	memlist_read_unlock();
1535
1536	/*
1537	 * clear bits for phys pages in each segment
1538	 */
1539	scnt = cpr_count_seg_pages(mapflag, cpr_clrbit);
1540
1541	/*
1542	 * set bits for phys pages referenced by the prom_ppages vnode;
1543	 * these pages are mostly comprised of forthdebug words
1544	 */
1545	vcnt = 0;
1546	for (pp = prom_ppages.v_pages; pp; ) {
1547		if (cpr_setbit(pp->p_offset, mapflag) == 0)
1548			vcnt++;
1549		pp = pp->p_vpnext;
1550		if (pp == prom_ppages.v_pages)
1551			break;
1552	}
1553
1554	/*
1555	 * total number of prom pages are:
1556	 * (non-page_t pages - seg pages + vnode pages)
1557	 */
1558	ppage_count = pcnt - scnt + vcnt;
1559	CPR_DEBUG(CPR_DEBUG1,
1560	    "find_ppages: pcnt %ld - scnt %ld + vcnt %ld = %ld\n",
1561	    pcnt, scnt, vcnt, ppage_count);
1562
1563	/*
1564	 * alloc array of pfn_t to store phys page list
1565	 */
1566	pphys_list_size = ppage_count * sizeof (pfn_t);
1567	pphys_list = kmem_alloc(pphys_list_size, KM_NOSLEEP);
1568	if (pphys_list == NULL) {
1569		cpr_err(CE_WARN, "cannot alloc pphys_list");
1570		return (ENOMEM);
1571	}
1572
1573	/*
1574	 * phys pages referenced in the bitmap should be
1575	 * those used by the prom; scan bitmap and save
1576	 * a list of prom phys page numbers
1577	 */
1578	dst = pphys_list;
1579	memlist_read_lock();
1580	for (pmem = phys_install; pmem; pmem = pmem->next) {
1581		npages = mmu_btop(pmem->size);
1582		ppn = mmu_btop(pmem->address);
1583		for (plast = ppn + npages; ppn < plast; ppn++) {
1584			if (cpr_isset(ppn, mapflag)) {
1585				ASSERT(dst < (pphys_list + ppage_count));
1586				*dst++ = ppn;
1587			}
1588		}
1589	}
1590	memlist_read_unlock();
1591
1592	/*
1593	 * allocate space to store prom pages
1594	 */
1595	ppage_buf = kmem_alloc(mmu_ptob(ppage_count), KM_NOSLEEP);
1596	if (ppage_buf == NULL) {
1597		kmem_free(pphys_list, pphys_list_size);
1598		pphys_list = NULL;
1599		cpr_err(CE_WARN, "cannot alloc ppage_buf");
1600		return (ENOMEM);
1601	}
1602
1603	return (0);
1604}
1605
1606
1607/*
1608 * save prom pages to kmem pages
1609 */
1610static void
1611i_cpr_save_ppages(void)
1612{
1613	pfn_t *pphys, *plast;
1614	caddr_t dst;
1615
1616	/*
1617	 * map in each prom page and copy to a kmem page
1618	 */
1619	dst = ppage_buf;
1620	plast = pphys_list + ppage_count;
1621	for (pphys = pphys_list; pphys < plast; pphys++) {
1622		i_cpr_mapin(cpr_vaddr, 1, *pphys);
1623		bcopy(cpr_vaddr, dst, MMU_PAGESIZE);
1624		i_cpr_mapout(cpr_vaddr, 1);
1625		dst += MMU_PAGESIZE;
1626	}
1627
1628	CPR_DEBUG(CPR_DEBUG1, "saved %ld prom pages\n", ppage_count);
1629}
1630
1631
1632/*
1633 * restore prom pages from kmem pages
1634 */
1635static void
1636i_cpr_restore_ppages(void)
1637{
1638	pfn_t *pphys, *plast;
1639	caddr_t src;
1640
1641	dcache_flushall();
1642
1643	/*
1644	 * map in each prom page and copy from a kmem page
1645	 */
1646	src = ppage_buf;
1647	plast = pphys_list + ppage_count;
1648	for (pphys = pphys_list; pphys < plast; pphys++) {
1649		i_cpr_mapin(cpr_vaddr, 1, *pphys);
1650		bcopy(src, cpr_vaddr, MMU_PAGESIZE);
1651		i_cpr_mapout(cpr_vaddr, 1);
1652		src += MMU_PAGESIZE;
1653	}
1654
1655	dcache_flushall();
1656
1657	CPR_DEBUG(CPR_DEBUG1, "restored %ld prom pages\n", ppage_count);
1658}
1659
1660
1661/*
1662 * save/restore prom pages or free related allocs
1663 */
1664int
1665i_cpr_prom_pages(int action)
1666{
1667	int error;
1668
1669	if (action == CPR_PROM_SAVE) {
1670		if (ppage_buf == NULL) {
1671			ASSERT(pphys_list == NULL);
1672			if (error = i_cpr_find_ppages())
1673				return (error);
1674			i_cpr_save_ppages();
1675		}
1676	} else if (action == CPR_PROM_RESTORE) {
1677		i_cpr_restore_ppages();
1678	} else if (action == CPR_PROM_FREE) {
1679		if (pphys_list) {
1680			ASSERT(pphys_list_size);
1681			kmem_free(pphys_list, pphys_list_size);
1682			pphys_list = NULL;
1683			pphys_list_size = 0;
1684		}
1685		if (ppage_buf) {
1686			ASSERT(ppage_count);
1687			kmem_free(ppage_buf, mmu_ptob(ppage_count));
1688			CPR_DEBUG(CPR_DEBUG1, "freed %ld prom pages\n",
1689			    ppage_count);
1690			ppage_buf = NULL;
1691			ppage_count = 0;
1692		}
1693	}
1694	return (0);
1695}
1696
1697
1698/*
1699 * record tlb data for the nucleus, bigktsb's, and the cpr module;
1700 * this data is later used by cprboot to install dtlb/itlb entries.
1701 * when we jump into the cpr module during the resume phase, those
1702 * mappings are needed until switching to the kernel trap table.
1703 * to make the dtte/itte info available during resume, we need
1704 * the info recorded prior to saving sensitive pages, otherwise
1705 * all the data would appear as NULLs.
1706 */
1707static void
1708i_cpr_save_tlbinfo(void)
1709{
1710	cti_t cti = {0};
1711
1712	/*
1713	 * during resume - shortly after jumping into the cpr module,
1714	 * sfmmu_load_mmustate() will overwrite any dtlb entry at any
1715	 * index used for TSBs; skip is set so that any saved tte will
1716	 * target other tlb offsets and prevent being lost during
1717	 * resume.  now scan the dtlb and save locked entries,
1718	 * then add entries for the tmp stack / data page and the
1719	 * cpr thread structure.
1720	 */
1721	cti.dst = m_info.dtte;
1722	cti.tail = cti.dst + CPR_MAX_TLB;
1723	cti.reader = dtlb_rd_entry;
1724	cti.writer = NULL;
1725	cti.filter = i_cpr_lnb;
1726	cti.index = cpunodes[CPU->cpu_id].dtlb_size - 1;
1727
1728	if (utsb_dtlb_ttenum != -1)
1729		cti.skip = (1 << utsb_dtlb_ttenum);
1730
1731	if (utsb4m_dtlb_ttenum != -1)
1732		cti.skip |= (1 << utsb4m_dtlb_ttenum);
1733
1734	i_cpr_scan_tlb(&cti);
1735	i_cpr_make_tte(&cti, &i_cpr_data_page, datava);
1736	i_cpr_make_tte(&cti, curthread, datava);
1737
1738	/*
1739	 * scan itlb and save locked entries; add an entry for
1740	 * the first text page of the cpr module; cprboot will
1741	 * jump to that page after restoring kernel pages.
1742	 */
1743	cti.dst = m_info.itte;
1744	cti.tail = cti.dst + CPR_MAX_TLB;
1745	cti.reader = itlb_rd_entry;
1746	cti.index = cpunodes[CPU->cpu_id].itlb_size - 1;
1747	cti.skip = 0;
1748	i_cpr_scan_tlb(&cti);
1749	i_cpr_make_tte(&cti, (void *)i_cpr_resume_setup, textva);
1750}
1751
1752
1753/* ARGSUSED */
1754int
1755i_cpr_dump_setup(vnode_t *vp)
1756{
1757	/*
1758	 * zero out m_info and add info to dtte/itte arrays
1759	 */
1760	bzero(&m_info, sizeof (m_info));
1761	i_cpr_save_tlbinfo();
1762	return (0);
1763}
1764
1765
1766int
1767i_cpr_is_supported(int sleeptype)
1768{
1769	char es_prop[] = "energystar-v2";
1770	pnode_t node;
1771	int last;
1772	extern int cpr_supported_override;
1773	extern int cpr_platform_enable;
1774
1775	if (sleeptype != CPR_TODISK)
1776		return (0);
1777
1778	/*
1779	 * The next statement tests if a specific platform has turned off
1780	 * cpr support.
1781	 */
1782	if (cpr_supported_override)
1783		return (0);
1784
1785	/*
1786	 * Do not inspect energystar-v* property if a platform has
1787	 * specifically turned on cpr support
1788	 */
1789	if (cpr_platform_enable)
1790		return (1);
1791
1792	node = prom_rootnode();
1793	if (prom_getproplen(node, es_prop) != -1)
1794		return (1);
1795	last = strlen(es_prop) - 1;
1796	es_prop[last] = '3';
1797	return (prom_getproplen(node, es_prop) != -1);
1798}
1799
1800
1801/*
1802 * the actual size of the statefile data isn't known until after all the
1803 * compressed pages are written; even the inode size doesn't reflect the
1804 * data size since there are usually many extra fs blocks.  for recording
1805 * the actual data size, the first sector of the statefile is copied to
1806 * a tmp buf, and the copy is later updated and flushed to disk.
1807 */
1808int
1809i_cpr_blockzero(char *base, char **bufpp, int *blkno, vnode_t *vp)
1810{
1811	extern int cpr_flush_write(vnode_t *);
1812	static char cpr_sector[DEV_BSIZE];
1813	cpr_ext bytes, *dst;
1814
1815	/*
1816	 * this routine is called after cdd_t and csu_md_t are copied
1817	 * to cpr_buf; mini-hack alert: the save/update method creates
1818	 * a dependency on the combined struct size being >= one sector
1819	 * or DEV_BSIZE; since introduction in Sol2.7, csu_md_t size is
1820	 * over 1K bytes and will probably grow with any changes.
1821	 *
1822	 * copy when vp is NULL, flush when non-NULL
1823	 */
1824	if (vp == NULL) {
1825		ASSERT((*bufpp - base) >= DEV_BSIZE);
1826		bcopy(base, cpr_sector, sizeof (cpr_sector));
1827		return (0);
1828	} else {
1829		bytes = dbtob(*blkno);
1830		dst = &((cdd_t *)cpr_sector)->cdd_filesize;
1831		bcopy(&bytes, dst, sizeof (bytes));
1832		bcopy(cpr_sector, base, sizeof (cpr_sector));
1833		*bufpp = base + sizeof (cpr_sector);
1834		*blkno = cpr_statefile_offset();
1835		CPR_DEBUG(CPR_DEBUG1, "statefile data size: %ld\n\n", bytes);
1836		return (cpr_flush_write(vp));
1837	}
1838}
1839
1840
1841/*
1842 * Allocate bitmaps according to the phys_install list.
1843 */
1844static int
1845i_cpr_bitmap_setup(void)
1846{
1847	struct memlist *pmem;
1848	cbd_t *dp, *tail;
1849	void *space;
1850	size_t size;
1851
1852	/*
1853	 * The number of bitmap descriptors will be the count of
1854	 * phys_install ranges plus 1 for a trailing NULL struct.
1855	 */
1856	cpr_nbitmaps = 1;
1857	for (pmem = phys_install; pmem; pmem = pmem->next)
1858		cpr_nbitmaps++;
1859
1860	if (cpr_nbitmaps > (CPR_MAX_BMDESC - 1)) {
1861		cpr_err(CE_WARN, "too many physical memory ranges %d, max %d",
1862		    cpr_nbitmaps, CPR_MAX_BMDESC - 1);
1863		return (EFBIG);
1864	}
1865
1866	/* Alloc an array of bitmap descriptors. */
1867	dp = kmem_zalloc(cpr_nbitmaps * sizeof (*dp), KM_NOSLEEP);
1868	if (dp == NULL) {
1869		cpr_nbitmaps = 0;
1870		return (ENOMEM);
1871	}
1872	tail = dp + cpr_nbitmaps;
1873
1874	CPR->c_bmda = dp;
1875	for (pmem = phys_install; pmem; pmem = pmem->next) {
1876		size = BITMAP_BYTES(pmem->size);
1877		space = kmem_zalloc(size * 2, KM_NOSLEEP);
1878		if (space == NULL)
1879			return (ENOMEM);
1880		ASSERT(dp < tail);
1881		dp->cbd_magic = CPR_BITMAP_MAGIC;
1882		dp->cbd_spfn = mmu_btop(pmem->address);
1883		dp->cbd_epfn = mmu_btop(pmem->address + pmem->size) - 1;
1884		dp->cbd_size = size;
1885		dp->cbd_reg_bitmap = (cpr_ptr)space;
1886		dp->cbd_vlt_bitmap = (cpr_ptr)((caddr_t)space + size);
1887		dp++;
1888	}
1889
1890	/* set magic for the last descriptor */
1891	ASSERT(dp == (tail - 1));
1892	dp->cbd_magic = CPR_BITMAP_MAGIC;
1893
1894	return (0);
1895}
1896
1897
1898void
1899i_cpr_bitmap_cleanup(void)
1900{
1901	cbd_t *dp;
1902
1903	if (CPR->c_bmda == NULL)
1904		return;
1905	for (dp = CPR->c_bmda; dp->cbd_size; dp++)
1906		kmem_free((void *)dp->cbd_reg_bitmap, dp->cbd_size * 2);
1907	kmem_free(CPR->c_bmda, cpr_nbitmaps * sizeof (*CPR->c_bmda));
1908	CPR->c_bmda = NULL;
1909	cpr_nbitmaps = 0;
1910}
1911
1912
1913/*
1914 * A "regular" and "volatile" bitmap are created for each range of
1915 * physical memory.  The volatile maps are used to count and track pages
1916 * susceptible to heap corruption - caused by drivers that allocate mem
1917 * during VOP_DUMP(); the regular maps are used for all the other non-
1918 * susceptible pages.  Before writing the bitmaps to the statefile,
1919 * each bitmap pair gets merged to simplify handling within cprboot.
1920 */
1921int
1922i_cpr_alloc_bitmaps(void)
1923{
1924	int err;
1925
1926	memlist_read_lock();
1927	err = i_cpr_bitmap_setup();
1928	memlist_read_unlock();
1929	if (err)
1930		i_cpr_bitmap_cleanup();
1931	return (err);
1932}
1933
1934
1935
1936/*
1937 * Power down the system.
1938 */
1939int
1940i_cpr_power_down(int sleeptype)
1941{
1942	int is_defined = 0;
1943	char *wordexists = "p\" power-off\" find nip swap l! ";
1944	char *req = "power-off";
1945
1946	ASSERT(sleeptype == CPR_TODISK);
1947
1948	/*
1949	 * is_defined has value -1 when defined
1950	 */
1951	prom_interpret(wordexists, (uintptr_t)&is_defined, 0, 0, 0, 0);
1952	if (is_defined) {
1953		CPR_DEBUG(CPR_DEBUG1, "\ncpr: %s...\n", req);
1954		prom_interpret(req, 0, 0, 0, 0, 0);
1955	}
1956	/*
1957	 * Only returns if failed
1958	 */
1959	return (EIO);
1960}
1961
1962void
1963i_cpr_stop_other_cpus(void)
1964{
1965	stop_other_cpus();
1966}
1967
1968/*
1969 *	Save context for the specified CPU
1970 */
1971/* ARGSUSED */
1972void *
1973i_cpr_save_context(void *arg)
1974{
1975	/*
1976	 * Not yet
1977	 */
1978	ASSERT(0);
1979	return (NULL);
1980}
1981
1982void
1983i_cpr_pre_resume_cpus(void)
1984{
1985	/*
1986	 * Not yet
1987	 */
1988	ASSERT(0);
1989}
1990
1991void
1992i_cpr_post_resume_cpus(void)
1993{
1994	/*
1995	 * Not yet
1996	 */
1997	ASSERT(0);
1998}
1999
2000/*
2001 * nothing to do
2002 */
2003void
2004i_cpr_alloc_cpus(void)
2005{
2006}
2007
2008/*
2009 * nothing to do
2010 */
2011void
2012i_cpr_free_cpus(void)
2013{
2014}
2015
2016/* ARGSUSED */
2017void
2018i_cpr_save_configuration(dev_info_t *dip)
2019{
2020	/*
2021	 * this is a no-op on sparc
2022	 */
2023}
2024
2025/* ARGSUSED */
2026void
2027i_cpr_restore_configuration(dev_info_t *dip)
2028{
2029	/*
2030	 * this is a no-op on sparc
2031	 */
2032}
2033