1bbdb7433SSean Christopherson #define MAGIC_NUM 0xdeadbeefdeadbeefUL
2bbdb7433SSean Christopherson #define GS_BASE 0x400000
3bbdb7433SSean Christopherson
test_cr8(void)4bbdb7433SSean Christopherson static void test_cr8(void)
5bbdb7433SSean Christopherson {
6bbdb7433SSean Christopherson unsigned long src, dst;
7bbdb7433SSean Christopherson
8bbdb7433SSean Christopherson dst = 777;
9bbdb7433SSean Christopherson src = 3;
10bbdb7433SSean Christopherson asm volatile("mov %[src], %%cr8; mov %%cr8, %[dst]"
11bbdb7433SSean Christopherson : [dst]"+r"(dst), [src]"+r"(src));
12bbdb7433SSean Christopherson report(dst == 3 && src == 3, "mov %%cr8");
13bbdb7433SSean Christopherson }
14bbdb7433SSean Christopherson
test_push(void * mem)15bbdb7433SSean Christopherson static void test_push(void *mem)
16bbdb7433SSean Christopherson {
17bbdb7433SSean Christopherson unsigned long tmp;
18bbdb7433SSean Christopherson unsigned long *stack_top = mem + 4096;
19bbdb7433SSean Christopherson unsigned long *new_stack_top;
20bbdb7433SSean Christopherson unsigned long memw = 0x123456789abcdeful;
21bbdb7433SSean Christopherson
22bbdb7433SSean Christopherson memset(mem, 0x55, (void *)stack_top - mem);
23bbdb7433SSean Christopherson
24bbdb7433SSean Christopherson asm volatile("mov %%rsp, %[tmp] \n\t"
25bbdb7433SSean Christopherson "mov %[stack_top], %%rsp \n\t"
26bbdb7433SSean Christopherson "pushq $-7 \n\t"
27bbdb7433SSean Christopherson "pushq %[reg] \n\t"
28bbdb7433SSean Christopherson "pushq (%[mem]) \n\t"
29bbdb7433SSean Christopherson "pushq $-7070707 \n\t"
30bbdb7433SSean Christopherson "mov %%rsp, %[new_stack_top] \n\t"
31bbdb7433SSean Christopherson "mov %[tmp], %%rsp"
32bbdb7433SSean Christopherson : [tmp]"=&r"(tmp), [new_stack_top]"=r"(new_stack_top)
33bbdb7433SSean Christopherson : [stack_top]"r"(stack_top),
34bbdb7433SSean Christopherson [reg]"r"(-17l), [mem]"r"(&memw)
35bbdb7433SSean Christopherson : "memory");
36bbdb7433SSean Christopherson
37bbdb7433SSean Christopherson report(stack_top[-1] == -7ul, "push $imm8");
38bbdb7433SSean Christopherson report(stack_top[-2] == -17ul, "push %%reg");
39bbdb7433SSean Christopherson report(stack_top[-3] == 0x123456789abcdeful, "push mem");
40bbdb7433SSean Christopherson report(stack_top[-4] == -7070707, "push $imm");
41bbdb7433SSean Christopherson }
42bbdb7433SSean Christopherson
test_pop(void * mem)43bbdb7433SSean Christopherson static void test_pop(void *mem)
44bbdb7433SSean Christopherson {
45bbdb7433SSean Christopherson unsigned long tmp, tmp3, rsp, rbp;
46bbdb7433SSean Christopherson unsigned long *stack_top = mem + 4096;
47bbdb7433SSean Christopherson unsigned long memw = 0x123456789abcdeful;
48bbdb7433SSean Christopherson static unsigned long tmp2;
49bbdb7433SSean Christopherson
50bbdb7433SSean Christopherson memset(mem, 0x55, (void *)stack_top - mem);
51bbdb7433SSean Christopherson
52bbdb7433SSean Christopherson asm volatile("pushq %[val] \n\t"
53bbdb7433SSean Christopherson "popq (%[mem])"
54bbdb7433SSean Christopherson : : [val]"m"(memw), [mem]"r"(mem) : "memory");
55bbdb7433SSean Christopherson report(*(unsigned long *)mem == memw, "pop mem");
56bbdb7433SSean Christopherson
57bbdb7433SSean Christopherson memw = 7 - memw;
58bbdb7433SSean Christopherson asm volatile("mov %%rsp, %[tmp] \n\t"
59bbdb7433SSean Christopherson "mov %[stack_top], %%rsp \n\t"
60bbdb7433SSean Christopherson "pushq %[val] \n\t"
61bbdb7433SSean Christopherson "popq %[tmp2] \n\t"
62bbdb7433SSean Christopherson "mov %[tmp], %%rsp"
63bbdb7433SSean Christopherson : [tmp]"=&r"(tmp), [tmp2]"=m"(tmp2)
64bbdb7433SSean Christopherson : [val]"r"(memw), [stack_top]"r"(stack_top)
65bbdb7433SSean Christopherson : "memory");
66bbdb7433SSean Christopherson report(tmp2 == memw, "pop mem (2)");
67bbdb7433SSean Christopherson
68bbdb7433SSean Christopherson memw = 129443 - memw;
69bbdb7433SSean Christopherson asm volatile("mov %%rsp, %[tmp] \n\t"
70bbdb7433SSean Christopherson "mov %[stack_top], %%rsp \n\t"
71bbdb7433SSean Christopherson "pushq %[val] \n\t"
72bbdb7433SSean Christopherson "popq %[tmp2] \n\t"
73bbdb7433SSean Christopherson "mov %[tmp], %%rsp"
74bbdb7433SSean Christopherson : [tmp]"=&r"(tmp), [tmp2]"=r"(tmp2)
75bbdb7433SSean Christopherson : [val]"r"(memw), [stack_top]"r"(stack_top)
76bbdb7433SSean Christopherson : "memory");
77bbdb7433SSean Christopherson report(tmp2 == memw, "pop reg");
78bbdb7433SSean Christopherson
79bbdb7433SSean Christopherson asm volatile("mov %%rsp, %[tmp] \n\t"
80bbdb7433SSean Christopherson "mov %[stack_top], %%rsp \n\t"
81bbdb7433SSean Christopherson "lea 1f(%%rip), %%rax \n\t"
82bbdb7433SSean Christopherson "push %%rax \n\t"
83bbdb7433SSean Christopherson "ret \n\t"
84bbdb7433SSean Christopherson "2: jmp 2b \n\t"
85bbdb7433SSean Christopherson "1: mov %[tmp], %%rsp"
86bbdb7433SSean Christopherson : [tmp]"=&r"(tmp) : [stack_top]"r"(stack_top)
87bbdb7433SSean Christopherson : "memory", "rax");
88bbdb7433SSean Christopherson report_pass("ret");
89bbdb7433SSean Christopherson
90bbdb7433SSean Christopherson stack_top[-1] = 0x778899;
91bbdb7433SSean Christopherson asm volatile("mov %[stack_top], %%r8 \n\t"
92bbdb7433SSean Christopherson "mov %%rsp, %%r9 \n\t"
93bbdb7433SSean Christopherson "xchg %%rbp, %%r8 \n\t"
94bbdb7433SSean Christopherson "leave \n\t"
95bbdb7433SSean Christopherson "xchg %%rsp, %%r9 \n\t"
96bbdb7433SSean Christopherson "xchg %%rbp, %%r8 \n\t"
97bbdb7433SSean Christopherson "mov %%r9, %[tmp] \n\t"
98bbdb7433SSean Christopherson "mov %%r8, %[tmp3]"
99bbdb7433SSean Christopherson : [tmp]"=&r"(tmp), [tmp3]"=&r"(tmp3) : [stack_top]"r"(stack_top-1)
100bbdb7433SSean Christopherson : "memory", "r8", "r9");
101bbdb7433SSean Christopherson report(tmp == (ulong)stack_top && tmp3 == 0x778899, "leave");
102bbdb7433SSean Christopherson
103bbdb7433SSean Christopherson rbp = 0xaa55aa55bb66bb66ULL;
104bbdb7433SSean Christopherson rsp = (unsigned long)stack_top;
105bbdb7433SSean Christopherson asm volatile("mov %[rsp], %%r8 \n\t"
106bbdb7433SSean Christopherson "mov %[rbp], %%r9 \n\t"
107bbdb7433SSean Christopherson "xchg %%rsp, %%r8 \n\t"
108bbdb7433SSean Christopherson "xchg %%rbp, %%r9 \n\t"
109bbdb7433SSean Christopherson "enter $0x1238, $0 \n\t"
110bbdb7433SSean Christopherson "xchg %%rsp, %%r8 \n\t"
111bbdb7433SSean Christopherson "xchg %%rbp, %%r9 \n\t"
112bbdb7433SSean Christopherson "xchg %%r8, %[rsp] \n\t"
113bbdb7433SSean Christopherson "xchg %%r9, %[rbp]"
114bbdb7433SSean Christopherson : [rsp]"+a"(rsp), [rbp]"+b"(rbp) : : "memory", "r8", "r9");
115bbdb7433SSean Christopherson report(rsp == (unsigned long)stack_top - 8 - 0x1238
116bbdb7433SSean Christopherson && rbp == (unsigned long)stack_top - 8
117bbdb7433SSean Christopherson && stack_top[-1] == 0xaa55aa55bb66bb66ULL,
118bbdb7433SSean Christopherson "enter");
119bbdb7433SSean Christopherson }
120bbdb7433SSean Christopherson
test_ljmp(void * mem)121bbdb7433SSean Christopherson static void test_ljmp(void *mem)
122bbdb7433SSean Christopherson {
123bbdb7433SSean Christopherson unsigned char *m = mem;
124bbdb7433SSean Christopherson volatile int res = 1;
125bbdb7433SSean Christopherson
126bbdb7433SSean Christopherson *(unsigned long**)m = &&jmpf;
127bbdb7433SSean Christopherson asm volatile ("data16 mov %%cs, %0":"=m"(*(m + sizeof(unsigned long))));
128bbdb7433SSean Christopherson asm volatile ("rex64 ljmp *%0"::"m"(*m));
129bbdb7433SSean Christopherson res = 0;
130bbdb7433SSean Christopherson jmpf:
131bbdb7433SSean Christopherson report(res, "ljmp");
132bbdb7433SSean Christopherson }
133bbdb7433SSean Christopherson
test_xchg(void * mem)134bbdb7433SSean Christopherson static void test_xchg(void *mem)
135bbdb7433SSean Christopherson {
136bbdb7433SSean Christopherson unsigned long *memq = mem;
137bbdb7433SSean Christopherson unsigned long rax;
138bbdb7433SSean Christopherson
139bbdb7433SSean Christopherson asm volatile("mov $0x123456789abcdef, %%rax\n\t"
140bbdb7433SSean Christopherson "mov %%rax, (%[memq])\n\t"
141bbdb7433SSean Christopherson "mov $0xfedcba9876543210, %%rax\n\t"
142bbdb7433SSean Christopherson "xchg %%al, (%[memq])\n\t"
143bbdb7433SSean Christopherson "mov %%rax, %[rax]\n\t"
144bbdb7433SSean Christopherson : [rax]"=r"(rax)
145bbdb7433SSean Christopherson : [memq]"r"(memq)
146bbdb7433SSean Christopherson : "memory", "rax");
147bbdb7433SSean Christopherson report(rax == 0xfedcba98765432ef && *memq == 0x123456789abcd10,
148bbdb7433SSean Christopherson "xchg reg, r/m (1)");
149bbdb7433SSean Christopherson
150bbdb7433SSean Christopherson asm volatile("mov $0x123456789abcdef, %%rax\n\t"
151bbdb7433SSean Christopherson "mov %%rax, (%[memq])\n\t"
152bbdb7433SSean Christopherson "mov $0xfedcba9876543210, %%rax\n\t"
153bbdb7433SSean Christopherson "xchg %%ax, (%[memq])\n\t"
154bbdb7433SSean Christopherson "mov %%rax, %[rax]\n\t"
155bbdb7433SSean Christopherson : [rax]"=r"(rax)
156bbdb7433SSean Christopherson : [memq]"r"(memq)
157bbdb7433SSean Christopherson : "memory", "rax");
158bbdb7433SSean Christopherson report(rax == 0xfedcba987654cdef && *memq == 0x123456789ab3210,
159bbdb7433SSean Christopherson "xchg reg, r/m (2)");
160bbdb7433SSean Christopherson
161bbdb7433SSean Christopherson asm volatile("mov $0x123456789abcdef, %%rax\n\t"
162bbdb7433SSean Christopherson "mov %%rax, (%[memq])\n\t"
163bbdb7433SSean Christopherson "mov $0xfedcba9876543210, %%rax\n\t"
164bbdb7433SSean Christopherson "xchg %%eax, (%[memq])\n\t"
165bbdb7433SSean Christopherson "mov %%rax, %[rax]\n\t"
166bbdb7433SSean Christopherson : [rax]"=r"(rax)
167bbdb7433SSean Christopherson : [memq]"r"(memq)
168bbdb7433SSean Christopherson : "memory", "rax");
169bbdb7433SSean Christopherson report(rax == 0x89abcdef && *memq == 0x123456776543210,
170bbdb7433SSean Christopherson "xchg reg, r/m (3)");
171bbdb7433SSean Christopherson
172bbdb7433SSean Christopherson asm volatile("mov $0x123456789abcdef, %%rax\n\t"
173bbdb7433SSean Christopherson "mov %%rax, (%[memq])\n\t"
174bbdb7433SSean Christopherson "mov $0xfedcba9876543210, %%rax\n\t"
175bbdb7433SSean Christopherson "xchg %%rax, (%[memq])\n\t"
176bbdb7433SSean Christopherson "mov %%rax, %[rax]\n\t"
177bbdb7433SSean Christopherson : [rax]"=r"(rax)
178bbdb7433SSean Christopherson : [memq]"r"(memq)
179bbdb7433SSean Christopherson : "memory", "rax");
180bbdb7433SSean Christopherson report(rax == 0x123456789abcdef && *memq == 0xfedcba9876543210,
181bbdb7433SSean Christopherson "xchg reg, r/m (4)");
182bbdb7433SSean Christopherson }
183bbdb7433SSean Christopherson
test_xadd(void * mem)184bbdb7433SSean Christopherson static void test_xadd(void *mem)
185bbdb7433SSean Christopherson {
186bbdb7433SSean Christopherson unsigned long *memq = mem;
187bbdb7433SSean Christopherson unsigned long rax;
188bbdb7433SSean Christopherson
189bbdb7433SSean Christopherson asm volatile("mov $0x123456789abcdef, %%rax\n\t"
190bbdb7433SSean Christopherson "mov %%rax, (%[memq])\n\t"
191bbdb7433SSean Christopherson "mov $0xfedcba9876543210, %%rax\n\t"
192bbdb7433SSean Christopherson "xadd %%al, (%[memq])\n\t"
193bbdb7433SSean Christopherson "mov %%rax, %[rax]\n\t"
194bbdb7433SSean Christopherson : [rax]"=r"(rax)
195bbdb7433SSean Christopherson : [memq]"r"(memq)
196bbdb7433SSean Christopherson : "memory", "rax");
197bbdb7433SSean Christopherson report(rax == 0xfedcba98765432ef && *memq == 0x123456789abcdff,
198bbdb7433SSean Christopherson "xadd reg, r/m (1)");
199bbdb7433SSean Christopherson
200bbdb7433SSean Christopherson asm volatile("mov $0x123456789abcdef, %%rax\n\t"
201bbdb7433SSean Christopherson "mov %%rax, (%[memq])\n\t"
202bbdb7433SSean Christopherson "mov $0xfedcba9876543210, %%rax\n\t"
203bbdb7433SSean Christopherson "xadd %%ax, (%[memq])\n\t"
204bbdb7433SSean Christopherson "mov %%rax, %[rax]\n\t"
205bbdb7433SSean Christopherson : [rax]"=r"(rax)
206bbdb7433SSean Christopherson : [memq]"r"(memq)
207bbdb7433SSean Christopherson : "memory", "rax");
208bbdb7433SSean Christopherson report(rax == 0xfedcba987654cdef && *memq == 0x123456789abffff,
209bbdb7433SSean Christopherson "xadd reg, r/m (2)");
210bbdb7433SSean Christopherson
211bbdb7433SSean Christopherson asm volatile("mov $0x123456789abcdef, %%rax\n\t"
212bbdb7433SSean Christopherson "mov %%rax, (%[memq])\n\t"
213bbdb7433SSean Christopherson "mov $0xfedcba9876543210, %%rax\n\t"
214bbdb7433SSean Christopherson "xadd %%eax, (%[memq])\n\t"
215bbdb7433SSean Christopherson "mov %%rax, %[rax]\n\t"
216bbdb7433SSean Christopherson : [rax]"=r"(rax)
217bbdb7433SSean Christopherson : [memq]"r"(memq)
218bbdb7433SSean Christopherson : "memory", "rax");
219bbdb7433SSean Christopherson report(rax == 0x89abcdef && *memq == 0x1234567ffffffff,
220bbdb7433SSean Christopherson "xadd reg, r/m (3)");
221bbdb7433SSean Christopherson
222bbdb7433SSean Christopherson asm volatile("mov $0x123456789abcdef, %%rax\n\t"
223bbdb7433SSean Christopherson "mov %%rax, (%[memq])\n\t"
224bbdb7433SSean Christopherson "mov $0xfedcba9876543210, %%rax\n\t"
225bbdb7433SSean Christopherson "xadd %%rax, (%[memq])\n\t"
226bbdb7433SSean Christopherson "mov %%rax, %[rax]\n\t"
227bbdb7433SSean Christopherson : [rax]"=r"(rax)
228bbdb7433SSean Christopherson : [memq]"r"(memq)
229bbdb7433SSean Christopherson : "memory", "rax");
230bbdb7433SSean Christopherson report(rax == 0x123456789abcdef && *memq == 0xffffffffffffffff,
231bbdb7433SSean Christopherson "xadd reg, r/m (4)");
232bbdb7433SSean Christopherson }
233bbdb7433SSean Christopherson
test_muldiv(long * mem)234bbdb7433SSean Christopherson static void test_muldiv(long *mem)
235bbdb7433SSean Christopherson {
236bbdb7433SSean Christopherson long a, d, aa, dd;
237bbdb7433SSean Christopherson u8 ex = 1;
238bbdb7433SSean Christopherson
239bbdb7433SSean Christopherson *mem = 0; a = 1; d = 2;
240bbdb7433SSean Christopherson asm (ASM_TRY("1f") "divq %3; movb $0, %2; 1:"
241bbdb7433SSean Christopherson : "+a"(a), "+d"(d), "+q"(ex) : "m"(*mem));
242bbdb7433SSean Christopherson report(a == 1 && d == 2 && ex, "divq (fault)");
243bbdb7433SSean Christopherson
244bbdb7433SSean Christopherson *mem = 987654321098765UL; a = 123456789012345UL; d = 123456789012345UL;
245bbdb7433SSean Christopherson asm (ASM_TRY("1f") "divq %3; movb $0, %2; 1:"
246bbdb7433SSean Christopherson : "+a"(a), "+d"(d), "+q"(ex) : "m"(*mem));
247bbdb7433SSean Christopherson report(a == 0x1ffffffb1b963b33ul && d == 0x273ba4384ede2ul && !ex, "divq (1)");
248bbdb7433SSean Christopherson
249bbdb7433SSean Christopherson aa = 0x1111111111111111; dd = 0x2222222222222222;
250bbdb7433SSean Christopherson *mem = 0x3333333333333333; a = aa; d = dd;
251bbdb7433SSean Christopherson asm("mulb %2" : "+a"(a), "+d"(d) : "m"(*mem));
252bbdb7433SSean Christopherson report(a == 0x1111111111110363 && d == dd, "mulb mem");
253bbdb7433SSean Christopherson *mem = 0x3333333333333333; a = aa; d = dd;
254bbdb7433SSean Christopherson asm("mulw %2" : "+a"(a), "+d"(d) : "m"(*mem));
255bbdb7433SSean Christopherson report(a == 0x111111111111c963 && d == 0x2222222222220369, "mulw mem");
256bbdb7433SSean Christopherson *mem = 0x3333333333333333; a = aa; d = dd;
257bbdb7433SSean Christopherson asm("mull %2" : "+a"(a), "+d"(d) : "m"(*mem));
258bbdb7433SSean Christopherson report(a == 0x962fc963 && d == 0x369d036, "mull mem");
259bbdb7433SSean Christopherson *mem = 0x3333333333333333; a = aa; d = dd;
260bbdb7433SSean Christopherson asm("mulq %2" : "+a"(a), "+d"(d) : "m"(*mem));
261bbdb7433SSean Christopherson report(a == 0x2fc962fc962fc963 && d == 0x369d0369d0369d0, "mulq mem");
262bbdb7433SSean Christopherson }
263bbdb7433SSean Christopherson
test_mmx(uint64_t * mem)264bbdb7433SSean Christopherson static void test_mmx(uint64_t *mem)
265bbdb7433SSean Christopherson {
266bbdb7433SSean Christopherson uint64_t v;
267bbdb7433SSean Christopherson
268bbdb7433SSean Christopherson write_cr0(read_cr0() & ~6); /* EM, TS */
269bbdb7433SSean Christopherson asm volatile("fninit");
270bbdb7433SSean Christopherson v = 0x0102030405060708ULL;
271bbdb7433SSean Christopherson asm("movq %1, %0" : "=m"(*mem) : "y"(v));
272bbdb7433SSean Christopherson report(v == *mem, "movq (mmx, read)");
273bbdb7433SSean Christopherson *mem = 0x8070605040302010ull;
274bbdb7433SSean Christopherson asm("movq %1, %0" : "=y"(v) : "m"(*mem));
275bbdb7433SSean Christopherson report(v == *mem, "movq (mmx, write)");
276bbdb7433SSean Christopherson }
277bbdb7433SSean Christopherson
test_rip_relative(unsigned * mem,char * insn_ram)278bbdb7433SSean Christopherson static void test_rip_relative(unsigned *mem, char *insn_ram)
279bbdb7433SSean Christopherson {
280bbdb7433SSean Christopherson /* movb $1, mem+2(%rip) */
281bbdb7433SSean Christopherson insn_ram[0] = 0xc6;
282bbdb7433SSean Christopherson insn_ram[1] = 0x05;
283bbdb7433SSean Christopherson *(unsigned *)&insn_ram[2] = 2 + (char *)mem - (insn_ram + 7);
284bbdb7433SSean Christopherson insn_ram[6] = 0x01;
285bbdb7433SSean Christopherson /* ret */
286bbdb7433SSean Christopherson insn_ram[7] = 0xc3;
287bbdb7433SSean Christopherson
288bbdb7433SSean Christopherson *mem = 0;
289bbdb7433SSean Christopherson asm("callq *%1" : "+m"(*mem) : "r"(insn_ram));
290bbdb7433SSean Christopherson report(*mem == 0x10000, "movb $imm, 0(%%rip)");
291bbdb7433SSean Christopherson }
292bbdb7433SSean Christopherson
test_cmov(u32 * mem)293bbdb7433SSean Christopherson static void test_cmov(u32 *mem)
294bbdb7433SSean Christopherson {
295bbdb7433SSean Christopherson u64 val;
296bbdb7433SSean Christopherson *mem = 0xabcdef12u;
297bbdb7433SSean Christopherson asm ("movq $0x1234567812345678, %%rax\n\t"
298bbdb7433SSean Christopherson "cmpl %%eax, %%eax\n\t"
299bbdb7433SSean Christopherson "cmovnel (%[mem]), %%eax\n\t"
300bbdb7433SSean Christopherson "movq %%rax, %[val]\n\t"
301bbdb7433SSean Christopherson : [val]"=r"(val) : [mem]"r"(mem) : "%rax", "cc");
302bbdb7433SSean Christopherson report(val == 0x12345678ul, "cmovnel");
303bbdb7433SSean Christopherson }
304bbdb7433SSean Christopherson
305bbdb7433SSean Christopherson
test_mmx_movq_mf(uint64_t * mem)306bbdb7433SSean Christopherson static void test_mmx_movq_mf(uint64_t *mem)
307bbdb7433SSean Christopherson {
308bbdb7433SSean Christopherson uint16_t fcw = 0; /* all exceptions unmasked */
30999bfe7e5SMathias Krause uint64_t val;
310bbdb7433SSean Christopherson
31199bfe7e5SMathias Krause write_cr0(read_cr0() & ~(X86_CR0_TS | X86_CR0_EM));
31299bfe7e5SMathias Krause asm volatile("fninit\n\t"
31399bfe7e5SMathias Krause "fldcw %[fcw]\n\t"
31499bfe7e5SMathias Krause "fldz\n\t"
31599bfe7e5SMathias Krause "fldz\n\t"
31699bfe7e5SMathias Krause /* generate exception (0.0 / 0.0) */
31799bfe7e5SMathias Krause "fdivp\n\t"
31899bfe7e5SMathias Krause /* trigger #MF */
31999bfe7e5SMathias Krause ASM_TRY_FEP("1f") "movq %%mm0, %[val]\n\t"
320bbdb7433SSean Christopherson /* exit MMX mode */
32199bfe7e5SMathias Krause "1: fnclex\n\t"
32299bfe7e5SMathias Krause "emms\n\t"
32399bfe7e5SMathias Krause : [val]"=m"(val)
32499bfe7e5SMathias Krause : [fcw]"m"(fcw));
32599bfe7e5SMathias Krause report(exception_vector() == MF_VECTOR, "movq mmx generates #MF");
326bbdb7433SSean Christopherson }
327bbdb7433SSean Christopherson
test_jmp_noncanonical(uint64_t * mem)328bbdb7433SSean Christopherson static void test_jmp_noncanonical(uint64_t *mem)
329bbdb7433SSean Christopherson {
33083380d69SMathias Krause *mem = NONCANONICAL;
33183380d69SMathias Krause asm volatile (ASM_TRY("1f") "jmp *%0; 1:" : : "m"(*mem));
33283380d69SMathias Krause report(exception_vector() == GP_VECTOR,
33383380d69SMathias Krause "jump to non-canonical address");
334bbdb7433SSean Christopherson }
335bbdb7433SSean Christopherson
test_reg_noncanonical(void)336*2b83c6c0SMathias Krause static void test_reg_noncanonical(void)
337*2b83c6c0SMathias Krause {
338*2b83c6c0SMathias Krause /* RAX based, should #GP(0) */
339*2b83c6c0SMathias Krause asm volatile(ASM_TRY("1f") "orq $0, (%[noncanonical]); 1:"
340*2b83c6c0SMathias Krause : : [noncanonical]"a"(NONCANONICAL));
341*2b83c6c0SMathias Krause report(exception_vector() == GP_VECTOR && exception_error_code() == 0,
342*2b83c6c0SMathias Krause "non-canonical memory access, should %s(0), got %s(%u)",
343*2b83c6c0SMathias Krause exception_mnemonic(GP_VECTOR),
344*2b83c6c0SMathias Krause exception_mnemonic(exception_vector()), exception_error_code());
345*2b83c6c0SMathias Krause
346*2b83c6c0SMathias Krause /* RSP based, should #SS(0) */
347*2b83c6c0SMathias Krause asm volatile(ASM_TRY("1f") "orq $0, (%%rsp,%[noncanonical],1); 1:"
348*2b83c6c0SMathias Krause : : [noncanonical]"r"(NONCANONICAL));
349*2b83c6c0SMathias Krause report(exception_vector() == SS_VECTOR && exception_error_code() == 0,
350*2b83c6c0SMathias Krause "non-canonical rsp-based access, should %s(0), got %s(%u)",
351*2b83c6c0SMathias Krause exception_mnemonic(SS_VECTOR),
352*2b83c6c0SMathias Krause exception_mnemonic(exception_vector()), exception_error_code());
353*2b83c6c0SMathias Krause
354*2b83c6c0SMathias Krause /* RBP based, should #SS(0) */
355*2b83c6c0SMathias Krause asm volatile(ASM_TRY("1f") "orq $0, (%%rbp,%[noncanonical],1); 1:"
356*2b83c6c0SMathias Krause : : [noncanonical]"r"(NONCANONICAL));
357*2b83c6c0SMathias Krause report(exception_vector() == SS_VECTOR && exception_error_code() == 0,
358*2b83c6c0SMathias Krause "non-canonical rbp-based access, should %s(0), got %s(%u)",
359*2b83c6c0SMathias Krause exception_mnemonic(SS_VECTOR),
360*2b83c6c0SMathias Krause exception_mnemonic(exception_vector()), exception_error_code());
361*2b83c6c0SMathias Krause }
362*2b83c6c0SMathias Krause
test_movabs(uint64_t * mem)363bbdb7433SSean Christopherson static void test_movabs(uint64_t *mem)
364bbdb7433SSean Christopherson {
365bbdb7433SSean Christopherson /* mov $0x9090909090909090, %rcx */
366bbdb7433SSean Christopherson unsigned long rcx;
367bbdb7433SSean Christopherson asm(KVM_FEP "mov $0x9090909090909090, %0" : "=c" (rcx) : "0" (0));
368bbdb7433SSean Christopherson report(rcx == 0x9090909090909090, "64-bit mov imm2");
369bbdb7433SSean Christopherson }
370bbdb7433SSean Christopherson
load_dpl0_seg(void)37105b0460eSMichal Luczaj static void load_dpl0_seg(void)
37205b0460eSMichal Luczaj {
37305b0460eSMichal Luczaj asm volatile(KVM_FEP "mov %0, %%fs" :: "r" (KERNEL_CS)); /* RPL=0 */
37405b0460eSMichal Luczaj }
37505b0460eSMichal Luczaj
test_user_load_dpl0_seg(void)37605b0460eSMichal Luczaj static void test_user_load_dpl0_seg(void)
37705b0460eSMichal Luczaj {
37805b0460eSMichal Luczaj bool raised_vector;
37905b0460eSMichal Luczaj
38005b0460eSMichal Luczaj run_in_user((usermode_func)load_dpl0_seg, GP_VECTOR, 0, 0, 0, 0,
38105b0460eSMichal Luczaj &raised_vector);
38205b0460eSMichal Luczaj
38305b0460eSMichal Luczaj report(raised_vector, "Wanted #GP on CPL=3 DPL=0 segment load");
38405b0460eSMichal Luczaj }
38505b0460eSMichal Luczaj
test_push16(uint64_t * mem)386bbdb7433SSean Christopherson static void test_push16(uint64_t *mem)
387bbdb7433SSean Christopherson {
388bbdb7433SSean Christopherson uint64_t rsp1, rsp2;
389bbdb7433SSean Christopherson uint16_t r;
390bbdb7433SSean Christopherson
391bbdb7433SSean Christopherson asm volatile ( "movq %%rsp, %[rsp1]\n\t"
392bbdb7433SSean Christopherson "pushw %[v]\n\t"
393bbdb7433SSean Christopherson "popw %[r]\n\t"
394bbdb7433SSean Christopherson "movq %%rsp, %[rsp2]\n\t"
395bbdb7433SSean Christopherson "movq %[rsp1], %%rsp\n\t" :
396bbdb7433SSean Christopherson [rsp1]"=r"(rsp1), [rsp2]"=r"(rsp2), [r]"=r"(r)
397bbdb7433SSean Christopherson : [v]"m"(*mem) : "memory");
398bbdb7433SSean Christopherson report(rsp1 == rsp2, "push16");
399bbdb7433SSean Christopherson }
400bbdb7433SSean Christopherson
test_sreg(volatile uint16_t * mem)401bbdb7433SSean Christopherson static void test_sreg(volatile uint16_t *mem)
402bbdb7433SSean Christopherson {
403bbdb7433SSean Christopherson u16 ss = read_ss();
404bbdb7433SSean Christopherson
405bbdb7433SSean Christopherson // check for null segment load
406bbdb7433SSean Christopherson *mem = 0;
407bbdb7433SSean Christopherson asm volatile("mov %0, %%ss" : : "m"(*mem));
408bbdb7433SSean Christopherson report(read_ss() == 0, "mov null, %%ss");
409bbdb7433SSean Christopherson
410bbdb7433SSean Christopherson // check for exception when ss.rpl != cpl on null segment load
411bbdb7433SSean Christopherson *mem = 3;
412369432acSMathias Krause asm volatile(ASM_TRY("1f") "mov %0, %%ss; 1:" : : "m"(*mem));
413369432acSMathias Krause report(exception_vector() == GP_VECTOR &&
414369432acSMathias Krause exception_error_code() == 0 && read_ss() == 0,
415bbdb7433SSean Christopherson "mov null, %%ss (with ss.rpl != cpl)");
416369432acSMathias Krause
417cb0fabbbSMathias Krause // check for exception when ss.rpl != cpl on non-null segment load
418cb0fabbbSMathias Krause *mem = KERNEL_DS | 3;
419cb0fabbbSMathias Krause asm volatile(ASM_TRY("1f") "mov %0, %%ss; 1:" : : "m"(*mem));
420cb0fabbbSMathias Krause report(exception_vector() == GP_VECTOR &&
421cb0fabbbSMathias Krause exception_error_code() == KERNEL_DS && read_ss() == 0,
422cb0fabbbSMathias Krause "mov non-null, %%ss (with ss.rpl != cpl)");
423cb0fabbbSMathias Krause
424bbdb7433SSean Christopherson write_ss(ss);
425bbdb7433SSean Christopherson }
426bbdb7433SSean Christopherson
usr_gs_mov(void)427bbdb7433SSean Christopherson static uint64_t usr_gs_mov(void)
428bbdb7433SSean Christopherson {
429bbdb7433SSean Christopherson static uint64_t dummy = MAGIC_NUM;
430bbdb7433SSean Christopherson uint64_t dummy_ptr = (uint64_t)&dummy;
431bbdb7433SSean Christopherson uint64_t ret;
432bbdb7433SSean Christopherson
433bbdb7433SSean Christopherson dummy_ptr -= GS_BASE;
4344a7802f3SMathias Krause asm volatile("mov %%gs:(%1), %0" : "=r"(ret) : "r"(dummy_ptr));
435bbdb7433SSean Christopherson
436bbdb7433SSean Christopherson return ret;
437bbdb7433SSean Christopherson }
438bbdb7433SSean Christopherson
test_iret(void)439bbdb7433SSean Christopherson static void test_iret(void)
440bbdb7433SSean Christopherson {
441bbdb7433SSean Christopherson uint64_t val;
442bbdb7433SSean Christopherson bool raised_vector;
443bbdb7433SSean Christopherson
444bbdb7433SSean Christopherson /* Update GS base to 4MiB */
445bbdb7433SSean Christopherson wrmsr(MSR_GS_BASE, GS_BASE);
446bbdb7433SSean Christopherson
447bbdb7433SSean Christopherson /*
448bbdb7433SSean Christopherson * Per the SDM, jumping to user mode via `iret`, which is returning to
449bbdb7433SSean Christopherson * outer privilege level, for segment registers (ES, FS, GS, and DS)
450bbdb7433SSean Christopherson * if the check fails, the segment selector becomes null.
451bbdb7433SSean Christopherson *
452bbdb7433SSean Christopherson * In our test case, GS becomes null.
453bbdb7433SSean Christopherson */
454bbdb7433SSean Christopherson val = run_in_user((usermode_func)usr_gs_mov, GP_VECTOR,
455bbdb7433SSean Christopherson 0, 0, 0, 0, &raised_vector);
456bbdb7433SSean Christopherson
457bbdb7433SSean Christopherson report(val == MAGIC_NUM, "Test ret/iret with a nullified segment");
458bbdb7433SSean Christopherson }
459bbdb7433SSean Christopherson
test_emulator_64(void * mem)460bbdb7433SSean Christopherson static void test_emulator_64(void *mem)
461bbdb7433SSean Christopherson {
462bbdb7433SSean Christopherson void *insn_page = alloc_page();
463bbdb7433SSean Christopherson void *insn_ram = vmap(virt_to_phys(insn_page), 4096);
464bbdb7433SSean Christopherson
465bbdb7433SSean Christopherson test_push(mem);
466bbdb7433SSean Christopherson test_pop(mem);
467bbdb7433SSean Christopherson
468bbdb7433SSean Christopherson test_xchg(mem);
469bbdb7433SSean Christopherson test_xadd(mem);
470bbdb7433SSean Christopherson
471bbdb7433SSean Christopherson test_cr8();
472bbdb7433SSean Christopherson
473bbdb7433SSean Christopherson test_ljmp(mem);
474bbdb7433SSean Christopherson test_muldiv(mem);
475bbdb7433SSean Christopherson test_mmx(mem);
476bbdb7433SSean Christopherson test_rip_relative(mem, insn_ram);
477bbdb7433SSean Christopherson test_iret();
478bbdb7433SSean Christopherson test_sreg(mem);
479bbdb7433SSean Christopherson test_cmov(mem);
480bbdb7433SSean Christopherson
481bbdb7433SSean Christopherson if (is_fep_available()) {
482bbdb7433SSean Christopherson test_mmx_movq_mf(mem);
483bbdb7433SSean Christopherson test_movabs(mem);
48405b0460eSMichal Luczaj test_user_load_dpl0_seg();
485bbdb7433SSean Christopherson }
486bbdb7433SSean Christopherson
487bbdb7433SSean Christopherson test_push16(mem);
488bbdb7433SSean Christopherson
489*2b83c6c0SMathias Krause test_reg_noncanonical();
490bbdb7433SSean Christopherson test_jmp_noncanonical(mem);
491bbdb7433SSean Christopherson }
492