ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

ARMv7 KVM 在 linux中的实现

2021-09-25 13:29:52  阅读:258  来源: 互联网

标签:__ KVM r0 vcpu kvm hyp ARMv7 linux arm


linux-5.6

函数角度

架构无关部分 在 virt
架构相关部分 在 arch/arm/kvm
  • 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
			...

运行时角度

  • VM entry

// 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)


  • VM exit
我们知道返回时的第一条指令

__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





标签:__,KVM,r0,vcpu,kvm,hyp,ARMv7,linux,arm
来源: https://blog.csdn.net/u011011827/article/details/120470296

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有