📄 wakeup.s
字号:
.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 4096ENTRY(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, %ss1: testl $2, video_flags - wakeup_code jz 1f mov video_mode - wakeup_code, %ax call mode_set1: # 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 wrmsr4: # 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 1f1: movw $0x0e00 + 'n', %fs:(0x14) movl real_magic - wakeup_code, %eax cmpl $0x12345678, %eax jne bogus_real_magic ljmpl $__KERNEL_CS,$wakeup_pmode_returnreal_save_gdt: .word 0 .long 0real_save_cr0: .long 0real_save_cr3: .long 0real_save_cr4: .long 0real_magic: .long 0video_mode: .long 0video_flags: .long 0real_efer_save_restore: .long 0real_save_efer_edx: .long 0real_save_efer_eax: .long 0bogus_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=successmode_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 latersetbad: clc retcheck_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 0x800wakeup_stack_begin: # Stack grows down.org 0xff0 # Just below end of pagewakeup_stack:ENTRY(wakeup_end) .org 0x1000wakeup_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),$1f1: 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 *%eaxbogus_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 %eax2: 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.dataALIGNENTRY(saved_magic) .long 0ENTRY(saved_eip) .long 0save_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 retrestore_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,,7ret_point: call restore_registers call restore_processor_state retALIGN# saved registerssaved_gdt: .long 0,0saved_idt: .long 0,0saved_ldt: .long 0saved_tss: .long 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -