xref: /onnv-gate/usr/src/uts/i86pc/os/cpr_impl.c (revision 9989:33d24b36e077)
15295Srandyf /*
25295Srandyf  * CDDL HEADER START
35295Srandyf  *
45295Srandyf  * The contents of this file are subject to the terms of the
55295Srandyf  * Common Development and Distribution License (the "License").
65295Srandyf  * You may not use this file except in compliance with the License.
75295Srandyf  *
85295Srandyf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95295Srandyf  * or http://www.opensolaris.org/os/licensing.
105295Srandyf  * See the License for the specific language governing permissions
115295Srandyf  * and limitations under the License.
125295Srandyf  *
135295Srandyf  * When distributing Covered Code, include this CDDL HEADER in each
145295Srandyf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155295Srandyf  * If applicable, add the following below this CDDL HEADER, with the
165295Srandyf  * fields enclosed by brackets "[]" replaced with your own identifying
175295Srandyf  * information: Portions Copyright [yyyy] [name of copyright owner]
185295Srandyf  *
195295Srandyf  * CDDL HEADER END
205295Srandyf  */
215295Srandyf /*
22*9989SJoseph.Townsend@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235295Srandyf  * Use is subject to license terms.
245295Srandyf  */
255295Srandyf 
265295Srandyf /*
275295Srandyf  * Platform specific implementation code
285295Srandyf  * Currently only suspend to RAM is supported (ACPI S3)
295295Srandyf  */
305295Srandyf 
315295Srandyf #define	SUNDDI_IMPL
325295Srandyf 
335295Srandyf #include <sys/types.h>
345295Srandyf #include <sys/promif.h>
355295Srandyf #include <sys/prom_isa.h>
365295Srandyf #include <sys/prom_plat.h>
375295Srandyf #include <sys/cpuvar.h>
385295Srandyf #include <sys/pte.h>
395295Srandyf #include <vm/hat.h>
405295Srandyf #include <vm/page.h>
415295Srandyf #include <vm/as.h>
425295Srandyf #include <sys/cpr.h>
435295Srandyf #include <sys/kmem.h>
445295Srandyf #include <sys/clock.h>
455295Srandyf #include <sys/kmem.h>
465295Srandyf #include <sys/panic.h>
475295Srandyf #include <vm/seg_kmem.h>
485295Srandyf #include <sys/cpu_module.h>
495295Srandyf #include <sys/callb.h>
505295Srandyf #include <sys/machsystm.h>
515295Srandyf #include <sys/vmsystm.h>
525295Srandyf #include <sys/systm.h>
535295Srandyf #include <sys/archsystm.h>
545295Srandyf #include <sys/stack.h>
555295Srandyf #include <sys/fs/ufs_fs.h>
565295Srandyf #include <sys/memlist.h>
575295Srandyf #include <sys/bootconf.h>
585295Srandyf #include <sys/thread.h>
595295Srandyf #include <sys/x_call.h>
605295Srandyf #include <sys/smp_impldefs.h>
615295Srandyf #include <vm/vm_dep.h>
625295Srandyf #include <sys/psm.h>
635295Srandyf #include <sys/epm.h>
645295Srandyf #include <sys/cpr_wakecode.h>
655295Srandyf #include <sys/x86_archext.h>
665295Srandyf #include <sys/reboot.h>
675295Srandyf #include <sys/acpi/acpi.h>
685295Srandyf #include <sys/acpica.h>
695295Srandyf 
705295Srandyf #define	AFMT	"%lx"
715295Srandyf 
725295Srandyf extern int	flushes_require_xcalls;
735295Srandyf extern cpuset_t	cpu_ready_set;
745295Srandyf 
755295Srandyf #if defined(__amd64)
765295Srandyf extern void	*wc_long_mode_64(void);
775295Srandyf #endif	/* __amd64 */
785295Srandyf extern int	tsc_gethrtime_enable;
795295Srandyf extern	void	i_cpr_start_cpu(void);
805295Srandyf 
815295Srandyf ushort_t	cpr_mach_type = CPR_MACHTYPE_X86;
825295Srandyf void		(*cpr_start_cpu_func)(void) = i_cpr_start_cpu;
835295Srandyf 
845295Srandyf static wc_cpu_t	*wc_other_cpus = NULL;
856336Sbholler static cpuset_t procset;
865295Srandyf 
875295Srandyf static void
885295Srandyf init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt);
895295Srandyf 
905295Srandyf static int i_cpr_platform_alloc(psm_state_request_t *req);
915295Srandyf static void i_cpr_platform_free(psm_state_request_t *req);
925295Srandyf static int i_cpr_save_apic(psm_state_request_t *req);
935295Srandyf static int i_cpr_restore_apic(psm_state_request_t *req);
945817Sjan static int wait_for_set(cpuset_t *set, int who);
955295Srandyf 
96*9989SJoseph.Townsend@Sun.COM static	void i_cpr_save_stack(kthread_t *t, wc_cpu_t *wc_cpu);
97*9989SJoseph.Townsend@Sun.COM void i_cpr_restore_stack(kthread_t *t, greg_t *save_stack);
98*9989SJoseph.Townsend@Sun.COM 
99*9989SJoseph.Townsend@Sun.COM #ifdef STACK_GROWTH_DOWN
100*9989SJoseph.Townsend@Sun.COM #define	CPR_GET_STACK_START(t) ((t)->t_stkbase)
101*9989SJoseph.Townsend@Sun.COM #define	CPR_GET_STACK_END(t) ((t)->t_stk)
102*9989SJoseph.Townsend@Sun.COM #else
103*9989SJoseph.Townsend@Sun.COM #define	CPR_GET_STACK_START(t) ((t)->t_stk)
104*9989SJoseph.Townsend@Sun.COM #define	CPR_GET_STACK_END(t) ((t)->t_stkbase)
105*9989SJoseph.Townsend@Sun.COM #endif	/* STACK_GROWTH_DOWN */
106*9989SJoseph.Townsend@Sun.COM 
1075295Srandyf /*
1085295Srandyf  * restart paused slave cpus
1095295Srandyf  */
1105295Srandyf void
1115295Srandyf i_cpr_machdep_setup(void)
1125295Srandyf {
1135295Srandyf 	if (ncpus > 1) {
1145295Srandyf 		CPR_DEBUG(CPR_DEBUG1, ("MP restarted...\n"));
1155295Srandyf 		mutex_enter(&cpu_lock);
1165295Srandyf 		start_cpus();
1175295Srandyf 		mutex_exit(&cpu_lock);
1185295Srandyf 	}
1195295Srandyf }
1205295Srandyf 
1215295Srandyf 
1225295Srandyf /*
1235295Srandyf  * Stop all interrupt activities in the system
1245295Srandyf  */
1255295Srandyf void
1265295Srandyf i_cpr_stop_intr(void)
1275295Srandyf {
1285295Srandyf 	(void) spl7();
1295295Srandyf }
1305295Srandyf 
1315295Srandyf /*
1325295Srandyf  * Set machine up to take interrupts
1335295Srandyf  */
1345295Srandyf void
1355295Srandyf i_cpr_enable_intr(void)
1365295Srandyf {
1375295Srandyf 	(void) spl0();
1385295Srandyf }
1395295Srandyf 
1405295Srandyf /*
1415295Srandyf  * Save miscellaneous information which needs to be written to the
1425295Srandyf  * state file.  This information is required to re-initialize
1435295Srandyf  * kernel/prom handshaking.
1445295Srandyf  */
1455295Srandyf void
1465295Srandyf i_cpr_save_machdep_info(void)
1475295Srandyf {
1485295Srandyf 	int notcalled = 0;
1495295Srandyf 	ASSERT(notcalled);
1505295Srandyf }
1515295Srandyf 
1525295Srandyf 
1535295Srandyf void
1545295Srandyf i_cpr_set_tbr(void)
1555295Srandyf {
1565295Srandyf }
1575295Srandyf 
1585295Srandyf 
1595295Srandyf processorid_t
1605295Srandyf i_cpr_bootcpuid(void)
1615295Srandyf {
1625295Srandyf 	return (0);
1635295Srandyf }
1645295Srandyf 
1655295Srandyf /*
1665295Srandyf  * cpu0 should contain bootcpu info
1675295Srandyf  */
1685295Srandyf cpu_t *
1695295Srandyf i_cpr_bootcpu(void)
1705295Srandyf {
1715295Srandyf 	ASSERT(MUTEX_HELD(&cpu_lock));
1725295Srandyf 
1735295Srandyf 	return (cpu_get(i_cpr_bootcpuid()));
1745295Srandyf }
1755295Srandyf 
1765295Srandyf /*
1775295Srandyf  *	Save context for the specified CPU
1785295Srandyf  */
1795295Srandyf void *
1805295Srandyf i_cpr_save_context(void *arg)
1815295Srandyf {
1825295Srandyf 	long	index = (long)arg;
1835295Srandyf 	psm_state_request_t *papic_state;
1845295Srandyf 	int resuming;
1855295Srandyf 	int	ret;
186*9989SJoseph.Townsend@Sun.COM 	wc_cpu_t	*wc_cpu = wc_other_cpus + index;
1875295Srandyf 
1885295Srandyf 	PMD(PMD_SX, ("i_cpr_save_context() index = %ld\n", index))
1895295Srandyf 
1905295Srandyf 	ASSERT(index < NCPU);
1915295Srandyf 
192*9989SJoseph.Townsend@Sun.COM 	papic_state = &(wc_cpu)->wc_apic_state;
1935295Srandyf 
1945295Srandyf 	ret = i_cpr_platform_alloc(papic_state);
1955295Srandyf 	ASSERT(ret == 0);
1965295Srandyf 
1975295Srandyf 	ret = i_cpr_save_apic(papic_state);
1985295Srandyf 	ASSERT(ret == 0);
1995295Srandyf 
200*9989SJoseph.Townsend@Sun.COM 	i_cpr_save_stack(curthread, wc_cpu);
201*9989SJoseph.Townsend@Sun.COM 
2025295Srandyf 	/*
2035295Srandyf 	 * wc_save_context returns twice, once when susending and
2045295Srandyf 	 * once when resuming,  wc_save_context() returns 0 when
2055295Srandyf 	 * suspending and non-zero upon resume
2065295Srandyf 	 */
207*9989SJoseph.Townsend@Sun.COM 	resuming = (wc_save_context(wc_cpu) == 0);
2085295Srandyf 
2095295Srandyf 	/*
2105295Srandyf 	 * do NOT call any functions after this point, because doing so
2115295Srandyf 	 * will modify the stack that we are running on
2125295Srandyf 	 */
2135295Srandyf 
2145295Srandyf 	if (resuming) {
2155295Srandyf 
2165295Srandyf 		ret = i_cpr_restore_apic(papic_state);
2175295Srandyf 		ASSERT(ret == 0);
2185295Srandyf 
2195295Srandyf 		i_cpr_platform_free(papic_state);
2205295Srandyf 
2215295Srandyf 		/*
2227113Sbholler 		 * Enable interrupts on this cpu.
2237113Sbholler 		 * Do not bind interrupts to this CPU's local APIC until
2247515SSeth.Goldberg@Sun.COM 		 * the CPU is ready to receive interrupts.
2257113Sbholler 		 */
2267113Sbholler 		ASSERT(CPU->cpu_id != i_cpr_bootcpuid());
2277113Sbholler 		mutex_enter(&cpu_lock);
2287113Sbholler 		cpu_enable_intr(CPU);
2297113Sbholler 		mutex_exit(&cpu_lock);
2307113Sbholler 
2317113Sbholler 		/*
2325295Srandyf 		 * Setting the bit in cpu_ready_set must be the last operation
2335295Srandyf 		 * in processor initialization; the boot CPU will continue to
2345295Srandyf 		 * boot once it sees this bit set for all active CPUs.
2355295Srandyf 		 */
2365295Srandyf 		CPUSET_ATOMIC_ADD(cpu_ready_set, CPU->cpu_id);
2375295Srandyf 
2385295Srandyf 		PMD(PMD_SX,
2396336Sbholler 		    ("i_cpr_save_context() resuming cpu %d in cpu_ready_set\n",
2406336Sbholler 		    CPU->cpu_id))
2417515SSeth.Goldberg@Sun.COM 	} else {
2427515SSeth.Goldberg@Sun.COM 		/*
2437515SSeth.Goldberg@Sun.COM 		 * Disable interrupts on this CPU so that PSM knows not to bind
2447515SSeth.Goldberg@Sun.COM 		 * interrupts here on resume until the CPU has executed
2457515SSeth.Goldberg@Sun.COM 		 * cpu_enable_intr() (above) in the resume path.
2467515SSeth.Goldberg@Sun.COM 		 * We explicitly do not grab cpu_lock here because at this point
2477515SSeth.Goldberg@Sun.COM 		 * in the suspend process, the boot cpu owns cpu_lock and all
2487515SSeth.Goldberg@Sun.COM 		 * other cpus are also executing in the pause thread (only
2497515SSeth.Goldberg@Sun.COM 		 * modifying their respective CPU structure).
2507515SSeth.Goldberg@Sun.COM 		 */
2517515SSeth.Goldberg@Sun.COM 		(void) cpu_disable_intr(CPU);
2525295Srandyf 	}
2537515SSeth.Goldberg@Sun.COM 
2547515SSeth.Goldberg@Sun.COM 	PMD(PMD_SX, ("i_cpr_save_context: wc_save_context returns %d\n",
2557515SSeth.Goldberg@Sun.COM 	    resuming))
2567515SSeth.Goldberg@Sun.COM 
2575295Srandyf 	return (NULL);
2585295Srandyf }
2595295Srandyf 
2605295Srandyf static ushort_t *warm_reset_vector = NULL;
2615295Srandyf 
2625295Srandyf static ushort_t *
2635295Srandyf map_warm_reset_vector()
2645295Srandyf {
2655295Srandyf 	/*LINTED*/
2665295Srandyf 	if (!(warm_reset_vector = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR,
2675295Srandyf 	    sizeof (ushort_t *), PROT_READ|PROT_WRITE)))
2685295Srandyf 		return (NULL);
2695295Srandyf 
2705295Srandyf 	/*
2715295Srandyf 	 * setup secondary cpu bios boot up vector
2725295Srandyf 	 */
2735295Srandyf 	*warm_reset_vector = (ushort_t)((caddr_t)
2745295Srandyf 	    /*LINTED*/
2755295Srandyf 	    ((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va
2765295Srandyf 	    + ((ulong_t)rm_platter_va & 0xf));
2775295Srandyf 	warm_reset_vector++;
2785295Srandyf 	*warm_reset_vector = (ushort_t)(rm_platter_pa >> 4);
2795295Srandyf 
2805295Srandyf 	--warm_reset_vector;
2815295Srandyf 	return (warm_reset_vector);
2825295Srandyf }
2835295Srandyf 
2845295Srandyf void
2855295Srandyf i_cpr_pre_resume_cpus()
2865295Srandyf {
2875295Srandyf 	/*
2885295Srandyf 	 * this is a cut down version of start_other_cpus()
2895295Srandyf 	 * just do the initialization to wake the other cpus
2905295Srandyf 	 */
2915295Srandyf 	unsigned who;
2925817Sjan 	int boot_cpuid = i_cpr_bootcpuid();
2935295Srandyf 	uint32_t		code_length = 0;
2945295Srandyf 	caddr_t			wakevirt = rm_platter_va;
2955295Srandyf 	/*LINTED*/
2965295Srandyf 	wakecode_t		*wp = (wakecode_t *)wakevirt;
2975295Srandyf 	char *str = "i_cpr_pre_resume_cpus";
2985295Srandyf 	extern int get_tsc_ready();
2995295Srandyf 	int err;
3005295Srandyf 
3015295Srandyf 	/*LINTED*/
3025295Srandyf 	rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va;
3035295Srandyf 
3045295Srandyf 	/*
3057515SSeth.Goldberg@Sun.COM 	 * If startup wasn't able to find a page under 1M, we cannot
3067515SSeth.Goldberg@Sun.COM 	 * proceed.
3077515SSeth.Goldberg@Sun.COM 	 */
3087515SSeth.Goldberg@Sun.COM 	if (rm_platter_va == 0) {
3097515SSeth.Goldberg@Sun.COM 		cmn_err(CE_WARN, "Cannot suspend the system because no "
3107515SSeth.Goldberg@Sun.COM 		    "memory below 1M could be found for processor startup");
3117515SSeth.Goldberg@Sun.COM 		return;
3127515SSeth.Goldberg@Sun.COM 	}
3137515SSeth.Goldberg@Sun.COM 
3147515SSeth.Goldberg@Sun.COM 	/*
3155295Srandyf 	 * Copy the real mode code at "real_mode_start" to the
3165295Srandyf 	 * page at rm_platter_va.
3175295Srandyf 	 */
3185295Srandyf 	warm_reset_vector = map_warm_reset_vector();
3195295Srandyf 	if (warm_reset_vector == NULL) {
3205295Srandyf 		PMD(PMD_SX, ("i_cpr_pre_resume_cpus() returning #2\n"))
3215295Srandyf 		return;
3225295Srandyf 	}
3235295Srandyf 
3245295Srandyf 	flushes_require_xcalls = 1;
3255295Srandyf 
3265295Srandyf 	/*
3275295Srandyf 	 * We lock our affinity to the master CPU to ensure that all slave CPUs
3285295Srandyf 	 * do their TSC syncs with the same CPU.
3295295Srandyf 	 */
3305295Srandyf 
3315295Srandyf 	affinity_set(CPU_CURRENT);
3325295Srandyf 
3335817Sjan 	/*
3346336Sbholler 	 * Mark the boot cpu as being ready and in the procset, since we are
3356336Sbholler 	 * running on that cpu.
3365817Sjan 	 */
3375817Sjan 	CPUSET_ONLY(cpu_ready_set, boot_cpuid);
3386336Sbholler 	CPUSET_ONLY(procset, boot_cpuid);
3395295Srandyf 
3405295Srandyf 	for (who = 0; who < ncpus; who++) {
3415295Srandyf 
3425295Srandyf 		wc_cpu_t	*cpup = wc_other_cpus + who;
3435295Srandyf 		wc_desctbr_t	gdt;
3445295Srandyf 
3455817Sjan 		if (who == boot_cpuid)
3465295Srandyf 			continue;
3475295Srandyf 
3485295Srandyf 		if (!CPU_IN_SET(mp_cpus, who))
3495295Srandyf 			continue;
3505295Srandyf 
3515295Srandyf 		PMD(PMD_SX, ("%s() waking up %d cpu\n", str, who))
3525295Srandyf 
3535295Srandyf 		bcopy(cpup, &(wp->wc_cpu), sizeof (wc_cpu_t));
3545295Srandyf 
3555295Srandyf 		gdt.base = cpup->wc_gdt_base;
3565295Srandyf 		gdt.limit = cpup->wc_gdt_limit;
3575295Srandyf 
3585295Srandyf #if defined(__amd64)
3595295Srandyf 		code_length = (uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start;
3605295Srandyf #else
3615295Srandyf 		code_length = 0;
3625295Srandyf #endif
3635295Srandyf 
3645295Srandyf 		init_real_mode_platter(who, code_length, cpup->wc_cr4, gdt);
3655295Srandyf 
3665295Srandyf 		if ((err = mach_cpuid_start(who, rm_platter_va)) != 0) {
3675295Srandyf 			cmn_err(CE_WARN, "cpu%d: failed to start during "
3685295Srandyf 			    "suspend/resume error %d", who, err);
3695295Srandyf 			continue;
3705295Srandyf 		}
3715295Srandyf 
3726336Sbholler 		PMD(PMD_SX, ("%s() #1 waiting for %d in procset\n", str, who))
3735295Srandyf 
3745817Sjan 		if (!wait_for_set(&procset, who))
3755817Sjan 			continue;
3765295Srandyf 
3775295Srandyf 		PMD(PMD_SX, ("%s() %d cpu started\n", str, who))
3785295Srandyf 
3795817Sjan 		PMD(PMD_SX, ("%s() tsc_ready = %d\n", str, get_tsc_ready()))
3805295Srandyf 
3815295Srandyf 		if (tsc_gethrtime_enable) {
3825295Srandyf 			PMD(PMD_SX, ("%s() calling tsc_sync_master\n", str))
3835295Srandyf 			tsc_sync_master(who);
3845295Srandyf 		}
3855295Srandyf 
3866336Sbholler 		PMD(PMD_SX, ("%s() waiting for %d in cpu_ready_set\n", str,
3876336Sbholler 		    who))
3885295Srandyf 		/*
3895295Srandyf 		 * Wait for cpu to declare that it is ready, we want the
3905295Srandyf 		 * cpus to start serially instead of in parallel, so that
3915295Srandyf 		 * they do not contend with each other in wc_rm_start()
3925295Srandyf 		 */
3935817Sjan 		if (!wait_for_set(&cpu_ready_set, who))
3945817Sjan 			continue;
3955295Srandyf 
3965295Srandyf 		/*
3975295Srandyf 		 * do not need to re-initialize dtrace using dtrace_cpu_init
3985295Srandyf 		 * function
3995295Srandyf 		 */
4005295Srandyf 		PMD(PMD_SX, ("%s() cpu %d now ready\n", str, who))
4015295Srandyf 	}
4025295Srandyf 
4035295Srandyf 	affinity_clear();
4045295Srandyf 
4055295Srandyf 	PMD(PMD_SX, ("%s() all cpus now ready\n", str))
4065817Sjan 
4075295Srandyf }
4085295Srandyf 
4095295Srandyf static void
4105295Srandyf unmap_warm_reset_vector(ushort_t *warm_reset_vector)
4115295Srandyf {
4125295Srandyf 	psm_unmap_phys((caddr_t)warm_reset_vector, sizeof (ushort_t *));
4135295Srandyf }
4145295Srandyf 
4155295Srandyf /*
4165295Srandyf  * We need to setup a 1:1 (virtual to physical) mapping for the
4175295Srandyf  * page containing the wakeup code.
4185295Srandyf  */
4195295Srandyf static struct as *save_as;	/* when switching to kas */
4205295Srandyf 
4215295Srandyf static void
4225295Srandyf unmap_wakeaddr_1to1(uint64_t wakephys)
4235295Srandyf {
4245295Srandyf 	uintptr_t	wp = (uintptr_t)wakephys;
4255295Srandyf 	hat_setup(save_as->a_hat, 0);	/* switch back from kernel hat */
4265295Srandyf 	hat_unload(kas.a_hat, (caddr_t)wp, PAGESIZE, HAT_UNLOAD);
4275295Srandyf }
4285295Srandyf 
4295295Srandyf void
4305295Srandyf i_cpr_post_resume_cpus()
4315295Srandyf {
4325295Srandyf 	uint64_t	wakephys = rm_platter_pa;
4335295Srandyf 
4345295Srandyf 	if (warm_reset_vector != NULL)
4355295Srandyf 		unmap_warm_reset_vector(warm_reset_vector);
4365295Srandyf 
4375295Srandyf 	hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE,
4385295Srandyf 	    HAT_UNLOAD);
4395295Srandyf 
4405295Srandyf 	/*
4415295Srandyf 	 * cmi_post_mpstartup() is only required upon boot not upon
4425295Srandyf 	 * resume from RAM
4435295Srandyf 	 */
4445295Srandyf 
4455295Srandyf 	PT(PT_UNDO1to1);
4465295Srandyf 	/* Tear down 1:1 mapping for wakeup code */
4475295Srandyf 	unmap_wakeaddr_1to1(wakephys);
4485295Srandyf }
4495295Srandyf 
4505295Srandyf /* ARGSUSED */
4515295Srandyf void
4525295Srandyf i_cpr_handle_xc(int flag)
4535295Srandyf {
4545295Srandyf }
4555295Srandyf 
4565295Srandyf int
4575295Srandyf i_cpr_reusable_supported(void)
4585295Srandyf {
4595295Srandyf 	return (0);
4605295Srandyf }
4615295Srandyf static void
4625295Srandyf map_wakeaddr_1to1(uint64_t wakephys)
4635295Srandyf {
4645295Srandyf 	uintptr_t	wp = (uintptr_t)wakephys;
4655295Srandyf 	hat_devload(kas.a_hat, (caddr_t)wp, PAGESIZE, btop(wakephys),
4665295Srandyf 	    (PROT_READ|PROT_WRITE|PROT_EXEC|HAT_STORECACHING_OK|HAT_NOSYNC),
4675295Srandyf 	    HAT_LOAD);
4685295Srandyf 	save_as = curthread->t_procp->p_as;
4695295Srandyf 	hat_setup(kas.a_hat, 0);	/* switch to kernel-only hat */
4705295Srandyf }
4715295Srandyf 
4725295Srandyf 
4735295Srandyf void
4745295Srandyf prt_other_cpus()
4755295Srandyf {
4765295Srandyf 	int	who;
4775295Srandyf 
4785295Srandyf 	if (ncpus == 1) {
4795295Srandyf 		PMD(PMD_SX, ("prt_other_cpus() other cpu table empty for "
4805295Srandyf 		    "uniprocessor machine\n"))
4815295Srandyf 		return;
4825295Srandyf 	}
4835295Srandyf 
4845295Srandyf 	for (who = 0; who < ncpus; who++) {
4855295Srandyf 
4865295Srandyf 		wc_cpu_t	*cpup = wc_other_cpus + who;
4875295Srandyf 
4885295Srandyf 		PMD(PMD_SX, ("prt_other_cpus() who = %d, gdt=%p:%x, "
4895295Srandyf 		    "idt=%p:%x, ldt=%lx, tr=%lx, kgsbase="
4905295Srandyf 		    AFMT ", sp=%lx\n", who,
4915295Srandyf 		    (void *)cpup->wc_gdt_base, cpup->wc_gdt_limit,
4925295Srandyf 		    (void *)cpup->wc_idt_base, cpup->wc_idt_limit,
4935295Srandyf 		    (long)cpup->wc_ldt, (long)cpup->wc_tr,
4945295Srandyf 		    (long)cpup->wc_kgsbase, (long)cpup->wc_rsp))
4955295Srandyf 	}
4965295Srandyf }
4975295Srandyf 
4985295Srandyf /*
4995295Srandyf  * Power down the system.
5005295Srandyf  */
5015295Srandyf int
5025295Srandyf i_cpr_power_down(int sleeptype)
5035295Srandyf {
5045295Srandyf 	caddr_t		wakevirt = rm_platter_va;
5055295Srandyf 	uint64_t	wakephys = rm_platter_pa;
5066336Sbholler 	ulong_t		saved_intr;
5075295Srandyf 	uint32_t	code_length = 0;
5085295Srandyf 	wc_desctbr_t	gdt;
5095295Srandyf 	/*LINTED*/
5105295Srandyf 	wakecode_t	*wp = (wakecode_t *)wakevirt;
5115295Srandyf 	/*LINTED*/
5125295Srandyf 	rm_platter_t	*wcpp = (rm_platter_t *)wakevirt;
5135295Srandyf 	wc_cpu_t	*cpup = &(wp->wc_cpu);
5145295Srandyf 	dev_info_t	*ppm;
5155295Srandyf 	int		ret = 0;
5165295Srandyf 	power_req_t	power_req;
5175295Srandyf 	char *str =	"i_cpr_power_down";
5185295Srandyf #if defined(__amd64)
5195295Srandyf 	/*LINTED*/
5205295Srandyf 	rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va;
5215295Srandyf #endif
5225295Srandyf 	extern int	cpr_suspend_succeeded;
5235295Srandyf 	extern void	kernel_wc_code();
5245295Srandyf 
5255295Srandyf 	ASSERT(sleeptype == CPR_TORAM);
5265295Srandyf 	ASSERT(CPU->cpu_id == 0);
5275295Srandyf 
5285295Srandyf 	if ((ppm = PPM(ddi_root_node())) == NULL) {
5295295Srandyf 		PMD(PMD_SX, ("%s: root node not claimed\n", str))
5305295Srandyf 		return (ENOTTY);
5315295Srandyf 	}
5325295Srandyf 
5335295Srandyf 	PMD(PMD_SX, ("Entering %s()\n", str))
5345295Srandyf 
5355295Srandyf 	PT(PT_IC);
5365295Srandyf 	saved_intr = intr_clear();
5375295Srandyf 
5385295Srandyf 	PT(PT_1to1);
5395295Srandyf 	/* Setup 1:1 mapping for wakeup code */
5405295Srandyf 	map_wakeaddr_1to1(wakephys);
5415295Srandyf 
5425295Srandyf 	PMD(PMD_SX, ("ncpus=%d\n", ncpus))
5435295Srandyf 
5445295Srandyf 	PMD(PMD_SX, ("wc_rm_end - wc_rm_start=%lx WC_CODESIZE=%x\n",
5455295Srandyf 	    ((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)), WC_CODESIZE))
5465295Srandyf 
5475295Srandyf 	PMD(PMD_SX, ("wakevirt=%p, wakephys=%x\n",
5485295Srandyf 	    (void *)wakevirt, (uint_t)wakephys))
5495295Srandyf 
5505295Srandyf 	ASSERT(((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)) <
5515295Srandyf 	    WC_CODESIZE);
5525295Srandyf 
5535295Srandyf 	bzero(wakevirt, PAGESIZE);
5545295Srandyf 
5555295Srandyf 	/* Copy code to rm_platter */
5565295Srandyf 	bcopy((caddr_t)wc_rm_start, wakevirt,
5575295Srandyf 	    (size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start));
5585295Srandyf 
5595295Srandyf 	prt_other_cpus();
5605295Srandyf 
5615295Srandyf #if defined(__amd64)
5625295Srandyf 
5635295Srandyf 	PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
5645295Srandyf 	    (ulong_t)real_mode_platter->rm_cr4, (ulong_t)getcr4()))
5655295Srandyf 	PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
5665295Srandyf 	    (ulong_t)real_mode_platter->rm_pdbr, getcr3()))
5675295Srandyf 
5685295Srandyf 	real_mode_platter->rm_cr4 = getcr4();
5695295Srandyf 	real_mode_platter->rm_pdbr = getcr3();
5705295Srandyf 
5715295Srandyf 	rmp_gdt_init(real_mode_platter);
5725295Srandyf 
5735295Srandyf 	/*
5745295Srandyf 	 * Since the CPU needs to jump to protected mode using an identity
5755295Srandyf 	 * mapped address, we need to calculate it here.
5765295Srandyf 	 */
5775295Srandyf 	real_mode_platter->rm_longmode64_addr = rm_platter_pa +
5785295Srandyf 	    ((uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start);
5795295Srandyf 
5805295Srandyf 	PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
5815295Srandyf 	    (ulong_t)real_mode_platter->rm_cr4, getcr4()))
5825295Srandyf 
5835295Srandyf 	PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
5845295Srandyf 	    (ulong_t)real_mode_platter->rm_pdbr, getcr3()))
5855295Srandyf 
5865295Srandyf 	PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n",
5875295Srandyf 	    (ulong_t)real_mode_platter->rm_longmode64_addr))
5885295Srandyf 
5895295Srandyf #endif
5905295Srandyf 
5915295Srandyf 	PT(PT_SC);
5925295Srandyf 	if (wc_save_context(cpup)) {
5935295Srandyf 
5945295Srandyf 		ret = i_cpr_platform_alloc(&(wc_other_cpus->wc_apic_state));
5955295Srandyf 		if (ret != 0)
5965295Srandyf 			return (ret);
5975295Srandyf 
5985295Srandyf 		ret = i_cpr_save_apic(&(wc_other_cpus->wc_apic_state));
5995295Srandyf 		PMD(PMD_SX, ("%s: i_cpr_save_apic() returned %d\n", str, ret))
6005295Srandyf 		if (ret != 0)
6015295Srandyf 			return (ret);
6025295Srandyf 
6035295Srandyf 		PMD(PMD_SX, ("wakephys=%x, kernel_wc_code=%p\n",
6045295Srandyf 		    (uint_t)wakephys, (void *)&kernel_wc_code))
6055295Srandyf 		PMD(PMD_SX, ("virtaddr=%lx, retaddr=%lx\n",
6065295Srandyf 		    (long)cpup->wc_virtaddr, (long)cpup->wc_retaddr))
6075295Srandyf 		PMD(PMD_SX, ("ebx=%x, edi=%x, esi=%x, ebp=%x, esp=%x\n",
6085295Srandyf 		    cpup->wc_ebx, cpup->wc_edi, cpup->wc_esi, cpup->wc_ebp,
6095295Srandyf 		    cpup->wc_esp))
6105295Srandyf 		PMD(PMD_SX, ("cr0=%lx, cr3=%lx, cr4=%lx\n",
6115295Srandyf 		    (long)cpup->wc_cr0, (long)cpup->wc_cr3,
6125295Srandyf 		    (long)cpup->wc_cr4))
6135295Srandyf 		PMD(PMD_SX, ("cs=%x, ds=%x, es=%x, ss=%x, fs=%lx, gs=%lx, "
6145295Srandyf 		    "flgs=%lx\n", cpup->wc_cs, cpup->wc_ds, cpup->wc_es,
6155295Srandyf 		    cpup->wc_ss, (long)cpup->wc_fs, (long)cpup->wc_gs,
6165295Srandyf 		    (long)cpup->wc_eflags))
6175295Srandyf 
6185295Srandyf 		PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, "
6195295Srandyf 		    "kgbase=%lx\n", (void *)cpup->wc_gdt_base,
6205295Srandyf 		    cpup->wc_gdt_limit, (void *)cpup->wc_idt_base,
6215295Srandyf 		    cpup->wc_idt_limit, (long)cpup->wc_ldt,
6225295Srandyf 		    (long)cpup->wc_tr, (long)cpup->wc_kgsbase))
6235295Srandyf 
6245295Srandyf 		gdt.base = cpup->wc_gdt_base;
6255295Srandyf 		gdt.limit = cpup->wc_gdt_limit;
6265295Srandyf 
6275295Srandyf #if defined(__amd64)
6285295Srandyf 		code_length = (uint32_t)wc_long_mode_64 -
6295295Srandyf 		    (uint32_t)wc_rm_start;
6305295Srandyf #else
6315295Srandyf 		code_length = 0;
6325295Srandyf #endif
6335295Srandyf 
6345295Srandyf 		init_real_mode_platter(0, code_length, cpup->wc_cr4, gdt);
6355295Srandyf 
6365295Srandyf #if defined(__amd64)
6375295Srandyf 		PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
6385295Srandyf 		    (ulong_t)wcpp->rm_cr4, getcr4()))
6395295Srandyf 
6405295Srandyf 		PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
6415295Srandyf 		    (ulong_t)wcpp->rm_pdbr, getcr3()))
6425295Srandyf 
6435295Srandyf 		PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n",
6445295Srandyf 		    (ulong_t)wcpp->rm_longmode64_addr))
6455295Srandyf 
6465295Srandyf 		PMD(PMD_SX,
6475295Srandyf 		    ("real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64]=%lx\n",
6485295Srandyf 		    (ulong_t)wcpp->rm_temp_gdt[TEMPGDT_KCODE64]))
6495295Srandyf #endif
6505295Srandyf 
6515295Srandyf 		PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, "
6525295Srandyf 		    "kgsbase=%lx\n", (void *)wcpp->rm_gdt_base,
6535295Srandyf 		    wcpp->rm_gdt_lim, (void *)wcpp->rm_idt_base,
6545295Srandyf 		    wcpp->rm_idt_lim, (long)cpup->wc_ldt, (long)cpup->wc_tr,
6555295Srandyf 		    (long)cpup->wc_kgsbase))
6565295Srandyf 
6575295Srandyf 		power_req.request_type = PMR_PPM_ENTER_SX;
6585295Srandyf 		power_req.req.ppm_power_enter_sx_req.sx_state = S3;
6595295Srandyf 		power_req.req.ppm_power_enter_sx_req.test_point =
6605295Srandyf 		    cpr_test_point;
6615295Srandyf 		power_req.req.ppm_power_enter_sx_req.wakephys = wakephys;
6625295Srandyf 
6635295Srandyf 		PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_ENTER_SX\n", str))
6645295Srandyf 		PT(PT_PPMCTLOP);
6655295Srandyf 		(void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER,
6665295Srandyf 		    &power_req, &ret);
6675295Srandyf 		PMD(PMD_SX, ("%s: returns %d\n", str, ret))
6685295Srandyf 
6695295Srandyf 		/*
6705295Srandyf 		 * If it works, we get control back to the else branch below
6715295Srandyf 		 * If we get control back here, it didn't work.
6725295Srandyf 		 * XXX return EINVAL here?
6735295Srandyf 		 */
6745295Srandyf 
6755295Srandyf 		unmap_wakeaddr_1to1(wakephys);
6765295Srandyf 		intr_restore(saved_intr);
6775295Srandyf 
6785295Srandyf 		return (ret);
6795295Srandyf 	} else {
6805295Srandyf 		cpr_suspend_succeeded = 1;
6815295Srandyf 
6825295Srandyf 		power_req.request_type = PMR_PPM_EXIT_SX;
6835295Srandyf 		power_req.req.ppm_power_enter_sx_req.sx_state = S3;
6845295Srandyf 
6855295Srandyf 		PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_EXIT_SX\n", str))
6865295Srandyf 		PT(PT_PPMCTLOP);
6875295Srandyf 		(void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER,
6885295Srandyf 		    &power_req, &ret);
6895295Srandyf 		PMD(PMD_SX, ("%s: returns %d\n", str, ret))
6905295Srandyf 
6915295Srandyf 		ret = i_cpr_restore_apic(&(wc_other_cpus->wc_apic_state));
6925295Srandyf 		/*
6935295Srandyf 		 * the restore should never fail, if the saved suceeded
6945295Srandyf 		 */
6955295Srandyf 		ASSERT(ret == 0);
6965295Srandyf 
6975295Srandyf 		i_cpr_platform_free(&(wc_other_cpus->wc_apic_state));
6985295Srandyf 
6997113Sbholler 		/*
7007113Sbholler 		 * Enable interrupts on boot cpu.
7017113Sbholler 		 */
7027113Sbholler 		ASSERT(CPU->cpu_id == i_cpr_bootcpuid());
7037113Sbholler 		mutex_enter(&cpu_lock);
7047113Sbholler 		cpu_enable_intr(CPU);
7057113Sbholler 		mutex_exit(&cpu_lock);
7067113Sbholler 
7075295Srandyf 		PT(PT_INTRRESTORE);
7085295Srandyf 		intr_restore(saved_intr);
7095295Srandyf 		PT(PT_CPU);
7105295Srandyf 
7115295Srandyf 		return (ret);
7125295Srandyf 	}
7135295Srandyf }
7145295Srandyf 
7155295Srandyf /*
7165295Srandyf  * Stop all other cpu's before halting or rebooting. We pause the cpu's
7175295Srandyf  * instead of sending a cross call.
7185295Srandyf  * Stolen from sun4/os/mp_states.c
7195295Srandyf  */
7205295Srandyf 
7215295Srandyf static int cpu_are_paused;	/* sic */
7225295Srandyf 
7235295Srandyf void
7245295Srandyf i_cpr_stop_other_cpus(void)
7255295Srandyf {
7265295Srandyf 	mutex_enter(&cpu_lock);
7275295Srandyf 	if (cpu_are_paused) {
7285295Srandyf 		mutex_exit(&cpu_lock);
7295295Srandyf 		return;
7305295Srandyf 	}
7315295Srandyf 	pause_cpus(NULL);
7325295Srandyf 	cpu_are_paused = 1;
7335295Srandyf 
7345295Srandyf 	mutex_exit(&cpu_lock);
7355295Srandyf }
7365295Srandyf 
7375295Srandyf int
7385295Srandyf i_cpr_is_supported(int sleeptype)
7395295Srandyf {
7405295Srandyf 	extern int cpr_supported_override;
7415295Srandyf 	extern int cpr_platform_enable;
7425295Srandyf 	extern int pm_S3_enabled;
7435295Srandyf 
7445295Srandyf 	if (sleeptype != CPR_TORAM)
7455295Srandyf 		return (0);
7465295Srandyf 
7475295Srandyf 	/*
7485295Srandyf 	 * The next statement tests if a specific platform has turned off
7495295Srandyf 	 * cpr support.
7505295Srandyf 	 */
7515295Srandyf 	if (cpr_supported_override)
7525295Srandyf 		return (0);
7535295Srandyf 
7545295Srandyf 	/*
7555295Srandyf 	 * If a platform has specifically turned on cpr support ...
7565295Srandyf 	 */
7575295Srandyf 	if (cpr_platform_enable)
7585295Srandyf 		return (1);
7595295Srandyf 
7605295Srandyf 	return (pm_S3_enabled);
7615295Srandyf }
7625295Srandyf 
7635295Srandyf void
7645295Srandyf i_cpr_bitmap_cleanup(void)
7655295Srandyf {
7665295Srandyf }
7675295Srandyf 
7685295Srandyf void
7695295Srandyf i_cpr_free_memory_resources(void)
7705295Srandyf {
7715295Srandyf }
7725295Srandyf 
7735295Srandyf /*
7745295Srandyf  * Needed only for S3 so far
7755295Srandyf  */
7765295Srandyf static int
7775295Srandyf i_cpr_platform_alloc(psm_state_request_t *req)
7785295Srandyf {
7797515SSeth.Goldberg@Sun.COM #ifdef DEBUG
7805295Srandyf 	char	*str = "i_cpr_platform_alloc";
7817515SSeth.Goldberg@Sun.COM #endif
7825295Srandyf 
7835295Srandyf 	PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req))
7845295Srandyf 
7857515SSeth.Goldberg@Sun.COM 	if (psm_state == NULL) {
7867515SSeth.Goldberg@Sun.COM 		PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
7875295Srandyf 		return (0);
7885295Srandyf 	}
7895295Srandyf 
7905295Srandyf 	req->psr_cmd = PSM_STATE_ALLOC;
7915295Srandyf 	return ((*psm_state)(req));
7925295Srandyf }
7935295Srandyf 
7945295Srandyf /*
7955295Srandyf  * Needed only for S3 so far
7965295Srandyf  */
7975295Srandyf static void
7985295Srandyf i_cpr_platform_free(psm_state_request_t *req)
7995295Srandyf {
8007515SSeth.Goldberg@Sun.COM #ifdef DEBUG
8015295Srandyf 	char	*str = "i_cpr_platform_free";
8027515SSeth.Goldberg@Sun.COM #endif
8035295Srandyf 
8045295Srandyf 	PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req))
8055295Srandyf 
8067515SSeth.Goldberg@Sun.COM 	if (psm_state == NULL) {
8077515SSeth.Goldberg@Sun.COM 		PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
8087515SSeth.Goldberg@Sun.COM 		return;
8095295Srandyf 	}
8105295Srandyf 
8115295Srandyf 	req->psr_cmd = PSM_STATE_FREE;
8125295Srandyf 	(void) (*psm_state)(req);
8135295Srandyf }
8145295Srandyf 
8155295Srandyf static int
8165295Srandyf i_cpr_save_apic(psm_state_request_t *req)
8175295Srandyf {
8187515SSeth.Goldberg@Sun.COM #ifdef DEBUG
8195295Srandyf 	char	*str = "i_cpr_save_apic";
8207515SSeth.Goldberg@Sun.COM #endif
8215295Srandyf 
8227515SSeth.Goldberg@Sun.COM 	if (psm_state == NULL) {
8237515SSeth.Goldberg@Sun.COM 		PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
8245295Srandyf 		return (0);
8255295Srandyf 	}
8265295Srandyf 
8275295Srandyf 	req->psr_cmd = PSM_STATE_SAVE;
8285295Srandyf 	return ((*psm_state)(req));
8295295Srandyf }
8305295Srandyf 
8315295Srandyf static int
8325295Srandyf i_cpr_restore_apic(psm_state_request_t *req)
8335295Srandyf {
8347515SSeth.Goldberg@Sun.COM #ifdef DEBUG
8355295Srandyf 	char	*str = "i_cpr_restore_apic";
8367515SSeth.Goldberg@Sun.COM #endif
8375295Srandyf 
8387515SSeth.Goldberg@Sun.COM 	if (psm_state == NULL) {
8397515SSeth.Goldberg@Sun.COM 		PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
8405295Srandyf 		return (0);
8415295Srandyf 	}
8425295Srandyf 
8435295Srandyf 	req->psr_cmd = PSM_STATE_RESTORE;
8445295Srandyf 	return ((*psm_state)(req));
8455295Srandyf }
8465295Srandyf 
8475295Srandyf 
8485295Srandyf /* stop lint complaining about offset not being used in 32bit mode */
8495295Srandyf #if !defined(__amd64)
8505295Srandyf /*ARGSUSED*/
8515295Srandyf #endif
8525295Srandyf static void
8535295Srandyf init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt)
8545295Srandyf {
8555295Srandyf 	/*LINTED*/
8565295Srandyf 	rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va;
8575295Srandyf 
8585295Srandyf 	/*
8595295Srandyf 	 * Fill up the real mode platter to make it easy for real mode code to
8605295Srandyf 	 * kick it off. This area should really be one passed by boot to kernel
8615295Srandyf 	 * and guaranteed to be below 1MB and aligned to 16 bytes. Should also
8625295Srandyf 	 * have identical physical and virtual address in paged mode.
8635295Srandyf 	 */
8645295Srandyf 
8655295Srandyf 	real_mode_platter->rm_pdbr = getcr3();
8665295Srandyf 	real_mode_platter->rm_cpu = cpun;
8675295Srandyf 	real_mode_platter->rm_cr4 = cr4;
8685295Srandyf 
8695295Srandyf 	real_mode_platter->rm_gdt_base = gdt.base;
8705295Srandyf 	real_mode_platter->rm_gdt_lim = gdt.limit;
8715295Srandyf 
8725295Srandyf #if defined(__amd64)
8735295Srandyf 	real_mode_platter->rm_x86feature = x86_feature;
8745295Srandyf 
8755295Srandyf 	if (getcr3() > 0xffffffffUL)
8765295Srandyf 		panic("Cannot initialize CPUs; kernel's 64-bit page tables\n"
8775295Srandyf 		    "located above 4G in physical memory (@ 0x%llx).",
8785295Srandyf 		    (unsigned long long)getcr3());
8795295Srandyf 
8805295Srandyf 	/*
8815295Srandyf 	 * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY
8825295Srandyf 	 * by code in real_mode_start():
8835295Srandyf 	 *
8845295Srandyf 	 * GDT[0]:  NULL selector
8855295Srandyf 	 * GDT[1]:  64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1
8865295Srandyf 	 *
8875295Srandyf 	 * Clear the IDT as interrupts will be off and a limit of 0 will cause
8885295Srandyf 	 * the CPU to triple fault and reset on an NMI, seemingly as reasonable
8895295Srandyf 	 * a course of action as any other, though it may cause the entire
8905295Srandyf 	 * platform to reset in some cases...
8915295Srandyf 	 */
8925295Srandyf 	real_mode_platter->rm_temp_gdt[0] = 0ULL;
8935295Srandyf 	real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL;
8945295Srandyf 
8955295Srandyf 	real_mode_platter->rm_temp_gdt_lim = (ushort_t)
8965295Srandyf 	    (sizeof (real_mode_platter->rm_temp_gdt) - 1);
8975295Srandyf 	real_mode_platter->rm_temp_gdt_base = rm_platter_pa +
8985295Srandyf 	    (uint32_t)(&((rm_platter_t *)0)->rm_temp_gdt);
8995295Srandyf 
9005295Srandyf 	real_mode_platter->rm_temp_idt_lim = 0;
9015295Srandyf 	real_mode_platter->rm_temp_idt_base = 0;
9025295Srandyf 
9035295Srandyf 	/*
9045295Srandyf 	 * Since the CPU needs to jump to protected mode using an identity
9055295Srandyf 	 * mapped address, we need to calculate it here.
9065295Srandyf 	 */
9075295Srandyf 	real_mode_platter->rm_longmode64_addr = rm_platter_pa + offset;
9085295Srandyf #endif	/* __amd64 */
9095295Srandyf 
9105295Srandyf 	/* return; */
9115295Srandyf }
9125295Srandyf 
9135295Srandyf void
9145295Srandyf i_cpr_start_cpu(void)
9155295Srandyf {
9165295Srandyf 
9175295Srandyf 	struct cpu *cp = CPU;
9185295Srandyf 
9195295Srandyf 	char *str = "i_cpr_start_cpu";
9205295Srandyf 	extern void init_cpu_syscall(struct cpu *cp);
9215295Srandyf 
9225295Srandyf 	PMD(PMD_SX, ("%s() called\n", str))
9235295Srandyf 
9245295Srandyf 	PMD(PMD_SX, ("%s() #0 cp->cpu_base_spl %d\n", str,
9255295Srandyf 	    cp->cpu_base_spl))
9265295Srandyf 
9275295Srandyf 	mutex_enter(&cpu_lock);
9285295Srandyf 	if (cp == i_cpr_bootcpu()) {
9295295Srandyf 		mutex_exit(&cpu_lock);
9305295Srandyf 		PMD(PMD_SX,
9315295Srandyf 		    ("%s() called on bootcpu nothing to do!\n", str))
9325295Srandyf 		return;
9335295Srandyf 	}
9345295Srandyf 	mutex_exit(&cpu_lock);
9355295Srandyf 
9365295Srandyf 	/*
9375295Srandyf 	 * We need to Sync PAT with cpu0's PAT. We have to do
9385295Srandyf 	 * this with interrupts disabled.
9395295Srandyf 	 */
9405295Srandyf 	if (x86_feature & X86_PAT)
9415295Srandyf 		pat_sync();
9425295Srandyf 
9435295Srandyf 	/*
9445295Srandyf 	 * Initialize this CPU's syscall handlers
9455295Srandyf 	 */
9465295Srandyf 	init_cpu_syscall(cp);
9475295Srandyf 
9485295Srandyf 	PMD(PMD_SX, ("%s() #1 cp->cpu_base_spl %d\n", str, cp->cpu_base_spl))
9495295Srandyf 
9505295Srandyf 	/*
9515295Srandyf 	 * Do not need to call cpuid_pass2(), cpuid_pass3(), cpuid_pass4() or
9525295Srandyf 	 * init_cpu_info(), since the work that they do is only needed to
9535295Srandyf 	 * be done once at boot time
9545295Srandyf 	 */
9555295Srandyf 
9565295Srandyf 
9575295Srandyf 	mutex_enter(&cpu_lock);
9585295Srandyf 	CPUSET_ADD(procset, cp->cpu_id);
9595295Srandyf 	mutex_exit(&cpu_lock);
9605295Srandyf 
9615295Srandyf 	PMD(PMD_SX, ("%s() #2 cp->cpu_base_spl %d\n", str,
9625295Srandyf 	    cp->cpu_base_spl))
9635295Srandyf 
9645295Srandyf 	if (tsc_gethrtime_enable) {
9655295Srandyf 		PMD(PMD_SX, ("%s() calling tsc_sync_slave\n", str))
9665295Srandyf 		tsc_sync_slave();
9675295Srandyf 	}
9685295Srandyf 
9695295Srandyf 	PMD(PMD_SX, ("%s() cp->cpu_id %d, cp->cpu_intr_actv %d\n", str,
9705295Srandyf 	    cp->cpu_id, cp->cpu_intr_actv))
9715295Srandyf 	PMD(PMD_SX, ("%s() #3 cp->cpu_base_spl %d\n", str,
9725295Srandyf 	    cp->cpu_base_spl))
9735295Srandyf 
9745295Srandyf 	(void) spl0();		/* enable interrupts */
9755295Srandyf 
9765295Srandyf 	PMD(PMD_SX, ("%s() #4 cp->cpu_base_spl %d\n", str,
9775295Srandyf 	    cp->cpu_base_spl))
9785295Srandyf 
9795295Srandyf 	/*
9805295Srandyf 	 * Set up the CPU module for this CPU.  This can't be done before
9815295Srandyf 	 * this CPU is made CPU_READY, because we may (in heterogeneous systems)
9825295Srandyf 	 * need to go load another CPU module.  The act of attempting to load
9835295Srandyf 	 * a module may trigger a cross-call, which will ASSERT unless this
9845295Srandyf 	 * cpu is CPU_READY.
9855295Srandyf 	 */
9865295Srandyf 
9875295Srandyf 	/*
9885295Srandyf 	 * cmi already been init'd (during boot), so do not need to do it again
9895295Srandyf 	 */
9905295Srandyf #ifdef PM_REINITMCAONRESUME
9915295Srandyf 	if (x86_feature & X86_MCA)
9925295Srandyf 		cmi_mca_init();
9935295Srandyf #endif
9945295Srandyf 
9955295Srandyf 	PMD(PMD_SX, ("%s() returning\n", str))
9965295Srandyf 
9975295Srandyf 	/* return; */
9985295Srandyf }
9995295Srandyf 
10005295Srandyf void
10015295Srandyf i_cpr_alloc_cpus(void)
10025295Srandyf {
10035295Srandyf 	char *str = "i_cpr_alloc_cpus";
10045295Srandyf 
10055295Srandyf 	PMD(PMD_SX, ("%s() CPU->cpu_id %d\n", str, CPU->cpu_id))
10065295Srandyf 	/*
10075295Srandyf 	 * we allocate this only when we actually need it to save on
10085295Srandyf 	 * kernel memory
10095295Srandyf 	 */
10105295Srandyf 
10115295Srandyf 	if (wc_other_cpus == NULL) {
10125295Srandyf 		wc_other_cpus = kmem_zalloc(ncpus * sizeof (wc_cpu_t),
10135295Srandyf 		    KM_SLEEP);
10145295Srandyf 	}
10155295Srandyf 
10165295Srandyf }
10175295Srandyf 
10185295Srandyf void
10195295Srandyf i_cpr_free_cpus(void)
10205295Srandyf {
10215295Srandyf 	if (wc_other_cpus != NULL) {
10225295Srandyf 		kmem_free((void *) wc_other_cpus, ncpus * sizeof (wc_cpu_t));
10235295Srandyf 		wc_other_cpus = NULL;
10245295Srandyf 	}
10255295Srandyf }
10265295Srandyf 
10275295Srandyf /*
10285295Srandyf  * wrapper for acpica_ddi_save_resources()
10295295Srandyf  */
10305295Srandyf void
10315295Srandyf i_cpr_save_configuration(dev_info_t *dip)
10325295Srandyf {
10335295Srandyf 	acpica_ddi_save_resources(dip);
10345295Srandyf }
10355295Srandyf 
10365295Srandyf /*
10375295Srandyf  * wrapper for acpica_ddi_restore_resources()
10385295Srandyf  */
10395295Srandyf void
10405295Srandyf i_cpr_restore_configuration(dev_info_t *dip)
10415295Srandyf {
10425295Srandyf 	acpica_ddi_restore_resources(dip);
10435295Srandyf }
10445817Sjan 
10455817Sjan static int
10465817Sjan wait_for_set(cpuset_t *set, int who)
10475817Sjan {
10485817Sjan 	int delays;
10495817Sjan 	char *str = "wait_for_set";
10505817Sjan 
10515817Sjan 	for (delays = 0; !CPU_IN_SET(*set, who); delays++) {
10525817Sjan 		if (delays == 500) {
10535817Sjan 			/*
10545817Sjan 			 * After five seconds, things are probably
10555817Sjan 			 * looking a bit bleak - explain the hang.
10565817Sjan 			 */
10575817Sjan 			cmn_err(CE_NOTE, "cpu%d: started, "
10585817Sjan 			    "but not running in the kernel yet", who);
10595817Sjan 			PMD(PMD_SX, ("%s() %d cpu started "
10605817Sjan 			    "but not running in the kernel yet\n",
10615817Sjan 			    str, who))
10625817Sjan 		} else if (delays > 2000) {
10635817Sjan 			/*
10645817Sjan 			 * We waited at least 20 seconds, bail ..
10655817Sjan 			 */
10665817Sjan 			cmn_err(CE_WARN, "cpu%d: timed out", who);
10675817Sjan 			PMD(PMD_SX, ("%s() %d cpu timed out\n",
10685817Sjan 			    str, who))
10695817Sjan 			return (0);
10705817Sjan 		}
10715817Sjan 
10725817Sjan 		/*
10735817Sjan 		 * wait at least 10ms, then check again..
10745817Sjan 		 */
10755817Sjan 		drv_usecwait(10000);
10765817Sjan 	}
10775817Sjan 
10785817Sjan 	return (1);
10795817Sjan }
1080*9989SJoseph.Townsend@Sun.COM 
1081*9989SJoseph.Townsend@Sun.COM static	void
1082*9989SJoseph.Townsend@Sun.COM i_cpr_save_stack(kthread_t *t, wc_cpu_t *wc_cpu)
1083*9989SJoseph.Townsend@Sun.COM {
1084*9989SJoseph.Townsend@Sun.COM 	size_t	stack_size;	/* size of stack */
1085*9989SJoseph.Townsend@Sun.COM 	caddr_t	start = CPR_GET_STACK_START(t);	/* stack start */
1086*9989SJoseph.Townsend@Sun.COM 	caddr_t	end = CPR_GET_STACK_END(t);	/* stack end  */
1087*9989SJoseph.Townsend@Sun.COM 
1088*9989SJoseph.Townsend@Sun.COM 	stack_size = (size_t)end - (size_t)start;
1089*9989SJoseph.Townsend@Sun.COM 
1090*9989SJoseph.Townsend@Sun.COM 	if (wc_cpu->wc_saved_stack_size < stack_size) {
1091*9989SJoseph.Townsend@Sun.COM 		if (wc_cpu->wc_saved_stack != NULL) {
1092*9989SJoseph.Townsend@Sun.COM 			kmem_free(wc_cpu->wc_saved_stack,
1093*9989SJoseph.Townsend@Sun.COM 			    wc_cpu->wc_saved_stack_size);
1094*9989SJoseph.Townsend@Sun.COM 		}
1095*9989SJoseph.Townsend@Sun.COM 		wc_cpu->wc_saved_stack = kmem_zalloc(stack_size, KM_SLEEP);
1096*9989SJoseph.Townsend@Sun.COM 		wc_cpu->wc_saved_stack_size = stack_size;
1097*9989SJoseph.Townsend@Sun.COM 	}
1098*9989SJoseph.Townsend@Sun.COM 
1099*9989SJoseph.Townsend@Sun.COM 	bcopy(start, wc_cpu->wc_saved_stack, stack_size);
1100*9989SJoseph.Townsend@Sun.COM }
1101*9989SJoseph.Townsend@Sun.COM 
1102*9989SJoseph.Townsend@Sun.COM void
1103*9989SJoseph.Townsend@Sun.COM i_cpr_restore_stack(kthread_t *t, greg_t *save_stack)
1104*9989SJoseph.Townsend@Sun.COM {
1105*9989SJoseph.Townsend@Sun.COM 	size_t	stack_size;	/* size of stack */
1106*9989SJoseph.Townsend@Sun.COM 	caddr_t	start = CPR_GET_STACK_START(t);	/* stack start */
1107*9989SJoseph.Townsend@Sun.COM 	caddr_t	end = CPR_GET_STACK_END(t);	/* stack end  */
1108*9989SJoseph.Townsend@Sun.COM 
1109*9989SJoseph.Townsend@Sun.COM 	stack_size = (size_t)end - (size_t)start;
1110*9989SJoseph.Townsend@Sun.COM 
1111*9989SJoseph.Townsend@Sun.COM 	bcopy(save_stack, start, stack_size);
1112*9989SJoseph.Townsend@Sun.COM }
1113