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