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