-
Notifications
You must be signed in to change notification settings - Fork 137
/
boot.S
233 lines (191 loc) · 5.42 KB
/
boot.S
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
/*
* Copyright (c) 2015-2020 Contributors as noted in the AUTHORS file
*
* This file is part of Solo5, a sandboxed execution environment.
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose with or without fee is hereby granted, provided
* that the above copyright notice and this permission notice appear
* in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "../cpu_x86_64.h"
#include "xen/elfnote.h"
#include "../virtio/multiboot.h"
#define ENTRY(x) .text; .globl x; .type x,%function; x:
#define END(x) .size x, . - x
#define XEN_HVM_START_MAGIC_VALUE 0x336ec578
#define MYMULTIBOOT_FLAGS \
(MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE)
.section .data.multiboot
.align 4
_multiboot_header:
.long MULTIBOOT_HEADER_MAGIC
.long MYMULTIBOOT_FLAGS
.long -(MULTIBOOT_HEADER_MAGIC+MYMULTIBOOT_FLAGS)
.long _multiboot_header
.long 0x100000
.long _edata
.long _ebss
.long _start32
/*
* Tell Xen that we are a PVH-capable kernel.
* See https://xenbits.xen.org/docs/unstable/misc/pvh.html.
*/
.section .note.solo5.xen, "a", @note
.align 4
.long 4
.long 4
.long XEN_ELFNOTE_PHYS32_ENTRY
.ascii "Xen\0"
.long _start32
.code32
/*
* Xen PVH entry point.
*
* When booted directly, Xen puts us only in 32bit flat protected mode, and
* passes a pointer to struct hvm_start_info in %ebx. When booted via grub's
* multiboot protocol, grub passes a pointer to struct multiboot_info in %ebx
* and sets a magic in %eax. Otherwise both boot modes works the same. The
* platform_init() differentiate the structure based on a magic at the
* beginning of hvm_start_info.
* It's our responsibility to install a page table and switch to long mode.
* Notably, we can't call C code until we've switched to long mode.
*/
ENTRY(_start32)
cld
movl $bootstack, %esp
/*
* Save Xen hvm_start_info or multiboot_info pointer (depending on boot
* mode) at top of stack, we pop it in 64bit
*/
pushl $0
pushl %ebx
cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
je 1f
movl (%ebx), %eax
cmpl $XEN_HVM_START_MAGIC_VALUE, %eax
jne unknownboot
1:
/*
* Load bootstrap GDT and reload segment registers, with the exception of
* CS, which will be reloaded on jumping to _start64
*/
lgdt (gdt64_ptr)
movl $0x10, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
xorl %eax, %eax
movl %eax, %fs
movl %eax, %gs
/*
* x86_64 switch to long mode
*/
/* 1: Enable PAE */
movl %cr4, %eax
orl $X86_CR4_PAE, %eax
movl %eax, %cr4
/* 2: Load PML4 pointer */
movl $cpu_pml4, %eax
movl %eax, %cr3
/* 3: Request long mode enable and enable NX functionality */
movl $0xc0000080, %ecx
rdmsr
orl $(X86_EFER_LME | X86_EFER_NXE), %eax
wrmsr
/* 4a: Enable paging and supervisor write protect */
movl %cr0, %eax
orl $(X86_CR0_PG | X86_CR0_WP), %eax
/* 4b: CPU sets long mode enabled after this instruction */
movl %eax, %cr0
/* 5: Reload CS with a 64-bit selector */
pushw $0x08
pushl $_start64
lret
/* NOTREACHED */
jmp haltme
unknownboot:
haltme:
cli
hlt
jmp haltme
END(_start32)
.code64
ENTRY(_start64)
movq $bootstack, %rsp
xorq %rbp, %rbp
/* Enable FPU and SSE units */
movq %cr0, %rax
andq $(~X86_CR0_EM), %rax
orq $(X86_CR0_MP | X86_CR0_NE), %rax
movq %rax, %cr0
movq %cr4, %rax
orq $(X86_CR4_OSXMMEXCPT | X86_CR4_OSFXSR), %rax
movq %rax, %cr4
ldmxcsr (mxcsr_ptr)
/* Read Xen hvm_start_info pointer */
movq -8(%rsp), %rdi
/* Call into C with correct start-of-day stack alignment */
pushq $0x0
pushq $0x0
call _start
/* NOTREACHED */
jmp haltme
END(_start64)
/*
* void _newstack(uint64_t stack_start, void (*tramp)(void *), void *arg);
*
* Switch to a new stack at (stack_start), and transfer control to
* (*tramp)(arg).
*/
ENTRY(_newstack)
movq %rdi, %rsp
movq %rdx, %rdi
/* As above, ensure correct start-of-day stack alignment */
pushq $0x0
pushq $0x0
call *%rsi
/* NOTREACHED */
jmp haltme
END(_newstack)
.data
/*
* amd64 programmer's manual:
*
* "In long mode, segmentation is not used ... except for a few exceptions."
*
* Uuuyea, exceptions.
*
* The GDT here is used only during bootstrapping, and is reloaded by
* cpu_init().
*/
.align 64
gdt64:
.quad 0x0 /* 0: NULL selector */
.quad GDT_DESC_CODE_VAL /* 0x8: 64-bit code */
.quad GDT_DESC_DATA_VAL /* 0x10: 64-bit data */
gdt64_end:
.align 64
.type gdt64_ptr, @object
gdt64_ptr:
.word gdt64_end-gdt64-1
.quad gdt64
.type mxcsr_ptr, @object
mxcsr_ptr:
.word 0x1f80 /* Intel SDM power-on default */
#include "pagetable.S"
.section .bss
/*
* Stack used during bootstrapping, reloaded before calling _start2().
*/
.space 4096
bootstack: