emulate_loadstore.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License, version 2, as
  4. * published by the Free Software Foundation.
  5. *
  6. * This program is distributed in the hope that it will be useful,
  7. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. * GNU General Public License for more details.
  10. *
  11. * You should have received a copy of the GNU General Public License
  12. * along with this program; if not, write to the Free Software
  13. * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. *
  15. * Copyright IBM Corp. 2007
  16. * Copyright 2011 Freescale Semiconductor, Inc.
  17. *
  18. * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  19. */
  20. #include <linux/jiffies.h>
  21. #include <linux/hrtimer.h>
  22. #include <linux/types.h>
  23. #include <linux/string.h>
  24. #include <linux/kvm_host.h>
  25. #include <linux/clockchips.h>
  26. #include <asm/reg.h>
  27. #include <asm/time.h>
  28. #include <asm/byteorder.h>
  29. #include <asm/kvm_ppc.h>
  30. #include <asm/disassemble.h>
  31. #include <asm/ppc-opcode.h>
  32. #include "timing.h"
  33. #include "trace.h"
  34. /* XXX to do:
  35. * lhax
  36. * lhaux
  37. * lswx
  38. * lswi
  39. * stswx
  40. * stswi
  41. * lha
  42. * lhau
  43. * lmw
  44. * stmw
  45. *
  46. */
  47. int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)
  48. {
  49. struct kvm_run *run = vcpu->run;
  50. u32 inst;
  51. int ra, rs, rt;
  52. enum emulation_result emulated;
  53. int advance = 1;
  54. /* this default type might be overwritten by subcategories */
  55. kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
  56. emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst);
  57. if (emulated != EMULATE_DONE)
  58. return emulated;
  59. ra = get_ra(inst);
  60. rs = get_rs(inst);
  61. rt = get_rt(inst);
  62. switch (get_op(inst)) {
  63. case 31:
  64. switch (get_xop(inst)) {
  65. case OP_31_XOP_LWZX:
  66. emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
  67. break;
  68. case OP_31_XOP_LBZX:
  69. emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
  70. break;
  71. case OP_31_XOP_LBZUX:
  72. emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
  73. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  74. break;
  75. case OP_31_XOP_STWX:
  76. emulated = kvmppc_handle_store(run, vcpu,
  77. kvmppc_get_gpr(vcpu, rs),
  78. 4, 1);
  79. break;
  80. case OP_31_XOP_STBX:
  81. emulated = kvmppc_handle_store(run, vcpu,
  82. kvmppc_get_gpr(vcpu, rs),
  83. 1, 1);
  84. break;
  85. case OP_31_XOP_STBUX:
  86. emulated = kvmppc_handle_store(run, vcpu,
  87. kvmppc_get_gpr(vcpu, rs),
  88. 1, 1);
  89. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  90. break;
  91. case OP_31_XOP_LHAX:
  92. emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
  93. break;
  94. case OP_31_XOP_LHZX:
  95. emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
  96. break;
  97. case OP_31_XOP_LHZUX:
  98. emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
  99. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  100. break;
  101. case OP_31_XOP_STHX:
  102. emulated = kvmppc_handle_store(run, vcpu,
  103. kvmppc_get_gpr(vcpu, rs),
  104. 2, 1);
  105. break;
  106. case OP_31_XOP_STHUX:
  107. emulated = kvmppc_handle_store(run, vcpu,
  108. kvmppc_get_gpr(vcpu, rs),
  109. 2, 1);
  110. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  111. break;
  112. case OP_31_XOP_DCBST:
  113. case OP_31_XOP_DCBF:
  114. case OP_31_XOP_DCBI:
  115. /* Do nothing. The guest is performing dcbi because
  116. * hardware DMA is not snooped by the dcache, but
  117. * emulated DMA either goes through the dcache as
  118. * normal writes, or the host kernel has handled dcache
  119. * coherence. */
  120. break;
  121. case OP_31_XOP_LWBRX:
  122. emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0);
  123. break;
  124. case OP_31_XOP_STWBRX:
  125. emulated = kvmppc_handle_store(run, vcpu,
  126. kvmppc_get_gpr(vcpu, rs),
  127. 4, 0);
  128. break;
  129. case OP_31_XOP_LHBRX:
  130. emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0);
  131. break;
  132. case OP_31_XOP_STHBRX:
  133. emulated = kvmppc_handle_store(run, vcpu,
  134. kvmppc_get_gpr(vcpu, rs),
  135. 2, 0);
  136. break;
  137. default:
  138. emulated = EMULATE_FAIL;
  139. break;
  140. }
  141. break;
  142. case OP_LWZ:
  143. emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
  144. break;
  145. /* TBD: Add support for other 64 bit load variants like ldu, ldux, ldx etc. */
  146. case OP_LD:
  147. rt = get_rt(inst);
  148. emulated = kvmppc_handle_load(run, vcpu, rt, 8, 1);
  149. break;
  150. case OP_LWZU:
  151. emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
  152. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  153. break;
  154. case OP_LBZ:
  155. emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
  156. break;
  157. case OP_LBZU:
  158. emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
  159. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  160. break;
  161. case OP_STW:
  162. emulated = kvmppc_handle_store(run, vcpu,
  163. kvmppc_get_gpr(vcpu, rs),
  164. 4, 1);
  165. break;
  166. /* TBD: Add support for other 64 bit store variants like stdu, stdux, stdx etc. */
  167. case OP_STD:
  168. rs = get_rs(inst);
  169. emulated = kvmppc_handle_store(run, vcpu,
  170. kvmppc_get_gpr(vcpu, rs),
  171. 8, 1);
  172. break;
  173. case OP_STWU:
  174. emulated = kvmppc_handle_store(run, vcpu,
  175. kvmppc_get_gpr(vcpu, rs),
  176. 4, 1);
  177. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  178. break;
  179. case OP_STB:
  180. emulated = kvmppc_handle_store(run, vcpu,
  181. kvmppc_get_gpr(vcpu, rs),
  182. 1, 1);
  183. break;
  184. case OP_STBU:
  185. emulated = kvmppc_handle_store(run, vcpu,
  186. kvmppc_get_gpr(vcpu, rs),
  187. 1, 1);
  188. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  189. break;
  190. case OP_LHZ:
  191. emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
  192. break;
  193. case OP_LHZU:
  194. emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
  195. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  196. break;
  197. case OP_LHA:
  198. emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
  199. break;
  200. case OP_LHAU:
  201. emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
  202. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  203. break;
  204. case OP_STH:
  205. emulated = kvmppc_handle_store(run, vcpu,
  206. kvmppc_get_gpr(vcpu, rs),
  207. 2, 1);
  208. break;
  209. case OP_STHU:
  210. emulated = kvmppc_handle_store(run, vcpu,
  211. kvmppc_get_gpr(vcpu, rs),
  212. 2, 1);
  213. kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
  214. break;
  215. default:
  216. emulated = EMULATE_FAIL;
  217. break;
  218. }
  219. if (emulated == EMULATE_FAIL) {
  220. advance = 0;
  221. kvmppc_core_queue_program(vcpu, 0);
  222. }
  223. trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated);
  224. /* Advance past emulated instruction. */
  225. if (advance)
  226. kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4);
  227. return emulated;
  228. }