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
31realmode_flags:	.long	0
32real_magic:	.long	0
33trampoline_segment:	.word 0
34_pad1:		.byte	0
35wakeup_jmp:	.byte	0xea	/* ljmpw */
36wakeup_jmp_off:	.word	3f
37wakeup_jmp_seg:	.word	0
38wakeup_gdt:	.quad	0, 0, 0
39signature:	.long	WAKEUP_HEADER_SIGNATURE
40
41	.text
42	.code16
43wakeup_code:
44	cld
45
46	/* Apparently some dimwit BIOS programmers don't know how to
47	   program a PM to RM transition, and we might end up here with
48	   junk in the data segment descriptor registers.  The only way
49	   to repair that is to go into PM and fix it ourselves... */
50	movw	$16, %cx
51	lgdtl	%cs:wakeup_gdt
52	movl	%cr0, %eax
53	orb	$X86_CR0_PE, %al
54	movl	%eax, %cr0
55	jmp	1f
561:	ljmpw	$8, $2f
572:
58	movw	%cx, %ds
59	movw	%cx, %es
60	movw	%cx, %ss
61	movw	%cx, %fs
62	movw	%cx, %gs
63
64	andb	$~X86_CR0_PE, %al
65	movl	%eax, %cr0
66	jmp	wakeup_jmp
673:
68	/* Set up segments */
69	movw	%cs, %ax
70	movw	%ax, %ds
71	movw	%ax, %es
72	movw	%ax, %ss
73	lidtl	wakeup_idt
74
75	movl	$wakeup_stack_end, %esp
76
77	/* Clear the EFLAGS */
78	pushl	$0
79	popfl
80
81	/* Check header signature... */
82	movl	signature, %eax
83	cmpl	$WAKEUP_HEADER_SIGNATURE, %eax
84	jne	bogus_real_magic
85
86	/* Check we really have everything... */
87	movl	end_signature, %eax
88	cmpl	$WAKEUP_END_SIGNATURE, %eax
89	jne	bogus_real_magic
90
91	/* Call the C code */
92	calll	main
93
94	/* Do any other stuff... */
95
96#ifndef CONFIG_64BIT
97	/* This could also be done in C code... */
98	movl	pmode_cr3, %eax
99	movl	%eax, %cr3
100
101	movl	pmode_cr4, %ecx
102	jecxz	1f
103	movl	%ecx, %cr4
1041:
105	movl	pmode_efer, %eax
106	movl	pmode_efer + 4, %edx
107	movl	%eax, %ecx
108	orl	%edx, %ecx
109	jz	1f
110	movl	$MSR_EFER, %ecx
111	wrmsr
1121:
113
114	lgdtl	pmode_gdt
115
116	/* This really couldn't... */
117	movl	pmode_cr0, %eax
118	movl	%eax, %cr0
119	jmp	pmode_return
120#else
121	pushw	$0
122	pushw	trampoline_segment
123	pushw	$0
124	lret
125#endif
126
127bogus_real_magic:
1281:
129	hlt
130	jmp	1b
131
132	.data
133	.balign	8
134
135	/* This is the standard real-mode IDT */
136wakeup_idt:
137	.word	0xffff		/* limit */
138	.long	0		/* address */
139	.word	0
140
141	.globl	HEAP, heap_end
142HEAP:
143	.long	wakeup_heap
144heap_end:
145	.long	wakeup_stack
146
147	.bss
148wakeup_heap:
149	.space	2048
150wakeup_stack:
151	.space	2048
152wakeup_stack_end:
153
154	.section ".signature","a"
155end_signature:
156	.long	WAKEUP_END_SIGNATURE
157