]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/x86/realmode/rm/wakeup_asm.S
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[mirror_ubuntu-bionic-kernel.git] / arch / x86 / realmode / rm / wakeup_asm.S
CommitLineData
b2441318 1/* SPDX-License-Identifier: GPL-2.0 */
e44b7b75
PM
2/*
3 * ACPI wakeup real mode startup stub
4 */
8e029fcd 5#include <linux/linkage.h>
e44b7b75
PM
6#include <asm/segment.h>
7#include <asm/msr-index.h>
0341c14d
JF
8#include <asm/page_types.h>
9#include <asm/pgtable_types.h>
4b4f7280 10#include <asm/processor-flags.h>
c4845474 11#include "realmode.h"
d1ee4335 12#include "wakeup.h"
e44b7b75 13
8e029fcd 14 .code16
e44b7b75
PM
15
16/* This should match the structure in wakeup.h */
8e029fcd
JS
17 .section ".data", "aw"
18
19 .balign 16
20GLOBAL(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
34END(wakeup_header)
e44b7b75
PM
35
36 .text
e44b7b75 37 .code16
8e029fcd
JS
38
39 .balign 16
40ENTRY(wakeup_start)
c9b77ccb 41 cli
e44b7b75
PM
42 cld
43
e5684ec4 44 LJMPW_RM(3f)
c9b77ccb 453:
4b4f7280
PA
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
c9b77ccb 55 ljmpw $8, $2f
4b4f7280
PA
562:
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
e5684ec4 65 LJMPW_RM(3f)
4b4f7280 663:
e44b7b75
PM
67 /* Set up segments */
68 movw %cs, %ax
8e029fcd
JS
69 movw %ax, %ss
70 movl $rm_stack_end, %esp
e44b7b75
PM
71 movw %ax, %ds
72 movw %ax, %es
8e029fcd
JS
73 movw %ax, %fs
74 movw %ax, %gs
e44b7b75 75
8e029fcd 76 lidtl wakeup_idt
e44b7b75 77
1396adc3 78 /* Clear the EFLAGS */
73201dbe
PA
79 pushl $0
80 popfl
e44b7b75
PM
81
82 /* Check header signature... */
83 movl signature, %eax
d1ee4335 84 cmpl $WAKEUP_HEADER_SIGNATURE, %eax
e44b7b75
PM
85 jne bogus_real_magic
86
87 /* Check we really have everything... */
88 movl end_signature, %eax
61f54461 89 cmpl $REALMODE_END_SIGNATURE, %eax
e44b7b75
PM
90 jne bogus_real_magic
91
92 /* Call the C code */
93 calll main
94
7a313666
KC
95 /* Restore MISC_ENABLE before entering protected mode, in case
96 BIOS decided to clear XD_DISABLE during S3. */
73201dbe
PA
97 movl pmode_behavior, %edi
98 btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
7a313666
KC
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
1051:
106
e44b7b75
PM
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
73201dbe 114 btl $WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
1396adc3 115 jnc 1f
73201dbe
PA
116 movl pmode_cr4, %eax
117 movl %eax, %cr4
e44b7b75 1181:
73201dbe 119 btl $WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
1396adc3 120 jnc 1f
e44b7b75
PM
121 movl pmode_efer, %eax
122 movl pmode_efer + 4, %edx
cfaa71ee 123 movl $MSR_EFER, %ecx
e44b7b75
PM
124 wrmsr
1251:
126
127 lgdtl pmode_gdt
128
129 /* This really couldn't... */
968ff9ee
PA
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 */
e44b7b75 135#else
f37240f1 136 jmp trampoline_start
e44b7b75
PM
137#endif
138
139bogus_real_magic:
1401:
141 hlt
142 jmp 1b
143
c9b77ccb
JS
144 .section ".rodata","a"
145
146 /*
147 * Set up the wakeup GDT. We set these up as Big Real Mode,
148 * that is, with limits set to 4 GB. At least the Lenovo
149 * Thinkpad X61 is known to need this for the video BIOS
150 * initialization quirk to work; this is likely to also
151 * be the case for other laptops or integrated video devices.
152 */
153
c9b77ccb 154 .balign 16
8e029fcd 155GLOBAL(wakeup_gdt)
c9b77ccb
JS
156 .word 3*8-1 /* Self-descriptor */
157 .long pa_wakeup_gdt
158 .word 0
159
160 .word 0xffff /* 16-bit code segment @ real_mode_base */
161 .long 0x9b000000 + pa_real_mode_base
162 .word 0x008f /* big real mode */
163
164 .word 0xffff /* 16-bit data segment @ real_mode_base */
165 .long 0x93000000 + pa_real_mode_base
166 .word 0x008f /* big real mode */
8e029fcd 167END(wakeup_gdt)
c9b77ccb 168
8e029fcd 169 .section ".rodata","a"
4b4f7280
PA
170 .balign 8
171
172 /* This is the standard real-mode IDT */
8e029fcd
JS
173 .balign 16
174GLOBAL(wakeup_idt)
4b4f7280
PA
175 .word 0xffff /* limit */
176 .long 0 /* address */
177 .word 0
8e029fcd 178END(wakeup_idt)