xref: /titanic_51/usr/src/uts/i86pc/ml/cpr_wakecode.s (revision e764248d4606662e466d4ee282fa5ef20e3dc578)
12df1fe9cSrandyf/*
22df1fe9cSrandyf * CDDL HEADER START
32df1fe9cSrandyf *
42df1fe9cSrandyf * The contents of this file are subject to the terms of the
52df1fe9cSrandyf * Common Development and Distribution License (the "License").
62df1fe9cSrandyf * You may not use this file except in compliance with the License.
72df1fe9cSrandyf *
82df1fe9cSrandyf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92df1fe9cSrandyf * or http://www.opensolaris.org/os/licensing.
102df1fe9cSrandyf * See the License for the specific language governing permissions
112df1fe9cSrandyf * and limitations under the License.
122df1fe9cSrandyf *
132df1fe9cSrandyf * When distributing Covered Code, include this CDDL HEADER in each
142df1fe9cSrandyf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152df1fe9cSrandyf * If applicable, add the following below this CDDL HEADER, with the
162df1fe9cSrandyf * fields enclosed by brackets "[]" replaced with your own identifying
172df1fe9cSrandyf * information: Portions Copyright [yyyy] [name of copyright owner]
182df1fe9cSrandyf *
192df1fe9cSrandyf * CDDL HEADER END
202df1fe9cSrandyf */
212df1fe9cSrandyf/*
227417cfdeSKuriakose Kuruvilla * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*e764248dSAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
242df1fe9cSrandyf */
252df1fe9cSrandyf
262df1fe9cSrandyf#include <sys/asm_linkage.h>
272df1fe9cSrandyf#include <sys/asm_misc.h>
282df1fe9cSrandyf#include <sys/regset.h>
292df1fe9cSrandyf#include <sys/privregs.h>
302df1fe9cSrandyf#include <sys/x86_archext.h>
312df1fe9cSrandyf#include <sys/cpr_wakecode.h>
322df1fe9cSrandyf
332df1fe9cSrandyf#if !defined(__lint)
342df1fe9cSrandyf#include <sys/segments.h>
352df1fe9cSrandyf#include "assym.h"
362df1fe9cSrandyf#endif
372df1fe9cSrandyf
381b1c71b2Sjan#ifdef  DEBUG
391b1c71b2Sjan#define LED     1
401b1c71b2Sjan#define SERIAL  1
411b1c71b2Sjan#endif	/*	DEBUG	*/
421b1c71b2Sjan
431b1c71b2Sjan#ifdef	DEBUG
441b1c71b2Sjan#define	COM1	0x3f8
451b1c71b2Sjan#define	COM2	0x2f8
461b1c71b2Sjan#define	WC_COM	COM2	/* either COM1 or COM2			*/
471b1c71b2Sjan#define	WC_LED	0x80    /* diagnostic led port ON motherboard	*/
481b1c71b2Sjan
491b1c71b2Sjan/*
501b1c71b2Sjan * defined as offsets from the data register
511b1c71b2Sjan */
521b1c71b2Sjan#define	DLL	0	/* divisor latch (lsb) */
531b1c71b2Sjan#define	DLH	1	/* divisor latch (msb) */
541b1c71b2Sjan#define	LCR	3	/* line control register		*/
551b1c71b2Sjan#define	MCR	4	/* modem control register		*/
561b1c71b2Sjan
571b1c71b2Sjan
581b1c71b2Sjan#define	DLAB	0x80    /* divisor latch access bit		*/
591b1c71b2Sjan#define	B9600L	0X0c	/* lsb bit pattern for 9600 baud	*/
601b1c71b2Sjan#define	B9600H	0X0	/* hsb bit pattern for 9600 baud	*/
611b1c71b2Sjan#define	DTR	0x01    /* Data Terminal Ready			*/
621b1c71b2Sjan#define	RTS	0x02    /* Request To Send			*/
631b1c71b2Sjan#define	STOP1	0x00	/* 1 stop bit				*/
641b1c71b2Sjan#define	BITS8	0x03    /* 8 bits per char			*/
651b1c71b2Sjan
661b1c71b2Sjan#endif	/*	DEBUG	*/
671b1c71b2Sjan
682df1fe9cSrandyf/*
692df1fe9cSrandyf *	This file contains the low level routines involved in getting
702df1fe9cSrandyf *	into and out of ACPI S3, including those needed for restarting
712df1fe9cSrandyf *	the non-boot cpus.
722df1fe9cSrandyf *
732df1fe9cSrandyf *	Our assumptions:
742df1fe9cSrandyf *
752df1fe9cSrandyf *	Our actions:
762df1fe9cSrandyf *
772df1fe9cSrandyf */
782df1fe9cSrandyf
792df1fe9cSrandyf#if defined(lint) || defined(__lint)
802df1fe9cSrandyf
812df1fe9cSrandyf/*ARGSUSED*/
822df1fe9cSrandyfint
832df1fe9cSrandyfwc_save_context(wc_cpu_t *pcpu)
842df1fe9cSrandyf{ return 0; }
852df1fe9cSrandyf
862df1fe9cSrandyf#else	/* lint */
872df1fe9cSrandyf
882df1fe9cSrandyf#if defined(__amd64)
892df1fe9cSrandyf
902df1fe9cSrandyf	ENTRY_NP(wc_save_context)
912df1fe9cSrandyf
922df1fe9cSrandyf	movq	(%rsp), %rdx		/ return address
932df1fe9cSrandyf	movq	%rdx, WC_RETADDR(%rdi)
942df1fe9cSrandyf	pushq	%rbp
952df1fe9cSrandyf	movq	%rsp,%rbp
962df1fe9cSrandyf
972df1fe9cSrandyf	movq    %rdi, WC_VIRTADDR(%rdi)
982df1fe9cSrandyf	movq    %rdi, WC_RDI(%rdi)
992df1fe9cSrandyf
1002df1fe9cSrandyf	movq    %rdx, WC_RDX(%rdi)
1012df1fe9cSrandyf
1022df1fe9cSrandyf/ stash everything else we need
1032df1fe9cSrandyf	sgdt	WC_GDT(%rdi)
1042df1fe9cSrandyf	sidt	WC_IDT(%rdi)
1052df1fe9cSrandyf	sldt	WC_LDT(%rdi)
1062df1fe9cSrandyf	str	WC_TR(%rdi)
1072df1fe9cSrandyf
1082df1fe9cSrandyf	movq	%cr0, %rdx
1092df1fe9cSrandyf	movq	%rdx, WC_CR0(%rdi)
1102df1fe9cSrandyf	movq	%cr3, %rdx
1112df1fe9cSrandyf	movq	%rdx, WC_CR3(%rdi)
1122df1fe9cSrandyf	movq	%cr4, %rdx
1132df1fe9cSrandyf	movq	%rdx, WC_CR4(%rdi)
1142df1fe9cSrandyf	movq	%cr8, %rdx
1152df1fe9cSrandyf	movq	%rdx, WC_CR8(%rdi)
1162df1fe9cSrandyf
1172df1fe9cSrandyf	movq    %r8, WC_R8(%rdi)
1182df1fe9cSrandyf	movq    %r9, WC_R9(%rdi)
1192df1fe9cSrandyf	movq    %r10, WC_R10(%rdi)
1202df1fe9cSrandyf	movq    %r11, WC_R11(%rdi)
1212df1fe9cSrandyf	movq    %r12, WC_R12(%rdi)
1222df1fe9cSrandyf	movq    %r13, WC_R13(%rdi)
1232df1fe9cSrandyf	movq    %r14, WC_R14(%rdi)
1242df1fe9cSrandyf	movq    %r15, WC_R15(%rdi)
1252df1fe9cSrandyf	movq    %rax, WC_RAX(%rdi)
1262df1fe9cSrandyf	movq    %rbp, WC_RBP(%rdi)
1272df1fe9cSrandyf	movq    %rbx, WC_RBX(%rdi)
1282df1fe9cSrandyf	movq    %rcx, WC_RCX(%rdi)
1292df1fe9cSrandyf	movq    %rsi, WC_RSI(%rdi)
1302df1fe9cSrandyf	movq    %rsp, WC_RSP(%rdi)
1312df1fe9cSrandyf
1322df1fe9cSrandyf	movw	%ss, WC_SS(%rdi)
1332df1fe9cSrandyf	movw	%cs, WC_CS(%rdi)
1342df1fe9cSrandyf	movw	%ds, WC_DS(%rdi)
1352df1fe9cSrandyf	movw	%es, WC_ES(%rdi)
1362df1fe9cSrandyf
1372df1fe9cSrandyf	movq	$0, %rcx		/ save %fs register
1382df1fe9cSrandyf	movw    %fs, %cx
1392df1fe9cSrandyf	movq    %rcx, WC_FS(%rdi)
1402df1fe9cSrandyf
1412df1fe9cSrandyf	movl    $MSR_AMD_FSBASE, %ecx
1422df1fe9cSrandyf	rdmsr
1432df1fe9cSrandyf	movl    %eax, WC_FSBASE(%rdi)
1442df1fe9cSrandyf	movl    %edx, WC_FSBASE+4(%rdi)
1452df1fe9cSrandyf
1462df1fe9cSrandyf	movq	$0, %rcx		/ save %gs register
1472df1fe9cSrandyf	movw    %gs, %cx
1482df1fe9cSrandyf	movq    %rcx, WC_GS(%rdi)
1492df1fe9cSrandyf
1502df1fe9cSrandyf	movl    $MSR_AMD_GSBASE, %ecx	/ save gsbase msr
1512df1fe9cSrandyf	rdmsr
1522df1fe9cSrandyf	movl    %eax, WC_GSBASE(%rdi)
1532df1fe9cSrandyf	movl    %edx, WC_GSBASE+4(%rdi)
1542df1fe9cSrandyf
1552df1fe9cSrandyf	movl    $MSR_AMD_KGSBASE, %ecx	/ save kgsbase msr
1562df1fe9cSrandyf	rdmsr
1572df1fe9cSrandyf	movl    %eax, WC_KGSBASE(%rdi)
1582df1fe9cSrandyf	movl    %edx, WC_KGSBASE+4(%rdi)
1592df1fe9cSrandyf
1603d995820SJoseph A Townsend	movq	%gs:CPU_ID, %rax	/ save current cpu id
1613d995820SJoseph A Townsend	movq	%rax, WC_CPU_ID(%rdi)
1623d995820SJoseph A Townsend
1632df1fe9cSrandyf	pushfq
1642df1fe9cSrandyf	popq	WC_EFLAGS(%rdi)
1652df1fe9cSrandyf
1662df1fe9cSrandyf	wbinvd				/ flush the cache
1673d995820SJoseph A Townsend	mfence
1682df1fe9cSrandyf
1692df1fe9cSrandyf	movq	$1, %rax		/ at suspend return 1
1702df1fe9cSrandyf
1712df1fe9cSrandyf	leave
1722df1fe9cSrandyf
1732df1fe9cSrandyf	ret
1742df1fe9cSrandyf
1752df1fe9cSrandyf	SET_SIZE(wc_save_context)
1762df1fe9cSrandyf
1772df1fe9cSrandyf#elif defined(__i386)
1782df1fe9cSrandyf
1792df1fe9cSrandyf	ENTRY_NP(wc_save_context)
1802df1fe9cSrandyf
1812df1fe9cSrandyf	movl	4(%esp), %eax		/ wc_cpu_t *
1822df1fe9cSrandyf	movl	%eax, WC_VIRTADDR(%eax)
1832df1fe9cSrandyf
1842df1fe9cSrandyf	movl	(%esp), %edx		/ return address
1852df1fe9cSrandyf	movl	%edx, WC_RETADDR(%eax)
1862df1fe9cSrandyf
1872df1fe9cSrandyf	str	WC_TR(%eax)		/ stash everything else we need
1882df1fe9cSrandyf	sgdt	WC_GDT(%eax)
1892df1fe9cSrandyf	sldt	WC_LDT(%eax)
1902df1fe9cSrandyf	sidt	WC_IDT(%eax)
1912df1fe9cSrandyf
1922df1fe9cSrandyf	movl	%cr0, %edx
1932df1fe9cSrandyf	movl	%edx, WC_CR0(%eax)
1942df1fe9cSrandyf	movl	%cr3, %edx
1952df1fe9cSrandyf	movl	%edx, WC_CR3(%eax)
1962df1fe9cSrandyf	movl	%cr4, %edx
1972df1fe9cSrandyf	movl	%edx, WC_CR4(%eax)
1982df1fe9cSrandyf
1992df1fe9cSrandyf	movl	%ebx, WC_EBX(%eax)
2002df1fe9cSrandyf	movl	%edi, WC_EDI(%eax)
2012df1fe9cSrandyf	movl	%esi, WC_ESI(%eax)
2022df1fe9cSrandyf	movl	%ebp, WC_EBP(%eax)
2032df1fe9cSrandyf	movl	%esp, WC_ESP(%eax)
2042df1fe9cSrandyf
2052df1fe9cSrandyf	movw	%ss, WC_SS(%eax)
2062df1fe9cSrandyf	movw	%cs, WC_CS(%eax)
2072df1fe9cSrandyf	movw	%ds, WC_DS(%eax)
2082df1fe9cSrandyf	movw	%es, WC_ES(%eax)
2092df1fe9cSrandyf	movw	%fs, WC_FS(%eax)
2102df1fe9cSrandyf	movw	%gs, WC_GS(%eax)
2112df1fe9cSrandyf
2122df1fe9cSrandyf	pushfl
2132df1fe9cSrandyf	popl	WC_EFLAGS(%eax)
2142df1fe9cSrandyf
2153d995820SJoseph A Townsend	pushl	%gs:CPU_ID		/ save current cpu id
2163d995820SJoseph A Townsend	popl	WC_CPU_ID(%eax)
2173d995820SJoseph A Townsend
2182df1fe9cSrandyf	wbinvd				/ flush the cache
2193d995820SJoseph A Townsend	mfence
2202df1fe9cSrandyf
2212df1fe9cSrandyf	movl	$1, %eax		/ at suspend return 1
2222df1fe9cSrandyf	ret
2232df1fe9cSrandyf
2242df1fe9cSrandyf	SET_SIZE(wc_save_context)
2252df1fe9cSrandyf
2262df1fe9cSrandyf#endif	/* __amd64 */
2272df1fe9cSrandyf
2282df1fe9cSrandyf#endif /* lint */
2292df1fe9cSrandyf
2302df1fe9cSrandyf
2312df1fe9cSrandyf/*
2322df1fe9cSrandyf *	Our assumptions:
2332df1fe9cSrandyf *		- We are running in real mode.
2342df1fe9cSrandyf *		- Interrupts are disabled.
2352df1fe9cSrandyf *
2362df1fe9cSrandyf *	Our actions:
2372df1fe9cSrandyf *		- We start using our GDT by loading correct values in the
2382df1fe9cSrandyf *		  selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL,
2392df1fe9cSrandyf *		  gs=KGS_SEL).
2402df1fe9cSrandyf *		- We change over to using our IDT.
2412df1fe9cSrandyf *		- We load the default LDT into the hardware LDT register.
2422df1fe9cSrandyf *		- We load the default TSS into the hardware task register.
2432df1fe9cSrandyf *		- We restore registers
2442df1fe9cSrandyf *		- We return to original caller (a la setjmp)
2452df1fe9cSrandyf */
2462df1fe9cSrandyf
2472df1fe9cSrandyf#if defined(lint) || defined(__lint)
2482df1fe9cSrandyf
2492df1fe9cSrandyfvoid
2502df1fe9cSrandyfwc_rm_start(void)
2512df1fe9cSrandyf{}
2522df1fe9cSrandyf
2532df1fe9cSrandyfvoid
2542df1fe9cSrandyfwc_rm_end(void)
2552df1fe9cSrandyf{}
2562df1fe9cSrandyf
2572df1fe9cSrandyf#else	/* lint */
2582df1fe9cSrandyf
2592df1fe9cSrandyf#if defined(__amd64)
2602df1fe9cSrandyf
2612df1fe9cSrandyf	ENTRY_NP(wc_rm_start)
2622df1fe9cSrandyf
2632df1fe9cSrandyf	/*
264dad25528SRichard Lowe	 * For the Sun Studio 10 assembler we needed to do a .code32 and
265dad25528SRichard Lowe	 * mentally invert the meaning of the addr16 and data16 prefixes to
266dad25528SRichard Lowe	 * get 32-bit access when generating code to be executed in 16-bit
267dad25528SRichard Lowe	 * mode (sigh...)
268dad25528SRichard Lowe	 *
269dad25528SRichard Lowe	 * This code, despite always being built with GNU as, has inherited
270dad25528SRichard Lowe	 * the conceptual damage.
2712df1fe9cSrandyf	 */
2722df1fe9cSrandyf
2732df1fe9cSrandyf	.code32
2742df1fe9cSrandyf
2752df1fe9cSrandyf	cli
2762df1fe9cSrandyf	movw		%cs, %ax
2772df1fe9cSrandyf	movw		%ax, %ds		/ establish ds ...
2782df1fe9cSrandyf	movw		%ax, %ss		/ ... and ss:esp
2792df1fe9cSrandyf	D16 movl	$WC_STKSTART, %esp
2802df1fe9cSrandyf/ using the following value blows up machines! - DO NOT USE
2812df1fe9cSrandyf/	D16 movl	0xffc, %esp
2822df1fe9cSrandyf
2832df1fe9cSrandyf
2842df1fe9cSrandyf#if     LED
2851b1c71b2Sjan	D16 movl        $WC_LED, %edx
2862df1fe9cSrandyf	D16 movb        $0xd1, %al
2872df1fe9cSrandyf	outb    (%dx)
2882df1fe9cSrandyf#endif
2892df1fe9cSrandyf
2902df1fe9cSrandyf#if     SERIAL
2911b1c71b2Sjan	D16 movl        $WC_COM, %edx
2922df1fe9cSrandyf	D16 movb        $0x61, %al
2932df1fe9cSrandyf	outb    (%dx)
2942df1fe9cSrandyf#endif
2952df1fe9cSrandyf
2962df1fe9cSrandyf	D16 call	cominit
2972df1fe9cSrandyf
2982df1fe9cSrandyf	/*
2992df1fe9cSrandyf	 * Enable protected-mode, write protect, and alignment mask
3002df1fe9cSrandyf	 * %cr0 has already been initialsed to zero
3012df1fe9cSrandyf	 */
3022df1fe9cSrandyf	movl		%cr0, %eax
303dad25528SRichard Lowe	D16 orl		$_CONST(CR0_PE|CR0_WP|CR0_AM), %eax
3042df1fe9cSrandyf	movl		%eax, %cr0
3052df1fe9cSrandyf
3062df1fe9cSrandyf	/*
3072df1fe9cSrandyf	 * Do a jmp immediately after writing to cr0 when enabling protected
3082df1fe9cSrandyf	 * mode to clear the real mode prefetch queue (per Intel's docs)
3092df1fe9cSrandyf	 */
3102df1fe9cSrandyf	jmp		pestart
3112df1fe9cSrandyfpestart:
3122df1fe9cSrandyf
3132df1fe9cSrandyf#if     LED
3141b1c71b2Sjan	D16 movl        $WC_LED, %edx
3152df1fe9cSrandyf	D16 movb        $0xd2, %al
3162df1fe9cSrandyf	outb    (%dx)
3172df1fe9cSrandyf#endif
3182df1fe9cSrandyf
3192df1fe9cSrandyf#if     SERIAL
3201b1c71b2Sjan	D16 movl        $WC_COM, %edx
3212df1fe9cSrandyf	D16 movb        $0x62, %al
3222df1fe9cSrandyf	outb    (%dx)
3232df1fe9cSrandyf#endif
3242df1fe9cSrandyf
3252df1fe9cSrandyf	/*
3262df1fe9cSrandyf	 * 16-bit protected mode is now active, so prepare to turn on long
3272df1fe9cSrandyf	 * mode
3282df1fe9cSrandyf	 */
3292df1fe9cSrandyf
3302df1fe9cSrandyf#if     LED
3311b1c71b2Sjan	D16 movl        $WC_LED, %edx
3322df1fe9cSrandyf	D16 movb        $0xd3, %al
3332df1fe9cSrandyf	outb    (%dx)
3342df1fe9cSrandyf#endif
3352df1fe9cSrandyf
3362df1fe9cSrandyf#if     SERIAL
3371b1c71b2Sjan	D16 movl        $WC_COM, %edx
3382df1fe9cSrandyf	D16 movb        $0x63, %al
3392df1fe9cSrandyf	outb    (%dx)
3402df1fe9cSrandyf#endif
3412df1fe9cSrandyf
3422df1fe9cSrandyf	/*
3432df1fe9cSrandyf 	 * Add any initial cr4 bits
3442df1fe9cSrandyf	 */
3452df1fe9cSrandyf	movl		%cr4, %eax
3462df1fe9cSrandyf	A16 D16 orl	CR4OFF, %eax
3472df1fe9cSrandyf
3482df1fe9cSrandyf	/*
3492df1fe9cSrandyf	 * Enable PAE mode (CR4.PAE)
3502df1fe9cSrandyf	 */
3512df1fe9cSrandyf	D16 orl		$CR4_PAE, %eax
3522df1fe9cSrandyf	movl		%eax, %cr4
3532df1fe9cSrandyf
3542df1fe9cSrandyf#if     LED
3551b1c71b2Sjan	D16 movl        $WC_LED, %edx
3562df1fe9cSrandyf	D16 movb        $0xd4, %al
3572df1fe9cSrandyf	outb    (%dx)
3582df1fe9cSrandyf#endif
3592df1fe9cSrandyf
3602df1fe9cSrandyf#if     SERIAL
3611b1c71b2Sjan	D16 movl        $WC_COM, %edx
3622df1fe9cSrandyf	D16 movb        $0x64, %al
3632df1fe9cSrandyf	outb    (%dx)
3642df1fe9cSrandyf#endif
3652df1fe9cSrandyf
3662df1fe9cSrandyf	/*
3672df1fe9cSrandyf	 * Point cr3 to the 64-bit long mode page tables.
3682df1fe9cSrandyf	 *
3692df1fe9cSrandyf	 * Note that these MUST exist in 32-bit space, as we don't have
3702df1fe9cSrandyf	 * a way to load %cr3 with a 64-bit base address for the page tables
3712df1fe9cSrandyf	 * until the CPU is actually executing in 64-bit long mode.
3722df1fe9cSrandyf	 */
3732df1fe9cSrandyf	A16 D16 movl	CR3OFF, %eax
3742df1fe9cSrandyf	movl		%eax, %cr3
3752df1fe9cSrandyf
3762df1fe9cSrandyf	/*
3772df1fe9cSrandyf	 * Set long mode enable in EFER (EFER.LME = 1)
3782df1fe9cSrandyf	 */
3792df1fe9cSrandyf	D16 movl	$MSR_AMD_EFER, %ecx
3802df1fe9cSrandyf	rdmsr
3812df1fe9cSrandyf
3822df1fe9cSrandyf	D16 orl		$AMD_EFER_LME, %eax
3832df1fe9cSrandyf	wrmsr
3842df1fe9cSrandyf
3852df1fe9cSrandyf#if     LED
3861b1c71b2Sjan	D16 movl        $WC_LED, %edx
3872df1fe9cSrandyf	D16 movb        $0xd5, %al
3882df1fe9cSrandyf	outb    (%dx)
3892df1fe9cSrandyf#endif
3902df1fe9cSrandyf
3912df1fe9cSrandyf#if     SERIAL
3921b1c71b2Sjan	D16 movl        $WC_COM, %edx
3932df1fe9cSrandyf	D16 movb        $0x65, %al
3942df1fe9cSrandyf	outb    (%dx)
3952df1fe9cSrandyf#endif
3962df1fe9cSrandyf
3972df1fe9cSrandyf	/*
3982df1fe9cSrandyf	 * Finally, turn on paging (CR0.PG = 1) to activate long mode.
3992df1fe9cSrandyf	 */
4002df1fe9cSrandyf	movl		%cr0, %eax
4012df1fe9cSrandyf	D16 orl		$CR0_PG, %eax
4022df1fe9cSrandyf	movl		%eax, %cr0
4032df1fe9cSrandyf
4042df1fe9cSrandyf	/*
4052df1fe9cSrandyf	 * The instruction after enabling paging in CR0 MUST be a branch.
4062df1fe9cSrandyf	 */
4072df1fe9cSrandyf	jmp		long_mode_active
4082df1fe9cSrandyf
4092df1fe9cSrandyflong_mode_active:
4102df1fe9cSrandyf
4112df1fe9cSrandyf#if     LED
4121b1c71b2Sjan	D16 movl        $WC_LED, %edx
4132df1fe9cSrandyf	D16 movb        $0xd6, %al
4142df1fe9cSrandyf	outb    (%dx)
4152df1fe9cSrandyf#endif
4162df1fe9cSrandyf
4172df1fe9cSrandyf#if     SERIAL
4181b1c71b2Sjan	D16 movl        $WC_COM, %edx
4192df1fe9cSrandyf	D16 movb        $0x66, %al
4202df1fe9cSrandyf	outb    (%dx)
4212df1fe9cSrandyf#endif
4222df1fe9cSrandyf
4232df1fe9cSrandyf	/*
4242df1fe9cSrandyf	 * Long mode is now active but since we're still running with the
4252df1fe9cSrandyf	 * original 16-bit CS we're actually in 16-bit compatability mode.
4262df1fe9cSrandyf	 *
4272df1fe9cSrandyf	 * We have to load an intermediate GDT and IDT here that we know are
4282df1fe9cSrandyf	 * in 32-bit space before we can use the kernel's GDT and IDT, which
4292df1fe9cSrandyf	 * may be in the 64-bit address space, and since we're in compatability
4302df1fe9cSrandyf	 * mode, we only have access to 16 and 32-bit instructions at the
4312df1fe9cSrandyf	 * moment.
4322df1fe9cSrandyf	 */
4332df1fe9cSrandyf	A16 D16 lgdt	TEMPGDTOFF	/* load temporary GDT */
4342df1fe9cSrandyf	A16 D16 lidt	TEMPIDTOFF	/* load temporary IDT */
4352df1fe9cSrandyf
4362df1fe9cSrandyf
4372df1fe9cSrandyf	/*
4382df1fe9cSrandyf 	 * Do a far transfer to 64-bit mode.  Set the CS selector to a 64-bit
4392df1fe9cSrandyf	 * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump
4402df1fe9cSrandyf	 * to the real mode platter address of wc_long_mode_64 as until the
4412df1fe9cSrandyf	 * 64-bit CS is in place we don't have access to 64-bit instructions
4422df1fe9cSrandyf	 * and thus can't reference a 64-bit %rip.
4432df1fe9cSrandyf	 */
4442df1fe9cSrandyf
4452df1fe9cSrandyf#if     LED
4461b1c71b2Sjan	D16 movl        $WC_LED, %edx
4472df1fe9cSrandyf	D16 movb        $0xd7, %al
4482df1fe9cSrandyf	outb    (%dx)
4492df1fe9cSrandyf#endif
4502df1fe9cSrandyf
4512df1fe9cSrandyf#if     SERIAL
4521b1c71b2Sjan	D16 movl        $WC_COM, %edx
4532df1fe9cSrandyf	D16 movb        $0x67, %al
4542df1fe9cSrandyf	outb    (%dx)
4552df1fe9cSrandyf#endif
4562df1fe9cSrandyf
4572df1fe9cSrandyf	D16 	pushl 	$TEMP_CS64_SEL
4582df1fe9cSrandyf	A16 D16 pushl	LM64OFF
4592df1fe9cSrandyf
4602df1fe9cSrandyf	D16 lret
4612df1fe9cSrandyf
4622df1fe9cSrandyf
4632df1fe9cSrandyf/*
4642df1fe9cSrandyf * Support routine to re-initialize VGA subsystem
4652df1fe9cSrandyf */
4662df1fe9cSrandyfvgainit:
4672df1fe9cSrandyf	D16 ret
4682df1fe9cSrandyf
4692df1fe9cSrandyf/*
4702df1fe9cSrandyf * Support routine to re-initialize keyboard (which is USB - help!)
4712df1fe9cSrandyf */
4722df1fe9cSrandyfkbdinit:
4732df1fe9cSrandyf	D16 ret
4742df1fe9cSrandyf
4752df1fe9cSrandyf/*
4762df1fe9cSrandyf * Support routine to re-initialize COM ports to something sane
4772df1fe9cSrandyf */
4782df1fe9cSrandyfcominit:
4792df1fe9cSrandyf	/ init COM1 & COM2
4801b1c71b2Sjan
4811b1c71b2Sjan#if     DEBUG
4821b1c71b2Sjan/*
4831b1c71b2Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that
4841b1c71b2Sjan * we can get debug output before the asy driver has resumed
4851b1c71b2Sjan */
4861b1c71b2Sjan
4871b1c71b2Sjan/ select COM1
488dad25528SRichard Lowe	D16 movl	$_CONST(COM1+LCR), %edx
4891b1c71b2Sjan	D16 movb	$DLAB, %al		/ divisor latch
4901b1c71b2Sjan	outb	(%dx)
4911b1c71b2Sjan
492dad25528SRichard Lowe	D16 movl	$_CONST(COM1+DLL), %edx	/ divisor latch lsb
4931b1c71b2Sjan	D16 movb	$B9600L, %al		/ divisor latch
4941b1c71b2Sjan	outb	(%dx)
4951b1c71b2Sjan
496dad25528SRichard Lowe	D16 movl	$_CONST(COM1+DLH), %edx	/ divisor latch hsb
4971b1c71b2Sjan	D16 movb	$B9600H, %al		/ divisor latch
4981b1c71b2Sjan	outb	(%dx)
4991b1c71b2Sjan
500dad25528SRichard Lowe	D16 movl	$_CONST(COM1+LCR), %edx	/ select COM1
501dad25528SRichard Lowe	D16 movb	$_CONST(STOP1|BITS8), %al	/ 1 stop bit, 8bit word len
5021b1c71b2Sjan	outb	(%dx)
5031b1c71b2Sjan
504dad25528SRichard Lowe	D16 movl	$_CONST(COM1+MCR), %edx	/ select COM1
505dad25528SRichard Lowe	D16 movb	$_CONST(RTS|DTR), %al		/ data term ready & req to send
5061b1c71b2Sjan	outb	(%dx)
5071b1c71b2Sjan
5081b1c71b2Sjan/ select COM2
509dad25528SRichard Lowe	D16 movl	$_CONST(COM2+LCR), %edx
5101b1c71b2Sjan	D16 movb	$DLAB, %al		/ divisor latch
5111b1c71b2Sjan	outb	(%dx)
5121b1c71b2Sjan
513dad25528SRichard Lowe	D16 movl	$_CONST(COM2+DLL), %edx	/ divisor latch lsb
5141b1c71b2Sjan	D16 movb	$B9600L, %al		/ divisor latch
5151b1c71b2Sjan	outb	(%dx)
5161b1c71b2Sjan
517dad25528SRichard Lowe	D16 movl	$_CONST(COM2+DLH), %edx	/ divisor latch hsb
5181b1c71b2Sjan	D16 movb	$B9600H, %al		/ divisor latch
5191b1c71b2Sjan	outb	(%dx)
5201b1c71b2Sjan
521dad25528SRichard Lowe	D16 movl	$_CONST(COM2+LCR), %edx	/ select COM1
522dad25528SRichard Lowe	D16 movb	$_CONST(STOP1|BITS8), %al	/ 1 stop bit, 8bit word len
5231b1c71b2Sjan	outb	(%dx)
5241b1c71b2Sjan
525dad25528SRichard Lowe	D16 movl	$_CONST(COM2+MCR), %edx	/ select COM1
526dad25528SRichard Lowe	D16 movb	$_CONST(RTS|DTR), %al		/ data term ready & req to send
5271b1c71b2Sjan	outb	(%dx)
5281b1c71b2Sjan#endif	/*	DEBUG	*/
5291b1c71b2Sjan
5302df1fe9cSrandyf	D16 ret
5312df1fe9cSrandyf
5322df1fe9cSrandyf	.code64
5332df1fe9cSrandyf
5342df1fe9cSrandyf	.globl wc_long_mode_64
5352df1fe9cSrandyfwc_long_mode_64:
5362df1fe9cSrandyf
5372df1fe9cSrandyf#if     LED
5381b1c71b2Sjan	movw        $WC_LED, %dx
5392df1fe9cSrandyf	movb        $0xd8, %al
5402df1fe9cSrandyf	outb    (%dx)
5412df1fe9cSrandyf#endif
5422df1fe9cSrandyf
5432df1fe9cSrandyf#if     SERIAL
5441b1c71b2Sjan	movw        $WC_COM, %dx
5452df1fe9cSrandyf	movb        $0x68, %al
5462df1fe9cSrandyf	outb    (%dx)
5472df1fe9cSrandyf#endif
5482df1fe9cSrandyf
5492df1fe9cSrandyf	/*
5502df1fe9cSrandyf	 * We are now running in long mode with a 64-bit CS (EFER.LMA=1,
5512df1fe9cSrandyf	 * CS.L=1) so we now have access to 64-bit instructions.
5522df1fe9cSrandyf	 *
5532df1fe9cSrandyf	 * First, set the 64-bit GDT base.
5542df1fe9cSrandyf	 */
5552df1fe9cSrandyf	.globl	rm_platter_pa
5562df1fe9cSrandyf	movl	rm_platter_pa, %eax
5572df1fe9cSrandyf
5582df1fe9cSrandyf	lgdtq	GDTROFF(%rax)		/* load 64-bit GDT */
5592df1fe9cSrandyf
5602df1fe9cSrandyf	/*
5612df1fe9cSrandyf	 * Save the CPU number in %r11; get the value here since it's saved in
5622df1fe9cSrandyf	 * the real mode platter.
5632df1fe9cSrandyf	 */
5642df1fe9cSrandyf/ JAN
5652df1fe9cSrandyf/ the following is wrong! need to figure out MP systems
5662df1fe9cSrandyf/	movl	CPUNOFF(%rax), %r11d
5672df1fe9cSrandyf
5682df1fe9cSrandyf	/*
5692df1fe9cSrandyf	 * Add rm_platter_pa to %rsp to point it to the same location as seen
5702df1fe9cSrandyf	 * from 64-bit mode.
5712df1fe9cSrandyf	 */
5722df1fe9cSrandyf	addq	%rax, %rsp
5732df1fe9cSrandyf
5742df1fe9cSrandyf	/*
5752df1fe9cSrandyf	 * Now do an lretq to load CS with the appropriate selector for the
5762df1fe9cSrandyf	 * kernel's 64-bit GDT and to start executing 64-bit setup code at the
5772df1fe9cSrandyf	 * virtual address where boot originally loaded this code rather than
5782df1fe9cSrandyf	 * the copy in the real mode platter's rm_code array as we've been
5792df1fe9cSrandyf	 * doing so far.
5802df1fe9cSrandyf	 */
5812df1fe9cSrandyf
5822df1fe9cSrandyf#if     LED
5831b1c71b2Sjan	movw        $WC_LED, %dx
5842df1fe9cSrandyf	movb        $0xd9, %al
5852df1fe9cSrandyf	outb    (%dx)
5862df1fe9cSrandyf#endif
5872df1fe9cSrandyf
5882df1fe9cSrandyf/ JAN this should produce 'i' but we get 'g' instead ???
5892df1fe9cSrandyf#if     SERIAL
5901b1c71b2Sjan	movw        $WC_COM, %dx
5912df1fe9cSrandyf	movb        $0x69, %al
5922df1fe9cSrandyf	outb    (%dx)
5932df1fe9cSrandyf#endif
5942df1fe9cSrandyf
5952df1fe9cSrandyf	pushq	$KCS_SEL
5962df1fe9cSrandyf	pushq	$kernel_wc_code
5972df1fe9cSrandyf	lretq
5982df1fe9cSrandyf
5992df1fe9cSrandyf	.globl kernel_wc_code
6002df1fe9cSrandyfkernel_wc_code:
6012df1fe9cSrandyf
6022df1fe9cSrandyf#if     LED
6031b1c71b2Sjan	movw        $WC_LED, %dx
6042df1fe9cSrandyf	movb        $0xda, %al
6052df1fe9cSrandyf	outb    (%dx)
6062df1fe9cSrandyf#endif
6072df1fe9cSrandyf
6082df1fe9cSrandyf/ JAN this should produce 'j' but we get 'g' instead ???
6092df1fe9cSrandyf#if     SERIAL
6101b1c71b2Sjan	movw        $WC_COM, %dx
6112df1fe9cSrandyf	movb        $0x6a, %al
6122df1fe9cSrandyf	outb    (%dx)
6132df1fe9cSrandyf#endif
6142df1fe9cSrandyf
6152df1fe9cSrandyf	/*
6162df1fe9cSrandyf	 * Complete the balance of the setup we need to before executing
6172df1fe9cSrandyf	 * 64-bit kernel code (namely init rsp, TSS, LGDT, FS and GS).
6182df1fe9cSrandyf	 */
6192df1fe9cSrandyf	.globl  rm_platter_va
6202df1fe9cSrandyf	movq    rm_platter_va, %rbx
6212df1fe9cSrandyf	addq	$WC_CPU, %rbx
6222df1fe9cSrandyf
6232df1fe9cSrandyf#if     LED
6241b1c71b2Sjan	movw        $WC_LED, %dx
6252df1fe9cSrandyf	movb        $0xdb, %al
6262df1fe9cSrandyf	outb    (%dx)
6272df1fe9cSrandyf#endif
6282df1fe9cSrandyf
6292df1fe9cSrandyf#if     SERIAL
6301b1c71b2Sjan	movw        $WC_COM, %dx
6312df1fe9cSrandyf	movw        $0x6b, %ax
6322df1fe9cSrandyf	outb    (%dx)
6332df1fe9cSrandyf#endif
6342df1fe9cSrandyf
6352df1fe9cSrandyf	/*
6362df1fe9cSrandyf	 * restore the rest of the registers
6372df1fe9cSrandyf	 */
6382df1fe9cSrandyf
6392df1fe9cSrandyf	lidtq	WC_IDT(%rbx)
6402df1fe9cSrandyf
6412df1fe9cSrandyf#if     LED
6421b1c71b2Sjan	movw        $WC_LED, %dx
6432df1fe9cSrandyf	movb        $0xdc, %al
6442df1fe9cSrandyf	outb    (%dx)
6452df1fe9cSrandyf#endif
6462df1fe9cSrandyf
6472df1fe9cSrandyf#if     SERIAL
6481b1c71b2Sjan	movw        $WC_COM, %dx
6492df1fe9cSrandyf	movw        $0x6c, %ax
6502df1fe9cSrandyf	outb    (%dx)
6512df1fe9cSrandyf#endif
6522df1fe9cSrandyf
6532df1fe9cSrandyf	/*
6542df1fe9cSrandyf	 * restore the rest of the registers
6552df1fe9cSrandyf	 */
6562df1fe9cSrandyf
6572df1fe9cSrandyf	movw    $KDS_SEL, %ax
6582df1fe9cSrandyf	movw    %ax, %ds
6592df1fe9cSrandyf	movw    %ax, %es
6602df1fe9cSrandyf	movw    %ax, %ss
6612df1fe9cSrandyf
6622df1fe9cSrandyf	/*
6632df1fe9cSrandyf	 * Before proceeding, enable usage of the page table NX bit if
6642df1fe9cSrandyf	 * that's how the page tables are set up.
6652df1fe9cSrandyf	 */
666*e764248dSAndy Fiddaman	btl     $X86FSET_NX, x86_featureset(%rip)
6677417cfdeSKuriakose Kuruvilla	jnc     1f
6682df1fe9cSrandyf	movl    $MSR_AMD_EFER, %ecx
6692df1fe9cSrandyf	rdmsr
6702df1fe9cSrandyf	orl     $AMD_EFER_NXE, %eax
6712df1fe9cSrandyf	wrmsr
6722df1fe9cSrandyf1:
6732df1fe9cSrandyf
6742df1fe9cSrandyf	movq	WC_CR4(%rbx), %rax	/ restore full cr4 (with Global Enable)
6752df1fe9cSrandyf	movq	%rax, %cr4
6762df1fe9cSrandyf
6772df1fe9cSrandyf	lldt	WC_LDT(%rbx)
6782df1fe9cSrandyf	movzwq	WC_TR(%rbx), %rax	/ clear TSS busy bit
6792df1fe9cSrandyf	addq	WC_GDT+2(%rbx), %rax
6802df1fe9cSrandyf	andl	$0xfffffdff, 4(%rax)
6812df1fe9cSrandyf	movq	4(%rax), %rcx
6822df1fe9cSrandyf	ltr	WC_TR(%rbx)
6832df1fe9cSrandyf
6842df1fe9cSrandyf#if     LED
6851b1c71b2Sjan	movw        $WC_LED, %dx
6862df1fe9cSrandyf	movb        $0xdd, %al
6872df1fe9cSrandyf	outb    (%dx)
6882df1fe9cSrandyf#endif
6892df1fe9cSrandyf
6902df1fe9cSrandyf#if     SERIAL
6911b1c71b2Sjan	movw        $WC_COM, %dx
6922df1fe9cSrandyf	movw        $0x6d, %ax
6932df1fe9cSrandyf	outb    (%dx)
6942df1fe9cSrandyf#endif
6952df1fe9cSrandyf
6962df1fe9cSrandyf/ restore %fsbase %gsbase %kgbase registers using wrmsr instruction
6972df1fe9cSrandyf
6982df1fe9cSrandyf	movq    WC_FS(%rbx), %rcx	/ restore fs register
6992df1fe9cSrandyf	movw    %cx, %fs
7002df1fe9cSrandyf
7012df1fe9cSrandyf	movl    $MSR_AMD_FSBASE, %ecx
7022df1fe9cSrandyf	movl    WC_FSBASE(%rbx), %eax
7032df1fe9cSrandyf	movl    WC_FSBASE+4(%rbx), %edx
7042df1fe9cSrandyf	wrmsr
7052df1fe9cSrandyf
7062df1fe9cSrandyf	movq    WC_GS(%rbx), %rcx	/ restore gs register
7072df1fe9cSrandyf	movw    %cx, %gs
7082df1fe9cSrandyf
7092df1fe9cSrandyf	movl    $MSR_AMD_GSBASE, %ecx	/ restore gsbase msr
7102df1fe9cSrandyf	movl    WC_GSBASE(%rbx), %eax
7112df1fe9cSrandyf	movl    WC_GSBASE+4(%rbx), %edx
7122df1fe9cSrandyf	wrmsr
7132df1fe9cSrandyf
7142df1fe9cSrandyf	movl    $MSR_AMD_KGSBASE, %ecx	/ restore kgsbase msr
7152df1fe9cSrandyf	movl    WC_KGSBASE(%rbx), %eax
7162df1fe9cSrandyf	movl    WC_KGSBASE+4(%rbx), %edx
7172df1fe9cSrandyf	wrmsr
7182df1fe9cSrandyf
7192df1fe9cSrandyf	movq	WC_CR0(%rbx), %rdx
7202df1fe9cSrandyf	movq	%rdx, %cr0
7212df1fe9cSrandyf	movq	WC_CR3(%rbx), %rdx
7222df1fe9cSrandyf	movq	%rdx, %cr3
7232df1fe9cSrandyf	movq	WC_CR8(%rbx), %rdx
7242df1fe9cSrandyf	movq	%rdx, %cr8
7252df1fe9cSrandyf
7262df1fe9cSrandyf#if     LED
7271b1c71b2Sjan	movw        $WC_LED, %dx
7282df1fe9cSrandyf	movb        $0xde, %al
7292df1fe9cSrandyf	outb    (%dx)
7302df1fe9cSrandyf#endif
7312df1fe9cSrandyf
7322df1fe9cSrandyf#if     SERIAL
7331b1c71b2Sjan	movw        $WC_COM, %dx
7342df1fe9cSrandyf	movb        $0x6e, %al
7352df1fe9cSrandyf	outb    (%dx)
7362df1fe9cSrandyf#endif
7372df1fe9cSrandyf
7383d995820SJoseph A Townsend	/*
7393d995820SJoseph A Townsend	 * if we are not running on the boot CPU restore stack contents by
7403d995820SJoseph A Townsend	 * calling i_cpr_restore_stack(curthread, save_stack);
7413d995820SJoseph A Townsend	 */
7423d995820SJoseph A Townsend	movq    %rsp, %rbp
7433d995820SJoseph A Townsend	call	i_cpr_bootcpuid
7443d995820SJoseph A Townsend	cmpl	%eax, WC_CPU_ID(%rbx)
7453d995820SJoseph A Townsend	je	2f
7463d995820SJoseph A Townsend
7473d995820SJoseph A Townsend	movq	%gs:CPU_THREAD, %rdi
7483d995820SJoseph A Townsend	movq	WC_SAVED_STACK(%rbx), %rsi
7493d995820SJoseph A Townsend	call	i_cpr_restore_stack
7503d995820SJoseph A Townsend2:
7513d995820SJoseph A Townsend
7523d995820SJoseph A Townsend	movq    WC_RSP(%rbx), %rsp	/ restore stack pointer
7532df1fe9cSrandyf
7542df1fe9cSrandyf	/*
755bc446630SGuoli Shu	 * APIC initialization
7562df1fe9cSrandyf	 */
7573d995820SJoseph A Townsend	movq    %rsp, %rbp
7582df1fe9cSrandyf
7594716fd88Sjan	/*
7604716fd88Sjan	 * skip iff function pointer is NULL
7614716fd88Sjan	 */
7624716fd88Sjan	cmpq	$0, ap_mlsetup
7633d995820SJoseph A Townsend	je	3f
7642df1fe9cSrandyf	call	*ap_mlsetup
7653d995820SJoseph A Townsend3:
7662df1fe9cSrandyf
7672df1fe9cSrandyf	call    *cpr_start_cpu_func
7682df1fe9cSrandyf
7692df1fe9cSrandyf/ restore %rbx to the value it ahd before we called the functions above
7702df1fe9cSrandyf	movq    rm_platter_va, %rbx
7712df1fe9cSrandyf	addq	$WC_CPU, %rbx
7722df1fe9cSrandyf
7732df1fe9cSrandyf	movq    WC_R8(%rbx), %r8
7742df1fe9cSrandyf	movq    WC_R9(%rbx), %r9
7752df1fe9cSrandyf	movq    WC_R10(%rbx), %r10
7762df1fe9cSrandyf	movq    WC_R11(%rbx), %r11
7772df1fe9cSrandyf	movq    WC_R12(%rbx), %r12
7782df1fe9cSrandyf	movq    WC_R13(%rbx), %r13
7792df1fe9cSrandyf	movq    WC_R14(%rbx), %r14
7802df1fe9cSrandyf	movq    WC_R15(%rbx), %r15
7812df1fe9cSrandyf/	movq    WC_RAX(%rbx), %rax
7822df1fe9cSrandyf	movq    WC_RBP(%rbx), %rbp
7832df1fe9cSrandyf	movq    WC_RCX(%rbx), %rcx
7842df1fe9cSrandyf/	movq    WC_RDX(%rbx), %rdx
7852df1fe9cSrandyf	movq    WC_RDI(%rbx), %rdi
7862df1fe9cSrandyf	movq    WC_RSI(%rbx), %rsi
7872df1fe9cSrandyf
7882df1fe9cSrandyf
7892df1fe9cSrandyf/ assume that %cs does not need to be restored
7902df1fe9cSrandyf/ %ds, %es & %ss are ignored in 64bit mode
7912df1fe9cSrandyf	movw	WC_SS(%rbx), %ss
7922df1fe9cSrandyf	movw	WC_DS(%rbx), %ds
7932df1fe9cSrandyf	movw	WC_ES(%rbx), %es
7942df1fe9cSrandyf
7952df1fe9cSrandyf#if     LED
7961b1c71b2Sjan	movw        $WC_LED, %dx
7972df1fe9cSrandyf	movb        $0xdf, %al
7982df1fe9cSrandyf	outb    (%dx)
7992df1fe9cSrandyf#endif
8002df1fe9cSrandyf
8012df1fe9cSrandyf#if     SERIAL
8021b1c71b2Sjan	movw        $WC_COM, %dx
8032df1fe9cSrandyf	movb        $0x6f, %al
8042df1fe9cSrandyf	outb    (%dx)
8052df1fe9cSrandyf#endif
8062df1fe9cSrandyf
8072df1fe9cSrandyf
8082df1fe9cSrandyf	movq    WC_RBP(%rbx), %rbp
8092df1fe9cSrandyf	movq    WC_RSP(%rbx), %rsp
8102df1fe9cSrandyf
8112df1fe9cSrandyf#if     LED
8121b1c71b2Sjan	movw        $WC_LED, %dx
8132df1fe9cSrandyf	movb        $0xe0, %al
8142df1fe9cSrandyf	outb    (%dx)
8152df1fe9cSrandyf#endif
8162df1fe9cSrandyf
8172df1fe9cSrandyf#if     SERIAL
8181b1c71b2Sjan	movw        $WC_COM, %dx
8192df1fe9cSrandyf	movb        $0x70, %al
8202df1fe9cSrandyf	outb    (%dx)
8212df1fe9cSrandyf#endif
8222df1fe9cSrandyf
8232df1fe9cSrandyf
8242df1fe9cSrandyf	movq    WC_RCX(%rbx), %rcx
8252df1fe9cSrandyf
8262df1fe9cSrandyf	pushq	WC_EFLAGS(%rbx)			/ restore flags
8272df1fe9cSrandyf	popfq
8282df1fe9cSrandyf
8292df1fe9cSrandyf#if     LED
8301b1c71b2Sjan	movw        $WC_LED, %dx
8312df1fe9cSrandyf	movb        $0xe1, %al
8322df1fe9cSrandyf	outb    (%dx)
8332df1fe9cSrandyf#endif
8342df1fe9cSrandyf
8352df1fe9cSrandyf#if     SERIAL
8361b1c71b2Sjan	movw        $WC_COM, %dx
8372df1fe9cSrandyf	movb        $0x71, %al
8382df1fe9cSrandyf	outb    (%dx)
8392df1fe9cSrandyf#endif
8402df1fe9cSrandyf
8412df1fe9cSrandyf/*
8422df1fe9cSrandyf * can not use outb after this point, because doing so would mean using
8432df1fe9cSrandyf * %dx which would modify %rdx which is restored here
8442df1fe9cSrandyf */
8452df1fe9cSrandyf
8462df1fe9cSrandyf	movq	%rbx, %rax
8472df1fe9cSrandyf	movq    WC_RDX(%rax), %rdx
8482df1fe9cSrandyf	movq    WC_RBX(%rax), %rbx
8492df1fe9cSrandyf
8502df1fe9cSrandyf	leave
8512df1fe9cSrandyf
8522df1fe9cSrandyf	movq	WC_RETADDR(%rax), %rax
8532df1fe9cSrandyf	movq	%rax, (%rsp)		/ return to caller of wc_save_context
8542df1fe9cSrandyf
8552df1fe9cSrandyf	xorl	%eax, %eax			/ at wakeup return 0
8562df1fe9cSrandyf	ret
8572df1fe9cSrandyf
8582df1fe9cSrandyf
8592df1fe9cSrandyf	SET_SIZE(wc_rm_start)
8602df1fe9cSrandyf
8612df1fe9cSrandyf	ENTRY_NP(asmspin)
8622df1fe9cSrandyf
8632df1fe9cSrandyf	movl	%edi, %ecx
8642df1fe9cSrandyfA1:
8652df1fe9cSrandyf	loop	A1
8662df1fe9cSrandyf
8672df1fe9cSrandyf	SET_SIZE(asmspin)
8682df1fe9cSrandyf
8692df1fe9cSrandyf	.globl wc_rm_end
8702df1fe9cSrandyfwc_rm_end:
8712df1fe9cSrandyf	nop
8722df1fe9cSrandyf
8732df1fe9cSrandyf#elif defined(__i386)
8742df1fe9cSrandyf
8752df1fe9cSrandyf	ENTRY_NP(wc_rm_start)
8762df1fe9cSrandyf
8772df1fe9cSrandyf/entry:	jmp		entry			/ stop here for HDT
8782df1fe9cSrandyf
8792df1fe9cSrandyf	cli
8802df1fe9cSrandyf	movw		%cs, %ax
8812df1fe9cSrandyf	movw		%ax, %ds		/ establish ds ...
8822df1fe9cSrandyf	movw		%ax, %ss		/ ... and ss:esp
8832df1fe9cSrandyf	D16 movl	$WC_STKSTART, %esp
8842df1fe9cSrandyf
8852df1fe9cSrandyf#if     LED
8861b1c71b2Sjan	D16 movl        $WC_LED, %edx
8872df1fe9cSrandyf	D16 movb        $0xd1, %al
8882df1fe9cSrandyf	outb    (%dx)
8892df1fe9cSrandyf#endif
8902df1fe9cSrandyf
8912df1fe9cSrandyf#if     SERIAL
8921b1c71b2Sjan	D16 movl        $WC_COM, %edx
8932df1fe9cSrandyf	D16 movb        $0x61, %al
8942df1fe9cSrandyf	outb    (%dx)
8952df1fe9cSrandyf#endif
8962df1fe9cSrandyf
8972df1fe9cSrandyf
8982df1fe9cSrandyf	D16 call	vgainit
8992df1fe9cSrandyf	D16 call	kbdinit
9002df1fe9cSrandyf	D16 call	cominit
9012df1fe9cSrandyf
9022df1fe9cSrandyf#if     LED
9031b1c71b2Sjan	D16 movl        $WC_LED, %edx
9042df1fe9cSrandyf	D16 movb        $0xd2, %al
9052df1fe9cSrandyf	outb    (%dx)
9062df1fe9cSrandyf#endif
9072df1fe9cSrandyf
9082df1fe9cSrandyf#if     SERIAL
9091b1c71b2Sjan	D16 movl        $WC_COM, %edx
9102df1fe9cSrandyf	D16 movb        $0x62, %al
9112df1fe9cSrandyf	outb    (%dx)
9122df1fe9cSrandyf#endif
9132df1fe9cSrandyf
9142df1fe9cSrandyf	D16 A16 movl	$WC_CPU, %ebx		/ base add of wc_cpu_t
9152df1fe9cSrandyf
9162df1fe9cSrandyf#if     LED
9172df1fe9cSrandyf	D16 movb        $0xd3, %al
9181b1c71b2Sjan	outb    $WC_LED
9192df1fe9cSrandyf#endif
9202df1fe9cSrandyf
9212df1fe9cSrandyf#if     SERIAL
9221b1c71b2Sjan	D16 movl        $WC_COM, %edx
9232df1fe9cSrandyf	D16 movb        $0x63, %al
9242df1fe9cSrandyf	outb    (%dx)
9252df1fe9cSrandyf#endif
9262df1fe9cSrandyf
9272df1fe9cSrandyf	D16 A16 movl	%cs:WC_DS(%ebx), %edx	/ %ds post prot/paging transit
9282df1fe9cSrandyf
9291b1c71b2Sjan#if     LED
9302df1fe9cSrandyf	D16 movb        $0xd4, %al
9311b1c71b2Sjan	outb    $WC_LED
9321b1c71b2Sjan#endif
9332df1fe9cSrandyf
9342df1fe9cSrandyf	D16 A16 lgdt	%cs:WC_GDT(%ebx)	/ restore gdt and idtr
9352df1fe9cSrandyf	D16 A16 lidt	%cs:WC_IDT(%ebx)
9362df1fe9cSrandyf
9371b1c71b2Sjan#if     LED
9382df1fe9cSrandyf	D16 movb        $0xd5, %al
9391b1c71b2Sjan	outb    $WC_LED
9401b1c71b2Sjan#endif
9412df1fe9cSrandyf
9422df1fe9cSrandyf	D16 A16 movl	%cs:WC_CR4(%ebx), %eax	/ restore cr4
943dad25528SRichard Lowe	D16 andl	$_BITNOT(CR4_PGE), %eax / don't set Global Enable yet
9442df1fe9cSrandyf	movl		%eax, %cr4
9452df1fe9cSrandyf
9461b1c71b2Sjan#if     LED
9472df1fe9cSrandyf	D16 movb        $0xd6, %al
9481b1c71b2Sjan	outb    $WC_LED
9491b1c71b2Sjan#endif
9502df1fe9cSrandyf
9512df1fe9cSrandyf	D16 A16 movl	%cs:WC_CR3(%ebx), %eax	/ set PDPT
9522df1fe9cSrandyf	movl		%eax, %cr3
9532df1fe9cSrandyf
9541b1c71b2Sjan#if     LED
9552df1fe9cSrandyf	D16 movb        $0xd7, %al
9561b1c71b2Sjan	outb    $WC_LED
9571b1c71b2Sjan#endif
9582df1fe9cSrandyf
9592df1fe9cSrandyf	D16 A16 movl	%cs:WC_CR0(%ebx), %eax	/ enable prot/paging, etc.
9602df1fe9cSrandyf	movl		%eax, %cr0
9612df1fe9cSrandyf
9621b1c71b2Sjan#if     LED
9632df1fe9cSrandyf	D16 movb        $0xd8, %al
9641b1c71b2Sjan	outb    $WC_LED
9651b1c71b2Sjan#endif
9662df1fe9cSrandyf
9672df1fe9cSrandyf	D16 A16 movl	%cs:WC_VIRTADDR(%ebx), %ebx	/ virtaddr of wc_cpu_t
9682df1fe9cSrandyf
9691b1c71b2Sjan#if     LED
9702df1fe9cSrandyf	D16 movb        $0xd9, %al
9711b1c71b2Sjan	outb    $WC_LED
9721b1c71b2Sjan#endif
9732df1fe9cSrandyf
9741b1c71b2Sjan#if     LED
9752df1fe9cSrandyf	D16 movb        $0xda, %al
9761b1c71b2Sjan	outb    $WC_LED
9771b1c71b2Sjan#endif
9781b1c71b2Sjan
9792df1fe9cSrandyf	jmp		flush			/ flush prefetch queue
9802df1fe9cSrandyfflush:
9812df1fe9cSrandyf	D16 pushl	$KCS_SEL
9822df1fe9cSrandyf	D16 pushl	$kernel_wc_code
9832df1fe9cSrandyf	D16 lret				/ re-appear at kernel_wc_code
9842df1fe9cSrandyf
9852df1fe9cSrandyf
9862df1fe9cSrandyf/*
9872df1fe9cSrandyf * Support routine to re-initialize VGA subsystem
9882df1fe9cSrandyf */
9892df1fe9cSrandyfvgainit:
9902df1fe9cSrandyf	D16 ret
9912df1fe9cSrandyf
9922df1fe9cSrandyf/*
9932df1fe9cSrandyf * Support routine to re-initialize keyboard (which is USB - help!)
9942df1fe9cSrandyf */
9952df1fe9cSrandyfkbdinit:
9962df1fe9cSrandyf	D16 ret
9972df1fe9cSrandyf
9982df1fe9cSrandyf/*
9992df1fe9cSrandyf * Support routine to re-initialize COM ports to something sane for debug output
10002df1fe9cSrandyf */
10012df1fe9cSrandyfcominit:
10021b1c71b2Sjan#if     DEBUG
10031b1c71b2Sjan/*
10041b1c71b2Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that
10051b1c71b2Sjan * we can get debug output before the asy driver has resumed
10061b1c71b2Sjan */
10071b1c71b2Sjan
10081b1c71b2Sjan/ select COM1
1009dad25528SRichard Lowe	D16 movl	$_CONST(COM1+LCR), %edx
10101b1c71b2Sjan	D16 movb	$DLAB, %al		/ divisor latch
10111b1c71b2Sjan	outb	(%dx)
10121b1c71b2Sjan
1013dad25528SRichard Lowe	D16 movl	$_CONST(COM1+DLL), %edx	/ divisor latch lsb
10141b1c71b2Sjan	D16 movb	$B9600L, %al		/ divisor latch
10151b1c71b2Sjan	outb	(%dx)
10161b1c71b2Sjan
1017dad25528SRichard Lowe	D16 movl	$_CONST(COM1+DLH), %edx	/ divisor latch hsb
10181b1c71b2Sjan	D16 movb	$B9600H, %al		/ divisor latch
10191b1c71b2Sjan	outb	(%dx)
10201b1c71b2Sjan
1021dad25528SRichard Lowe	D16 movl	$_CONST(COM1+LCR), %edx	/ select COM1
1022dad25528SRichard Lowe	D16 movb	$_CONST(STOP1|BITS8), %al	/ 1 stop bit, 8bit word len
10231b1c71b2Sjan	outb	(%dx)
10241b1c71b2Sjan
1025dad25528SRichard Lowe	D16 movl	$_CONST(COM1+MCR), %edx	/ select COM1
1026dad25528SRichard Lowe	D16 movb	$_CONST(RTS|DTR), %al		/ 1 stop bit, 8bit word len
10271b1c71b2Sjan	outb	(%dx)
10281b1c71b2Sjan
10291b1c71b2Sjan/ select COM2
1030dad25528SRichard Lowe	D16 movl	$_CONST(COM2+LCR), %edx
10311b1c71b2Sjan	D16 movb	$DLAB, %al		/ divisor latch
10321b1c71b2Sjan	outb	(%dx)
10331b1c71b2Sjan
1034dad25528SRichard Lowe	D16 movl	$_CONST(COM2+DLL), %edx	/ divisor latch lsb
10351b1c71b2Sjan	D16 movb	$B9600L, %al		/ divisor latch
10361b1c71b2Sjan	outb	(%dx)
10371b1c71b2Sjan
1038dad25528SRichard Lowe	D16 movl	$_CONST(COM2+DLH), %edx	/ divisor latch hsb
10391b1c71b2Sjan	D16 movb	$B9600H, %al		/ divisor latch
10401b1c71b2Sjan	outb	(%dx)
10411b1c71b2Sjan
1042dad25528SRichard Lowe	D16 movl	$_CONST(COM2+LCR), %edx	/ select COM1
1043dad25528SRichard Lowe	D16 movb	$_CONST(STOP1|BITS8), %al	/ 1 stop bit, 8bit word len
10441b1c71b2Sjan	outb	(%dx)
10451b1c71b2Sjan
1046dad25528SRichard Lowe	D16 movl	$_CONST(COM2+MCR), %edx	/ select COM1
1047dad25528SRichard Lowe	D16 movb	$_CONST(RTS|DTR), %al		/ 1 stop bit, 8bit word len
10481b1c71b2Sjan	outb	(%dx)
10491b1c71b2Sjan#endif	/*	DEBUG	*/
10501b1c71b2Sjan
10512df1fe9cSrandyf	D16 ret
10522df1fe9cSrandyf
10532df1fe9cSrandyf	.globl wc_rm_end
10542df1fe9cSrandyfwc_rm_end:
10552df1fe9cSrandyf	nop
10562df1fe9cSrandyf
10572df1fe9cSrandyf	.globl	kernel_wc_code
10582df1fe9cSrandyfkernel_wc_code:
10592df1fe9cSrandyf	/ At this point we are with kernel's cs and proper eip.
10602df1fe9cSrandyf	/ We will be executing not from the copy in real mode platter,
10612df1fe9cSrandyf	/ but from the original code where boot loaded us.
10622df1fe9cSrandyf	/ By this time GDT and IDT are loaded as is cr0, cr3 and cr4.
10632df1fe9cSrandyf	/ %ebx is wc_cpu
10642df1fe9cSrandyf	/ %dx is our ds
10652df1fe9cSrandyf
10661b1c71b2Sjan#if     LED
10672df1fe9cSrandyf	D16 movb        $0xdb, %al
10681b1c71b2Sjan	outb	$WC_LED
10691b1c71b2Sjan#endif
10702df1fe9cSrandyf
10712df1fe9cSrandyf/ got here OK
10722df1fe9cSrandyf
10732df1fe9cSrandyf	movw	%dx, %ds		/ $KDS_SEL
10741b1c71b2Sjan
10751b1c71b2Sjan#if     LED
10762df1fe9cSrandyf	movb	$0xdc, %al
10771b1c71b2Sjan	outb	$WC_LED
10781b1c71b2Sjan#endif
10792df1fe9cSrandyf
10804716fd88Sjan	/*
10814716fd88Sjan	 * Before proceeding, enable usage of the page table NX bit if
10824716fd88Sjan	 * that's how the page tables are set up.
10834716fd88Sjan	 */
10847417cfdeSKuriakose Kuruvilla	bt      $X86FSET_NX, x86_featureset
10857417cfdeSKuriakose Kuruvilla	jnc     1f
10864716fd88Sjan	movl    $MSR_AMD_EFER, %ecx
10872df1fe9cSrandyf	rdmsr
10882df1fe9cSrandyf	orl     $AMD_EFER_NXE, %eax
10892df1fe9cSrandyf	wrmsr
10904716fd88Sjan1:
10912df1fe9cSrandyf
10922df1fe9cSrandyf	movl	WC_CR4(%ebx), %eax	/ restore full cr4 (with Global Enable)
10932df1fe9cSrandyf	movl	%eax, %cr4
10942df1fe9cSrandyf
10952df1fe9cSrandyf
10962df1fe9cSrandyf	lldt	WC_LDT(%ebx)		/ $LDT_SEL
10972df1fe9cSrandyf
10982df1fe9cSrandyf	movzwl	WC_TR(%ebx), %eax	/ clear TSS busy bit
10992df1fe9cSrandyf	addl	WC_GDT+2(%ebx), %eax
1100dad25528SRichard Lowe	andl	$_BITNOT(0x200), 4(%eax)
11012df1fe9cSrandyf	ltr	WC_TR(%ebx)		/ $UTSS_SEL
11022df1fe9cSrandyf
11033d995820SJoseph A Townsend	movw	WC_SS(%ebx), %ss	/ restore segment registers
11043d995820SJoseph A Townsend	movw	WC_ES(%ebx), %es
11053d995820SJoseph A Townsend	movw	WC_FS(%ebx), %fs
11063d995820SJoseph A Townsend	movw	WC_GS(%ebx), %gs
11073d995820SJoseph A Townsend
11083d995820SJoseph A Townsend	/*
11093d995820SJoseph A Townsend	 * set the stack pointer to point into the identity mapped page
11103d995820SJoseph A Townsend	 * temporarily, so we can make function calls
11113d995820SJoseph A Townsend	 */
11123d995820SJoseph A Townsend	.globl  rm_platter_va
11133d995820SJoseph A Townsend	movl    rm_platter_va, %eax
11143d995820SJoseph A Townsend	movl	$WC_STKSTART, %esp
11153d995820SJoseph A Townsend	addl	%eax, %esp
11163d995820SJoseph A Townsend	movl	%esp, %ebp
11173d995820SJoseph A Townsend
11183d995820SJoseph A Townsend	/*
11193d995820SJoseph A Townsend	 * if we are not running on the boot CPU restore stack contents by
11203d995820SJoseph A Townsend	 * calling i_cpr_restore_stack(curthread, save_stack);
11213d995820SJoseph A Townsend	 */
11223d995820SJoseph A Townsend	call	i_cpr_bootcpuid
11233d995820SJoseph A Townsend	cmpl	%eax, WC_CPU_ID(%ebx)
11243d995820SJoseph A Townsend	je	2f
11253d995820SJoseph A Townsend
11263d995820SJoseph A Townsend	pushl	WC_SAVED_STACK(%ebx)
11273d995820SJoseph A Townsend	pushl	%gs:CPU_THREAD
11283d995820SJoseph A Townsend	call	i_cpr_restore_stack
11293d995820SJoseph A Townsend	addl	$0x10, %esp
11303d995820SJoseph A Townsend2:
11313d995820SJoseph A Townsend
11323d995820SJoseph A Townsend	movl	WC_ESP(%ebx), %esp
11333d995820SJoseph A Townsend	movl	%esp, %ebp
11342df1fe9cSrandyf
11352df1fe9cSrandyf	movl	WC_RETADDR(%ebx), %eax	/ return to caller of wc_save_context
11362df1fe9cSrandyf	movl	%eax, (%esp)
11372df1fe9cSrandyf
11382df1fe9cSrandyf	/*
11394716fd88Sjan	 * APIC initialization, skip iff function pointer is NULL
11402df1fe9cSrandyf	 */
11414716fd88Sjan	cmpl	$0, ap_mlsetup
11423d995820SJoseph A Townsend	je	3f
11432df1fe9cSrandyf	call	*ap_mlsetup
11443d995820SJoseph A Townsend3:
11452df1fe9cSrandyf
11462df1fe9cSrandyf	call    *cpr_start_cpu_func
11472df1fe9cSrandyf
11482df1fe9cSrandyf	pushl	WC_EFLAGS(%ebx)		/ restore flags
11492df1fe9cSrandyf	popfl
11502df1fe9cSrandyf
11512df1fe9cSrandyf	movl	WC_EDI(%ebx), %edi	/ restore general registers
11522df1fe9cSrandyf	movl	WC_ESI(%ebx), %esi
11532df1fe9cSrandyf	movl	WC_EBP(%ebx), %ebp
11542df1fe9cSrandyf	movl	WC_EBX(%ebx), %ebx
11552df1fe9cSrandyf
11562df1fe9cSrandyf/exit:	jmp	exit			/ stop here for HDT
11572df1fe9cSrandyf
11582df1fe9cSrandyf	xorl	%eax, %eax		/ at wakeup return 0
11592df1fe9cSrandyf	ret
11602df1fe9cSrandyf
11612df1fe9cSrandyf	SET_SIZE(wc_rm_start)
11622df1fe9cSrandyf
11632df1fe9cSrandyf
11642df1fe9cSrandyf#endif	/* defined(__amd64) */
11652df1fe9cSrandyf
11662df1fe9cSrandyf#endif /* lint */
11672df1fe9cSrandyf
1168