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