ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / x86_64 / kernel / warmreboot.S
1 /*
2  * Switch back to real mode and call the BIOS reboot vector.
3  * This is a trampoline copied around in process.c 
4  * Written 2003 by Andi Kleen, SuSE Labs.               
5  */                     
6         
7 #include <asm/msr.h>
8
9 #define R(x) x-warm_reboot(%ebx)
10 #define R64(x) x-warm_reboot(%rbx)
11                 
12         /* running in identity mapping and in the first 64k of memory
13            and in compatibility mode. This must be position independent */
14
15         /* Follows 14.7 "Leaving Long Mode" in the AMD x86-64 manual, volume 2
16            and 8.9.2 "Switching Back to Real-Address Mode" in the Intel IA32
17            manual, volume 2 */
18
19         /* ebx: self pointer to warm_reboot */
20
21         .globl warm_reboot
22 warm_reboot:
23         addl  %ebx,  R64(real_mode_desc)        /* relocate tables */
24         addl  %ebx,2+R64(warm_gdt_desc)         
25
26         movq  %cr0,%rax
27         btr  $31,%rax           
28         movq %rax,%cr0          /* disable paging */
29         jmp  1f                 /* flush prefetch queue */
30         
31         .code32 
32 1:      movl $MSR_EFER,%ecx
33         rdmsr
34         andl $~((1<<_EFER_LME)|(1<<_EFER_SCE)|(1<<_EFER_NX)),%eax
35         wrmsr                   /* disable long mode in EFER */
36                 
37         xorl %eax,%eax
38         movl %eax,%cr3          /* flush tlb */
39
40         /* Running protected mode without paging now */
41         
42         wbinvd                  /* flush caches. Needed? */
43
44         lidt R(warm_idt_desc)
45         lgdt R(warm_gdt_desc)
46         
47         movl $0x10,%ecx         /* load segment registers with real mode settings */
48         movl %ecx,%ds
49         movl %ecx,%es
50         movl %ecx,%fs
51         movl %ecx,%gs
52         movl %ecx,%ss
53         
54         lea  R(real_mode_desc),%eax             
55         ljmp *(%eax)
56
57         .code16:
58 real_mode:
59         xorl %eax,%eax
60         movl %eax,%cr0
61         
62         /* some people claim $0xf000,0xfff0 is better. Use what 32bit linux uses. */
63         /* code as bytes because gas has problems with it */
64         .byte   0xea,0xf0,0xff,0x00,0xf0        /* ljmp  0xf000:0xfff0 */
65
66 real_mode_desc:
67         .long  real_mode - warm_reboot
68         .short 8        
69 warm_gdt_desc:
70         .short 8*3
71         .long warm_gdt - warm_reboot
72 warm_gdt:       
73         .quad   0
74         .quad   0x00009a000000ffff      /* 16-bit real-mode 64k code at 0x00000000 */
75         .quad   0x000092000100ffff      /* 16-bit real-mode 64k data at 0x00000100 */
76         
77 warm_idt_desc:
78         .short 0x3ff
79         .long  0
80                                 
81         .globl warm_reboot_end
82 warm_reboot_end:
83