1 #include "ioram.h" 2 #include "vm.h" 3 #include "libcflat.h" 4 5 #define memset __builtin_memset 6 #define TESTDEV_IO_PORT 0xe0 7 8 int fails, tests; 9 10 void report(const char *name, int result) 11 { 12 ++tests; 13 if (result) 14 printf("PASS: %s\n", name); 15 else { 16 printf("FAIL: %s\n", name); 17 ++fails; 18 } 19 } 20 21 static char st1[] = "abcdefghijklmnop"; 22 23 void test_stringio() 24 { 25 unsigned char r = 0; 26 asm volatile("cld \n\t" 27 "movw %0, %%dx \n\t" 28 "rep outsb \n\t" 29 : : "i"((short)TESTDEV_IO_PORT), 30 "S"(st1), "c"(sizeof(st1) - 1)); 31 asm volatile("inb %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT)); 32 report("outsb up", r == st1[sizeof(st1) - 2]); /* last char */ 33 34 asm volatile("std \n\t" 35 "movw %0, %%dx \n\t" 36 "rep outsb \n\t" 37 : : "i"((short)TESTDEV_IO_PORT), 38 "S"(st1 + sizeof(st1) - 2), "c"(sizeof(st1) - 1)); 39 asm volatile("cld \n\t" : : ); 40 asm volatile("in %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT)); 41 report("outsb down", r == st1[0]); 42 } 43 44 void test_cmps_one(unsigned char *m1, unsigned char *m3) 45 { 46 void *rsi, *rdi; 47 long rcx, tmp; 48 49 rsi = m1; rdi = m3; rcx = 30; 50 asm volatile("xor %[tmp], %[tmp] \n\t" 51 "repe/cmpsb" 52 : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) 53 : : "cc"); 54 report("repe/cmpsb (1)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30); 55 56 rsi = m1; rdi = m3; rcx = 15; 57 asm volatile("xor %[tmp], %[tmp] \n\t" 58 "repe/cmpsw" 59 : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) 60 : : "cc"); 61 report("repe/cmpsw (1)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30); 62 63 rsi = m1; rdi = m3; rcx = 7; 64 asm volatile("xor %[tmp], %[tmp] \n\t" 65 "repe/cmpsl" 66 : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) 67 : : "cc"); 68 report("repe/cmpll (1)", rcx == 0 && rsi == m1 + 28 && rdi == m3 + 28); 69 70 rsi = m1; rdi = m3; rcx = 4; 71 asm volatile("xor %[tmp], %[tmp] \n\t" 72 "repe/cmpsq" 73 : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) 74 : : "cc"); 75 report("repe/cmpsq (1)", rcx == 0 && rsi == m1 + 32 && rdi == m3 + 32); 76 77 rsi = m1; rdi = m3; rcx = 130; 78 asm volatile("xor %[tmp], %[tmp] \n\t" 79 "repe/cmpsb" 80 : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) 81 : : "cc"); 82 report("repe/cmpsb (2)", 83 rcx == 29 && rsi == m1 + 101 && rdi == m3 + 101); 84 85 rsi = m1; rdi = m3; rcx = 65; 86 asm volatile("xor %[tmp], %[tmp] \n\t" 87 "repe/cmpsw" 88 : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) 89 : : "cc"); 90 report("repe/cmpsw (2)", 91 rcx == 14 && rsi == m1 + 102 && rdi == m3 + 102); 92 93 rsi = m1; rdi = m3; rcx = 32; 94 asm volatile("xor %[tmp], %[tmp] \n\t" 95 "repe/cmpsl" 96 : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) 97 : : "cc"); 98 report("repe/cmpll (2)", 99 rcx == 6 && rsi == m1 + 104 && rdi == m3 + 104); 100 101 rsi = m1; rdi = m3; rcx = 16; 102 asm volatile("xor %[tmp], %[tmp] \n\t" 103 "repe/cmpsq" 104 : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) 105 : : "cc"); 106 report("repe/cmpsq (2)", 107 rcx == 3 && rsi == m1 + 104 && rdi == m3 + 104); 108 109 } 110 111 void test_cmps(void *mem) 112 { 113 unsigned char *m1 = mem, *m2 = mem + 1024; 114 unsigned char m3[1024]; 115 116 for (int i = 0; i < 100; ++i) 117 m1[i] = m2[i] = m3[i] = i; 118 for (int i = 100; i < 200; ++i) 119 m1[i] = (m3[i] = m2[i] = i) + 1; 120 test_cmps_one(m1, m3); 121 test_cmps_one(m1, m2); 122 } 123 124 void test_cr8(void) 125 { 126 unsigned long src, dst; 127 128 dst = 777; 129 src = 3; 130 asm volatile("mov %[src], %%cr8; mov %%cr8, %[dst]" 131 : [dst]"+r"(dst), [src]"+r"(src)); 132 report("mov %cr8", dst == 3 && src == 3); 133 } 134 135 void test_push(void *mem) 136 { 137 unsigned long tmp; 138 unsigned long *stack_top = mem + 4096; 139 unsigned long *new_stack_top; 140 unsigned long memw = 0x123456789abcdeful; 141 142 memset(mem, 0x55, (void *)stack_top - mem); 143 144 asm volatile("mov %%rsp, %[tmp] \n\t" 145 "mov %[stack_top], %%rsp \n\t" 146 "pushq $-7 \n\t" 147 "pushq %[reg] \n\t" 148 "pushq (%[mem]) \n\t" 149 "pushq $-7070707 \n\t" 150 "mov %%rsp, %[new_stack_top] \n\t" 151 "mov %[tmp], %%rsp" 152 : [tmp]"=&r"(tmp), [new_stack_top]"=r"(new_stack_top) 153 : [stack_top]"r"(stack_top), 154 [reg]"r"(-17l), [mem]"r"(&memw) 155 : "memory"); 156 157 report("push $imm8", stack_top[-1] == -7ul); 158 report("push %reg", stack_top[-2] == -17ul); 159 report("push mem", stack_top[-3] == 0x123456789abcdeful); 160 report("push $imm", stack_top[-4] == -7070707); 161 } 162 163 void test_pop(void *mem) 164 { 165 unsigned long tmp; 166 unsigned long *stack_top = mem + 4096; 167 unsigned long memw = 0x123456789abcdeful; 168 static unsigned long tmp2; 169 170 memset(mem, 0x55, (void *)stack_top - mem); 171 172 asm volatile("pushq %[val] \n\t" 173 "popq (%[mem])" 174 : : [val]"m"(memw), [mem]"r"(mem) : "memory"); 175 report("pop mem", *(unsigned long *)mem == memw); 176 177 memw = 7 - memw; 178 asm volatile("mov %%rsp, %[tmp] \n\t" 179 "mov %[stack_top], %%rsp \n\t" 180 "pushq %[val] \n\t" 181 "popq %[tmp2] \n\t" 182 "mov %[tmp], %%rsp" 183 : [tmp]"=&r"(tmp), [tmp2]"=m"(tmp2) 184 : [val]"r"(memw), [stack_top]"r"(stack_top) 185 : "memory"); 186 report("pop mem (2)", tmp2 == memw); 187 188 memw = 129443 - memw; 189 asm volatile("mov %%rsp, %[tmp] \n\t" 190 "mov %[stack_top], %%rsp \n\t" 191 "pushq %[val] \n\t" 192 "popq %[tmp2] \n\t" 193 "mov %[tmp], %%rsp" 194 : [tmp]"=&r"(tmp), [tmp2]"=r"(tmp2) 195 : [val]"r"(memw), [stack_top]"r"(stack_top) 196 : "memory"); 197 report("pop reg", tmp2 == memw); 198 199 asm volatile("mov %%rsp, %[tmp] \n\t" 200 "mov %[stack_top], %%rsp \n\t" 201 "push $1f \n\t" 202 "ret \n\t" 203 "2: jmp 2b \n\t" 204 "1: mov %[tmp], %%rsp" 205 : [tmp]"=&r"(tmp) : [stack_top]"r"(stack_top) 206 : "memory"); 207 report("ret", 1); 208 } 209 210 void test_ljmp(void *mem) 211 { 212 unsigned char *m = mem; 213 volatile int res = 1; 214 215 *(unsigned long**)m = &&jmpf; 216 asm volatile ("data16/mov %%cs, %0":"=m"(*(m + sizeof(unsigned long)))); 217 asm volatile ("rex64/ljmp *%0"::"m"(*m)); 218 res = 0; 219 jmpf: 220 report("ljmp", res); 221 } 222 223 void test_incdecnotneg(void *mem) 224 { 225 unsigned long *m = mem, v = 1234; 226 unsigned char *mb = mem, vb = 66; 227 228 *m = 0; 229 230 asm volatile ("incl %0":"+m"(*m)); 231 report("incl", *m == 1); 232 asm volatile ("decl %0":"+m"(*m)); 233 report("decl", *m == 0); 234 asm volatile ("incb %0":"+m"(*m)); 235 report("incb", *m == 1); 236 asm volatile ("decb %0":"+m"(*m)); 237 report("decb", *m == 0); 238 239 asm volatile ("lock incl %0":"+m"(*m)); 240 report("lock incl", *m == 1); 241 asm volatile ("lock decl %0":"+m"(*m)); 242 report("lock decl", *m == 0); 243 asm volatile ("lock incb %0":"+m"(*m)); 244 report("lock incb", *m == 1); 245 asm volatile ("lock decb %0":"+m"(*m)); 246 report("lock decb", *m == 0); 247 248 *m = v; 249 250 asm ("lock negq %0" : "+m"(*m)); v = -v; 251 report("lock negl", *m == v); 252 asm ("lock notq %0" : "+m"(*m)); v = ~v; 253 report("lock notl", *m == v); 254 255 *mb = vb; 256 257 asm ("lock negb %0" : "+m"(*mb)); vb = -vb; 258 report("lock negb", *mb == vb); 259 asm ("lock notb %0" : "+m"(*mb)); vb = ~vb; 260 report("lock notb", *mb == vb); 261 } 262 263 void test_smsw(void) 264 { 265 char mem[16]; 266 unsigned short msw, msw_orig, *pmsw; 267 int i, zero; 268 269 msw_orig = read_cr0(); 270 271 asm("smsw %0" : "=r"(msw)); 272 report("smsw (1)", msw == msw_orig); 273 274 memset(mem, 0, 16); 275 pmsw = (void *)mem; 276 asm("smsw %0" : "=m"(pmsw[4])); 277 zero = 1; 278 for (i = 0; i < 8; ++i) 279 if (i != 4 && pmsw[i]) 280 zero = 0; 281 report("smsw (2)", msw == pmsw[4] && zero); 282 } 283 284 void test_lmsw(void) 285 { 286 char mem[16]; 287 unsigned short msw, *pmsw; 288 unsigned long cr0; 289 290 cr0 = read_cr0(); 291 292 msw = cr0 ^ 8; 293 asm("lmsw %0" : : "r"(msw)); 294 printf("before %lx after %lx\n", cr0, read_cr0()); 295 report("lmsw (1)", (cr0 ^ read_cr0()) == 8); 296 297 pmsw = (void *)mem; 298 *pmsw = cr0; 299 asm("lmsw %0" : : "m"(*pmsw)); 300 printf("before %lx after %lx\n", cr0, read_cr0()); 301 report("lmsw (2)", cr0 == read_cr0()); 302 303 /* lmsw can't clear cr0.pe */ 304 msw = (cr0 & ~1ul) ^ 4; /* change EM to force trap */ 305 asm("lmsw %0" : : "r"(msw)); 306 report("lmsw (3)", (cr0 ^ read_cr0()) == 4 && (cr0 & 1)); 307 308 /* back to normal */ 309 msw = cr0; 310 asm("lmsw %0" : : "r"(msw)); 311 } 312 313 void test_xchg(void *mem) 314 { 315 unsigned long *memq = mem; 316 unsigned long rax; 317 318 asm volatile("mov $0x123456789abcdef, %%rax\n\t" 319 "mov %%rax, (%[memq])\n\t" 320 "mov $0xfedcba9876543210, %%rax\n\t" 321 "xchg %%al, (%[memq])\n\t" 322 "mov %%rax, %[rax]\n\t" 323 : [rax]"=r"(rax) 324 : [memq]"r"(memq) 325 : "memory"); 326 report("xchg reg, r/m (1)", 327 rax == 0xfedcba98765432ef && *memq == 0x123456789abcd10); 328 329 asm volatile("mov $0x123456789abcdef, %%rax\n\t" 330 "mov %%rax, (%[memq])\n\t" 331 "mov $0xfedcba9876543210, %%rax\n\t" 332 "xchg %%ax, (%[memq])\n\t" 333 "mov %%rax, %[rax]\n\t" 334 : [rax]"=r"(rax) 335 : [memq]"r"(memq) 336 : "memory"); 337 report("xchg reg, r/m (2)", 338 rax == 0xfedcba987654cdef && *memq == 0x123456789ab3210); 339 340 asm volatile("mov $0x123456789abcdef, %%rax\n\t" 341 "mov %%rax, (%[memq])\n\t" 342 "mov $0xfedcba9876543210, %%rax\n\t" 343 "xchg %%eax, (%[memq])\n\t" 344 "mov %%rax, %[rax]\n\t" 345 : [rax]"=r"(rax) 346 : [memq]"r"(memq) 347 : "memory"); 348 report("xchg reg, r/m (3)", 349 rax == 0x89abcdef && *memq == 0x123456776543210); 350 351 asm volatile("mov $0x123456789abcdef, %%rax\n\t" 352 "mov %%rax, (%[memq])\n\t" 353 "mov $0xfedcba9876543210, %%rax\n\t" 354 "xchg %%rax, (%[memq])\n\t" 355 "mov %%rax, %[rax]\n\t" 356 : [rax]"=r"(rax) 357 : [memq]"r"(memq) 358 : "memory"); 359 report("xchg reg, r/m (4)", 360 rax == 0x123456789abcdef && *memq == 0xfedcba9876543210); 361 } 362 363 int main() 364 { 365 void *mem; 366 unsigned long t1, t2; 367 368 setup_vm(); 369 mem = vmap(IORAM_BASE_PHYS, IORAM_LEN); 370 371 // test mov reg, r/m and mov r/m, reg 372 t1 = 0x123456789abcdef; 373 asm volatile("mov %[t1], (%[mem]) \n\t" 374 "mov (%[mem]), %[t2]" 375 : [t2]"=r"(t2) 376 : [t1]"r"(t1), [mem]"r"(mem) 377 : "memory"); 378 report("mov reg, r/m (1)", t2 == 0x123456789abcdef); 379 380 test_cmps(mem); 381 382 test_push(mem); 383 test_pop(mem); 384 385 test_xchg(mem); 386 387 test_cr8(); 388 389 test_smsw(); 390 test_lmsw(); 391 test_ljmp(mem); 392 test_stringio(); 393 test_incdecnotneg(mem); 394 395 printf("\nSUMMARY: %d tests, %d failures\n", tests, fails); 396 return fails ? 1 : 0; 397 } 398