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 10 .code16 11 .section ".header", "a" 12 13/* This should match the structure in wakeup.h */ 14 .globl wakeup_header 15wakeup_header: 16video_mode: .short 0 /* Video mode number */ 17pmode_return: .byte 0x66, 0xea /* ljmpl */ 18 .long 0 /* offset goes here */ 19 .short __KERNEL_CS 20pmode_cr0: .long 0 /* Saved %cr0 */ 21pmode_cr3: .long 0 /* Saved %cr3 */ 22pmode_cr4: .long 0 /* Saved %cr4 */ 23pmode_efer: .quad 0 /* Saved EFER */ 24pmode_gdt: .quad 0 25realmode_flags: .long 0 26real_magic: .long 0 27trampoline_segment: .word 0 28_pad1: .byte 0 29wakeup_jmp: .byte 0xea /* ljmpw */ 30wakeup_jmp_off: .word 3f 31wakeup_jmp_seg: .word 0 32wakeup_gdt: .quad 0, 0, 0 33signature: .long 0x51ee1111 34 35 .text 36 .globl _start 37 .code16 38wakeup_code: 39_start: 40 cli 41 cld 42 43 /* Apparently some dimwit BIOS programmers don't know how to 44 program a PM to RM transition, and we might end up here with 45 junk in the data segment descriptor registers. The only way 46 to repair that is to go into PM and fix it ourselves... */ 47 movw $16, %cx 48 lgdtl %cs:wakeup_gdt 49 movl %cr0, %eax 50 orb $X86_CR0_PE, %al 51 movl %eax, %cr0 52 jmp 1f 531: ljmpw $8, $2f 542: 55 movw %cx, %ds 56 movw %cx, %es 57 movw %cx, %ss 58 movw %cx, %fs 59 movw %cx, %gs 60 61 andb $~X86_CR0_PE, %al 62 movl %eax, %cr0 63 jmp wakeup_jmp 643: 65 /* Set up segments */ 66 movw %cs, %ax 67 movw %ax, %ds 68 movw %ax, %es 69 movw %ax, %ss 70 lidtl wakeup_idt 71 72 movl $wakeup_stack_end, %esp 73 74 /* Clear the EFLAGS */ 75 pushl $0 76 popfl 77 78 /* Check header signature... */ 79 movl signature, %eax 80 cmpl $0x51ee1111, %eax 81 jne bogus_real_magic 82 83 /* Check we really have everything... */ 84 movl end_signature, %eax 85 cmpl $0x65a22c82, %eax 86 jne bogus_real_magic 87 88 /* Call the C code */ 89 calll main 90 91 /* Do any other stuff... */ 92 93#ifndef CONFIG_64BIT 94 /* This could also be done in C code... */ 95 movl pmode_cr3, %eax 96 movl %eax, %cr3 97 98 movl pmode_cr4, %ecx 99 jecxz 1f 100 movl %ecx, %cr4 1011: 102 movl pmode_efer, %eax 103 movl pmode_efer + 4, %edx 104 movl %eax, %ecx 105 orl %edx, %ecx 106 jz 1f 107 movl $MSR_EFER, %ecx 108 wrmsr 1091: 110 111 lgdtl pmode_gdt 112 113 /* This really couldn't... */ 114 movl pmode_cr0, %eax 115 movl %eax, %cr0 116 jmp pmode_return 117#else 118 pushw $0 119 pushw trampoline_segment 120 pushw $0 121 lret 122#endif 123 124bogus_real_magic: 1251: 126 hlt 127 jmp 1b 128 129 .data 130 .balign 8 131 132 /* This is the standard real-mode IDT */ 133wakeup_idt: 134 .word 0xffff /* limit */ 135 .long 0 /* address */ 136 .word 0 137 138 .globl HEAP, heap_end 139HEAP: 140 .long wakeup_heap 141heap_end: 142 .long wakeup_stack 143 144 .bss 145wakeup_heap: 146 .space 2048 147wakeup_stack: 148 .space 2048 149wakeup_stack_end: 150