15295Srandyf/* 25295Srandyf * CDDL HEADER START 35295Srandyf * 45295Srandyf * The contents of this file are subject to the terms of the 55295Srandyf * Common Development and Distribution License (the "License"). 65295Srandyf * You may not use this file except in compliance with the License. 75295Srandyf * 85295Srandyf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95295Srandyf * or http://www.opensolaris.org/os/licensing. 105295Srandyf * See the License for the specific language governing permissions 115295Srandyf * and limitations under the License. 125295Srandyf * 135295Srandyf * When distributing Covered Code, include this CDDL HEADER in each 145295Srandyf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155295Srandyf * If applicable, add the following below this CDDL HEADER, with the 165295Srandyf * fields enclosed by brackets "[]" replaced with your own identifying 175295Srandyf * information: Portions Copyright [yyyy] [name of copyright owner] 185295Srandyf * 195295Srandyf * CDDL HEADER END 205295Srandyf */ 215295Srandyf/* 2212826Skuriakose.kuruvilla@oracle.com * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 235295Srandyf */ 245295Srandyf 255295Srandyf#include <sys/asm_linkage.h> 265295Srandyf#include <sys/asm_misc.h> 275295Srandyf#include <sys/regset.h> 285295Srandyf#include <sys/privregs.h> 295295Srandyf#include <sys/x86_archext.h> 305295Srandyf#include <sys/cpr_wakecode.h> 315295Srandyf 325295Srandyf#if !defined(__lint) 335295Srandyf#include <sys/segments.h> 345295Srandyf#include "assym.h" 355295Srandyf#endif 365295Srandyf 376876Sjan#ifdef DEBUG 386876Sjan#define LED 1 396876Sjan#define SERIAL 1 406876Sjan#endif /* DEBUG */ 416876Sjan 426876Sjan#ifdef DEBUG 436876Sjan#define COM1 0x3f8 446876Sjan#define COM2 0x2f8 456876Sjan#define WC_COM COM2 /* either COM1 or COM2 */ 466876Sjan#define WC_LED 0x80 /* diagnostic led port ON motherboard */ 476876Sjan 486876Sjan/* 496876Sjan * defined as offsets from the data register 506876Sjan */ 516876Sjan#define DLL 0 /* divisor latch (lsb) */ 526876Sjan#define DLH 1 /* divisor latch (msb) */ 536876Sjan#define LCR 3 /* line control register */ 546876Sjan#define MCR 4 /* modem control register */ 556876Sjan 566876Sjan 576876Sjan#define DLAB 0x80 /* divisor latch access bit */ 586876Sjan#define B9600L 0X0c /* lsb bit pattern for 9600 baud */ 596876Sjan#define B9600H 0X0 /* hsb bit pattern for 9600 baud */ 606876Sjan#define DTR 0x01 /* Data Terminal Ready */ 616876Sjan#define RTS 0x02 /* Request To Send */ 626876Sjan#define STOP1 0x00 /* 1 stop bit */ 636876Sjan#define BITS8 0x03 /* 8 bits per char */ 646876Sjan 656876Sjan#endif /* DEBUG */ 666876Sjan 675295Srandyf/* 685295Srandyf * This file contains the low level routines involved in getting 695295Srandyf * into and out of ACPI S3, including those needed for restarting 705295Srandyf * the non-boot cpus. 715295Srandyf * 725295Srandyf * Our assumptions: 735295Srandyf * 745295Srandyf * Our actions: 755295Srandyf * 765295Srandyf */ 775295Srandyf 785295Srandyf#if defined(lint) || defined(__lint) 795295Srandyf 805295Srandyf/*ARGSUSED*/ 815295Srandyfint 825295Srandyfwc_save_context(wc_cpu_t *pcpu) 835295Srandyf{ return 0; } 845295Srandyf 855295Srandyf#else /* lint */ 865295Srandyf 875295Srandyf#if defined(__GNU_AS__) 885295Srandyf 895295Srandyf NOTHING AT ALL YET! 905295Srandyf 915295Srandyf#else /* !defined(__GNU_AS__) */ 925295Srandyf 935295Srandyf#if defined(__amd64) 945295Srandyf 955295Srandyf ENTRY_NP(wc_save_context) 965295Srandyf 975295Srandyf movq (%rsp), %rdx / return address 985295Srandyf movq %rdx, WC_RETADDR(%rdi) 995295Srandyf pushq %rbp 1005295Srandyf movq %rsp,%rbp 1015295Srandyf 1025295Srandyf movq %rdi, WC_VIRTADDR(%rdi) 1035295Srandyf movq %rdi, WC_RDI(%rdi) 1045295Srandyf 1055295Srandyf movq %rdx, WC_RDX(%rdi) 1065295Srandyf 1075295Srandyf/ stash everything else we need 1085295Srandyf sgdt WC_GDT(%rdi) 1095295Srandyf sidt WC_IDT(%rdi) 1105295Srandyf sldt WC_LDT(%rdi) 1115295Srandyf str WC_TR(%rdi) 1125295Srandyf 1135295Srandyf movq %cr0, %rdx 1145295Srandyf movq %rdx, WC_CR0(%rdi) 1155295Srandyf movq %cr3, %rdx 1165295Srandyf movq %rdx, WC_CR3(%rdi) 1175295Srandyf movq %cr4, %rdx 1185295Srandyf movq %rdx, WC_CR4(%rdi) 1195295Srandyf movq %cr8, %rdx 1205295Srandyf movq %rdx, WC_CR8(%rdi) 1215295Srandyf 1225295Srandyf movq %r8, WC_R8(%rdi) 1235295Srandyf movq %r9, WC_R9(%rdi) 1245295Srandyf movq %r10, WC_R10(%rdi) 1255295Srandyf movq %r11, WC_R11(%rdi) 1265295Srandyf movq %r12, WC_R12(%rdi) 1275295Srandyf movq %r13, WC_R13(%rdi) 1285295Srandyf movq %r14, WC_R14(%rdi) 1295295Srandyf movq %r15, WC_R15(%rdi) 1305295Srandyf movq %rax, WC_RAX(%rdi) 1315295Srandyf movq %rbp, WC_RBP(%rdi) 1325295Srandyf movq %rbx, WC_RBX(%rdi) 1335295Srandyf movq %rcx, WC_RCX(%rdi) 1345295Srandyf movq %rsi, WC_RSI(%rdi) 1355295Srandyf movq %rsp, WC_RSP(%rdi) 1365295Srandyf 1375295Srandyf movw %ss, WC_SS(%rdi) 1385295Srandyf movw %cs, WC_CS(%rdi) 1395295Srandyf movw %ds, WC_DS(%rdi) 1405295Srandyf movw %es, WC_ES(%rdi) 1415295Srandyf 1425295Srandyf movq $0, %rcx / save %fs register 1435295Srandyf movw %fs, %cx 1445295Srandyf movq %rcx, WC_FS(%rdi) 1455295Srandyf 1465295Srandyf movl $MSR_AMD_FSBASE, %ecx 1475295Srandyf rdmsr 1485295Srandyf movl %eax, WC_FSBASE(%rdi) 1495295Srandyf movl %edx, WC_FSBASE+4(%rdi) 1505295Srandyf 1515295Srandyf movq $0, %rcx / save %gs register 1525295Srandyf movw %gs, %cx 1535295Srandyf movq %rcx, WC_GS(%rdi) 1545295Srandyf 1555295Srandyf movl $MSR_AMD_GSBASE, %ecx / save gsbase msr 1565295Srandyf rdmsr 1575295Srandyf movl %eax, WC_GSBASE(%rdi) 1585295Srandyf movl %edx, WC_GSBASE+4(%rdi) 1595295Srandyf 1605295Srandyf movl $MSR_AMD_KGSBASE, %ecx / save kgsbase msr 1615295Srandyf rdmsr 1625295Srandyf movl %eax, WC_KGSBASE(%rdi) 1635295Srandyf movl %edx, WC_KGSBASE+4(%rdi) 1645295Srandyf 1659989SJoseph.Townsend@Sun.COM movq %gs:CPU_ID, %rax / save current cpu id 1669989SJoseph.Townsend@Sun.COM movq %rax, WC_CPU_ID(%rdi) 1679989SJoseph.Townsend@Sun.COM 1685295Srandyf pushfq 1695295Srandyf popq WC_EFLAGS(%rdi) 1705295Srandyf 1715295Srandyf wbinvd / flush the cache 1729989SJoseph.Townsend@Sun.COM mfence 1735295Srandyf 1745295Srandyf movq $1, %rax / at suspend return 1 1755295Srandyf 1765295Srandyf leave 1775295Srandyf 1785295Srandyf ret 1795295Srandyf 1805295Srandyf SET_SIZE(wc_save_context) 1815295Srandyf 1825295Srandyf#elif defined(__i386) 1835295Srandyf 1845295Srandyf ENTRY_NP(wc_save_context) 1855295Srandyf 1865295Srandyf movl 4(%esp), %eax / wc_cpu_t * 1875295Srandyf movl %eax, WC_VIRTADDR(%eax) 1885295Srandyf 1895295Srandyf movl (%esp), %edx / return address 1905295Srandyf movl %edx, WC_RETADDR(%eax) 1915295Srandyf 1925295Srandyf str WC_TR(%eax) / stash everything else we need 1935295Srandyf sgdt WC_GDT(%eax) 1945295Srandyf sldt WC_LDT(%eax) 1955295Srandyf sidt WC_IDT(%eax) 1965295Srandyf 1975295Srandyf movl %cr0, %edx 1985295Srandyf movl %edx, WC_CR0(%eax) 1995295Srandyf movl %cr3, %edx 2005295Srandyf movl %edx, WC_CR3(%eax) 2015295Srandyf movl %cr4, %edx 2025295Srandyf movl %edx, WC_CR4(%eax) 2035295Srandyf 2045295Srandyf movl %ebx, WC_EBX(%eax) 2055295Srandyf movl %edi, WC_EDI(%eax) 2065295Srandyf movl %esi, WC_ESI(%eax) 2075295Srandyf movl %ebp, WC_EBP(%eax) 2085295Srandyf movl %esp, WC_ESP(%eax) 2095295Srandyf 2105295Srandyf movw %ss, WC_SS(%eax) 2115295Srandyf movw %cs, WC_CS(%eax) 2125295Srandyf movw %ds, WC_DS(%eax) 2135295Srandyf movw %es, WC_ES(%eax) 2145295Srandyf movw %fs, WC_FS(%eax) 2155295Srandyf movw %gs, WC_GS(%eax) 2165295Srandyf 2175295Srandyf pushfl 2185295Srandyf popl WC_EFLAGS(%eax) 2195295Srandyf 2209989SJoseph.Townsend@Sun.COM pushl %gs:CPU_ID / save current cpu id 2219989SJoseph.Townsend@Sun.COM popl WC_CPU_ID(%eax) 2229989SJoseph.Townsend@Sun.COM 2235295Srandyf wbinvd / flush the cache 2249989SJoseph.Townsend@Sun.COM mfence 2255295Srandyf 2265295Srandyf movl $1, %eax / at suspend return 1 2275295Srandyf ret 2285295Srandyf 2295295Srandyf SET_SIZE(wc_save_context) 2305295Srandyf 2315295Srandyf#endif /* __amd64 */ 2325295Srandyf 2335295Srandyf#endif /* __GNU_AS__ */ 2345295Srandyf 2355295Srandyf#endif /* lint */ 2365295Srandyf 2375295Srandyf 2385295Srandyf/* 2395295Srandyf * Our assumptions: 2405295Srandyf * - We are running in real mode. 2415295Srandyf * - Interrupts are disabled. 2425295Srandyf * 2435295Srandyf * Our actions: 2445295Srandyf * - We start using our GDT by loading correct values in the 2455295Srandyf * selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL, 2465295Srandyf * gs=KGS_SEL). 2475295Srandyf * - We change over to using our IDT. 2485295Srandyf * - We load the default LDT into the hardware LDT register. 2495295Srandyf * - We load the default TSS into the hardware task register. 2505295Srandyf * - We restore registers 2515295Srandyf * - We return to original caller (a la setjmp) 2525295Srandyf */ 2535295Srandyf 2545295Srandyf#if defined(lint) || defined(__lint) 2555295Srandyf 2565295Srandyfvoid 2575295Srandyfwc_rm_start(void) 2585295Srandyf{} 2595295Srandyf 2605295Srandyfvoid 2615295Srandyfwc_rm_end(void) 2625295Srandyf{} 2635295Srandyf 2645295Srandyf#else /* lint */ 2655295Srandyf 2665295Srandyf#if defined(__GNU_AS__) 2675295Srandyf 2685295Srandyf NOTHING AT ALL YET! 2695295Srandyf 2705295Srandyf#else /* __GNU_AS__ */ 2715295Srandyf 2725295Srandyf#if defined(__amd64) 2735295Srandyf 2745295Srandyf ENTRY_NP(wc_rm_start) 2755295Srandyf 2765295Srandyf /* 2775295Srandyf * For vulcan as we need to do a .code32 and mentally invert the 2785295Srandyf * meaning of the addr16 and data16 prefixes to get 32-bit access when 2795295Srandyf * generating code to be executed in 16-bit mode (sigh...) 2805295Srandyf */ 2815295Srandyf 2825295Srandyf .code32 2835295Srandyf 2845295Srandyf cli 2855295Srandyf movw %cs, %ax 2865295Srandyf movw %ax, %ds / establish ds ... 2875295Srandyf movw %ax, %ss / ... and ss:esp 2885295Srandyf D16 movl $WC_STKSTART, %esp 2895295Srandyf/ using the following value blows up machines! - DO NOT USE 2905295Srandyf/ D16 movl 0xffc, %esp 2915295Srandyf 2925295Srandyf 2935295Srandyf#if LED 2946876Sjan D16 movl $WC_LED, %edx 2955295Srandyf D16 movb $0xd1, %al 2965295Srandyf outb (%dx) 2975295Srandyf#endif 2985295Srandyf 2995295Srandyf#if SERIAL 3006876Sjan D16 movl $WC_COM, %edx 3015295Srandyf D16 movb $0x61, %al 3025295Srandyf outb (%dx) 3035295Srandyf#endif 3045295Srandyf 3055295Srandyf D16 call cominit 3065295Srandyf 3075295Srandyf /* 3085295Srandyf * Enable protected-mode, write protect, and alignment mask 3095295Srandyf * %cr0 has already been initialsed to zero 3105295Srandyf */ 3115295Srandyf movl %cr0, %eax 3125295Srandyf D16 orl $[CR0_PE|CR0_WP|CR0_AM], %eax 3135295Srandyf movl %eax, %cr0 3145295Srandyf 3155295Srandyf /* 3165295Srandyf * Do a jmp immediately after writing to cr0 when enabling protected 3175295Srandyf * mode to clear the real mode prefetch queue (per Intel's docs) 3185295Srandyf */ 3195295Srandyf jmp pestart 3205295Srandyfpestart: 3215295Srandyf 3225295Srandyf#if LED 3236876Sjan D16 movl $WC_LED, %edx 3245295Srandyf D16 movb $0xd2, %al 3255295Srandyf outb (%dx) 3265295Srandyf#endif 3275295Srandyf 3285295Srandyf#if SERIAL 3296876Sjan D16 movl $WC_COM, %edx 3305295Srandyf D16 movb $0x62, %al 3315295Srandyf outb (%dx) 3325295Srandyf#endif 3335295Srandyf 3345295Srandyf /* 3355295Srandyf * 16-bit protected mode is now active, so prepare to turn on long 3365295Srandyf * mode 3375295Srandyf */ 3385295Srandyf 3395295Srandyf#if LED 3406876Sjan D16 movl $WC_LED, %edx 3415295Srandyf D16 movb $0xd3, %al 3425295Srandyf outb (%dx) 3435295Srandyf#endif 3445295Srandyf 3455295Srandyf#if SERIAL 3466876Sjan D16 movl $WC_COM, %edx 3475295Srandyf D16 movb $0x63, %al 3485295Srandyf outb (%dx) 3495295Srandyf#endif 3505295Srandyf 3515295Srandyf /* 3525295Srandyf * Add any initial cr4 bits 3535295Srandyf */ 3545295Srandyf movl %cr4, %eax 3555295Srandyf A16 D16 orl CR4OFF, %eax 3565295Srandyf 3575295Srandyf /* 3585295Srandyf * Enable PAE mode (CR4.PAE) 3595295Srandyf */ 3605295Srandyf D16 orl $CR4_PAE, %eax 3615295Srandyf movl %eax, %cr4 3625295Srandyf 3635295Srandyf#if LED 3646876Sjan D16 movl $WC_LED, %edx 3655295Srandyf D16 movb $0xd4, %al 3665295Srandyf outb (%dx) 3675295Srandyf#endif 3685295Srandyf 3695295Srandyf#if SERIAL 3706876Sjan D16 movl $WC_COM, %edx 3715295Srandyf D16 movb $0x64, %al 3725295Srandyf outb (%dx) 3735295Srandyf#endif 3745295Srandyf 3755295Srandyf /* 3765295Srandyf * Point cr3 to the 64-bit long mode page tables. 3775295Srandyf * 3785295Srandyf * Note that these MUST exist in 32-bit space, as we don't have 3795295Srandyf * a way to load %cr3 with a 64-bit base address for the page tables 3805295Srandyf * until the CPU is actually executing in 64-bit long mode. 3815295Srandyf */ 3825295Srandyf A16 D16 movl CR3OFF, %eax 3835295Srandyf movl %eax, %cr3 3845295Srandyf 3855295Srandyf /* 3865295Srandyf * Set long mode enable in EFER (EFER.LME = 1) 3875295Srandyf */ 3885295Srandyf D16 movl $MSR_AMD_EFER, %ecx 3895295Srandyf rdmsr 3905295Srandyf 3915295Srandyf D16 orl $AMD_EFER_LME, %eax 3925295Srandyf wrmsr 3935295Srandyf 3945295Srandyf#if LED 3956876Sjan D16 movl $WC_LED, %edx 3965295Srandyf D16 movb $0xd5, %al 3975295Srandyf outb (%dx) 3985295Srandyf#endif 3995295Srandyf 4005295Srandyf#if SERIAL 4016876Sjan D16 movl $WC_COM, %edx 4025295Srandyf D16 movb $0x65, %al 4035295Srandyf outb (%dx) 4045295Srandyf#endif 4055295Srandyf 4065295Srandyf /* 4075295Srandyf * Finally, turn on paging (CR0.PG = 1) to activate long mode. 4085295Srandyf */ 4095295Srandyf movl %cr0, %eax 4105295Srandyf D16 orl $CR0_PG, %eax 4115295Srandyf movl %eax, %cr0 4125295Srandyf 4135295Srandyf /* 4145295Srandyf * The instruction after enabling paging in CR0 MUST be a branch. 4155295Srandyf */ 4165295Srandyf jmp long_mode_active 4175295Srandyf 4185295Srandyflong_mode_active: 4195295Srandyf 4205295Srandyf#if LED 4216876Sjan D16 movl $WC_LED, %edx 4225295Srandyf D16 movb $0xd6, %al 4235295Srandyf outb (%dx) 4245295Srandyf#endif 4255295Srandyf 4265295Srandyf#if SERIAL 4276876Sjan D16 movl $WC_COM, %edx 4285295Srandyf D16 movb $0x66, %al 4295295Srandyf outb (%dx) 4305295Srandyf#endif 4315295Srandyf 4325295Srandyf /* 4335295Srandyf * Long mode is now active but since we're still running with the 4345295Srandyf * original 16-bit CS we're actually in 16-bit compatability mode. 4355295Srandyf * 4365295Srandyf * We have to load an intermediate GDT and IDT here that we know are 4375295Srandyf * in 32-bit space before we can use the kernel's GDT and IDT, which 4385295Srandyf * may be in the 64-bit address space, and since we're in compatability 4395295Srandyf * mode, we only have access to 16 and 32-bit instructions at the 4405295Srandyf * moment. 4415295Srandyf */ 4425295Srandyf A16 D16 lgdt TEMPGDTOFF /* load temporary GDT */ 4435295Srandyf A16 D16 lidt TEMPIDTOFF /* load temporary IDT */ 4445295Srandyf 4455295Srandyf 4465295Srandyf /* 4475295Srandyf * Do a far transfer to 64-bit mode. Set the CS selector to a 64-bit 4485295Srandyf * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump 4495295Srandyf * to the real mode platter address of wc_long_mode_64 as until the 4505295Srandyf * 64-bit CS is in place we don't have access to 64-bit instructions 4515295Srandyf * and thus can't reference a 64-bit %rip. 4525295Srandyf */ 4535295Srandyf 4545295Srandyf#if LED 4556876Sjan D16 movl $WC_LED, %edx 4565295Srandyf D16 movb $0xd7, %al 4575295Srandyf outb (%dx) 4585295Srandyf#endif 4595295Srandyf 4605295Srandyf#if SERIAL 4616876Sjan D16 movl $WC_COM, %edx 4625295Srandyf D16 movb $0x67, %al 4635295Srandyf outb (%dx) 4645295Srandyf#endif 4655295Srandyf 4665295Srandyf D16 pushl $TEMP_CS64_SEL 4675295Srandyf A16 D16 pushl LM64OFF 4685295Srandyf 4695295Srandyf D16 lret 4705295Srandyf 4715295Srandyf 4725295Srandyf/* 4735295Srandyf * Support routine to re-initialize VGA subsystem 4745295Srandyf */ 4755295Srandyfvgainit: 4765295Srandyf D16 ret 4775295Srandyf 4785295Srandyf/* 4795295Srandyf * Support routine to re-initialize keyboard (which is USB - help!) 4805295Srandyf */ 4815295Srandyfkbdinit: 4825295Srandyf D16 ret 4835295Srandyf 4845295Srandyf/* 4855295Srandyf * Support routine to re-initialize COM ports to something sane 4865295Srandyf */ 4875295Srandyfcominit: 4885295Srandyf / init COM1 & COM2 4896876Sjan 4906876Sjan#if DEBUG 4916876Sjan/* 4926876Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that 4936876Sjan * we can get debug output before the asy driver has resumed 4946876Sjan */ 4956876Sjan 4966876Sjan/ select COM1 4976876Sjan D16 movl $[COM1+LCR], %edx 4986876Sjan D16 movb $DLAB, %al / divisor latch 4996876Sjan outb (%dx) 5006876Sjan 5016876Sjan D16 movl $[COM1+DLL], %edx / divisor latch lsb 5026876Sjan D16 movb $B9600L, %al / divisor latch 5036876Sjan outb (%dx) 5046876Sjan 5056876Sjan D16 movl $[COM1+DLH], %edx / divisor latch hsb 5066876Sjan D16 movb $B9600H, %al / divisor latch 5076876Sjan outb (%dx) 5086876Sjan 5096876Sjan D16 movl $[COM1+LCR], %edx / select COM1 5106876Sjan D16 movb $[STOP1|BITS8], %al / 1 stop bit, 8bit word len 5116876Sjan outb (%dx) 5126876Sjan 5136876Sjan D16 movl $[COM1+MCR], %edx / select COM1 5146876Sjan D16 movb $[RTS|DTR], %al / data term ready & req to send 5156876Sjan outb (%dx) 5166876Sjan 5176876Sjan/ select COM2 5186876Sjan D16 movl $[COM2+LCR], %edx 5196876Sjan D16 movb $DLAB, %al / divisor latch 5206876Sjan outb (%dx) 5216876Sjan 5226876Sjan D16 movl $[COM2+DLL], %edx / divisor latch lsb 5236876Sjan D16 movb $B9600L, %al / divisor latch 5246876Sjan outb (%dx) 5256876Sjan 5266876Sjan D16 movl $[COM2+DLH], %edx / divisor latch hsb 5276876Sjan D16 movb $B9600H, %al / divisor latch 5286876Sjan outb (%dx) 5296876Sjan 5306876Sjan D16 movl $[COM2+LCR], %edx / select COM1 5316876Sjan D16 movb $[STOP1|BITS8], %al / 1 stop bit, 8bit word len 5326876Sjan outb (%dx) 5336876Sjan 5346876Sjan D16 movl $[COM2+MCR], %edx / select COM1 5356876Sjan D16 movb $[RTS|DTR], %al / data term ready & req to send 5366876Sjan outb (%dx) 5376876Sjan#endif /* DEBUG */ 5386876Sjan 5395295Srandyf D16 ret 5405295Srandyf 5415295Srandyf .code64 5425295Srandyf 5435295Srandyf .globl wc_long_mode_64 5445295Srandyfwc_long_mode_64: 5455295Srandyf 5465295Srandyf#if LED 5476876Sjan movw $WC_LED, %dx 5485295Srandyf movb $0xd8, %al 5495295Srandyf outb (%dx) 5505295Srandyf#endif 5515295Srandyf 5525295Srandyf#if SERIAL 5536876Sjan movw $WC_COM, %dx 5545295Srandyf movb $0x68, %al 5555295Srandyf outb (%dx) 5565295Srandyf#endif 5575295Srandyf 5585295Srandyf /* 5595295Srandyf * We are now running in long mode with a 64-bit CS (EFER.LMA=1, 5605295Srandyf * CS.L=1) so we now have access to 64-bit instructions. 5615295Srandyf * 5625295Srandyf * First, set the 64-bit GDT base. 5635295Srandyf */ 5645295Srandyf .globl rm_platter_pa 5655295Srandyf movl rm_platter_pa, %eax 5665295Srandyf 5675295Srandyf lgdtq GDTROFF(%rax) /* load 64-bit GDT */ 5685295Srandyf 5695295Srandyf /* 5705295Srandyf * Save the CPU number in %r11; get the value here since it's saved in 5715295Srandyf * the real mode platter. 5725295Srandyf */ 5735295Srandyf/ JAN 5745295Srandyf/ the following is wrong! need to figure out MP systems 5755295Srandyf/ movl CPUNOFF(%rax), %r11d 5765295Srandyf 5775295Srandyf /* 5785295Srandyf * Add rm_platter_pa to %rsp to point it to the same location as seen 5795295Srandyf * from 64-bit mode. 5805295Srandyf */ 5815295Srandyf addq %rax, %rsp 5825295Srandyf 5835295Srandyf /* 5845295Srandyf * Now do an lretq to load CS with the appropriate selector for the 5855295Srandyf * kernel's 64-bit GDT and to start executing 64-bit setup code at the 5865295Srandyf * virtual address where boot originally loaded this code rather than 5875295Srandyf * the copy in the real mode platter's rm_code array as we've been 5885295Srandyf * doing so far. 5895295Srandyf */ 5905295Srandyf 5915295Srandyf#if LED 5926876Sjan movw $WC_LED, %dx 5935295Srandyf movb $0xd9, %al 5945295Srandyf outb (%dx) 5955295Srandyf#endif 5965295Srandyf 5975295Srandyf/ JAN this should produce 'i' but we get 'g' instead ??? 5985295Srandyf#if SERIAL 5996876Sjan movw $WC_COM, %dx 6005295Srandyf movb $0x69, %al 6015295Srandyf outb (%dx) 6025295Srandyf#endif 6035295Srandyf 6045295Srandyf pushq $KCS_SEL 6055295Srandyf pushq $kernel_wc_code 6065295Srandyf lretq 6075295Srandyf 6085295Srandyf .globl kernel_wc_code 6095295Srandyfkernel_wc_code: 6105295Srandyf 6115295Srandyf#if LED 6126876Sjan movw $WC_LED, %dx 6135295Srandyf movb $0xda, %al 6145295Srandyf outb (%dx) 6155295Srandyf#endif 6165295Srandyf 6175295Srandyf/ JAN this should produce 'j' but we get 'g' instead ??? 6185295Srandyf#if SERIAL 6196876Sjan movw $WC_COM, %dx 6205295Srandyf movb $0x6a, %al 6215295Srandyf outb (%dx) 6225295Srandyf#endif 6235295Srandyf 6245295Srandyf /* 6255295Srandyf * Complete the balance of the setup we need to before executing 6265295Srandyf * 64-bit kernel code (namely init rsp, TSS, LGDT, FS and GS). 6275295Srandyf */ 6285295Srandyf .globl rm_platter_va 6295295Srandyf movq rm_platter_va, %rbx 6305295Srandyf addq $WC_CPU, %rbx 6315295Srandyf 6325295Srandyf#if LED 6336876Sjan movw $WC_LED, %dx 6345295Srandyf movb $0xdb, %al 6355295Srandyf outb (%dx) 6365295Srandyf#endif 6375295Srandyf 6385295Srandyf#if SERIAL 6396876Sjan movw $WC_COM, %dx 6405295Srandyf movw $0x6b, %ax 6415295Srandyf outb (%dx) 6425295Srandyf#endif 6435295Srandyf 6445295Srandyf /* 6455295Srandyf * restore the rest of the registers 6465295Srandyf */ 6475295Srandyf 6485295Srandyf lidtq WC_IDT(%rbx) 6495295Srandyf 6505295Srandyf#if LED 6516876Sjan movw $WC_LED, %dx 6525295Srandyf movb $0xdc, %al 6535295Srandyf outb (%dx) 6545295Srandyf#endif 6555295Srandyf 6565295Srandyf#if SERIAL 6576876Sjan movw $WC_COM, %dx 6585295Srandyf movw $0x6c, %ax 6595295Srandyf outb (%dx) 6605295Srandyf#endif 6615295Srandyf 6625295Srandyf /* 6635295Srandyf * restore the rest of the registers 6645295Srandyf */ 6655295Srandyf 6665295Srandyf movw $KDS_SEL, %ax 6675295Srandyf movw %ax, %ds 6685295Srandyf movw %ax, %es 6695295Srandyf movw %ax, %ss 6705295Srandyf 6715295Srandyf /* 6725295Srandyf * Before proceeding, enable usage of the page table NX bit if 6735295Srandyf * that's how the page tables are set up. 6745295Srandyf */ 675*13136Skuriakose.kuruvilla@oracle.com bt $X86FSET_NX, x86_featureset(%rip) 67612826Skuriakose.kuruvilla@oracle.com jnc 1f 6775295Srandyf movl $MSR_AMD_EFER, %ecx 6785295Srandyf rdmsr 6795295Srandyf orl $AMD_EFER_NXE, %eax 6805295Srandyf wrmsr 6815295Srandyf1: 6825295Srandyf 6835295Srandyf movq WC_CR4(%rbx), %rax / restore full cr4 (with Global Enable) 6845295Srandyf movq %rax, %cr4 6855295Srandyf 6865295Srandyf lldt WC_LDT(%rbx) 6875295Srandyf movzwq WC_TR(%rbx), %rax / clear TSS busy bit 6885295Srandyf addq WC_GDT+2(%rbx), %rax 6895295Srandyf andl $0xfffffdff, 4(%rax) 6905295Srandyf movq 4(%rax), %rcx 6915295Srandyf ltr WC_TR(%rbx) 6925295Srandyf 6935295Srandyf#if LED 6946876Sjan movw $WC_LED, %dx 6955295Srandyf movb $0xdd, %al 6965295Srandyf outb (%dx) 6975295Srandyf#endif 6985295Srandyf 6995295Srandyf#if SERIAL 7006876Sjan movw $WC_COM, %dx 7015295Srandyf movw $0x6d, %ax 7025295Srandyf outb (%dx) 7035295Srandyf#endif 7045295Srandyf 7055295Srandyf/ restore %fsbase %gsbase %kgbase registers using wrmsr instruction 7065295Srandyf 7075295Srandyf movq WC_FS(%rbx), %rcx / restore fs register 7085295Srandyf movw %cx, %fs 7095295Srandyf 7105295Srandyf movl $MSR_AMD_FSBASE, %ecx 7115295Srandyf movl WC_FSBASE(%rbx), %eax 7125295Srandyf movl WC_FSBASE+4(%rbx), %edx 7135295Srandyf wrmsr 7145295Srandyf 7155295Srandyf movq WC_GS(%rbx), %rcx / restore gs register 7165295Srandyf movw %cx, %gs 7175295Srandyf 7185295Srandyf movl $MSR_AMD_GSBASE, %ecx / restore gsbase msr 7195295Srandyf movl WC_GSBASE(%rbx), %eax 7205295Srandyf movl WC_GSBASE+4(%rbx), %edx 7215295Srandyf wrmsr 7225295Srandyf 7235295Srandyf movl $MSR_AMD_KGSBASE, %ecx / restore kgsbase msr 7245295Srandyf movl WC_KGSBASE(%rbx), %eax 7255295Srandyf movl WC_KGSBASE+4(%rbx), %edx 7265295Srandyf wrmsr 7275295Srandyf 7285295Srandyf movq WC_CR0(%rbx), %rdx 7295295Srandyf movq %rdx, %cr0 7305295Srandyf movq WC_CR3(%rbx), %rdx 7315295Srandyf movq %rdx, %cr3 7325295Srandyf movq WC_CR8(%rbx), %rdx 7335295Srandyf movq %rdx, %cr8 7345295Srandyf 7355295Srandyf#if LED 7366876Sjan movw $WC_LED, %dx 7375295Srandyf movb $0xde, %al 7385295Srandyf outb (%dx) 7395295Srandyf#endif 7405295Srandyf 7415295Srandyf#if SERIAL 7426876Sjan movw $WC_COM, %dx 7435295Srandyf movb $0x6e, %al 7445295Srandyf outb (%dx) 7455295Srandyf#endif 7465295Srandyf 7479989SJoseph.Townsend@Sun.COM /* 7489989SJoseph.Townsend@Sun.COM * if we are not running on the boot CPU restore stack contents by 7499989SJoseph.Townsend@Sun.COM * calling i_cpr_restore_stack(curthread, save_stack); 7509989SJoseph.Townsend@Sun.COM */ 7519989SJoseph.Townsend@Sun.COM movq %rsp, %rbp 7529989SJoseph.Townsend@Sun.COM call i_cpr_bootcpuid 7539989SJoseph.Townsend@Sun.COM cmpl %eax, WC_CPU_ID(%rbx) 7549989SJoseph.Townsend@Sun.COM je 2f 7559989SJoseph.Townsend@Sun.COM 7569989SJoseph.Townsend@Sun.COM movq %gs:CPU_THREAD, %rdi 7579989SJoseph.Townsend@Sun.COM movq WC_SAVED_STACK(%rbx), %rsi 7589989SJoseph.Townsend@Sun.COM call i_cpr_restore_stack 7599989SJoseph.Townsend@Sun.COM2: 7609989SJoseph.Townsend@Sun.COM 7619989SJoseph.Townsend@Sun.COM movq WC_RSP(%rbx), %rsp / restore stack pointer 7625295Srandyf 7635295Srandyf /* 7647362SKerry.Shu@Sun.COM * APIC initialization 7655295Srandyf */ 7669989SJoseph.Townsend@Sun.COM movq %rsp, %rbp 7675295Srandyf 7685817Sjan /* 7695817Sjan * skip iff function pointer is NULL 7705817Sjan */ 7715817Sjan cmpq $0, ap_mlsetup 7729989SJoseph.Townsend@Sun.COM je 3f 7735817Sjan call *ap_mlsetup 7749989SJoseph.Townsend@Sun.COM3: 7755295Srandyf 7765295Srandyf call *cpr_start_cpu_func 7775295Srandyf 7785295Srandyf/ restore %rbx to the value it ahd before we called the functions above 7795295Srandyf movq rm_platter_va, %rbx 7805295Srandyf addq $WC_CPU, %rbx 7815295Srandyf 7825295Srandyf movq WC_R8(%rbx), %r8 7835295Srandyf movq WC_R9(%rbx), %r9 7845295Srandyf movq WC_R10(%rbx), %r10 7855295Srandyf movq WC_R11(%rbx), %r11 7865295Srandyf movq WC_R12(%rbx), %r12 7875295Srandyf movq WC_R13(%rbx), %r13 7885295Srandyf movq WC_R14(%rbx), %r14 7895295Srandyf movq WC_R15(%rbx), %r15 7905295Srandyf/ movq WC_RAX(%rbx), %rax 7915295Srandyf movq WC_RBP(%rbx), %rbp 7925295Srandyf movq WC_RCX(%rbx), %rcx 7935295Srandyf/ movq WC_RDX(%rbx), %rdx 7945295Srandyf movq WC_RDI(%rbx), %rdi 7955295Srandyf movq WC_RSI(%rbx), %rsi 7965295Srandyf 7975295Srandyf 7985295Srandyf/ assume that %cs does not need to be restored 7995295Srandyf/ %ds, %es & %ss are ignored in 64bit mode 8005295Srandyf movw WC_SS(%rbx), %ss 8015295Srandyf movw WC_DS(%rbx), %ds 8025295Srandyf movw WC_ES(%rbx), %es 8035295Srandyf 8045295Srandyf#if LED 8056876Sjan movw $WC_LED, %dx 8065295Srandyf movb $0xdf, %al 8075295Srandyf outb (%dx) 8085295Srandyf#endif 8095295Srandyf 8105295Srandyf#if SERIAL 8116876Sjan movw $WC_COM, %dx 8125295Srandyf movb $0x6f, %al 8135295Srandyf outb (%dx) 8145295Srandyf#endif 8155295Srandyf 8165295Srandyf 8175295Srandyf movq WC_RBP(%rbx), %rbp 8185295Srandyf movq WC_RSP(%rbx), %rsp 8195295Srandyf 8205295Srandyf#if LED 8216876Sjan movw $WC_LED, %dx 8225295Srandyf movb $0xe0, %al 8235295Srandyf outb (%dx) 8245295Srandyf#endif 8255295Srandyf 8265295Srandyf#if SERIAL 8276876Sjan movw $WC_COM, %dx 8285295Srandyf movb $0x70, %al 8295295Srandyf outb (%dx) 8305295Srandyf#endif 8315295Srandyf 8325295Srandyf 8335295Srandyf movq WC_RCX(%rbx), %rcx 8345295Srandyf 8355295Srandyf pushq WC_EFLAGS(%rbx) / restore flags 8365295Srandyf popfq 8375295Srandyf 8385295Srandyf#if LED 8396876Sjan movw $WC_LED, %dx 8405295Srandyf movb $0xe1, %al 8415295Srandyf outb (%dx) 8425295Srandyf#endif 8435295Srandyf 8445295Srandyf#if SERIAL 8456876Sjan movw $WC_COM, %dx 8465295Srandyf movb $0x71, %al 8475295Srandyf outb (%dx) 8485295Srandyf#endif 8495295Srandyf 8505295Srandyf/* 8515295Srandyf * can not use outb after this point, because doing so would mean using 8525295Srandyf * %dx which would modify %rdx which is restored here 8535295Srandyf */ 8545295Srandyf 8555295Srandyf movq %rbx, %rax 8565295Srandyf movq WC_RDX(%rax), %rdx 8575295Srandyf movq WC_RBX(%rax), %rbx 8585295Srandyf 8595295Srandyf leave 8605295Srandyf 8615295Srandyf movq WC_RETADDR(%rax), %rax 8625295Srandyf movq %rax, (%rsp) / return to caller of wc_save_context 8635295Srandyf 8645295Srandyf xorl %eax, %eax / at wakeup return 0 8655295Srandyf ret 8665295Srandyf 8675295Srandyf 8685295Srandyf SET_SIZE(wc_rm_start) 8695295Srandyf 8705295Srandyf ENTRY_NP(asmspin) 8715295Srandyf 8725295Srandyf movl %edi, %ecx 8735295SrandyfA1: 8745295Srandyf loop A1 8755295Srandyf 8765295Srandyf SET_SIZE(asmspin) 8775295Srandyf 8785295Srandyf .globl wc_rm_end 8795295Srandyfwc_rm_end: 8805295Srandyf nop 8815295Srandyf 8825295Srandyf#elif defined(__i386) 8835295Srandyf 8845295Srandyf ENTRY_NP(wc_rm_start) 8855295Srandyf 8865295Srandyf/entry: jmp entry / stop here for HDT 8875295Srandyf 8885295Srandyf cli 8895295Srandyf movw %cs, %ax 8905295Srandyf movw %ax, %ds / establish ds ... 8915295Srandyf movw %ax, %ss / ... and ss:esp 8925295Srandyf D16 movl $WC_STKSTART, %esp 8935295Srandyf 8945295Srandyf#if LED 8956876Sjan D16 movl $WC_LED, %edx 8965295Srandyf D16 movb $0xd1, %al 8975295Srandyf outb (%dx) 8985295Srandyf#endif 8995295Srandyf 9005295Srandyf#if SERIAL 9016876Sjan D16 movl $WC_COM, %edx 9025295Srandyf D16 movb $0x61, %al 9035295Srandyf outb (%dx) 9045295Srandyf#endif 9055295Srandyf 9065295Srandyf 9075295Srandyf D16 call vgainit 9085295Srandyf D16 call kbdinit 9095295Srandyf D16 call cominit 9105295Srandyf 9115295Srandyf#if LED 9126876Sjan D16 movl $WC_LED, %edx 9135295Srandyf D16 movb $0xd2, %al 9145295Srandyf outb (%dx) 9155295Srandyf#endif 9165295Srandyf 9175295Srandyf#if SERIAL 9186876Sjan D16 movl $WC_COM, %edx 9195295Srandyf D16 movb $0x62, %al 9205295Srandyf outb (%dx) 9215295Srandyf#endif 9225295Srandyf 9235295Srandyf D16 A16 movl $WC_CPU, %ebx / base add of wc_cpu_t 9245295Srandyf 9255295Srandyf#if LED 9265295Srandyf D16 movb $0xd3, %al 9276876Sjan outb $WC_LED 9285295Srandyf#endif 9295295Srandyf 9305295Srandyf#if SERIAL 9316876Sjan D16 movl $WC_COM, %edx 9325295Srandyf D16 movb $0x63, %al 9335295Srandyf outb (%dx) 9345295Srandyf#endif 9355295Srandyf 9365295Srandyf D16 A16 movl %cs:WC_DS(%ebx), %edx / %ds post prot/paging transit 9375295Srandyf 9386876Sjan#if LED 9395295Srandyf D16 movb $0xd4, %al 9406876Sjan outb $WC_LED 9416876Sjan#endif 9425295Srandyf 9435295Srandyf D16 A16 lgdt %cs:WC_GDT(%ebx) / restore gdt and idtr 9445295Srandyf D16 A16 lidt %cs:WC_IDT(%ebx) 9455295Srandyf 9466876Sjan#if LED 9475295Srandyf D16 movb $0xd5, %al 9486876Sjan outb $WC_LED 9496876Sjan#endif 9505295Srandyf 9515295Srandyf D16 A16 movl %cs:WC_CR4(%ebx), %eax / restore cr4 9525295Srandyf D16 andl $-1!CR4_PGE, %eax / don't set Global Enable yet 9535295Srandyf movl %eax, %cr4 9545295Srandyf 9556876Sjan#if LED 9565295Srandyf D16 movb $0xd6, %al 9576876Sjan outb $WC_LED 9586876Sjan#endif 9595295Srandyf 9605295Srandyf D16 A16 movl %cs:WC_CR3(%ebx), %eax / set PDPT 9615295Srandyf movl %eax, %cr3 9625295Srandyf 9636876Sjan#if LED 9645295Srandyf D16 movb $0xd7, %al 9656876Sjan outb $WC_LED 9666876Sjan#endif 9675295Srandyf 9685295Srandyf D16 A16 movl %cs:WC_CR0(%ebx), %eax / enable prot/paging, etc. 9695295Srandyf movl %eax, %cr0 9705295Srandyf 9716876Sjan#if LED 9725295Srandyf D16 movb $0xd8, %al 9736876Sjan outb $WC_LED 9746876Sjan#endif 9755295Srandyf 9765295Srandyf D16 A16 movl %cs:WC_VIRTADDR(%ebx), %ebx / virtaddr of wc_cpu_t 9775295Srandyf 9786876Sjan#if LED 9795295Srandyf D16 movb $0xd9, %al 9806876Sjan outb $WC_LED 9816876Sjan#endif 9825295Srandyf 9836876Sjan#if LED 9845295Srandyf D16 movb $0xda, %al 9856876Sjan outb $WC_LED 9866876Sjan#endif 9876876Sjan 9885295Srandyf jmp flush / flush prefetch queue 9895295Srandyfflush: 9905295Srandyf D16 pushl $KCS_SEL 9915295Srandyf D16 pushl $kernel_wc_code 9925295Srandyf D16 lret / re-appear at kernel_wc_code 9935295Srandyf 9945295Srandyf 9955295Srandyf/* 9965295Srandyf * Support routine to re-initialize VGA subsystem 9975295Srandyf */ 9985295Srandyfvgainit: 9995295Srandyf D16 ret 10005295Srandyf 10015295Srandyf/* 10025295Srandyf * Support routine to re-initialize keyboard (which is USB - help!) 10035295Srandyf */ 10045295Srandyfkbdinit: 10055295Srandyf D16 ret 10065295Srandyf 10075295Srandyf/* 10085295Srandyf * Support routine to re-initialize COM ports to something sane for debug output 10095295Srandyf */ 10105295Srandyfcominit: 10116876Sjan#if DEBUG 10126876Sjan/* 10136876Sjan * on debug kernels we need to initialize COM1 & COM2 here, so that 10146876Sjan * we can get debug output before the asy driver has resumed 10156876Sjan */ 10166876Sjan 10176876Sjan/ select COM1 10186876Sjan D16 movl $[COM1+LCR], %edx 10196876Sjan D16 movb $DLAB, %al / divisor latch 10206876Sjan outb (%dx) 10216876Sjan 10226876Sjan D16 movl $[COM1+DLL], %edx / divisor latch lsb 10236876Sjan D16 movb $B9600L, %al / divisor latch 10246876Sjan outb (%dx) 10256876Sjan 10266876Sjan D16 movl $[COM1+DLH], %edx / divisor latch hsb 10276876Sjan D16 movb $B9600H, %al / divisor latch 10286876Sjan outb (%dx) 10296876Sjan 10306876Sjan D16 movl $[COM1+LCR], %edx / select COM1 10316876Sjan D16 movb $[STOP1|BITS8], %al / 1 stop bit, 8bit word len 10326876Sjan outb (%dx) 10336876Sjan 10346876Sjan D16 movl $[COM1+MCR], %edx / select COM1 10356876Sjan D16 movb $[RTS|DTR], %al / 1 stop bit, 8bit word len 10366876Sjan outb (%dx) 10376876Sjan 10386876Sjan/ select COM2 10396876Sjan D16 movl $[COM2+LCR], %edx 10406876Sjan D16 movb $DLAB, %al / divisor latch 10416876Sjan outb (%dx) 10426876Sjan 10436876Sjan D16 movl $[COM2+DLL], %edx / divisor latch lsb 10446876Sjan D16 movb $B9600L, %al / divisor latch 10456876Sjan outb (%dx) 10466876Sjan 10476876Sjan D16 movl $[COM2+DLH], %edx / divisor latch hsb 10486876Sjan D16 movb $B9600H, %al / divisor latch 10496876Sjan outb (%dx) 10506876Sjan 10516876Sjan D16 movl $[COM2+LCR], %edx / select COM1 10526876Sjan D16 movb $[STOP1|BITS8], %al / 1 stop bit, 8bit word len 10536876Sjan outb (%dx) 10546876Sjan 10556876Sjan D16 movl $[COM2+MCR], %edx / select COM1 10566876Sjan D16 movb $[RTS|DTR], %al / 1 stop bit, 8bit word len 10576876Sjan outb (%dx) 10586876Sjan#endif /* DEBUG */ 10596876Sjan 10605295Srandyf D16 ret 10615295Srandyf 10625295Srandyf .globl wc_rm_end 10635295Srandyfwc_rm_end: 10645295Srandyf nop 10655295Srandyf 10665295Srandyf .globl kernel_wc_code 10675295Srandyfkernel_wc_code: 10685295Srandyf / At this point we are with kernel's cs and proper eip. 10695295Srandyf / We will be executing not from the copy in real mode platter, 10705295Srandyf / but from the original code where boot loaded us. 10715295Srandyf / By this time GDT and IDT are loaded as is cr0, cr3 and cr4. 10725295Srandyf / %ebx is wc_cpu 10735295Srandyf / %dx is our ds 10745295Srandyf 10756876Sjan#if LED 10765295Srandyf D16 movb $0xdb, %al 10776876Sjan outb $WC_LED 10786876Sjan#endif 10795295Srandyf 10805295Srandyf/ got here OK 10815295Srandyf 10825295Srandyf movw %dx, %ds / $KDS_SEL 10836876Sjan 10846876Sjan#if LED 10855295Srandyf movb $0xdc, %al 10866876Sjan outb $WC_LED 10876876Sjan#endif 10885295Srandyf 10895817Sjan /* 10905817Sjan * Before proceeding, enable usage of the page table NX bit if 10915817Sjan * that's how the page tables are set up. 10925817Sjan */ 109312826Skuriakose.kuruvilla@oracle.com bt $X86FSET_NX, x86_featureset 109412826Skuriakose.kuruvilla@oracle.com jnc 1f 10955817Sjan movl $MSR_AMD_EFER, %ecx 10965295Srandyf rdmsr 10975817Sjan orl $AMD_EFER_NXE, %eax 10985295Srandyf wrmsr 10995817Sjan1: 11005295Srandyf 11015295Srandyf movl WC_CR4(%ebx), %eax / restore full cr4 (with Global Enable) 11025295Srandyf movl %eax, %cr4 11035295Srandyf 11045295Srandyf 11055295Srandyf lldt WC_LDT(%ebx) / $LDT_SEL 11065295Srandyf 11075295Srandyf movzwl WC_TR(%ebx), %eax / clear TSS busy bit 11085295Srandyf addl WC_GDT+2(%ebx), %eax 11095295Srandyf andl $-1!0x200, 4(%eax) 11105295Srandyf ltr WC_TR(%ebx) / $UTSS_SEL 11115295Srandyf 11129989SJoseph.Townsend@Sun.COM movw WC_SS(%ebx), %ss / restore segment registers 11139989SJoseph.Townsend@Sun.COM movw WC_ES(%ebx), %es 11149989SJoseph.Townsend@Sun.COM movw WC_FS(%ebx), %fs 11159989SJoseph.Townsend@Sun.COM movw WC_GS(%ebx), %gs 11169989SJoseph.Townsend@Sun.COM 11179989SJoseph.Townsend@Sun.COM /* 11189989SJoseph.Townsend@Sun.COM * set the stack pointer to point into the identity mapped page 11199989SJoseph.Townsend@Sun.COM * temporarily, so we can make function calls 11209989SJoseph.Townsend@Sun.COM */ 11219989SJoseph.Townsend@Sun.COM .globl rm_platter_va 11229989SJoseph.Townsend@Sun.COM movl rm_platter_va, %eax 11239989SJoseph.Townsend@Sun.COM movl $WC_STKSTART, %esp 11249989SJoseph.Townsend@Sun.COM addl %eax, %esp 11259989SJoseph.Townsend@Sun.COM movl %esp, %ebp 11269989SJoseph.Townsend@Sun.COM 11279989SJoseph.Townsend@Sun.COM /* 11289989SJoseph.Townsend@Sun.COM * if we are not running on the boot CPU restore stack contents by 11299989SJoseph.Townsend@Sun.COM * calling i_cpr_restore_stack(curthread, save_stack); 11309989SJoseph.Townsend@Sun.COM */ 11319989SJoseph.Townsend@Sun.COM call i_cpr_bootcpuid 11329989SJoseph.Townsend@Sun.COM cmpl %eax, WC_CPU_ID(%ebx) 11339989SJoseph.Townsend@Sun.COM je 2f 11349989SJoseph.Townsend@Sun.COM 11359989SJoseph.Townsend@Sun.COM pushl WC_SAVED_STACK(%ebx) 11369989SJoseph.Townsend@Sun.COM pushl %gs:CPU_THREAD 11379989SJoseph.Townsend@Sun.COM call i_cpr_restore_stack 11389989SJoseph.Townsend@Sun.COM addl $0x10, %esp 11399989SJoseph.Townsend@Sun.COM2: 11409989SJoseph.Townsend@Sun.COM 11419989SJoseph.Townsend@Sun.COM movl WC_ESP(%ebx), %esp 11429989SJoseph.Townsend@Sun.COM movl %esp, %ebp 11435295Srandyf 11445295Srandyf movl WC_RETADDR(%ebx), %eax / return to caller of wc_save_context 11455295Srandyf movl %eax, (%esp) 11465295Srandyf 11475295Srandyf /* 11485817Sjan * APIC initialization, skip iff function pointer is NULL 11495295Srandyf */ 11505817Sjan cmpl $0, ap_mlsetup 11519989SJoseph.Townsend@Sun.COM je 3f 11525817Sjan call *ap_mlsetup 11539989SJoseph.Townsend@Sun.COM3: 11545295Srandyf 11555295Srandyf call *cpr_start_cpu_func 11565295Srandyf 11575295Srandyf pushl WC_EFLAGS(%ebx) / restore flags 11585295Srandyf popfl 11595295Srandyf 11605295Srandyf movl WC_EDI(%ebx), %edi / restore general registers 11615295Srandyf movl WC_ESI(%ebx), %esi 11625295Srandyf movl WC_EBP(%ebx), %ebp 11635295Srandyf movl WC_EBX(%ebx), %ebx 11645295Srandyf 11655295Srandyf/exit: jmp exit / stop here for HDT 11665295Srandyf 11675295Srandyf xorl %eax, %eax / at wakeup return 0 11685295Srandyf ret 11695295Srandyf 11705295Srandyf SET_SIZE(wc_rm_start) 11715295Srandyf 11725295Srandyf 11735295Srandyf#endif /* defined(__amd64) */ 11745295Srandyf 11755295Srandyf#endif /* !defined(__GNU_AS__) */ 11765295Srandyf 11775295Srandyf#endif /* lint */ 11785295Srandyf 1179