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
178
179
180
181
|
.code16
#define wakesym(sym) (sym - wakeup_start)
.align 16
ENTRY(wakeup_start)
cli
cld
# setup data segment
movw %cs, %ax
movw %ax, %ds
movw %ax, %ss # A stack required for BIOS call
movw $wakesym(wakeup_stack), %sp
pushl $0 # Kill dangerous flag early
popfl
# check magic number
movl wakesym(real_magic), %eax
cmpl $0x12345678, %eax
jne bogus_real_magic
# for acpi_sleep=s3_bios
testl $1, wakesym(video_flags)
jz 1f
lcall $0xc000, $3
movw %cs, %ax # In case messed by BIOS
movw %ax, %ds
movw %ax, %ss # Need this? How to ret if clobbered?
1: # for acpi_sleep=s3_mode
testl $2, wakesym(video_flags)
jz 1f
movl wakesym(video_mode), %eax
call mode_setw
1: # Show some progress if VGA is resumed
movw $0xb800, %ax
movw %ax, %fs
movw $0x0e00 + 'L', %fs:(0x10)
# boot trampoline is under 1M, and shift its start into
# %fs to reference symbols in that area
mov wakesym(trampoline_seg), %fs
lidt %fs:bootsym(idt_48)
lgdt %fs:bootsym(gdt_48)
movw $1, %ax
lmsw %ax # Turn on CR0.PE
ljmpl $BOOT_CS32, $bootsym_rel(wakeup_32, 6)
/* This code uses an extended set of video mode numbers. These include:
* Aliases for standard modes
* NORMAL_VGA (-1)
* EXTENDED_VGA (-2)
* ASK_VGA (-3)
* Video modes numbered by menu position -- NOT RECOMMENDED because of lack
* of compatibility when extending the table. These are between 0x00 and 0xff.
*/
#define VIDEO_FIRST_MENU 0x0000
/* Standard BIOS video modes (BIOS number + 0x0100) */
#define VIDEO_FIRST_BIOS 0x0100
/* VESA BIOS video modes (VESA number + 0x0200) */
#define VIDEO_FIRST_VESA 0x0200
/* Video7 special modes (BIOS number + 0x0900) */
#define VIDEO_FIRST_V7 0x0900
# Setting of user mode (AX=mode ID) => CF=success
mode_setw:
movw %ax, %bx
cmpb $VIDEO_FIRST_VESA>>8, %ah
jnc check_vesaw
decb %ah
setbadw: clc
ret
check_vesaw:
subb $VIDEO_FIRST_VESA>>8, %bh
orw $0x4000, %bx # Use linear frame buffer
movw $0x4f02, %ax # VESA BIOS mode set call
int $0x10
cmpw $0x004f, %ax # AL=4f if implemented
jnz _setbadw # AH=0 if OK
stc
ret
_setbadw: jmp setbadw
bogus_real_magic:
movw $0x0e00 + 'B', %fs:(0x12)
jmp bogus_real_magic
.align 4
real_magic: .long 0x12345678
GLOBAL(video_mode)
.long 0
GLOBAL(video_flags)
.long 0
trampoline_seg: .word 0
.pushsection .trampoline_seg, "a"
.long trampoline_seg - .
.popsection
.code32
# Now in protect mode, with paging disabled
# Add offset for any reference to xen specific symbols
wakeup_32:
/* Set up segment registers and initial stack for protected mode */
mov $BOOT_DS, %eax
mov %eax, %ds
mov %eax, %ss
mov $bootsym_rel(wakeup_stack, 4, %esp)
# check saved magic again
mov $sym_phys(saved_magic), %eax
add bootsym_rel(trampoline_xen_phys_start, 4, %eax)
mov (%eax), %eax
cmp $0x9abcdef0, %eax
jne bogus_saved_magic
/* fpu init? */
/* Initialise CR4. */
mov $X86_CR4_PAE, %ecx
mov %ecx, %cr4
/* Load pagetable base register */
mov $sym_phys(idle_pg_table),%eax
add bootsym_rel(trampoline_xen_phys_start,4,%eax)
mov %eax,%cr3
/* Will cpuid feature change after resume? */
/* Set up EFER (Extended Feature Enable Register). */
mov bootsym_rel(cpuid_ext_features,4,%edi)
test $0x20100800,%edi /* SYSCALL/SYSRET, No Execute, Long Mode? */
jz .Lskip_eferw
movl $MSR_EFER,%ecx
rdmsr
btsl $_EFER_LME,%eax /* Long Mode */
btsl $_EFER_SCE,%eax /* SYSCALL/SYSRET */
btl $20,%edi /* No Execute? */
jnc 1f
btsl $_EFER_NX,%eax /* No Execute */
1: wrmsr
.Lskip_eferw:
wbinvd
/* Enable paging and flush prefetch queue */
mov $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */
mov %eax,%cr0
jmp 1f
1:
/* Now in compatibility mode. Long-jump to 64-bit mode */
ljmp $BOOT_CS64, $bootsym_rel(wakeup_64,6)
.code64
wakeup_64:
/* Jump to high mappings and the higher-level wakeup code. */
movq ret_point(%rip), %rbx
jmp *%rbx
ret_point:
.quad __ret_point
bogus_saved_magic:
movw $0x0e00 + 'S', 0xb8014
jmp bogus_saved_magic
.align 16
.fill PAGE_SIZE,1,0
wakeup_stack:
|