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
22warm_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
321:	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:
58real_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
66real_mode_desc:
67	.long  real_mode - warm_reboot
68	.short 8
69warm_gdt_desc:
70	.short 8*3
71	.long warm_gdt - warm_reboot
72warm_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
77warm_idt_desc:
78	.short 0x3ff
79	.long  0
80
81	.globl warm_reboot_end
82warm_reboot_end:
83
84