vmm_linux.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include <linux/module.h>
  2. #include <linux/fs.h>
  3. #include <linux/mm.h>
  4. #include <linux/slab.h>
  5. #include <linux/uaccess.h>
  6. #include <linux/io.h>
  7. #include <linux/memblock.h>
  8. #include <asm/cacheflush.h>
  9. #include <mach/hardware.h>
  10. #include "vmm_linux.h"
  11. #define IOMAP_NUM 3
  12. #define BUFF_SZ (4 * 1024)
  13. struct vmm_iomap *_linux_iomap = NULL;
  14. const char *uart_name = "uart";
  15. /* some exported Linux Kernel patch */
  16. extern void vmm_set_status(int status);
  17. extern void vmm_context_init(void *context_addr);
  18. extern unsigned long vmm_save_irq(void);
  19. extern void vmm_restore_irq(unsigned long flags);
  20. static struct vmm_domain domain =
  21. {
  22. .kernel = DOMAIN_KERNEL,
  23. .user = DOMAIN_USER,
  24. .io = DOMAIN_IO,
  25. .vmm = DOMAIN_RTVMM,
  26. .vmm_share = DOMAIN_RTVMM_SHR,
  27. };
  28. static struct vmm_iomap iomap[RT_VMM_IOMAP_MAXNR] =
  29. {
  30. {.name = "UART1", .pa = 0x1000A000, .size = 4096},
  31. {.name = "TIMER", .pa = 0x10012000, .size = 4096},
  32. {.name = "GIC_CPU", .pa = 0x1E000000, .size = 4096},
  33. {.name = "GIC_DIST", .pa = 0x1E001000, .size = 4096},
  34. {.name = "SYS_CTRL", .pa = 0x1001A000, .size = 4096},
  35. {.pa = 0},
  36. };
  37. void vmm_iomap_init(void)
  38. {
  39. int index;
  40. _linux_iomap = &iomap[0];
  41. BUILD_BUG_ON(ARRAY_SIZE(iomap) > RT_VMM_IOMAP_MAXNR);
  42. for (index = 0; index < ARRAY_SIZE(iomap); index++) {
  43. if (_linux_iomap[index].pa == 0)
  44. break;
  45. if (_linux_iomap[index].size != 0)
  46. _linux_iomap[index].va =
  47. ioremap_nocache(_linux_iomap[index].pa,
  48. _linux_iomap[index].size);
  49. printk("%s: 0x%08lx --> 0x%p, size %u\n",
  50. _linux_iomap[index].name,
  51. _linux_iomap[index].pa,
  52. _linux_iomap[index].va,
  53. _linux_iomap[index].size);
  54. }
  55. printk("vmm: init iomap done!\n");
  56. }
  57. #if 0
  58. void trap_set_vector(unsigned long start, unsigned int length)
  59. {
  60. int sctrl;
  61. /* C12-C0 is only active when SCTLR.V = 0 */
  62. asm volatile ("mrc p15, #0, %0, c1, c0, #0"
  63. :"=r" (sctrl));
  64. sctrl &= ~(1 << 13);
  65. asm volatile ("mcr p15, #0, %0, c1, c0, #0"
  66. :
  67. :"r" (sctrl));
  68. asm volatile ("mcr p15, #0, %0, c12, c0, #0"
  69. :
  70. :"r" (start));
  71. rmb();
  72. }
  73. #else
  74. extern void trap_set_vector(unsigned long start, unsigned int length);
  75. #endif
  76. static void vmm_open_domain(void)
  77. {
  78. unsigned long dval;
  79. asm volatile ("mrc p15, 0, %0, c3, c0\n"
  80. : "=r" (dval));
  81. dval |= (0x1 << (DOMAIN_RTVMM * 2)) |
  82. (0x1 << (DOMAIN_RTVMM_SHR * 2));
  83. asm volatile ("mcr p15, 0, %0, c3, c0\n"
  84. : : "r" (dval));
  85. }
  86. static void vmm_close_domain(void)
  87. {
  88. unsigned long dval;
  89. asm volatile ("mrc p15, 0, %0, c3, c0\n"
  90. : "=r" (dval));
  91. /* we still need access tp DOMAIN_RTVMM_SHR because the IRQ stack is
  92. * there. */
  93. dval &= ~(0x3 << (DOMAIN_RTVMM * 2));
  94. asm volatile ("mcr p15, 0, %0, c3, c0\n"
  95. : : "r" (dval));
  96. }
  97. static DEFINE_SPINLOCK(init_lock);
  98. void vmm_entry(void)
  99. {
  100. vmm_entry_t entry;
  101. unsigned long flags;
  102. struct vmm_entry_param eparam = {
  103. .iomap = &iomap[0],
  104. .domain = &domain,
  105. };
  106. printk("Entry VMM:0x%08x with iomap 0x%p\n", VMM_BEGIN, _linux_iomap);
  107. spin_lock_irqsave(&init_lock, flags);
  108. memcpy((void*)(LINUX_VECTOR_POS), (void*)0xFFFF0000,
  109. LINUX_VECTOR_PGSZ);
  110. flush_icache_range(LINUX_VECTOR_POS,
  111. LINUX_VECTOR_POS + LINUX_VECTOR_PGSZ);
  112. /*dump_vector(0xFFFF0000);*/
  113. /* set the interrupt vector to RTT */
  114. trap_set_vector(VMM_BEGIN, 16 * 4);
  115. /*dump_vector(VMM_END-LINUX_VECTOR_PGSZ);*/
  116. entry = (vmm_entry_t)VMM_BEGIN;
  117. vmm_context_init(&RT_VMM_SHARE->ctx);
  118. vmm_set_status(0x01);
  119. pr_info("Linux domain: kernel: %d, user: %d, io: %d\n",
  120. DOMAIN_KERNEL, DOMAIN_USER, DOMAIN_IO);
  121. /* switch to RTT and Good Luck */
  122. entry(&eparam);
  123. spin_unlock_irqrestore(&init_lock, flags);
  124. /* we now switched to virtual IRQ but the hardware IRQ is disabled
  125. * before entering RT-Thread. So we have to enabled it by hand. */
  126. {
  127. asm volatile ("cpsie i":::"memory", "cc");
  128. }
  129. printk("come back to Linux.\n");
  130. }
  131. int vmm_load_fw(const char* filename)
  132. {
  133. mm_segment_t oldfs = {0};
  134. unsigned long len;
  135. unsigned long file_sz;
  136. loff_t pos = 0;
  137. struct file *flp = NULL;
  138. char *buf_ptr = (char*)VMM_BEGIN;
  139. printk("loading RT-Thread:%s ....", filename);
  140. /* FIXME: we should not need this actually. But currently Linux would
  141. * hang without this. Let's just proceed and I will go back to handle
  142. * this in the future. */
  143. memset((void*)VMM_BEGIN, 0, VMM_SIZE);
  144. flp = filp_open(filename, O_RDONLY, S_IRWXU);
  145. if (IS_ERR(flp))
  146. {
  147. printk("vmm loader: open file failed. "
  148. "Return 0x%p\n", flp);
  149. return -1;
  150. }
  151. /* get file size */
  152. file_sz = vfs_llseek(flp, 0, SEEK_END);
  153. vfs_llseek(flp, 0, SEEK_SET);
  154. oldfs = get_fs();
  155. set_fs(get_ds());
  156. while (file_sz > 0)
  157. {
  158. // len = vfs_read(flp, (void __user __force *)buff, BUFF_SZ, &pos);
  159. len = vfs_read(flp, (void __user __force*)buf_ptr, BUFF_SZ, &pos);
  160. file_sz -= len;
  161. buf_ptr += len;
  162. }
  163. set_fs(oldfs);
  164. filp_close(flp, NULL);
  165. printk("done!\n");
  166. /* flush RT-Thread memory */
  167. flush_cache_vmap(VMM_BEGIN, VMM_END);
  168. return 0;
  169. }
  170. static int __init vmm_init(void)
  171. {
  172. printk("VMM started.\n");
  173. vmm_iomap_init();
  174. /* Open the domain permission so we could write firmware to it */
  175. vmm_open_domain();
  176. if (vmm_load_fw("/vmm/rtthread.bin") == 0)
  177. vmm_entry();
  178. return 0;
  179. }
  180. static void __exit vmm_exit(void)
  181. {
  182. int i;
  183. unsigned long flags;
  184. spin_lock_irqsave(&init_lock, flags);
  185. vmm_set_status(0x00);
  186. trap_set_vector(LINUX_VECTOR_POS, 16 * 4);
  187. spin_unlock_irqrestore(&init_lock, flags);
  188. for (i = 0; i < ARRAY_SIZE(iomap); i++)
  189. {
  190. if (iomap[i].pa == 0)
  191. break;
  192. printk("iounmap %s(0x%p)\n",
  193. iomap[i].name,
  194. iomap[i].va);
  195. iounmap(iomap[i].va);
  196. }
  197. vmm_close_domain();
  198. printk("vmm exit\n");
  199. }
  200. module_init(vmm_init);
  201. module_exit(vmm_exit);
  202. MODULE_AUTHOR("bernard.xiong <bernard.xiong@gmail.com>");
  203. MODULE_DESCRIPTION("RT-VMM");
  204. MODULE_LICENSE("GPL");