1 .section .text.page_aligned 2#include <linux/linkage.h> 3#include <asm/segment.h> 4#include <asm/page.h> 5 6# 7# wakeup_code runs in real mode, and at unknown address (determined at run-time). 8# Therefore it must only use relative jumps/calls. 9# 10# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled 11# 12# If physical address of wakeup_code is 0x12345, BIOS should call us with 13# cs = 0x1234, eip = 0x05 14# 15 16#define BEEP \ 17 inb $97, %al; \ 18 outb %al, $0x80; \ 19 movb $3, %al; \ 20 outb %al, $97; \ 21 outb %al, $0x80; \ 22 movb $-74, %al; \ 23 outb %al, $67; \ 24 outb %al, $0x80; \ 25 movb $-119, %al; \ 26 outb %al, $66; \ 27 outb %al, $0x80; \ 28 movb $15, %al; \ 29 outb %al, $66; 30 31ALIGN 32 .align 4096 33ENTRY(wakeup_start) 34wakeup_code: 35 wakeup_code_start = . 36 .code16 37 38 cli 39 cld 40 41 # setup data segment 42 movw %cs, %ax 43 movw %ax, %ds # Make ds:0 point to wakeup_start 44 movw %ax, %ss 45 46 testl $4, realmode_flags - wakeup_code 47 jz 1f 48 BEEP 491: 50 mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board 51 52 pushl $0 # Kill any dangerous flags 53 popfl 54 55 movl real_magic - wakeup_code, %eax 56 cmpl $0x12345678, %eax 57 jne bogus_real_magic 58 59 testl $1, realmode_flags - wakeup_code 60 jz 1f 61 lcall $0xc000,$3 62 movw %cs, %ax 63 movw %ax, %ds # Bios might have played with that 64 movw %ax, %ss 651: 66 67 testl $2, realmode_flags - wakeup_code 68 jz 1f 69 mov video_mode - wakeup_code, %ax 70 call mode_set 711: 72 73 # set up page table 74 movl $swsusp_pg_dir-__PAGE_OFFSET, %eax 75 movl %eax, %cr3 76 77 testl $1, real_efer_save_restore - wakeup_code 78 jz 4f 79 # restore efer setting 80 movl real_save_efer_edx - wakeup_code, %edx 81 movl real_save_efer_eax - wakeup_code, %eax 82 mov $0xc0000080, %ecx 83 wrmsr 844: 85 # make sure %cr4 is set correctly (features, etc) 86 movl real_save_cr4 - wakeup_code, %eax 87 movl %eax, %cr4 88 89 # need a gdt -- use lgdtl to force 32-bit operands, in case 90 # the GDT is located past 16 megabytes. 91 lgdtl real_save_gdt - wakeup_code 92 93 movl real_save_cr0 - wakeup_code, %eax 94 movl %eax, %cr0 95 jmp 1f 961: 97 movl real_magic - wakeup_code, %eax 98 cmpl $0x12345678, %eax 99 jne bogus_real_magic 100 101 testl $8, realmode_flags - wakeup_code 102 jz 1f 103 BEEP 1041: 105 ljmpl $__KERNEL_CS, $wakeup_pmode_return 106 107real_save_gdt: .word 0 108 .long 0 109real_save_cr0: .long 0 110real_save_cr3: .long 0 111real_save_cr4: .long 0 112real_magic: .long 0 113video_mode: .long 0 114realmode_flags: .long 0 115real_efer_save_restore: .long 0 116real_save_efer_edx: .long 0 117real_save_efer_eax: .long 0 118 119bogus_real_magic: 120 jmp bogus_real_magic 121 122/* This code uses an extended set of video mode numbers. These include: 123 * Aliases for standard modes 124 * NORMAL_VGA (-1) 125 * EXTENDED_VGA (-2) 126 * ASK_VGA (-3) 127 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack 128 * of compatibility when extending the table. These are between 0x00 and 0xff. 129 */ 130#define VIDEO_FIRST_MENU 0x0000 131 132/* Standard BIOS video modes (BIOS number + 0x0100) */ 133#define VIDEO_FIRST_BIOS 0x0100 134 135/* VESA BIOS video modes (VESA number + 0x0200) */ 136#define VIDEO_FIRST_VESA 0x0200 137 138/* Video7 special modes (BIOS number + 0x0900) */ 139#define VIDEO_FIRST_V7 0x0900 140 141# Setting of user mode (AX=mode ID) => CF=success 142 143# For now, we only handle VESA modes (0x0200..0x03ff). To handle other 144# modes, we should probably compile in the video code from the boot 145# directory. 146mode_set: 147 movw %ax, %bx 148 subb $VIDEO_FIRST_VESA>>8, %bh 149 cmpb $2, %bh 150 jb check_vesa 151 152setbad: 153 clc 154 ret 155 156check_vesa: 157 orw $0x4000, %bx # Use linear frame buffer 158 movw $0x4f02, %ax # VESA BIOS mode set call 159 int $0x10 160 cmpw $0x004f, %ax # AL=4f if implemented 161 jnz setbad # AH=0 if OK 162 163 stc 164 ret 165 166 .code32 167 ALIGN 168 169.org 0x800 170wakeup_stack_begin: # Stack grows down 171 172.org 0xff0 # Just below end of page 173wakeup_stack: 174ENTRY(wakeup_end) 175 176.org 0x1000 177 178wakeup_pmode_return: 179 movw $__KERNEL_DS, %ax 180 movw %ax, %ss 181 movw %ax, %ds 182 movw %ax, %es 183 movw %ax, %fs 184 movw %ax, %gs 185 186 # reload the gdt, as we need the full 32 bit address 187 lgdt saved_gdt 188 lidt saved_idt 189 lldt saved_ldt 190 ljmp $(__KERNEL_CS),$1f 1911: 192 movl %cr3, %eax 193 movl %eax, %cr3 194 wbinvd 195 196 # and restore the stack ... but you need gdt for this to work 197 movl saved_context_esp, %esp 198 199 movl %cs:saved_magic, %eax 200 cmpl $0x12345678, %eax 201 jne bogus_magic 202 203 # jump to place where we left off 204 movl saved_eip,%eax 205 jmp *%eax 206 207bogus_magic: 208 jmp bogus_magic 209 210 211## 212# acpi_copy_wakeup_routine 213# 214# Copy the above routine to low memory. 215# 216# Parameters: 217# %eax: place to copy wakeup routine to 218# 219# Returned address is location of code in low memory (past data and stack) 220# 221ENTRY(acpi_copy_wakeup_routine) 222 223 pushl %ebx 224 sgdt saved_gdt 225 sidt saved_idt 226 sldt saved_ldt 227 str saved_tss 228 229 movl nx_enabled, %edx 230 movl %edx, real_efer_save_restore - wakeup_start (%eax) 231 testl $1, real_efer_save_restore - wakeup_start (%eax) 232 jz 2f 233 # save efer setting 234 pushl %eax 235 movl %eax, %ebx 236 mov $0xc0000080, %ecx 237 rdmsr 238 movl %edx, real_save_efer_edx - wakeup_start (%ebx) 239 movl %eax, real_save_efer_eax - wakeup_start (%ebx) 240 popl %eax 2412: 242 243 movl %cr3, %edx 244 movl %edx, real_save_cr3 - wakeup_start (%eax) 245 movl %cr4, %edx 246 movl %edx, real_save_cr4 - wakeup_start (%eax) 247 movl %cr0, %edx 248 movl %edx, real_save_cr0 - wakeup_start (%eax) 249 sgdt real_save_gdt - wakeup_start (%eax) 250 251 movl saved_videomode, %edx 252 movl %edx, video_mode - wakeup_start (%eax) 253 movl acpi_realmode_flags, %edx 254 movl %edx, realmode_flags - wakeup_start (%eax) 255 movl $0x12345678, real_magic - wakeup_start (%eax) 256 movl $0x12345678, saved_magic 257 popl %ebx 258 ret 259 260save_registers: 261 leal 4(%esp), %eax 262 movl %eax, saved_context_esp 263 movl %ebx, saved_context_ebx 264 movl %ebp, saved_context_ebp 265 movl %esi, saved_context_esi 266 movl %edi, saved_context_edi 267 pushfl ; popl saved_context_eflags 268 269 movl $ret_point, saved_eip 270 ret 271 272 273restore_registers: 274 movl saved_context_ebp, %ebp 275 movl saved_context_ebx, %ebx 276 movl saved_context_esi, %esi 277 movl saved_context_edi, %edi 278 pushl saved_context_eflags ; popfl 279 ret 280 281ENTRY(do_suspend_lowlevel) 282 call save_processor_state 283 call save_registers 284 pushl $3 285 call acpi_enter_sleep_state 286 addl $4, %esp 287 288# In case of S3 failure, we'll emerge here. Jump 289# to ret_point to recover 290 jmp ret_point 291 .p2align 4,,7 292ret_point: 293 call restore_registers 294 call restore_processor_state 295 ret 296 297.data 298ALIGN 299ENTRY(saved_magic) .long 0 300ENTRY(saved_eip) .long 0 301 302# saved registers 303saved_gdt: .long 0,0 304saved_idt: .long 0,0 305saved_ldt: .long 0 306saved_tss: .long 0 307 308