xref: /illumos-gate/usr/src/uts/i86pc/ml/cpr_wakecode.S (revision 5d9d9091)
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.
2365f20420SRobert Mustacchi * Copyright 2019 Joyent, Inc.
24abe1e6b3SAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
252df1fe9cSrandyf */
2665f20420SRobert Mustacchi
272df1fe9cSrandyf#include <sys/asm_linkage.h>
282df1fe9cSrandyf#include <sys/asm_misc.h>
292df1fe9cSrandyf#include <sys/regset.h>
302df1fe9cSrandyf#include <sys/privregs.h>
312df1fe9cSrandyf#include <sys/x86_archext.h>
322df1fe9cSrandyf#include <sys/cpr_wakecode.h>
332df1fe9cSrandyf
342df1fe9cSrandyf#include <sys/segments.h>
352df1fe9cSrandyf#include "assym.h"
362df1fe9cSrandyf
371b1c71b2Sjan#ifdef  DEBUG
381b1c71b2Sjan#define LED     1
391b1c71b2Sjan#define SERIAL  1
401b1c71b2Sjan#endif	/*	DEBUG	*/
411b1c71b2Sjan
421b1c71b2Sjan#ifdef	DEBUG
431b1c71b2Sjan#define	COM1	0x3f8
441b1c71b2Sjan#define	COM2	0x2f8
451b1c71b2Sjan#define	WC_COM	COM2	/* either COM1 or COM2			*/
461b1c71b2Sjan#define	WC_LED	0x80    /* diagnostic led port ON motherboard	*/
471b1c71b2Sjan
481b1c71b2Sjan/*
491b1c71b2Sjan * defined as offsets from the data register
501b1c71b2Sjan */
511b1c71b2Sjan#define	DLL	0	/* divisor latch (lsb) */
521b1c71b2Sjan#define	DLH	1	/* divisor latch (msb) */
531b1c71b2Sjan#define	LCR	3	/* line control register		*/
541b1c71b2Sjan#define	MCR	4	/* modem control register		*/
551b1c71b2Sjan
561b1c71b2Sjan
571b1c71b2Sjan#define	DLAB	0x80    /* divisor latch access bit		*/
581b1c71b2Sjan#define	B9600L	0X0c	/* lsb bit pattern for 9600 baud	*/
591b1c71b2Sjan#define	B9600H	0X0	/* hsb bit pattern for 9600 baud	*/
601b1c71b2Sjan#define	DTR	0x01    /* Data Terminal Ready			*/
611b1c71b2Sjan#define	RTS	0x02    /* Request To Send			*/
621b1c71b2Sjan#define	STOP1	0x00	/* 1 stop bit				*/
631b1c71b2Sjan#define	BITS8	0x03    /* 8 bits per char			*/
641b1c71b2Sjan
651b1c71b2Sjan#endif	/*	DEBUG	*/
661b1c71b2Sjan
672df1fe9cSrandyf/*
682df1fe9cSrandyf *	This file contains the low level routines involved in getting
692df1fe9cSrandyf *	into and out of ACPI S3, including those needed for restarting
702df1fe9cSrandyf *	the non-boot cpus.
712df1fe9cSrandyf *
722df1fe9cSrandyf *	Our assumptions:
732df1fe9cSrandyf *
742df1fe9cSrandyf *	Our actions:
752df1fe9cSrandyf *
762df1fe9cSrandyf */
772df1fe9cSrandyf
782df1fe9cSrandyf	ENTRY_NP(wc_save_context)
792df1fe9cSrandyf
802df1fe9cSrandyf	movq	(%rsp), %rdx		/ return address
812df1fe9cSrandyf	movq	%rdx, WC_RETADDR(%rdi)
822df1fe9cSrandyf	pushq	%rbp
832df1fe9cSrandyf	movq	%rsp,%rbp
842df1fe9cSrandyf
852df1fe9cSrandyf	movq    %rdi, WC_VIRTADDR(%rdi)
862df1fe9cSrandyf	movq    %rdi, WC_RDI(%rdi)
872df1fe9cSrandyf
882df1fe9cSrandyf	movq    %rdx, WC_RDX(%rdi)
892df1fe9cSrandyf
902df1fe9cSrandyf/ stash everything else we need
912df1fe9cSrandyf	sgdt	WC_GDT(%rdi)
922df1fe9cSrandyf	sidt	WC_IDT(%rdi)
932df1fe9cSrandyf	sldt	WC_LDT(%rdi)
942df1fe9cSrandyf	str	WC_TR(%rdi)
952df1fe9cSrandyf
962df1fe9cSrandyf	movq	%cr0, %rdx
972df1fe9cSrandyf	movq	%rdx, WC_CR0(%rdi)
982df1fe9cSrandyf	movq	%cr3, %rdx
992df1fe9cSrandyf	movq	%rdx, WC_CR3(%rdi)
1002df1fe9cSrandyf	movq	%cr4, %rdx
1012df1fe9cSrandyf	movq	%rdx, WC_CR4(%rdi)
1022df1fe9cSrandyf	movq	%cr8, %rdx
1032df1fe9cSrandyf	movq	%rdx, WC_CR8(%rdi)
1042df1fe9cSrandyf
1052df1fe9cSrandyf	movq    %r8, WC_R8(%rdi)
1062df1fe9cSrandyf	movq    %r9, WC_R9(%rdi)
1072df1fe9cSrandyf	movq    %r10, WC_R10(%rdi)
1082df1fe9cSrandyf	movq    %r11, WC_R11(%rdi)
1092df1fe9cSrandyf	movq    %r12, WC_R12(%rdi)
1102df1fe9cSrandyf	movq    %r13, WC_R13(%rdi)
1112df1fe9cSrandyf	movq    %r14, WC_R14(%rdi)
1122df1fe9cSrandyf	movq    %r15, WC_R15(%rdi)
1132df1fe9cSrandyf	movq    %rax, WC_RAX(%rdi)
1142df1fe9cSrandyf	movq    %rbp, WC_RBP(%rdi)
1152df1fe9cSrandyf	movq    %rbx, WC_RBX(%rdi)
1162df1fe9cSrandyf	movq    %rcx, WC_RCX(%rdi)
1172df1fe9cSrandyf	movq    %rsi, WC_RSI(%rdi)
1182df1fe9cSrandyf	movq    %rsp, WC_RSP(%rdi)
1192df1fe9cSrandyf
1202df1fe9cSrandyf	movw	%ss, WC_SS(%rdi)
1212df1fe9cSrandyf	movw	%cs, WC_CS(%rdi)
1222df1fe9cSrandyf	movw	%ds, WC_DS(%rdi)
1232df1fe9cSrandyf	movw	%es, WC_ES(%rdi)
1242df1fe9cSrandyf
1252df1fe9cSrandyf	movq	$0, %rcx		/ save %fs register
1262df1fe9cSrandyf	movw    %fs, %cx
1272df1fe9cSrandyf	movq    %rcx, WC_FS(%rdi)
1282df1fe9cSrandyf
1292df1fe9cSrandyf	movl    $MSR_AMD_FSBASE, %ecx
1302df1fe9cSrandyf	rdmsr
1312df1fe9cSrandyf	movl    %eax, WC_FSBASE(%rdi)
1322df1fe9cSrandyf	movl    %edx, WC_FSBASE+4(%rdi)
1332df1fe9cSrandyf
1342df1fe9cSrandyf	movq	$0, %rcx		/ save %gs register
1352df1fe9cSrandyf	movw    %gs, %cx
1362df1fe9cSrandyf	movq    %rcx, WC_GS(%rdi)
1372df1fe9cSrandyf
1382df1fe9cSrandyf	movl    $MSR_AMD_GSBASE, %ecx	/ save gsbase msr
1392df1fe9cSrandyf	rdmsr
1402df1fe9cSrandyf	movl    %eax, WC_GSBASE(%rdi)
1412df1fe9cSrandyf	movl    %edx, WC_GSBASE+4(%rdi)
1422df1fe9cSrandyf
1432df1fe9cSrandyf	movl    $MSR_AMD_KGSBASE, %ecx	/ save kgsbase msr
1442df1fe9cSrandyf	rdmsr
1452df1fe9cSrandyf	movl    %eax, WC_KGSBASE(%rdi)
1462df1fe9cSrandyf	movl    %edx, WC_KGSBASE+4(%rdi)
1472df1fe9cSrandyf
1483d995820SJoseph A Townsend	movq	%gs:CPU_ID, %rax	/ save current cpu id
1493d995820SJoseph A Townsend	movq	%rax, WC_CPU_ID(%rdi)
1503d995820SJoseph A Townsend
1512df1fe9cSrandyf	pushfq
1522df1fe9cSrandyf	popq	WC_EFLAGS(%rdi)
1532df1fe9cSrandyf
1542df1fe9cSrandyf	wbinvd				/ flush the cache
1553d995820SJoseph A Townsend	mfence
1562df1fe9cSrandyf
1572df1fe9cSrandyf	movq	$1, %rax		/ at suspend return 1
1582df1fe9cSrandyf
1592df1fe9cSrandyf	leave
1602df1fe9cSrandyf
1612df1fe9cSrandyf	ret
1622df1fe9cSrandyf
1632df1fe9cSrandyf	SET_SIZE(wc_save_context)
1642df1fe9cSrandyf
1652df1fe9cSrandyf
1662df1fe9cSrandyf/*
1672df1fe9cSrandyf *	Our assumptions:
1682df1fe9cSrandyf *		- We are running in real mode.
1692df1fe9cSrandyf *		- Interrupts are disabled.
1702df1fe9cSrandyf *
1712df1fe9cSrandyf *	Our actions:
1722df1fe9cSrandyf *		- We start using our GDT by loading correct values in the
1732df1fe9cSrandyf *		  selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL,
1742df1fe9cSrandyf *		  gs=KGS_SEL).
1752df1fe9cSrandyf *		- We change over to using our IDT.
1762df1fe9cSrandyf *		- We load the default LDT into the hardware LDT register.
1772df1fe9cSrandyf *		- We load the default TSS into the hardware task register.
1782df1fe9cSrandyf *		- We restore registers
1792df1fe9cSrandyf *		- We return to original caller (a la setjmp)
1802df1fe9cSrandyf */
1812df1fe9cSrandyf
1822df1fe9cSrandyf	ENTRY_NP(wc_rm_start)
1832df1fe9cSrandyf
1842df1fe9cSrandyf	/*
185dad25528SRichard Lowe	 * For the Sun Studio 10 assembler we needed to do a .code32 and
186dad25528SRichard Lowe	 * mentally invert the meaning of the addr16 and data16 prefixes to
187dad25528SRichard Lowe	 * get 32-bit access when generating code to be executed in 16-bit
188dad25528SRichard Lowe	 * mode (sigh...)
189dad25528SRichard Lowe	 *
190dad25528SRichard Lowe	 * This code, despite always being built with GNU as, has inherited
191dad25528SRichard Lowe	 * the conceptual damage.
1922df1fe9cSrandyf	 */
1932df1fe9cSrandyf
1942df1fe9cSrandyf	.code32
1952df1fe9cSrandyf
1962df1fe9cSrandyf	cli
1972df1fe9cSrandyf	movw		%cs, %ax
1982df1fe9cSrandyf	movw		%ax, %ds		/ establish ds ...
1992df1fe9cSrandyf	movw		%ax, %ss		/ ... and ss:esp
2002df1fe9cSrandyf	D16 movl	$WC_STKSTART, %esp
2012df1fe9cSrandyf/ using the following value blows up machines! - DO NOT USE
2022df1fe9cSrandyf/	D16 movl	0xffc, %esp
2032df1fe9cSrandyf
2042df1fe9cSrandyf
2052df1fe9cSrandyf#if     LED
2061b1c71b2Sjan	D16 movl        $WC_LED, %edx
2072df1fe9cSrandyf	D16 movb        $0xd1, %al
2082df1fe9cSrandyf	outb    (%dx)
2092df1fe9cSrandyf#endif
2102df1fe9cSrandyf
2112df1fe9cSrandyf#if     SERIAL
2121b1c71b2Sjan	D16 movl        $WC_COM, %edx
2132df1fe9cSrandyf	D16 movb        $0x61, %al
2142df1fe9cSrandyf	outb    (%dx)
2152df1fe9cSrandyf#endif
2162df1fe9cSrandyf
2172df1fe9cSrandyf	D16 call	cominit
2182df1fe9cSrandyf
2192df1fe9cSrandyf	/*
2202df1fe9cSrandyf	 * Enable protected-mode, write protect, and alignment mask
2212df1fe9cSrandyf	 * %cr0 has already been initialsed to zero
2222df1fe9cSrandyf	 */
2232df1fe9cSrandyf	movl		%cr0, %eax
224dad25528SRichard Lowe	D16 orl		$_CONST(CR0_PE|CR0_WP|CR0_AM), %eax
2252df1fe9cSrandyf	movl		%eax, %cr0
2262df1fe9cSrandyf
2272df1fe9cSrandyf	/*
2282df1fe9cSrandyf	 * Do a jmp immediately after writing to cr0 when enabling protected
2292df1fe9cSrandyf	 * mode to clear the real mode prefetch queue (per Intel's docs)
2302df1fe9cSrandyf	 */
2312df1fe9cSrandyf	jmp		pestart
2322df1fe9cSrandyfpestart:
2332df1fe9cSrandyf
2342df1fe9cSrandyf#if     LED
2351b1c71b2Sjan	D16 movl        $WC_LED, %edx
2362df1fe9cSrandyf	D16 movb        $0xd2, %al
2372df1fe9cSrandyf	outb    (%dx)
2382df1fe9cSrandyf#endif
2392df1fe9cSrandyf
2402df1fe9cSrandyf#if     SERIAL
2411b1c71b2Sjan	D16 movl        $WC_COM, %edx
2422df1fe9cSrandyf	D16 movb        $0x62, %al
2432df1fe9cSrandyf	outb    (%dx)
2442df1fe9cSrandyf#endif
2452df1fe9cSrandyf
2462df1fe9cSrandyf	/*
2472df1fe9cSrandyf	 * 16-bit protected mode is now active, so prepare to turn on long
2482df1fe9cSrandyf	 * mode
2492df1fe9cSrandyf	 */
2502df1fe9cSrandyf
2512df1fe9cSrandyf#if     LED
2521b1c71b2Sjan	D16 movl        $WC_LED, %edx
2532df1fe9cSrandyf	D16 movb        $0xd3, %al
2542df1fe9cSrandyf	outb    (%dx)
2552df1fe9cSrandyf#endif
2562df1fe9cSrandyf
2572df1fe9cSrandyf#if     SERIAL
2581b1c71b2Sjan	D16 movl        $WC_COM, %edx
2592df1fe9cSrandyf	D16 movb        $0x63, %al
2602df1fe9cSrandyf	outb    (%dx)
2612df1fe9cSrandyf#endif
2622df1fe9cSrandyf
2632df1fe9cSrandyf	/*
26465f20420SRobert Mustacchi	 * Add any initial cr4 bits
2652df1fe9cSrandyf	 */
2662df1fe9cSrandyf	movl		%cr4, %eax
2672df1fe9cSrandyf	A16 D16 orl	CR4OFF, %eax
2682df1fe9cSrandyf
2692df1fe9cSrandyf	/*
2702df1fe9cSrandyf	 * Enable PAE mode (CR4.PAE)
2712df1fe9cSrandyf	 */
2722df1fe9cSrandyf	D16 orl		$CR4_PAE, %eax
2732df1fe9cSrandyf	movl		%eax, %cr4
2742df1fe9cSrandyf
2752df1fe9cSrandyf#if     LED
2761b1c71b2Sjan	D16 movl        $WC_LED, %edx
2772df1fe9cSrandyf	D16 movb        $0xd4, %al
2782df1fe9cSrandyf	outb    (%dx)
2792df1fe9cSrandyf#endif
2802df1fe9cSrandyf
2812df1fe9cSrandyf#if     SERIAL
2821b1c71b2Sjan	D16 movl        $WC_COM, %edx
2832df1fe9cSrandyf	D16 movb        $0x64, %al
2842df1fe9cSrandyf	outb    (%dx)
2852df1fe9cSrandyf#endif
2862df1fe9cSrandyf
2872df1fe9cSrandyf	/*
2882df1fe9cSrandyf	 * Point cr3 to the 64-bit long mode page tables.
2892df1fe9cSrandyf	 *
2902df1fe9cSrandyf	 * Note that these MUST exist in 32-bit space, as we don't have
2912df1fe9cSrandyf	 * a way to load %cr3 with a 64-bit base address for the page tables
2922df1fe9cSrandyf	 * until the CPU is actually executing in 64-bit long mode.
2932df1fe9cSrandyf	 */
2942df1fe9cSrandyf	A16 D16 movl	CR3OFF, %eax
2952df1fe9cSrandyf	movl		%eax, %cr3
2962df1fe9cSrandyf
2972df1fe9cSrandyf	/*
2982df1fe9cSrandyf	 * Set long mode enable in EFER (EFER.LME = 1)
2992df1fe9cSrandyf	 */
3002df1fe9cSrandyf	D16 movl	$MSR_AMD_EFER, %ecx
3012df1fe9cSrandyf	rdmsr
3022df1fe9cSrandyf
3032df1fe9cSrandyf	D16 orl		$AMD_EFER_LME, %eax
3042df1fe9cSrandyf	wrmsr
3052df1fe9cSrandyf
3062df1fe9cSrandyf#if     LED
3071b1c71b2Sjan	D16 movl        $WC_LED, %edx
3082df1fe9cSrandyf	D16 movb        $0xd5, %al
3092df1fe9cSrandyf	outb    (%dx)
3102df1fe9cSrandyf#endif
3112df1fe9cSrandyf
3122df1fe9cSrandyf#if     SERIAL
3131b1c71b2Sjan	D16 movl        $WC_COM, %edx
3142df1fe9cSrandyf	D16 movb        $0x65, %al
3152df1fe9cSrandyf	outb    (%dx)
3162df1fe9cSrandyf#endif
3172df1fe9cSrandyf
3182df1fe9cSrandyf	/*
3192df1fe9cSrandyf	 * Finally, turn on paging (CR0.PG = 1) to activate long mode.
3202df1fe9cSrandyf	 */
3212df1fe9cSrandyf	movl		%cr0, %eax
3222df1fe9cSrandyf	D16 orl		$CR0_PG, %eax
3232df1fe9cSrandyf	movl		%eax, %cr0
3242df1fe9cSrandyf
3252df1fe9cSrandyf	/*
3262df1fe9cSrandyf	 * The instruction after enabling paging in CR0 MUST be a branch.
3272df1fe9cSrandyf	 */
3282df1fe9cSrandyf	jmp		long_mode_active
3292df1fe9cSrandyf
3302df1fe9cSrandyflong_mode_active:
3312df1fe9cSrandyf
3322df1fe9cSrandyf#if     LED
3331b1c71b2Sjan	D16 movl        $WC_LED, %edx
3342df1fe9cSrandyf	D16 movb        $0xd6, %al
3352df1fe9cSrandyf	outb    (%dx)
3362df1fe9cSrandyf#endif
3372df1fe9cSrandyf
3382df1fe9cSrandyf#if     SERIAL
3391b1c71b2Sjan	D16 movl        $WC_COM, %edx
3402df1fe9cSrandyf	D16 movb        $0x66, %al
3412df1fe9cSrandyf	outb    (%dx)
3422df1fe9cSrandyf#endif
3432df1fe9cSrandyf
3442df1fe9cSrandyf	/*
3452df1fe9cSrandyf	 * Long mode is now active but since we're still running with the
3462df1fe9cSrandyf	 * original 16-bit CS we're actually in 16-bit compatability mode.
3472df1fe9cSrandyf	 *
3482df1fe9cSrandyf	 * We have to load an intermediate GDT and IDT here that we know are
3492df1fe9cSrandyf	 * in 32-bit space before we can use the kernel's GDT and IDT, which
3502df1fe9cSrandyf	 * may be in the 64-bit address space, and since we're in compatability
3512df1fe9cSrandyf	 * mode, we only have access to 16 and 32-bit instructions at the
3522df1fe9cSrandyf	 * moment.
3532df1fe9cSrandyf	 */
3542df1fe9cSrandyf	A16 D16 lgdt	TEMPGDTOFF	/* load temporary GDT */
3552df1fe9cSrandyf	A16 D16 lidt	TEMPIDTOFF	/* load temporary IDT */
3562df1fe9cSrandyf
3572df1fe9cSrandyf
3582df1fe9cSrandyf	/*
35965f20420SRobert Mustacchi	 * Do a far transfer to 64-bit mode.  Set the CS selector to a 64-bit
3602df1fe9cSrandyf	 * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump
3612df1fe9cSrandyf	 * to the real mode platter address of wc_long_mode_64 as until the
3622df1fe9cSrandyf	 * 64-bit CS is in place we don't have access to 64-bit instructions
3632df1fe9cSrandyf	 * and thus can't reference a 64-bit %rip.
3642df1fe9cSrandyf	 */
3652df1fe9cSrandyf
3662df1fe9cSrandyf#if     LED
3671b1c71b2Sjan	D16 movl        $WC_LED, %edx
3682df1fe9cSrandyf	D16 movb        $0xd7, %al
3692df1fe9cSrandyf	outb    (%dx)
3702df1fe9cSrandyf#endif
3712df1fe9cSrandyf
3722df1fe9cSrandyf#if     SERIAL
3731b1c71b2Sjan	D16 movl        $WC_COM, %edx
3742df1fe9cSrandyf	D16 movb        $0x67, %al
3752df1fe9cSrandyf	outb    (%dx)
3762df1fe9cSrandyf#endif
3772df1fe9cSrandyf
37865f20420SRobert Mustacchi	D16	pushl	$TEMP_CS64_SEL
3792df1fe9cSrandyf	A16 D16 pushl	LM64OFF
3802df1fe9cSrandyf
3812df1fe9cSrandyf	D16 lret
3822df1fe9cSrandyf
3832df1fe9cSrandyf
3842df1fe9cSrandyf/*
3852df1fe9cSrandyf * Support routine to re-initialize VGA subsystem
3862df1fe9cSrandyf */
3872df1fe9cSrandyfvgainit:
3882df1fe9cSrandyf	D16 ret
3892df1fe9cSrandyf
3902df1fe9cSrandyf/*
3912df1fe9cSrandyf * Support routine to re-initialize keyboard (which is USB - help!)
3922df1fe9cSrandyf */
3932df1fe9cSrandyfkbdinit:
3942df1fe9cSrandyf	D16 ret
3952df1fe9cSrandyf
3962df1fe9cSrandyf/*
3972df1fe9cSrandyf * Support routine to re-initialize COM ports to something sane
3982df1fe9cSrandyf */
3992df1fe9cSrandyfcominit:
4002df1fe9cSrandyf	/ init COM1 & COM2
40165f20420SRobert Mustacchi
4021b1c71b2Sjan#if     DEBUG
4031b1c71b2Sjan/*
4041b1c71b2Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that
4051b1c71b2Sjan * we can get debug output before the asy driver has resumed
4061b1c71b2Sjan */
4071b1c71b2Sjan
4081b1c71b2Sjan/ select COM1
409dad25528SRichard Lowe	D16 movl	$_CONST(COM1+LCR), %edx
4101b1c71b2Sjan	D16 movb	$DLAB, %al		/ divisor latch
4111b1c71b2Sjan	outb	(%dx)
4121b1c71b2Sjan
413dad25528SRichard Lowe	D16 movl	$_CONST(COM1+DLL), %edx	/ divisor latch lsb
4141b1c71b2Sjan	D16 movb	$B9600L, %al		/ divisor latch
4151b1c71b2Sjan	outb	(%dx)
4161b1c71b2Sjan
417dad25528SRichard Lowe	D16 movl	$_CONST(COM1+DLH), %edx	/ divisor latch hsb
4181b1c71b2Sjan	D16 movb	$B9600H, %al		/ divisor latch
4191b1c71b2Sjan	outb	(%dx)
4201b1c71b2Sjan
421dad25528SRichard Lowe	D16 movl	$_CONST(COM1+LCR), %edx	/ select COM1
422dad25528SRichard Lowe	D16 movb	$_CONST(STOP1|BITS8), %al	/ 1 stop bit, 8bit word len
4231b1c71b2Sjan	outb	(%dx)
4241b1c71b2Sjan
425dad25528SRichard Lowe	D16 movl	$_CONST(COM1+MCR), %edx	/ select COM1
426dad25528SRichard Lowe	D16 movb	$_CONST(RTS|DTR), %al		/ data term ready & req to send
4271b1c71b2Sjan	outb	(%dx)
4281b1c71b2Sjan
4291b1c71b2Sjan/ select COM2
430dad25528SRichard Lowe	D16 movl	$_CONST(COM2+LCR), %edx
4311b1c71b2Sjan	D16 movb	$DLAB, %al		/ divisor latch
4321b1c71b2Sjan	outb	(%dx)
4331b1c71b2Sjan
434dad25528SRichard Lowe	D16 movl	$_CONST(COM2+DLL), %edx	/ divisor latch lsb
4351b1c71b2Sjan	D16 movb	$B9600L, %al		/ divisor latch
4361b1c71b2Sjan	outb	(%dx)
4371b1c71b2Sjan
438dad25528SRichard Lowe	D16 movl	$_CONST(COM2+DLH), %edx	/ divisor latch hsb
4391b1c71b2Sjan	D16 movb	$B9600H, %al		/ divisor latch
4401b1c71b2Sjan	outb	(%dx)
4411b1c71b2Sjan
442dad25528SRichard Lowe	D16 movl	$_CONST(COM2+LCR), %edx	/ select COM1
443dad25528SRichard Lowe	D16 movb	$_CONST(STOP1|BITS8), %al	/ 1 stop bit, 8bit word len
4441b1c71b2Sjan	outb	(%dx)
4451b1c71b2Sjan
446dad25528SRichard Lowe	D16 movl	$_CONST(COM2+MCR), %edx	/ select COM1
447dad25528SRichard Lowe	D16 movb	$_CONST(RTS|DTR), %al		/ data term ready & req to send
4481b1c71b2Sjan	outb	(%dx)
4491b1c71b2Sjan#endif	/*	DEBUG	*/
4501b1c71b2Sjan
4512df1fe9cSrandyf	D16 ret
4522df1fe9cSrandyf
4532df1fe9cSrandyf	.code64
4542df1fe9cSrandyf
4552df1fe9cSrandyf	.globl wc_long_mode_64
4562df1fe9cSrandyfwc_long_mode_64:
4572df1fe9cSrandyf
4582df1fe9cSrandyf#if     LED
4591b1c71b2Sjan	movw        $WC_LED, %dx
4602df1fe9cSrandyf	movb        $0xd8, %al
4612df1fe9cSrandyf	outb    (%dx)
4622df1fe9cSrandyf#endif
4632df1fe9cSrandyf
4642df1fe9cSrandyf#if     SERIAL
4651b1c71b2Sjan	movw        $WC_COM, %dx
4662df1fe9cSrandyf	movb        $0x68, %al
4672df1fe9cSrandyf	outb    (%dx)
4682df1fe9cSrandyf#endif
4692df1fe9cSrandyf
4702df1fe9cSrandyf	/*
4712df1fe9cSrandyf	 * We are now running in long mode with a 64-bit CS (EFER.LMA=1,
4722df1fe9cSrandyf	 * CS.L=1) so we now have access to 64-bit instructions.
4732df1fe9cSrandyf	 *
4742df1fe9cSrandyf	 * First, set the 64-bit GDT base.
4752df1fe9cSrandyf	 */
4762df1fe9cSrandyf	.globl	rm_platter_pa
4772df1fe9cSrandyf	movl	rm_platter_pa, %eax
4782df1fe9cSrandyf
4792df1fe9cSrandyf	lgdtq	GDTROFF(%rax)		/* load 64-bit GDT */
4802df1fe9cSrandyf
4812df1fe9cSrandyf	/*
4822df1fe9cSrandyf	 * Save the CPU number in %r11; get the value here since it's saved in
4832df1fe9cSrandyf	 * the real mode platter.
4842df1fe9cSrandyf	 */
4852df1fe9cSrandyf/ JAN
4862df1fe9cSrandyf/ the following is wrong! need to figure out MP systems
4872df1fe9cSrandyf/	movl	CPUNOFF(%rax), %r11d
4882df1fe9cSrandyf
4892df1fe9cSrandyf	/*
4902df1fe9cSrandyf	 * Add rm_platter_pa to %rsp to point it to the same location as seen
4912df1fe9cSrandyf	 * from 64-bit mode.
4922df1fe9cSrandyf	 */
4932df1fe9cSrandyf	addq	%rax, %rsp
4942df1fe9cSrandyf
4952df1fe9cSrandyf	/*
4962df1fe9cSrandyf	 * Now do an lretq to load CS with the appropriate selector for the
4972df1fe9cSrandyf	 * kernel's 64-bit GDT and to start executing 64-bit setup code at the
4982df1fe9cSrandyf	 * virtual address where boot originally loaded this code rather than
4992df1fe9cSrandyf	 * the copy in the real mode platter's rm_code array as we've been
5002df1fe9cSrandyf	 * doing so far.
5012df1fe9cSrandyf	 */
5022df1fe9cSrandyf
5032df1fe9cSrandyf#if     LED
5041b1c71b2Sjan	movw        $WC_LED, %dx
5052df1fe9cSrandyf	movb        $0xd9, %al
5062df1fe9cSrandyf	outb    (%dx)
5072df1fe9cSrandyf#endif
5082df1fe9cSrandyf
5092df1fe9cSrandyf/ JAN this should produce 'i' but we get 'g' instead ???
5102df1fe9cSrandyf#if     SERIAL
5111b1c71b2Sjan	movw        $WC_COM, %dx
5122df1fe9cSrandyf	movb        $0x69, %al
5132df1fe9cSrandyf	outb    (%dx)
5142df1fe9cSrandyf#endif
5152df1fe9cSrandyf
5162df1fe9cSrandyf	pushq	$KCS_SEL
5172df1fe9cSrandyf	pushq	$kernel_wc_code
5182df1fe9cSrandyf	lretq
5192df1fe9cSrandyf
5202df1fe9cSrandyf	.globl kernel_wc_code
5212df1fe9cSrandyfkernel_wc_code:
5222df1fe9cSrandyf
5232df1fe9cSrandyf#if     LED
5241b1c71b2Sjan	movw        $WC_LED, %dx
5252df1fe9cSrandyf	movb        $0xda, %al
5262df1fe9cSrandyf	outb    (%dx)
5272df1fe9cSrandyf#endif
5282df1fe9cSrandyf
5292df1fe9cSrandyf/ JAN this should produce 'j' but we get 'g' instead ???
5302df1fe9cSrandyf#if     SERIAL
5311b1c71b2Sjan	movw        $WC_COM, %dx
5322df1fe9cSrandyf	movb        $0x6a, %al
5332df1fe9cSrandyf	outb    (%dx)
5342df1fe9cSrandyf#endif
5352df1fe9cSrandyf
5362df1fe9cSrandyf	/*
5372df1fe9cSrandyf	 * Complete the balance of the setup we need to before executing
5382df1fe9cSrandyf	 * 64-bit kernel code (namely init rsp, TSS, LGDT, FS and GS).
5392df1fe9cSrandyf	 */
5402df1fe9cSrandyf	.globl  rm_platter_va
5412df1fe9cSrandyf	movq    rm_platter_va, %rbx
5422df1fe9cSrandyf	addq	$WC_CPU, %rbx
5432df1fe9cSrandyf
5442df1fe9cSrandyf#if     LED
5451b1c71b2Sjan	movw        $WC_LED, %dx
5462df1fe9cSrandyf	movb        $0xdb, %al
5472df1fe9cSrandyf	outb    (%dx)
5482df1fe9cSrandyf#endif
5492df1fe9cSrandyf
5502df1fe9cSrandyf#if     SERIAL
5511b1c71b2Sjan	movw        $WC_COM, %dx
5522df1fe9cSrandyf	movw        $0x6b, %ax
5532df1fe9cSrandyf	outb    (%dx)
5542df1fe9cSrandyf#endif
5552df1fe9cSrandyf
5562df1fe9cSrandyf	/*
5572df1fe9cSrandyf	 * restore the rest of the registers
5582df1fe9cSrandyf	 */
5592df1fe9cSrandyf
5602df1fe9cSrandyf	lidtq	WC_IDT(%rbx)
5612df1fe9cSrandyf
5622df1fe9cSrandyf#if     LED
5631b1c71b2Sjan	movw        $WC_LED, %dx
5642df1fe9cSrandyf	movb        $0xdc, %al
5652df1fe9cSrandyf	outb    (%dx)
5662df1fe9cSrandyf#endif
5672df1fe9cSrandyf
5682df1fe9cSrandyf#if     SERIAL
5691b1c71b2Sjan	movw        $WC_COM, %dx
5702df1fe9cSrandyf	movw        $0x6c, %ax
5712df1fe9cSrandyf	outb    (%dx)
5722df1fe9cSrandyf#endif
5732df1fe9cSrandyf
5742df1fe9cSrandyf	/*
5752df1fe9cSrandyf	 * restore the rest of the registers
5762df1fe9cSrandyf	 */
5772df1fe9cSrandyf
5782df1fe9cSrandyf	movw    $KDS_SEL, %ax
5792df1fe9cSrandyf	movw    %ax, %ds
5802df1fe9cSrandyf	movw    %ax, %es
5812df1fe9cSrandyf	movw    %ax, %ss
5822df1fe9cSrandyf
5832df1fe9cSrandyf	/*
5842df1fe9cSrandyf	 * Before proceeding, enable usage of the page table NX bit if
5852df1fe9cSrandyf	 * that's how the page tables are set up.
5862df1fe9cSrandyf	 */
587abe1e6b3SAndy Fiddaman	btl     $X86FSET_NX, x86_featureset(%rip)
5887417cfdeSKuriakose Kuruvilla	jnc     1f
5892df1fe9cSrandyf	movl    $MSR_AMD_EFER, %ecx
5902df1fe9cSrandyf	rdmsr
5912df1fe9cSrandyf	orl     $AMD_EFER_NXE, %eax
5922df1fe9cSrandyf	wrmsr
5932df1fe9cSrandyf1:
5942df1fe9cSrandyf
5952df1fe9cSrandyf	movq	WC_CR4(%rbx), %rax	/ restore full cr4 (with Global Enable)
5962df1fe9cSrandyf	movq	%rax, %cr4
5972df1fe9cSrandyf
5982df1fe9cSrandyf	lldt	WC_LDT(%rbx)
5992df1fe9cSrandyf	movzwq	WC_TR(%rbx), %rax	/ clear TSS busy bit
6002df1fe9cSrandyf	addq	WC_GDT+2(%rbx), %rax
6012df1fe9cSrandyf	andl	$0xfffffdff, 4(%rax)
6022df1fe9cSrandyf	movq	4(%rax), %rcx
60365f20420SRobert Mustacchi	ltr	WC_TR(%rbx)
6042df1fe9cSrandyf
6052df1fe9cSrandyf#if     LED
6061b1c71b2Sjan	movw        $WC_LED, %dx
6072df1fe9cSrandyf	movb        $0xdd, %al
6082df1fe9cSrandyf	outb    (%dx)
6092df1fe9cSrandyf#endif
6102df1fe9cSrandyf
6112df1fe9cSrandyf#if     SERIAL
6121b1c71b2Sjan	movw        $WC_COM, %dx
6132df1fe9cSrandyf	movw        $0x6d, %ax
6142df1fe9cSrandyf	outb    (%dx)
6152df1fe9cSrandyf#endif
6162df1fe9cSrandyf
6172df1fe9cSrandyf/ restore %fsbase %gsbase %kgbase registers using wrmsr instruction
6182df1fe9cSrandyf
6192df1fe9cSrandyf	movq    WC_FS(%rbx), %rcx	/ restore fs register
6202df1fe9cSrandyf	movw    %cx, %fs
6212df1fe9cSrandyf
6222df1fe9cSrandyf	movl    $MSR_AMD_FSBASE, %ecx
6232df1fe9cSrandyf	movl    WC_FSBASE(%rbx), %eax
6242df1fe9cSrandyf	movl    WC_FSBASE+4(%rbx), %edx
6252df1fe9cSrandyf	wrmsr
62665f20420SRobert Mustacchi
6272df1fe9cSrandyf	movq    WC_GS(%rbx), %rcx	/ restore gs register
6282df1fe9cSrandyf	movw    %cx, %gs
6292df1fe9cSrandyf
6302df1fe9cSrandyf	movl    $MSR_AMD_GSBASE, %ecx	/ restore gsbase msr
6312df1fe9cSrandyf	movl    WC_GSBASE(%rbx), %eax
6322df1fe9cSrandyf	movl    WC_GSBASE+4(%rbx), %edx
6332df1fe9cSrandyf	wrmsr
6342df1fe9cSrandyf
6352df1fe9cSrandyf	movl    $MSR_AMD_KGSBASE, %ecx	/ restore kgsbase msr
6362df1fe9cSrandyf	movl    WC_KGSBASE(%rbx), %eax
6372df1fe9cSrandyf	movl    WC_KGSBASE+4(%rbx), %edx
6382df1fe9cSrandyf	wrmsr
6392df1fe9cSrandyf
6402df1fe9cSrandyf	movq	WC_CR0(%rbx), %rdx
6412df1fe9cSrandyf	movq	%rdx, %cr0
6422df1fe9cSrandyf	movq	WC_CR3(%rbx), %rdx
6432df1fe9cSrandyf	movq	%rdx, %cr3
6442df1fe9cSrandyf	movq	WC_CR8(%rbx), %rdx
6452df1fe9cSrandyf	movq	%rdx, %cr8
6462df1fe9cSrandyf
6472df1fe9cSrandyf#if     LED
6481b1c71b2Sjan	movw        $WC_LED, %dx
6492df1fe9cSrandyf	movb        $0xde, %al
6502df1fe9cSrandyf	outb    (%dx)
6512df1fe9cSrandyf#endif
6522df1fe9cSrandyf
6532df1fe9cSrandyf#if     SERIAL
6541b1c71b2Sjan	movw        $WC_COM, %dx
6552df1fe9cSrandyf	movb        $0x6e, %al
6562df1fe9cSrandyf	outb    (%dx)
6572df1fe9cSrandyf#endif
6582df1fe9cSrandyf
6593d995820SJoseph A Townsend	/*
6603d995820SJoseph A Townsend	 * if we are not running on the boot CPU restore stack contents by
6613d995820SJoseph A Townsend	 * calling i_cpr_restore_stack(curthread, save_stack);
6623d995820SJoseph A Townsend	 */
6633d995820SJoseph A Townsend	movq    %rsp, %rbp
6643d995820SJoseph A Townsend	call	i_cpr_bootcpuid
6653d995820SJoseph A Townsend	cmpl	%eax, WC_CPU_ID(%rbx)
6663d995820SJoseph A Townsend	je	2f
6673d995820SJoseph A Townsend
6683d995820SJoseph A Townsend	movq	%gs:CPU_THREAD, %rdi
6693d995820SJoseph A Townsend	movq	WC_SAVED_STACK(%rbx), %rsi
6703d995820SJoseph A Townsend	call	i_cpr_restore_stack
6713d995820SJoseph A Townsend2:
6723d995820SJoseph A Townsend
6733d995820SJoseph A Townsend	movq    WC_RSP(%rbx), %rsp	/ restore stack pointer
6742df1fe9cSrandyf
6752df1fe9cSrandyf	/*
676bc446630SGuoli Shu	 * APIC initialization
6772df1fe9cSrandyf	 */
6783d995820SJoseph A Townsend	movq    %rsp, %rbp
6792df1fe9cSrandyf
6804716fd88Sjan	/*
6814716fd88Sjan	 * skip iff function pointer is NULL
6824716fd88Sjan	 */
6834716fd88Sjan	cmpq	$0, ap_mlsetup
6843d995820SJoseph A Townsend	je	3f
68565f20420SRobert Mustacchi	leaq	ap_mlsetup, %rax
68665f20420SRobert Mustacchi	INDIRECT_CALL_REG(rax)
6873d995820SJoseph A Townsend3:
6882df1fe9cSrandyf
68965f20420SRobert Mustacchi	leaq	cpr_start_cpu_func, %rax
69065f20420SRobert Mustacchi	INDIRECT_CALL_REG(rax)
6912df1fe9cSrandyf
6922df1fe9cSrandyf/ restore %rbx to the value it ahd before we called the functions above
6932df1fe9cSrandyf	movq    rm_platter_va, %rbx
6942df1fe9cSrandyf	addq	$WC_CPU, %rbx
6952df1fe9cSrandyf
6962df1fe9cSrandyf	movq    WC_R8(%rbx), %r8
6972df1fe9cSrandyf	movq    WC_R9(%rbx), %r9
6982df1fe9cSrandyf	movq    WC_R10(%rbx), %r10
6992df1fe9cSrandyf	movq    WC_R11(%rbx), %r11
7002df1fe9cSrandyf	movq    WC_R12(%rbx), %r12
7012df1fe9cSrandyf	movq    WC_R13(%rbx), %r13
7022df1fe9cSrandyf	movq    WC_R14(%rbx), %r14
7032df1fe9cSrandyf	movq    WC_R15(%rbx), %r15
7042df1fe9cSrandyf/	movq    WC_RAX(%rbx), %rax
7052df1fe9cSrandyf	movq    WC_RBP(%rbx), %rbp
7062df1fe9cSrandyf	movq    WC_RCX(%rbx), %rcx
7072df1fe9cSrandyf/	movq    WC_RDX(%rbx), %rdx
7082df1fe9cSrandyf	movq    WC_RDI(%rbx), %rdi
7092df1fe9cSrandyf	movq    WC_RSI(%rbx), %rsi
7102df1fe9cSrandyf
7112df1fe9cSrandyf
7122df1fe9cSrandyf/ assume that %cs does not need to be restored
7132df1fe9cSrandyf/ %ds, %es & %ss are ignored in 64bit mode
7142df1fe9cSrandyf	movw	WC_SS(%rbx), %ss
7152df1fe9cSrandyf	movw	WC_DS(%rbx), %ds
7162df1fe9cSrandyf	movw	WC_ES(%rbx), %es
7172df1fe9cSrandyf
7182df1fe9cSrandyf#if     LED
7191b1c71b2Sjan	movw        $WC_LED, %dx
7202df1fe9cSrandyf	movb        $0xdf, %al
7212df1fe9cSrandyf	outb    (%dx)
7222df1fe9cSrandyf#endif
7232df1fe9cSrandyf
7242df1fe9cSrandyf#if     SERIAL
7251b1c71b2Sjan	movw        $WC_COM, %dx
7262df1fe9cSrandyf	movb        $0x6f, %al
7272df1fe9cSrandyf	outb    (%dx)
7282df1fe9cSrandyf#endif
7292df1fe9cSrandyf
7302df1fe9cSrandyf
7312df1fe9cSrandyf	movq    WC_RBP(%rbx), %rbp
7322df1fe9cSrandyf	movq    WC_RSP(%rbx), %rsp
7332df1fe9cSrandyf
7342df1fe9cSrandyf#if     LED
7351b1c71b2Sjan	movw        $WC_LED, %dx
7362df1fe9cSrandyf	movb        $0xe0, %al
7372df1fe9cSrandyf	outb    (%dx)
7382df1fe9cSrandyf#endif
7392df1fe9cSrandyf
7402df1fe9cSrandyf#if     SERIAL
7411b1c71b2Sjan	movw        $WC_COM, %dx
7422df1fe9cSrandyf	movb        $0x70, %al
7432df1fe9cSrandyf	outb    (%dx)
7442df1fe9cSrandyf#endif
7452df1fe9cSrandyf
7462df1fe9cSrandyf
7472df1fe9cSrandyf	movq    WC_RCX(%rbx), %rcx
7482df1fe9cSrandyf
7492df1fe9cSrandyf	pushq	WC_EFLAGS(%rbx)			/ restore flags
7502df1fe9cSrandyf	popfq
7512df1fe9cSrandyf
7522df1fe9cSrandyf#if     LED
7531b1c71b2Sjan	movw        $WC_LED, %dx
7542df1fe9cSrandyf	movb        $0xe1, %al
7552df1fe9cSrandyf	outb    (%dx)
7562df1fe9cSrandyf#endif
7572df1fe9cSrandyf
7582df1fe9cSrandyf#if     SERIAL
7591b1c71b2Sjan	movw        $WC_COM, %dx
7602df1fe9cSrandyf	movb        $0x71, %al
7612df1fe9cSrandyf	outb    (%dx)
7622df1fe9cSrandyf#endif
7632df1fe9cSrandyf
7642df1fe9cSrandyf/*
7652df1fe9cSrandyf * can not use outb after this point, because doing so would mean using
7662df1fe9cSrandyf * %dx which would modify %rdx which is restored here
7672df1fe9cSrandyf */
7682df1fe9cSrandyf
7692df1fe9cSrandyf	movq	%rbx, %rax
7702df1fe9cSrandyf	movq    WC_RDX(%rax), %rdx
7712df1fe9cSrandyf	movq    WC_RBX(%rax), %rbx
7722df1fe9cSrandyf
7732df1fe9cSrandyf	leave
7742df1fe9cSrandyf
7752df1fe9cSrandyf	movq	WC_RETADDR(%rax), %rax
7762df1fe9cSrandyf	movq	%rax, (%rsp)		/ return to caller of wc_save_context
7772df1fe9cSrandyf
7782df1fe9cSrandyf	xorl	%eax, %eax			/ at wakeup return 0
7792df1fe9cSrandyf	ret
7802df1fe9cSrandyf
7812df1fe9cSrandyf
7822df1fe9cSrandyf	SET_SIZE(wc_rm_start)
7832df1fe9cSrandyf
7842df1fe9cSrandyf	ENTRY_NP(asmspin)
7852df1fe9cSrandyf
7862df1fe9cSrandyf	movl	%edi, %ecx
7872df1fe9cSrandyfA1:
7882df1fe9cSrandyf	loop	A1
7892df1fe9cSrandyf
7902df1fe9cSrandyf	SET_SIZE(asmspin)
7912df1fe9cSrandyf
7922df1fe9cSrandyf	.globl wc_rm_end
7932df1fe9cSrandyfwc_rm_end:
7942df1fe9cSrandyf	nop
7952df1fe9cSrandyf
796