8 #include <arch/vcore.h>
12 /*****************************************************************************/
13 /* TODO: This is a complete hack, but necessary for vcore stuff to work for now
14 * The issue is that exit sometimes calls sys_yield(), and we can't recover from
15 * that properly under our vcore model (we shouldn't though). We really need to
16 * rethink what sys_yield 'should' do when in multicore mode, or else come up
17 * with a different syscall entirely. */
21 #define exit(status) ros_syscall(SYS_proc_destroy, getpid(), status, 0, 0, 0, 0)
22 /*****************************************************************************/
24 #define LOG2_MAX_VCORES 6
25 #define MAX_VCORES (1 << LOG2_MAX_VCORES)
27 #define TRANSITION_STACK_PAGES 2
28 #define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
30 /* Defined by glibc; Must be implemented by a user level threading library */
31 extern void vcore_entry();
32 /* Declared in glibc's start.c */
33 extern __thread bool __vcore_context;
35 /* Utility Functions */
36 void *allocate_tls(void);
37 void free_tls(void *tcb);
38 void *reinit_tls(void *tcb);
40 /* Vcore API functions */
41 static inline size_t max_vcores(void);
42 static inline size_t num_vcores(void);
43 static inline int vcore_id(void);
44 static inline bool in_vcore_context(void);
45 static inline bool in_multi_mode(void);
46 static inline void __enable_notifs(uint32_t vcoreid);
47 static inline void __disable_notifs(uint32_t vcoreid);
48 static inline bool notif_is_enabled(uint32_t vcoreid);
49 static inline bool vcore_is_mapped(uint32_t vcoreid);
50 static inline bool vcore_is_preempted(uint32_t vcoreid);
51 static inline struct preempt_data *vcpd_of(uint32_t vcoreid);
52 static inline bool preempt_is_pending(uint32_t vcoreid);
53 static inline bool __preempt_is_pending(uint32_t vcoreid);
55 void vcore_event_init(void);
56 void vcore_change_to_m(void);
57 int vcore_request(long nr_new_vcores);
58 void vcore_yield(bool preempt_pending);
59 bool clear_notif_pending(uint32_t vcoreid);
60 void enable_notifs(uint32_t vcoreid);
61 void disable_notifs(uint32_t vcoreid);
62 void vcore_idle(void);
63 void ensure_vcore_runs(uint32_t vcoreid);
64 void cpu_relax_vc(uint32_t vcoreid);
67 static inline size_t max_vcores(void)
69 return MIN(__procinfo.max_vcores, MAX_VCORES);
72 static inline size_t num_vcores(void)
74 return __procinfo.num_vcores;
77 static inline int vcore_id(void)
82 static inline bool in_vcore_context(void)
84 return __vcore_context;
87 static inline bool in_multi_mode(void)
89 return __procinfo.is_mcp;
92 /* Only call this if you know what you are doing. */
93 static inline void __enable_notifs(uint32_t vcoreid)
95 vcpd_of(vcoreid)->notif_disabled = FALSE;
98 static inline void __disable_notifs(uint32_t vcoreid)
100 vcpd_of(vcoreid)->notif_disabled = TRUE;
103 static inline bool notif_is_enabled(uint32_t vcoreid)
105 return !vcpd_of(vcoreid)->notif_disabled;
108 static inline bool vcore_is_mapped(uint32_t vcoreid)
110 return __procinfo.vcoremap[vcoreid].valid;
113 /* We could also check for VC_K_LOCK, but that's a bit much. */
114 static inline bool vcore_is_preempted(uint32_t vcoreid)
116 struct preempt_data *vcpd = vcpd_of(vcoreid);
117 return atomic_read(&vcpd->flags) & VC_PREEMPTED;
120 static inline struct preempt_data *vcpd_of(uint32_t vcoreid)
122 return &__procdata.vcore_preempt_data[vcoreid];
125 /* Uthread's can call this in case they care if a preemption is coming. If a
126 * preempt is incoming, this will return TRUE, if you are in uthread context. A
127 * reasonable response for a uthread is to yield, and vcore_entry will deal with
128 * the preempt pending.
130 * If you call this from vcore context, it will do nothing. In general, it's
131 * not safe to just yield (or do whatever you plan on doing) from arbitrary
132 * places in vcore context. So we just lie about PP. */
133 static inline bool preempt_is_pending(uint32_t vcoreid)
135 if (in_vcore_context())
137 return __preempt_is_pending(vcoreid);
140 static inline bool __preempt_is_pending(uint32_t vcoreid)
142 return __procinfo.vcoremap[vcoreid].preempt_pending;