linux-5.6
函数角度
架构无关部分 在 virt
架构相关部分 在 arch/arm/kvm
__init_stage2_translation // 没被 virt 调用
__kvm_arm_vcpu_get_events
__kvm_arm_vcpu_set_events
__kvm_flush_vm_context
__kvm_hyp_init
__kvm_tlb_flush_local_vmid
__kvm_tlb_flush_vmid
__kvm_tlb_flush_vmid_ipa
__kvm_vcpu_run_nvhe
__vcpu_spsr // 没被 virt 调用
handle_exit
kvm_arch_vcpu_ioctl_get_fpu
kvm_arch_vcpu_ioctl_get_regs
kvm_arch_vcpu_ioctl_get_sregs
kvm_arch_vcpu_ioctl_set_fpu
kvm_arch_vcpu_ioctl_set_guest_debug
kvm_arch_vcpu_ioctl_set_regs
kvm_arch_vcpu_ioctl_set_sregs
kvm_arch_vcpu_ioctl_translate
kvm_arm_copy_reg_indices
kvm_arm_get_reg
kvm_arm_num_regs
kvm_arm_set_reg
kvm_arm_vcpu_arch_get_attr
kvm_arm_vcpu_arch_has_attr
kvm_arm_vcpu_arch_set_attr
kvm_coproc_table_init
kvm_inject_vabt
kvm_reset_vcpu
kvm_target_cpu
kvm_vcpu_preferred_target
vgic_v3_cpu_sysregs_uaccess
vgic_v3_has_cpu_sysregs_attr
初始化角度
virt/kvm/arm/arm.c
module_init(arm_init);
kvm_init
...
运行时角度
// arm 的 kvm 代码(包括架构和非架构相关) 运行在 两个mode
// 有 __hyp_text 标识的 运行在 hyp mode
vcpu 对应一个 fd ,对应一个 file_operations , 为 kvm_vcpu_fops
static struct file_operations kvm_vcpu_fops = {
.release = kvm_vcpu_release,
.unlocked_ioctl = kvm_vcpu_ioctl,
.mmap = kvm_vcpu_mmap,
.llseek = noop_llseek,
KVM_COMPAT(kvm_vcpu_compat_ioctl),
};
kvm_vcpu_ioctl // virt/kvm/kvm_main.c
switch (ioctl) {
case KVM_RUN: {
oldpid = rcu_access_pointer(vcpu->pid);
kvm_arch_vcpu_ioctl_run(vcpu, vcpu->run); // virt/kvm/arm/arm.c
kvm_vcpu_first_run_init
kvm_arm_vcpu_is_finalized
kvm_timer_enable
kvm_arm_pmu_v3_enable
while (ret > 0) {
...
/**************************************************************
* Enter the guest
* /
trace_kvm_entry(*vcpu_pc(vcpu));
guest_enter_irqoff();
if (has_vhe()) {ret = kvm_vcpu_run_vhe(vcpu);}
else {ret = kvm_call_hyp_ret(__kvm_vcpu_run_nvhe, vcpu);}
vcpu->mode = OUTSIDE_GUEST_MODE;
vcpu->stat.exits++;
/*
* Back from guest
*************************************************************/
...
guest_exit
handle_exit
}
}
}
__kvm_vcpu_run_nvhe // __hyp_text
/* Jump in the fire! */
again:
exit_code = __guest_enter(vcpu, host_ctxt); // 该行执行后,进入虚拟机, 下一行就是返回.
/* And we're baaack! */
// arch/arm/kvm/hyp/entry.S
/* int __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host) */
ENTRY(__guest_enter)
@ Save host registers
add r1, r1, #(USR_REGS_OFFSET + S_R4)
stm r1!, {r4-r12}
str lr, [r1, #4] @ Skip SP_usr (already saved)
@ Restore guest registers
add r0, r0, #(VCPU_GUEST_CTXT + USR_REGS_OFFSET + S_R0)
ldr lr, [r0, #S_LR]
ldm r0, {r0-r12}
clrex
eret // 该指令后进入 虚拟机
ENDPROC(__guest_enter)
我们知道返回时的第一条指令
__guest_enter 会进入,那什么时候返回呢?不知道
ENTRY(__guest_exit)
/*
* return convention:
* guest r0, r1, r2 saved on the stack
* r0: vcpu pointer
* r1: exception code
*/
add r2, r0, #(VCPU_GUEST_CTXT + USR_REGS_OFFSET + S_R3)
stm r2!, {r3-r12}
str lr, [r2, #4]
add r2, r0, #(VCPU_GUEST_CTXT + USR_REGS_OFFSET + S_R0)
pop {r3, r4, r5} @ r0, r1, r2
stm r2, {r3-r5}
ldr r0, [r0, #VCPU_HOST_CTXT]
add r0, r0, #(USR_REGS_OFFSET + S_R4)
ldm r0!, {r4-r12}
ldr lr, [r0, #4]
mov r0, r1
mrs r1, SPSR
mrs r2, ELR_hyp
mrc p15, 4, r3, c5, c2, 0 @ HSR
/*
* Force loads and stores to complete before unmasking aborts
* and forcing the delivery of the exception. This gives us a
* single instruction window, which the handler will try to
* match.
*/
dsb sy
cpsie a
.global abort_guest_exit_start
abort_guest_exit_start:
isb
.global abort_guest_exit_end
abort_guest_exit_end:
/*
* If we took an abort, r0[31] will be set, and cmp will set
* the N bit in PSTATE.
*/
cmp r0, #0
msrmi SPSR_cxsf, r1
msrmi ELR_hyp, r2
mcrmi p15, 4, r3, c5, c2, 0 @ HSR
bx lr
ENDPROC(__guest_exit)
arch/arm/kvm/hyp/hyp-entry.S
guest_trap: // hyp_hvc
load_vcpu r0 @ Load VCPU pointer to r0
#ifdef CONFIG_VFPv3
@ Check for a VFP access
lsr r1, r1, #HSR_EC_SHIFT
cmp r1, #HSR_EC_CP_0_13
beq __vfp_guest_restore
#endif
mov r1, #ARM_EXCEPTION_HVC
b __guest_exit
hyp_irq:
push {r0, r1, r2}
mov r1, #ARM_EXCEPTION_IRQ
load_vcpu r0 @ Load VCPU pointer to r0
b __guest_exit
arch/arm/kvm/hyp/hyp-entry.S
.align 5
__kvm_hyp_vector:
.global __kvm_hyp_vector
@ Hyp-mode exception vector
W(b) hyp_reset
W(b) hyp_undef
W(b) hyp_svc
W(b) hyp_pabt
W(b) hyp_dabt
W(b) hyp_hvc
W(b) hyp_irq
W(b) hyp_fiq
.macro vect_br val, targ
ARM( eor sp, sp, #\val )
ARM( tst sp, #7 )
ARM( eorne sp, sp, #\val )
THUMB( cmp r1, #\val )
THUMB( popeq {r1, r2} )
beq \targ
.endm
vect_br 0, hyp_fiq
vect_br 1, hyp_irq
vect_br 2, hyp_hvc
vect_br 3, hyp_dabt
vect_br 4, hyp_pabt
vect_br 5, hyp_svc
vect_br 6, hyp_undef
vect_br 7, hyp_reset
#endif
.macro invalid_vector label, cause
.align
\label: mov r0, #\cause
b __hyp_panic
.endm
invalid_vector hyp_reset ARM_EXCEPTION_RESET
invalid_vector hyp_undef ARM_EXCEPTION_UNDEFINED
invalid_vector hyp_svc ARM_EXCEPTION_SOFTWARE
invalid_vector hyp_pabt ARM_EXCEPTION_PREF_ABORT
invalid_vector hyp_fiq ARM_EXCEPTION_FIQ
实现了以下三个,其他五个没实现
hyp_dabt
hyp_hvc
hyp_irq