0018-KVM-x86-emulator-introduce-emulator_recalc_and_set_m.patch 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. From d2c4fc069a073d621d2cbc97ffe9547754784639 Mon Sep 17 00:00:00 2001
  2. From: Maxim Levitsky <[email protected]>
  3. Date: Tue, 25 Oct 2022 15:47:29 +0300
  4. Subject: [PATCH] KVM: x86: emulator: introduce emulator_recalc_and_set_mode
  5. Some instructions update the cpu execution mode, which needs to update the
  6. emulation mode.
  7. Extract this code, and make assign_eip_far use it.
  8. assign_eip_far now reads CS, instead of getting it via a parameter,
  9. which is ok, because callers always assign CS to the same value
  10. before calling this function.
  11. No functional change is intended.
  12. Signed-off-by: Maxim Levitsky <[email protected]>
  13. ---
  14. arch/x86/kvm/emulate.c | 85 ++++++++++++++++++++++++++++--------------
  15. 1 file changed, 57 insertions(+), 28 deletions(-)
  16. diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
  17. index 5ee1998dd38e..d75d33d60cb8 100644
  18. --- a/arch/x86/kvm/emulate.c
  19. +++ b/arch/x86/kvm/emulate.c
  20. @@ -760,8 +760,7 @@ static int linearize(struct x86_emulate_ctxt *ctxt,
  21. ctxt->mode, linear);
  22. }
  23. -static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst,
  24. - enum x86emul_mode mode)
  25. +static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst)
  26. {
  27. ulong linear;
  28. int rc;
  29. @@ -771,41 +770,71 @@ static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst,
  30. if (ctxt->op_bytes != sizeof(unsigned long))
  31. addr.ea = dst & ((1UL << (ctxt->op_bytes << 3)) - 1);
  32. - rc = __linearize(ctxt, addr, &max_size, 1, false, true, mode, &linear);
  33. + rc = __linearize(ctxt, addr, &max_size, 1, false, true, ctxt->mode, &linear);
  34. if (rc == X86EMUL_CONTINUE)
  35. ctxt->_eip = addr.ea;
  36. return rc;
  37. }
  38. +static inline int emulator_recalc_and_set_mode(struct x86_emulate_ctxt *ctxt)
  39. +{
  40. + u64 efer;
  41. + struct desc_struct cs;
  42. + u16 selector;
  43. + u32 base3;
  44. +
  45. + ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
  46. +
  47. + if (!(ctxt->ops->get_cr(ctxt, 0) & X86_CR0_PE)) {
  48. + /* Real mode. cpu must not have long mode active */
  49. + if (efer & EFER_LMA)
  50. + return X86EMUL_UNHANDLEABLE;
  51. + ctxt->mode = X86EMUL_MODE_REAL;
  52. + return X86EMUL_CONTINUE;
  53. + }
  54. +
  55. + if (ctxt->eflags & X86_EFLAGS_VM) {
  56. + /* Protected/VM86 mode. cpu must not have long mode active */
  57. + if (efer & EFER_LMA)
  58. + return X86EMUL_UNHANDLEABLE;
  59. + ctxt->mode = X86EMUL_MODE_VM86;
  60. + return X86EMUL_CONTINUE;
  61. + }
  62. +
  63. + if (!ctxt->ops->get_segment(ctxt, &selector, &cs, &base3, VCPU_SREG_CS))
  64. + return X86EMUL_UNHANDLEABLE;
  65. +
  66. + if (efer & EFER_LMA) {
  67. + if (cs.l) {
  68. + /* Proper long mode */
  69. + ctxt->mode = X86EMUL_MODE_PROT64;
  70. + } else if (cs.d) {
  71. + /* 32 bit compatibility mode*/
  72. + ctxt->mode = X86EMUL_MODE_PROT32;
  73. + } else {
  74. + ctxt->mode = X86EMUL_MODE_PROT16;
  75. + }
  76. + } else {
  77. + /* Legacy 32 bit / 16 bit mode */
  78. + ctxt->mode = cs.d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
  79. + }
  80. +
  81. + return X86EMUL_CONTINUE;
  82. +}
  83. +
  84. static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst)
  85. {
  86. - return assign_eip(ctxt, dst, ctxt->mode);
  87. + return assign_eip(ctxt, dst);
  88. }
  89. -static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst,
  90. - const struct desc_struct *cs_desc)
  91. +static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst)
  92. {
  93. - enum x86emul_mode mode = ctxt->mode;
  94. - int rc;
  95. + int rc = emulator_recalc_and_set_mode(ctxt);
  96. -#ifdef CONFIG_X86_64
  97. - if (ctxt->mode >= X86EMUL_MODE_PROT16) {
  98. - if (cs_desc->l) {
  99. - u64 efer = 0;
  100. + if (rc != X86EMUL_CONTINUE)
  101. + return rc;
  102. - ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
  103. - if (efer & EFER_LMA)
  104. - mode = X86EMUL_MODE_PROT64;
  105. - } else
  106. - mode = X86EMUL_MODE_PROT32; /* temporary value */
  107. - }
  108. -#endif
  109. - if (mode == X86EMUL_MODE_PROT16 || mode == X86EMUL_MODE_PROT32)
  110. - mode = cs_desc->d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
  111. - rc = assign_eip(ctxt, dst, mode);
  112. - if (rc == X86EMUL_CONTINUE)
  113. - ctxt->mode = mode;
  114. - return rc;
  115. + return assign_eip(ctxt, dst);
  116. }
  117. static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)
  118. @@ -2139,7 +2168,7 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
  119. if (rc != X86EMUL_CONTINUE)
  120. return rc;
  121. - rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
  122. + rc = assign_eip_far(ctxt, ctxt->src.val);
  123. /* Error handling is not implemented. */
  124. if (rc != X86EMUL_CONTINUE)
  125. return X86EMUL_UNHANDLEABLE;
  126. @@ -2217,7 +2246,7 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
  127. &new_desc);
  128. if (rc != X86EMUL_CONTINUE)
  129. return rc;
  130. - rc = assign_eip_far(ctxt, eip, &new_desc);
  131. + rc = assign_eip_far(ctxt, eip);
  132. /* Error handling is not implemented. */
  133. if (rc != X86EMUL_CONTINUE)
  134. return X86EMUL_UNHANDLEABLE;
  135. @@ -3117,7 +3146,7 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
  136. if (rc != X86EMUL_CONTINUE)
  137. return rc;
  138. - rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
  139. + rc = assign_eip_far(ctxt, ctxt->src.val);
  140. if (rc != X86EMUL_CONTINUE)
  141. goto fail;
  142. --
  143. 2.38.1