123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- .text
- #include <linux/linkage.h>
- #include <asm/segment.h>
- #include <asm/page.h>
- #
- # wakeup_code runs in real mode, and at unknown address (determined at run-time).
- # Therefore it must only use relative jumps/calls.
- #
- # Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
- #
- # If physical address of wakeup_code is 0x12345, BIOS should call us with
- # cs = 0x1234, eip = 0x05
- #
- ALIGN
- .align 4096
- ENTRY(wakeup_start)
- wakeup_code:
- wakeup_code_start = .
- .code16
- movw $0xb800, %ax
- movw %ax,%fs
- movw $0x0e00 + 'L', %fs:(0x10)
- cli
- cld
- # setup data segment
- movw %cs, %ax
- movw %ax, %ds # Make ds:0 point to wakeup_start
- movw %ax, %ss
- mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board
- movw $0x0e00 + 'S', %fs:(0x12)
- pushl $0 # Kill any dangerous flags
- popfl
- movl real_magic - wakeup_code, %eax
- cmpl $0x12345678, %eax
- jne bogus_real_magic
- testl $1, video_flags - wakeup_code
- jz 1f
- lcall $0xc000,$3
- movw %cs, %ax
- movw %ax, %ds # Bios might have played with that
- movw %ax, %ss
- 1:
- testl $2, video_flags - wakeup_code
- jz 1f
- mov video_mode - wakeup_code, %ax
- call mode_set
- 1:
- # set up page table
- movl $swapper_pg_dir-__PAGE_OFFSET, %eax
- movl %eax, %cr3
- testl $1, real_efer_save_restore - wakeup_code
- jz 4f
- # restore efer setting
- movl real_save_efer_edx - wakeup_code, %edx
- movl real_save_efer_eax - wakeup_code, %eax
- mov $0xc0000080, %ecx
- wrmsr
- 4:
- # make sure %cr4 is set correctly (features, etc)
- movl real_save_cr4 - wakeup_code, %eax
- movl %eax, %cr4
- movw $0xb800, %ax
- movw %ax,%fs
- movw $0x0e00 + 'i', %fs:(0x12)
-
- # need a gdt -- use lgdtl to force 32-bit operands, in case
- # the GDT is located past 16 megabytes.
- lgdtl real_save_gdt - wakeup_code
- movl real_save_cr0 - wakeup_code, %eax
- movl %eax, %cr0
- jmp 1f
- 1:
- movw $0x0e00 + 'n', %fs:(0x14)
- movl real_magic - wakeup_code, %eax
- cmpl $0x12345678, %eax
- jne bogus_real_magic
- ljmpl $__KERNEL_CS,$wakeup_pmode_return
- real_save_gdt: .word 0
- .long 0
- real_save_cr0: .long 0
- real_save_cr3: .long 0
- real_save_cr4: .long 0
- real_magic: .long 0
- video_mode: .long 0
- video_flags: .long 0
- real_efer_save_restore: .long 0
- real_save_efer_edx: .long 0
- real_save_efer_eax: .long 0
- bogus_real_magic:
- movw $0x0e00 + 'B', %fs:(0x12)
- jmp bogus_real_magic
- /* This code uses an extended set of video mode numbers. These include:
- * Aliases for standard modes
- * NORMAL_VGA (-1)
- * EXTENDED_VGA (-2)
- * ASK_VGA (-3)
- * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
- * of compatibility when extending the table. These are between 0x00 and 0xff.
- */
- #define VIDEO_FIRST_MENU 0x0000
- /* Standard BIOS video modes (BIOS number + 0x0100) */
- #define VIDEO_FIRST_BIOS 0x0100
- /* VESA BIOS video modes (VESA number + 0x0200) */
- #define VIDEO_FIRST_VESA 0x0200
- /* Video7 special modes (BIOS number + 0x0900) */
- #define VIDEO_FIRST_V7 0x0900
- # Setting of user mode (AX=mode ID) => CF=success
- mode_set:
- movw %ax, %bx
- #if 0
- cmpb $0xff, %ah
- jz setalias
- testb $VIDEO_RECALC>>8, %ah
- jnz _setrec
- cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
- jnc setres
-
- cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
- jz setspc
- cmpb $VIDEO_FIRST_V7>>8, %ah
- jz setv7
- #endif
-
- cmpb $VIDEO_FIRST_VESA>>8, %ah
- jnc check_vesa
- #if 0
- orb %ah, %ah
- jz setmenu
- #endif
-
- decb %ah
- # jz setbios Add bios modes later
- setbad: clc
- ret
- check_vesa:
- subb $VIDEO_FIRST_VESA>>8, %bh
- orw $0x4000, %bx # Use linear frame buffer
- movw $0x4f02, %ax # VESA BIOS mode set call
- int $0x10
- cmpw $0x004f, %ax # AL=4f if implemented
- jnz _setbad # AH=0 if OK
- stc
- ret
- _setbad: jmp setbad
- .code32
- ALIGN
- .org 0x800
- wakeup_stack_begin: # Stack grows down
- .org 0xff0 # Just below end of page
- wakeup_stack:
- ENTRY(wakeup_end)
-
- .org 0x1000
- wakeup_pmode_return:
- movw $__KERNEL_DS, %ax
- movw %ax, %ss
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
- movw $0x0e00 + 'u', 0xb8016
- # reload the gdt, as we need the full 32 bit address
- lgdt saved_gdt
- lidt saved_idt
- lldt saved_ldt
- ljmp $(__KERNEL_CS),$1f
- 1:
- movl %cr3, %eax
- movl %eax, %cr3
- wbinvd
- # and restore the stack ... but you need gdt for this to work
- movl saved_context_esp, %esp
- movl %cs:saved_magic, %eax
- cmpl $0x12345678, %eax
- jne bogus_magic
- # jump to place where we left off
- movl saved_eip,%eax
- jmp *%eax
- bogus_magic:
- movw $0x0e00 + 'B', 0xb8018
- jmp bogus_magic
- ##
- # acpi_copy_wakeup_routine
- #
- # Copy the above routine to low memory.
- #
- # Parameters:
- # %eax: place to copy wakeup routine to
- #
- # Returned address is location of code in low memory (past data and stack)
- #
- ENTRY(acpi_copy_wakeup_routine)
- sgdt saved_gdt
- sidt saved_idt
- sldt saved_ldt
- str saved_tss
- movl nx_enabled, %edx
- movl %edx, real_efer_save_restore - wakeup_start (%eax)
- testl $1, real_efer_save_restore - wakeup_start (%eax)
- jz 2f
- # save efer setting
- pushl %eax
- movl %eax, %ebx
- mov $0xc0000080, %ecx
- rdmsr
- movl %edx, real_save_efer_edx - wakeup_start (%ebx)
- movl %eax, real_save_efer_eax - wakeup_start (%ebx)
- popl %eax
- 2:
- movl %cr3, %edx
- movl %edx, real_save_cr3 - wakeup_start (%eax)
- movl %cr4, %edx
- movl %edx, real_save_cr4 - wakeup_start (%eax)
- movl %cr0, %edx
- movl %edx, real_save_cr0 - wakeup_start (%eax)
- sgdt real_save_gdt - wakeup_start (%eax)
- movl saved_videomode, %edx
- movl %edx, video_mode - wakeup_start (%eax)
- movl acpi_video_flags, %edx
- movl %edx, video_flags - wakeup_start (%eax)
- movl $0x12345678, real_magic - wakeup_start (%eax)
- movl $0x12345678, saved_magic
- ret
- .data
- ALIGN
- ENTRY(saved_magic) .long 0
- ENTRY(saved_eip) .long 0
- save_registers:
- leal 4(%esp), %eax
- movl %eax, saved_context_esp
- movl %ebx, saved_context_ebx
- movl %ebp, saved_context_ebp
- movl %esi, saved_context_esi
- movl %edi, saved_context_edi
- pushfl ; popl saved_context_eflags
- movl $ret_point, saved_eip
- ret
- restore_registers:
- movl saved_context_ebp, %ebp
- movl saved_context_ebx, %ebx
- movl saved_context_esi, %esi
- movl saved_context_edi, %edi
- pushl saved_context_eflags ; popfl
- ret
- ENTRY(do_suspend_lowlevel)
- call save_processor_state
- call save_registers
- pushl $3
- call acpi_enter_sleep_state
- addl $4, %esp
- ret
- .p2align 4,,7
- ret_point:
- call restore_registers
- call restore_processor_state
- ret
- ENTRY(do_suspend_lowlevel_s4bios)
- call save_processor_state
- call save_registers
- call acpi_enter_sleep_state_s4bios
- ret
- ALIGN
- # saved registers
- saved_gdt: .long 0,0
- saved_idt: .long 0,0
- saved_ldt: .long 0
- saved_tss: .long 0
|