aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/boot/x86_64.S
blob: 98289c7ab656e07bfddfa654f7630bddd773d345 (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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#include <xen/config.h>
#include <public/xen.h>
#include <asm/page.h>
#include <asm/msr.h>

#define  SECONDARY_CPU_FLAG 0xA5A5A5A5
                
        .text
        .code32
        
ENTRY(start)
        jmp __start
        
        .org    0x004
/*** MULTIBOOT HEADER ****/
        /* Magic number indicating a Multiboot header. */
        .long   0x1BADB002
        /* Flags to bootloader (see Multiboot spec). */
        .long   0x00000002
        /* Checksum: must be the negated sum of the first two fields. */
        .long   -0x1BADB004

        .org    0x010
        .asciz "ERR: Not a 64-bit CPU!"
        .org    0x028
        .asciz "ERR: Not a Multiboot bootloader!"
bad_cpu:
        mov     $0x100010,%esi # Error message
        jmp     print_err
not_multiboot:
        mov     $0x100028,%esi # Error message
print_err:
        mov     $0xB8000,%edi  # VGA framebuffer
1:      mov     (%esi),%bl
        test    %bl,%bl        # Terminate on '\0' sentinel
2:      je      2b
        mov     $0x3f8+5,%dx   # UART Line Status Register
3:      in      %dx,%al
        test    $0x20,%al      # Test THR Empty flag
        je      3b
        mov     $0x3f8+0,%dx   # UART Transmit Holding Register
        mov     %bl,%al
        out     %al,%dx        # Send a character over the serial line
        movsb                  # Write a character to the VGA framebuffer
        mov     $7,%al
        stosb                  # Write an attribute to the VGA framebuffer
        jmp     1b
        
__start:
        cld
        cli

        /* Set up a few descriptors: on entry only CS is guaranteed good. */
        lgdt    %cs:0x1001f0
        mov     $(__HYPERVISOR_DS),%ecx
        mov     %ecx,%ds
        mov     %ecx,%es

        /* Check for Multiboot bootloader */
        cmp     $(SECONDARY_CPU_FLAG),%ebx
        je      skip_multiboot_check
        cmp     $0x2BADB002,%eax
        jne     not_multiboot
skip_multiboot_check:
        
        /* Save the Multiboot info structure for later use. */
        mov     %ebx,0x1001e0

        /* We begin by interrogating the CPU for the presence of long mode. */
        mov     $0x80000000,%eax
        cpuid
        cmp     $0x80000000,%eax    # any function > 0x80000000?
        jbe     bad_cpu
        mov     $0x80000001,%eax
        cpuid
        bt      $29,%edx            # Long mode feature?
        jnc     bad_cpu
        
        /* Set up FPU. */
        fninit
        
        /* Enable PAE in CR4. */
        mov     $0x20,%ecx # X86_CR4_PAE
        mov     %ecx,%cr4

        /* Load pagetable base register. */
        mov     $0x101000,%eax   /* idle_pg_table */
        mov     %eax,%cr3

        /* Set up EFER (Extended Feature Enable Register). */
        movl    $MSR_EFER, %ecx
        rdmsr
        /* Long Mode, SYSCALL/SYSRET, No-Execute */
        movl    $(EFER_LME|EFER_SCE|EFER_NX),%eax
        wrmsr

        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 into 64-bit mode. */
        ljmp    $(__HYPERVISOR_CS64),$0x100100
        
        .code64
        .org    0x0100

        /* Install relocated selectors (FS/GS unused). */
        lgdt    gdt_descr(%rip)
        mov     $(__HYPERVISOR_DS),%ecx
        mov     %ecx,%ds
        mov     %ecx,%es
        mov     %ecx,%ss

        /* Enable full CR4 features. */
        mov     mmu_cr4_features(%rip),%rcx
        mov     %rcx,%cr4

        mov     stack_start(%rip),%rsp
        
        /* Reset EFLAGS (subsumes CLI and CLD). */
        pushq   $0
        popf

        /* Jump to high mappings. */
        mov     high_start(%rip),%rax
        push    %rax
        ret
__high_start:
        
        lidt    idt_descr(%rip)
                
        cmp     $(SECONDARY_CPU_FLAG),%ebx
        je      start_secondary

        /* Initialize BSS (no nasty surprises!) */
        lea     __bss_start(%rip),%rdi
        lea     _end(%rip),%rcx
        sub     %rdi,%rcx
        xor     %rax,%rax
        rep     stosb

        /* Initialise IDT with simple error defaults. */
        lea     ignore_int(%rip),%rdx
        mov     $(__HYPERVISOR_CS64 << 16),%eax
        mov     %dx,%ax            /* selector = 0x0010 = cs */
        mov     $0x8E00,%dx        /* interrupt gate - dpl=0, present */
        lea     idt_table(%rip),%rdi
        mov     $256,%rcx
1:      mov     %eax,(%rdi)
        mov     %edx,4(%rdi)
        add     $8,%rdi
        loop    1b

        /* Pass off the Multiboot info structure to C land. */
        mov     0x1001e0,%edi
        lea     start(%rip),%rax
        sub     $0x100000,%rax
        add     %rax,%rdi
        call    cmain

/* This is the default interrupt handler. */
int_msg:
        .asciz "Unknown interrupt\n"
ignore_int:
        cld
        mov     $(__HYPERVISOR_DS),%eax
        mov     %eax,%ds
        mov     %eax,%es
        lea     int_msg(%rip),%rdi
        call    SYMBOL_NAME(printf)
1:      jmp     1b

        .code32

        .org    0x1e0
                        
/*** DESCRIPTOR TABLES ***/

.globl SYMBOL_NAME(idt)
.globl SYMBOL_NAME(gdt)        

        .org    0x1f0
        .word   (LAST_RESERVED_GDT_ENTRY*8)+7
        .long   0x100200 # gdt_table
        
        .org    0x200
ENTRY(gdt_table)
        .fill FIRST_RESERVED_GDT_ENTRY,8,0
        .quad 0x0000000000000000     /* unused */
        .quad 0x00cf9a000000ffff     /* 0x0808 ring 0 code, compatability */
        .quad 0x00af9a000000ffff     /* 0x0810 ring 0 code, 64-bit mode   */
        .quad 0x00cf92000000ffff     /* 0x0818 ring 0 data                */
        .quad 0x00cffa000000ffff     /* 0x0823 ring 3 code, compatibility */
        .quad 0x00affa000000ffff     /* 0x082b ring 3 code, 64-bit mode   */
        .quad 0x00cff2000000ffff     /* 0x0833 ring 3 data                */
        .quad 0x0000000000000000     /* unused                            */
        .fill 2*NR_CPUS,8,0          /* space for TSS and LDT per CPU     */

        .word   0
gdt_descr:
        .word   (LAST_RESERVED_GDT_ENTRY*8)+7
SYMBOL_NAME(gdt):       
        .quad   SYMBOL_NAME(gdt_table)

        .word   0    
idt_descr:
        .word   256*8-1
SYMBOL_NAME(idt):
        .quad   SYMBOL_NAME(idt_table)

ENTRY(stack_start)
        .quad   SYMBOL_NAME(cpu0_stack) + 8100

high_start:
        .quad   __high_start
                
/* Initial PML4 -- level-4 page table */
        .org 0x1000
ENTRY(idle_pg_table)
ENTRY(idle_pg_table_4)
        .quad 0x0000000000102007 # PML4[0]
        .fill 261,8,0
        .quad 0x0000000000102007 # PML4[262]

/* Initial PDP -- level-3 page table */
        .org 0x2000
ENTRY(idle_pg_table_l3)
        .quad 0x0000000000103007

/* Initial PDE -- level-2 page table. */
        .org 0x3000
ENTRY(idle_pg_table_l2)
        .macro identmap from=0, count=512
        .if \count-1
        identmap "(\from+0)","(\count/2)"
        identmap "(\from+(0x200000*(\count/2)))","(\count/2)"
        .else
        .quad 0x00000000000001e3 + \from
        .endif
        .endm
        identmap /* Too orangey for crows :-) */

        .org 0x4000
ENTRY(cpu0_stack)    # Initial stack is 8kB

        .org 0x6000
ENTRY(stext)
ENTRY(_stext)

.globl map_domain_mem, unmap_domain_mem, ret_from_intr
map_domain_mem:
unmap_domain_mem:
ret_from_intr:
#undef machine_to_phys_mapping
.globl copy_to_user, set_intr_gate, die, machine_to_phys_mapping
copy_to_user:
set_intr_gate:
die:
machine_to_phys_mapping:
.globl copy_from_user, show_registers, __set_fixmap, do_iopl, check_descriptor
copy_from_user: 
show_registers: 
__set_fixmap: 
do_iopl: 
check_descriptor:
.globl set_gdt, idt_table, copy_user_generic, memcmp, idt_tables, new_thread
set_gdt:
idt_table:
copy_user_generic:
memcmp:
idt_tables:
new_thread:
.globl switch_to, continue_nonidle_task, __get_user_1, paging_init, trap_init
switch_to:
continue_nonidle_task:
__get_user_1:
paging_init:
trap_init: 
.globl __get_user_8, zap_low_mappings, set_debugreg,synchronise_pagetables
__get_user_8:
zap_low_mappings:
set_debugreg:
synchronise_pagetables:
.globl destroy_gdt
destroy_gdt: