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