xref: /onnv-gate/usr/src/uts/i86pc/ml/cpr_wakecode.s (revision 13136:67d1861e02c1)
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/*
2212826Skuriakose.kuruvilla@oracle.com * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235295Srandyf */
245295Srandyf
255295Srandyf#include <sys/asm_linkage.h>
265295Srandyf#include <sys/asm_misc.h>
275295Srandyf#include <sys/regset.h>
285295Srandyf#include <sys/privregs.h>
295295Srandyf#include <sys/x86_archext.h>
305295Srandyf#include <sys/cpr_wakecode.h>
315295Srandyf
325295Srandyf#if !defined(__lint)
335295Srandyf#include <sys/segments.h>
345295Srandyf#include "assym.h"
355295Srandyf#endif
365295Srandyf
376876Sjan#ifdef  DEBUG
386876Sjan#define LED     1
396876Sjan#define SERIAL  1
406876Sjan#endif	/*	DEBUG	*/
416876Sjan
426876Sjan#ifdef	DEBUG
436876Sjan#define	COM1	0x3f8
446876Sjan#define	COM2	0x2f8
456876Sjan#define	WC_COM	COM2	/* either COM1 or COM2			*/
466876Sjan#define	WC_LED	0x80    /* diagnostic led port ON motherboard	*/
476876Sjan
486876Sjan/*
496876Sjan * defined as offsets from the data register
506876Sjan */
516876Sjan#define	DLL	0	/* divisor latch (lsb) */
526876Sjan#define	DLH	1	/* divisor latch (msb) */
536876Sjan#define	LCR	3	/* line control register		*/
546876Sjan#define	MCR	4	/* modem control register		*/
556876Sjan
566876Sjan
576876Sjan#define	DLAB	0x80    /* divisor latch access bit		*/
586876Sjan#define	B9600L	0X0c	/* lsb bit pattern for 9600 baud	*/
596876Sjan#define	B9600H	0X0	/* hsb bit pattern for 9600 baud	*/
606876Sjan#define	DTR	0x01    /* Data Terminal Ready			*/
616876Sjan#define	RTS	0x02    /* Request To Send			*/
626876Sjan#define	STOP1	0x00	/* 1 stop bit				*/
636876Sjan#define	BITS8	0x03    /* 8 bits per char			*/
646876Sjan
656876Sjan#endif	/*	DEBUG	*/
666876Sjan
675295Srandyf/*
685295Srandyf *	This file contains the low level routines involved in getting
695295Srandyf *	into and out of ACPI S3, including those needed for restarting
705295Srandyf *	the non-boot cpus.
715295Srandyf *
725295Srandyf *	Our assumptions:
735295Srandyf *
745295Srandyf *	Our actions:
755295Srandyf *
765295Srandyf */
775295Srandyf
785295Srandyf#if defined(lint) || defined(__lint)
795295Srandyf
805295Srandyf/*ARGSUSED*/
815295Srandyfint
825295Srandyfwc_save_context(wc_cpu_t *pcpu)
835295Srandyf{ return 0; }
845295Srandyf
855295Srandyf#else	/* lint */
865295Srandyf
875295Srandyf#if defined(__GNU_AS__)
885295Srandyf
895295Srandyf	NOTHING AT ALL YET!
905295Srandyf
915295Srandyf#else	/* !defined(__GNU_AS__) */
925295Srandyf
935295Srandyf#if defined(__amd64)
945295Srandyf
955295Srandyf	ENTRY_NP(wc_save_context)
965295Srandyf
975295Srandyf	movq	(%rsp), %rdx		/ return address
985295Srandyf	movq	%rdx, WC_RETADDR(%rdi)
995295Srandyf	pushq	%rbp
1005295Srandyf	movq	%rsp,%rbp
1015295Srandyf
1025295Srandyf	movq    %rdi, WC_VIRTADDR(%rdi)
1035295Srandyf	movq    %rdi, WC_RDI(%rdi)
1045295Srandyf
1055295Srandyf	movq    %rdx, WC_RDX(%rdi)
1065295Srandyf
1075295Srandyf/ stash everything else we need
1085295Srandyf	sgdt	WC_GDT(%rdi)
1095295Srandyf	sidt	WC_IDT(%rdi)
1105295Srandyf	sldt	WC_LDT(%rdi)
1115295Srandyf	str	WC_TR(%rdi)
1125295Srandyf
1135295Srandyf	movq	%cr0, %rdx
1145295Srandyf	movq	%rdx, WC_CR0(%rdi)
1155295Srandyf	movq	%cr3, %rdx
1165295Srandyf	movq	%rdx, WC_CR3(%rdi)
1175295Srandyf	movq	%cr4, %rdx
1185295Srandyf	movq	%rdx, WC_CR4(%rdi)
1195295Srandyf	movq	%cr8, %rdx
1205295Srandyf	movq	%rdx, WC_CR8(%rdi)
1215295Srandyf
1225295Srandyf	movq    %r8, WC_R8(%rdi)
1235295Srandyf	movq    %r9, WC_R9(%rdi)
1245295Srandyf	movq    %r10, WC_R10(%rdi)
1255295Srandyf	movq    %r11, WC_R11(%rdi)
1265295Srandyf	movq    %r12, WC_R12(%rdi)
1275295Srandyf	movq    %r13, WC_R13(%rdi)
1285295Srandyf	movq    %r14, WC_R14(%rdi)
1295295Srandyf	movq    %r15, WC_R15(%rdi)
1305295Srandyf	movq    %rax, WC_RAX(%rdi)
1315295Srandyf	movq    %rbp, WC_RBP(%rdi)
1325295Srandyf	movq    %rbx, WC_RBX(%rdi)
1335295Srandyf	movq    %rcx, WC_RCX(%rdi)
1345295Srandyf	movq    %rsi, WC_RSI(%rdi)
1355295Srandyf	movq    %rsp, WC_RSP(%rdi)
1365295Srandyf
1375295Srandyf	movw	%ss, WC_SS(%rdi)
1385295Srandyf	movw	%cs, WC_CS(%rdi)
1395295Srandyf	movw	%ds, WC_DS(%rdi)
1405295Srandyf	movw	%es, WC_ES(%rdi)
1415295Srandyf
1425295Srandyf	movq	$0, %rcx		/ save %fs register
1435295Srandyf	movw    %fs, %cx
1445295Srandyf	movq    %rcx, WC_FS(%rdi)
1455295Srandyf
1465295Srandyf	movl    $MSR_AMD_FSBASE, %ecx
1475295Srandyf	rdmsr
1485295Srandyf	movl    %eax, WC_FSBASE(%rdi)
1495295Srandyf	movl    %edx, WC_FSBASE+4(%rdi)
1505295Srandyf
1515295Srandyf	movq	$0, %rcx		/ save %gs register
1525295Srandyf	movw    %gs, %cx
1535295Srandyf	movq    %rcx, WC_GS(%rdi)
1545295Srandyf
1555295Srandyf	movl    $MSR_AMD_GSBASE, %ecx	/ save gsbase msr
1565295Srandyf	rdmsr
1575295Srandyf	movl    %eax, WC_GSBASE(%rdi)
1585295Srandyf	movl    %edx, WC_GSBASE+4(%rdi)
1595295Srandyf
1605295Srandyf	movl    $MSR_AMD_KGSBASE, %ecx	/ save kgsbase msr
1615295Srandyf	rdmsr
1625295Srandyf	movl    %eax, WC_KGSBASE(%rdi)
1635295Srandyf	movl    %edx, WC_KGSBASE+4(%rdi)
1645295Srandyf
1659989SJoseph.Townsend@Sun.COM	movq	%gs:CPU_ID, %rax	/ save current cpu id
1669989SJoseph.Townsend@Sun.COM	movq	%rax, WC_CPU_ID(%rdi)
1679989SJoseph.Townsend@Sun.COM
1685295Srandyf	pushfq
1695295Srandyf	popq	WC_EFLAGS(%rdi)
1705295Srandyf
1715295Srandyf	wbinvd				/ flush the cache
1729989SJoseph.Townsend@Sun.COM	mfence
1735295Srandyf
1745295Srandyf	movq	$1, %rax		/ at suspend return 1
1755295Srandyf
1765295Srandyf	leave
1775295Srandyf
1785295Srandyf	ret
1795295Srandyf
1805295Srandyf	SET_SIZE(wc_save_context)
1815295Srandyf
1825295Srandyf#elif defined(__i386)
1835295Srandyf
1845295Srandyf	ENTRY_NP(wc_save_context)
1855295Srandyf
1865295Srandyf	movl	4(%esp), %eax		/ wc_cpu_t *
1875295Srandyf	movl	%eax, WC_VIRTADDR(%eax)
1885295Srandyf
1895295Srandyf	movl	(%esp), %edx		/ return address
1905295Srandyf	movl	%edx, WC_RETADDR(%eax)
1915295Srandyf
1925295Srandyf	str	WC_TR(%eax)		/ stash everything else we need
1935295Srandyf	sgdt	WC_GDT(%eax)
1945295Srandyf	sldt	WC_LDT(%eax)
1955295Srandyf	sidt	WC_IDT(%eax)
1965295Srandyf
1975295Srandyf	movl	%cr0, %edx
1985295Srandyf	movl	%edx, WC_CR0(%eax)
1995295Srandyf	movl	%cr3, %edx
2005295Srandyf	movl	%edx, WC_CR3(%eax)
2015295Srandyf	movl	%cr4, %edx
2025295Srandyf	movl	%edx, WC_CR4(%eax)
2035295Srandyf
2045295Srandyf	movl	%ebx, WC_EBX(%eax)
2055295Srandyf	movl	%edi, WC_EDI(%eax)
2065295Srandyf	movl	%esi, WC_ESI(%eax)
2075295Srandyf	movl	%ebp, WC_EBP(%eax)
2085295Srandyf	movl	%esp, WC_ESP(%eax)
2095295Srandyf
2105295Srandyf	movw	%ss, WC_SS(%eax)
2115295Srandyf	movw	%cs, WC_CS(%eax)
2125295Srandyf	movw	%ds, WC_DS(%eax)
2135295Srandyf	movw	%es, WC_ES(%eax)
2145295Srandyf	movw	%fs, WC_FS(%eax)
2155295Srandyf	movw	%gs, WC_GS(%eax)
2165295Srandyf
2175295Srandyf	pushfl
2185295Srandyf	popl	WC_EFLAGS(%eax)
2195295Srandyf
2209989SJoseph.Townsend@Sun.COM	pushl	%gs:CPU_ID		/ save current cpu id
2219989SJoseph.Townsend@Sun.COM	popl	WC_CPU_ID(%eax)
2229989SJoseph.Townsend@Sun.COM
2235295Srandyf	wbinvd				/ flush the cache
2249989SJoseph.Townsend@Sun.COM	mfence
2255295Srandyf
2265295Srandyf	movl	$1, %eax		/ at suspend return 1
2275295Srandyf	ret
2285295Srandyf
2295295Srandyf	SET_SIZE(wc_save_context)
2305295Srandyf
2315295Srandyf#endif	/* __amd64 */
2325295Srandyf
2335295Srandyf#endif	/* __GNU_AS__ */
2345295Srandyf
2355295Srandyf#endif /* lint */
2365295Srandyf
2375295Srandyf
2385295Srandyf/*
2395295Srandyf *	Our assumptions:
2405295Srandyf *		- We are running in real mode.
2415295Srandyf *		- Interrupts are disabled.
2425295Srandyf *
2435295Srandyf *	Our actions:
2445295Srandyf *		- We start using our GDT by loading correct values in the
2455295Srandyf *		  selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL,
2465295Srandyf *		  gs=KGS_SEL).
2475295Srandyf *		- We change over to using our IDT.
2485295Srandyf *		- We load the default LDT into the hardware LDT register.
2495295Srandyf *		- We load the default TSS into the hardware task register.
2505295Srandyf *		- We restore registers
2515295Srandyf *		- We return to original caller (a la setjmp)
2525295Srandyf */
2535295Srandyf
2545295Srandyf#if defined(lint) || defined(__lint)
2555295Srandyf
2565295Srandyfvoid
2575295Srandyfwc_rm_start(void)
2585295Srandyf{}
2595295Srandyf
2605295Srandyfvoid
2615295Srandyfwc_rm_end(void)
2625295Srandyf{}
2635295Srandyf
2645295Srandyf#else	/* lint */
2655295Srandyf
2665295Srandyf#if defined(__GNU_AS__)
2675295Srandyf
2685295Srandyf	NOTHING AT ALL YET!
2695295Srandyf
2705295Srandyf#else	/* __GNU_AS__ */
2715295Srandyf
2725295Srandyf#if defined(__amd64)
2735295Srandyf
2745295Srandyf	ENTRY_NP(wc_rm_start)
2755295Srandyf
2765295Srandyf	/*
2775295Srandyf	 * For vulcan as we need to do a .code32 and mentally invert the
2785295Srandyf	 * meaning of the addr16 and data16 prefixes to get 32-bit access when
2795295Srandyf	 * generating code to be executed in 16-bit mode (sigh...)
2805295Srandyf	 */
2815295Srandyf
2825295Srandyf	.code32
2835295Srandyf
2845295Srandyf	cli
2855295Srandyf	movw		%cs, %ax
2865295Srandyf	movw		%ax, %ds		/ establish ds ...
2875295Srandyf	movw		%ax, %ss		/ ... and ss:esp
2885295Srandyf	D16 movl	$WC_STKSTART, %esp
2895295Srandyf/ using the following value blows up machines! - DO NOT USE
2905295Srandyf/	D16 movl	0xffc, %esp
2915295Srandyf
2925295Srandyf
2935295Srandyf#if     LED
2946876Sjan	D16 movl        $WC_LED, %edx
2955295Srandyf	D16 movb        $0xd1, %al
2965295Srandyf	outb    (%dx)
2975295Srandyf#endif
2985295Srandyf
2995295Srandyf#if     SERIAL
3006876Sjan	D16 movl        $WC_COM, %edx
3015295Srandyf	D16 movb        $0x61, %al
3025295Srandyf	outb    (%dx)
3035295Srandyf#endif
3045295Srandyf
3055295Srandyf	D16 call	cominit
3065295Srandyf
3075295Srandyf	/*
3085295Srandyf	 * Enable protected-mode, write protect, and alignment mask
3095295Srandyf	 * %cr0 has already been initialsed to zero
3105295Srandyf	 */
3115295Srandyf	movl		%cr0, %eax
3125295Srandyf	D16 orl		$[CR0_PE|CR0_WP|CR0_AM], %eax
3135295Srandyf	movl		%eax, %cr0
3145295Srandyf
3155295Srandyf	/*
3165295Srandyf	 * Do a jmp immediately after writing to cr0 when enabling protected
3175295Srandyf	 * mode to clear the real mode prefetch queue (per Intel's docs)
3185295Srandyf	 */
3195295Srandyf	jmp		pestart
3205295Srandyfpestart:
3215295Srandyf
3225295Srandyf#if     LED
3236876Sjan	D16 movl        $WC_LED, %edx
3245295Srandyf	D16 movb        $0xd2, %al
3255295Srandyf	outb    (%dx)
3265295Srandyf#endif
3275295Srandyf
3285295Srandyf#if     SERIAL
3296876Sjan	D16 movl        $WC_COM, %edx
3305295Srandyf	D16 movb        $0x62, %al
3315295Srandyf	outb    (%dx)
3325295Srandyf#endif
3335295Srandyf
3345295Srandyf	/*
3355295Srandyf	 * 16-bit protected mode is now active, so prepare to turn on long
3365295Srandyf	 * mode
3375295Srandyf	 */
3385295Srandyf
3395295Srandyf#if     LED
3406876Sjan	D16 movl        $WC_LED, %edx
3415295Srandyf	D16 movb        $0xd3, %al
3425295Srandyf	outb    (%dx)
3435295Srandyf#endif
3445295Srandyf
3455295Srandyf#if     SERIAL
3466876Sjan	D16 movl        $WC_COM, %edx
3475295Srandyf	D16 movb        $0x63, %al
3485295Srandyf	outb    (%dx)
3495295Srandyf#endif
3505295Srandyf
3515295Srandyf	/*
3525295Srandyf 	 * Add any initial cr4 bits
3535295Srandyf	 */
3545295Srandyf	movl		%cr4, %eax
3555295Srandyf	A16 D16 orl	CR4OFF, %eax
3565295Srandyf
3575295Srandyf	/*
3585295Srandyf	 * Enable PAE mode (CR4.PAE)
3595295Srandyf	 */
3605295Srandyf	D16 orl		$CR4_PAE, %eax
3615295Srandyf	movl		%eax, %cr4
3625295Srandyf
3635295Srandyf#if     LED
3646876Sjan	D16 movl        $WC_LED, %edx
3655295Srandyf	D16 movb        $0xd4, %al
3665295Srandyf	outb    (%dx)
3675295Srandyf#endif
3685295Srandyf
3695295Srandyf#if     SERIAL
3706876Sjan	D16 movl        $WC_COM, %edx
3715295Srandyf	D16 movb        $0x64, %al
3725295Srandyf	outb    (%dx)
3735295Srandyf#endif
3745295Srandyf
3755295Srandyf	/*
3765295Srandyf	 * Point cr3 to the 64-bit long mode page tables.
3775295Srandyf	 *
3785295Srandyf	 * Note that these MUST exist in 32-bit space, as we don't have
3795295Srandyf	 * a way to load %cr3 with a 64-bit base address for the page tables
3805295Srandyf	 * until the CPU is actually executing in 64-bit long mode.
3815295Srandyf	 */
3825295Srandyf	A16 D16 movl	CR3OFF, %eax
3835295Srandyf	movl		%eax, %cr3
3845295Srandyf
3855295Srandyf	/*
3865295Srandyf	 * Set long mode enable in EFER (EFER.LME = 1)
3875295Srandyf	 */
3885295Srandyf	D16 movl	$MSR_AMD_EFER, %ecx
3895295Srandyf	rdmsr
3905295Srandyf
3915295Srandyf	D16 orl		$AMD_EFER_LME, %eax
3925295Srandyf	wrmsr
3935295Srandyf
3945295Srandyf#if     LED
3956876Sjan	D16 movl        $WC_LED, %edx
3965295Srandyf	D16 movb        $0xd5, %al
3975295Srandyf	outb    (%dx)
3985295Srandyf#endif
3995295Srandyf
4005295Srandyf#if     SERIAL
4016876Sjan	D16 movl        $WC_COM, %edx
4025295Srandyf	D16 movb        $0x65, %al
4035295Srandyf	outb    (%dx)
4045295Srandyf#endif
4055295Srandyf
4065295Srandyf	/*
4075295Srandyf	 * Finally, turn on paging (CR0.PG = 1) to activate long mode.
4085295Srandyf	 */
4095295Srandyf	movl		%cr0, %eax
4105295Srandyf	D16 orl		$CR0_PG, %eax
4115295Srandyf	movl		%eax, %cr0
4125295Srandyf
4135295Srandyf	/*
4145295Srandyf	 * The instruction after enabling paging in CR0 MUST be a branch.
4155295Srandyf	 */
4165295Srandyf	jmp		long_mode_active
4175295Srandyf
4185295Srandyflong_mode_active:
4195295Srandyf
4205295Srandyf#if     LED
4216876Sjan	D16 movl        $WC_LED, %edx
4225295Srandyf	D16 movb        $0xd6, %al
4235295Srandyf	outb    (%dx)
4245295Srandyf#endif
4255295Srandyf
4265295Srandyf#if     SERIAL
4276876Sjan	D16 movl        $WC_COM, %edx
4285295Srandyf	D16 movb        $0x66, %al
4295295Srandyf	outb    (%dx)
4305295Srandyf#endif
4315295Srandyf
4325295Srandyf	/*
4335295Srandyf	 * Long mode is now active but since we're still running with the
4345295Srandyf	 * original 16-bit CS we're actually in 16-bit compatability mode.
4355295Srandyf	 *
4365295Srandyf	 * We have to load an intermediate GDT and IDT here that we know are
4375295Srandyf	 * in 32-bit space before we can use the kernel's GDT and IDT, which
4385295Srandyf	 * may be in the 64-bit address space, and since we're in compatability
4395295Srandyf	 * mode, we only have access to 16 and 32-bit instructions at the
4405295Srandyf	 * moment.
4415295Srandyf	 */
4425295Srandyf	A16 D16 lgdt	TEMPGDTOFF	/* load temporary GDT */
4435295Srandyf	A16 D16 lidt	TEMPIDTOFF	/* load temporary IDT */
4445295Srandyf
4455295Srandyf
4465295Srandyf	/*
4475295Srandyf 	 * Do a far transfer to 64-bit mode.  Set the CS selector to a 64-bit
4485295Srandyf	 * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump
4495295Srandyf	 * to the real mode platter address of wc_long_mode_64 as until the
4505295Srandyf	 * 64-bit CS is in place we don't have access to 64-bit instructions
4515295Srandyf	 * and thus can't reference a 64-bit %rip.
4525295Srandyf	 */
4535295Srandyf
4545295Srandyf#if     LED
4556876Sjan	D16 movl        $WC_LED, %edx
4565295Srandyf	D16 movb        $0xd7, %al
4575295Srandyf	outb    (%dx)
4585295Srandyf#endif
4595295Srandyf
4605295Srandyf#if     SERIAL
4616876Sjan	D16 movl        $WC_COM, %edx
4625295Srandyf	D16 movb        $0x67, %al
4635295Srandyf	outb    (%dx)
4645295Srandyf#endif
4655295Srandyf
4665295Srandyf	D16 	pushl 	$TEMP_CS64_SEL
4675295Srandyf	A16 D16 pushl	LM64OFF
4685295Srandyf
4695295Srandyf	D16 lret
4705295Srandyf
4715295Srandyf
4725295Srandyf/*
4735295Srandyf * Support routine to re-initialize VGA subsystem
4745295Srandyf */
4755295Srandyfvgainit:
4765295Srandyf	D16 ret
4775295Srandyf
4785295Srandyf/*
4795295Srandyf * Support routine to re-initialize keyboard (which is USB - help!)
4805295Srandyf */
4815295Srandyfkbdinit:
4825295Srandyf	D16 ret
4835295Srandyf
4845295Srandyf/*
4855295Srandyf * Support routine to re-initialize COM ports to something sane
4865295Srandyf */
4875295Srandyfcominit:
4885295Srandyf	/ init COM1 & COM2
4896876Sjan
4906876Sjan#if     DEBUG
4916876Sjan/*
4926876Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that
4936876Sjan * we can get debug output before the asy driver has resumed
4946876Sjan */
4956876Sjan
4966876Sjan/ select COM1
4976876Sjan	D16 movl	$[COM1+LCR], %edx
4986876Sjan	D16 movb	$DLAB, %al		/ divisor latch
4996876Sjan	outb	(%dx)
5006876Sjan
5016876Sjan	D16 movl	$[COM1+DLL], %edx	/ divisor latch lsb
5026876Sjan	D16 movb	$B9600L, %al		/ divisor latch
5036876Sjan	outb	(%dx)
5046876Sjan
5056876Sjan	D16 movl	$[COM1+DLH], %edx	/ divisor latch hsb
5066876Sjan	D16 movb	$B9600H, %al		/ divisor latch
5076876Sjan	outb	(%dx)
5086876Sjan
5096876Sjan	D16 movl	$[COM1+LCR], %edx	/ select COM1
5106876Sjan	D16 movb	$[STOP1|BITS8], %al	/ 1 stop bit, 8bit word len
5116876Sjan	outb	(%dx)
5126876Sjan
5136876Sjan	D16 movl	$[COM1+MCR], %edx	/ select COM1
5146876Sjan	D16 movb	$[RTS|DTR], %al		/ data term ready & req to send
5156876Sjan	outb	(%dx)
5166876Sjan
5176876Sjan/ select COM2
5186876Sjan	D16 movl	$[COM2+LCR], %edx
5196876Sjan	D16 movb	$DLAB, %al		/ divisor latch
5206876Sjan	outb	(%dx)
5216876Sjan
5226876Sjan	D16 movl	$[COM2+DLL], %edx	/ divisor latch lsb
5236876Sjan	D16 movb	$B9600L, %al		/ divisor latch
5246876Sjan	outb	(%dx)
5256876Sjan
5266876Sjan	D16 movl	$[COM2+DLH], %edx	/ divisor latch hsb
5276876Sjan	D16 movb	$B9600H, %al		/ divisor latch
5286876Sjan	outb	(%dx)
5296876Sjan
5306876Sjan	D16 movl	$[COM2+LCR], %edx	/ select COM1
5316876Sjan	D16 movb	$[STOP1|BITS8], %al	/ 1 stop bit, 8bit word len
5326876Sjan	outb	(%dx)
5336876Sjan
5346876Sjan	D16 movl	$[COM2+MCR], %edx	/ select COM1
5356876Sjan	D16 movb	$[RTS|DTR], %al		/ data term ready & req to send
5366876Sjan	outb	(%dx)
5376876Sjan#endif	/*	DEBUG	*/
5386876Sjan
5395295Srandyf	D16 ret
5405295Srandyf
5415295Srandyf	.code64
5425295Srandyf
5435295Srandyf	.globl wc_long_mode_64
5445295Srandyfwc_long_mode_64:
5455295Srandyf
5465295Srandyf#if     LED
5476876Sjan	movw        $WC_LED, %dx
5485295Srandyf	movb        $0xd8, %al
5495295Srandyf	outb    (%dx)
5505295Srandyf#endif
5515295Srandyf
5525295Srandyf#if     SERIAL
5536876Sjan	movw        $WC_COM, %dx
5545295Srandyf	movb        $0x68, %al
5555295Srandyf	outb    (%dx)
5565295Srandyf#endif
5575295Srandyf
5585295Srandyf	/*
5595295Srandyf	 * We are now running in long mode with a 64-bit CS (EFER.LMA=1,
5605295Srandyf	 * CS.L=1) so we now have access to 64-bit instructions.
5615295Srandyf	 *
5625295Srandyf	 * First, set the 64-bit GDT base.
5635295Srandyf	 */
5645295Srandyf	.globl	rm_platter_pa
5655295Srandyf	movl	rm_platter_pa, %eax
5665295Srandyf
5675295Srandyf	lgdtq	GDTROFF(%rax)		/* load 64-bit GDT */
5685295Srandyf
5695295Srandyf	/*
5705295Srandyf	 * Save the CPU number in %r11; get the value here since it's saved in
5715295Srandyf	 * the real mode platter.
5725295Srandyf	 */
5735295Srandyf/ JAN
5745295Srandyf/ the following is wrong! need to figure out MP systems
5755295Srandyf/	movl	CPUNOFF(%rax), %r11d
5765295Srandyf
5775295Srandyf	/*
5785295Srandyf	 * Add rm_platter_pa to %rsp to point it to the same location as seen
5795295Srandyf	 * from 64-bit mode.
5805295Srandyf	 */
5815295Srandyf	addq	%rax, %rsp
5825295Srandyf
5835295Srandyf	/*
5845295Srandyf	 * Now do an lretq to load CS with the appropriate selector for the
5855295Srandyf	 * kernel's 64-bit GDT and to start executing 64-bit setup code at the
5865295Srandyf	 * virtual address where boot originally loaded this code rather than
5875295Srandyf	 * the copy in the real mode platter's rm_code array as we've been
5885295Srandyf	 * doing so far.
5895295Srandyf	 */
5905295Srandyf
5915295Srandyf#if     LED
5926876Sjan	movw        $WC_LED, %dx
5935295Srandyf	movb        $0xd9, %al
5945295Srandyf	outb    (%dx)
5955295Srandyf#endif
5965295Srandyf
5975295Srandyf/ JAN this should produce 'i' but we get 'g' instead ???
5985295Srandyf#if     SERIAL
5996876Sjan	movw        $WC_COM, %dx
6005295Srandyf	movb        $0x69, %al
6015295Srandyf	outb    (%dx)
6025295Srandyf#endif
6035295Srandyf
6045295Srandyf	pushq	$KCS_SEL
6055295Srandyf	pushq	$kernel_wc_code
6065295Srandyf	lretq
6075295Srandyf
6085295Srandyf	.globl kernel_wc_code
6095295Srandyfkernel_wc_code:
6105295Srandyf
6115295Srandyf#if     LED
6126876Sjan	movw        $WC_LED, %dx
6135295Srandyf	movb        $0xda, %al
6145295Srandyf	outb    (%dx)
6155295Srandyf#endif
6165295Srandyf
6175295Srandyf/ JAN this should produce 'j' but we get 'g' instead ???
6185295Srandyf#if     SERIAL
6196876Sjan	movw        $WC_COM, %dx
6205295Srandyf	movb        $0x6a, %al
6215295Srandyf	outb    (%dx)
6225295Srandyf#endif
6235295Srandyf
6245295Srandyf	/*
6255295Srandyf	 * Complete the balance of the setup we need to before executing
6265295Srandyf	 * 64-bit kernel code (namely init rsp, TSS, LGDT, FS and GS).
6275295Srandyf	 */
6285295Srandyf	.globl  rm_platter_va
6295295Srandyf	movq    rm_platter_va, %rbx
6305295Srandyf	addq	$WC_CPU, %rbx
6315295Srandyf
6325295Srandyf#if     LED
6336876Sjan	movw        $WC_LED, %dx
6345295Srandyf	movb        $0xdb, %al
6355295Srandyf	outb    (%dx)
6365295Srandyf#endif
6375295Srandyf
6385295Srandyf#if     SERIAL
6396876Sjan	movw        $WC_COM, %dx
6405295Srandyf	movw        $0x6b, %ax
6415295Srandyf	outb    (%dx)
6425295Srandyf#endif
6435295Srandyf
6445295Srandyf	/*
6455295Srandyf	 * restore the rest of the registers
6465295Srandyf	 */
6475295Srandyf
6485295Srandyf	lidtq	WC_IDT(%rbx)
6495295Srandyf
6505295Srandyf#if     LED
6516876Sjan	movw        $WC_LED, %dx
6525295Srandyf	movb        $0xdc, %al
6535295Srandyf	outb    (%dx)
6545295Srandyf#endif
6555295Srandyf
6565295Srandyf#if     SERIAL
6576876Sjan	movw        $WC_COM, %dx
6585295Srandyf	movw        $0x6c, %ax
6595295Srandyf	outb    (%dx)
6605295Srandyf#endif
6615295Srandyf
6625295Srandyf	/*
6635295Srandyf	 * restore the rest of the registers
6645295Srandyf	 */
6655295Srandyf
6665295Srandyf	movw    $KDS_SEL, %ax
6675295Srandyf	movw    %ax, %ds
6685295Srandyf	movw    %ax, %es
6695295Srandyf	movw    %ax, %ss
6705295Srandyf
6715295Srandyf	/*
6725295Srandyf	 * Before proceeding, enable usage of the page table NX bit if
6735295Srandyf	 * that's how the page tables are set up.
6745295Srandyf	 */
675*13136Skuriakose.kuruvilla@oracle.com	bt      $X86FSET_NX, x86_featureset(%rip)
67612826Skuriakose.kuruvilla@oracle.com	jnc     1f
6775295Srandyf	movl    $MSR_AMD_EFER, %ecx
6785295Srandyf	rdmsr
6795295Srandyf	orl     $AMD_EFER_NXE, %eax
6805295Srandyf	wrmsr
6815295Srandyf1:
6825295Srandyf
6835295Srandyf	movq	WC_CR4(%rbx), %rax	/ restore full cr4 (with Global Enable)
6845295Srandyf	movq	%rax, %cr4
6855295Srandyf
6865295Srandyf	lldt	WC_LDT(%rbx)
6875295Srandyf	movzwq	WC_TR(%rbx), %rax	/ clear TSS busy bit
6885295Srandyf	addq	WC_GDT+2(%rbx), %rax
6895295Srandyf	andl	$0xfffffdff, 4(%rax)
6905295Srandyf	movq	4(%rax), %rcx
6915295Srandyf	ltr	WC_TR(%rbx)
6925295Srandyf
6935295Srandyf#if     LED
6946876Sjan	movw        $WC_LED, %dx
6955295Srandyf	movb        $0xdd, %al
6965295Srandyf	outb    (%dx)
6975295Srandyf#endif
6985295Srandyf
6995295Srandyf#if     SERIAL
7006876Sjan	movw        $WC_COM, %dx
7015295Srandyf	movw        $0x6d, %ax
7025295Srandyf	outb    (%dx)
7035295Srandyf#endif
7045295Srandyf
7055295Srandyf/ restore %fsbase %gsbase %kgbase registers using wrmsr instruction
7065295Srandyf
7075295Srandyf	movq    WC_FS(%rbx), %rcx	/ restore fs register
7085295Srandyf	movw    %cx, %fs
7095295Srandyf
7105295Srandyf	movl    $MSR_AMD_FSBASE, %ecx
7115295Srandyf	movl    WC_FSBASE(%rbx), %eax
7125295Srandyf	movl    WC_FSBASE+4(%rbx), %edx
7135295Srandyf	wrmsr
7145295Srandyf
7155295Srandyf	movq    WC_GS(%rbx), %rcx	/ restore gs register
7165295Srandyf	movw    %cx, %gs
7175295Srandyf
7185295Srandyf	movl    $MSR_AMD_GSBASE, %ecx	/ restore gsbase msr
7195295Srandyf	movl    WC_GSBASE(%rbx), %eax
7205295Srandyf	movl    WC_GSBASE+4(%rbx), %edx
7215295Srandyf	wrmsr
7225295Srandyf
7235295Srandyf	movl    $MSR_AMD_KGSBASE, %ecx	/ restore kgsbase msr
7245295Srandyf	movl    WC_KGSBASE(%rbx), %eax
7255295Srandyf	movl    WC_KGSBASE+4(%rbx), %edx
7265295Srandyf	wrmsr
7275295Srandyf
7285295Srandyf	movq	WC_CR0(%rbx), %rdx
7295295Srandyf	movq	%rdx, %cr0
7305295Srandyf	movq	WC_CR3(%rbx), %rdx
7315295Srandyf	movq	%rdx, %cr3
7325295Srandyf	movq	WC_CR8(%rbx), %rdx
7335295Srandyf	movq	%rdx, %cr8
7345295Srandyf
7355295Srandyf#if     LED
7366876Sjan	movw        $WC_LED, %dx
7375295Srandyf	movb        $0xde, %al
7385295Srandyf	outb    (%dx)
7395295Srandyf#endif
7405295Srandyf
7415295Srandyf#if     SERIAL
7426876Sjan	movw        $WC_COM, %dx
7435295Srandyf	movb        $0x6e, %al
7445295Srandyf	outb    (%dx)
7455295Srandyf#endif
7465295Srandyf
7479989SJoseph.Townsend@Sun.COM	/*
7489989SJoseph.Townsend@Sun.COM	 * if we are not running on the boot CPU restore stack contents by
7499989SJoseph.Townsend@Sun.COM	 * calling i_cpr_restore_stack(curthread, save_stack);
7509989SJoseph.Townsend@Sun.COM	 */
7519989SJoseph.Townsend@Sun.COM	movq    %rsp, %rbp
7529989SJoseph.Townsend@Sun.COM	call	i_cpr_bootcpuid
7539989SJoseph.Townsend@Sun.COM	cmpl	%eax, WC_CPU_ID(%rbx)
7549989SJoseph.Townsend@Sun.COM	je	2f
7559989SJoseph.Townsend@Sun.COM
7569989SJoseph.Townsend@Sun.COM	movq	%gs:CPU_THREAD, %rdi
7579989SJoseph.Townsend@Sun.COM	movq	WC_SAVED_STACK(%rbx), %rsi
7589989SJoseph.Townsend@Sun.COM	call	i_cpr_restore_stack
7599989SJoseph.Townsend@Sun.COM2:
7609989SJoseph.Townsend@Sun.COM
7619989SJoseph.Townsend@Sun.COM	movq    WC_RSP(%rbx), %rsp	/ restore stack pointer
7625295Srandyf
7635295Srandyf	/*
7647362SKerry.Shu@Sun.COM	 * APIC initialization
7655295Srandyf	 */
7669989SJoseph.Townsend@Sun.COM	movq    %rsp, %rbp
7675295Srandyf
7685817Sjan	/*
7695817Sjan	 * skip iff function pointer is NULL
7705817Sjan	 */
7715817Sjan	cmpq	$0, ap_mlsetup
7729989SJoseph.Townsend@Sun.COM	je	3f
7735817Sjan	call	*ap_mlsetup
7749989SJoseph.Townsend@Sun.COM3:
7755295Srandyf
7765295Srandyf	call    *cpr_start_cpu_func
7775295Srandyf
7785295Srandyf/ restore %rbx to the value it ahd before we called the functions above
7795295Srandyf	movq    rm_platter_va, %rbx
7805295Srandyf	addq	$WC_CPU, %rbx
7815295Srandyf
7825295Srandyf	movq    WC_R8(%rbx), %r8
7835295Srandyf	movq    WC_R9(%rbx), %r9
7845295Srandyf	movq    WC_R10(%rbx), %r10
7855295Srandyf	movq    WC_R11(%rbx), %r11
7865295Srandyf	movq    WC_R12(%rbx), %r12
7875295Srandyf	movq    WC_R13(%rbx), %r13
7885295Srandyf	movq    WC_R14(%rbx), %r14
7895295Srandyf	movq    WC_R15(%rbx), %r15
7905295Srandyf/	movq    WC_RAX(%rbx), %rax
7915295Srandyf	movq    WC_RBP(%rbx), %rbp
7925295Srandyf	movq    WC_RCX(%rbx), %rcx
7935295Srandyf/	movq    WC_RDX(%rbx), %rdx
7945295Srandyf	movq    WC_RDI(%rbx), %rdi
7955295Srandyf	movq    WC_RSI(%rbx), %rsi
7965295Srandyf
7975295Srandyf
7985295Srandyf/ assume that %cs does not need to be restored
7995295Srandyf/ %ds, %es & %ss are ignored in 64bit mode
8005295Srandyf	movw	WC_SS(%rbx), %ss
8015295Srandyf	movw	WC_DS(%rbx), %ds
8025295Srandyf	movw	WC_ES(%rbx), %es
8035295Srandyf
8045295Srandyf#if     LED
8056876Sjan	movw        $WC_LED, %dx
8065295Srandyf	movb        $0xdf, %al
8075295Srandyf	outb    (%dx)
8085295Srandyf#endif
8095295Srandyf
8105295Srandyf#if     SERIAL
8116876Sjan	movw        $WC_COM, %dx
8125295Srandyf	movb        $0x6f, %al
8135295Srandyf	outb    (%dx)
8145295Srandyf#endif
8155295Srandyf
8165295Srandyf
8175295Srandyf	movq    WC_RBP(%rbx), %rbp
8185295Srandyf	movq    WC_RSP(%rbx), %rsp
8195295Srandyf
8205295Srandyf#if     LED
8216876Sjan	movw        $WC_LED, %dx
8225295Srandyf	movb        $0xe0, %al
8235295Srandyf	outb    (%dx)
8245295Srandyf#endif
8255295Srandyf
8265295Srandyf#if     SERIAL
8276876Sjan	movw        $WC_COM, %dx
8285295Srandyf	movb        $0x70, %al
8295295Srandyf	outb    (%dx)
8305295Srandyf#endif
8315295Srandyf
8325295Srandyf
8335295Srandyf	movq    WC_RCX(%rbx), %rcx
8345295Srandyf
8355295Srandyf	pushq	WC_EFLAGS(%rbx)			/ restore flags
8365295Srandyf	popfq
8375295Srandyf
8385295Srandyf#if     LED
8396876Sjan	movw        $WC_LED, %dx
8405295Srandyf	movb        $0xe1, %al
8415295Srandyf	outb    (%dx)
8425295Srandyf#endif
8435295Srandyf
8445295Srandyf#if     SERIAL
8456876Sjan	movw        $WC_COM, %dx
8465295Srandyf	movb        $0x71, %al
8475295Srandyf	outb    (%dx)
8485295Srandyf#endif
8495295Srandyf
8505295Srandyf/*
8515295Srandyf * can not use outb after this point, because doing so would mean using
8525295Srandyf * %dx which would modify %rdx which is restored here
8535295Srandyf */
8545295Srandyf
8555295Srandyf	movq	%rbx, %rax
8565295Srandyf	movq    WC_RDX(%rax), %rdx
8575295Srandyf	movq    WC_RBX(%rax), %rbx
8585295Srandyf
8595295Srandyf	leave
8605295Srandyf
8615295Srandyf	movq	WC_RETADDR(%rax), %rax
8625295Srandyf	movq	%rax, (%rsp)		/ return to caller of wc_save_context
8635295Srandyf
8645295Srandyf	xorl	%eax, %eax			/ at wakeup return 0
8655295Srandyf	ret
8665295Srandyf
8675295Srandyf
8685295Srandyf	SET_SIZE(wc_rm_start)
8695295Srandyf
8705295Srandyf	ENTRY_NP(asmspin)
8715295Srandyf
8725295Srandyf	movl	%edi, %ecx
8735295SrandyfA1:
8745295Srandyf	loop	A1
8755295Srandyf
8765295Srandyf	SET_SIZE(asmspin)
8775295Srandyf
8785295Srandyf	.globl wc_rm_end
8795295Srandyfwc_rm_end:
8805295Srandyf	nop
8815295Srandyf
8825295Srandyf#elif defined(__i386)
8835295Srandyf
8845295Srandyf	ENTRY_NP(wc_rm_start)
8855295Srandyf
8865295Srandyf/entry:	jmp		entry			/ stop here for HDT
8875295Srandyf
8885295Srandyf	cli
8895295Srandyf	movw		%cs, %ax
8905295Srandyf	movw		%ax, %ds		/ establish ds ...
8915295Srandyf	movw		%ax, %ss		/ ... and ss:esp
8925295Srandyf	D16 movl	$WC_STKSTART, %esp
8935295Srandyf
8945295Srandyf#if     LED
8956876Sjan	D16 movl        $WC_LED, %edx
8965295Srandyf	D16 movb        $0xd1, %al
8975295Srandyf	outb    (%dx)
8985295Srandyf#endif
8995295Srandyf
9005295Srandyf#if     SERIAL
9016876Sjan	D16 movl        $WC_COM, %edx
9025295Srandyf	D16 movb        $0x61, %al
9035295Srandyf	outb    (%dx)
9045295Srandyf#endif
9055295Srandyf
9065295Srandyf
9075295Srandyf	D16 call	vgainit
9085295Srandyf	D16 call	kbdinit
9095295Srandyf	D16 call	cominit
9105295Srandyf
9115295Srandyf#if     LED
9126876Sjan	D16 movl        $WC_LED, %edx
9135295Srandyf	D16 movb        $0xd2, %al
9145295Srandyf	outb    (%dx)
9155295Srandyf#endif
9165295Srandyf
9175295Srandyf#if     SERIAL
9186876Sjan	D16 movl        $WC_COM, %edx
9195295Srandyf	D16 movb        $0x62, %al
9205295Srandyf	outb    (%dx)
9215295Srandyf#endif
9225295Srandyf
9235295Srandyf	D16 A16 movl	$WC_CPU, %ebx		/ base add of wc_cpu_t
9245295Srandyf
9255295Srandyf#if     LED
9265295Srandyf	D16 movb        $0xd3, %al
9276876Sjan	outb    $WC_LED
9285295Srandyf#endif
9295295Srandyf
9305295Srandyf#if     SERIAL
9316876Sjan	D16 movl        $WC_COM, %edx
9325295Srandyf	D16 movb        $0x63, %al
9335295Srandyf	outb    (%dx)
9345295Srandyf#endif
9355295Srandyf
9365295Srandyf	D16 A16 movl	%cs:WC_DS(%ebx), %edx	/ %ds post prot/paging transit
9375295Srandyf
9386876Sjan#if     LED
9395295Srandyf	D16 movb        $0xd4, %al
9406876Sjan	outb    $WC_LED
9416876Sjan#endif
9425295Srandyf
9435295Srandyf	D16 A16 lgdt	%cs:WC_GDT(%ebx)	/ restore gdt and idtr
9445295Srandyf	D16 A16 lidt	%cs:WC_IDT(%ebx)
9455295Srandyf
9466876Sjan#if     LED
9475295Srandyf	D16 movb        $0xd5, %al
9486876Sjan	outb    $WC_LED
9496876Sjan#endif
9505295Srandyf
9515295Srandyf	D16 A16 movl	%cs:WC_CR4(%ebx), %eax	/ restore cr4
9525295Srandyf	D16 andl	$-1!CR4_PGE, %eax	/ don't set Global Enable yet
9535295Srandyf	movl		%eax, %cr4
9545295Srandyf
9556876Sjan#if     LED
9565295Srandyf	D16 movb        $0xd6, %al
9576876Sjan	outb    $WC_LED
9586876Sjan#endif
9595295Srandyf
9605295Srandyf	D16 A16 movl	%cs:WC_CR3(%ebx), %eax	/ set PDPT
9615295Srandyf	movl		%eax, %cr3
9625295Srandyf
9636876Sjan#if     LED
9645295Srandyf	D16 movb        $0xd7, %al
9656876Sjan	outb    $WC_LED
9666876Sjan#endif
9675295Srandyf
9685295Srandyf	D16 A16 movl	%cs:WC_CR0(%ebx), %eax	/ enable prot/paging, etc.
9695295Srandyf	movl		%eax, %cr0
9705295Srandyf
9716876Sjan#if     LED
9725295Srandyf	D16 movb        $0xd8, %al
9736876Sjan	outb    $WC_LED
9746876Sjan#endif
9755295Srandyf
9765295Srandyf	D16 A16 movl	%cs:WC_VIRTADDR(%ebx), %ebx	/ virtaddr of wc_cpu_t
9775295Srandyf
9786876Sjan#if     LED
9795295Srandyf	D16 movb        $0xd9, %al
9806876Sjan	outb    $WC_LED
9816876Sjan#endif
9825295Srandyf
9836876Sjan#if     LED
9845295Srandyf	D16 movb        $0xda, %al
9856876Sjan	outb    $WC_LED
9866876Sjan#endif
9876876Sjan
9885295Srandyf	jmp		flush			/ flush prefetch queue
9895295Srandyfflush:
9905295Srandyf	D16 pushl	$KCS_SEL
9915295Srandyf	D16 pushl	$kernel_wc_code
9925295Srandyf	D16 lret				/ re-appear at kernel_wc_code
9935295Srandyf
9945295Srandyf
9955295Srandyf/*
9965295Srandyf * Support routine to re-initialize VGA subsystem
9975295Srandyf */
9985295Srandyfvgainit:
9995295Srandyf	D16 ret
10005295Srandyf
10015295Srandyf/*
10025295Srandyf * Support routine to re-initialize keyboard (which is USB - help!)
10035295Srandyf */
10045295Srandyfkbdinit:
10055295Srandyf	D16 ret
10065295Srandyf
10075295Srandyf/*
10085295Srandyf * Support routine to re-initialize COM ports to something sane for debug output
10095295Srandyf */
10105295Srandyfcominit:
10116876Sjan#if     DEBUG
10126876Sjan/*
10136876Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that
10146876Sjan * we can get debug output before the asy driver has resumed
10156876Sjan */
10166876Sjan
10176876Sjan/ select COM1
10186876Sjan	D16 movl	$[COM1+LCR], %edx
10196876Sjan	D16 movb	$DLAB, %al		/ divisor latch
10206876Sjan	outb	(%dx)
10216876Sjan
10226876Sjan	D16 movl	$[COM1+DLL], %edx	/ divisor latch lsb
10236876Sjan	D16 movb	$B9600L, %al		/ divisor latch
10246876Sjan	outb	(%dx)
10256876Sjan
10266876Sjan	D16 movl	$[COM1+DLH], %edx	/ divisor latch hsb
10276876Sjan	D16 movb	$B9600H, %al		/ divisor latch
10286876Sjan	outb	(%dx)
10296876Sjan
10306876Sjan	D16 movl	$[COM1+LCR], %edx	/ select COM1
10316876Sjan	D16 movb	$[STOP1|BITS8], %al	/ 1 stop bit, 8bit word len
10326876Sjan	outb	(%dx)
10336876Sjan
10346876Sjan	D16 movl	$[COM1+MCR], %edx	/ select COM1
10356876Sjan	D16 movb	$[RTS|DTR], %al		/ 1 stop bit, 8bit word len
10366876Sjan	outb	(%dx)
10376876Sjan
10386876Sjan/ select COM2
10396876Sjan	D16 movl	$[COM2+LCR], %edx
10406876Sjan	D16 movb	$DLAB, %al		/ divisor latch
10416876Sjan	outb	(%dx)
10426876Sjan
10436876Sjan	D16 movl	$[COM2+DLL], %edx	/ divisor latch lsb
10446876Sjan	D16 movb	$B9600L, %al		/ divisor latch
10456876Sjan	outb	(%dx)
10466876Sjan
10476876Sjan	D16 movl	$[COM2+DLH], %edx	/ divisor latch hsb
10486876Sjan	D16 movb	$B9600H, %al		/ divisor latch
10496876Sjan	outb	(%dx)
10506876Sjan
10516876Sjan	D16 movl	$[COM2+LCR], %edx	/ select COM1
10526876Sjan	D16 movb	$[STOP1|BITS8], %al	/ 1 stop bit, 8bit word len
10536876Sjan	outb	(%dx)
10546876Sjan
10556876Sjan	D16 movl	$[COM2+MCR], %edx	/ select COM1
10566876Sjan	D16 movb	$[RTS|DTR], %al		/ 1 stop bit, 8bit word len
10576876Sjan	outb	(%dx)
10586876Sjan#endif	/*	DEBUG	*/
10596876Sjan
10605295Srandyf	D16 ret
10615295Srandyf
10625295Srandyf	.globl wc_rm_end
10635295Srandyfwc_rm_end:
10645295Srandyf	nop
10655295Srandyf
10665295Srandyf	.globl	kernel_wc_code
10675295Srandyfkernel_wc_code:
10685295Srandyf	/ At this point we are with kernel's cs and proper eip.
10695295Srandyf	/ We will be executing not from the copy in real mode platter,
10705295Srandyf	/ but from the original code where boot loaded us.
10715295Srandyf	/ By this time GDT and IDT are loaded as is cr0, cr3 and cr4.
10725295Srandyf	/ %ebx is wc_cpu
10735295Srandyf	/ %dx is our ds
10745295Srandyf
10756876Sjan#if     LED
10765295Srandyf	D16 movb        $0xdb, %al
10776876Sjan	outb	$WC_LED
10786876Sjan#endif
10795295Srandyf
10805295Srandyf/ got here OK
10815295Srandyf
10825295Srandyf	movw	%dx, %ds		/ $KDS_SEL
10836876Sjan
10846876Sjan#if     LED
10855295Srandyf	movb	$0xdc, %al
10866876Sjan	outb	$WC_LED
10876876Sjan#endif
10885295Srandyf
10895817Sjan	/*
10905817Sjan	 * Before proceeding, enable usage of the page table NX bit if
10915817Sjan	 * that's how the page tables are set up.
10925817Sjan	 */
109312826Skuriakose.kuruvilla@oracle.com	bt      $X86FSET_NX, x86_featureset
109412826Skuriakose.kuruvilla@oracle.com	jnc     1f
10955817Sjan	movl    $MSR_AMD_EFER, %ecx
10965295Srandyf	rdmsr
10975817Sjan	orl     $AMD_EFER_NXE, %eax
10985295Srandyf	wrmsr
10995817Sjan1:
11005295Srandyf
11015295Srandyf	movl	WC_CR4(%ebx), %eax	/ restore full cr4 (with Global Enable)
11025295Srandyf	movl	%eax, %cr4
11035295Srandyf
11045295Srandyf
11055295Srandyf	lldt	WC_LDT(%ebx)		/ $LDT_SEL
11065295Srandyf
11075295Srandyf	movzwl	WC_TR(%ebx), %eax	/ clear TSS busy bit
11085295Srandyf	addl	WC_GDT+2(%ebx), %eax
11095295Srandyf	andl	$-1!0x200, 4(%eax)
11105295Srandyf	ltr	WC_TR(%ebx)		/ $UTSS_SEL
11115295Srandyf
11129989SJoseph.Townsend@Sun.COM	movw	WC_SS(%ebx), %ss	/ restore segment registers
11139989SJoseph.Townsend@Sun.COM	movw	WC_ES(%ebx), %es
11149989SJoseph.Townsend@Sun.COM	movw	WC_FS(%ebx), %fs
11159989SJoseph.Townsend@Sun.COM	movw	WC_GS(%ebx), %gs
11169989SJoseph.Townsend@Sun.COM
11179989SJoseph.Townsend@Sun.COM	/*
11189989SJoseph.Townsend@Sun.COM	 * set the stack pointer to point into the identity mapped page
11199989SJoseph.Townsend@Sun.COM	 * temporarily, so we can make function calls
11209989SJoseph.Townsend@Sun.COM	 */
11219989SJoseph.Townsend@Sun.COM	.globl  rm_platter_va
11229989SJoseph.Townsend@Sun.COM	movl    rm_platter_va, %eax
11239989SJoseph.Townsend@Sun.COM	movl	$WC_STKSTART, %esp
11249989SJoseph.Townsend@Sun.COM	addl	%eax, %esp
11259989SJoseph.Townsend@Sun.COM	movl	%esp, %ebp
11269989SJoseph.Townsend@Sun.COM
11279989SJoseph.Townsend@Sun.COM	/*
11289989SJoseph.Townsend@Sun.COM	 * if we are not running on the boot CPU restore stack contents by
11299989SJoseph.Townsend@Sun.COM	 * calling i_cpr_restore_stack(curthread, save_stack);
11309989SJoseph.Townsend@Sun.COM	 */
11319989SJoseph.Townsend@Sun.COM	call	i_cpr_bootcpuid
11329989SJoseph.Townsend@Sun.COM	cmpl	%eax, WC_CPU_ID(%ebx)
11339989SJoseph.Townsend@Sun.COM	je	2f
11349989SJoseph.Townsend@Sun.COM
11359989SJoseph.Townsend@Sun.COM	pushl	WC_SAVED_STACK(%ebx)
11369989SJoseph.Townsend@Sun.COM	pushl	%gs:CPU_THREAD
11379989SJoseph.Townsend@Sun.COM	call	i_cpr_restore_stack
11389989SJoseph.Townsend@Sun.COM	addl	$0x10, %esp
11399989SJoseph.Townsend@Sun.COM2:
11409989SJoseph.Townsend@Sun.COM
11419989SJoseph.Townsend@Sun.COM	movl	WC_ESP(%ebx), %esp
11429989SJoseph.Townsend@Sun.COM	movl	%esp, %ebp
11435295Srandyf
11445295Srandyf	movl	WC_RETADDR(%ebx), %eax	/ return to caller of wc_save_context
11455295Srandyf	movl	%eax, (%esp)
11465295Srandyf
11475295Srandyf	/*
11485817Sjan	 * APIC initialization, skip iff function pointer is NULL
11495295Srandyf	 */
11505817Sjan	cmpl	$0, ap_mlsetup
11519989SJoseph.Townsend@Sun.COM	je	3f
11525817Sjan	call	*ap_mlsetup
11539989SJoseph.Townsend@Sun.COM3:
11545295Srandyf
11555295Srandyf	call    *cpr_start_cpu_func
11565295Srandyf
11575295Srandyf	pushl	WC_EFLAGS(%ebx)		/ restore flags
11585295Srandyf	popfl
11595295Srandyf
11605295Srandyf	movl	WC_EDI(%ebx), %edi	/ restore general registers
11615295Srandyf	movl	WC_ESI(%ebx), %esi
11625295Srandyf	movl	WC_EBP(%ebx), %ebp
11635295Srandyf	movl	WC_EBX(%ebx), %ebx
11645295Srandyf
11655295Srandyf/exit:	jmp	exit			/ stop here for HDT
11665295Srandyf
11675295Srandyf	xorl	%eax, %eax		/ at wakeup return 0
11685295Srandyf	ret
11695295Srandyf
11705295Srandyf	SET_SIZE(wc_rm_start)
11715295Srandyf
11725295Srandyf
11735295Srandyf#endif	/* defined(__amd64) */
11745295Srandyf
11755295Srandyf#endif	/* !defined(__GNU_AS__) */
11765295Srandyf
11775295Srandyf#endif /* lint */
11785295Srandyf
1179