Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/realmode/rm/wakeup_asm.S
26490 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
/*
3
* ACPI wakeup real mode startup stub
4
*/
5
#include <linux/linkage.h>
6
#include <asm/segment.h>
7
#include <asm/msr-index.h>
8
#include <asm/page_types.h>
9
#include <asm/pgtable_types.h>
10
#include <asm/processor-flags.h>
11
#include "realmode.h"
12
#include "wakeup.h"
13
14
.code16
15
16
/* This should match the structure in wakeup.h */
17
.section ".data", "aw"
18
19
.balign 16
20
SYM_DATA_START(wakeup_header)
21
video_mode: .short 0 /* Video mode number */
22
pmode_entry: .long 0
23
pmode_cs: .short __KERNEL_CS
24
pmode_cr0: .long 0 /* Saved %cr0 */
25
pmode_cr3: .long 0 /* Saved %cr3 */
26
pmode_cr4: .long 0 /* Saved %cr4 */
27
pmode_efer: .quad 0 /* Saved EFER */
28
pmode_gdt: .quad 0
29
pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
30
pmode_behavior: .long 0 /* Wakeup behavior flags */
31
realmode_flags: .long 0
32
real_magic: .long 0
33
signature: .long WAKEUP_HEADER_SIGNATURE
34
SYM_DATA_END(wakeup_header)
35
36
.text
37
.code16
38
39
.balign 16
40
SYM_CODE_START(wakeup_start)
41
cli
42
cld
43
44
LJMPW_RM(3f)
45
3:
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
ljmpw $8, $2f
56
2:
57
movw %cx, %ds
58
movw %cx, %es
59
movw %cx, %ss
60
movw %cx, %fs
61
movw %cx, %gs
62
63
andb $~X86_CR0_PE, %al
64
movl %eax, %cr0
65
LJMPW_RM(3f)
66
3:
67
/* Set up segments */
68
movw %cs, %ax
69
movw %ax, %ss
70
movl $rm_stack_end, %esp
71
movw %ax, %ds
72
movw %ax, %es
73
movw %ax, %fs
74
movw %ax, %gs
75
76
lidtl .Lwakeup_idt
77
78
/* Clear the EFLAGS */
79
pushl $0
80
popfl
81
82
/* Check header signature... */
83
movl signature, %eax
84
cmpl $WAKEUP_HEADER_SIGNATURE, %eax
85
jne bogus_real_magic
86
87
/* Check we really have everything... */
88
movl end_signature, %eax
89
cmpl $REALMODE_END_SIGNATURE, %eax
90
jne bogus_real_magic
91
92
/* Call the C code */
93
calll main
94
95
/* Restore MISC_ENABLE before entering protected mode, in case
96
BIOS decided to clear XD_DISABLE during S3. */
97
movl pmode_behavior, %edi
98
btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
99
jnc 1f
100
101
movl pmode_misc_en, %eax
102
movl pmode_misc_en + 4, %edx
103
movl $MSR_IA32_MISC_ENABLE, %ecx
104
wrmsr
105
1:
106
107
/* Do any other stuff... */
108
109
#ifndef CONFIG_64BIT
110
/* This could also be done in C code... */
111
movl pmode_cr3, %eax
112
movl %eax, %cr3
113
114
btl $WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
115
jnc 1f
116
movl pmode_cr4, %eax
117
movl %eax, %cr4
118
1:
119
btl $WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
120
jnc 1f
121
movl pmode_efer, %eax
122
movl pmode_efer + 4, %edx
123
movl $MSR_EFER, %ecx
124
wrmsr
125
1:
126
127
lgdtl pmode_gdt
128
129
/* This really couldn't... */
130
movl pmode_entry, %eax
131
movl pmode_cr0, %ecx
132
movl %ecx, %cr0
133
ljmpl $__KERNEL_CS, $pa_startup_32
134
/* -> jmp *%eax in trampoline_32.S */
135
#else
136
jmp trampoline_start
137
#endif
138
SYM_CODE_END(wakeup_start)
139
140
bogus_real_magic:
141
1:
142
hlt
143
jmp 1b
144
145
.section ".rodata","a"
146
147
/*
148
* Set up the wakeup GDT. We set these up as Big Real Mode,
149
* that is, with limits set to 4 GB. At least the Lenovo
150
* Thinkpad X61 is known to need this for the video BIOS
151
* initialization quirk to work; this is likely to also
152
* be the case for other laptops or integrated video devices.
153
*/
154
155
.balign 16
156
SYM_DATA_START(wakeup_gdt)
157
.word 3*8-1 /* Self-descriptor */
158
.long pa_wakeup_gdt
159
.word 0
160
161
.word 0xffff /* 16-bit code segment @ real_mode_base */
162
.long 0x9b000000 + pa_real_mode_base
163
.word 0x008f /* big real mode */
164
165
.word 0xffff /* 16-bit data segment @ real_mode_base */
166
.long 0x93000000 + pa_real_mode_base
167
.word 0x008f /* big real mode */
168
SYM_DATA_END(wakeup_gdt)
169
170
.section ".rodata","a"
171
.balign 8
172
173
/* This is the standard real-mode IDT */
174
.balign 16
175
SYM_DATA_START_LOCAL(.Lwakeup_idt)
176
.word 0xffff /* limit */
177
.long 0 /* address */
178
.word 0
179
SYM_DATA_END(.Lwakeup_idt)
180
181