Files
Deshab-OS/CODE/UTSM/vmm/vmexit.c
T
2026-07-28 12:00:02 +08:00

126 lines
4.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <utsm/vmx.h>
#include <utsm/ept.h>
#include <utsm/vmm.h>
#include <utsm/hypercall.h>
#include <utsm/ipc_shm.h>
#include <utsm/log.h>
#include <utsm/types.h>
/* VM-Exit 处理器:从 VMCS 读取 exit reason 与 guest 状态,分发处理。
*
* Phase 1.1:处理 HLT(终止 guest)、EPT violation(动态映射)、异常。
* Phase 1.3:增加 VMCALL hypercall 处理(读 guest GPR、分发、写返回值)。
*/
extern void vmx_vmresume_wrapper(void);
static u64 g_vmexit_count;
static void log_exit_diagnostics(u64 reason, u64 qualification, u64 rip, u64 len) {
log_hex64("[VMEXIT] reason=", reason);
log_hex64("[VMEXIT] qual=", qualification);
log_hex64("[VMEXIT] rip=", rip);
log_hex64("[VMEXIT] ilen=", len);
}
/* 处理 HLT:Phase 1.1 自检场景下表示 guest 完成测试,停止 guest。 */
static int handle_hlt(u64 rip, u64 instr_len, int *out_resume) {
*out_resume = 0; /* 不 resume,guest 终止 */
log_info("[VMEXIT] HLT - guest halted");
(void)rip; (void)instr_len;
return 0;
}
/* 处理 EPT violation:动态映射缺失的 GPA。
* Phase 1.1:1:1 映射缺失的页面,权限 RWX。 */
static int handle_ept_violation(u64 qualification, int *out_resume) {
u64 gpa = vmx_vmcs_read(VMCS_GUEST_PHYSICAL_ADDR);
u64 page = gpa & ~(EPT_PAGE_SIZE - 1);
log_hex64("[VMEXIT] EPT violation gpa=", gpa);
(void)qualification;
/* 1:1 映射该页(假设 HPA=GPA) */
if (ept_identity_map(page, EPT_PAGE_SIZE, EPT_RWX) != 0) {
log_error("[VMEXIT] failed to map EPT page");
*out_resume = 0;
return -1;
}
*out_resume = 1;
return 0;
}
/* 处理通用异常:打印诊断信息,终止 guest。 */
static int handle_exception(u64 qualification, u64 rip, int *out_resume) {
u64 intr_info = vmx_vmcs_read(0x4404); /* VM_EXIT_INTR_INFO */
log_hex64("[VMEXIT] exception intr_info=", intr_info);
log_hex64("[VMEXIT] exception qual=", qualification);
log_hex64("[VMEXIT] exception rip=", rip);
*out_resume = 0;
return 0;
}
/* VM-Exit 主分发器。从 vmx_vm_exit_handler(汇编入口)调用。
* 返回 1 表示 vmresume;0 表示终止 guest。 */
int vmexit_dispatch(void) {
u64 reason = vmx_vmcs_read(VMCS_EXIT_REASON) & 0xFFFF;
u64 qualification = vmx_vmcs_read(VMCS_EXIT_QUALIFICATION);
u64 rip = vmx_vmcs_read(VMCS_GUEST_RIP);
u64 instr_len = vmx_vmcs_read(VMCS_INSTRUCTION_LENGTH);
int resume = 0;
g_vmexit_count++;
switch (reason) {
case EXIT_HLT:
handle_hlt(rip, instr_len, &resume);
break;
case EXIT_EPT_VIOLATION:
handle_ept_violation(qualification, &resume);
break;
case EXIT_EXCEPTION_NMI:
handle_exception(qualification, rip, &resume);
break;
case EXIT_TRIPLE_FAULT:
log_error("[VMEXIT] triple fault");
resume = 0;
break;
case EXIT_CPUID:
/* 简化:让 guest 通过 CPUID,前进 RIP。Phase 1.2+ 完整模拟。 */
log_info("[VMEXIT] CPUID - skip");
vmx_vmcs_write(VMCS_GUEST_RIP, rip + instr_len);
resume = 1;
break;
case EXIT_IO_INSTRUCTION:
/* 简化:跳过 IO 指令。Phase 1.4 virtio-console 完整处理。 */
vmx_vmcs_write(VMCS_GUEST_RIP, rip + instr_len);
resume = 1;
break;
case EXIT_RDMSR:
case EXIT_WRMSR:
vmx_vmcs_write(VMCS_GUEST_RIP, rip + instr_len);
resume = 1;
break;
case EXIT_VMCALL:
/* VMCALL hypercall: read guest GPRs from g_guest_regs (saved by
* vmexit_asm.S), dispatch to the hypercall handler, and write
* the return value into g_guest_regs.rax. The handler also
* advances GUEST_RIP past the VMCALL instruction. */
{
int hcall_resume = hypercall_handle(
g_guest_regs.rax, g_guest_regs.rdi,
g_guest_regs.rsi, g_guest_regs.rdx,
rip, instr_len);
resume = hcall_resume;
}
break;
default:
log_exit_diagnostics(reason, qualification, rip, instr_len);
resume = 0;
break;
}
(void)qualification;
return resume;
}
u64 vmexit_get_count(void) { return g_vmexit_count; }