aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/boot/wakeup.S
blob: a986b422f8c090ef4b8e7034eeb144fa1ebf08dc (plain)
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
        .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(early_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
        movl    $BOOT_TRAMPOLINE, %eax
        shrl    $4, %eax
        movl    %eax, %fs
        lidt    %fs:bootsym(idt_48)
        lgdt    %fs:bootsym(gdt_48)

        movw    $1, %ax
        lmsw    %ax             # Turn on CR0.PE 
        jmp     1f
1:      ljmpl   $BOOT_CS32, $bootsym_phys(wakeup_32)

/* 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
         .globl video_mode, video_flags
video_mode:     .long 0
video_flags:    .long 0

        .code32

        # Now in protect mode, with paging disabled
        # Add offset for any reference to xen specific symbols

wakeup_32:
        mov     $BOOT_DS, %eax
        mov     %eax, %ds
        mov     %eax, %ss
        mov     $bootsym_phys(early_stack), %esp

        # check saved magic again
        mov     $sym_phys(saved_magic), %eax
        add     bootsym_phys(trampoline_xen_phys_start), %eax
        mov     (%eax), %eax
        cmp     $0x9abcdef0, %eax
        jne     bogus_saved_magic
        
        /* fpu init? */

        /* Initialise CR4. */
#if CONFIG_PAGING_LEVELS == 2
        mov     $X86_CR4_PSE, %ecx
#else
        mov     $X86_CR4_PAE, %ecx
#endif
        mov     %ecx, %cr4

        /* Load pagetable base register */
        mov     $sym_phys(idle_pg_table),%eax
        add     bootsym_phys(trampoline_xen_phys_start),%eax
        mov     %eax,%cr3

        /* Will cpuid feature change after resume? */
#if CONFIG_PAGING_LEVELS != 2
        /* Set up EFER (Extended Feature Enable Register). */
        mov     bootsym_phys(cpuid_ext_features),%edi
        test    $0x20100800,%edi /* SYSCALL/SYSRET, No Execute, Long Mode? */
        jz      .Lskip_eferw
        movl    $MSR_EFER,%ecx
        rdmsr
#if CONFIG_PAGING_LEVELS == 4
        btsl    $_EFER_LME,%eax /* Long Mode      */
        btsl    $_EFER_SCE,%eax /* SYSCALL/SYSRET */
#endif
        btl     $20,%edi        /* No Execute?    */
        jnc     1f
        btsl    $_EFER_NX,%eax  /* No Execute     */
1:      wrmsr
.Lskip_eferw:
#endif

        wbinvd

        mov     $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */
        mov     %eax,%cr0
        jmp     1f
1:

#if defined(__x86_64__)

        /* Now in compatibility mode. Long-jump to 64-bit mode */
        ljmp    $BOOT_CS64, $bootsym_phys(wakeup_64)

        .code64
        .align  8
        .word   0,0,0
lgdt_descr:
        .word   LAST_RESERVED_GDT_BYTE
        .quad   gdt_table - FIRST_RESERVED_GDT_BYTE
        
wakeup_64:
        lgdt    lgdt_descr(%rip)
        mov     $(__HYPERVISOR_DS64), %eax
        mov     %eax, %ds

        # long jump to return point, with cs reload
        rex64 ljmp    *ret_point(%rip)

        .align 8
ret_point:
        .quad   __ret_point
        .word   __HYPERVISOR_CS64

#else /* !defined(__x86_64__) */
        lgdt    gdt_descr
        mov     $(__HYPERVISOR_DS), %eax
        mov     %eax, %ds

        ljmp    $(__HYPERVISOR_CS), $__ret_point
#endif

bogus_saved_magic:
        movw    $0x0e00 + 'S', 0xb8014
        jmp     bogus_saved_magic