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
|
#include <xen/config.h>
#include <hypervisor-ifs/hypervisor-if.h>
#include <asm/page.h>
#define SECONDARY_CPU_FLAG 0xA5A5A5A5
.text
ENTRY(start)
jmp __start
.align 4
/*** 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
bad_cpu_msg:
.asciz "ERR: Not a P6-compatible CPU!"
not_multiboot_msg:
.asciz "ERR: Not a Multiboot bootloader!"
bad_cpu:
mov $SYMBOL_NAME(bad_cpu_msg)-__PAGE_OFFSET,%esi
jmp print_err
not_multiboot:
mov $SYMBOL_NAME(not_multiboot_msg)-__PAGE_OFFSET,%esi
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:
/* Set up a few descriptors: on entry only CS is guaranteed good. */
lgdt %cs:nopaging_gdt_descr-__PAGE_OFFSET
mov $(__HYPERVISOR_DS),%ecx
mov %ecx,%ds
mov %ecx,%es
mov %ecx,%fs
mov %ecx,%gs
ljmp $(__HYPERVISOR_CS),$(1f)-__PAGE_OFFSET
1: lss stack_start-__PAGE_OFFSET,%esp
/* Reset EFLAGS (subsumes CLI and CLD). */
pushl $0
popf
/* CPU type checks. We need P6+. */
mov $0x200000,%edx
pushfl
pop %ecx
and %edx,%ecx
jne bad_cpu # ID bit should be clear
pushl %edx
popfl
pushfl
pop %ecx
and %edx,%ecx
je bad_cpu # ID bit should be set
/* Set up FPU. */
fninit
/* Set up CR4, except global flag which Intel requires should be */
/* left until after paging is enabled (IA32 Manual Vol. 3, Sec. 2.5) */
mov mmu_cr4_features-__PAGE_OFFSET,%ecx
and $0x7f,%cl # CR4.PGE (global enable)
mov %ecx,%cr4
cmp $(SECONDARY_CPU_FLAG),%ebx
je start_paging
/* Check for Multiboot bootloader */
cmp $0x2BADB002,%eax
jne not_multiboot
/* Save the Multiboot info structure for later use. */
add $__PAGE_OFFSET,%ebx
push %ebx
/* Initialize BSS (no nasty surprises!) */
mov $__bss_start-__PAGE_OFFSET,%edi
mov $_end-__PAGE_OFFSET,%ecx
sub %edi,%ecx
xor %eax,%eax
rep stosb
/* Initialize low and high mappings of all memory with 4MB pages */
mov $idle_pg_table-__PAGE_OFFSET,%edi
mov $0x1e3,%eax /* PRESENT+RW+A+D+4MB+GLOBAL */
1: mov %eax,__PAGE_OFFSET>>20(%edi) /* high mapping */
stosl /* low mapping */
add $(1<<L2_PAGETABLE_SHIFT),%eax
cmp $DIRECTMAP_PHYS_END+0x1e3,%eax
jne 1b
1: stosl /* low mappings cover as much physmem as possible */
add $(1<<L2_PAGETABLE_SHIFT),%eax
cmp $__HYPERVISOR_VIRT_START+0x1e3,%eax
jne 1b
/* Initialise IDT with simple error defaults. */
lea ignore_int,%edx
mov $(__HYPERVISOR_CS << 16),%eax
mov %dx,%ax /* selector = 0x0010 = cs */
mov $0x8E00,%dx /* interrupt gate - dpl=0, present */
lea SYMBOL_NAME(idt_table)-__PAGE_OFFSET,%edi
mov $256,%ecx
1: mov %eax,(%edi)
mov %edx,4(%edi)
add $8,%edi
loop 1b
start_paging:
mov $idle_pg_table-__PAGE_OFFSET,%eax
mov %eax,%cr3
mov $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */
mov %eax,%cr0
jmp 1f
1: /* Install relocated selectors (FS/GS unused). */
lgdt gdt_descr
mov $(__HYPERVISOR_DS),%ecx
mov %ecx,%ds
mov %ecx,%es
mov %ecx,%ss
ljmp $(__HYPERVISOR_CS),$1f
1: /* Paging enabled, so we can now enable GLOBAL mappings in CR4. */
mov mmu_cr4_features,%ecx
mov %ecx,%cr4
/* Relocate ESP */
add $__PAGE_OFFSET,%esp
lidt idt_descr
cmp $(SECONDARY_CPU_FLAG),%ebx
je start_secondary
/* Call into main C routine. This should never return.*/
call cmain
ud2 /* Force a panic (invalid opcode). */
/* This is the default interrupt handler. */
int_msg:
.asciz "Unknown interrupt\n"
ALIGN
ignore_int:
cld
mov $(__HYPERVISOR_DS),%eax
mov %eax,%ds
mov %eax,%es
pushl $int_msg
call SYMBOL_NAME(printf)
1: jmp 1b
/*** STACK LOCATION ***/
ENTRY(stack_start)
.long SYMBOL_NAME(cpu0_stack) + 8100 - __PAGE_OFFSET
.long __HYPERVISOR_DS
/*** DESCRIPTOR TABLES ***/
.globl SYMBOL_NAME(idt)
.globl SYMBOL_NAME(gdt)
ALIGN
.word 0
idt_descr:
.word 256*8-1
SYMBOL_NAME(idt):
.long SYMBOL_NAME(idt_table)
.word 0
gdt_descr:
.word (LAST_RESERVED_GDT_ENTRY*8)+7
SYMBOL_NAME(gdt):
.long SYMBOL_NAME(gdt_table) /* gdt base */
.word 0
nopaging_gdt_descr:
.word (LAST_RESERVED_GDT_ENTRY*8)+7
.long SYMBOL_NAME(gdt_table)-__PAGE_OFFSET
ALIGN
/* NB. Rings != 0 get access up to 0xFC400000. This allows access to the */
/* machine->physical mapping table. Ring 0 can access all memory. */
ENTRY(gdt_table)
.fill FIRST_RESERVED_GDT_ENTRY,8,0
.quad 0x0000000000000000 /* unused */
.quad 0x00cf9a000000ffff /* 0x0808 ring 0 4.00GB code at 0x0 */
.quad 0x00cf92000000ffff /* 0x0810 ring 0 4.00GB data at 0x0 */
.quad 0x00cfba000000c3ff /* 0x0819 ring 1 3.95GB code at 0x0 */
.quad 0x00cfb2000000c3ff /* 0x0821 ring 1 3.95GB data at 0x0 */
.quad 0x00cffa000000c3ff /* 0x082b ring 3 3.95GB code at 0x0 */
.quad 0x00cff2000000c3ff /* 0x0833 ring 3 3.95GB data at 0x0 */
.quad 0x0000000000000000 /* unused */
.fill 2*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
.org 0x1000
ENTRY(idle_pg_table) # Initial page directory is 4kB
.org 0x2000
ENTRY(cpu0_stack) # Initial stack is 8kB
.org 0x4000
ENTRY(stext)
ENTRY(_stext)
|