vmm_context.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * guest context on VMM
  3. *
  4. * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd
  5. *
  6. * This file is part of RT-Thread (http://www.rt-thread.org)
  7. *
  8. * All rights reserved.
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License along
  21. * with this program; if not, write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  23. *
  24. * Change Logs:
  25. * Date Author Notes
  26. * 2013-11-04 Grissiom add comment
  27. */
  28. #include <rthw.h>
  29. #include <rtthread.h>
  30. #include <interrupt.h>
  31. #include <log_trace.h>
  32. #include <vmm.h>
  33. #include "vmm_context.h"
  34. struct rt_vmm_share_layout rt_vmm_share SECTION(".vmm.share");
  35. volatile struct vmm_context *_vmm_context = RT_NULL;
  36. void vmm_context_init(void *context_addr)
  37. {
  38. _vmm_context = (struct vmm_context *)context_addr;
  39. rt_memset((void *)_vmm_context, 0x00, sizeof(struct vmm_context));
  40. /* When loading RT-Thread, the IRQ on the guest should be disabled. */
  41. _vmm_context->virq_status = 1;
  42. }
  43. #ifdef RT_VMM_USING_DOMAIN
  44. unsigned long guest_domain_val SECTION(".bss.share");
  45. unsigned long vmm_domain_val SECTION(".bss.share");
  46. /* some RT-Thread code need to be called in the guest
  47. * context(rt_thread_idle_excute for example). To simplify the code, we need a
  48. * "super" domain mode to have access of both side. The code executed in super
  49. * domain mode is restricted and should be harmless. */
  50. unsigned long super_domain_val SECTION(".bss.share");
  51. void vmm_context_init_domain(struct vmm_domain *domain)
  52. {
  53. asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (guest_domain_val));
  54. rt_kprintf("Linux domain: kernel: %d, user: %d, io: %d\n"
  55. "VMM domain: vmm: %d, share: %d\n",
  56. domain->kernel, domain->user, domain->io,
  57. domain->vmm, domain->vmm_share);
  58. if (domain->kernel == domain->vmm ||
  59. domain->io == domain->vmm)
  60. {
  61. rt_kprintf("VMM and the guest share the same domain\n");
  62. super_domain_val = vmm_domain_val = guest_domain_val;
  63. return;
  64. }
  65. vmm_domain_val = guest_domain_val;
  66. /* become client to our own territory */
  67. vmm_domain_val |= (1 << (domain->vmm * 2)) | (1 << (domain->vmm_share * 2));
  68. super_domain_val = vmm_domain_val;
  69. /* super domain has access to both side */
  70. super_domain_val |= (1 << (domain->kernel * 2)) | (1 << (domain->user * 2));
  71. rt_kprintf("Original DAC: 0x%08x\n", guest_domain_val);
  72. }
  73. unsigned long vmm_context_enter_domain(unsigned long domain_val)
  74. {
  75. unsigned long old_domain;
  76. asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain));
  77. asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");
  78. return old_domain;
  79. }
  80. void vmm_context_restore_domain(unsigned long domain_val)
  81. {
  82. asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");
  83. }
  84. #endif
  85. void vmm_virq_pending(int irq)
  86. {
  87. /* when running this piece of code, the guest is already suspended. So it's
  88. * safe to set the bits without locks. */
  89. _vmm_context->virq_pending[irq / 32] |= (1 << (irq % 32));
  90. _vmm_context->virq_pended = 1;
  91. /* mask this IRQ in host */
  92. rt_hw_interrupt_mask(irq);
  93. }
  94. void vmm_virq_update(void)
  95. {
  96. if ((!_vmm_context->virq_status) &&
  97. ( _vmm_context->virq_pended))
  98. {
  99. rt_hw_interrupt_trigger(RT_VMM_VIRQ_TRIGGER);
  100. }
  101. }
  102. /** check the guest IRQ status
  103. *
  104. * @return 0 on guest should handle IRQ, -1 on should restore the guest context
  105. * normally.
  106. */
  107. int vmm_virq_check(void)
  108. {
  109. if ((!_vmm_context->virq_status) &&
  110. ( _vmm_context->virq_pended))
  111. {
  112. return 0;
  113. }
  114. return -1;
  115. }
  116. /* 10 = len("%08x, ") */
  117. static char _vmbuf[10*ARRAY_SIZE(_vmm_context->virq_pending)];
  118. void vmm_dump_virq(void)
  119. {
  120. int i, s;
  121. vmm_info("---- virtual IRQ ----\n");
  122. vmm_info(" status: %08x, pended: %08x, pending:\n",
  123. _vmm_context->virq_status, _vmm_context->virq_pended);
  124. for (s = 0, i = 0; i < ARRAY_SIZE(_vmm_context->virq_pending); i++)
  125. {
  126. s += rt_snprintf(_vmbuf+s, sizeof(_vmbuf)-s,
  127. "%08x, ", _vmm_context->virq_pending[i]);
  128. }
  129. vmm_info("%.*s\n", sizeof(_vmbuf), _vmbuf);
  130. vmm_info("---- virtual IRQ ----\n");
  131. }
  132. int vmm_virq_coherence_ok(void)
  133. {
  134. int i, res;
  135. int should_pend = 0;
  136. for (i = 0; i < ARRAY_SIZE(_vmm_context->virq_pending); i++)
  137. {
  138. should_pend |= _vmm_context->virq_pending[i];
  139. }
  140. res = (_vmm_context->virq_pended == !!should_pend);
  141. if (!res)
  142. {
  143. vmm_info("--- %x %x, %x\n",
  144. _vmm_context->virq_pended, should_pend, !!should_pend);
  145. }
  146. return res;
  147. }
  148. extern struct rt_thread vmm_thread;
  149. void vmm_show_guest_reg(void)
  150. {
  151. struct rt_hw_stack *sp = vmm_thread.sp;
  152. #ifdef RT_VMM_USING_DOMAIN
  153. unsigned long old_domain;
  154. old_domain = vmm_context_enter_domain(super_domain_val);
  155. #endif
  156. vmm_info("CPSR: %08x, PC: %08x, LR: %08x, SP: %08x\n",
  157. sp->cpsr, sp->pc, sp->lr, sp+1);
  158. #ifdef RT_VMM_USING_DOMAIN
  159. vmm_context_restore_domain(old_domain);
  160. #endif
  161. }
  162. void vmm_dump_domain(void)
  163. {
  164. unsigned long dac;
  165. asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (dac));
  166. vmm_info("current DAC: %08x\n", dac);
  167. #ifdef RT_VMM_USING_DOMAIN
  168. vmm_info("guest DAC: %08x, RTT DAC: %08x, super DAC: %08x\n",
  169. guest_domain_val, vmm_domain_val, super_domain_val);
  170. #endif
  171. }
  172. void vmm_show_guest(void)
  173. {
  174. vmm_show_guest_reg();
  175. vmm_dump_virq();
  176. vmm_dump_domain();
  177. }
  178. #ifdef RT_USING_FINSH
  179. #include <finsh.h>
  180. FINSH_FUNCTION_EXPORT_ALIAS(vmm_show_guest, vmm, show vmm status);
  181. #endif
  182. static int _bad_cpsr(unsigned long cpsr)
  183. {
  184. int bad = 1;
  185. switch (cpsr & MODEMASK)
  186. {
  187. case USERMODE:
  188. case FIQMODE:
  189. case IRQMODE:
  190. case SVCMODE:
  191. #ifdef CPU_HAS_MONITOR_MODE
  192. case MONITORMODE:
  193. #endif
  194. case ABORTMODE:
  195. #ifdef CPU_HAS_HYP_MODE
  196. case HYPMODE:
  197. #endif
  198. case UNDEFMODE:
  199. case MODEMASK:
  200. bad = 0;
  201. break;
  202. };
  203. return bad;
  204. }
  205. void vmm_verify_guest_status(struct rt_hw_stack *sp)
  206. {
  207. int dump_vmm = 0;
  208. unsigned long cpsr;
  209. #ifdef RT_VMM_USING_DOMAIN
  210. unsigned long old_domain;
  211. old_domain = vmm_context_enter_domain(super_domain_val);
  212. #endif
  213. cpsr = sp->cpsr;
  214. if (_bad_cpsr(cpsr))
  215. {
  216. vmm_info("=================================\n");
  217. vmm_info("VMM WARING: bad CPSR in guest\n");
  218. dump_vmm = 1;
  219. }
  220. else
  221. {
  222. if (cpsr & A_Bit && 0)
  223. {
  224. vmm_info("=================================\n");
  225. vmm_info("VMM WARING: A bit is set in guest\n");
  226. dump_vmm = 1;
  227. }
  228. if ((cpsr & I_Bit) && (sp->pc <= VMM_BEGIN))
  229. {
  230. vmm_info("=================================\n");
  231. vmm_info("VMM WARING: IRQ disabled in guest\n");
  232. dump_vmm = 1;
  233. }
  234. if (cpsr & F_Bit)
  235. {
  236. vmm_info("=================================\n");
  237. vmm_info("VMM WARING: FIQ disabled in guest\n");
  238. dump_vmm = 1;
  239. }
  240. if ((cpsr & MODEMASK) == USERMODE)
  241. {
  242. if (_vmm_context->virq_status & 1)
  243. {
  244. vmm_info("=================================\n");
  245. vmm_info("VMM WARING: VIRQ disabled in user mode\n");
  246. dump_vmm = 1;
  247. }
  248. if ((sp->pc > 0xbf000000) && (sp->pc < 0xffff0000))
  249. {
  250. vmm_info("=================================\n");
  251. vmm_info("VMM WARING: executing kernel code in usr mode\n");
  252. dump_vmm = 1;
  253. }
  254. /* FIXME: when the guest is suspended in user mode and its
  255. * interrupts come, this can be misleading. */
  256. #if 0
  257. if (_vmm_context->virq_pended)
  258. {
  259. vmm_info("=================================\n");
  260. vmm_info("VMM WARING: VIRQ pended in user mode\n");
  261. dump_vmm = 1;
  262. }
  263. #endif
  264. }
  265. else if ((cpsr & MODEMASK) == SVCMODE && sp->pc < 0xbf000000)
  266. {
  267. vmm_info("=================================\n");
  268. vmm_info("VMM WARING: executing usr code in svc mode\n");
  269. dump_vmm = 1;
  270. }
  271. }
  272. #if 0
  273. if (!vmm_virq_coherence_ok())
  274. {
  275. vmm_info("=================================\n");
  276. vmm_info("VMM WARING: bad VIRQ status\n");
  277. dump_vmm = 1;
  278. }
  279. #endif
  280. if (dump_vmm)
  281. {
  282. vmm_show_guest();
  283. vmm_info("=================================\n");
  284. }
  285. #ifdef RT_VMM_USING_DOMAIN
  286. vmm_context_restore_domain(old_domain);
  287. #endif
  288. }