Blame view

kernel/linux-rt-4.4.41/arch/x86/realmode/rm/wakeup_asm.S 3.64 KB
5113f6f70   김현기   kernel add
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
  /*
   * ACPI wakeup real mode startup stub
   */
  #include <linux/linkage.h>
  #include <asm/segment.h>
  #include <asm/msr-index.h>
  #include <asm/page_types.h>
  #include <asm/pgtable_types.h>
  #include <asm/processor-flags.h>
  #include "realmode.h"
  #include "wakeup.h"
  
  	.code16
  
  /* This should match the structure in wakeup.h */
  	.section ".data", "aw"
  
  	.balign	16
  GLOBAL(wakeup_header)
  	video_mode:	.short	0	/* Video mode number */
  	pmode_entry:	.long	0
  	pmode_cs:	.short	__KERNEL_CS
  	pmode_cr0:	.long	0	/* Saved %cr0 */
  	pmode_cr3:	.long	0	/* Saved %cr3 */
  	pmode_cr4:	.long	0	/* Saved %cr4 */
  	pmode_efer:	.quad	0	/* Saved EFER */
  	pmode_gdt:	.quad	0
  	pmode_misc_en:	.quad	0	/* Saved MISC_ENABLE MSR */
  	pmode_behavior:	.long	0	/* Wakeup behavior flags */
  	realmode_flags:	.long	0
  	real_magic:	.long	0
  	signature:	.long	WAKEUP_HEADER_SIGNATURE
  END(wakeup_header)
  
  	.text
  	.code16
  
  	.balign	16
  ENTRY(wakeup_start)
  	cli
  	cld
  
  	LJMPW_RM(3f)
  3:
  	/* Apparently some dimwit BIOS programmers don't know how to
  	   program a PM to RM transition, and we might end up here with
  	   junk in the data segment descriptor registers.  The only way
  	   to repair that is to go into PM and fix it ourselves... */
  	movw	$16, %cx
  	lgdtl	%cs:wakeup_gdt
  	movl	%cr0, %eax
  	orb	$X86_CR0_PE, %al
  	movl	%eax, %cr0
  	ljmpw	$8, $2f
  2:
  	movw	%cx, %ds
  	movw	%cx, %es
  	movw	%cx, %ss
  	movw	%cx, %fs
  	movw	%cx, %gs
  
  	andb	$~X86_CR0_PE, %al
  	movl	%eax, %cr0
  	LJMPW_RM(3f)
  3:
  	/* Set up segments */
  	movw	%cs, %ax
  	movw	%ax, %ss
  	movl	$rm_stack_end, %esp
  	movw	%ax, %ds
  	movw	%ax, %es
  	movw	%ax, %fs
  	movw	%ax, %gs
  
  	lidtl	wakeup_idt
  
  	/* Clear the EFLAGS */
  	pushl $0
  	popfl
  
  	/* Check header signature... */
  	movl	signature, %eax
  	cmpl	$WAKEUP_HEADER_SIGNATURE, %eax
  	jne	bogus_real_magic
  
  	/* Check we really have everything... */
  	movl	end_signature, %eax
  	cmpl	$REALMODE_END_SIGNATURE, %eax
  	jne	bogus_real_magic
  
  	/* Call the C code */
  	calll	main
  
  	/* Restore MISC_ENABLE before entering protected mode, in case
  	   BIOS decided to clear XD_DISABLE during S3. */
  	movl	pmode_behavior, %edi
  	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
  	jnc	1f
  
  	movl	pmode_misc_en, %eax
  	movl	pmode_misc_en + 4, %edx
  	movl	$MSR_IA32_MISC_ENABLE, %ecx
  	wrmsr
  1:
  
  	/* Do any other stuff... */
  
  #ifndef CONFIG_64BIT
  	/* This could also be done in C code... */
  	movl	pmode_cr3, %eax
  	movl	%eax, %cr3
  
  	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
  	jnc	1f
  	movl	pmode_cr4, %eax
  	movl	%eax, %cr4
  1:
  	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
  	jnc	1f
  	movl	pmode_efer, %eax
  	movl	pmode_efer + 4, %edx
  	movl	$MSR_EFER, %ecx
  	wrmsr
  1:
  
  	lgdtl	pmode_gdt
  
  	/* This really couldn't... */
  	movl	pmode_entry, %eax
  	movl	pmode_cr0, %ecx
  	movl	%ecx, %cr0
  	ljmpl	$__KERNEL_CS, $pa_startup_32
  	/* -> jmp *%eax in trampoline_32.S */
  #else
  	jmp	trampoline_start
  #endif
  
  bogus_real_magic:
  1:
  	hlt
  	jmp	1b
  
  	.section ".rodata","a"
  
  	/*
  	 * Set up the wakeup GDT.  We set these up as Big Real Mode,
  	 * that is, with limits set to 4 GB.  At least the Lenovo
  	 * Thinkpad X61 is known to need this for the video BIOS
  	 * initialization quirk to work; this is likely to also
  	 * be the case for other laptops or integrated video devices.
  	 */
  
  	.balign	16
  GLOBAL(wakeup_gdt)
  	.word	3*8-1		/* Self-descriptor */
  	.long	pa_wakeup_gdt
  	.word	0
  
  	.word	0xffff		/* 16-bit code segment @ real_mode_base */
  	.long	0x9b000000 + pa_real_mode_base
  	.word	0x008f		/* big real mode */
  
  	.word	0xffff		/* 16-bit data segment @ real_mode_base */
  	.long	0x93000000 + pa_real_mode_base
  	.word	0x008f		/* big real mode */
  END(wakeup_gdt)
  
  	.section ".rodata","a"
  	.balign	8
  
  	/* This is the standard real-mode IDT */
  	.balign	16
  GLOBAL(wakeup_idt)
  	.word	0xffff		/* limit */
  	.long	0		/* address */
  	.word	0
  END(wakeup_idt)