1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
/*
* mrst_s0i3_asm.S - super-deep sleep state for the Moorestown MID platform
*
* Copyright (c) 2010, Intel Corporation.
* H. Peter Anvin <hpa@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/linkage.h>
#include <asm/asm.h>
#include <asm/msr-index.h>
#include <asm/page.h>
#include <asm/segment.h>
#include "mrst_s0i3.h"
/* Physical address */
#define pa(X) ((X) - __PAGE_OFFSET)
.code32 /* MRST boots up in flat 32-bit mode */
.text
ENTRY(mrst_s0i3_entry)
pushl %edi
pushl %esi
pushl %ebp
pushl %ebx
movl %esp, %esi
sldt %eax
pushl %eax
subl $8, %esp
sidtl 2(%esp)
pushl %gs
pushl %fs
movl %cr3, %eax
pushl %eax
subl $8, %esp
sgdtl 2(%esp)
movl %cr0, %eax
pushl %eax
movl %cr4, %eax
pushl %eax
movl $(MSR_EFER), %ecx
rdmsr
pushl %edx
pushl %eax
movl $(MSR_IA32_MISC_ENABLE), %ecx
rdmsr
pushl %edx
pushl %eax
movl 28(%esp), %eax /* GDT base */
subl $(__PAGE_OFFSET), %eax /* Convert to a physical address */
pushl %eax
pushl 28(%esp) /* GDT length, pad */
pushfl
leal (-__PAGE_OFFSET)(%esp), %eax
movl %eax, mrst_s0i3_resume_stack
wbinvd
movl %esp, %eax /* As good as anything... */
xorl %edx, %edx
xorl %ecx, %ecx
monitor
movl $MRST_C6_HINTS_EAX, %eax
movl $MRST_C6_HINTS_ECX, %ecx
sti
mwait
/* If MWAIT wakes us up, assume something happened... */
cli
/* jmp simulate_resume */
movl %esi, %esp
xorl %eax, %eax /* Not really S0i3 */
popl %ebx
popl %ebp
popl %esi
popl %edi
ret
ENDPROC(mrst_s0i3_entry)
/*
* Hack for testing: simulate a wakeup
*/
simulate_resume:
movl $pa(initial_page_table), %eax
movl %eax, %cr3
ljmpl $(__KERNEL_CS), $pa(1f)
1:
movl %cr0, %eax
andl $~0x80000000, %eax
movl %eax, %cr0 /* Disable paging */
xorl %eax, %eax
movl %eax, %cr3
movl %eax, %cr4
xorl %edx, %edx
movl $(MSR_EFER), %ecx
wrmsr
lldt %ax
movl %eax, %esp
/* Fall through */
/*
* After S0i3 the MRST firmare will put us back in 32-bit flat mode
*/
ENTRY(mrst_s0i3_resume)
cli
movl pa(mrst_s0i3_resume_stack), %esp
popfl
lgdtl 2(%esp) /* Physical GDT pointer */
addl $8, %esp
movl $(__KERNEL_DS), %eax
movl %eax, %ss
movl %eax, %ds
movl %eax, %es
popl %eax
popl %edx
movl $(MSR_IA32_MISC_ENABLE), %ecx
wrmsr
popl %eax
popl %edx
movl $(MSR_EFER), %ecx
wrmsr
popl %eax
movl %eax, %cr4
movl $pa(initial_page_table), %eax
movl %eax, %cr3
popl %eax
movl %eax, %cr0 /* Enables paging! */
ljmpl $(__KERNEL_CS), $1f
1:
addl $__PAGE_OFFSET, %esp
lgdtl 2(%esp) /* Linear GDT pointer */
popl %eax /* GDT length + junk */
popl %ebx /* Linear address of GDT */
popl %eax
movl %eax, %cr3
movl $(GDT_ENTRY_TSS*8), %eax
/* Clear the TSS busy bit: %ebx == GDT.base */
andb $~0x02, (GDT_ENTRY_TSS*8+5)(%ebx)
ltr %ax /* Set the TSS */
popl %fs
popl %gs
/* x86-64 would need to restore MSR_GS_BASE too */
lidtl 2(%esp)
addl $8, %esp
popl %eax
lldt %ax
movl $1, %eax /* Resume from actual S0i3 */
popl %ebx
popl %ebp
popl %esi
popl %edi
ret
ENDPROC(mrst_s0i3_resume)
.bss
.balign 4
mrst_s0i3_resume_stack:
.space 4
END(mrst_s0i3_resume_stack)
|