Skip to content

Fix and improve VTL switching loop and state management#545

Merged
sangho2 merged 8 commits intosanghle/lvbs/ktlsfrom
sanghle/lvbs/fix_vtl_switch
Jan 22, 2026
Merged

Fix and improve VTL switching loop and state management#545
sangho2 merged 8 commits intosanghle/lvbs/ktlsfrom
sanghle/lvbs/fix_vtl_switch

Conversation

@sangho2
Copy link
Contributor

@sangho2 sangho2 commented Dec 9, 2025

This PR fixes some bugs in the VTL switching loop and improve its reliability and performance.
Specifically, this PR uses assembly code to carefully switch between VTLs while saving/restoring
VTL0 registers. This PR removes some unreliable stack manipulation code we had before.
In addition, this PR makes it clear that we no longer store the VTL1 state in per-core storage.

Note: this PR and #541 should be merged together since #541 suffers from a crash due to
some bugs that this PR is fixing.

@sangho2 sangho2 marked this pull request as ready for review December 9, 2025 05:39
@wdcui wdcui requested review from CvvT and jstarks December 9, 2025 22:18
Copy link
Member

@wdcui wdcui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for improving the code, Sangho. I left a couple of comments below. Please wait for @jstarks 's review.

@sangho2 sangho2 force-pushed the sanghle/lvbs/fix_vtl_switch branch from 898c3d5 to 1cbad25 Compare December 18, 2025 22:47
Copy link
Member

@wdcui wdcui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me (1) why we have both per_cpu and ktls and (2) why we load/store vtl0 state from per_cpu via stack. I left some other minor comments.

/// `fn_save_state` is the function to save VTL state stored in the stack.
/// `scratch_off` is the offset of the kernel TLS which holds the scratch space to
/// save/restore the current stack pointer.
macro_rules! SAVE_VTL_STATE_ASM {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code like this should be moved out of mshv at some point?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to handle xsave here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xsave and xstore are handled inside vtl_switch_loop_body because we don't particularly need assembly code for it.

stringify!($scratch_off),
"]\n", // anchor
"sub rsp, ",
stringify!($state_size),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the rsp value after line 159 the same as after the call?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We save and restore rsp in Lines 156 and 177, respectively, using scrachpad.

"mov rsp, gs:[{kernel_sp_off}]", // reset kernel stack pointer. Hyper-V saves/restores rsp and rip.
VTL_RETURN_ASM!({vtl_ret_addr_off}),
// *** VTL1 resumes here regardless of the entry reason (VTL switch or intercept) ***
SAVE_VTL_STATE_ASM!({save_vtl0_state}, {scratch_off}),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we save the vtl0 state to the per cpu storage directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, using stack as temporary storage to save the current registers is one of the most reliable and efficient ways.

// is due to memory or register access violation, the VTL0 kernel might not have saved
// its states), we conservatively save and restore its extended states on every VTL switch.
with_per_cpu_variables_mut(|per_cpu_variables| {
per_cpu_variables.save_extended_states(HV_VTL_NORMAL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we make sure all the code executed before we get to this point doesn't change the extended state?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only executes some assembly code and memory copy operations. I agree that some compiler optimization might be able to use SSE though.

@sangho2
Copy link
Contributor Author

sangho2 commented Jan 19, 2026

It's not clear to me (1) why we have both per_cpu and ktls and (2) why we load/store vtl0 state from per_cpu via stack. I left some other minor comments.

The main reason I introduced KernelTls is that, assembly code cannot easily access PerCpuVariables because it is protected by RefCell (i.e., this is for Rust code not assembly code). KernelTls is named after ShimTls but at this point this is confusing because we no longer have ShimTls. Let me rename it (PerCpuVariablesAsm or something else).
I think using stack is most reliable and efficient way to save the current CPU registers. Also, as noted above, PerCpuVariables is protected by RefCell so assembly code cannot simply access it.

@praveen-pk
Copy link

this PR makes it clear that we no longer store the VTL1 state in per-core storage.

Is this being dropped because all VTL1 invocations can start with a fresh stack for now. Should this change be revisited once dynamic TAs are enabled?

@sangho2
Copy link
Contributor Author

sangho2 commented Jan 21, 2026

this PR makes it clear that we no longer store the VTL1 state in per-core storage.

Is this being dropped because all VTL1 invocations can start with a fresh stack for now. Should this change be revisited once dynamic TAs are enabled?

We shouldn't use per-core storage for saving the VTL1 state because, as discussed, we can't ensure that VTL1 is re-entered with the same core. We need a separate global data structure for this.

@sangho2 sangho2 force-pushed the sanghle/lvbs/fix_vtl_switch branch from f7e7331 to 9f80306 Compare January 22, 2026 05:33
@sangho2 sangho2 force-pushed the sanghle/lvbs/fix_vtl_switch branch from 9f80306 to c85aac5 Compare January 22, 2026 05:34
@sangho2
Copy link
Contributor Author

sangho2 commented Jan 22, 2026

Let me add XSAVE/XRSTORE when I merge #541. doing this in this PR is a bit tricky due to complicated rebase.

This PR adds `run_thread` support for LVBS platform and revise its
syscall handling routine based on
Linux userland platform's syscall handling. It has suppressed new page
table creation for now
because it needs to be done by the runner via an upcall (userspace
support still exists, but doesn't
create a separate one for each TA instance for now).

---------

Co-authored-by: Sangho Lee <sanghle@microsoft.com>
@sangho2 sangho2 merged commit dc8b467 into sanghle/lvbs/ktls Jan 22, 2026
4 of 8 checks passed
@sangho2 sangho2 deleted the sanghle/lvbs/fix_vtl_switch branch January 22, 2026 21:48
@sangho2 sangho2 restored the sanghle/lvbs/fix_vtl_switch branch January 23, 2026 03:54
Copy link
Contributor

@tgopinath-microsoft tgopinath-microsoft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved with comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants