Advertisement
Guest User

real CMPXCHG

a guest
Mar 22nd, 2017
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 11.01 KB | None | 0 0
  1. diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
  2. index 2d92957..21ee46c 100644
  3. --- a/xen/arch/x86/hvm/emulate.c
  4. +++ b/xen/arch/x86/hvm/emulate.c
  5. @@ -20,11 +20,75 @@
  6.  #include <asm/hvm/emulate.h>
  7.  #include <asm/hvm/hvm.h>
  8.  #include <asm/hvm/ioreq.h>
  9. +#include <asm/hvm/nestedhvm.h>
  10.  #include <asm/hvm/trace.h>
  11.  #include <asm/hvm/support.h>
  12.  #include <asm/hvm/svm/svm.h>
  13.  #include <asm/vm_event.h>
  14.  
  15. +/*
  16. + * Atomic compare and exchange.  Compare OLD with MEM, if identical,
  17. + * store NEW in MEM.  Return the initial value in MEM.  Success is
  18. + * indicated by comparing RETURN with OLD.
  19. + */
  20. +#define __raw_cmpxchg(ptr, old, new, size, lock)                \
  21. +({                                                              \
  22. +    __typeof__(*(ptr)) __ret;                                   \
  23. +    __typeof__(*(ptr)) __old = (old);                           \
  24. +    __typeof__(*(ptr)) __new = (new);                           \
  25. +    switch (size) {                                             \
  26. +    case 1:                                                     \
  27. +    {                                                           \
  28. +        volatile u8 *__ptr = (volatile u8 *)(ptr);              \
  29. +        asm volatile(lock "cmpxchgb %2,%1"                      \
  30. +                     : "=a" (__ret), "+m" (*__ptr)              \
  31. +                     : "q" (__new), "0" (__old)                 \
  32. +                     : "memory");                               \
  33. +        break;                                                  \
  34. +    }                                                           \
  35. +    case 2:                                                     \
  36. +    {                                                           \
  37. +        volatile u16 *__ptr = (volatile u16 *)(ptr);            \
  38. +        asm volatile(lock "cmpxchgw %2,%1"                      \
  39. +                     : "=a" (__ret), "+m" (*__ptr)              \
  40. +                     : "r" (__new), "0" (__old)                 \
  41. +                     : "memory");                               \
  42. +        break;                                                  \
  43. +    }                                                           \
  44. +    case 4:                                                     \
  45. +    {                                                           \
  46. +        volatile u32 *__ptr = (volatile u32 *)(ptr);            \
  47. +        asm volatile(lock "cmpxchgl %2,%1"                      \
  48. +                     : "=a" (__ret), "+m" (*__ptr)              \
  49. +                     : "r" (__new), "0" (__old)                 \
  50. +                     : "memory");                               \
  51. +        break;                                                  \
  52. +    }                                                           \
  53. +    case 8:                                                     \
  54. +    {                                                           \
  55. +        volatile u64 *__ptr = (volatile u64 *)(ptr);            \
  56. +        asm volatile(lock "cmpxchgq %2,%1"                      \
  57. +                     : "=a" (__ret), "+m" (*__ptr)              \
  58. +                     : "r" (__new), "0" (__old)                 \
  59. +                     : "memory");                               \
  60. +        break;                                                  \
  61. +    }                                                           \
  62. +    }                                                           \
  63. +    __ret;                                                      \
  64. +})
  65. +
  66. +#define __sync_cmpxchg(ptr, old, new, size)                     \
  67. +    __raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
  68. +
  69. +#define __cmpxchg_local(ptr, old, new, size)                    \
  70. +    __raw_cmpxchg((ptr), (old), (new), (size), "")
  71. +
  72. +#define sync_cmpxchg(ptr, old, new)                             \
  73. +    __sync_cmpxchg(ptr, old, new, sizeof(*(ptr)))
  74. +
  75. +#define cmpxchg_local(ptr, old, new)                            \
  76. +    __cmpxchg_local(ptr, old, new, sizeof(*(ptr)))
  77. +
  78.  static void hvmtrace_io_assist(const ioreq_t *p)
  79.  {
  80.      unsigned int size, event;
  81. @@ -992,6 +1056,7 @@ static int hvmemul_cmpxchg_discard(
  82.      void *p_old,
  83.      void *p_new,
  84.      unsigned int bytes,
  85. +    bool lock,
  86.      struct x86_emulate_ctxt *ctxt)
  87.  {
  88.      return X86EMUL_OKAY;
  89. @@ -1035,10 +1100,137 @@ static int hvmemul_cmpxchg(
  90.      void *p_old,
  91.      void *p_new,
  92.      unsigned int bytes,
  93. +    bool lock,
  94.      struct x86_emulate_ctxt *ctxt)
  95.  {
  96. +    unsigned long addr, gfn, reps = 1;
  97. +    struct hvm_emulate_ctxt *hvmemul_ctxt =
  98. +        container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
  99. +    uint32_t pfec = PFEC_page_present | PFEC_write_access;
  100. +    paddr_t gpa = addr & ~PAGE_MASK;
  101. +    struct page_info *page;
  102. +    struct vcpu *curr = current;
  103. +       p2m_type_t p2mt;
  104. +       char *p;
  105. +    int rc = X86EMUL_OKAY;
  106. +    bool ret = true;
  107. +
  108. +    if ( is_x86_system_segment(seg) )
  109. +        pfec |= PFEC_implicit;
  110. +    else if ( hvmemul_ctxt->seg_reg[x86_seg_ss].attr.fields.dpl == 3 )
  111. +        pfec |= PFEC_user_mode;
  112. +
  113. +    rc = hvmemul_virtual_to_linear(
  114. +        seg, offset, bytes, &reps, hvm_access_write, hvmemul_ctxt, &addr);
  115. +    if ( rc != X86EMUL_OKAY || !bytes )
  116. +        return rc;
  117. +
  118. +    gfn = paging_gva_to_gfn(curr, addr, &pfec);
  119. +    if ( gfn == gfn_x(INVALID_GFN) )
  120. +    {
  121. +        pagefault_info_t pfinfo = {};
  122. +
  123. +        if ( ( pfec & PFEC_page_paged ) || ( pfec & PFEC_page_shared ) )
  124. +            return X86EMUL_RETRY;
  125. +
  126. +        pfinfo.linear = addr;
  127. +        pfinfo.ec = pfec;
  128. +
  129. +        x86_emul_pagefault(pfinfo.ec, pfinfo.linear, &hvmemul_ctxt->ctxt);
  130. +        return X86EMUL_EXCEPTION;
  131. +    }
  132. +    gpa |= (paddr_t)gfn << PAGE_SHIFT;
  133. +
  134. +    /*
  135. +     * No need to do the P2M lookup for internally handled MMIO, benefiting
  136. +     * - 32-bit WinXP (& older Windows) on AMD CPUs for LAPIC accesses,
  137. +     * - newer Windows (like Server 2012) for HPET accesses.
  138. +     */
  139. +    if ( !nestedhvm_vcpu_in_guestmode(curr) && hvm_mmio_internal(gpa) )
  140. +        return X86EMUL_UNHANDLEABLE;
  141. +
  142. +    page = get_page_from_gfn(curr->domain, gfn, &p2mt, P2M_UNSHARE);
  143. +
  144. +    if ( !page )
  145. +        return X86EMUL_UNHANDLEABLE;
  146. +
  147. +    if ( p2m_is_paging(p2mt) )
  148. +    {
  149. +        put_page(page);
  150. +        p2m_mem_paging_populate(curr->domain, gfn);
  151. +        return X86EMUL_RETRY;
  152. +    }
  153. +    if ( p2m_is_shared(p2mt) )
  154. +    {
  155. +        put_page(page);
  156. +        return X86EMUL_RETRY;
  157. +    }
  158. +    if ( p2m_is_grant(p2mt) )
  159. +    {
  160. +        put_page(page);
  161. +        return X86EMUL_UNHANDLEABLE;
  162. +    }
  163. +
  164. +    p = (char *)__map_domain_page(page) + (addr & ~PAGE_MASK);
  165. +
  166. +       switch ( bytes )
  167. +       {
  168. +       case 1:
  169. +    {
  170. +        uint8_t val, old = *(uint8_t *)p_old, new = *(uint8_t *)p_new;
  171. +        uint8_t *mem = (uint8_t *)p;
  172. +
  173. +        val = ( lock ? sync_cmpxchg(mem, old, new) : cmpxchg_local(mem, old, new) );
  174. +        ret = ( val == new  );
  175. +               break;
  176. +    }
  177. +       case 2:
  178. +    {
  179. +        uint16_t val, old = *(uint16_t *)p_old, new = *(uint16_t *)p_new;
  180. +        uint16_t *mem = (uint16_t *)p;
  181. +
  182. +        val = ( lock ? sync_cmpxchg(mem, old, new) : cmpxchg_local(mem, old, new) );
  183. +        ret = ( val == new );
  184. +               break;
  185. +    }
  186. +       case 4:
  187. +    {
  188. +        uint32_t val, old = *(uint32_t *)p_old, new = *(uint32_t *)p_new;
  189. +        uint32_t *mem = (uint32_t *)p;
  190. +
  191. +        // printk("- mem: %d, old: %d, new: %d\n", *mem, old, new);
  192. +        val = ( lock ? sync_cmpxchg(mem, old, new) : cmpxchg_local(mem, old, new) );
  193. +        // printk("+ mem: %d, old: %d, new: %d, val: %d\n", *mem, old, new, val);
  194. +        ret = ( val == new );
  195. +               break;
  196. +    }
  197. +       case 8:
  198. +    {
  199. +        uint64_t val, old = *(uint64_t *)p_old, new = *(uint64_t *)p_new;
  200. +        uint64_t *mem = (uint64_t *)p;
  201. +
  202. +        val = ( lock ? sync_cmpxchg(mem, old, new) : cmpxchg_local(mem, old, new) );
  203. +        ret = ( val == new );
  204. +               break;
  205. +    }
  206. +       default:
  207. +               rc = X86EMUL_UNHANDLEABLE;
  208. +       }
  209. +
  210. +    if ( !ret ) {
  211. +        // printk("X86EMUL_RETRY\n");
  212. +        // rc = X86EMUL_RETRY;
  213. +    }
  214. +
  215.      /* Fix this in case the guest is really relying on r-m-w atomicity. */
  216. -    return hvmemul_write(seg, offset, p_new, bytes, ctxt);
  217. +    // return hvmemul_write(seg, offset, p_new, bytes, ctxt);
  218. +
  219. +    unmap_domain_page(p);
  220. +    put_page(page);
  221. +
  222. +    // printk("returning %s\n", ( rc == X86EMUL_OKAY ) ? "X86EMUL_OKAY" : "error");
  223. +
  224. +    return rc;
  225.  }
  226.  
  227.  static int hvmemul_validate(
  228. diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
  229. index a6b2649..b6d8be6 100644
  230. --- a/xen/arch/x86/mm.c
  231. +++ b/xen/arch/x86/mm.c
  232. @@ -5336,6 +5336,7 @@ static int ptwr_emulated_cmpxchg(
  233.      void *p_old,
  234.      void *p_new,
  235.      unsigned int bytes,
  236. +    bool lock,
  237.      struct x86_emulate_ctxt *ctxt)
  238.  {
  239.      paddr_t old = 0, new = 0;
  240. diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
  241. index d93f2ab..4c269b8 100644
  242. --- a/xen/arch/x86/mm/shadow/common.c
  243. +++ b/xen/arch/x86/mm/shadow/common.c
  244. @@ -280,6 +280,7 @@ hvm_emulate_cmpxchg(enum x86_segment seg,
  245.                      void *p_old,
  246.                      void *p_new,
  247.                      unsigned int bytes,
  248. +                    bool lock,
  249.                      struct x86_emulate_ctxt *ctxt)
  250.  {
  251.      struct sh_emulate_ctxt *sh_ctxt =
  252. diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c
  253. index bb67be6..d5d78e6 100644
  254. --- a/xen/arch/x86/x86_emulate/x86_emulate.c
  255. +++ b/xen/arch/x86/x86_emulate/x86_emulate.c
  256. @@ -1850,7 +1850,7 @@ protmode_load_seg(
  257.  
  258.          fail_if(!ops->cmpxchg);
  259.          switch ( (rc = ops->cmpxchg(sel_seg, (sel & 0xfff8) + 4, &desc.b,
  260. -                                    &new_desc_b, sizeof(desc.b), ctxt)) )
  261. +                                    &new_desc_b, sizeof(desc.b), false, ctxt)) )
  262.          {
  263.          case X86EMUL_OKAY:
  264.              break;
  265. @@ -7017,7 +7017,7 @@ x86_emulate(
  266.              }
  267.  
  268.              if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old, aux,
  269. -                                    op_bytes, ctxt)) != X86EMUL_OKAY )
  270. +                                    op_bytes, lock_prefix, ctxt)) != X86EMUL_OKAY )
  271.                  goto done;
  272.              _regs.eflags |= X86_EFLAGS_ZF;
  273.          }
  274. @@ -7941,7 +7941,7 @@ x86_emulate(
  275.              fail_if(!ops->cmpxchg);
  276.              rc = ops->cmpxchg(
  277.                  dst.mem.seg, dst.mem.off, &dst.orig_val,
  278. -                &dst.val, dst.bytes, ctxt);
  279. +                &dst.val, dst.bytes, lock_prefix, ctxt);
  280.          }
  281.          else
  282.          {
  283. diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h
  284. index 9c5fcde..dc46e1f 100644
  285. --- a/xen/arch/x86/x86_emulate/x86_emulate.h
  286. +++ b/xen/arch/x86/x86_emulate/x86_emulate.h
  287. @@ -259,6 +259,7 @@ struct x86_emulate_ops
  288.          void *p_old,
  289.          void *p_new,
  290.          unsigned int bytes,
  291. +        bool lock,
  292.          struct x86_emulate_ctxt *ctxt);
  293.  
  294.      /*
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement