2026-07-28 14:35:14 +08:00
|
|
|
|
/* linux_resume.c — Linux guest park-and-resume 唤醒实现。
|
|
|
|
|
|
*
|
|
|
|
|
|
* linux_resume() 通过 vmresume 唤醒已 HLT park 的 Linux guest。
|
|
|
|
|
|
* guest daemon 处理 IPC 请求后再次 HLT park,控制权返回 host。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 控制流与 linux_launch() 的 vmlaunch 对称:
|
|
|
|
|
|
* - 保存 host RSP 和返回 RIP
|
|
|
|
|
|
* - 执行 vmresume(成功则进入 guest,不返回)
|
|
|
|
|
|
* - guest HLT → VM-Exit → handle_hlt park → g_guest_terminated=1
|
|
|
|
|
|
* - vmexit_asm.S 恢复 host RSP,jmp 到返回 RIP
|
|
|
|
|
|
* - linux_resume() 继续执行,返回 0
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <utsm/linux_resume.h>
|
2026-10-01 23:13:42 +08:00
|
|
|
|
#include <utsm/linux_xsave.h>
|
2026-07-28 14:35:14 +08:00
|
|
|
|
#include <utsm/vmx.h>
|
|
|
|
|
|
#include <utsm/vmm.h>
|
|
|
|
|
|
#include <utsm/log.h>
|
|
|
|
|
|
#include <utsm/types.h>
|
|
|
|
|
|
|
2026-10-01 23:13:42 +08:00
|
|
|
|
/* Must be RIP-relative, not a stack slot: vmexit_asm restores guest GPRs
|
|
|
|
|
|
* (including RBP) before jumping here, so "=m"(local) can #PF at CR2≈0. */
|
|
|
|
|
|
int g_linux_resume_failed;
|
|
|
|
|
|
|
2026-07-28 14:35:14 +08:00
|
|
|
|
int linux_is_parked(void) {
|
|
|
|
|
|
return g_guest_parked ? 1 : 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int linux_resume(void) {
|
|
|
|
|
|
if (!g_guest_parked) {
|
|
|
|
|
|
log_warn("[LINUX] resume: guest not parked");
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 设置 active 标志:handle_hlt 检查此标志决定 park(而非 terminate) */
|
|
|
|
|
|
g_linux_guest_active = 1;
|
|
|
|
|
|
g_guest_terminated = 0;
|
|
|
|
|
|
g_guest_parked = 0;
|
2026-10-01 23:13:42 +08:00
|
|
|
|
vmx_linux_timeslice_reset();
|
|
|
|
|
|
linux_xsave_save_host();
|
|
|
|
|
|
linux_xsave_load_guest();
|
|
|
|
|
|
vmx_linux_prepare_entry();
|
2026-07-28 14:35:14 +08:00
|
|
|
|
|
2026-10-01 23:13:42 +08:00
|
|
|
|
/* vmresume 控制流(与 linux_launch 的 vmlaunch 对称)。
|
|
|
|
|
|
* clobber 全 GPR:从 park 跳回时 CPU 上是 guest 寄存器。 */
|
|
|
|
|
|
g_linux_resume_failed = 1;
|
2026-07-28 14:35:14 +08:00
|
|
|
|
__asm__ volatile(
|
2026-10-01 23:13:42 +08:00
|
|
|
|
"pushq %%rbx\n\t"
|
|
|
|
|
|
"pushq %%rbp\n\t"
|
|
|
|
|
|
"pushq %%r12\n\t"
|
|
|
|
|
|
"pushq %%r13\n\t"
|
|
|
|
|
|
"pushq %%r14\n\t"
|
|
|
|
|
|
"pushq %%r15\n\t"
|
|
|
|
|
|
"movq %%rsp, g_saved_host_rsp(%%rip)\n\t"
|
|
|
|
|
|
"leaq 1f(%%rip), %%rax\n\t"
|
|
|
|
|
|
"movq %%rax, g_saved_return_rip(%%rip)\n\t"
|
|
|
|
|
|
"vmresume\n\t"
|
|
|
|
|
|
"movl $1, g_linux_resume_failed(%%rip)\n\t"
|
2026-07-28 14:35:14 +08:00
|
|
|
|
"jmp 2f\n\t"
|
|
|
|
|
|
"1:\n\t"
|
2026-10-01 23:13:42 +08:00
|
|
|
|
"movl $0, g_linux_resume_failed(%%rip)\n\t"
|
2026-07-28 14:35:14 +08:00
|
|
|
|
"2:\n\t"
|
2026-10-01 23:13:42 +08:00
|
|
|
|
"popq %%r15\n\t"
|
|
|
|
|
|
"popq %%r14\n\t"
|
|
|
|
|
|
"popq %%r13\n\t"
|
|
|
|
|
|
"popq %%r12\n\t"
|
|
|
|
|
|
"popq %%rbp\n\t"
|
|
|
|
|
|
"popq %%rbx\n\t"
|
|
|
|
|
|
:
|
|
|
|
|
|
:
|
|
|
|
|
|
: "rax", "rcx", "rdx", "rsi", "rdi",
|
|
|
|
|
|
"r8", "r9", "r10", "r11", "cc", "memory"
|
2026-07-28 14:35:14 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/* 回到 host 上下文 */
|
|
|
|
|
|
g_linux_guest_active = 0;
|
2026-10-01 23:13:42 +08:00
|
|
|
|
g_guest_parked = 1;
|
|
|
|
|
|
vmx_linux_timeslice_disarm();
|
|
|
|
|
|
linux_xsave_save_guest();
|
|
|
|
|
|
linux_xsave_load_host();
|
2026-07-28 14:35:14 +08:00
|
|
|
|
|
2026-10-01 23:13:42 +08:00
|
|
|
|
if (g_linux_resume_failed) {
|
2026-07-28 14:35:14 +08:00
|
|
|
|
u64 error = vmx_vmcs_read(VMCS_VMX_INSTRUCTION_ERROR);
|
|
|
|
|
|
log_hex64("[LINUX] vmresume failed, error=", error);
|
|
|
|
|
|
return -2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|