acpi_wakecode.S (215200) | acpi_wakecode.S (235622) |
---|---|
1/*- 2 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> | 1/*- 2 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> |
3 * Copyright (c) 2001 Mitsuru IWASAKI | 3 * Copyright (c) 2001-2012 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 4 * Copyright (c) 2003 Peter Wemm 5 * Copyright (c) 2008-2012 Jung-uk Kim <jkim@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 --- 7 unchanged lines hidden (view full) --- 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 * | 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright --- 7 unchanged lines hidden (view full) --- 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * |
27 * $FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 215200 2010-11-12 20:55:14Z jkim $ | 29 * $FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 235622 2012-05-18 18:55:58Z iwasaki $ |
28 */ 29 30#include <machine/asmacros.h> | 30 */ 31 32#include <machine/asmacros.h> |
33#include <machine/ppireg.h> |
|
31#include <machine/specialreg.h> | 34#include <machine/specialreg.h> |
35#include <machine/timerreg.h> |
|
32 33#include "assym.s" 34 35/* 36 * Resume entry point. The BIOS enters here in real mode after POST with 37 * CS set to the page where we stored this code. It should configure the 38 * segment registers with a flat 4 GB address space and EFLAGS.IF = 0. 39 * Depending on the previous sleep state, we may need to initialize more 40 * of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk). 41 */ | 36 37#include "assym.s" 38 39/* 40 * Resume entry point. The BIOS enters here in real mode after POST with 41 * CS set to the page where we stored this code. It should configure the 42 * segment registers with a flat 4 GB address space and EFLAGS.IF = 0. 43 * Depending on the previous sleep state, we may need to initialize more 44 * of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk). 45 */ |
42 .align 4 43 .code16 44wakeup_16: 45 nop 46 cli 47 cld | |
48 | 46 |
47 .data /* So we can modify it */ 48 49 ALIGN_TEXT 50 .code16 51wakeup_start: |
|
49 /* 50 * Set up segment registers for real mode, a small stack for 51 * any calls we make, and clear any flags. 52 */ | 52 /* 53 * Set up segment registers for real mode, a small stack for 54 * any calls we make, and clear any flags. 55 */ |
53 movw %cs,%ax 54 movw %ax,%ds 55 movw %ax,%ss 56 movw $PAGE_SIZE,%sp 57 pushl $0 58 popfl | 56 cli /* make sure no interrupts */ 57 mov %cs, %ax /* copy %cs to %ds. Remember these */ 58 mov %ax, %ds /* are offsets rather than selectors */ 59 mov %ax, %ss 60 movw $PAGE_SIZE, %sp 61 xorw %ax, %ax 62 pushw %ax 63 popfw |
59 60 /* To debug resume hangs, beep the speaker if the user requested. */ | 64 65 /* To debug resume hangs, beep the speaker if the user requested. */ |
61 cmpl $1,resume_beep 62 jne nobeep 63 movb $0xc0,%al 64 outb %al,$0x42 65 movb $0x04,%al 66 outb %al,$0x42 67 inb $0x61,%al 68 orb $0x3,%al 69 outb %al,$0x61 70nobeep: | 66 testb $~0, resume_beep - wakeup_start 67 jz 1f 68 movb $0, resume_beep - wakeup_start |
71 | 69 |
72 /* Re-initialize video BIOS if the reset_video tunable is set. */ 73 cmpl $1,reset_video 74 jne nobiosreset 75 lcall $0xc000,$3 | 70 /* Set PIC timer2 to beep. */ 71 movb $(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT), %al 72 outb %al, $TIMER_MODE |
76 | 73 |
77 /* 78 * Set up segment registers for real mode again in case the 79 * previous BIOS call clobbers them. 80 */ 81 movw %cs,%ax 82 movw %ax,%ds 83 movw %ax,%ss 84nobiosreset: | 74 /* Turn on speaker. */ 75 inb $IO_PPI, %al 76 orb $PIT_SPKR, %al 77 outb %al, $IO_PPI |
85 | 78 |
86 /* Load GDT for real mode. Use 32 bit prefix for addresses >16 MB. */ 87 lgdtl physical_gdt | 79 /* Set frequency. */ 80 movw $0x4c0, %ax 81 outb %al, $TIMER_CNTR2 82 shrw $8, %ax 83 outb %al, $TIMER_CNTR2 841: |
88 | 85 |
89 /* Restore CR2, CR3 and CR4 */ 90 movl previous_cr2,%eax 91 movl %eax,%cr2 92 movl previous_cr3,%eax 93 movl %eax,%cr3 94 movl previous_cr4,%eax 95 movl %eax,%cr4 | 86 /* Re-initialize video BIOS if the reset_video tunable is set. */ 87 testb $~0, reset_video - wakeup_start 88 jz 1f 89 movb $0, reset_video - wakeup_start 90 lcall $0xc000, $3 |
96 | 91 |
97 /* Transfer some values to protected mode with an inline stack */ 98#define NVALUES 9 99#define TRANSFER_STACK32(val, idx) \ 100 movl val,%eax; \ 101 movl %eax,wakeup_32stack+(idx+1)+(idx*4) | 92 /* When we reach here, int 0x10 should be ready. Hide cursor. */ 93 movb $0x01, %ah 94 movb $0x20, %ch 95 int $0x10 |
102 | 96 |
103 TRANSFER_STACK32(previous_ss, (NVALUES - 9)) 104 TRANSFER_STACK32(previous_fs, (NVALUES - 8)) 105 TRANSFER_STACK32(previous_ds, (NVALUES - 7)) 106 TRANSFER_STACK32(physical_gdt+2, (NVALUES - 6)) 107 TRANSFER_STACK32(where_to_recover, (NVALUES - 5)) 108 TRANSFER_STACK32(previous_idt+2, (NVALUES - 4)) 109 TRANSFER_STACK32(previous_ldt, (NVALUES - 3)) 110 TRANSFER_STACK32(previous_gdt+2, (NVALUES - 2)) 111 TRANSFER_STACK32(previous_tr, (NVALUES - 1)) 112 TRANSFER_STACK32(previous_cr0, (NVALUES - 0)) | 97 /* Re-start in case the previous BIOS call clobbers them. */ 98 jmp wakeup_start 991: |
113 | 100 |
114 mov physical_esp,%esi /* to be used in 32bit code */ | 101 /* 102 * Find relocation base and patch the gdt descript and ljmp targets 103 */ 104 xorl %ebx, %ebx 105 mov %cs, %bx 106 sall $4, %ebx /* %ebx is now our relocation base */ |
115 | 107 |
108 /* 109 * Load the descriptor table pointer. We'll need it when running 110 * in 16-bit protected mode. 111 */ 112 lgdtl bootgdtdesc - wakeup_start 113 |
|
116 /* Enable protected mode */ | 114 /* Enable protected mode */ |
117 movl %cr0,%eax 118 orl $(CR0_PE),%eax 119 movl %eax,%cr0 | 115 movl $CR0_PE, %eax 116 mov %eax, %cr0 |
120 | 117 |
118 /* 119 * Now execute a far jump to turn on protected mode. This 120 * causes the segment registers to turn into selectors and causes 121 * %cs to be loaded from the gdt. 122 * 123 * The following instruction is: 124 * ljmpl $bootcode32 - bootgdt, $wakeup_32 - wakeup_start 125 * but gas cannot assemble that. And besides, we patch the targets 126 * in early startup and its a little clearer what we are patching. 127 */ |
|
121wakeup_sw32: | 128wakeup_sw32: |
122 /* Switch to protected mode by intersegmental jump */ 123 ljmpl $KCSEL,$0x12345678 /* Code location, to be replaced */ | 129 .byte 0x66 /* size override to 32 bits */ 130 .byte 0xea /* opcode for far jump */ 131 .long wakeup_32 - wakeup_start /* offset in segment */ 132 .word bootcode32 - bootgdt /* index in gdt for 32 bit code */ |
124 125 /* | 133 134 /* |
126 * Now switched to protected mode without paging enabled. 127 * %esi: KERNEL stack pointer (physical address) | 135 * At this point, we are running in 32 bit legacy protected mode. |
128 */ | 136 */ |
137 ALIGN_TEXT |
|
129 .code32 130wakeup_32: | 138 .code32 139wakeup_32: |
131 nop | |
132 | 140 |
133 /* Set up segment registers for protected mode */ 134 movw $KDSEL,%ax /* KDSEL to segment registers */ 135 movw %ax,%ds 136 movw %ax,%es 137 movw %ax,%gs 138 movw %ax,%ss 139 movw $KPSEL,%ax /* KPSEL to %fs */ 140 movw %ax,%fs 141 movl %esi,%esp /* physical address stack pointer */ | 141 mov $bootdata32 - bootgdt, %eax 142 mov %ax, %ds |
142 | 143 |
143wakeup_32stack: 144 /* Operands are overwritten in 16 bit code by TRANSFER_STACK32 macro */ 145 pushl $0xabcdef09 /* ss + dummy */ 146 pushl $0xabcdef08 /* fs + gs */ 147 pushl $0xabcdef07 /* ds + es */ 148 pushl $0xabcdef06 /* gdt:base (physical address) */ 149 pushl $0xabcdef05 /* recover address */ 150 pushl $0xabcdef04 /* idt:base */ 151 pushl $0xabcdef03 /* ldt + idt:limit */ 152 pushl $0xabcdef02 /* gdt:base */ 153 pushl $0xabcdef01 /* TR + gdt:limit */ 154 pushl $0xabcdef00 /* CR0 */ | 144 /* Get PCB and return address. */ 145 movl wakeup_pcb - wakeup_start(%ebx), %esi 146 movl wakeup_ret - wakeup_start(%ebx), %edi |
155 | 147 |
156 movl %esp,%ebp 157#define CR0_REGISTER 0(%ebp) 158#define TASK_REGISTER 4(%ebp) 159#define PREVIOUS_GDT 6(%ebp) 160#define PREVIOUS_LDT 12(%ebp) 161#define PREVIOUS_IDT 14(%ebp) 162#define RECOVER_ADDR 20(%ebp) 163#define PHYSICAL_GDT_BASE 24(%ebp) 164#define PREVIOUS_DS 28(%ebp) 165#define PREVIOUS_ES 30(%ebp) 166#define PREVIOUS_FS 32(%ebp) 167#define PREVIOUS_GS 34(%ebp) 168#define PREVIOUS_SS 36(%ebp) | 148 /* Restore CR4 and CR3. */ 149 movl wakeup_cr4 - wakeup_start(%ebx), %eax 150 mov %eax, %cr4 151 movl wakeup_cr3 - wakeup_start(%ebx), %eax 152 mov %eax, %cr3 |
169 | 153 |
170 /* Fixup TSS type field */ 171#define TSS_TYPEFIX_MASK 0xf9 172 xorl %esi,%esi 173 movl PHYSICAL_GDT_BASE,%ebx 174 movw TASK_REGISTER,%si 175 leal (%ebx,%esi),%eax /* get TSS segment descriptor */ 176 andb $TSS_TYPEFIX_MASK,5(%eax) | 154 /* 155 * Finally, switch to long bit mode by enabling paging. We have 156 * to be very careful here because all the segmentation disappears 157 * out from underneath us. The spec says we can depend on the 158 * subsequent pipelined branch to execute, but *only if* everthing 159 * is still identity mapped. If any mappings change, the pipeline 160 * will flush. 161 */ 162 mov %cr0, %eax 163 orl $CR0_PG, %eax 164 mov %eax, %cr0 |
177 | 165 |
178 /* Prepare to return to sleep/wakeup code point */ 179 lgdtl PREVIOUS_GDT 180 lidtl PREVIOUS_IDT 181 182 /* Pack values from the GDT to be loaded into segment registers. */ 183 movl PREVIOUS_DS,%ebx 184 movl PREVIOUS_FS,%ecx 185 movl PREVIOUS_SS,%edx 186 movw TASK_REGISTER,%si 187 shll $16,%esi 188 movw PREVIOUS_LDT,%si 189 movl RECOVER_ADDR,%edi 190 191 /* Enable paging and etc. */ 192 movl CR0_REGISTER,%eax 193 movl %eax,%cr0 194 195 /* Flush the prefetch queue */ | |
196 jmp 1f | 166 jmp 1f |
1971: jmp 1f | |
1981: | 1671: |
168 /* Jump to return address. */ 169 jmp *%edi |
|
199 | 170 |
200 /* 201 * Now we are in kernel virtual memory addressing with the following 202 * original register values: 203 * %ebx: ds + es 204 * %ecx: fs + gs 205 * %edx: ss + dummy 206 * %esi: LDTR + TR 207 * %edi: recover address 208 * We'll load these back into the segment registers now. 209 */ 210 nop | 171 .data |
211 | 172 |
212 movl %esi,%eax /* LDTR + TR */ 213 lldt %ax /* load LDT register */ 214 shrl $16,%eax 215 ltr %ax /* load task register */ | 173resume_beep: 174 .byte 0 175reset_video: 176 .byte 0 |
216 | 177 |
217 /* Restore segment registers */ 218 movl %ebx,%eax /* ds + es */ 219 movw %ax,%ds 220 shrl $16,%eax 221 movw %ax,%es 222 movl %ecx,%eax /* fs + gs */ 223 movw %ax,%fs 224 shrl $16,%eax 225 movw %ax,%gs 226 movl %edx,%eax /* ss */ 227 movw %ax,%ss | 178 ALIGN_DATA 179bootgdt: 180 .long 0x00000000 181 .long 0x00000000 |
228 | 182 |
229 /* Jump to acpi_restorecpu() */ 230 jmp *%edi | 183bootcode32: 184 .long 0x0000ffff 185 .long 0x00cf9b00 |
231 | 186 |
232/* used in real mode */ 233physical_gdt: .word 0 234 .long 0 235physical_esp: .long 0 236previous_cr2: .long 0 237previous_cr3: .long 0 238previous_cr4: .long 0 239resume_beep: .long 0 240reset_video: .long 0 | 187bootdata32: 188 .long 0x0000ffff 189 .long 0x00cf9300 190bootgdtend: |
241 | 191 |
242/* 243 * Transfer from real mode to protected mode. The order of these variables 244 * is very important, DO NOT INSERT OR CHANGE unless you know why. 245 */ 246previous_cr0: .long 0 247previous_tr: .word 0 248previous_gdt: .word 0 249 .long 0 250previous_ldt: .word 0 251previous_idt: .word 0 252 .long 0 253where_to_recover: .long 0 254previous_ds: .word 0 255previous_es: .word 0 256previous_fs: .word 0 257previous_gs: .word 0 258previous_ss: .word 0 259dummy: .word 0 | 192bootgdtdesc: 193 .word bootgdtend - bootgdt /* Length */ 194 .long bootgdt - wakeup_start /* Offset plus %ds << 4 */ 195 196 ALIGN_DATA 197wakeup_cr4: 198 .long 0 199wakeup_cr3: 200 .long 0 201wakeup_pcb: 202 .long 0 203wakeup_ret: 204 .long 0 205dummy: |