| #include <stdlib.h> |
| #include <stdio.h> |
| |
| typedef unsigned int UInt; |
| typedef unsigned long long int ULong; |
| |
| void do_cmpxchg8b ( /*OUT*/ |
| ULong* rdxOut, ULong* raxOut, |
| ULong* memHiOut, ULong* memLoOut, |
| ULong* zOut, |
| /*IN*/ |
| ULong rdxIn, ULong raxIn, |
| ULong memHiIn, ULong memLoIn, |
| ULong rcxIn, ULong rbxIn ) |
| { |
| UInt mem[2]; |
| ULong block[6]; |
| mem[0] = (UInt)memLoIn; |
| mem[1] = (UInt)memHiIn; |
| block[0] = rdxIn; |
| block[1] = raxIn; |
| block[2] = rcxIn; |
| block[3] = rbxIn; |
| block[4] = (ULong)&mem[0]; |
| block[5] = ~(0ULL); |
| __asm__ __volatile__( |
| "movq %0,%%r11\n" |
| "\tmovq 0(%%r11),%%rdx\n" |
| "\tmovq 8(%%r11),%%rax\n" |
| "\tmovq 16(%%r11),%%rcx\n" |
| "\tmovq 24(%%r11),%%rbx\n" |
| "\tmovq 32(%%r11),%%r10\n" |
| "\tlock cmpxchg8b (%%r10)\n" |
| "\tmovabsq $0,%%r10\n" |
| "\tsetz %%r10b\n" |
| "\tmovq %%r10,40(%%r11)\n" |
| "\tmovq %%rdx,0(%%r11)\n" |
| "\tmovq %%rax,8(%%r11)\n" |
| : /*out*/ |
| : /*in*/ "r"(&block[0]) |
| : /*trash*/ "%r11", "%r10", "%rax", "%rbx", "%rcx", "%rdx", |
| "cc", "memory" ); |
| *rdxOut = block[0]; |
| *raxOut = block[1]; |
| *memLoOut = (ULong)mem[0]; |
| *memHiOut = (ULong)mem[1]; |
| *zOut = block[5]; |
| } |
| |
| void try8b ( ULong d, ULong a, ULong mHi, ULong mLo, ULong c, ULong b ) |
| { |
| ULong dd, aa, mmHi, mmLo, zz; |
| do_cmpxchg8b( &dd, &aa, &mmHi, &mmLo, &zz, |
| d,a,mHi,mLo,c,b); |
| printf(" Q d:a=%llx:%llx mem=%llx:%llx c:b=%llx:%llx " |
| "-> z=%lld d:a=%llx:%llx mem=%llx:%llx\n", |
| d,a, mHi,mLo, c,b, zz, dd,aa, mmHi,mmLo ); |
| } |
| |
| void do_cmpxchg16b ( /*OUT*/ |
| ULong* rdxOut, ULong* raxOut, |
| ULong* memHiOut, ULong* memLoOut, |
| ULong* zOut, |
| /*IN*/ |
| ULong rdxIn, ULong raxIn, |
| ULong memHiIn, ULong memLoIn, |
| ULong rcxIn, ULong rbxIn ) |
| { |
| ULong mem[2] __attribute__((aligned(16))); |
| ULong block[6]; |
| mem[0] = memLoIn; |
| mem[1] = memHiIn; |
| block[0] = rdxIn; |
| block[1] = raxIn; |
| block[2] = rcxIn; |
| block[3] = rbxIn; |
| block[4] = (ULong)&mem[0]; |
| block[5] = ~(0ULL); |
| __asm__ __volatile__( |
| "movq %0,%%r11\n" |
| "\tmovq 0(%%r11),%%rdx\n" |
| "\tmovq 8(%%r11),%%rax\n" |
| "\tmovq 16(%%r11),%%rcx\n" |
| "\tmovq 24(%%r11),%%rbx\n" |
| "\tmovq 32(%%r11),%%r10\n" |
| "\t.byte 0xf0, 0x49, 0x0f, 0xc7, 0x0a\n" /* lock cmpxchg16b (%%r10) */ |
| "\tmovabsq $0,%%r10\n" |
| "\tsetz %%r10b\n" |
| "\tmovq %%r10,40(%%r11)\n" |
| "\tmovq %%rdx,0(%%r11)\n" |
| "\tmovq %%rax,8(%%r11)\n" |
| : /*out*/ |
| : /*in*/ "r"(&block[0]) |
| : /*trash*/ "%r11", "%r10", "%rax", "%rbx", "%rcx", "%rdx", |
| "cc", "memory" ); |
| *rdxOut = block[0]; |
| *raxOut = block[1]; |
| *memLoOut = mem[0]; |
| *memHiOut = mem[1]; |
| *zOut = block[5]; |
| } |
| |
| void try16b ( ULong d, ULong a, ULong mHi, ULong mLo, ULong c, ULong b ) |
| { |
| ULong dd, aa, mmHi, mmLo, zz; |
| do_cmpxchg16b( &dd, &aa, &mmHi, &mmLo, &zz, |
| d,a,mHi,mLo,c,b); |
| printf("QQ d:a=%llx:%llx mem=%llx:%llx c:b=%llx:%llx " |
| "-> z=%lld d:a=%llx:%llx mem=%llx:%llx\n", |
| d,a, mHi,mLo, c,b, zz, dd,aa, mmHi,mmLo ); |
| } |
| |
| int main(void) |
| { |
| ULong z = 0xDEADBEEF00000000ULL; |
| |
| try8b( 0,1, 5,4, 3,2 ); |
| try8b( 0,1, 0,1, 3,2 ); |
| |
| try8b( 0,1, 0,4, 3,2 ); |
| try8b( 0,1, 0,0, 3,2 ); |
| |
| try8b( 0,1, 5,0, 3,2 ); |
| try8b( 0,1, 1,1, 3,2 ); |
| |
| try8b( 0+z,1+z, 5+z,4+z, 3+z,2+z ); |
| try8b( 0+z,1+z, 0+z,1+z, 3+z,2+z ); |
| |
| try8b( 0+z,1+z, 0+z,4+z, 3+z,2+z ); |
| try8b( 0+z,1+z, 0+z,0+z, 3+z,2+z ); |
| |
| try8b( 0+z,1+z, 5+z,0+z, 3+z,2+z ); |
| try8b( 0+z,1+z, 1+z,1+z, 3+z,2+z ); |
| |
| try16b( 0,1, 5,4, 3,2 ); |
| try16b( 0,1, 0,1, 3,2 ); |
| |
| try16b( 0,1, 0,4, 3,2 ); |
| try16b( 0,1, 0,0, 3,2 ); |
| |
| try16b( 0,1, 5,0, 3,2 ); |
| try16b( 0,1, 1,1, 3,2 ); |
| |
| try16b( 0+z,1+z, 5+z,4+z, 3+z,2+z ); |
| try16b( 0+z,1+z, 0+z,1+z, 3+z,2+z ); |
| |
| try16b( 0+z,1+z, 0+z,4+z, 3+z,2+z ); |
| try16b( 0+z,1+z, 0+z,0+z, 3+z,2+z ); |
| |
| try16b( 0+z,1+z, 5+z,0+z, 3+z,2+z ); |
| try16b( 0+z,1+z, 1+z,1+z, 3+z,2+z ); |
| |
| return 0; |
| } |
| |