xref: /kvm-unit-tests/x86/trampolines.S (revision 4c8a99ca02252d4a2bee43f4558fe47ce5ab7ec0)
1/*
2 * Common bootstrapping code to transition from 16-bit to 32-bit code, and to
3 * transition from 32-bit to 64-bit code (x86-64 only)
4 */
5
6 /* EFI provides it's own SIPI sequence to handle relocation. */
7#ifndef CONFIG_EFI
8.code16
9.globl rm_trampoline
10rm_trampoline:
11
12/* Store SIPI vector code at the beginning of trampoline. */
13sipi_entry:
14	mov %cr0, %eax
15	or $1, %eax
16	mov %eax, %cr0
17	lgdtl ap_rm_gdt_descr - sipi_entry
18	ljmpl $8, $ap_start32
19sipi_end:
20
21.globl ap_rm_gdt_descr
22ap_rm_gdt_descr:
23#ifdef __i386__
24	.word 0
25	.long 0
26#else
27	.word gdt32_end - gdt32 - 1
28	.long gdt32
29#endif
30
31.globl rm_trampoline_end
32rm_trampoline_end:
33#endif
34
35/* The 32-bit => 64-bit trampoline is x86-64 only. */
36#ifdef __x86_64__
37.code32
38
39/*
40 * EFI builds with "-shared -fPIC" and so cannot directly reference any absolute
41 * address.  In 64-bit mode, RIP-relative addressing neatly solves the problem,
42 * but 32-bit code doesn't have that luxury.  Make a dummy CALL to get RIP into
43 * a GPR in order to emulate RIP-relative for 32-bit transition code.
44 */
45.macro load_absolute_addr, addr, reg
46#ifdef CONFIG_EFI
47	call 1f
481:
49	pop \reg
50	add \addr - 1b, \reg
51#else
52	mov \addr, \reg
53#endif
54.endm
55
56MSR_GS_BASE = 0xc0000101
57
58.macro setup_percpu_area
59	lea -4096(%esp), %eax
60	mov $0, %edx
61	mov $MSR_GS_BASE, %ecx
62	wrmsr
63.endm
64
65.macro setup_segments
66	mov $MSR_GS_BASE, %ecx
67	rdmsr
68
69	mov $0x10, %bx
70	mov %bx, %ds
71	mov %bx, %es
72	mov %bx, %fs
73	mov %bx, %gs
74	mov %bx, %ss
75
76	/* restore MSR_GS_BASE */
77	wrmsr
78.endm
79
80prepare_64:
81	load_absolute_addr $gdt_descr, %edx
82	lgdtl (%edx)
83
84	setup_segments
85
86	xor %eax, %eax
87	mov %eax, %cr4
88
89enter_long_mode:
90	mov %cr4, %eax
91	bts $5, %eax  // pae
92	mov %eax, %cr4
93
94	/* Note, EFI doesn't yet support 5-level paging. */
95#ifdef CONFIG_EFI
96	load_absolute_addr $ptl4, %eax
97#else
98	mov pt_root, %eax
99#endif
100	mov %eax, %cr3
101
102efer = 0xc0000080
103	mov $efer, %ecx
104	rdmsr
105	bts $8, %eax
106	wrmsr
107
108	mov %cr0, %eax
109	bts $0, %eax
110	bts $31, %eax
111	mov %eax, %cr0
112	ret
113
114.globl ap_start32
115ap_start32:
116	setup_segments
117
118	load_absolute_addr $smp_stacktop, %edx
119	mov $-4096, %esp
120	lock xaddl %esp, (%edx)
121
122	setup_percpu_area
123	call prepare_64
124
125	load_absolute_addr $ap_start64, %edx
126	pushl $0x08
127	pushl %edx
128	lretl
129#endif
130