socsvn commit: r288695 - in soc2015/mihai/bhyve-on-arm-head/sys/arm: include vmm

mihai at FreeBSD.org mihai at FreeBSD.org
Thu Jul 23 17:52:58 UTC 2015


Author: mihai
Date: Thu Jul 23 17:52:55 2015
New Revision: 288695
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=288695

Log:
  soc2015: mihai: bhyve: sys: arm: arm.c: handle stub exception and implement emulation for MMIO accesses

Modified:
  soc2015/mihai/bhyve-on-arm-head/sys/arm/include/vmm.h
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.c
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/hyp.h
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.h
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/vmm.c

Modified: soc2015/mihai/bhyve-on-arm-head/sys/arm/include/vmm.h
==============================================================================
--- soc2015/mihai/bhyve-on-arm-head/sys/arm/include/vmm.h	Thu Jul 23 15:50:39 2015	(r288694)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/include/vmm.h	Thu Jul 23 17:52:55 2015	(r288695)
@@ -32,6 +32,21 @@
 	VM_REG_GUEST_LR,
 	VM_REG_GUEST_PC,
 	VM_REG_GUEST_CPSR,
+	VM_REG_GUEST_SP_SVC,
+	VM_REG_GUEST_LR_SVC,
+	VM_REG_GUEST_SP_ABT,
+	VM_REG_GUEST_LR_ABT,
+	VM_REG_GUEST_SP_UND,
+	VM_REG_GUEST_LR_UND,
+	VM_REG_GUEST_SP_IRQ,
+	VM_REG_GUEST_LR_IRQ,
+	VM_REG_GUEST_R8_FIQ,
+	VM_REG_GUEST_R9_FIQ,
+	VM_REG_GUEST_R10_FIQ,
+	VM_REG_GUEST_R11_FIQ,
+	VM_REG_GUEST_R12_FIQ,
+	VM_REG_GUEST_SP_FIQ,
+	VM_REG_GUEST_LR_FIQ,
 	VM_REG_LAST
 };
 
@@ -229,6 +244,11 @@
 
 #define	VM_MAXCPU	16			/* maximum virtual cpus */
 
+struct vie {
+	uint8_t access_size:4, sign_extend:1, dir:1, unused:2;
+	enum vm_reg_name reg;
+};
+
 /*
  * Identifiers for optional vmm capabilities
  */
@@ -240,16 +260,8 @@
 	VM_CAP_MAX
 };
 enum vm_exitcode {
-	VM_EXITCODE_INOUT,
-	VM_EXITCODE_VMX,
 	VM_EXITCODE_BOGUS,
-	VM_EXITCODE_RDMSR,
-	VM_EXITCODE_WRMSR,
-	VM_EXITCODE_HLT,
-	VM_EXITCODE_MTRAP,
-	VM_EXITCODE_PAUSE,
-	VM_EXITCODE_PAGING,
-	VM_EXITCODE_SPINUP_AP,
+	VM_EXITCODE_INST_EMUL,
 	VM_EXITCODE_HYP,
 	VM_EXITCODE_MAX
 };
