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