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
|
#define CR0_PG 0x80000000
#define CR0_PE 0x00000001
#define CR4_PAE 0x00000020
#define CR4_PGE 0x00000080
#define PHYSADDR(x) (x - smp_initialization_start)
# NOTE: THIS CODE REQUIRES THAT IT BE PLACED STARTING AT PHYSICAL ADDRESS 0x0
.file "smp_trampoline.S"
.global smp_initialization_start, smp_initialization_end
smp_initialization_start:
/* When we initialize a processor, it starts in 16-bit real mode */
.code16
.align 0x1000
smp_processor_init:
cli
// enable PAE
mov $(CR4_PAE | CR4_PGE), %eax
mov %eax, %cr4
mov $PHYSADDR(pml4), %eax
mov %eax, %cr3
// enter long mode
mov $0xC0000080, %ecx
rdmsr
or $0x100, %eax
wrmsr
lgdt PHYSADDR(GDTPointer)
// Enable paging AND protection simultaneously
movl %cr0, %eax
or $(CR0_PG | CR0_PE), %eax
movl %eax, %cr0
ljmp $0x8, $PHYSADDR(smp_trampoline)
.code64
smp_trampoline:
movabsq $(0xffff880000000000 + PHYSADDR(stack_pointer)), %rsp
xor %rbp, %rbp
movabsq $smp_processor_entry, %rax
call *%rax
.align 16
GDT64:
GDTNull:
.quad 0
GDTKernelCode:
// base = 0x0, limit = 0x0
// flags: present, ring 0, executable, readable, 64bit
.word 0, 0
.byte 0, 0x9a, 0x20, 0
GDTEnd:
GDTPointer:
.word GDTEnd - GDT64 - 1 // size of gdt - 1
.long PHYSADDR(GDT64) // pointer to gdt
.align 0x1000
pml4: // maps first 1GB of RAM to both 0x0000000000000000 and 0xffff800000000000
.quad PHYSADDR(pdpt) + 3
.fill 255,8,0
.quad PHYSADDR(pdpt) + 3
.fill 15,8,0
.quad PHYSADDR(pdpt) + 3
.fill 239,8,0
pdpt:
.quad 0x0000000000000083
.fill 511,8,0
.skip 0x1000
stack_pointer:
smp_initialization_end:
|