1/* 2 * ACPI wakeup real mode startup stub 3 */ 4#include <asm/segment.h> 5#include <asm/msr-index.h> 6#include <asm/page_types.h> 7#include <asm/pgtable_types.h> 8#include <asm/processor-flags.h> 9#include "wakeup.h" 10 11 .code16 12 .section ".jump", "ax" 13 .globl _start 14_start: 15 cli 16 jmp wakeup_code 17 18/* This should match the structure in wakeup.h */ 19 .section ".header", "a" 20 .globl wakeup_header 21wakeup_header: 22video_mode: .short 0 /* Video mode number */ 23pmode_return: .byte 0x66, 0xea /* ljmpl */ 24 .long 0 /* offset goes here */ 25 .short __KERNEL_CS 26pmode_cr0: .long 0 /* Saved %cr0 */ 27pmode_cr3: .long 0 /* Saved %cr3 */ 28pmode_cr4: .long 0 /* Saved %cr4 */ 29pmode_efer: .quad 0 /* Saved EFER */ 30pmode_gdt: .quad 0 31pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ 32pmode_behavior: .long 0 /* Wakeup behavior flags */ 33realmode_flags: .long 0 34real_magic: .long 0 35trampoline_segment: .word 0 36_pad1: .byte 0 37wakeup_jmp: .byte 0xea /* ljmpw */ 38wakeup_jmp_off: .word 3f 39wakeup_jmp_seg: .word 0 40wakeup_gdt: .quad 0, 0, 0 41signature: .long WAKEUP_HEADER_SIGNATURE 42 43 .text 44 .code16 45wakeup_code: 46 cld 47 48 /* Apparently some dimwit BIOS programmers don't know how to 49 program a PM to RM transition, and we might end up here with 50 junk in the data segment descriptor registers. The only way 51 to repair that is to go into PM and fix it ourselves... */ 52 movw $16, %cx 53 lgdtl %cs:wakeup_gdt 54 movl %cr0, %eax 55 orb $X86_CR0_PE, %al 56 movl %eax, %cr0 57 jmp 1f 581: ljmpw $8, $2f 592: 60 movw %cx, %ds 61 movw %cx, %es 62 movw %cx, %ss 63 movw %cx, %fs 64 movw %cx, %gs 65 66 andb $~X86_CR0_PE, %al 67 movl %eax, %cr0 68 jmp wakeup_jmp 693: 70 /* Set up segments */ 71 movw %cs, %ax 72 movw %ax, %ds 73 movw %ax, %es 74 movw %ax, %ss 75 lidtl wakeup_idt 76 77 movl $wakeup_stack_end, %esp 78 79 /* Clear the EFLAGS */ 80 pushl $0 81 popfl 82 83 /* Check header signature... */ 84 movl signature, %eax 85 cmpl $WAKEUP_HEADER_SIGNATURE, %eax 86 jne bogus_real_magic 87 88 /* Check we really have everything... */ 89 movl end_signature, %eax 90 cmpl $WAKEUP_END_SIGNATURE, %eax 91 jne bogus_real_magic 92 93 /* Call the C code */ 94 calll main 95 96 /* Restore MISC_ENABLE before entering protected mode, in case 97 BIOS decided to clear XD_DISABLE during S3. */ 98 movl pmode_behavior, %eax 99 btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax 100 jnc 1f 101 102 movl pmode_misc_en, %eax 103 movl pmode_misc_en + 4, %edx 104 movl $MSR_IA32_MISC_ENABLE, %ecx 105 wrmsr 1061: 107 108 /* Do any other stuff... */ 109 110#ifndef CONFIG_64BIT 111 /* This could also be done in C code... */ 112 movl pmode_cr3, %eax 113 movl %eax, %cr3 114 115 movl pmode_cr4, %ecx 116 jecxz 1f 117 movl %ecx, %cr4 1181: 119 movl pmode_efer, %eax 120 movl pmode_efer + 4, %edx 121 movl %eax, %ecx 122 orl %edx, %ecx 123 jz 1f 124 movl $MSR_EFER, %ecx 125 wrmsr 1261: 127 128 lgdtl pmode_gdt 129 130 /* This really couldn't... */ 131 movl pmode_cr0, %eax 132 movl %eax, %cr0 133 jmp pmode_return 134#else 135 pushw $0 136 pushw trampoline_segment 137 pushw $0 138 lret 139#endif 140 141bogus_real_magic: 1421: 143 hlt 144 jmp 1b 145 146 .data 147 .balign 8 148 149 /* This is the standard real-mode IDT */ 150wakeup_idt: 151 .word 0xffff /* limit */ 152 .long 0 /* address */ 153 .word 0 154 155 .globl HEAP, heap_end 156HEAP: 157 .long wakeup_heap 158heap_end: 159 .long wakeup_stack 160 161 .bss 162wakeup_heap: 163 .space 2048 164wakeup_stack: 165 .space 2048 166wakeup_stack_end: 167 168 .section ".signature","a" 169end_signature: 170 .long WAKEUP_END_SIGNATURE 171