xref: /linux/arch/x86/realmode/rm/wakeup_asm.S (revision c95baf12f5077419db01313ab61c2aac007d40cd)
1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */
2c4845474SJarkko Sakkinen/*
3c4845474SJarkko Sakkinen * ACPI wakeup real mode startup stub
4c4845474SJarkko Sakkinen */
5c4845474SJarkko Sakkinen#include <linux/linkage.h>
6c4845474SJarkko Sakkinen#include <asm/segment.h>
7c4845474SJarkko Sakkinen#include <asm/msr-index.h>
8c4845474SJarkko Sakkinen#include <asm/page_types.h>
9c4845474SJarkko Sakkinen#include <asm/pgtable_types.h>
10c4845474SJarkko Sakkinen#include <asm/processor-flags.h>
11c4845474SJarkko Sakkinen#include "realmode.h"
12c4845474SJarkko Sakkinen#include "wakeup.h"
13c4845474SJarkko Sakkinen
14c4845474SJarkko Sakkinen	.code16
15c4845474SJarkko Sakkinen
16c4845474SJarkko Sakkinen/* This should match the structure in wakeup.h */
17c4845474SJarkko Sakkinen	.section ".data", "aw"
18c4845474SJarkko Sakkinen
19c4845474SJarkko Sakkinen	.balign	16
2078f44330SJiri SlabySYM_DATA_START(wakeup_header)
21c4845474SJarkko Sakkinen	video_mode:	.short	0	/* Video mode number */
22c4845474SJarkko Sakkinen	pmode_entry:	.long	0
23c4845474SJarkko Sakkinen	pmode_cs:	.short	__KERNEL_CS
24c4845474SJarkko Sakkinen	pmode_cr0:	.long	0	/* Saved %cr0 */
25c4845474SJarkko Sakkinen	pmode_cr3:	.long	0	/* Saved %cr3 */
26c4845474SJarkko Sakkinen	pmode_cr4:	.long	0	/* Saved %cr4 */
27c4845474SJarkko Sakkinen	pmode_efer:	.quad	0	/* Saved EFER */
28c4845474SJarkko Sakkinen	pmode_gdt:	.quad	0
29c4845474SJarkko Sakkinen	pmode_misc_en:	.quad	0	/* Saved MISC_ENABLE MSR */
30c4845474SJarkko Sakkinen	pmode_behavior:	.long	0	/* Wakeup behavior flags */
31c4845474SJarkko Sakkinen	realmode_flags:	.long	0
32c4845474SJarkko Sakkinen	real_magic:	.long	0
33c4845474SJarkko Sakkinen	signature:	.long	WAKEUP_HEADER_SIGNATURE
3478f44330SJiri SlabySYM_DATA_END(wakeup_header)
35c4845474SJarkko Sakkinen
36c4845474SJarkko Sakkinen	.text
37c4845474SJarkko Sakkinen	.code16
38c4845474SJarkko Sakkinen
39c4845474SJarkko Sakkinen	.balign	16
40*4aec216bSJiri SlabySYM_CODE_START(wakeup_start)
41c4845474SJarkko Sakkinen	cli
42c4845474SJarkko Sakkinen	cld
43c4845474SJarkko Sakkinen
44c4845474SJarkko Sakkinen	LJMPW_RM(3f)
45c4845474SJarkko Sakkinen3:
46c4845474SJarkko Sakkinen	/* Apparently some dimwit BIOS programmers don't know how to
47c4845474SJarkko Sakkinen	   program a PM to RM transition, and we might end up here with
48c4845474SJarkko Sakkinen	   junk in the data segment descriptor registers.  The only way
49c4845474SJarkko Sakkinen	   to repair that is to go into PM and fix it ourselves... */
50c4845474SJarkko Sakkinen	movw	$16, %cx
51c4845474SJarkko Sakkinen	lgdtl	%cs:wakeup_gdt
52c4845474SJarkko Sakkinen	movl	%cr0, %eax
53c4845474SJarkko Sakkinen	orb	$X86_CR0_PE, %al
54c4845474SJarkko Sakkinen	movl	%eax, %cr0
55c4845474SJarkko Sakkinen	ljmpw	$8, $2f
56c4845474SJarkko Sakkinen2:
57c4845474SJarkko Sakkinen	movw	%cx, %ds
58c4845474SJarkko Sakkinen	movw	%cx, %es
59c4845474SJarkko Sakkinen	movw	%cx, %ss
60c4845474SJarkko Sakkinen	movw	%cx, %fs
61c4845474SJarkko Sakkinen	movw	%cx, %gs
62c4845474SJarkko Sakkinen
63c4845474SJarkko Sakkinen	andb	$~X86_CR0_PE, %al
64c4845474SJarkko Sakkinen	movl	%eax, %cr0
65c4845474SJarkko Sakkinen	LJMPW_RM(3f)
66c4845474SJarkko Sakkinen3:
67c4845474SJarkko Sakkinen	/* Set up segments */
68c4845474SJarkko Sakkinen	movw	%cs, %ax
69c4845474SJarkko Sakkinen	movw	%ax, %ss
70c4845474SJarkko Sakkinen	movl	$rm_stack_end, %esp
71c4845474SJarkko Sakkinen	movw	%ax, %ds
72c4845474SJarkko Sakkinen	movw	%ax, %es
73c4845474SJarkko Sakkinen	movw	%ax, %fs
74c4845474SJarkko Sakkinen	movw	%ax, %gs
75c4845474SJarkko Sakkinen
7630a2441cSJiri Slaby	lidtl	.Lwakeup_idt
77c4845474SJarkko Sakkinen
781396adc3SH. Peter Anvin	/* Clear the EFLAGS */
79c4845474SJarkko Sakkinen	pushl $0
80c4845474SJarkko Sakkinen	popfl
81c4845474SJarkko Sakkinen
82c4845474SJarkko Sakkinen	/* Check header signature... */
83c4845474SJarkko Sakkinen	movl	signature, %eax
84c4845474SJarkko Sakkinen	cmpl	$WAKEUP_HEADER_SIGNATURE, %eax
85c4845474SJarkko Sakkinen	jne	bogus_real_magic
86c4845474SJarkko Sakkinen
87c4845474SJarkko Sakkinen	/* Check we really have everything... */
88c4845474SJarkko Sakkinen	movl	end_signature, %eax
8961f54461SH. Peter Anvin	cmpl	$REALMODE_END_SIGNATURE, %eax
90c4845474SJarkko Sakkinen	jne	bogus_real_magic
91c4845474SJarkko Sakkinen
92c4845474SJarkko Sakkinen	/* Call the C code */
93c4845474SJarkko Sakkinen	calll	main
94c4845474SJarkko Sakkinen
95c4845474SJarkko Sakkinen	/* Restore MISC_ENABLE before entering protected mode, in case
96c4845474SJarkko Sakkinen	   BIOS decided to clear XD_DISABLE during S3. */
9773201dbeSH. Peter Anvin	movl	pmode_behavior, %edi
9873201dbeSH. Peter Anvin	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
99c4845474SJarkko Sakkinen	jnc	1f
100c4845474SJarkko Sakkinen
101c4845474SJarkko Sakkinen	movl	pmode_misc_en, %eax
102c4845474SJarkko Sakkinen	movl	pmode_misc_en + 4, %edx
103c4845474SJarkko Sakkinen	movl	$MSR_IA32_MISC_ENABLE, %ecx
104c4845474SJarkko Sakkinen	wrmsr
105c4845474SJarkko Sakkinen1:
106c4845474SJarkko Sakkinen
107c4845474SJarkko Sakkinen	/* Do any other stuff... */
108c4845474SJarkko Sakkinen
109c4845474SJarkko Sakkinen#ifndef CONFIG_64BIT
110c4845474SJarkko Sakkinen	/* This could also be done in C code... */
111c4845474SJarkko Sakkinen	movl	pmode_cr3, %eax
112c4845474SJarkko Sakkinen	movl	%eax, %cr3
113c4845474SJarkko Sakkinen
11473201dbeSH. Peter Anvin	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
1151396adc3SH. Peter Anvin	jnc	1f
11673201dbeSH. Peter Anvin	movl	pmode_cr4, %eax
11773201dbeSH. Peter Anvin	movl	%eax, %cr4
118c4845474SJarkko Sakkinen1:
11973201dbeSH. Peter Anvin	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
1201396adc3SH. Peter Anvin	jnc	1f
121c4845474SJarkko Sakkinen	movl	pmode_efer, %eax
122c4845474SJarkko Sakkinen	movl	pmode_efer + 4, %edx
123c4845474SJarkko Sakkinen	movl	$MSR_EFER, %ecx
124c4845474SJarkko Sakkinen	wrmsr
125c4845474SJarkko Sakkinen1:
126c4845474SJarkko Sakkinen
127c4845474SJarkko Sakkinen	lgdtl	pmode_gdt
128c4845474SJarkko Sakkinen
129c4845474SJarkko Sakkinen	/* This really couldn't... */
130c4845474SJarkko Sakkinen	movl	pmode_entry, %eax
131c4845474SJarkko Sakkinen	movl	pmode_cr0, %ecx
132c4845474SJarkko Sakkinen	movl	%ecx, %cr0
133c4845474SJarkko Sakkinen	ljmpl	$__KERNEL_CS, $pa_startup_32
134c4845474SJarkko Sakkinen	/* -> jmp *%eax in trampoline_32.S */
135c4845474SJarkko Sakkinen#else
136f37240f1SJarkko Sakkinen	jmp	trampoline_start
137c4845474SJarkko Sakkinen#endif
138*4aec216bSJiri SlabySYM_CODE_END(wakeup_start)
139c4845474SJarkko Sakkinen
140c4845474SJarkko Sakkinenbogus_real_magic:
141c4845474SJarkko Sakkinen1:
142c4845474SJarkko Sakkinen	hlt
143c4845474SJarkko Sakkinen	jmp	1b
144c4845474SJarkko Sakkinen
145c4845474SJarkko Sakkinen	.section ".rodata","a"
146c4845474SJarkko Sakkinen
147c4845474SJarkko Sakkinen	/*
148c4845474SJarkko Sakkinen	 * Set up the wakeup GDT.  We set these up as Big Real Mode,
149c4845474SJarkko Sakkinen	 * that is, with limits set to 4 GB.  At least the Lenovo
150c4845474SJarkko Sakkinen	 * Thinkpad X61 is known to need this for the video BIOS
151c4845474SJarkko Sakkinen	 * initialization quirk to work; this is likely to also
152c4845474SJarkko Sakkinen	 * be the case for other laptops or integrated video devices.
153c4845474SJarkko Sakkinen	 */
154c4845474SJarkko Sakkinen
155c4845474SJarkko Sakkinen	.balign	16
15678f44330SJiri SlabySYM_DATA_START(wakeup_gdt)
157c4845474SJarkko Sakkinen	.word	3*8-1		/* Self-descriptor */
158c4845474SJarkko Sakkinen	.long	pa_wakeup_gdt
159c4845474SJarkko Sakkinen	.word	0
160c4845474SJarkko Sakkinen
161c4845474SJarkko Sakkinen	.word	0xffff		/* 16-bit code segment @ real_mode_base */
162c4845474SJarkko Sakkinen	.long	0x9b000000 + pa_real_mode_base
163c4845474SJarkko Sakkinen	.word	0x008f		/* big real mode */
164c4845474SJarkko Sakkinen
165c4845474SJarkko Sakkinen	.word	0xffff		/* 16-bit data segment @ real_mode_base */
166c4845474SJarkko Sakkinen	.long	0x93000000 + pa_real_mode_base
167c4845474SJarkko Sakkinen	.word	0x008f		/* big real mode */
16878f44330SJiri SlabySYM_DATA_END(wakeup_gdt)
169c4845474SJarkko Sakkinen
170c4845474SJarkko Sakkinen	.section ".rodata","a"
171c4845474SJarkko Sakkinen	.balign	8
172c4845474SJarkko Sakkinen
173c4845474SJarkko Sakkinen	/* This is the standard real-mode IDT */
174c4845474SJarkko Sakkinen	.balign	16
175b8c3f9b5SJiri SlabySYM_DATA_START_LOCAL(.Lwakeup_idt)
176c4845474SJarkko Sakkinen	.word	0xffff		/* limit */
177c4845474SJarkko Sakkinen	.long	0		/* address */
178c4845474SJarkko Sakkinen	.word	0
179b8c3f9b5SJiri SlabySYM_DATA_END(.Lwakeup_idt)
180