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. 232df1fe9cSrandyf */ 242df1fe9cSrandyf 252df1fe9cSrandyf#include <sys/asm_linkage.h> 262df1fe9cSrandyf#include <sys/asm_misc.h> 272df1fe9cSrandyf#include <sys/regset.h> 282df1fe9cSrandyf#include <sys/privregs.h> 292df1fe9cSrandyf#include <sys/x86_archext.h> 302df1fe9cSrandyf#include <sys/cpr_wakecode.h> 312df1fe9cSrandyf 322df1fe9cSrandyf#if !defined(__lint) 332df1fe9cSrandyf#include <sys/segments.h> 342df1fe9cSrandyf#include "assym.h" 352df1fe9cSrandyf#endif 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#if defined(lint) || defined(__lint) 792df1fe9cSrandyf 802df1fe9cSrandyf/*ARGSUSED*/ 812df1fe9cSrandyfint 822df1fe9cSrandyfwc_save_context(wc_cpu_t *pcpu) 832df1fe9cSrandyf{ return 0; } 842df1fe9cSrandyf 852df1fe9cSrandyf#else /* lint */ 862df1fe9cSrandyf 872df1fe9cSrandyf#if defined(__amd64) 882df1fe9cSrandyf 892df1fe9cSrandyf ENTRY_NP(wc_save_context) 902df1fe9cSrandyf 912df1fe9cSrandyf movq (%rsp), %rdx / return address 922df1fe9cSrandyf movq %rdx, WC_RETADDR(%rdi) 932df1fe9cSrandyf pushq %rbp 942df1fe9cSrandyf movq %rsp,%rbp 952df1fe9cSrandyf 962df1fe9cSrandyf movq %rdi, WC_VIRTADDR(%rdi) 972df1fe9cSrandyf movq %rdi, WC_RDI(%rdi) 982df1fe9cSrandyf 992df1fe9cSrandyf movq %rdx, WC_RDX(%rdi) 1002df1fe9cSrandyf 1012df1fe9cSrandyf/ stash everything else we need 1022df1fe9cSrandyf sgdt WC_GDT(%rdi) 1032df1fe9cSrandyf sidt WC_IDT(%rdi) 1042df1fe9cSrandyf sldt WC_LDT(%rdi) 1052df1fe9cSrandyf str WC_TR(%rdi) 1062df1fe9cSrandyf 1072df1fe9cSrandyf movq %cr0, %rdx 1082df1fe9cSrandyf movq %rdx, WC_CR0(%rdi) 1092df1fe9cSrandyf movq %cr3, %rdx 1102df1fe9cSrandyf movq %rdx, WC_CR3(%rdi) 1112df1fe9cSrandyf movq %cr4, %rdx 1122df1fe9cSrandyf movq %rdx, WC_CR4(%rdi) 1132df1fe9cSrandyf movq %cr8, %rdx 1142df1fe9cSrandyf movq %rdx, WC_CR8(%rdi) 1152df1fe9cSrandyf 1162df1fe9cSrandyf movq %r8, WC_R8(%rdi) 1172df1fe9cSrandyf movq %r9, WC_R9(%rdi) 1182df1fe9cSrandyf movq %r10, WC_R10(%rdi) 1192df1fe9cSrandyf movq %r11, WC_R11(%rdi) 1202df1fe9cSrandyf movq %r12, WC_R12(%rdi) 1212df1fe9cSrandyf movq %r13, WC_R13(%rdi) 1222df1fe9cSrandyf movq %r14, WC_R14(%rdi) 1232df1fe9cSrandyf movq %r15, WC_R15(%rdi) 1242df1fe9cSrandyf movq %rax, WC_RAX(%rdi) 1252df1fe9cSrandyf movq %rbp, WC_RBP(%rdi) 1262df1fe9cSrandyf movq %rbx, WC_RBX(%rdi) 1272df1fe9cSrandyf movq %rcx, WC_RCX(%rdi) 1282df1fe9cSrandyf movq %rsi, WC_RSI(%rdi) 1292df1fe9cSrandyf movq %rsp, WC_RSP(%rdi) 1302df1fe9cSrandyf 1312df1fe9cSrandyf movw %ss, WC_SS(%rdi) 1322df1fe9cSrandyf movw %cs, WC_CS(%rdi) 1332df1fe9cSrandyf movw %ds, WC_DS(%rdi) 1342df1fe9cSrandyf movw %es, WC_ES(%rdi) 1352df1fe9cSrandyf 1362df1fe9cSrandyf movq $0, %rcx / save %fs register 1372df1fe9cSrandyf movw %fs, %cx 1382df1fe9cSrandyf movq %rcx, WC_FS(%rdi) 1392df1fe9cSrandyf 1402df1fe9cSrandyf movl $MSR_AMD_FSBASE, %ecx 1412df1fe9cSrandyf rdmsr 1422df1fe9cSrandyf movl %eax, WC_FSBASE(%rdi) 1432df1fe9cSrandyf movl %edx, WC_FSBASE+4(%rdi) 1442df1fe9cSrandyf 1452df1fe9cSrandyf movq $0, %rcx / save %gs register 1462df1fe9cSrandyf movw %gs, %cx 1472df1fe9cSrandyf movq %rcx, WC_GS(%rdi) 1482df1fe9cSrandyf 1492df1fe9cSrandyf movl $MSR_AMD_GSBASE, %ecx / save gsbase msr 1502df1fe9cSrandyf rdmsr 1512df1fe9cSrandyf movl %eax, WC_GSBASE(%rdi) 1522df1fe9cSrandyf movl %edx, WC_GSBASE+4(%rdi) 1532df1fe9cSrandyf 1542df1fe9cSrandyf movl $MSR_AMD_KGSBASE, %ecx / save kgsbase msr 1552df1fe9cSrandyf rdmsr 1562df1fe9cSrandyf movl %eax, WC_KGSBASE(%rdi) 1572df1fe9cSrandyf movl %edx, WC_KGSBASE+4(%rdi) 1582df1fe9cSrandyf 1593d995820SJoseph A Townsend movq %gs:CPU_ID, %rax / save current cpu id 1603d995820SJoseph A Townsend movq %rax, WC_CPU_ID(%rdi) 1613d995820SJoseph A Townsend 1622df1fe9cSrandyf pushfq 1632df1fe9cSrandyf popq WC_EFLAGS(%rdi) 1642df1fe9cSrandyf 1652df1fe9cSrandyf wbinvd / flush the cache 1663d995820SJoseph A Townsend mfence 1672df1fe9cSrandyf 1682df1fe9cSrandyf movq $1, %rax / at suspend return 1 1692df1fe9cSrandyf 1702df1fe9cSrandyf leave 1712df1fe9cSrandyf 1722df1fe9cSrandyf ret 1732df1fe9cSrandyf 1742df1fe9cSrandyf SET_SIZE(wc_save_context) 1752df1fe9cSrandyf 1762df1fe9cSrandyf#elif defined(__i386) 1772df1fe9cSrandyf 1782df1fe9cSrandyf ENTRY_NP(wc_save_context) 1792df1fe9cSrandyf 1802df1fe9cSrandyf movl 4(%esp), %eax / wc_cpu_t * 1812df1fe9cSrandyf movl %eax, WC_VIRTADDR(%eax) 1822df1fe9cSrandyf 1832df1fe9cSrandyf movl (%esp), %edx / return address 1842df1fe9cSrandyf movl %edx, WC_RETADDR(%eax) 1852df1fe9cSrandyf 1862df1fe9cSrandyf str WC_TR(%eax) / stash everything else we need 1872df1fe9cSrandyf sgdt WC_GDT(%eax) 1882df1fe9cSrandyf sldt WC_LDT(%eax) 1892df1fe9cSrandyf sidt WC_IDT(%eax) 1902df1fe9cSrandyf 1912df1fe9cSrandyf movl %cr0, %edx 1922df1fe9cSrandyf movl %edx, WC_CR0(%eax) 1932df1fe9cSrandyf movl %cr3, %edx 1942df1fe9cSrandyf movl %edx, WC_CR3(%eax) 1952df1fe9cSrandyf movl %cr4, %edx 1962df1fe9cSrandyf movl %edx, WC_CR4(%eax) 1972df1fe9cSrandyf 1982df1fe9cSrandyf movl %ebx, WC_EBX(%eax) 1992df1fe9cSrandyf movl %edi, WC_EDI(%eax) 2002df1fe9cSrandyf movl %esi, WC_ESI(%eax) 2012df1fe9cSrandyf movl %ebp, WC_EBP(%eax) 2022df1fe9cSrandyf movl %esp, WC_ESP(%eax) 2032df1fe9cSrandyf 2042df1fe9cSrandyf movw %ss, WC_SS(%eax) 2052df1fe9cSrandyf movw %cs, WC_CS(%eax) 2062df1fe9cSrandyf movw %ds, WC_DS(%eax) 2072df1fe9cSrandyf movw %es, WC_ES(%eax) 2082df1fe9cSrandyf movw %fs, WC_FS(%eax) 2092df1fe9cSrandyf movw %gs, WC_GS(%eax) 2102df1fe9cSrandyf 2112df1fe9cSrandyf pushfl 2122df1fe9cSrandyf popl WC_EFLAGS(%eax) 2132df1fe9cSrandyf 2143d995820SJoseph A Townsend pushl %gs:CPU_ID / save current cpu id 2153d995820SJoseph A Townsend popl WC_CPU_ID(%eax) 2163d995820SJoseph A Townsend 2172df1fe9cSrandyf wbinvd / flush the cache 2183d995820SJoseph A Townsend mfence 2192df1fe9cSrandyf 2202df1fe9cSrandyf movl $1, %eax / at suspend return 1 2212df1fe9cSrandyf ret 2222df1fe9cSrandyf 2232df1fe9cSrandyf SET_SIZE(wc_save_context) 2242df1fe9cSrandyf 2252df1fe9cSrandyf#endif /* __amd64 */ 2262df1fe9cSrandyf 2272df1fe9cSrandyf#endif /* lint */ 2282df1fe9cSrandyf 2292df1fe9cSrandyf 2302df1fe9cSrandyf/* 2312df1fe9cSrandyf * Our assumptions: 2322df1fe9cSrandyf * - We are running in real mode. 2332df1fe9cSrandyf * - Interrupts are disabled. 2342df1fe9cSrandyf * 2352df1fe9cSrandyf * Our actions: 2362df1fe9cSrandyf * - We start using our GDT by loading correct values in the 2372df1fe9cSrandyf * selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL, 2382df1fe9cSrandyf * gs=KGS_SEL). 2392df1fe9cSrandyf * - We change over to using our IDT. 2402df1fe9cSrandyf * - We load the default LDT into the hardware LDT register. 2412df1fe9cSrandyf * - We load the default TSS into the hardware task register. 2422df1fe9cSrandyf * - We restore registers 2432df1fe9cSrandyf * - We return to original caller (a la setjmp) 2442df1fe9cSrandyf */ 2452df1fe9cSrandyf 2462df1fe9cSrandyf#if defined(lint) || defined(__lint) 2472df1fe9cSrandyf 2482df1fe9cSrandyfvoid 2492df1fe9cSrandyfwc_rm_start(void) 2502df1fe9cSrandyf{} 2512df1fe9cSrandyf 2522df1fe9cSrandyfvoid 2532df1fe9cSrandyfwc_rm_end(void) 2542df1fe9cSrandyf{} 2552df1fe9cSrandyf 2562df1fe9cSrandyf#else /* lint */ 2572df1fe9cSrandyf 2582df1fe9cSrandyf#if defined(__amd64) 2592df1fe9cSrandyf 2602df1fe9cSrandyf ENTRY_NP(wc_rm_start) 2612df1fe9cSrandyf 2622df1fe9cSrandyf /* 263*dad25528SRichard Lowe * For the Sun Studio 10 assembler we needed to do a .code32 and 264*dad25528SRichard Lowe * mentally invert the meaning of the addr16 and data16 prefixes to 265*dad25528SRichard Lowe * get 32-bit access when generating code to be executed in 16-bit 266*dad25528SRichard Lowe * mode (sigh...) 267*dad25528SRichard Lowe * 268*dad25528SRichard Lowe * This code, despite always being built with GNU as, has inherited 269*dad25528SRichard Lowe * the conceptual damage. 2702df1fe9cSrandyf */ 2712df1fe9cSrandyf 2722df1fe9cSrandyf .code32 2732df1fe9cSrandyf 2742df1fe9cSrandyf cli 2752df1fe9cSrandyf movw %cs, %ax 2762df1fe9cSrandyf movw %ax, %ds / establish ds ... 2772df1fe9cSrandyf movw %ax, %ss / ... and ss:esp 2782df1fe9cSrandyf D16 movl $WC_STKSTART, %esp 2792df1fe9cSrandyf/ using the following value blows up machines! - DO NOT USE 2802df1fe9cSrandyf/ D16 movl 0xffc, %esp 2812df1fe9cSrandyf 2822df1fe9cSrandyf 2832df1fe9cSrandyf#if LED 2841b1c71b2Sjan D16 movl $WC_LED, %edx 2852df1fe9cSrandyf D16 movb $0xd1, %al 2862df1fe9cSrandyf outb (%dx) 2872df1fe9cSrandyf#endif 2882df1fe9cSrandyf 2892df1fe9cSrandyf#if SERIAL 2901b1c71b2Sjan D16 movl $WC_COM, %edx 2912df1fe9cSrandyf D16 movb $0x61, %al 2922df1fe9cSrandyf outb (%dx) 2932df1fe9cSrandyf#endif 2942df1fe9cSrandyf 2952df1fe9cSrandyf D16 call cominit 2962df1fe9cSrandyf 2972df1fe9cSrandyf /* 2982df1fe9cSrandyf * Enable protected-mode, write protect, and alignment mask 2992df1fe9cSrandyf * %cr0 has already been initialsed to zero 3002df1fe9cSrandyf */ 3012df1fe9cSrandyf movl %cr0, %eax 302*dad25528SRichard Lowe D16 orl $_CONST(CR0_PE|CR0_WP|CR0_AM), %eax 3032df1fe9cSrandyf movl %eax, %cr0 3042df1fe9cSrandyf 3052df1fe9cSrandyf /* 3062df1fe9cSrandyf * Do a jmp immediately after writing to cr0 when enabling protected 3072df1fe9cSrandyf * mode to clear the real mode prefetch queue (per Intel's docs) 3082df1fe9cSrandyf */ 3092df1fe9cSrandyf jmp pestart 3102df1fe9cSrandyfpestart: 3112df1fe9cSrandyf 3122df1fe9cSrandyf#if LED 3131b1c71b2Sjan D16 movl $WC_LED, %edx 3142df1fe9cSrandyf D16 movb $0xd2, %al 3152df1fe9cSrandyf outb (%dx) 3162df1fe9cSrandyf#endif 3172df1fe9cSrandyf 3182df1fe9cSrandyf#if SERIAL 3191b1c71b2Sjan D16 movl $WC_COM, %edx 3202df1fe9cSrandyf D16 movb $0x62, %al 3212df1fe9cSrandyf outb (%dx) 3222df1fe9cSrandyf#endif 3232df1fe9cSrandyf 3242df1fe9cSrandyf /* 3252df1fe9cSrandyf * 16-bit protected mode is now active, so prepare to turn on long 3262df1fe9cSrandyf * mode 3272df1fe9cSrandyf */ 3282df1fe9cSrandyf 3292df1fe9cSrandyf#if LED 3301b1c71b2Sjan D16 movl $WC_LED, %edx 3312df1fe9cSrandyf D16 movb $0xd3, %al 3322df1fe9cSrandyf outb (%dx) 3332df1fe9cSrandyf#endif 3342df1fe9cSrandyf 3352df1fe9cSrandyf#if SERIAL 3361b1c71b2Sjan D16 movl $WC_COM, %edx 3372df1fe9cSrandyf D16 movb $0x63, %al 3382df1fe9cSrandyf outb (%dx) 3392df1fe9cSrandyf#endif 3402df1fe9cSrandyf 3412df1fe9cSrandyf /* 3422df1fe9cSrandyf * Add any initial cr4 bits 3432df1fe9cSrandyf */ 3442df1fe9cSrandyf movl %cr4, %eax 3452df1fe9cSrandyf A16 D16 orl CR4OFF, %eax 3462df1fe9cSrandyf 3472df1fe9cSrandyf /* 3482df1fe9cSrandyf * Enable PAE mode (CR4.PAE) 3492df1fe9cSrandyf */ 3502df1fe9cSrandyf D16 orl $CR4_PAE, %eax 3512df1fe9cSrandyf movl %eax, %cr4 3522df1fe9cSrandyf 3532df1fe9cSrandyf#if LED 3541b1c71b2Sjan D16 movl $WC_LED, %edx 3552df1fe9cSrandyf D16 movb $0xd4, %al 3562df1fe9cSrandyf outb (%dx) 3572df1fe9cSrandyf#endif 3582df1fe9cSrandyf 3592df1fe9cSrandyf#if SERIAL 3601b1c71b2Sjan D16 movl $WC_COM, %edx 3612df1fe9cSrandyf D16 movb $0x64, %al 3622df1fe9cSrandyf outb (%dx) 3632df1fe9cSrandyf#endif 3642df1fe9cSrandyf 3652df1fe9cSrandyf /* 3662df1fe9cSrandyf * Point cr3 to the 64-bit long mode page tables. 3672df1fe9cSrandyf * 3682df1fe9cSrandyf * Note that these MUST exist in 32-bit space, as we don't have 3692df1fe9cSrandyf * a way to load %cr3 with a 64-bit base address for the page tables 3702df1fe9cSrandyf * until the CPU is actually executing in 64-bit long mode. 3712df1fe9cSrandyf */ 3722df1fe9cSrandyf A16 D16 movl CR3OFF, %eax 3732df1fe9cSrandyf movl %eax, %cr3 3742df1fe9cSrandyf 3752df1fe9cSrandyf /* 3762df1fe9cSrandyf * Set long mode enable in EFER (EFER.LME = 1) 3772df1fe9cSrandyf */ 3782df1fe9cSrandyf D16 movl $MSR_AMD_EFER, %ecx 3792df1fe9cSrandyf rdmsr 3802df1fe9cSrandyf 3812df1fe9cSrandyf D16 orl $AMD_EFER_LME, %eax 3822df1fe9cSrandyf wrmsr 3832df1fe9cSrandyf 3842df1fe9cSrandyf#if LED 3851b1c71b2Sjan D16 movl $WC_LED, %edx 3862df1fe9cSrandyf D16 movb $0xd5, %al 3872df1fe9cSrandyf outb (%dx) 3882df1fe9cSrandyf#endif 3892df1fe9cSrandyf 3902df1fe9cSrandyf#if SERIAL 3911b1c71b2Sjan D16 movl $WC_COM, %edx 3922df1fe9cSrandyf D16 movb $0x65, %al 3932df1fe9cSrandyf outb (%dx) 3942df1fe9cSrandyf#endif 3952df1fe9cSrandyf 3962df1fe9cSrandyf /* 3972df1fe9cSrandyf * Finally, turn on paging (CR0.PG = 1) to activate long mode. 3982df1fe9cSrandyf */ 3992df1fe9cSrandyf movl %cr0, %eax 4002df1fe9cSrandyf D16 orl $CR0_PG, %eax 4012df1fe9cSrandyf movl %eax, %cr0 4022df1fe9cSrandyf 4032df1fe9cSrandyf /* 4042df1fe9cSrandyf * The instruction after enabling paging in CR0 MUST be a branch. 4052df1fe9cSrandyf */ 4062df1fe9cSrandyf jmp long_mode_active 4072df1fe9cSrandyf 4082df1fe9cSrandyflong_mode_active: 4092df1fe9cSrandyf 4102df1fe9cSrandyf#if LED 4111b1c71b2Sjan D16 movl $WC_LED, %edx 4122df1fe9cSrandyf D16 movb $0xd6, %al 4132df1fe9cSrandyf outb (%dx) 4142df1fe9cSrandyf#endif 4152df1fe9cSrandyf 4162df1fe9cSrandyf#if SERIAL 4171b1c71b2Sjan D16 movl $WC_COM, %edx 4182df1fe9cSrandyf D16 movb $0x66, %al 4192df1fe9cSrandyf outb (%dx) 4202df1fe9cSrandyf#endif 4212df1fe9cSrandyf 4222df1fe9cSrandyf /* 4232df1fe9cSrandyf * Long mode is now active but since we're still running with the 4242df1fe9cSrandyf * original 16-bit CS we're actually in 16-bit compatability mode. 4252df1fe9cSrandyf * 4262df1fe9cSrandyf * We have to load an intermediate GDT and IDT here that we know are 4272df1fe9cSrandyf * in 32-bit space before we can use the kernel's GDT and IDT, which 4282df1fe9cSrandyf * may be in the 64-bit address space, and since we're in compatability 4292df1fe9cSrandyf * mode, we only have access to 16 and 32-bit instructions at the 4302df1fe9cSrandyf * moment. 4312df1fe9cSrandyf */ 4322df1fe9cSrandyf A16 D16 lgdt TEMPGDTOFF /* load temporary GDT */ 4332df1fe9cSrandyf A16 D16 lidt TEMPIDTOFF /* load temporary IDT */ 4342df1fe9cSrandyf 4352df1fe9cSrandyf 4362df1fe9cSrandyf /* 4372df1fe9cSrandyf * Do a far transfer to 64-bit mode. Set the CS selector to a 64-bit 4382df1fe9cSrandyf * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump 4392df1fe9cSrandyf * to the real mode platter address of wc_long_mode_64 as until the 4402df1fe9cSrandyf * 64-bit CS is in place we don't have access to 64-bit instructions 4412df1fe9cSrandyf * and thus can't reference a 64-bit %rip. 4422df1fe9cSrandyf */ 4432df1fe9cSrandyf 4442df1fe9cSrandyf#if LED 4451b1c71b2Sjan D16 movl $WC_LED, %edx 4462df1fe9cSrandyf D16 movb $0xd7, %al 4472df1fe9cSrandyf outb (%dx) 4482df1fe9cSrandyf#endif 4492df1fe9cSrandyf 4502df1fe9cSrandyf#if SERIAL 4511b1c71b2Sjan D16 movl $WC_COM, %edx 4522df1fe9cSrandyf D16 movb $0x67, %al 4532df1fe9cSrandyf outb (%dx) 4542df1fe9cSrandyf#endif 4552df1fe9cSrandyf 4562df1fe9cSrandyf D16 pushl $TEMP_CS64_SEL 4572df1fe9cSrandyf A16 D16 pushl LM64OFF 4582df1fe9cSrandyf 4592df1fe9cSrandyf D16 lret 4602df1fe9cSrandyf 4612df1fe9cSrandyf 4622df1fe9cSrandyf/* 4632df1fe9cSrandyf * Support routine to re-initialize VGA subsystem 4642df1fe9cSrandyf */ 4652df1fe9cSrandyfvgainit: 4662df1fe9cSrandyf D16 ret 4672df1fe9cSrandyf 4682df1fe9cSrandyf/* 4692df1fe9cSrandyf * Support routine to re-initialize keyboard (which is USB - help!) 4702df1fe9cSrandyf */ 4712df1fe9cSrandyfkbdinit: 4722df1fe9cSrandyf D16 ret 4732df1fe9cSrandyf 4742df1fe9cSrandyf/* 4752df1fe9cSrandyf * Support routine to re-initialize COM ports to something sane 4762df1fe9cSrandyf */ 4772df1fe9cSrandyfcominit: 4782df1fe9cSrandyf / init COM1 & COM2 4791b1c71b2Sjan 4801b1c71b2Sjan#if DEBUG 4811b1c71b2Sjan/* 4821b1c71b2Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that 4831b1c71b2Sjan * we can get debug output before the asy driver has resumed 4841b1c71b2Sjan */ 4851b1c71b2Sjan 4861b1c71b2Sjan/ select COM1 487*dad25528SRichard Lowe D16 movl $_CONST(COM1+LCR), %edx 4881b1c71b2Sjan D16 movb $DLAB, %al / divisor latch 4891b1c71b2Sjan outb (%dx) 4901b1c71b2Sjan 491*dad25528SRichard Lowe D16 movl $_CONST(COM1+DLL), %edx / divisor latch lsb 4921b1c71b2Sjan D16 movb $B9600L, %al / divisor latch 4931b1c71b2Sjan outb (%dx) 4941b1c71b2Sjan 495*dad25528SRichard Lowe D16 movl $_CONST(COM1+DLH), %edx / divisor latch hsb 4961b1c71b2Sjan D16 movb $B9600H, %al / divisor latch 4971b1c71b2Sjan outb (%dx) 4981b1c71b2Sjan 499*dad25528SRichard Lowe D16 movl $_CONST(COM1+LCR), %edx / select COM1 500*dad25528SRichard Lowe D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len 5011b1c71b2Sjan outb (%dx) 5021b1c71b2Sjan 503*dad25528SRichard Lowe D16 movl $_CONST(COM1+MCR), %edx / select COM1 504*dad25528SRichard Lowe D16 movb $_CONST(RTS|DTR), %al / data term ready & req to send 5051b1c71b2Sjan outb (%dx) 5061b1c71b2Sjan 5071b1c71b2Sjan/ select COM2 508*dad25528SRichard Lowe D16 movl $_CONST(COM2+LCR), %edx 5091b1c71b2Sjan D16 movb $DLAB, %al / divisor latch 5101b1c71b2Sjan outb (%dx) 5111b1c71b2Sjan 512*dad25528SRichard Lowe D16 movl $_CONST(COM2+DLL), %edx / divisor latch lsb 5131b1c71b2Sjan D16 movb $B9600L, %al / divisor latch 5141b1c71b2Sjan outb (%dx) 5151b1c71b2Sjan 516*dad25528SRichard Lowe D16 movl $_CONST(COM2+DLH), %edx / divisor latch hsb 5171b1c71b2Sjan D16 movb $B9600H, %al / divisor latch 5181b1c71b2Sjan outb (%dx) 5191b1c71b2Sjan 520*dad25528SRichard Lowe D16 movl $_CONST(COM2+LCR), %edx / select COM1 521*dad25528SRichard Lowe D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len 5221b1c71b2Sjan outb (%dx) 5231b1c71b2Sjan 524*dad25528SRichard Lowe D16 movl $_CONST(COM2+MCR), %edx / select COM1 525*dad25528SRichard Lowe D16 movb $_CONST(RTS|DTR), %al / data term ready & req to send 5261b1c71b2Sjan outb (%dx) 5271b1c71b2Sjan#endif /* DEBUG */ 5281b1c71b2Sjan 5292df1fe9cSrandyf D16 ret 5302df1fe9cSrandyf 5312df1fe9cSrandyf .code64 5322df1fe9cSrandyf 5332df1fe9cSrandyf .globl wc_long_mode_64 5342df1fe9cSrandyfwc_long_mode_64: 5352df1fe9cSrandyf 5362df1fe9cSrandyf#if LED 5371b1c71b2Sjan movw $WC_LED, %dx 5382df1fe9cSrandyf movb $0xd8, %al 5392df1fe9cSrandyf outb (%dx) 5402df1fe9cSrandyf#endif 5412df1fe9cSrandyf 5422df1fe9cSrandyf#if SERIAL 5431b1c71b2Sjan movw $WC_COM, %dx 5442df1fe9cSrandyf movb $0x68, %al 5452df1fe9cSrandyf outb (%dx) 5462df1fe9cSrandyf#endif 5472df1fe9cSrandyf 5482df1fe9cSrandyf /* 5492df1fe9cSrandyf * We are now running in long mode with a 64-bit CS (EFER.LMA=1, 5502df1fe9cSrandyf * CS.L=1) so we now have access to 64-bit instructions. 5512df1fe9cSrandyf * 5522df1fe9cSrandyf * First, set the 64-bit GDT base. 5532df1fe9cSrandyf */ 5542df1fe9cSrandyf .globl rm_platter_pa 5552df1fe9cSrandyf movl rm_platter_pa, %eax 5562df1fe9cSrandyf 5572df1fe9cSrandyf lgdtq GDTROFF(%rax) /* load 64-bit GDT */ 5582df1fe9cSrandyf 5592df1fe9cSrandyf /* 5602df1fe9cSrandyf * Save the CPU number in %r11; get the value here since it's saved in 5612df1fe9cSrandyf * the real mode platter. 5622df1fe9cSrandyf */ 5632df1fe9cSrandyf/ JAN 5642df1fe9cSrandyf/ the following is wrong! need to figure out MP systems 5652df1fe9cSrandyf/ movl CPUNOFF(%rax), %r11d 5662df1fe9cSrandyf 5672df1fe9cSrandyf /* 5682df1fe9cSrandyf * Add rm_platter_pa to %rsp to point it to the same location as seen 5692df1fe9cSrandyf * from 64-bit mode. 5702df1fe9cSrandyf */ 5712df1fe9cSrandyf addq %rax, %rsp 5722df1fe9cSrandyf 5732df1fe9cSrandyf /* 5742df1fe9cSrandyf * Now do an lretq to load CS with the appropriate selector for the 5752df1fe9cSrandyf * kernel's 64-bit GDT and to start executing 64-bit setup code at the 5762df1fe9cSrandyf * virtual address where boot originally loaded this code rather than 5772df1fe9cSrandyf * the copy in the real mode platter's rm_code array as we've been 5782df1fe9cSrandyf * doing so far. 5792df1fe9cSrandyf */ 5802df1fe9cSrandyf 5812df1fe9cSrandyf#if LED 5821b1c71b2Sjan movw $WC_LED, %dx 5832df1fe9cSrandyf movb $0xd9, %al 5842df1fe9cSrandyf outb (%dx) 5852df1fe9cSrandyf#endif 5862df1fe9cSrandyf 5872df1fe9cSrandyf/ JAN this should produce 'i' but we get 'g' instead ??? 5882df1fe9cSrandyf#if SERIAL 5891b1c71b2Sjan movw $WC_COM, %dx 5902df1fe9cSrandyf movb $0x69, %al 5912df1fe9cSrandyf outb (%dx) 5922df1fe9cSrandyf#endif 5932df1fe9cSrandyf 5942df1fe9cSrandyf pushq $KCS_SEL 5952df1fe9cSrandyf pushq $kernel_wc_code 5962df1fe9cSrandyf lretq 5972df1fe9cSrandyf 5982df1fe9cSrandyf .globl kernel_wc_code 5992df1fe9cSrandyfkernel_wc_code: 6002df1fe9cSrandyf 6012df1fe9cSrandyf#if LED 6021b1c71b2Sjan movw $WC_LED, %dx 6032df1fe9cSrandyf movb $0xda, %al 6042df1fe9cSrandyf outb (%dx) 6052df1fe9cSrandyf#endif 6062df1fe9cSrandyf 6072df1fe9cSrandyf/ JAN this should produce 'j' but we get 'g' instead ??? 6082df1fe9cSrandyf#if SERIAL 6091b1c71b2Sjan movw $WC_COM, %dx 6102df1fe9cSrandyf movb $0x6a, %al 6112df1fe9cSrandyf outb (%dx) 6122df1fe9cSrandyf#endif 6132df1fe9cSrandyf 6142df1fe9cSrandyf /* 6152df1fe9cSrandyf * Complete the balance of the setup we need to before executing 6162df1fe9cSrandyf * 64-bit kernel code (namely init rsp, TSS, LGDT, FS and GS). 6172df1fe9cSrandyf */ 6182df1fe9cSrandyf .globl rm_platter_va 6192df1fe9cSrandyf movq rm_platter_va, %rbx 6202df1fe9cSrandyf addq $WC_CPU, %rbx 6212df1fe9cSrandyf 6222df1fe9cSrandyf#if LED 6231b1c71b2Sjan movw $WC_LED, %dx 6242df1fe9cSrandyf movb $0xdb, %al 6252df1fe9cSrandyf outb (%dx) 6262df1fe9cSrandyf#endif 6272df1fe9cSrandyf 6282df1fe9cSrandyf#if SERIAL 6291b1c71b2Sjan movw $WC_COM, %dx 6302df1fe9cSrandyf movw $0x6b, %ax 6312df1fe9cSrandyf outb (%dx) 6322df1fe9cSrandyf#endif 6332df1fe9cSrandyf 6342df1fe9cSrandyf /* 6352df1fe9cSrandyf * restore the rest of the registers 6362df1fe9cSrandyf */ 6372df1fe9cSrandyf 6382df1fe9cSrandyf lidtq WC_IDT(%rbx) 6392df1fe9cSrandyf 6402df1fe9cSrandyf#if LED 6411b1c71b2Sjan movw $WC_LED, %dx 6422df1fe9cSrandyf movb $0xdc, %al 6432df1fe9cSrandyf outb (%dx) 6442df1fe9cSrandyf#endif 6452df1fe9cSrandyf 6462df1fe9cSrandyf#if SERIAL 6471b1c71b2Sjan movw $WC_COM, %dx 6482df1fe9cSrandyf movw $0x6c, %ax 6492df1fe9cSrandyf outb (%dx) 6502df1fe9cSrandyf#endif 6512df1fe9cSrandyf 6522df1fe9cSrandyf /* 6532df1fe9cSrandyf * restore the rest of the registers 6542df1fe9cSrandyf */ 6552df1fe9cSrandyf 6562df1fe9cSrandyf movw $KDS_SEL, %ax 6572df1fe9cSrandyf movw %ax, %ds 6582df1fe9cSrandyf movw %ax, %es 6592df1fe9cSrandyf movw %ax, %ss 6602df1fe9cSrandyf 6612df1fe9cSrandyf /* 6622df1fe9cSrandyf * Before proceeding, enable usage of the page table NX bit if 6632df1fe9cSrandyf * that's how the page tables are set up. 6642df1fe9cSrandyf */ 665dfea898aSKuriakose Kuruvilla bt $X86FSET_NX, x86_featureset(%rip) 6667417cfdeSKuriakose Kuruvilla jnc 1f 6672df1fe9cSrandyf movl $MSR_AMD_EFER, %ecx 6682df1fe9cSrandyf rdmsr 6692df1fe9cSrandyf orl $AMD_EFER_NXE, %eax 6702df1fe9cSrandyf wrmsr 6712df1fe9cSrandyf1: 6722df1fe9cSrandyf 6732df1fe9cSrandyf movq WC_CR4(%rbx), %rax / restore full cr4 (with Global Enable) 6742df1fe9cSrandyf movq %rax, %cr4 6752df1fe9cSrandyf 6762df1fe9cSrandyf lldt WC_LDT(%rbx) 6772df1fe9cSrandyf movzwq WC_TR(%rbx), %rax / clear TSS busy bit 6782df1fe9cSrandyf addq WC_GDT+2(%rbx), %rax 6792df1fe9cSrandyf andl $0xfffffdff, 4(%rax) 6802df1fe9cSrandyf movq 4(%rax), %rcx 6812df1fe9cSrandyf ltr WC_TR(%rbx) 6822df1fe9cSrandyf 6832df1fe9cSrandyf#if LED 6841b1c71b2Sjan movw $WC_LED, %dx 6852df1fe9cSrandyf movb $0xdd, %al 6862df1fe9cSrandyf outb (%dx) 6872df1fe9cSrandyf#endif 6882df1fe9cSrandyf 6892df1fe9cSrandyf#if SERIAL 6901b1c71b2Sjan movw $WC_COM, %dx 6912df1fe9cSrandyf movw $0x6d, %ax 6922df1fe9cSrandyf outb (%dx) 6932df1fe9cSrandyf#endif 6942df1fe9cSrandyf 6952df1fe9cSrandyf/ restore %fsbase %gsbase %kgbase registers using wrmsr instruction 6962df1fe9cSrandyf 6972df1fe9cSrandyf movq WC_FS(%rbx), %rcx / restore fs register 6982df1fe9cSrandyf movw %cx, %fs 6992df1fe9cSrandyf 7002df1fe9cSrandyf movl $MSR_AMD_FSBASE, %ecx 7012df1fe9cSrandyf movl WC_FSBASE(%rbx), %eax 7022df1fe9cSrandyf movl WC_FSBASE+4(%rbx), %edx 7032df1fe9cSrandyf wrmsr 7042df1fe9cSrandyf 7052df1fe9cSrandyf movq WC_GS(%rbx), %rcx / restore gs register 7062df1fe9cSrandyf movw %cx, %gs 7072df1fe9cSrandyf 7082df1fe9cSrandyf movl $MSR_AMD_GSBASE, %ecx / restore gsbase msr 7092df1fe9cSrandyf movl WC_GSBASE(%rbx), %eax 7102df1fe9cSrandyf movl WC_GSBASE+4(%rbx), %edx 7112df1fe9cSrandyf wrmsr 7122df1fe9cSrandyf 7132df1fe9cSrandyf movl $MSR_AMD_KGSBASE, %ecx / restore kgsbase msr 7142df1fe9cSrandyf movl WC_KGSBASE(%rbx), %eax 7152df1fe9cSrandyf movl WC_KGSBASE+4(%rbx), %edx 7162df1fe9cSrandyf wrmsr 7172df1fe9cSrandyf 7182df1fe9cSrandyf movq WC_CR0(%rbx), %rdx 7192df1fe9cSrandyf movq %rdx, %cr0 7202df1fe9cSrandyf movq WC_CR3(%rbx), %rdx 7212df1fe9cSrandyf movq %rdx, %cr3 7222df1fe9cSrandyf movq WC_CR8(%rbx), %rdx 7232df1fe9cSrandyf movq %rdx, %cr8 7242df1fe9cSrandyf 7252df1fe9cSrandyf#if LED 7261b1c71b2Sjan movw $WC_LED, %dx 7272df1fe9cSrandyf movb $0xde, %al 7282df1fe9cSrandyf outb (%dx) 7292df1fe9cSrandyf#endif 7302df1fe9cSrandyf 7312df1fe9cSrandyf#if SERIAL 7321b1c71b2Sjan movw $WC_COM, %dx 7332df1fe9cSrandyf movb $0x6e, %al 7342df1fe9cSrandyf outb (%dx) 7352df1fe9cSrandyf#endif 7362df1fe9cSrandyf 7373d995820SJoseph A Townsend /* 7383d995820SJoseph A Townsend * if we are not running on the boot CPU restore stack contents by 7393d995820SJoseph A Townsend * calling i_cpr_restore_stack(curthread, save_stack); 7403d995820SJoseph A Townsend */ 7413d995820SJoseph A Townsend movq %rsp, %rbp 7423d995820SJoseph A Townsend call i_cpr_bootcpuid 7433d995820SJoseph A Townsend cmpl %eax, WC_CPU_ID(%rbx) 7443d995820SJoseph A Townsend je 2f 7453d995820SJoseph A Townsend 7463d995820SJoseph A Townsend movq %gs:CPU_THREAD, %rdi 7473d995820SJoseph A Townsend movq WC_SAVED_STACK(%rbx), %rsi 7483d995820SJoseph A Townsend call i_cpr_restore_stack 7493d995820SJoseph A Townsend2: 7503d995820SJoseph A Townsend 7513d995820SJoseph A Townsend movq WC_RSP(%rbx), %rsp / restore stack pointer 7522df1fe9cSrandyf 7532df1fe9cSrandyf /* 754bc446630SGuoli Shu * APIC initialization 7552df1fe9cSrandyf */ 7563d995820SJoseph A Townsend movq %rsp, %rbp 7572df1fe9cSrandyf 7584716fd88Sjan /* 7594716fd88Sjan * skip iff function pointer is NULL 7604716fd88Sjan */ 7614716fd88Sjan cmpq $0, ap_mlsetup 7623d995820SJoseph A Townsend je 3f 7632df1fe9cSrandyf call *ap_mlsetup 7643d995820SJoseph A Townsend3: 7652df1fe9cSrandyf 7662df1fe9cSrandyf call *cpr_start_cpu_func 7672df1fe9cSrandyf 7682df1fe9cSrandyf/ restore %rbx to the value it ahd before we called the functions above 7692df1fe9cSrandyf movq rm_platter_va, %rbx 7702df1fe9cSrandyf addq $WC_CPU, %rbx 7712df1fe9cSrandyf 7722df1fe9cSrandyf movq WC_R8(%rbx), %r8 7732df1fe9cSrandyf movq WC_R9(%rbx), %r9 7742df1fe9cSrandyf movq WC_R10(%rbx), %r10 7752df1fe9cSrandyf movq WC_R11(%rbx), %r11 7762df1fe9cSrandyf movq WC_R12(%rbx), %r12 7772df1fe9cSrandyf movq WC_R13(%rbx), %r13 7782df1fe9cSrandyf movq WC_R14(%rbx), %r14 7792df1fe9cSrandyf movq WC_R15(%rbx), %r15 7802df1fe9cSrandyf/ movq WC_RAX(%rbx), %rax 7812df1fe9cSrandyf movq WC_RBP(%rbx), %rbp 7822df1fe9cSrandyf movq WC_RCX(%rbx), %rcx 7832df1fe9cSrandyf/ movq WC_RDX(%rbx), %rdx 7842df1fe9cSrandyf movq WC_RDI(%rbx), %rdi 7852df1fe9cSrandyf movq WC_RSI(%rbx), %rsi 7862df1fe9cSrandyf 7872df1fe9cSrandyf 7882df1fe9cSrandyf/ assume that %cs does not need to be restored 7892df1fe9cSrandyf/ %ds, %es & %ss are ignored in 64bit mode 7902df1fe9cSrandyf movw WC_SS(%rbx), %ss 7912df1fe9cSrandyf movw WC_DS(%rbx), %ds 7922df1fe9cSrandyf movw WC_ES(%rbx), %es 7932df1fe9cSrandyf 7942df1fe9cSrandyf#if LED 7951b1c71b2Sjan movw $WC_LED, %dx 7962df1fe9cSrandyf movb $0xdf, %al 7972df1fe9cSrandyf outb (%dx) 7982df1fe9cSrandyf#endif 7992df1fe9cSrandyf 8002df1fe9cSrandyf#if SERIAL 8011b1c71b2Sjan movw $WC_COM, %dx 8022df1fe9cSrandyf movb $0x6f, %al 8032df1fe9cSrandyf outb (%dx) 8042df1fe9cSrandyf#endif 8052df1fe9cSrandyf 8062df1fe9cSrandyf 8072df1fe9cSrandyf movq WC_RBP(%rbx), %rbp 8082df1fe9cSrandyf movq WC_RSP(%rbx), %rsp 8092df1fe9cSrandyf 8102df1fe9cSrandyf#if LED 8111b1c71b2Sjan movw $WC_LED, %dx 8122df1fe9cSrandyf movb $0xe0, %al 8132df1fe9cSrandyf outb (%dx) 8142df1fe9cSrandyf#endif 8152df1fe9cSrandyf 8162df1fe9cSrandyf#if SERIAL 8171b1c71b2Sjan movw $WC_COM, %dx 8182df1fe9cSrandyf movb $0x70, %al 8192df1fe9cSrandyf outb (%dx) 8202df1fe9cSrandyf#endif 8212df1fe9cSrandyf 8222df1fe9cSrandyf 8232df1fe9cSrandyf movq WC_RCX(%rbx), %rcx 8242df1fe9cSrandyf 8252df1fe9cSrandyf pushq WC_EFLAGS(%rbx) / restore flags 8262df1fe9cSrandyf popfq 8272df1fe9cSrandyf 8282df1fe9cSrandyf#if LED 8291b1c71b2Sjan movw $WC_LED, %dx 8302df1fe9cSrandyf movb $0xe1, %al 8312df1fe9cSrandyf outb (%dx) 8322df1fe9cSrandyf#endif 8332df1fe9cSrandyf 8342df1fe9cSrandyf#if SERIAL 8351b1c71b2Sjan movw $WC_COM, %dx 8362df1fe9cSrandyf movb $0x71, %al 8372df1fe9cSrandyf outb (%dx) 8382df1fe9cSrandyf#endif 8392df1fe9cSrandyf 8402df1fe9cSrandyf/* 8412df1fe9cSrandyf * can not use outb after this point, because doing so would mean using 8422df1fe9cSrandyf * %dx which would modify %rdx which is restored here 8432df1fe9cSrandyf */ 8442df1fe9cSrandyf 8452df1fe9cSrandyf movq %rbx, %rax 8462df1fe9cSrandyf movq WC_RDX(%rax), %rdx 8472df1fe9cSrandyf movq WC_RBX(%rax), %rbx 8482df1fe9cSrandyf 8492df1fe9cSrandyf leave 8502df1fe9cSrandyf 8512df1fe9cSrandyf movq WC_RETADDR(%rax), %rax 8522df1fe9cSrandyf movq %rax, (%rsp) / return to caller of wc_save_context 8532df1fe9cSrandyf 8542df1fe9cSrandyf xorl %eax, %eax / at wakeup return 0 8552df1fe9cSrandyf ret 8562df1fe9cSrandyf 8572df1fe9cSrandyf 8582df1fe9cSrandyf SET_SIZE(wc_rm_start) 8592df1fe9cSrandyf 8602df1fe9cSrandyf ENTRY_NP(asmspin) 8612df1fe9cSrandyf 8622df1fe9cSrandyf movl %edi, %ecx 8632df1fe9cSrandyfA1: 8642df1fe9cSrandyf loop A1 8652df1fe9cSrandyf 8662df1fe9cSrandyf SET_SIZE(asmspin) 8672df1fe9cSrandyf 8682df1fe9cSrandyf .globl wc_rm_end 8692df1fe9cSrandyfwc_rm_end: 8702df1fe9cSrandyf nop 8712df1fe9cSrandyf 8722df1fe9cSrandyf#elif defined(__i386) 8732df1fe9cSrandyf 8742df1fe9cSrandyf ENTRY_NP(wc_rm_start) 8752df1fe9cSrandyf 8762df1fe9cSrandyf/entry: jmp entry / stop here for HDT 8772df1fe9cSrandyf 8782df1fe9cSrandyf cli 8792df1fe9cSrandyf movw %cs, %ax 8802df1fe9cSrandyf movw %ax, %ds / establish ds ... 8812df1fe9cSrandyf movw %ax, %ss / ... and ss:esp 8822df1fe9cSrandyf D16 movl $WC_STKSTART, %esp 8832df1fe9cSrandyf 8842df1fe9cSrandyf#if LED 8851b1c71b2Sjan D16 movl $WC_LED, %edx 8862df1fe9cSrandyf D16 movb $0xd1, %al 8872df1fe9cSrandyf outb (%dx) 8882df1fe9cSrandyf#endif 8892df1fe9cSrandyf 8902df1fe9cSrandyf#if SERIAL 8911b1c71b2Sjan D16 movl $WC_COM, %edx 8922df1fe9cSrandyf D16 movb $0x61, %al 8932df1fe9cSrandyf outb (%dx) 8942df1fe9cSrandyf#endif 8952df1fe9cSrandyf 8962df1fe9cSrandyf 8972df1fe9cSrandyf D16 call vgainit 8982df1fe9cSrandyf D16 call kbdinit 8992df1fe9cSrandyf D16 call cominit 9002df1fe9cSrandyf 9012df1fe9cSrandyf#if LED 9021b1c71b2Sjan D16 movl $WC_LED, %edx 9032df1fe9cSrandyf D16 movb $0xd2, %al 9042df1fe9cSrandyf outb (%dx) 9052df1fe9cSrandyf#endif 9062df1fe9cSrandyf 9072df1fe9cSrandyf#if SERIAL 9081b1c71b2Sjan D16 movl $WC_COM, %edx 9092df1fe9cSrandyf D16 movb $0x62, %al 9102df1fe9cSrandyf outb (%dx) 9112df1fe9cSrandyf#endif 9122df1fe9cSrandyf 9132df1fe9cSrandyf D16 A16 movl $WC_CPU, %ebx / base add of wc_cpu_t 9142df1fe9cSrandyf 9152df1fe9cSrandyf#if LED 9162df1fe9cSrandyf D16 movb $0xd3, %al 9171b1c71b2Sjan outb $WC_LED 9182df1fe9cSrandyf#endif 9192df1fe9cSrandyf 9202df1fe9cSrandyf#if SERIAL 9211b1c71b2Sjan D16 movl $WC_COM, %edx 9222df1fe9cSrandyf D16 movb $0x63, %al 9232df1fe9cSrandyf outb (%dx) 9242df1fe9cSrandyf#endif 9252df1fe9cSrandyf 9262df1fe9cSrandyf D16 A16 movl %cs:WC_DS(%ebx), %edx / %ds post prot/paging transit 9272df1fe9cSrandyf 9281b1c71b2Sjan#if LED 9292df1fe9cSrandyf D16 movb $0xd4, %al 9301b1c71b2Sjan outb $WC_LED 9311b1c71b2Sjan#endif 9322df1fe9cSrandyf 9332df1fe9cSrandyf D16 A16 lgdt %cs:WC_GDT(%ebx) / restore gdt and idtr 9342df1fe9cSrandyf D16 A16 lidt %cs:WC_IDT(%ebx) 9352df1fe9cSrandyf 9361b1c71b2Sjan#if LED 9372df1fe9cSrandyf D16 movb $0xd5, %al 9381b1c71b2Sjan outb $WC_LED 9391b1c71b2Sjan#endif 9402df1fe9cSrandyf 9412df1fe9cSrandyf D16 A16 movl %cs:WC_CR4(%ebx), %eax / restore cr4 942*dad25528SRichard Lowe D16 andl $_BITNOT(CR4_PGE), %eax / don't set Global Enable yet 9432df1fe9cSrandyf movl %eax, %cr4 9442df1fe9cSrandyf 9451b1c71b2Sjan#if LED 9462df1fe9cSrandyf D16 movb $0xd6, %al 9471b1c71b2Sjan outb $WC_LED 9481b1c71b2Sjan#endif 9492df1fe9cSrandyf 9502df1fe9cSrandyf D16 A16 movl %cs:WC_CR3(%ebx), %eax / set PDPT 9512df1fe9cSrandyf movl %eax, %cr3 9522df1fe9cSrandyf 9531b1c71b2Sjan#if LED 9542df1fe9cSrandyf D16 movb $0xd7, %al 9551b1c71b2Sjan outb $WC_LED 9561b1c71b2Sjan#endif 9572df1fe9cSrandyf 9582df1fe9cSrandyf D16 A16 movl %cs:WC_CR0(%ebx), %eax / enable prot/paging, etc. 9592df1fe9cSrandyf movl %eax, %cr0 9602df1fe9cSrandyf 9611b1c71b2Sjan#if LED 9622df1fe9cSrandyf D16 movb $0xd8, %al 9631b1c71b2Sjan outb $WC_LED 9641b1c71b2Sjan#endif 9652df1fe9cSrandyf 9662df1fe9cSrandyf D16 A16 movl %cs:WC_VIRTADDR(%ebx), %ebx / virtaddr of wc_cpu_t 9672df1fe9cSrandyf 9681b1c71b2Sjan#if LED 9692df1fe9cSrandyf D16 movb $0xd9, %al 9701b1c71b2Sjan outb $WC_LED 9711b1c71b2Sjan#endif 9722df1fe9cSrandyf 9731b1c71b2Sjan#if LED 9742df1fe9cSrandyf D16 movb $0xda, %al 9751b1c71b2Sjan outb $WC_LED 9761b1c71b2Sjan#endif 9771b1c71b2Sjan 9782df1fe9cSrandyf jmp flush / flush prefetch queue 9792df1fe9cSrandyfflush: 9802df1fe9cSrandyf D16 pushl $KCS_SEL 9812df1fe9cSrandyf D16 pushl $kernel_wc_code 9822df1fe9cSrandyf D16 lret / re-appear at kernel_wc_code 9832df1fe9cSrandyf 9842df1fe9cSrandyf 9852df1fe9cSrandyf/* 9862df1fe9cSrandyf * Support routine to re-initialize VGA subsystem 9872df1fe9cSrandyf */ 9882df1fe9cSrandyfvgainit: 9892df1fe9cSrandyf D16 ret 9902df1fe9cSrandyf 9912df1fe9cSrandyf/* 9922df1fe9cSrandyf * Support routine to re-initialize keyboard (which is USB - help!) 9932df1fe9cSrandyf */ 9942df1fe9cSrandyfkbdinit: 9952df1fe9cSrandyf D16 ret 9962df1fe9cSrandyf 9972df1fe9cSrandyf/* 9982df1fe9cSrandyf * Support routine to re-initialize COM ports to something sane for debug output 9992df1fe9cSrandyf */ 10002df1fe9cSrandyfcominit: 10011b1c71b2Sjan#if DEBUG 10021b1c71b2Sjan/* 10031b1c71b2Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that 10041b1c71b2Sjan * we can get debug output before the asy driver has resumed 10051b1c71b2Sjan */ 10061b1c71b2Sjan 10071b1c71b2Sjan/ select COM1 1008*dad25528SRichard Lowe D16 movl $_CONST(COM1+LCR), %edx 10091b1c71b2Sjan D16 movb $DLAB, %al / divisor latch 10101b1c71b2Sjan outb (%dx) 10111b1c71b2Sjan 1012*dad25528SRichard Lowe D16 movl $_CONST(COM1+DLL), %edx / divisor latch lsb 10131b1c71b2Sjan D16 movb $B9600L, %al / divisor latch 10141b1c71b2Sjan outb (%dx) 10151b1c71b2Sjan 1016*dad25528SRichard Lowe D16 movl $_CONST(COM1+DLH), %edx / divisor latch hsb 10171b1c71b2Sjan D16 movb $B9600H, %al / divisor latch 10181b1c71b2Sjan outb (%dx) 10191b1c71b2Sjan 1020*dad25528SRichard Lowe D16 movl $_CONST(COM1+LCR), %edx / select COM1 1021*dad25528SRichard Lowe D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len 10221b1c71b2Sjan outb (%dx) 10231b1c71b2Sjan 1024*dad25528SRichard Lowe D16 movl $_CONST(COM1+MCR), %edx / select COM1 1025*dad25528SRichard Lowe D16 movb $_CONST(RTS|DTR), %al / 1 stop bit, 8bit word len 10261b1c71b2Sjan outb (%dx) 10271b1c71b2Sjan 10281b1c71b2Sjan/ select COM2 1029*dad25528SRichard Lowe D16 movl $_CONST(COM2+LCR), %edx 10301b1c71b2Sjan D16 movb $DLAB, %al / divisor latch 10311b1c71b2Sjan outb (%dx) 10321b1c71b2Sjan 1033*dad25528SRichard Lowe D16 movl $_CONST(COM2+DLL), %edx / divisor latch lsb 10341b1c71b2Sjan D16 movb $B9600L, %al / divisor latch 10351b1c71b2Sjan outb (%dx) 10361b1c71b2Sjan 1037*dad25528SRichard Lowe D16 movl $_CONST(COM2+DLH), %edx / divisor latch hsb 10381b1c71b2Sjan D16 movb $B9600H, %al / divisor latch 10391b1c71b2Sjan outb (%dx) 10401b1c71b2Sjan 1041*dad25528SRichard Lowe D16 movl $_CONST(COM2+LCR), %edx / select COM1 1042*dad25528SRichard Lowe D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len 10431b1c71b2Sjan outb (%dx) 10441b1c71b2Sjan 1045*dad25528SRichard Lowe D16 movl $_CONST(COM2+MCR), %edx / select COM1 1046*dad25528SRichard Lowe D16 movb $_CONST(RTS|DTR), %al / 1 stop bit, 8bit word len 10471b1c71b2Sjan outb (%dx) 10481b1c71b2Sjan#endif /* DEBUG */ 10491b1c71b2Sjan 10502df1fe9cSrandyf D16 ret 10512df1fe9cSrandyf 10522df1fe9cSrandyf .globl wc_rm_end 10532df1fe9cSrandyfwc_rm_end: 10542df1fe9cSrandyf nop 10552df1fe9cSrandyf 10562df1fe9cSrandyf .globl kernel_wc_code 10572df1fe9cSrandyfkernel_wc_code: 10582df1fe9cSrandyf / At this point we are with kernel's cs and proper eip. 10592df1fe9cSrandyf / We will be executing not from the copy in real mode platter, 10602df1fe9cSrandyf / but from the original code where boot loaded us. 10612df1fe9cSrandyf / By this time GDT and IDT are loaded as is cr0, cr3 and cr4. 10622df1fe9cSrandyf / %ebx is wc_cpu 10632df1fe9cSrandyf / %dx is our ds 10642df1fe9cSrandyf 10651b1c71b2Sjan#if LED 10662df1fe9cSrandyf D16 movb $0xdb, %al 10671b1c71b2Sjan outb $WC_LED 10681b1c71b2Sjan#endif 10692df1fe9cSrandyf 10702df1fe9cSrandyf/ got here OK 10712df1fe9cSrandyf 10722df1fe9cSrandyf movw %dx, %ds / $KDS_SEL 10731b1c71b2Sjan 10741b1c71b2Sjan#if LED 10752df1fe9cSrandyf movb $0xdc, %al 10761b1c71b2Sjan outb $WC_LED 10771b1c71b2Sjan#endif 10782df1fe9cSrandyf 10794716fd88Sjan /* 10804716fd88Sjan * Before proceeding, enable usage of the page table NX bit if 10814716fd88Sjan * that's how the page tables are set up. 10824716fd88Sjan */ 10837417cfdeSKuriakose Kuruvilla bt $X86FSET_NX, x86_featureset 10847417cfdeSKuriakose Kuruvilla jnc 1f 10854716fd88Sjan movl $MSR_AMD_EFER, %ecx 10862df1fe9cSrandyf rdmsr 10872df1fe9cSrandyf orl $AMD_EFER_NXE, %eax 10882df1fe9cSrandyf wrmsr 10894716fd88Sjan1: 10902df1fe9cSrandyf 10912df1fe9cSrandyf movl WC_CR4(%ebx), %eax / restore full cr4 (with Global Enable) 10922df1fe9cSrandyf movl %eax, %cr4 10932df1fe9cSrandyf 10942df1fe9cSrandyf 10952df1fe9cSrandyf lldt WC_LDT(%ebx) / $LDT_SEL 10962df1fe9cSrandyf 10972df1fe9cSrandyf movzwl WC_TR(%ebx), %eax / clear TSS busy bit 10982df1fe9cSrandyf addl WC_GDT+2(%ebx), %eax 1099*dad25528SRichard Lowe andl $_BITNOT(0x200), 4(%eax) 11002df1fe9cSrandyf ltr WC_TR(%ebx) / $UTSS_SEL 11012df1fe9cSrandyf 11023d995820SJoseph A Townsend movw WC_SS(%ebx), %ss / restore segment registers 11033d995820SJoseph A Townsend movw WC_ES(%ebx), %es 11043d995820SJoseph A Townsend movw WC_FS(%ebx), %fs 11053d995820SJoseph A Townsend movw WC_GS(%ebx), %gs 11063d995820SJoseph A Townsend 11073d995820SJoseph A Townsend /* 11083d995820SJoseph A Townsend * set the stack pointer to point into the identity mapped page 11093d995820SJoseph A Townsend * temporarily, so we can make function calls 11103d995820SJoseph A Townsend */ 11113d995820SJoseph A Townsend .globl rm_platter_va 11123d995820SJoseph A Townsend movl rm_platter_va, %eax 11133d995820SJoseph A Townsend movl $WC_STKSTART, %esp 11143d995820SJoseph A Townsend addl %eax, %esp 11153d995820SJoseph A Townsend movl %esp, %ebp 11163d995820SJoseph A Townsend 11173d995820SJoseph A Townsend /* 11183d995820SJoseph A Townsend * if we are not running on the boot CPU restore stack contents by 11193d995820SJoseph A Townsend * calling i_cpr_restore_stack(curthread, save_stack); 11203d995820SJoseph A Townsend */ 11213d995820SJoseph A Townsend call i_cpr_bootcpuid 11223d995820SJoseph A Townsend cmpl %eax, WC_CPU_ID(%ebx) 11233d995820SJoseph A Townsend je 2f 11243d995820SJoseph A Townsend 11253d995820SJoseph A Townsend pushl WC_SAVED_STACK(%ebx) 11263d995820SJoseph A Townsend pushl %gs:CPU_THREAD 11273d995820SJoseph A Townsend call i_cpr_restore_stack 11283d995820SJoseph A Townsend addl $0x10, %esp 11293d995820SJoseph A Townsend2: 11303d995820SJoseph A Townsend 11313d995820SJoseph A Townsend movl WC_ESP(%ebx), %esp 11323d995820SJoseph A Townsend movl %esp, %ebp 11332df1fe9cSrandyf 11342df1fe9cSrandyf movl WC_RETADDR(%ebx), %eax / return to caller of wc_save_context 11352df1fe9cSrandyf movl %eax, (%esp) 11362df1fe9cSrandyf 11372df1fe9cSrandyf /* 11384716fd88Sjan * APIC initialization, skip iff function pointer is NULL 11392df1fe9cSrandyf */ 11404716fd88Sjan cmpl $0, ap_mlsetup 11413d995820SJoseph A Townsend je 3f 11422df1fe9cSrandyf call *ap_mlsetup 11433d995820SJoseph A Townsend3: 11442df1fe9cSrandyf 11452df1fe9cSrandyf call *cpr_start_cpu_func 11462df1fe9cSrandyf 11472df1fe9cSrandyf pushl WC_EFLAGS(%ebx) / restore flags 11482df1fe9cSrandyf popfl 11492df1fe9cSrandyf 11502df1fe9cSrandyf movl WC_EDI(%ebx), %edi / restore general registers 11512df1fe9cSrandyf movl WC_ESI(%ebx), %esi 11522df1fe9cSrandyf movl WC_EBP(%ebx), %ebp 11532df1fe9cSrandyf movl WC_EBX(%ebx), %ebx 11542df1fe9cSrandyf 11552df1fe9cSrandyf/exit: jmp exit / stop here for HDT 11562df1fe9cSrandyf 11572df1fe9cSrandyf xorl %eax, %eax / at wakeup return 0 11582df1fe9cSrandyf ret 11592df1fe9cSrandyf 11602df1fe9cSrandyf SET_SIZE(wc_rm_start) 11612df1fe9cSrandyf 11622df1fe9cSrandyf 11632df1fe9cSrandyf#endif /* defined(__amd64) */ 11642df1fe9cSrandyf 11652df1fe9cSrandyf#endif /* lint */ 11662df1fe9cSrandyf 1167