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