cpu.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /* Copyright 2018 SiFive, Inc */
  2. /* SPDX-License-Identifier: Apache-2.0 */
  3. /*! @file cpu.h
  4. * @brief API for accessing CPU capabilities.
  5. */
  6. #ifndef METAL__CPU_H
  7. #define METAL__CPU_H
  8. #include <stdint.h>
  9. #include <metal/interrupt.h>
  10. struct metal_cpu;
  11. /*!
  12. * @brief Function signature for exception handlers
  13. */
  14. typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
  15. struct metal_cpu_vtable {
  16. unsigned long long (*mcycle_get)(struct metal_cpu *cpu);
  17. unsigned long long (*timebase_get)(struct metal_cpu *cpu);
  18. unsigned long long (*mtime_get)(struct metal_cpu *cpu);
  19. int (*mtimecmp_set)(struct metal_cpu *cpu, unsigned long long time);
  20. struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu);
  21. int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
  22. struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu);
  23. int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
  24. int (*set_sw_ipi)(struct metal_cpu *cpu, int hartid);
  25. int (*clear_sw_ipi)(struct metal_cpu *cpu, int hartid);
  26. int (*get_msip)(struct metal_cpu *cpu, int hartid);
  27. struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu);
  28. int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
  29. int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
  30. uintptr_t (*get_epc)(struct metal_cpu *cpu);
  31. int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
  32. };
  33. /*! @brief A device handle for a CPU hart
  34. */
  35. struct metal_cpu {
  36. const struct metal_cpu_vtable *vtable;
  37. };
  38. /*! @brief Get a reference to a CPU hart
  39. *
  40. * @param hartid The ID of the desired CPU hart
  41. * @return A pointer to the CPU device handle
  42. */
  43. struct metal_cpu* metal_cpu_get(unsigned int hartid);
  44. /*! @brief Get the hartid of the CPU hart executing this function
  45. *
  46. * @return The hartid of the current CPU hart */
  47. int metal_cpu_get_current_hartid(void);
  48. /*! @brief Get the number of CPU harts
  49. *
  50. * @return The number of CPU harts */
  51. int metal_cpu_get_num_harts(void);
  52. /*! @brief Get the CPU cycle count timer value
  53. *
  54. * Get the value of the cycle count timer for a given CPU
  55. *
  56. * @param cpu The CPU device handle
  57. * @return The value of the CPU cycle count timer
  58. */
  59. __inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
  60. { return cpu->vtable->mcycle_get(cpu); }
  61. /*! @brief Get the timebase of the CPU
  62. *
  63. * Get the value of the timebase of the cycle count timer
  64. *
  65. * @param cpu The CPU device handle
  66. * @return The value of the cycle count timer timebase
  67. */
  68. __inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
  69. { return cpu->vtable->timebase_get(cpu); }
  70. /*! @brief Get the value of the mtime RTC
  71. *
  72. * Get the value of the mtime real-time clock. The CPU interrupt controller
  73. * must be initialized before this function is called or the return value
  74. * will be 0.
  75. *
  76. * @param cpu The CPU device handle
  77. * @return The value of mtime, or 0 if failure
  78. */
  79. __inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
  80. { return cpu->vtable->mtime_get(cpu); }
  81. /*! @brief Set the value of the RTC mtimecmp RTC
  82. *
  83. * Set the value of the mtime real-time clock compare register. The CPU
  84. * interrupt controller must be initialized before this function is called
  85. * or the return value will be -1;
  86. *
  87. * @param cpu The CPU device handle
  88. * @param time The value to set the compare register to
  89. * @return The value of mtimecmp or -1 if error
  90. */
  91. __inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
  92. { return cpu->vtable->mtimecmp_set(cpu, time); }
  93. /*! @brief Get a reference to RTC timer interrupt controller
  94. *
  95. * Get a reference to the interrupt controller for the real-time clock interrupt.
  96. * The controller returned by this function must be initialized before any interrupts
  97. * are registered or enabled with it.
  98. *
  99. * @param cpu The CPU device handle
  100. * @return A pointer to the timer interrupt handle
  101. */
  102. __inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
  103. { return cpu->vtable->tmr_controller_interrupt(cpu); }
  104. /*! @brief Get the RTC timer interrupt id
  105. *
  106. * Get the interrupt ID of the real-time clock interrupt
  107. *
  108. * @param cpu The CPU device handle
  109. * @return The timer interrupt ID
  110. */
  111. __inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
  112. { return cpu->vtable->get_tmr_interrupt_id(cpu); }
  113. /*! @brief Get a reference to the software interrupt controller
  114. *
  115. * Get a reference to the interrupt controller for the software/inter-process
  116. * interrupt. The controller returned by this function must be initialized before
  117. * any interrupts are registered or enabled with it.
  118. *
  119. * @param cpu The CPU device handle
  120. * @return A pointer to the software interrupt handle
  121. */
  122. __inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
  123. { return cpu->vtable->sw_controller_interrupt(cpu); }
  124. /*! @brief Get the software interrupt id
  125. *
  126. * Get the interrupt ID for the software/inter-process interrupt
  127. *
  128. * @param cpu The CPU device handle
  129. * @return the software interrupt ID
  130. */
  131. __inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
  132. { return cpu->vtable->get_sw_interrupt_id(cpu); }
  133. /*!
  134. * @brief Set the inter-process interrupt for a hart
  135. *
  136. * Trigger a software/inter-process interrupt for a hart. The CPU interrupt
  137. * controller for the CPU handle passed to this function must be initialized
  138. * before this function is called.
  139. *
  140. * @param cpu The CPU device handle
  141. * @param hartid The CPU hart ID to be interrupted
  142. * @return 0 upon success
  143. */
  144. __inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
  145. { return cpu->vtable->set_sw_ipi(cpu, hartid); }
  146. /*!
  147. * @brief Clear the inter-process interrupt for a hart
  148. *
  149. * Clear the software/inter-process interrupt for a hart. The CPU interrupt
  150. * controller for the CPU handle passed to this function must be initialized
  151. * before this function is called.
  152. *
  153. * @param cpu The CPU device handle
  154. * @param hartid The CPU hart ID to clear
  155. * @return 0 upon success
  156. */
  157. __inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
  158. { return cpu->vtable->clear_sw_ipi(cpu, hartid); }
  159. /*!
  160. * @brief Get the value of MSIP for the given hart
  161. *
  162. * Get the value of the machine software interrupt pending bit for
  163. * the given hart. The CPU interrupt controller for the CPU handle passed
  164. * as argument to this function must be initialized before this function
  165. * is called.
  166. *
  167. * @param cpu the CPU device handle
  168. * @param hartid The CPU hart to read
  169. * @return 0 upon success
  170. */
  171. __inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
  172. { return cpu->vtable->get_msip(cpu, hartid); }
  173. /*!
  174. * @brief Get the interrupt controller for the CPU
  175. *
  176. * Get the CPU interrupt controller. The controller returned by this
  177. * function must be initialized before any interrupts are registered
  178. * or enabled and before any exception handlers are registered with
  179. * this CPU.
  180. *
  181. * @param cpu The CPU device handle
  182. * @return The handle for the CPU interrupt controller
  183. */
  184. __inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
  185. { return cpu->vtable->controller_interrupt(cpu); }
  186. /*!
  187. * @brief Register an exception handler
  188. *
  189. * Register an exception handler for the CPU. The CPU interrupt controller must be initialized
  190. * before this function is called.
  191. *
  192. * @param cpu The CPU device handle
  193. * @param ecode The exception code to register a handler for
  194. * @param handler Callback function for the exception handler
  195. * @return 0 upon success
  196. */
  197. __inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
  198. { return cpu->vtable->exception_register(cpu, ecode, handler); }
  199. /*!
  200. * @brief Get the length of an instruction in bytes
  201. *
  202. * Get the length of an instruction in bytes.
  203. *
  204. * On RISC-V platforms, this is useful for detecting whether an instruction is
  205. * compressed (2 bytes long) or uncompressed (4 bytes long).
  206. *
  207. * This function is useful in conjuction with `metal_cpu_get_exception_pc()`
  208. * and `metal_cpu_set_exception_pc()` in order to cause the exception handler to
  209. * return execution after the faulting instruction.
  210. *
  211. * @param cpu The CPU device handle
  212. * @param epc The address of the instruction to measure
  213. * @return the length of the instruction in bytes
  214. */
  215. __inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
  216. { return cpu->vtable->get_ilen(cpu, epc); }
  217. /*!
  218. * @brief Get the program counter of the current exception.
  219. *
  220. * This function must be called within an exception handler. The behavior is
  221. * undefined outside of an exception handler.
  222. *
  223. * @param cpu The CPU device handle
  224. * @return The value of the program counter at the time of the exception
  225. */
  226. __inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu)
  227. { return cpu->vtable->get_epc(cpu); }
  228. /*!
  229. * @brief Set the exception program counter
  230. *
  231. * This function must be called within an exception handler. The behavior
  232. * is undefined outside of an exception handler.
  233. *
  234. * This function can be used to cause an exception handler to return execution
  235. * to an address other than the one that caused the exception.
  236. *
  237. * @param cpu the CPU device handle
  238. * @param epc The address to set the exception program counter to
  239. * @return 0 upon success
  240. */
  241. __inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
  242. { return cpu->vtable->set_epc(cpu, epc); }
  243. #endif