| #include <ros/syscall.h> | 
 | #include <parlib/vcore.h> | 
 | #include <parlib/stdio.h> | 
 | #include <stdlib.h> | 
 |  | 
 | /* Here's how the HW popping works:  It sets up the future stack pointer to | 
 |  * have extra stuff after it, and then it pops the registers, then pops the new | 
 |  * context's stack pointer.  Then it uses the extra stuff (the new PC is on the | 
 |  * stack, the location of notif_disabled, and a clobbered work register) to | 
 |  * enable notifs, make sure notif IPIs weren't pending, restore the work reg, | 
 |  * and then "ret". | 
 |  * | 
 |  * However, we can't just put the extra stuff directly below the rsp.  We need | 
 |  * to leave room for the redzone: area that is potentially being used.  (Even if | 
 |  * you compile with -mno-red-zone, some asm code (glibc memcpy) will still use | 
 |  * that area). | 
 |  * | 
 |  * This is what the target uthread's stack will look like (growing down): | 
 |  * | 
 |  * Target RSP -> |   u_thread's old stuff   | the future %rsp, tf->tf_rsp | 
 |  *               |            .             | beginning of Red Zone | 
 |  *               |            .             | | 
 |  *               |   128 Bytes of Red Zone  | | 
 |  *               |            .             | | 
 |  *               |            .             | end of Red Zone | 
 |  *               |   new rip                | 0x08 below Red (one slot is 0x08) | 
 |  *               |   rflags space           | 0x10 below | 
 |  *               |   rdi save space         | 0x18 below | 
 |  *               |   *sysc ptr to syscall   | 0x20 below | 
 |  *               |   notif_pending_loc      | 0x28 below | 
 |  *               |   notif_disabled_loc     | 0x30 below | 
 |  * | 
 |  * The important thing is that it can handle 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. | 
 |  * | 
 |  * Related to that is whether or not our stack pointer is sufficiently far down | 
 |  * so that restarting *this* code won't clobber shit we need later.  The way we | 
 |  * do this is that we do any "stack jumping" before we enable interrupts/notifs. | 
 |  * These jumps are when we directly modify rsp, specifically in the down | 
 |  * direction (subtracts).  Adds would be okay. */ | 
 |  | 
 | /* Helper for writing the info we need later to the u_tf's stack.  Also, note | 
 |  * this goes backwards, since memory reads up the stack. */ | 
 | struct restart_helper { | 
 | 	void				*notif_disab_loc; | 
 | 	void				*notif_pend_loc; | 
 | 	struct syscall			*sysc; | 
 | 	uint64_t			rdi_save; | 
 | 	uint64_t			rflags; | 
 | 	uint64_t			rip; | 
 | }; | 
 |  | 
 | /* Static syscall, used for self-notifying.  We never wait on it, and we | 
 |  * actually might submit it multiple times in parallel on different cores! | 
 |  * While this may seem dangerous, the kernel needs to be able to handle this | 
 |  * scenario.  It's also important that we never wait on this, since for all but | 
 |  * the first call, the DONE flag will be set.  (Set once, then never reset) */ | 
 | struct syscall vc_entry = { | 
 | 	.num = SYS_vc_entry, | 
 | 	.err = 0, | 
 | 	.retval = 0, | 
 | 	.flags = 0, | 
 | 	.ev_q = 0, | 
 | 	.u_data = 0, | 
 | 	.arg0 = 0, | 
 | 	.arg1 = 0, | 
 | 	.arg2 = 0, | 
 | 	.arg3 = 0, | 
 | 	.arg4 = 0, | 
 | 	.arg5 = 0, | 
 | }; | 
 |  | 
 | static void pop_hw_tf(struct hw_trapframe *tf, uint32_t vcoreid) | 
 | { | 
 | 	#define X86_RED_ZONE_SZ		128 | 
 | 	struct restart_helper *rst; | 
 | 	struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid]; | 
 |  | 
 | 	/* The stuff we need to write will be below the current stack and red | 
 | 	 * zone of the utf */ | 
 | 	rst = (struct restart_helper*)((void*)tf->tf_rsp - X86_RED_ZONE_SZ - | 
 | 	                               sizeof(struct restart_helper)); | 
 | 	/* Fill in the info we'll need later */ | 
 | 	rst->notif_disab_loc = &vcpd->notif_disabled; | 
 | 	rst->notif_pend_loc = &vcpd->notif_pending; | 
 | 	rst->sysc = &vc_entry; | 
 | 	rst->rdi_save = 0;			/* avoid bugs */ | 
 | 	rst->rflags = tf->tf_rflags; | 
 | 	rst->rip = tf->tf_rip; | 
 |  | 
 | 	asm volatile ("movq %0, %%rsp;       " /* jump rsp to the utf */ | 
 | 	              "popq %%rax;           " /* restore registers */ | 
 | 	              "popq %%rbx;           " | 
 | 	              "popq %%rcx;           " | 
 | 	              "popq %%rdx;           " | 
 | 	              "popq %%rbp;           " | 
 | 	              "popq %%rsi;           " | 
 | 	              "popq %%rdi;           " | 
 | 	              "popq %%r8;            " | 
 | 	              "popq %%r9;            " | 
 | 	              "popq %%r10;           " | 
 | 	              "popq %%r11;           " | 
 | 	              "popq %%r12;           " | 
 | 	              "popq %%r13;           " | 
 | 	              "popq %%r14;           " | 
 | 	              "popq %%r15;           " | 
 | 	              "addq $0x28, %%rsp;    " /* move to rsp slot in the tf */ | 
 | 	              "popq %%rsp;           " /* change to the utf's %rsp */ | 
 | 	              "subq %[red], %%rsp;   " /* jump over the redzone */ | 
 | 	              "subq $0x10, %%rsp;    " /* move rsp to below rdi's slot*/ | 
 | 	              "pushq %%rdi;          " /* save rdi, will clobber soon */ | 
 | 	              "subq $0x18, %%rsp;    " /* move to notif_dis_loc slot */ | 
 | 	              "popq %%rdi;           " /* load notif_disabled addr */ | 
 | 	              "movb $0x00, (%%rdi);  " /* enable notifications */ | 
 | 	              /* Need a wrmb() here so the write of enable_notif can't | 
 | 	               * pass the read of notif_pending (racing with a potential | 
 | 	               * cross-core call with proc_notify()). */ | 
 | 	              "lock addb $0, (%%rdi);" /* LOCK is a CPU mb() */ | 
 | 	              /* From here down, we can get interrupted and restarted */ | 
 | 	              "popq %%rdi;           " /* get notif_pending status loc*/ | 
 | 	              "testb $0x01, (%%rdi); " /* test if a notif is pending */ | 
 | 	              "jz 1f;                " /* if not pending skip syscall */ | 
 | 	              /* Actual syscall. Note we don't wait on the async call */ | 
 | 	              "popq %%rdi;           " /* &sysc, trap arg0 */ | 
 | 	              "pushq %%rsi;          " /* save rax, will be trap arg1 */ | 
 | 	              "pushq %%rax;          " /* save rax, will be trap ret */ | 
 | 	              "movq $0x1, %%rsi;     " /* send one async syscall: arg1*/ | 
 | 	              "int %1;               " /* fire the syscall */ | 
 | 	              "popq %%rax;           " /* restore regs after syscall */ | 
 | 	              "popq %%rsi;           " | 
 | 	              "jmp 2f;               " /* skip 1:, already popped */ | 
 | 	              "1: addq $0x08, %%rsp; " /* discard &sysc on non-sc path*/ | 
 | 	              "2: popq %%rdi;        " /* restore tf's %rdi both paths*/ | 
 | 	              "popfq;                " /* restore utf's rflags */ | 
 | 	              "ret %[red];           " /* ret to the new PC, skip red */ | 
 | 	              : | 
 | 	              : "g"(&tf->tf_rax), "i"(T_SYSCALL), | 
 | 		        [red]"i"(X86_RED_ZONE_SZ) | 
 | 	              : "memory"); | 
 | } | 
 |  | 
 | static void pop_sw_tf(struct sw_trapframe *sw_tf, uint32_t vcoreid) | 
 | { | 
 | 	struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid]; | 
 |  | 
 | 	/* Restore callee-saved FPU state.  We need to clear exceptions before | 
 | 	 * reloading the FP CW, in case the new CW unmasks any.  We also need to | 
 | 	 * reset the tag word to clear out the stack. | 
 | 	 * | 
 | 	 * The main issue here is that while our context was saved in an | 
 | 	 * ABI-complaint manner, we may be starting up on a somewhat random FPU | 
 | 	 * state.  Having gibberish in registers isn't a big deal, but some of | 
 | 	 * the FP environment settings could cause trouble.  If fnclex; emms | 
 | 	 * isn't enough, we could also save/restore the entire FP env with | 
 | 	 * fldenv, or do an fninit before fldcw. */ | 
 | 	asm volatile ("ldmxcsr %0" : : "m"(sw_tf->tf_mxcsr)); | 
 | 	asm volatile ("fnclex; emms; fldcw %0" : : "m"(sw_tf->tf_fpucw)); | 
 | 	/* Basic plan: restore all regs, off rcx as the sw_tf.  Switch to the | 
 | 	 * new stack, save the PC so we can jump to it later.  Use clobberably | 
 | 	 * registers for the locations of sysc, notif_dis, and notif_pend. Once | 
 | 	 * on the new stack, we enable notifs, check if we missed one, and if | 
 | 	 * so, self notify.  Note the syscall clobbers rax. */ | 
 | 	asm volatile ("movq 0x00(%0), %%rbx; " /* restore regs */ | 
 | 	              "movq 0x08(%0), %%rbp; " | 
 | 	              "movq 0x10(%0), %%r12; " | 
 | 	              "movq 0x18(%0), %%r13; " | 
 | 	              "movq 0x20(%0), %%r14; " | 
 | 	              "movq 0x28(%0), %%r15; " | 
 | 	              "movq 0x30(%0), %%r8;  " /* save rip in r8 */ | 
 | 	              "movq 0x38(%0), %%rsp; " /* jump to future stack */ | 
 | 	              "movb $0x00, (%2);     " /* enable notifications */ | 
 | 	              /* Need a wrmb() here so the write of enable_notif can't | 
 | 	               * pass the read of notif_pending (racing with a potential | 
 | 	               * cross-core call with proc_notify()). */ | 
 | 	              "lock addb $0, (%2);   " /* LOCK is a CPU mb() */ | 
 | 	              /* From here down, we can get interrupted and restarted */ | 
 | 	              "testb $0x01, (%3);    " /* test if a notif is pending */ | 
 | 	              "jz 1f;                " /* if not pending, skip syscall*/ | 
 | 	              /* Actual syscall.  Note we don't wait on the async call. | 
 | 	               * &vc_entry is already in rdi (trap arg0). */ | 
 | 	              "movq $0x1, %%rsi;     " /* send one async syscall: arg1*/ | 
 | 	              "int %4;               " /* fire the syscall */ | 
 | 	              "1: jmp *%%r8;         " /* ret saved earlier */ | 
 | 	              : | 
 | 	              : "c"(&sw_tf->tf_rbx), | 
 | 	                "D"(&vc_entry), | 
 | 	                "S"(&vcpd->notif_disabled), | 
 | 	                "d"(&vcpd->notif_pending), | 
 | 	                "i"(T_SYSCALL) | 
 | 	              : "memory"); | 
 | } | 
 |  | 
 | /* Pops a user context, reanabling notifications at the same time.  A Userspace | 
 |  * scheduler can call this when transitioning off the transition stack. | 
 |  * | 
 |  * pop_user_ctx will fail if we have a notif_pending; you're not allowed to | 
 |  * leave vcore context with notif_pending set.  Some code in vcore_entry | 
 |  * needs clear notif_pending and check whatever might have caused a notif | 
 |  * (e.g. call handle_events()). | 
 |  * | 
 |  * 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. */ | 
 | void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid) | 
 | { | 
 | 	struct preempt_data *vcpd = vcpd_of(vcoreid); | 
 |  | 
 | 	/* We check early for notif_pending, since if we deal with it during | 
 | 	 * pop_hw_tf, we grow the stack slightly.  If a thread consistently | 
 | 	 * fails to restart due to notif pending, it will eventually run off the | 
 | 	 * bottom of its stack.  By performing the check here, we shrink that | 
 | 	 * window.  You'd have to have a notif come after this check, but also | 
 | 	 * *not* before this check.  If you PF in pop_user_ctx, this all failed. | 
 | 	 * */ | 
 | 	if (vcpd->notif_pending) { | 
 | 		/* if pop_user_ctx fails (and resets the vcore), the ctx | 
 | 		 * contents must be in VCPD (due to !UTHREAD_SAVED).  it might | 
 | 		 * already be there. */ | 
 | 		if (ctx != &vcpd->uthread_ctx) | 
 | 			vcpd->uthread_ctx = *ctx; | 
 | 		/* To restart the vcore, we must have the right TLS, stack | 
 | 		 * pointer, and vc_ctx = TRUE. */ | 
 | 		set_tls_desc((void*)vcpd->vcore_tls_desc); | 
 | 		begin_safe_access_tls_vars() | 
 | 		__vcore_context = TRUE; | 
 | 		end_safe_access_tls_vars() | 
 | 		set_stack_pointer((void*)vcpd->vcore_stack); | 
 | 		vcore_entry(); | 
 | 	} | 
 | 	switch (ctx->type) { | 
 | 	case ROS_HW_CTX: | 
 | 		pop_hw_tf(&ctx->tf.hw_tf, vcoreid); | 
 | 		break; | 
 | 	case ROS_SW_CTX: | 
 | 		pop_sw_tf(&ctx->tf.sw_tf, vcoreid); | 
 | 		break; | 
 | 	case ROS_VM_CTX: | 
 | 		ros_syscall(SYS_pop_ctx, ctx, 0, 0, 0, 0, 0); | 
 | 		break; | 
 | 	} | 
 | 	assert(0); | 
 | } | 
 |  | 
 | /* Like the regular pop_user_ctx, but this one doesn't check or clear | 
 |  * notif_pending.  The only case where we use this is when an IRQ/notif | 
 |  * interrupts a uthread that is in the process of disabling notifs. | 
 |  * | 
 |  * If we need to support VM_CTXs here, we'll need to tell the kernel whether or | 
 |  * not we want to enable_notifs (flag to SYS_pop_ctx).  The only use case for | 
 |  * this is when disabling notifs.  Currently, a VM can't do this or do things | 
 |  * like uthread_yield.  It doesn't have access to the vcore's or uthread's TLS | 
 |  * to bootstrap any of that stuff. */ | 
 | void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid) | 
 | { | 
 | 	struct hw_trapframe *tf = &ctx->tf.hw_tf; | 
 | 	struct restart_helper *rst; | 
 | 	struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid]; | 
 |  | 
 | 	assert(ctx->type == ROS_HW_CTX); | 
 | 	/* The stuff we need to write will be below the current stack of the utf | 
 | 	 */ | 
 | 	rst = (struct restart_helper*)((void*)tf->tf_rsp - | 
 | 	                               sizeof(struct restart_helper)); | 
 | 	/* Fill in the info we'll need later */ | 
 | 	rst->notif_disab_loc = &vcpd->notif_disabled; | 
 | 	rst->rdi_save = 0;			/* avoid bugs */ | 
 | 	rst->rflags = tf->tf_rflags; | 
 | 	rst->rip = tf->tf_rip; | 
 |  | 
 | 	asm volatile ("movq %0, %%rsp;       " /* jump esp to the utf */ | 
 | 	              "popq %%rax;           " /* restore registers */ | 
 | 	              "popq %%rbx;           " | 
 | 	              "popq %%rcx;           " | 
 | 	              "popq %%rdx;           " | 
 | 	              "popq %%rbp;           " | 
 | 	              "popq %%rsi;           " | 
 | 	              "popq %%rdi;           " | 
 | 	              "popq %%r8;            " | 
 | 	              "popq %%r9;            " | 
 | 	              "popq %%r10;           " | 
 | 	              "popq %%r11;           " | 
 | 	              "popq %%r12;           " | 
 | 	              "popq %%r13;           " | 
 | 	              "popq %%r14;           " | 
 | 	              "popq %%r15;           " | 
 | 	              "addq $0x28, %%rsp;    " /* move to rsp slot in the tf */ | 
 | 	              "popq %%rsp;           " /* change to the utf's %rsp */ | 
 | 	              "subq $0x10, %%rsp;    " /* move rsp to below rdi's slot*/ | 
 | 	              "pushq %%rdi;          " /* save rdi, will clobber soon */ | 
 | 	              "subq $0x18, %%rsp;    " /* move to notif_dis_loc slot */ | 
 | 	              "popq %%rdi;           " /* load notif_disabled addr */ | 
 | 	              "movb $0x00, (%%rdi);  " /* enable notifications */ | 
 | 	              /* Here's where we differ from the regular pop_user_ctx(). | 
 | 	               * We need to adjust rsp and whatnot, but don't do test, | 
 | 	               * clear notif_pending, or call a syscall. */ | 
 | 	              /* From here down, we can get interrupted and restarted */ | 
 | 	              "addq $0x10, %%rsp;    " /* move to rdi save slot */ | 
 | 	              "popq %%rdi;           " /* restore tf's %rdi */ | 
 | 	              "popfq;                " /* restore utf's rflags */ | 
 | 	              "ret;                  " /* return to the new PC */ | 
 | 	              : | 
 | 	              : "g"(&tf->tf_rax) | 
 | 	              : "memory"); | 
 | } | 
 |  | 
 | void fprintf_hw_tf(FILE *f, struct hw_trapframe *hw_tf) | 
 | { | 
 | 	fprintf(f, "[user] HW TRAP frame 0x%016x\n", hw_tf); | 
 | 	fprintf(f, "  rax  0x%016lx\n",           hw_tf->tf_rax); | 
 | 	fprintf(f, "  rbx  0x%016lx\n",           hw_tf->tf_rbx); | 
 | 	fprintf(f, "  rcx  0x%016lx\n",           hw_tf->tf_rcx); | 
 | 	fprintf(f, "  rdx  0x%016lx\n",           hw_tf->tf_rdx); | 
 | 	fprintf(f, "  rbp  0x%016lx\n",           hw_tf->tf_rbp); | 
 | 	fprintf(f, "  rsi  0x%016lx\n",           hw_tf->tf_rsi); | 
 | 	fprintf(f, "  rdi  0x%016lx\n",           hw_tf->tf_rdi); | 
 | 	fprintf(f, "  r8   0x%016lx\n",           hw_tf->tf_r8); | 
 | 	fprintf(f, "  r9   0x%016lx\n",           hw_tf->tf_r9); | 
 | 	fprintf(f, "  r10  0x%016lx\n",           hw_tf->tf_r10); | 
 | 	fprintf(f, "  r11  0x%016lx\n",           hw_tf->tf_r11); | 
 | 	fprintf(f, "  r12  0x%016lx\n",           hw_tf->tf_r12); | 
 | 	fprintf(f, "  r13  0x%016lx\n",           hw_tf->tf_r13); | 
 | 	fprintf(f, "  r14  0x%016lx\n",           hw_tf->tf_r14); | 
 | 	fprintf(f, "  r15  0x%016lx\n",           hw_tf->tf_r15); | 
 | 	fprintf(f, "  trap 0x%08x\n",             hw_tf->tf_trapno); | 
 | 	fprintf(f, "  gsbs 0x%016lx\n",           hw_tf->tf_gsbase); | 
 | 	fprintf(f, "  fsbs 0x%016lx\n",           hw_tf->tf_fsbase); | 
 | 	fprintf(f, "  err  0x--------%08x\n",     hw_tf->tf_err); | 
 | 	fprintf(f, "  rip  0x%016lx\n",           hw_tf->tf_rip); | 
 | 	fprintf(f, "  cs   0x------------%04x\n", hw_tf->tf_cs); | 
 | 	fprintf(f, "  flag 0x%016lx\n",           hw_tf->tf_rflags); | 
 | 	fprintf(f, "  rsp  0x%016lx\n",           hw_tf->tf_rsp); | 
 | 	fprintf(f, "  ss   0x------------%04x\n", hw_tf->tf_ss); | 
 | } | 
 |  | 
 | void fprintf_sw_tf(FILE *f, struct sw_trapframe *sw_tf) | 
 | { | 
 | 	fprintf(f, "[user] SW TRAP frame 0x%016p\n", sw_tf); | 
 | 	fprintf(f, "  rbx  0x%016lx\n",           sw_tf->tf_rbx); | 
 | 	fprintf(f, "  rbp  0x%016lx\n",           sw_tf->tf_rbp); | 
 | 	fprintf(f, "  r12  0x%016lx\n",           sw_tf->tf_r12); | 
 | 	fprintf(f, "  r13  0x%016lx\n",           sw_tf->tf_r13); | 
 | 	fprintf(f, "  r14  0x%016lx\n",           sw_tf->tf_r14); | 
 | 	fprintf(f, "  r15  0x%016lx\n",           sw_tf->tf_r15); | 
 | 	fprintf(f, "  gsbs 0x%016lx\n",           sw_tf->tf_gsbase); | 
 | 	fprintf(f, "  fsbs 0x%016lx\n",           sw_tf->tf_fsbase); | 
 | 	fprintf(f, "  rip  0x%016lx\n",           sw_tf->tf_rip); | 
 | 	fprintf(f, "  rsp  0x%016lx\n",           sw_tf->tf_rsp); | 
 | 	fprintf(f, " mxcsr 0x%08x\n",             sw_tf->tf_mxcsr); | 
 | 	fprintf(f, " fpucw 0x%04x\n",             sw_tf->tf_fpucw); | 
 | } | 
 |  | 
 | void fprintf_vm_tf(FILE *f, struct vm_trapframe *vm_tf) | 
 | { | 
 | 	fprintf(f, "[user] VM Trapframe 0x%016x\n", vm_tf); | 
 | 	fprintf(f, "  rax  0x%016lx\n",           vm_tf->tf_rax); | 
 | 	fprintf(f, "  rbx  0x%016lx\n",           vm_tf->tf_rbx); | 
 | 	fprintf(f, "  rcx  0x%016lx\n",           vm_tf->tf_rcx); | 
 | 	fprintf(f, "  rdx  0x%016lx\n",           vm_tf->tf_rdx); | 
 | 	fprintf(f, "  rbp  0x%016lx\n",           vm_tf->tf_rbp); | 
 | 	fprintf(f, "  rsi  0x%016lx\n",           vm_tf->tf_rsi); | 
 | 	fprintf(f, "  rdi  0x%016lx\n",           vm_tf->tf_rdi); | 
 | 	fprintf(f, "  r8   0x%016lx\n",           vm_tf->tf_r8); | 
 | 	fprintf(f, "  r9   0x%016lx\n",           vm_tf->tf_r9); | 
 | 	fprintf(f, "  r10  0x%016lx\n",           vm_tf->tf_r10); | 
 | 	fprintf(f, "  r11  0x%016lx\n",           vm_tf->tf_r11); | 
 | 	fprintf(f, "  r12  0x%016lx\n",           vm_tf->tf_r12); | 
 | 	fprintf(f, "  r13  0x%016lx\n",           vm_tf->tf_r13); | 
 | 	fprintf(f, "  r14  0x%016lx\n",           vm_tf->tf_r14); | 
 | 	fprintf(f, "  r15  0x%016lx\n",           vm_tf->tf_r15); | 
 | 	fprintf(f, "  rip  0x%016lx\n",           vm_tf->tf_rip); | 
 | 	fprintf(f, "  rflg 0x%016lx\n",           vm_tf->tf_rflags); | 
 | 	fprintf(f, "  rsp  0x%016lx\n",           vm_tf->tf_rsp); | 
 | 	fprintf(f, "  cr2  0x%016lx\n",           vm_tf->tf_cr2); | 
 | 	fprintf(f, "  cr3  0x%016lx\n",           vm_tf->tf_cr3); | 
 | 	fprintf(f, "Gpcore 0x%08x\n",             vm_tf->tf_guest_pcoreid); | 
 | 	fprintf(f, "Flags  0x%08x\n",             vm_tf->tf_flags); | 
 | 	fprintf(f, "Inject 0x%08x\n",             vm_tf->tf_trap_inject); | 
 | 	fprintf(f, "ExitRs 0x%08x\n",             vm_tf->tf_exit_reason); | 
 | 	fprintf(f, "ExitQl 0x%08x\n",             vm_tf->tf_exit_qual); | 
 | 	fprintf(f, "Intr1  0x%016lx\n",           vm_tf->tf_intrinfo1); | 
 | 	fprintf(f, "Intr2  0x%016lx\n",           vm_tf->tf_intrinfo2); | 
 | 	fprintf(f, "GIntr  0x----%04x\n",         vm_tf->tf_guest_intr_status); | 
 | 	fprintf(f, "GVA    0x%016lx\n",           vm_tf->tf_guest_va); | 
 | 	fprintf(f, "GPA    0x%016lx\n",           vm_tf->tf_guest_pa); | 
 | } | 
 |  | 
 | void print_user_context(struct user_context *ctx) | 
 | { | 
 | 	switch (ctx->type) { | 
 | 	case ROS_HW_CTX: | 
 | 		fprintf_hw_tf(stdout, &ctx->tf.hw_tf); | 
 | 		break; | 
 | 	case ROS_SW_CTX: | 
 | 		fprintf_sw_tf(stdout, &ctx->tf.sw_tf); | 
 | 		break; | 
 | 	case ROS_VM_CTX: | 
 | 		fprintf_vm_tf(stdout, &ctx->tf.vm_tf); | 
 | 		break; | 
 | 	default: | 
 | 		fprintf(stderr, "Unknown context type %d\n", ctx->type); | 
 | 	} | 
 | } | 
 |  | 
 | /* The second-lowest level function jumped to by the kernel on every vcore | 
 |  * entry.  We get called from __kernel_vcore_entry. | 
 |  * | 
 |  * We should consider making it mandatory to set the tls_desc in the kernel. We | 
 |  * wouldn't even need to pass the vcore id to user space at all if we did this. | 
 |  * It would already be set in the preinstalled TLS as __vcore_id. */ | 
 | void __attribute__((noreturn)) __kvc_entry_c(void) | 
 | { | 
 | 	/* The kernel sets the TLS desc for us, based on whatever is in VCPD. | 
 | 	 * | 
 | 	 * x86 32-bit TLS is pretty jacked up, so the kernel doesn't set the TLS | 
 | 	 * desc for us.  it's a little more expensive to do it here, esp for | 
 | 	 * amd64.  Can remove this when/if we overhaul 32 bit TLS. */ | 
 | 	int id = __vcore_id_on_entry; | 
 |  | 
 | 	#ifndef __x86_64__ | 
 | 	set_tls_desc(vcpd_of(id)->vcore_tls_desc); | 
 | 	#endif | 
 | 	/* Every time the vcore comes up, it must set that it is in vcore | 
 | 	 * context.  uthreads may share the same TLS as their vcore (when | 
 | 	 * uthreads do not have their own TLS), and if a uthread was preempted, | 
 | 	 * __vcore_context == FALSE, and that will continue to be true the next | 
 | 	 * time the vcore pops up. */ | 
 | 	__vcore_context = TRUE; | 
 | 	vcore_entry(); | 
 | 	fprintf(stderr, "vcore_entry() should never return!\n"); | 
 | 	abort(); | 
 | 	__builtin_unreachable(); | 
 | } |