aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/boot/wakeup.S
blob: a3883c14311eb3fce8d74e01a8d90687dffcf761 (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
        .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: