cpuport.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-07-14 JasonHu First Version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdef.h>
  13. #include <rtdbg.h>
  14. #include "cpuport.h"
  15. #include "tss.h"
  16. #include "segment.h"
  17. #include "gate.h"
  18. #include "stackframe.h"
  19. #include "page.h"
  20. #include "mmu.h"
  21. #include <lwp.h>
  22. #include <lwp_arch.h>
  23. #include <interrupt.h>
  24. /**
  25. * @brief from thread used interrupt context switch
  26. *
  27. */
  28. volatile rt_ubase_t rt_interrupt_from_thread = 0;
  29. /**
  30. * @brief to thread used interrupt context switch
  31. *
  32. */
  33. volatile rt_ubase_t rt_interrupt_to_thread = 0;
  34. /**
  35. * @brief flag to indicate context switch in interrupt or not
  36. *
  37. */
  38. volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0;
  39. extern void rt_hw_context_switch_to_real(rt_ubase_t to);
  40. extern void rt_hw_context_switch_real(rt_ubase_t from, rt_ubase_t to);
  41. /**
  42. * any thread will come here when first start
  43. */
  44. static void rt_hw_thread_entry(hw_thread_func_t function, void *arg, void (*texit)())
  45. {
  46. rt_hw_interrupt_enable(EFLAGS_IF); /* enable interrupt, avoid not sched */
  47. function(arg);
  48. if (texit)
  49. texit();
  50. dbg_log(DBG_ERROR, "rt thread execute done, should never be here!");
  51. for (;;)
  52. {
  53. }
  54. }
  55. rt_uint8_t *rt_hw_stack_init(void *tentry,
  56. void *parameter,
  57. rt_uint8_t *stack_addr,
  58. void *texit)
  59. {
  60. rt_uint8_t *stk;
  61. stk = stack_addr + sizeof(rt_ubase_t);
  62. stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_ubase_t)stk, sizeof(rt_ubase_t));
  63. stk -= sizeof(struct rt_hw_stack_frame);
  64. stk -= sizeof(rt_hw_context_t);
  65. rt_hw_context_t *context = (rt_hw_context_t *)stk;
  66. context->eip = rt_hw_thread_entry;
  67. context->function = tentry;
  68. context->arg = parameter;
  69. context->texit = texit;
  70. context->ebp = context->ebx = context->esi = context->edi = 0;
  71. return stk;
  72. }
  73. void rt_hw_context_switch_to(rt_ubase_t to)
  74. {
  75. rt_thread_t to_thread = rt_thread_sp_to_thread((void *)to);
  76. #ifdef RT_USING_USERSPACE
  77. /**
  78. * update kernel esp0 as to thread's kernel stack, to make sure process can't
  79. * get the correct kernel stack from tss esp0 when interrupt occur in user mode.
  80. */
  81. rt_ubase_t stacktop = (rt_ubase_t)(to_thread->stack_addr + to_thread->stack_size);
  82. rt_hw_tss_set_kstacktop(stacktop);
  83. lwp_mmu_switch(to_thread); /* switch mmu before switch context */
  84. #endif /* RT_USING_USERSPACE */
  85. rt_hw_context_switch_to_real(to);
  86. }
  87. void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to)
  88. {
  89. rt_thread_t from_thread = rt_thread_sp_to_thread((void *)from);
  90. rt_thread_t to_thread = rt_thread_sp_to_thread((void *)to);
  91. #ifdef RT_USING_LWP
  92. lwp_user_setting_save(from_thread);
  93. #endif /* RT_USING_LWP */
  94. #ifdef RT_USING_USERSPACE
  95. /**
  96. * update kernel esp0 as to thread's kernel stack, to make sure process can't
  97. * get the correct kernel stack from tss esp0 when interrupt occur in user mode.
  98. */
  99. rt_ubase_t stacktop = (rt_ubase_t)(to_thread->stack_addr + to_thread->stack_size);
  100. rt_hw_tss_set_kstacktop(stacktop);
  101. lwp_mmu_switch(to_thread); /* switch mmu before switch context */
  102. #endif /* RT_USING_USERSPACE */
  103. rt_hw_context_switch_real(from, to);
  104. #ifdef RT_USING_LWP
  105. lwp_user_setting_restore(to_thread);
  106. #endif /* RT_USING_LWP */
  107. }
  108. /**
  109. * when called rt_hw_context_switch_interrupt, just set from and to thread stack.
  110. * when interrupt leave, we check rt_thread_switch_interrupt_flag. if it's 1, we
  111. * will set rt_thread_switch_interrupt_flag as 0 then do context switch.
  112. * see interrupt_gcc.S on lable rt_hw_intr_thread_switch.
  113. */
  114. void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread)
  115. {
  116. if (rt_thread_switch_interrupt_flag == 0)
  117. rt_interrupt_from_thread = from;
  118. rt_interrupt_to_thread = to;
  119. rt_thread_switch_interrupt_flag = 1;
  120. return;
  121. }
  122. void rt_hw_cpu_shutdown()
  123. {
  124. }
  125. void rt_hw_cpu_init()
  126. {
  127. rt_hw_segment_init();
  128. rt_hw_gate_init();
  129. rt_hw_tss_init();
  130. }