| #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; \ |
| }) |
| |
| #error implement these |
| static bool has_refl_fault(struct user_context *ctx) |
| { |
| return 0; |
| } |
| |
| static void clear_refl_fault(struct user_context *ctx) |
| { |
| } |
| |
| static unsigned int __arch_refl_get_nr(struct user_context *ctx) |
| { |
| return 0; |
| } |
| |
| static unsigned int __arch_refl_get_err(struct user_context *ctx) |
| { |
| return 0; |
| } |
| |
| static unsigned long __arch_refl_get_aux(struct user_context *ctx) |
| { |
| return 0; |
| } |
| |
| #endif /* PARLIB_ARCH_VCORE_H */ |