Linux Audio

Check our new training course

Loading...
v5.14.15
  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
 20SYM_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
 34SYM_DATA_END(wakeup_header)
 35
 36	.text
 37	.code16
 38
 39	.balign	16
 40SYM_CODE_START(wakeup_start)
 41	cli
 42	cld
 43
 44	LJMPW_RM(3f)
 453:
 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
 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
 65	LJMPW_RM(3f)
 663:
 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
1051:
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
1181:
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
1251:
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
138SYM_CODE_END(wakeup_start)
139
140bogus_real_magic:
1411:
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
156SYM_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 */
168SYM_DATA_END(wakeup_gdt)
169
170	.section ".rodata","a"
171	.balign	8
172
173	/* This is the standard real-mode IDT */
174	.balign	16
175SYM_DATA_START_LOCAL(.Lwakeup_idt)
176	.word	0xffff		/* limit */
177	.long	0		/* address */
178	.word	0
179SYM_DATA_END(.Lwakeup_idt)
v3.15
 
  1/*
  2 * ACPI wakeup real mode startup stub
  3 */
  4#include <linux/linkage.h>
  5#include <asm/segment.h>
  6#include <asm/msr-index.h>
  7#include <asm/page_types.h>
  8#include <asm/pgtable_types.h>
  9#include <asm/processor-flags.h>
 10#include "realmode.h"
 11#include "wakeup.h"
 12
 13	.code16
 14
 15/* This should match the structure in wakeup.h */
 16	.section ".data", "aw"
 17
 18	.balign	16
 19GLOBAL(wakeup_header)
 20	video_mode:	.short	0	/* Video mode number */
 21	pmode_entry:	.long	0
 22	pmode_cs:	.short	__KERNEL_CS
 23	pmode_cr0:	.long	0	/* Saved %cr0 */
 24	pmode_cr3:	.long	0	/* Saved %cr3 */
 25	pmode_cr4:	.long	0	/* Saved %cr4 */
 26	pmode_efer:	.quad	0	/* Saved EFER */
 27	pmode_gdt:	.quad	0
 28	pmode_misc_en:	.quad	0	/* Saved MISC_ENABLE MSR */
 29	pmode_behavior:	.long	0	/* Wakeup behavior flags */
 30	realmode_flags:	.long	0
 31	real_magic:	.long	0
 32	signature:	.long	WAKEUP_HEADER_SIGNATURE
 33END(wakeup_header)
 34
 35	.text
 36	.code16
 37
 38	.balign	16
 39ENTRY(wakeup_start)
 40	cli
 41	cld
 42
 43	LJMPW_RM(3f)
 443:
 45	/* Apparently some dimwit BIOS programmers don't know how to
 46	   program a PM to RM transition, and we might end up here with
 47	   junk in the data segment descriptor registers.  The only way
 48	   to repair that is to go into PM and fix it ourselves... */
 49	movw	$16, %cx
 50	lgdtl	%cs:wakeup_gdt
 51	movl	%cr0, %eax
 52	orb	$X86_CR0_PE, %al
 53	movl	%eax, %cr0
 54	ljmpw	$8, $2f
 552:
 56	movw	%cx, %ds
 57	movw	%cx, %es
 58	movw	%cx, %ss
 59	movw	%cx, %fs
 60	movw	%cx, %gs
 61
 62	andb	$~X86_CR0_PE, %al
 63	movl	%eax, %cr0
 64	LJMPW_RM(3f)
 653:
 66	/* Set up segments */
 67	movw	%cs, %ax
 68	movw	%ax, %ss
 69	movl	$rm_stack_end, %esp
 70	movw	%ax, %ds
 71	movw	%ax, %es
 72	movw	%ax, %fs
 73	movw	%ax, %gs
 74
 75	lidtl	wakeup_idt
 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	$REALMODE_END_SIGNATURE, %eax
 89	jne	bogus_real_magic
 90
 91	/* Call the C code */
 92	calll	main
 93
 94	/* Restore MISC_ENABLE before entering protected mode, in case
 95	   BIOS decided to clear XD_DISABLE during S3. */
 96	movl	pmode_behavior, %edi
 97	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
 98	jnc	1f
 99
100	movl	pmode_misc_en, %eax
101	movl	pmode_misc_en + 4, %edx
102	movl	$MSR_IA32_MISC_ENABLE, %ecx
103	wrmsr
1041:
105
106	/* Do any other stuff... */
107
108#ifndef CONFIG_64BIT
109	/* This could also be done in C code... */
110	movl	pmode_cr3, %eax
111	movl	%eax, %cr3
112
113	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
114	jnc	1f
115	movl	pmode_cr4, %eax
116	movl	%eax, %cr4
1171:
118	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
119	jnc	1f
120	movl	pmode_efer, %eax
121	movl	pmode_efer + 4, %edx
122	movl	$MSR_EFER, %ecx
123	wrmsr
1241:
125
126	lgdtl	pmode_gdt
127
128	/* This really couldn't... */
129	movl	pmode_entry, %eax
130	movl	pmode_cr0, %ecx
131	movl	%ecx, %cr0
132	ljmpl	$__KERNEL_CS, $pa_startup_32
133	/* -> jmp *%eax in trampoline_32.S */
134#else
135	jmp	trampoline_start
136#endif
 
137
138bogus_real_magic:
1391:
140	hlt
141	jmp	1b
142
143	.section ".rodata","a"
144
145	/*
146	 * Set up the wakeup GDT.  We set these up as Big Real Mode,
147	 * that is, with limits set to 4 GB.  At least the Lenovo
148	 * Thinkpad X61 is known to need this for the video BIOS
149	 * initialization quirk to work; this is likely to also
150	 * be the case for other laptops or integrated video devices.
151	 */
152
153	.balign	16
154GLOBAL(wakeup_gdt)
155	.word	3*8-1		/* Self-descriptor */
156	.long	pa_wakeup_gdt
157	.word	0
158
159	.word	0xffff		/* 16-bit code segment @ real_mode_base */
160	.long	0x9b000000 + pa_real_mode_base
161	.word	0x008f		/* big real mode */
162
163	.word	0xffff		/* 16-bit data segment @ real_mode_base */
164	.long	0x93000000 + pa_real_mode_base
165	.word	0x008f		/* big real mode */
166END(wakeup_gdt)
167
168	.section ".rodata","a"
169	.balign	8
170
171	/* This is the standard real-mode IDT */
172	.balign	16
173GLOBAL(wakeup_idt)
174	.word	0xffff		/* limit */
175	.long	0		/* address */
176	.word	0
177END(wakeup_idt)