| #ifndef PARLIB_ARCH_VCORE_H | 
 | #define PARLIB_ARCH_VCORE_H | 
 |  | 
 | #include <ros/common.h> | 
 | #include <ros/trapframe.h> | 
 | #include <arch/arch.h> | 
 | #include <ros/syscall.h> | 
 | #include <ros/procdata.h> | 
 | #include <assert.h> | 
 | #include <sys/vcore-tls.h> | 
 |  | 
 | #ifdef __riscv64 | 
 | # define REG_L "ld" | 
 | # define REG_S "sd" | 
 | #else | 
 | # define REG_L "lw" | 
 | # define REG_S "sw" | 
 | #endif | 
 |  | 
 | /* Register saves and restores happen in asm. */ | 
 | typedef void (*helper_fn)(struct hw_trapframe*, struct preempt_data*, uint32_t); | 
 | void __pop_ros_tf_regs(struct hw_trapframe *tf, struct preempt_data* vcpd, | 
 |                     uint32_t vcoreid, helper_fn helper) __attribute__((noreturn)); | 
 | void __save_ros_tf_regs(struct hw_trapframe *tf) __attribute__((returns_twice)); | 
 |  | 
 | /* Helper function that may handle notifications after re-enabling them. */ | 
 | static void __pop_ros_tf_notifs(struct hw_trapframe *tf, | 
 |                                 struct preempt_data* vcpd, uint32_t vcoreid) | 
 | { | 
 | 	vcpd->notif_disabled = FALSE; | 
 |  | 
 | 	__sync_synchronize(); | 
 |  | 
 | 	if(vcpd->notif_pending) | 
 | 		ros_syscall(SYS_self_notify, vcoreid, 0, 0, 0, 0, 0); | 
 | } | 
 |  | 
 | /* Helper function that won't handle notifications after re-enabling them. */ | 
 | static void __pop_ros_tf_notifs_raw(struct hw_trapframe *tf, | 
 |                                     struct preempt_data* vcpd, uint32_t vcoreid) | 
 | { | 
 | 	vcpd->notif_disabled = FALSE; | 
 | } | 
 |  | 
 | static inline void __pop_ros_tf(struct hw_trapframe *tf, uint32_t vcoreid, | 
 |                                 helper_fn helper) | 
 | { | 
 | 	// since we're changing the stack, move stuff into regs for now | 
 | 	register uint32_t _vcoreid = vcoreid; | 
 | 	register struct hw_trapframe* _tf = tf; | 
 |  | 
 | 	set_stack_pointer((void*)tf->gpr[GPR_SP]); | 
 |  | 
 | 	tf = _tf; | 
 | 	vcoreid = _vcoreid; | 
 | 	struct preempt_data* vcpd = &__procdata.vcore_preempt_data[vcoreid]; | 
 | 	__pop_ros_tf_regs(tf, vcpd, vcoreid, helper); | 
 | } | 
 |  | 
 | /* Pops a user context, reanabling notifications at the same time.  A Userspace | 
 |  * scheduler can call this when transitioning off the transition stack. | 
 |  * | 
 |  * Make sure you clear the notif_pending flag, and then check the queue before | 
 |  * calling this.  If notif_pending is not clear, this will self_notify this | 
 |  * core, since it should be because we missed a notification message while | 
 |  * notifs were disabled.  | 
 |  * | 
 |  * The important thing is that it can a notification after it enables | 
 |  * notifications, and when it gets resumed it can ultimately run the new | 
 |  * context.  Enough state is saved in the running context and stack to continue | 
 |  * running. */ | 
 | static inline void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid) | 
 | { | 
 | 	struct hw_trapframe *tf = &ctx->tf.hw_tf; | 
 | 	assert(ctx->type == ROS_HW_CTX); | 
 | 	__pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs); | 
 | } | 
 |  | 
 | /* Like the regular pop_user_ctx, but this one doesn't check or clear | 
 |  * notif_pending. */ | 
 | static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid) | 
 | { | 
 | 	struct hw_trapframe *tf = &ctx->tf.hw_tf; | 
 | 	assert(ctx->type == ROS_HW_CTX); | 
 | 	__pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs_raw); | 
 | } | 
 |  | 
 | /* Save the current context/registers into the given ctx, setting the pc of the | 
 |  * tf to the end of this function.  You only need to save that which you later | 
 |  * restore with pop_user_ctx(). */ | 
 | static inline void save_user_ctx(struct user_context *ctx) | 
 | { | 
 | 	struct hw_trapframe *tf = &ctx->tf.hw_tf; | 
 | 	ctx->type = ROS_HW_CTX; | 
 | 	__save_ros_tf_regs(tf); | 
 | } | 
 |  | 
 | static inline void init_user_ctx(struct user_context *ctx, uint32_t entry_pt, | 
 |                                  uint32_t stack_top) | 
 | { | 
 | 	struct hw_trapframe *u_tf = &ctx->tf.hw_tf; | 
 | 	ctx->type = ROS_HW_CTX; | 
 | 	memset(u_tf, 0, sizeof(*u_tf)); | 
 | 	u_tf->gpr[GPR_SP] = stack_top; | 
 | 	u_tf->epc = entry_pt; | 
 | } | 
 |  | 
 | #define __vcore_id_on_entry \ | 
 | ({ \ | 
 | 	register int temp asm ("a0"); \ | 
 | 	temp; \ | 
 | }) | 
 |  | 
 | #endif /* PARLIB_ARCH_VCORE_H */ |