acpi_wakecode.S revision 159409
1/*- 2 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> 3 * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 159409 2006-06-08 17:54:10Z njl $ 28 */ 29 30#define LOCORE 31 32#include <machine/asmacros.h> 33#include <machine/specialreg.h> 34 35#include "assym.s" 36 37 .align 4096 38 .code16 39wakeup_16: 40 nop 41 cli 42 43 /* 44 * Set up segment registers for real mode and a small stack for 45 * any calls we make. 46 */ 47 movw %cs,%ax 48 movw %ax,%ds 49 movw %ax,%ss 50 movw $PAGE_SIZE,%sp 51 52 /* To debug resume hangs, beep the speaker if the user requested. */ 53 cmpl $1,resume_beep 54 jne nobeep 55 movb $0xc0,%al 56 outb %al,$0x42 57 movb $0x04,%al 58 outb %al,$0x42 59 inb $0x61,%al 60 orb $0x3,%al 61 outb %al,$0x61 62nobeep: 63 64 /* Re-initialize video BIOS if the reset_video tunable is set. */ 65 cmpl $1,reset_video 66 jne nobiosreset 67 lcall $0xc000,$3 68 69 /* 70 * Set up segment registers for real mode again in case the 71 * previous BIOS call clobbers them. 72 */ 73 movw %cs,%ax 74 movw %ax,%ds 75 movw %ax,%ss 76nobiosreset: 77 78 /* Load GDT for real mode */ 79 lgdt physical_gdt 80 81 /* Restore CR2, CR3 and CR4 */ 82 mov previous_cr2,%eax 83 mov %eax,%cr2 84 mov previous_cr3,%eax 85 mov %eax,%cr3 86 mov previous_cr4,%eax 87 mov %eax,%cr4 88 89 /* Transfer some values to protected mode */ 90#define NVALUES 9 91#define TRANSFER_STACK32(val, idx) \ 92 mov val,%eax; \ 93 mov %eax,wakeup_32stack+(idx+1)+(idx*4); 94 95 TRANSFER_STACK32(previous_ss, (NVALUES - 9)) 96 TRANSFER_STACK32(previous_fs, (NVALUES - 8)) 97 TRANSFER_STACK32(previous_ds, (NVALUES - 7)) 98 TRANSFER_STACK32(physical_gdt+2, (NVALUES - 6)) 99 TRANSFER_STACK32(where_to_recover, (NVALUES - 5)) 100 TRANSFER_STACK32(previous_idt+2, (NVALUES - 4)) 101 TRANSFER_STACK32(previous_ldt, (NVALUES - 3)) 102 TRANSFER_STACK32(previous_gdt+2, (NVALUES - 2)) 103 TRANSFER_STACK32(previous_tr, (NVALUES - 1)) 104 TRANSFER_STACK32(previous_cr0, (NVALUES - 0)) 105 106 mov physical_esp,%esi /* to be used in 32bit code */ 107 108 /* Enable protected mode */ 109 mov %cr0,%eax 110 orl $(CR0_PE),%eax 111 mov %eax,%cr0 112 113wakeup_sw32: 114 /* Switch to protected mode by intersegmental jump */ 115 ljmpl $KCSEL,$0x12345678 /* Code location, to be replaced */ 116 117 .code32 118wakeup_32: 119 /* 120 * Switched to protected mode w/o paging 121 * %esi: KERNEL stack pointer (physical address) 122 */ 123 124 nop 125 126 /* Set up segment registers for protected mode */ 127 movw $KDSEL,%ax /* KDSEL to segment registers */ 128 movw %ax,%ds 129 movw %ax,%es 130 movw %ax,%gs 131 movw %ax,%ss 132 movw $KPSEL,%ax /* KPSEL to %fs */ 133 movw %ax,%fs 134 movl %esi,%esp /* physical address stack pointer */ 135 136wakeup_32stack: 137 /* Operands are overwritten in 16bit code */ 138 pushl $0xabcdef09 /* ss + dummy */ 139 pushl $0xabcdef08 /* fs + gs */ 140 pushl $0xabcdef07 /* ds + es */ 141 pushl $0xabcdef06 /* gdt:base (physical address) */ 142 pushl $0xabcdef05 /* recover address */ 143 pushl $0xabcdef04 /* idt:base */ 144 pushl $0xabcdef03 /* ldt + idt:limit */ 145 pushl $0xabcdef02 /* gdt:base */ 146 pushl $0xabcdef01 /* TR + gdt:limit */ 147 pushl $0xabcdef00 /* CR0 */ 148 149 movl %esp,%ebp 150#define CR0_REGISTER 0(%ebp) 151#define TASK_REGISTER 4(%ebp) 152#define PREVIOUS_GDT 6(%ebp) 153#define PREVIOUS_LDT 12(%ebp) 154#define PREVIOUS_IDT 14(%ebp) 155#define RECOVER_ADDR 20(%ebp) 156#define PHYSICAL_GDT_BASE 24(%ebp) 157#define PREVIOUS_DS 28(%ebp) 158#define PREVIOUS_ES 30(%ebp) 159#define PREVIOUS_FS 32(%ebp) 160#define PREVIOUS_GS 34(%ebp) 161#define PREVIOUS_SS 36(%ebp) 162 163 /* Fixup TSS type field */ 164#define TSS_TYPEFIX_MASK 0xf9 165 xorl %esi,%esi 166 movl PHYSICAL_GDT_BASE,%ebx 167 movw TASK_REGISTER,%si 168 leal (%ebx,%esi),%eax /* get TSS segment descriptor */ 169 andb $TSS_TYPEFIX_MASK,5(%eax) 170 171 /* Prepare to return to sleep/wakeup code point */ 172 lgdt PREVIOUS_GDT 173 lidt PREVIOUS_IDT 174 175 xorl %eax,%eax 176 movl %eax,%ebx 177 movl %eax,%ecx 178 movl %eax,%edx 179 movl %eax,%esi 180 movl %eax,%edi 181 movl PREVIOUS_DS,%ebx 182 movl PREVIOUS_FS,%ecx 183 movl PREVIOUS_SS,%edx 184 movw TASK_REGISTER,%si 185 shll $16,%esi 186 movw PREVIOUS_LDT,%si 187 movl RECOVER_ADDR,%edi 188 189 /* Enable paging and etc. */ 190 movl CR0_REGISTER,%eax 191 movl %eax,%cr0 192 193 /* Flush the prefetch queue */ 194 jmp 1f 1951: jmp 1f 1961: 197 /* 198 * Now that we are in kernel virtual memory addressing 199 * %ebx: ds + es 200 * %ecx: fs + gs 201 * %edx: ss + dummy 202 * %esi: LDTR + TR 203 * %edi: recover address 204 */ 205 206 nop 207 208 movl %esi,%eax /* LDTR + TR */ 209 lldt %ax /* load LDT register */ 210 shrl $16,%eax 211 ltr %ax /* load task register */ 212 213 /* Restore segment registers */ 214 movl %ebx,%eax /* ds + es */ 215 movw %ax,%ds 216 shrl $16,%eax 217 movw %ax,%es 218 movl %ecx,%eax /* fs + gs */ 219 movw %ax,%fs 220 shrl $16,%eax 221 movw %ax,%gs 222 movl %edx,%eax /* ss */ 223 movw %ax,%ss 224 225 /* Jump to acpi_restorecpu() */ 226 jmp *%edi 227 228/* used in real mode */ 229physical_gdt: .word 0 230 .long 0 231physical_esp: .long 0 232previous_cr2: .long 0 233previous_cr3: .long 0 234previous_cr4: .long 0 235resume_beep: .long 0 236reset_video: .long 0 237 238/* transfer from real mode to protected mode */ 239previous_cr0: .long 0 240previous_tr: .word 0 241previous_gdt: .word 0 242 .long 0 243previous_ldt: .word 0 244previous_idt: .word 0 245 .long 0 246where_to_recover: .long 0 247previous_ds: .word 0 248previous_es: .word 0 249previous_fs: .word 0 250previous_gs: .word 0 251previous_ss: .word 0 252dummy: .word 0 253