@@ -271,7 +283,7 @@
 
 struct vm_exit {
 	enum vm_exitcode	exitcode;
-	int			inst_length;	/* 0 means unknown */
+	int			inst_length;
 	uint64_t		pc;
 	union {
 		/*
@@ -283,6 +295,7 @@
 			uint32_t	hdfar;	/* VA at a Data Abort exception */
 			uint32_t	hifar;	/* VA at a Prefetch Abort exception */
 			uint32_t	hpfar;	/* IPA[39:12] at aborts on stage 2 address translations */
+			uint32_t	mode;
 		} hyp;
 
 		struct {
@@ -291,7 +304,7 @@
 		} paging;
 		struct {
 			uint64_t	gpa;
-			uint64_t	gla;
+			struct vie	vie;
 		} inst_emul;
 		/*
 		 * VMX specific payload. Used when there is no "better"

Modified: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.c
==============================================================================
--- soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.c	Thu Jul 23 15:50:39 2015	(r288694)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.c	Thu Jul 23 17:52:55 2015	(r288695)
@@ -214,6 +214,189 @@
 	return (hyp);
 }
 
+static enum vm_reg_name
+get_vm_reg_name(uint32_t reg_nr, uint32_t mode)
+{
+	switch(reg_nr) {
+		case 0:
+			return VM_REG_GUEST_R0;
+		case 1:
+			return VM_REG_GUEST_R1;
+		case 2:
+			return VM_REG_GUEST_R2;
+		case 3:
+			return VM_REG_GUEST_R3;
+		case 4:
+			return VM_REG_GUEST_R4;
+		case 5:
+			return VM_REG_GUEST_R5;
+		case 6:
+			return VM_REG_GUEST_R6;
+		case 7:
+			return VM_REG_GUEST_R7;
+		case 8:
+			if (mode == PSR_FIQ32_MODE)
+				return VM_REG_GUEST_R8_FIQ;
+			else
+				return VM_REG_GUEST_R8;
+		case 9:
+			if (mode == PSR_FIQ32_MODE)
+				return VM_REG_GUEST_R9_FIQ;
+			else
+				return VM_REG_GUEST_R9;
+		case 10:
+			if (mode == PSR_FIQ32_MODE)
+				return VM_REG_GUEST_R10_FIQ;
+			else
+				return VM_REG_GUEST_R10;
+		case 11:
+			if (mode == PSR_FIQ32_MODE)
+				return VM_REG_GUEST_R11_FIQ;
+			else
+				return VM_REG_GUEST_R11;
+		case 12:
+			if (mode == PSR_FIQ32_MODE)
+				return VM_REG_GUEST_R12_FIQ;
+			else
+				return VM_REG_GUEST_R12;
+		case 13:
+			if (mode == PSR_FIQ32_MODE)
+				return VM_REG_GUEST_SP_FIQ;
+			else if (mode == PSR_SVC32_MODE)
+				return VM_REG_GUEST_SP_SVC;
+			else if (mode == PSR_ABT32_MODE)
+				return VM_REG_GUEST_SP_ABT;
+			else if (mode == PSR_UND32_MODE)
+				return VM_REG_GUEST_SP_UND;
+			else if (mode == PSR_IRQ32_MODE)
+				return VM_REG_GUEST_SP_IRQ;
+			else
+				return VM_REG_GUEST_SP;
+		case 14:
+			if (mode == PSR_FIQ32_MODE)
+				return VM_REG_GUEST_LR_FIQ;
+			else if (mode == PSR_SVC32_MODE)
+				return VM_REG_GUEST_LR_SVC;
+			else if (mode == PSR_ABT32_MODE)
+				return VM_REG_GUEST_LR_ABT;
+			else if (mode == PSR_UND32_MODE)
+				return VM_REG_GUEST_LR_UND;
+			else if (mode == PSR_IRQ32_MODE)
+				return VM_REG_GUEST_LR_IRQ;
+			else
+				return VM_REG_GUEST_LR;
+	}
+	return VM_REG_LAST;
+}
+
+static int hyp_handle_exception(struct vm_exit *vmexit)
+{
+	int handled;
+	int hsr_ec, hsr_il, hsr_iss;
+
+	handled = UNHANDLED;
+	hsr_ec = HSR_EC(vmexit->u.hyp.hsr);
+	hsr_il = HSR_IL(vmexit->u.hyp.hsr);
+	hsr_iss = HSR_ISS(vmexit->u.hyp.hsr);
+
+	switch(hsr_ec) {
+		case HSR_EC_UNKN:
+			printf("%s:%d Unknown exception\n",__func__, __LINE__);
+			break;
+		case HSR_EC_WFI_WFE:
+			printf("%s:%d WFI/WFE exception - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_MCR_MRC_CP15:
+			printf("%s:%d MCR/MRC CP15 - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_MCRR_MRRC_CP15:
+			printf("%s:%d MCRR/MRRC CP15 - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_MCR_MRC_CP14:
+			printf("%s:%d MCR/MRC CP14 - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_LDC_STC_CP14:
+			printf("%s:%d LDC/STC CP14 - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_HCPTR_CP0_CP13:
+			printf("%s:%d MCR/MRC CP14 - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_MRC_VMRS_CP10:
+			printf("%s:%d MCR/VMRS CP14 - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_BXJ:
+			printf("%s:%d BXJ - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_MRRC_CP14:
+			printf("%s:%d MRRC CP14 - unimplemented\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_SVC:
+			panic("%s:%d SVC called from hyp-mode\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_HVC:
+			printf("%s:%d HVC called from hyp-mode - unsupported\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_SMC:
+			printf("%s:%d SMC called from hyp-mode - unsupported\n",
+			    __func__, __LINE__);
+			break;
+		case HSR_EC_PABT:
+			printf("%s:%d PABT from guest at address %x - unimplemented\n",
+			    __func__, __LINE__, vmexit->u.hyp.hifar);
+			break;
+		case HSR_EC_PABT_HYP:
+			printf("%s:%d PABT taken from HYP mode at %x with HSR: %x\n",
+			    __func__, __LINE__, vmexit->u.hyp.hifar, vmexit->u.hyp.hsr);
+			break;
+		case HSR_EC_DABT:
+			if (HSR_ISS_ISV(hsr_iss)) {
+				if (LPAE_TRANSLATION_FAULT(HSR_ISS_DFSC(hsr_iss))) {
+					/*
+					 * The page is not mapped and a possible MMIO access
+					 * Build the instruction info and return to user to emulate
+					 */
+					vmexit->exitcode = VM_EXITCODE_INST_EMUL;
+					vmexit->u.inst_emul.gpa = vmexit->u.hyp.hdfar;
+					vmexit->u.inst_emul.vie.access_size = HSR_ISS_ACCESS_SIZE(HSR_ISS_SAS(hsr_iss));
+					vmexit->u.inst_emul.vie.sign_extend = HSR_ISS_SSE(hsr_iss);
+					vmexit->u.inst_emul.vie.dir = HSR_ISS_WnR(hsr_iss);
+					vmexit->u.inst_emul.vie.reg = get_vm_reg_name(HSR_ISS_SRT(hsr_iss),
+					    vmexit->u.hyp.mode);
+					printf("%s:%d gpa: %llx, as: %d, se: %d, dir: %d, reg: %d\n",__func__, __LINE__,
+					    vmexit->u.inst_emul.gpa, vmexit->u.inst_emul.vie.access_size, vmexit->u.inst_emul.vie.sign_extend,
+					    vmexit->u.inst_emul.vie.dir, vmexit->u.inst_emul.vie.reg);
+
+				} else {
+					printf("%s:%d DABT from guest at address %x witho a stage-2 fault != translation\n",
+					    __func__, __LINE__, vmexit->u.hyp.hdfar);
+				}
+			} else {
+				printf("%s:%d DABT from guest at address %x without a stage-2 fault translation\n",
+				    __func__, __LINE__, vmexit->u.hyp.hdfar);
+			}
+			break;
+		case HSR_EC_DABT_HYP:
+			printf("%s:%d DABT taken from HYP mode at %x with HSR: %x\n",
+			    __func__, __LINE__, vmexit->u.hyp.hdfar, vmexit->u.hyp.hsr);
+			break;
+		default:
+			printf("%s:%d Unknown HSR_EC code: %x\n",__func__, __LINE__, hsr_ec);
+			break;
+	}
+	return handled;
+}
+
 static int
 hyp_exit_process(struct hyp *hyp, int vcpu, struct vm_exit *vmexit)
 {
@@ -237,8 +420,14 @@
 	case EXCEPTION_PABT:
 	case EXCEPTION_DABT:
 	case EXCEPTION_HVC:
-		printf("%s PABT/DABT/HYP unimplemented exception\n",__func__);
+		printf("%s PABT/DABT/HYP exception\n",__func__);
+		printf("%s HSR: %x, HIFAR: %x, HDFAR: %x, HPFAR: %x\n", __func__,
+		    vmexit->u.hyp.hsr, vmexit->u.hyp.hifar,
+		    vmexit->u.hyp.hdfar, vmexit->u.hyp.hpfar);
+
 		vmexit->exitcode = VM_EXITCODE_HYP;
+		handled = hyp_handle_exception(vmexit);
+
 		break;
 	case EXCEPTION_FIQ:
 		printf("%s FIQ unsupported exception\n",__func__);
@@ -272,19 +461,26 @@
 	vm = hyp->vm;
 	vmexit = vm_exitinfo(vm, vcpu);
 
+	hypctx->regs.r_pc = (uint32_t) pc;
+
 	do {
 		handled = UNHANDLED;
 
 		rc = vmm_call_hyp((void *)hyp_enter_guest, hypctx);
 		
-		printf("%s rc: %d\n",__func__, rc);
 		vmexit->pc = hypctx->regs.r_pc;
-		vmexit->inst_length = 4; /* TODO -> HSR[25] */
+
 		vmexit->u.hyp.exception_nr = rc;
 		vmexit->u.hyp.hsr = hypctx->exit_info.hsr;
 		vmexit->u.hyp.hifar = hypctx->exit_info.hifar;
 		vmexit->u.hyp.hdfar = hypctx->exit_info.hdfar;
 		vmexit->u.hyp.hpfar = hypctx->exit_info.hpfar;
+		vmexit->u.hyp.mode = hypctx->regs.r_cpsr & PSR_MODE;
+
+		if (HSR_IL(vmexit->u.hyp.hsr))
+			vmexit->inst_length = 4;
+		else
+			vmexit->inst_length = 2;
 
 		handled = hyp_exit_process(hyp, vcpu, vmexit);
 
@@ -345,11 +541,42 @@
 		return (&hypctx->regs.r_pc);
 	case VM_REG_GUEST_CPSR:
 		return (&hypctx->regs.r_cpsr);
+	case VM_REG_GUEST_SP_SVC:
+		return (&hypctx->sp_svc);
+	case VM_REG_GUEST_LR_SVC:
+		return (&hypctx->lr_svc);
+	case VM_REG_GUEST_SP_ABT:
+		return (&hypctx->sp_abt);
+	case VM_REG_GUEST_LR_ABT:
+		return (&hypctx->lr_abt);
+	case VM_REG_GUEST_SP_UND:
+		return (&hypctx->sp_und);
+	case VM_REG_GUEST_LR_UND:
+		return (&hypctx->lr_und);
+	case VM_REG_GUEST_SP_IRQ:
+		return (&hypctx->sp_irq);
+	case VM_REG_GUEST_LR_IRQ:
+		return (&hypctx->lr_irq);
+	case VM_REG_GUEST_R8_FIQ:
+		return (&hypctx->r8_fiq);
+	case VM_REG_GUEST_R9_FIQ:
+		return (&hypctx->r9_fiq);
+	case VM_REG_GUEST_R10_FIQ:
+		return (&hypctx->r10_fiq);
+	case VM_REG_GUEST_R11_FIQ:
+		return (&hypctx->r11_fiq);
+	case VM_REG_GUEST_R12_FIQ:
+		return (&hypctx->r12_fiq);
+	case VM_REG_GUEST_SP_FIQ:
+		return (&hypctx->sp_fiq);
+	case VM_REG_GUEST_LR_FIQ:
+		return (&hypctx->lr_fiq);
 	default:
 		break;
 	}
 	return (NULL);
 }
+
 static int
 arm_getreg(void *arg, int vcpu, int reg, uint64_t *retval)
 {

Modified: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/hyp.h
==============================================================================
--- soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/hyp.h	Thu Jul 23 15:50:39 2015	(r288694)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/hyp.h	Thu Jul 23 17:52:55 2015	(r288695)
@@ -11,8 +11,49 @@
 #define EXCEPTION_FIQ		6
 #define EXCEPTION_IRQ		7
 
+
+
 #define	HSR_EC_SHIFT		26
+#define	HSR_IL_SHIFT		25
+#define	HSR_IL_MASK		(1 << HSR_IL_SHIFT)
+#define	HSR_ISS_MASK		((1 << 25) - 1)
+
+#define HSR_EC(x)		(x >> HSR_EC_SHIFT)
+#define	HSR_IL(x)		((x & HSR_IL_MASK) >> HSR_IL_SHIFT)
+#define	HSR_ISS(x)		(x & HSR_ISS_MASK)
+
+#define	HSR_EC_UNKN		0x00
+#define	HSR_EC_WFI_WFE		0x01
+#define	HSR_EC_MCR_MRC_CP15	0x03
+#define	HSR_EC_MCRR_MRRC_CP15	0x04
+#define	HSR_EC_MCR_MRC_CP14	0x05
+#define	HSR_EC_LDC_STC_CP14	0x06
+#define	HSR_EC_HCPTR_CP0_CP13	0x07
+#define	HSR_EC_MRC_VMRS_CP10	0x08
+#define	HSR_EC_BXJ		0x0A
+#define	HSR_EC_MRRC_CP14	0x0C
+
+#define	HSR_EC_SVC		0x11
 #define	HSR_EC_HVC		0x12
+#define	HSR_EC_SMC		0x13
+#define	HSR_EC_PABT		0x20
+#define	HSR_EC_PABT_HYP		0x21
+#define	HSR_EC_DABT		0x24
+#define	HSR_EC_DABT_HYP		0x25
+
+#define HSR_ISS_ISV(x)		((x >> 24) & 1)
+#define HSR_ISS_SAS(x)		((x >> 22) & 3)
+#define HSR_ISS_SSE(x)		((x >> 21) & 1)
+#define HSR_ISS_SRT(x)		((x >> 16) & 0xf)
+#define HSR_ISS_EA(x)		((x >> 9) & 1)
+#define HSR_ISS_CM(x)		((x >> 8) & 1)
+#define HSR_ISS_S1PTW(x)	((x >> 7) & 1)
+#define HSR_ISS_WnR(x)		((x >> 6) & 1)
+#define HSR_ISS_DFSC(x)		((x >> 0) & 0x3f)
+
+#define HSR_ISS_ACCESS_SIZE(x)	((x == 0) ? 1 : (x == 1) ? 2 : 4)
+
+
 #define	VTTBR_VMID_SHIFT	16
 #define	VTTBR_VMID_MASK		0xff
 

Modified: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.h
==============================================================================
--- soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.h	Thu Jul 23 15:50:39 2015	(r288694)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.h	Thu Jul 23 17:52:55 2015	(r288695)
@@ -60,4 +60,9 @@
 
 #define	LPAE_AF			(0x1 << 10)		/* Access Flag */
 
+/* Table B3-24 Long-descriptor format FSR encodings */
+#define LPAE_TRANSLATION_FAULT(x)	((0b000111) & x)
+#define LPAE_ACCESS_FLAG_FAULT(x)	((0b001011) & x)
+#define LPAE_PERMISSION_FAULT(x)	((0b001111) & x)
+#define LPAE_FAULT_LEVEL(x)		(0x3 & x)
 #endif

Modified: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/vmm.c
==============================================================================
--- soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/vmm.c	Thu Jul 23 15:50:39 2015	(r288694)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/vmm.c	Thu Jul 23 17:52:55 2015	(r288695)
@@ -269,12 +269,15 @@
 vm_run(struct vm *vm, struct vm_run *vmrun)
 {
 	int error, vcpuid;
+	uint32_t pc;
 	struct vcpu *vcpu;
 	struct vm_exit *vme;
 	bool retu;
 	void *rptr = NULL, *sptr = NULL;
 
 	vcpuid = vmrun->cpuid;
+	pc = vmrun->pc;
+
 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
 		return (EINVAL);
 
@@ -284,12 +287,12 @@
 	vcpu = &vm->vcpu[vcpuid];
 	vme = &vcpu->exitinfo;
 
-	printf("%s vcpuid: %d, nextpc: %llx\n",__func__, vcpuid, vcpu->nextpc);
+	printf("%s vcpuid: %d, nextpc: %x\n",__func__, vcpuid, pc);
 
 restart:
 	critical_enter();
 
-	error = VMRUN(vm->cookie, vcpuid, vcpu->nextpc, NULL, rptr, sptr);
+	error = VMRUN(vm->cookie, vcpuid, pc, NULL, rptr, sptr);
 
 	printf("%s VMRUN error: %d\n",__func__, error);
 
@@ -297,6 +300,10 @@
 
 	if (error == 0) {
 		switch (vme->exitcode) {
+		case VM_EXITCODE_INST_EMUL:
+			/* TODO there is no in-kernel emulation yet */
+			retu = true;
+			break;
 		default:
 			retu = true;	/* handled in userland */
 			break;
@@ -305,10 +312,9 @@
 
 	if (error == 0 && retu == false)
 		goto restart;
-	printf("%s before bhcopy\n",__func__);
+
 	/* copy the exit information */
 	bcopy(vme, &vmrun->vm_exit, sizeof(struct vm_exit));
-	printf("%s after bhcopy\n",__func__);
 
 	return (error);
 }


More information about the svn-soc-all mailing list