cpr_wakecode.s revision bc4466305498eebc620bcefaac080629452b3156
1N/A * The contents of this file are subject to the terms of the 1N/A * Common Development and Distribution License (the "License"). 1N/A * You may not use this file except in compliance with the License. 1N/A * See the License for the specific language governing permissions 1N/A * and limitations under the License. 1N/A * When distributing Covered Code, include this CDDL HEADER in each 1N/A * If applicable, add the following below this CDDL HEADER, with the 1N/A * fields enclosed by brackets "[]" replaced with your own identifying 1N/A * information: Portions Copyright [yyyy] [name of copyright owner] 1N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 1N/A * Use is subject to license terms. 1N/A#
define WC_LED 0x80 /* diagnostic led port ON motherboard */ * defined as offsets from the data register #
define DLL 0
/* divisor latch (lsb) */#
define DLH 1 /* divisor latch (msb) */#
define LCR 3 /* line control register */#
define MCR 4 /* modem control register */#
define DLAB 0x80 /* divisor latch access bit */#
define B9600L 0X0c /* lsb bit pattern for 9600 baud */#
define B9600H 0X0 /* hsb bit pattern for 9600 baud */#
define DTR 0x01 /* Data Terminal Ready */#
define RTS 0x02 /* Request To Send */#
define STOP1 0x00 /* 1 stop bit */#
define BITS8 0x03 /* 8 bits per char */ * This file contains the low level routines involved in getting * into and out of ACPI S3, including those needed for restarting #
else /* !defined(__GNU_AS__) */ * - We are running in real mode. * - Interrupts are disabled. * - We start using our GDT by loading correct values in the * selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL, * - We change over to using our IDT. * - We load the default LDT into the hardware LDT register. * - We load the default TSS into the hardware task register. * - We return to original caller (a la setjmp) * For vulcan as we need to do a .code32 and mentally invert the * meaning of the addr16 and data16 prefixes to get 32-bit access when * generating code to be executed in 16-bit mode (sigh...) * Enable protected-mode, write protect, and alignment mask * %cr0 has already been initialsed to zero * Do a jmp immediately after writing to cr0 when enabling protected * mode to clear the real mode prefetch queue (per Intel's docs) * 16-bit protected mode is now active, so prepare to turn on long * Add any initial cr4 bits * Enable PAE mode (CR4.PAE) * Point cr3 to the 64-bit long mode page tables. * Note that these MUST exist in 32-bit space, as we don't have * a way to load %cr3 with a 64-bit base address for the page tables * until the CPU is actually executing in 64-bit long mode. * Set long mode enable in EFER (EFER.LME = 1) * Finally, turn on paging (CR0.PG = 1) to activate long mode. * The instruction after enabling paging in CR0 MUST be a branch. * Long mode is now active but since we're still running with the * original 16-bit CS we're actually in 16-bit compatability mode. * We have to load an intermediate GDT and IDT here that we know are * in 32-bit space before we can use the kernel's GDT and IDT, which * may be in the 64-bit address space, and since we're in compatability * mode, we only have access to 16 and 32-bit instructions at the * Do a far transfer to 64-bit mode. Set the CS selector to a 64-bit * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump * to the real mode platter address of wc_long_mode_64 as until the * 64-bit CS is in place we don't have access to 64-bit instructions * and thus can't reference a 64-bit %rip. * Support routine to re-initialize VGA subsystem * Support routine to re-initialize keyboard (which is USB - help!) * Support routine to re-initialize COM ports to something sane * on debug kernels we need to initialize COM1 & COM2 here, so that * we can get debug output before the asy driver has resumed * We are now running in long mode with a 64-bit CS (EFER.LMA=1, * CS.L=1) so we now have access to 64-bit instructions. * First, set the 64-bit GDT base. * Save the CPU number in %r11; get the value here since it's saved in * Add rm_platter_pa to %rsp to point it to the same location as seen * Now do an lretq to load CS with the appropriate selector for the * kernel's 64-bit GDT and to start executing 64-bit setup code at the * virtual address where boot originally loaded this code rather than * the copy in the real mode platter's rm_code array as we've been * Complete the balance of the setup we need to before executing * 64-bit kernel code (namely init rsp, TSS, LGDT, FS and GS). * restore the rest of the registers * restore the rest of the registers * Before proceeding, enable usage of the page table NX bit if * that's how the page tables are set up. movq %
rsp, %
rbp /* stack aligned on 16-byte boundary */ * skip iff function pointer is NULL * can not use outb after this point, because doing so would mean using * %dx which would modify %rdx which is restored here D16 A16 movl %cs:WC_CR3(%ebx), %eax / set PDPT D16 A16 movl %cs:WC_CR0(%ebx), %eax / enable prot/paging, etc. D16 A16 movl %cs:WC_VIRTADDR(%ebx), %ebx / virtaddr of wc_cpu_t jmp flush / flush prefetch queue D16 pushl $kernel_wc_code D16 lret / re-appear at kernel_wc_code * Support routine to re-initialize VGA subsystem * Support routine to re-initialize keyboard (which is USB - help!) * Support routine to re-initialize COM ports to something sane for debug output * on debug kernels we need to initialize COM1 & COM2 here, so that * we can get debug output before the asy driver has resumed D16 movl $[COM1+LCR], %edx D16 movb $DLAB, %al / divisor latch D16 movl $[COM1+DLL], %edx / divisor latch lsb D16 movb $B9600L, %al / divisor latch D16 movl $[COM1+DLH], %edx / divisor latch hsb D16 movb $B9600H, %al / divisor latch D16 movl $[COM1+LCR], %edx / select COM1 D16 movb $[STOP1|BITS8], %al / 1 stop bit, 8bit word len D16 movl $[COM1+MCR], %edx / select COM1 D16 movb $[RTS|DTR], %al / 1 stop bit, 8bit word len D16 movl $[COM2+LCR], %edx D16 movb $DLAB, %al / divisor latch D16 movl $[COM2+DLL], %edx / divisor latch lsb D16 movb $B9600L, %al / divisor latch D16 movl $[COM2+DLH], %edx / divisor latch hsb D16 movb $B9600H, %al / divisor latch D16 movl $[COM2+LCR], %edx / select COM1 D16 movb $[STOP1|BITS8], %al / 1 stop bit, 8bit word len D16 movl $[COM2+MCR], %edx / select COM1 D16 movb $[RTS|DTR], %al / 1 stop bit, 8bit word len * Before proceeding, enable usage of the page table NX bit if * that's how the page tables are set up. movl WC_RETADDR(%ebx), %eax / return to caller of wc_save_context movw WC_ES(%ebx), %es / restore segment registers * APIC initialization, skip iff function pointer is NULL pushl WC_EFLAGS(%ebx) / restore flags movl WC_EDI(%ebx), %edi / restore general registers /exit: jmp exit / stop here for HDT xorl %eax, %eax / at wakeup return 0 #endif /* defined(__amd64) */ #endif /* !defined(__GNU_AS__) */