Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
[linux-2.6] / arch / x86 / kernel / acpi / realmode / wakeup.S
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
15 wakeup_header:
16 video_mode:     .short  0       /* Video mode number */
17 pmode_return:   .byte   0x66, 0xea      /* ljmpl */
18                 .long   0       /* offset goes here */
19                 .short  __KERNEL_CS
20 pmode_cr0:      .long   0       /* Saved %cr0 */
21 pmode_cr3:      .long   0       /* Saved %cr3 */
22 pmode_cr4:      .long   0       /* Saved %cr4 */
23 pmode_efer:     .quad   0       /* Saved EFER */
24 pmode_gdt:      .quad   0
25 realmode_flags: .long   0
26 real_magic:     .long   0
27 trampoline_segment:     .word 0
28 _pad1:          .byte   0
29 wakeup_jmp:     .byte   0xea    /* ljmpw */
30 wakeup_jmp_off: .word   3f
31 wakeup_jmp_seg: .word   0
32 wakeup_gdt:     .quad   0, 0, 0
33 signature:      .long   0x51ee1111
34
35         .text
36         .globl  _start
37         .code16
38 wakeup_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
53 1:      ljmpw   $8, $2f
54 2:
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
64 3:
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
101 1:
102         movl    pmode_efer, %eax
103         movl    pmode_efer + 4, %edx
104         movl    %eax, %ecx
105         orl     %edx, %ecx
106         jz      1f
107         movl    $0xc0000080, %ecx
108         wrmsr
109 1:
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
124 bogus_real_magic:
125 1:
126         hlt
127         jmp     1b
128
129         .data
130         .balign 8
131
132         /* This is the standard real-mode IDT */
133 wakeup_idt:
134         .word   0xffff          /* limit */
135         .long   0               /* address */
136         .word   0
137
138         .globl  HEAP, heap_end
139 HEAP:
140         .long   wakeup_heap
141 heap_end:
142         .long   wakeup_stack
143
144         .bss
145 wakeup_heap:
146         .space  2048
147 wakeup_stack:
148         .space  2048
149 wakeup_stack_end: