acpi_wakecode.S revision 189903
1232366Sdavide/*- 2232366Sdavide * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> 3232366Sdavide * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 4232366Sdavide * Copyright (c) 2003 Peter Wemm 5232366Sdavide * Copyright (c) 2008 Jung-uk Kim <jkim@FreeBSD.org> 6232366Sdavide * All rights reserved. 7232366Sdavide * 8232366Sdavide * Redistribution and use in source and binary forms, with or without 9232366Sdavide * modification, are permitted provided that the following conditions 10232366Sdavide * are met: 11232366Sdavide * 1. Redistributions of source code must retain the above copyright 12232366Sdavide * notice, this list of conditions and the following disclaimer. 13232366Sdavide * 2. Redistributions in binary form must reproduce the above copyright 14232366Sdavide * notice, this list of conditions and the following disclaimer in the 15232366Sdavide * documentation and/or other materials provided with the distribution. 16232366Sdavide * 17232366Sdavide * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18232366Sdavide * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19232366Sdavide * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20232366Sdavide * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21232366Sdavide * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22232366Sdavide * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23232366Sdavide * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24232366Sdavide * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25232366Sdavide * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26232366Sdavide * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27241741Ssbruno * SUCH DAMAGE. 28232366Sdavide * 29232366Sdavide * $FreeBSD: head/sys/amd64/acpica/acpi_wakecode.S 189903 2009-03-17 00:48:11Z jkim $ 30232366Sdavide */ 31232366Sdavide 32232366Sdavide#define LOCORE 33232366Sdavide 34232366Sdavide#include <machine/asmacros.h> 35232366Sdavide#include <machine/specialreg.h> 36232366Sdavide 37232366Sdavide#include "assym.s" 38232366Sdavide 39232366Sdavide/* 40232366Sdavide * Resume entry point for real mode. 41232366Sdavide * 42232366Sdavide * If XFirmwareWakingVector is zero and FirmwareWakingVector is non-zero 43232366Sdavide * in FACS, the BIOS enters here in real mode after POST with CS set to 44232366Sdavide * (FirmwareWakingVector >> 4) and IP set to (FirmwareWakingVector & 0xf). 45232366Sdavide * Depending on the previous sleep state, we may need to initialize more 46232366Sdavide * of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk). 47232366Sdavide * 48232366Sdavide * Note: If XFirmwareWakingVector is non-zero, it should disable address 49232366Sdavide * translation/paging and interrupts, load all segment registers with 50232366Sdavide * a flat 4 GB address space, and set EFLAGS.IF to zero. Currently 51232366Sdavide * this mode is not supported by this code. 52232366Sdavide */ 53232366Sdavide 54232366Sdavide .data /* So we can modify it */ 55232366Sdavide 56232366Sdavide ALIGN_TEXT 57232366Sdavidewakeup_start: 58232366Sdavide .code16 59232366Sdavide /* 60232366Sdavide * Set up segment registers for real mode, a small stack for 61232366Sdavide * any calls we make, and clear any flags. 62232366Sdavide */ 63232366Sdavide cli /* make sure no interrupts */ 64232366Sdavide cld 65232366Sdavide mov %cs, %ax /* copy %cs to %ds. Remember these */ 66232366Sdavide mov %ax, %ds /* are offsets rather than selectors */ 67232366Sdavide mov %ax, %ss 68232366Sdavide movw $PAGE_SIZE - 8, %sp 69232366Sdavide pushw $0 70232366Sdavide popfw 71232366Sdavide 72232366Sdavide /* To debug resume hangs, beep the speaker if the user requested. */ 73232366Sdavide cmpw $0, resume_beep - wakeup_start 74232366Sdavide je 1f 75232366Sdavide movb $0xc0, %al 76232366Sdavide outb %al, $0x42 77232366Sdavide movb $0x04, %al 78232366Sdavide outb %al, $0x42 79232366Sdavide inb $0x61, %al 80232366Sdavide orb $0x3, %al 81232366Sdavide outb %al, $0x61 82232366Sdavide movw $0, resume_beep - wakeup_start 83232366Sdavide1: 84232366Sdavide 85232366Sdavide /* Re-initialize video BIOS if the reset_video tunable is set. */ 86232366Sdavide cmpw $0, reset_video - wakeup_start 87232366Sdavide je 1f 88232366Sdavide lcall $0xc000, $3 89232366Sdavide movw $0, reset_video - wakeup_start 90232366Sdavide 91232366Sdavide /* 92232366Sdavide * Set up segment registers for real mode again in case the 93232366Sdavide * previous BIOS call clobbers them. 94232366Sdavide */ 95232366Sdavide mov %cs, %ax 96232366Sdavide mov %ax, %ds 97232366Sdavide mov %ax, %ss 98232366Sdavide1: 99232366Sdavide 100232366Sdavide /* 101232366Sdavide * Find relocation base and patch the gdt descript and ljmp targets 102232366Sdavide */ 103232366Sdavide xorl %ebx, %ebx 104232366Sdavide mov %cs, %bx 105232366Sdavide sall $4, %ebx /* %ebx is now our relocation base */ 106232366Sdavide 107232366Sdavide /* 108232366Sdavide * Load the descriptor table pointer. We'll need it when running 109232366Sdavide * in 16-bit protected mode. 110232366Sdavide */ 111232366Sdavide lgdtl bootgdtdesc - wakeup_start 112232366Sdavide 113232366Sdavide /* Enable protected mode */ 114232377Spluknet movl $CR0_PE, %eax 115232366Sdavide mov %eax, %cr0 116232366Sdavide 117232366Sdavide /* 118232366Sdavide * Now execute a far jump to turn on protected mode. This 119232366Sdavide * causes the segment registers to turn into selectors and causes 120232366Sdavide * %cs to be loaded from the gdt. 121232366Sdavide * 122232366Sdavide * The following instruction is: 123232366Sdavide * ljmpl $bootcode32 - bootgdt, $wakeup_32 - wakeup_start 124232366Sdavide * but gas cannot assemble that. And besides, we patch the targets 125232366Sdavide * in early startup and its a little clearer what we are patching. 126232366Sdavide */ 127232366Sdavidewakeup_sw32: 128232366Sdavide .byte 0x66 /* size override to 32 bits */ 129232377Spluknet .byte 0xea /* opcode for far jump */ 130232366Sdavide .long wakeup_32 - wakeup_start /* offset in segment */ 131232366Sdavide .word bootcode32 - bootgdt /* index in gdt for 32 bit code */ 132232366Sdavide 133232377Spluknet /* 134232366Sdavide * At this point, we are running in 32 bit legacy protected mode. 135232366Sdavide */ 136232366Sdavide .code32 137232377Spluknetwakeup_32: 138232366Sdavide 139232366Sdavide mov $bootdata32 - bootgdt, %eax 140232366Sdavide mov %ax, %ds 141232366Sdavide 142232366Sdavide /* Turn on the PAE and PSE bits for when paging is enabled */ 143232366Sdavide mov %cr4, %eax 144232377Spluknet orl $(CR4_PAE | CR4_PSE), %eax 145232366Sdavide mov %eax, %cr4 146232366Sdavide 147232366Sdavide /* 148232377Spluknet * Enable EFER.LME so that we get long mode when all the prereqs are 149232366Sdavide * in place. In this case, it turns on when CR0_PG is finally enabled. 150232366Sdavide * Pick up a few other EFER bits that we'll use need we're here. 151232366Sdavide */ 152232377Spluknet movl $MSR_EFER, %ecx 153232366Sdavide rdmsr 154232366Sdavide orl $EFER_LME | EFER_SCE, %eax 155232366Sdavide wrmsr 156232366Sdavide 157232377Spluknet /* 158232366Sdavide * Point to the embedded page tables for startup. Note that this 159232366Sdavide * only gets accessed after we're actually in 64 bit mode, however 160232366Sdavide * we can only set the bottom 32 bits of %cr3 in this state. This 161232377Spluknet * means we are required to use a temporary page table that is below 162232366Sdavide * the 4GB limit. %ebx is still our relocation base. We could just 163232366Sdavide * subtract 3 * PAGE_SIZE, but that would be too easy. 164232366Sdavide */ 165232377Spluknet leal wakeup_pagetables - wakeup_start(%ebx), %eax 166232366Sdavide movl (%eax), %eax 167232366Sdavide mov %eax, %cr3 168232366Sdavide 169232377Spluknet /* 170232377Spluknet * Finally, switch to long bit mode by enabling paging. We have 171232366Sdavide * to be very careful here because all the segmentation disappears 172232366Sdavide * out from underneath us. The spec says we can depend on the 173232366Sdavide * subsequent pipelined branch to execute, but *only if* everthing 174232377Spluknet * is still identity mapped. If any mappings change, the pipeline 175232377Spluknet * will flush. 176232366Sdavide */ 177232366Sdavide mov %cr0, %eax 178232366Sdavide orl $CR0_PG, %eax 179232366Sdavide mov %eax, %cr0 180232377Spluknet 181232366Sdavide /* 182232366Sdavide * At this point paging is enabled, and we are in "compatability" mode. 183232366Sdavide * We do another far jump to reload %cs with the 64 bit selector. 184232377Spluknet * %cr3 points to a 4-level page table page. 185232366Sdavide * We cannot yet jump all the way to the kernel because we can only 186232366Sdavide * specify a 32 bit linear address. So, yet another trampoline. 187232366Sdavide * 188232366Sdavide * The following instruction is: 189232366Sdavide * ljmp $bootcode64 - bootgdt, $wakeup_64 - wakeup_start 190232366Sdavide * but gas cannot assemble that. And besides, we patch the targets 191232366Sdavide * in early startup and its a little clearer what we are patching. 192232366Sdavide */ 193232366Sdavidewakeup_sw64: 194232366Sdavide .byte 0xea /* opcode for far jump */ 195232366Sdavide .long wakeup_64 - wakeup_start /* offset in segment */ 196232366Sdavide .word bootcode64 - bootgdt /* index in gdt for 64 bit code */ 197232366Sdavide 198232366Sdavide /* 199232366Sdavide * Yeehar! We're running in 64-bit mode! We can mostly ignore our 200232366Sdavide * segment registers, and get on with it. 201232366Sdavide * Note that we are running at the correct virtual address, but with 202232366Sdavide * a 1:1 1GB mirrored mapping over entire address space. We had better 203232366Sdavide * switch to a real %cr3 promptly so that we can get to the direct map 204232366Sdavide * space. Remember that jmp is relative and that we've been relocated, 205232366Sdavide * so use an indirect jump. 206232366Sdavide */ 207232366Sdavide .code64 208232366Sdavidewakeup_64: 209232366Sdavide mov $bootdata64 - bootgdt, %eax 210232366Sdavide mov %ax, %ds 211241741Ssbruno 212233628Sfabient /* Restore arguments and return. */ 213232366Sdavide movq wakeup_ctx - wakeup_start(%rbx), %rdi 214232366Sdavide movq wakeup_kpml4 - wakeup_start(%rbx), %rsi 215232366Sdavide movq wakeup_retaddr - wakeup_start(%rbx), %rax 216232366Sdavide jmp *%rax 217232366Sdavide 218232366Sdavide ALIGN_DATA 219232366Sdavidebootgdt: 220232366Sdavide .long 0x00000000 221232366Sdavide .long 0x00000000 222232366Sdavide 223232366Sdavidebootcode64: 224232366Sdavide .long 0x0000ffff 225232366Sdavide .long 0x00af9b00 226232366Sdavide 227232366Sdavidebootdata64: 228232366Sdavide .long 0x0000ffff 229232366Sdavide .long 0x00af9300 230232366Sdavide 231232377Spluknetbootcode32: 232232366Sdavide .long 0x0000ffff 233232366Sdavide .long 0x00cf9b00 234232366Sdavide 235bootdata32: 236 .long 0x0000ffff 237 .long 0x00cf9300 238bootgdtend: 239 240wakeup_pagetables: 241 .long 0 242 243bootgdtdesc: 244 .word bootgdtend - bootgdt /* Length */ 245 .long bootgdt - wakeup_start /* Offset plus %ds << 4 */ 246 247 ALIGN_DATA 248resume_beep: 249 .long 0 250reset_video: 251 .long 0 252wakeup_retaddr: 253 .quad 0 254wakeup_kpml4: 255 .quad 0 256 257wakeup_ctx: 258 .quad 0 259wakeup_xpcb: 260 .quad 0 261wakeup_gdt: 262 .word 0 263 .quad 0 264wakeup_efer: 265 .quad 0 266wakeup_pat: 267 .quad 0 268wakeup_star: 269 .quad 0 270wakeup_lstar: 271 .quad 0 272wakeup_cstar: 273 .quad 0 274wakeup_sfmask: 275 .quad 0 276wakeup_cpu: 277 .long 0 278dummy: 279