int arch_vcpu_irq_execute(struct vmm_vcpu * vcpu, arch_regs_t * regs, u32 irq_no, u32 reason) { u32 old_cpsr, new_cpsr, new_mode, new_flags, lr_off; virtual_addr_t new_pc; old_cpsr = cpu_vcpu_cpsr_retrieve(vcpu, regs); new_cpsr = old_cpsr; new_flags = 0x0; switch(irq_no) { case CPU_RESET_IRQ: new_mode = CPSR_MODE_SUPERVISOR; new_flags |= CPSR_ASYNC_ABORT_DISABLED; new_flags |= CPSR_IRQ_DISABLED; new_flags |= CPSR_FIQ_DISABLED; lr_off = 0; break; case CPU_UNDEF_INST_IRQ: new_mode = CPSR_MODE_UNDEFINED; new_flags |= CPSR_IRQ_DISABLED; lr_off = 4; break; case CPU_SOFT_IRQ: new_mode = CPSR_MODE_SUPERVISOR; new_flags |= CPSR_IRQ_DISABLED; lr_off = 4; break; case CPU_PREFETCH_ABORT_IRQ: new_mode = CPSR_MODE_ABORT; new_flags |= CPSR_ASYNC_ABORT_DISABLED; new_flags |= CPSR_IRQ_DISABLED; lr_off = 4; break; case CPU_DATA_ABORT_IRQ: new_mode = CPSR_MODE_ABORT; new_flags |= CPSR_ASYNC_ABORT_DISABLED; new_flags |= CPSR_IRQ_DISABLED; lr_off = 8; break; case CPU_NOT_USED_IRQ: new_mode = CPSR_MODE_SUPERVISOR; new_flags |= CPSR_ASYNC_ABORT_DISABLED; new_flags |= CPSR_IRQ_DISABLED; new_flags |= CPSR_FIQ_DISABLED; lr_off = 0; break; case CPU_EXTERNAL_IRQ: if (old_cpsr & CPSR_IRQ_DISABLED) { return VMM_EFAIL; } new_mode = CPSR_MODE_IRQ; new_flags |= CPSR_ASYNC_ABORT_DISABLED; new_flags |= CPSR_IRQ_DISABLED; lr_off = 4; break; case CPU_EXTERNAL_FIQ: if (old_cpsr & CPSR_FIQ_DISABLED) { return VMM_EFAIL; } new_mode = CPSR_MODE_FIQ; new_flags |= CPSR_ASYNC_ABORT_DISABLED; new_flags |= CPSR_IRQ_DISABLED; new_flags |= CPSR_FIQ_DISABLED; lr_off = 4; break; default: return VMM_EFAIL; break; }; new_pc = cpu_vcpu_cp15_vector_addr(vcpu, irq_no); new_cpsr &= ~CPSR_MODE_MASK; new_cpsr |= (new_mode | new_flags); new_cpsr &= ~(CPSR_IT1_MASK | CPSR_IT2_MASK); if (arm_feature(vcpu, ARM_FEATURE_V4T)) { if (arm_priv(vcpu)->cp15.c1_sctlr & (1 << 30)) { new_cpsr |= CPSR_THUMB_ENABLED; } else { new_cpsr &= ~CPSR_THUMB_ENABLED; } } cpu_vcpu_cpsr_update(vcpu, regs, new_cpsr, CPSR_ALLBITS_MASK); cpu_vcpu_spsr_update(vcpu, old_cpsr, CPSR_ALLBITS_MASK); regs->lr = regs->pc + lr_off; regs->pc = new_pc; return VMM_OK; }
int arch_vcpu_regs_init(struct vmm_vcpu * vcpu) { u32 ite, cpuid = ARM_CPUID_CORTEXA8; /* Initialize User Mode Registers */ /* For both Orphan & Normal VCPUs */ vmm_memset(arm_regs(vcpu), 0, sizeof(arch_regs_t)); arm_regs(vcpu)->pc = vcpu->start_pc; if (vcpu->is_normal) { arm_regs(vcpu)->cpsr = CPSR_ZERO_MASK; arm_regs(vcpu)->cpsr |= CPSR_ASYNC_ABORT_DISABLED; arm_regs(vcpu)->cpsr |= CPSR_MODE_USER; } else { arm_regs(vcpu)->cpsr = CPSR_ZERO_MASK; arm_regs(vcpu)->cpsr |= CPSR_ASYNC_ABORT_DISABLED; arm_regs(vcpu)->cpsr |= CPSR_MODE_SUPERVISOR; arm_regs(vcpu)->sp = vcpu->start_sp; } /* Initialize Supervisor Mode Registers */ /* For only Normal VCPUs */ if (!vcpu->is_normal) { return VMM_OK; } if (!vcpu->reset_count) { vcpu->arch_priv = vmm_malloc(sizeof(arm_priv_t)); vmm_memset(arm_priv(vcpu), 0, sizeof(arm_priv_t)); arm_priv(vcpu)->cpsr = CPSR_ASYNC_ABORT_DISABLED | CPSR_IRQ_DISABLED | CPSR_FIQ_DISABLED | CPSR_MODE_SUPERVISOR; } else { for (ite = 0; ite < CPU_FIQ_GPR_COUNT; ite++) { arm_priv(vcpu)->gpr_usr[ite] = 0x0; arm_priv(vcpu)->gpr_fiq[ite] = 0x0; } arm_priv(vcpu)->sp_usr = 0x0; arm_priv(vcpu)->lr_usr = 0x0; arm_priv(vcpu)->sp_svc = 0x0; arm_priv(vcpu)->lr_svc = 0x0; arm_priv(vcpu)->spsr_svc = 0x0; arm_priv(vcpu)->sp_mon = 0x0; arm_priv(vcpu)->lr_mon = 0x0; arm_priv(vcpu)->spsr_mon = 0x0; arm_priv(vcpu)->sp_abt = 0x0; arm_priv(vcpu)->lr_abt = 0x0; arm_priv(vcpu)->spsr_abt = 0x0; arm_priv(vcpu)->sp_und = 0x0; arm_priv(vcpu)->lr_und = 0x0; arm_priv(vcpu)->spsr_und = 0x0; arm_priv(vcpu)->sp_irq = 0x0; arm_priv(vcpu)->lr_irq = 0x0; arm_priv(vcpu)->spsr_irq = 0x0; arm_priv(vcpu)->sp_fiq = 0x0; arm_priv(vcpu)->lr_fiq = 0x0; arm_priv(vcpu)->spsr_fiq = 0x0; cpu_vcpu_cpsr_update(vcpu, arm_regs(vcpu), (CPSR_ZERO_MASK | CPSR_ASYNC_ABORT_DISABLED | CPSR_IRQ_DISABLED | CPSR_FIQ_DISABLED | CPSR_MODE_SUPERVISOR), CPSR_ALLBITS_MASK); } if (!vcpu->reset_count) { arm_priv(vcpu)->features = 0; switch (cpuid) { case ARM_CPUID_CORTEXA8: arm_set_feature(vcpu, ARM_FEATURE_V4T); arm_set_feature(vcpu, ARM_FEATURE_V5); arm_set_feature(vcpu, ARM_FEATURE_V6); arm_set_feature(vcpu, ARM_FEATURE_V6K); arm_set_feature(vcpu, ARM_FEATURE_V7); arm_set_feature(vcpu, ARM_FEATURE_AUXCR); arm_set_feature(vcpu, ARM_FEATURE_THUMB2); arm_set_feature(vcpu, ARM_FEATURE_VFP); arm_set_feature(vcpu, ARM_FEATURE_VFP3); arm_set_feature(vcpu, ARM_FEATURE_NEON); arm_set_feature(vcpu, ARM_FEATURE_THUMB2EE); break; case ARM_CPUID_CORTEXA9: arm_set_feature(vcpu, ARM_FEATURE_V4T); arm_set_feature(vcpu, ARM_FEATURE_V5); arm_set_feature(vcpu, ARM_FEATURE_V6); arm_set_feature(vcpu, ARM_FEATURE_V6K); arm_set_feature(vcpu, ARM_FEATURE_V7); arm_set_feature(vcpu, ARM_FEATURE_AUXCR); arm_set_feature(vcpu, ARM_FEATURE_THUMB2); arm_set_feature(vcpu, ARM_FEATURE_VFP); arm_set_feature(vcpu, ARM_FEATURE_VFP3); arm_set_feature(vcpu, ARM_FEATURE_VFP_FP16); arm_set_feature(vcpu, ARM_FEATURE_NEON); arm_set_feature(vcpu, ARM_FEATURE_THUMB2EE); arm_set_feature(vcpu, ARM_FEATURE_V7MP); break; default: break; }; } #ifdef CONFIG_ARM32_FUNCSTATS for (ite=0; ite < ARM_FUNCSTAT_MAX; ite++) { arm_priv(vcpu)->funcstat[ite].function_name = NULL; arm_priv(vcpu)->funcstat[ite].entry_count = 0; arm_priv(vcpu)->funcstat[ite].exit_count = 0; arm_priv(vcpu)->funcstat[ite].time = 0; } #endif return cpu_vcpu_cp15_init(vcpu, cpuid); }
int arch_vcpu_init(struct vmm_vcpu *vcpu) { u32 ite, cpuid; const char *attr; /* Initialize User Mode Registers */ /* For both Orphan & Normal VCPUs */ memset(arm_regs(vcpu), 0, sizeof(arch_regs_t)); arm_regs(vcpu)->pc = vcpu->start_pc; arm_regs(vcpu)->sp_excp = vcpu->stack_va + vcpu->stack_sz - 4; if (vcpu->is_normal) { arm_regs(vcpu)->cpsr = CPSR_ZERO_MASK; arm_regs(vcpu)->cpsr |= CPSR_ASYNC_ABORT_DISABLED; arm_regs(vcpu)->cpsr |= CPSR_MODE_USER; arm_regs(vcpu)->sp = 0; } else { arm_regs(vcpu)->cpsr = CPSR_ZERO_MASK; arm_regs(vcpu)->cpsr |= CPSR_ASYNC_ABORT_DISABLED; arm_regs(vcpu)->cpsr |= CPSR_MODE_SUPERVISOR; arm_regs(vcpu)->sp = arm_regs(vcpu)->sp_excp; } /* Initialize Supervisor Mode Registers */ /* For only Normal VCPUs */ if (!vcpu->is_normal) { return VMM_OK; } attr = vmm_devtree_attrval(vcpu->node, VMM_DEVTREE_COMPATIBLE_ATTR_NAME); if (!attr) { return VMM_EFAIL; } if (strcmp(attr, "armv5te,arm926ej") == 0) { cpuid = ARM_CPUID_ARM926; } else if (strcmp(attr, "armv6,arm11mp") == 0) { cpuid = ARM_CPUID_ARM11MPCORE; } else if (strcmp(attr, "armv7a,cortex-a8") == 0) { cpuid = ARM_CPUID_CORTEXA8; } else if (strcmp(attr, "armv7a,cortex-a9") == 0) { cpuid = ARM_CPUID_CORTEXA9; } else { return VMM_EFAIL; } if (!vcpu->reset_count) { vcpu->arch_priv = vmm_zalloc(sizeof(arm_priv_t)); arm_priv(vcpu)->cpsr = CPSR_ASYNC_ABORT_DISABLED | CPSR_IRQ_DISABLED | CPSR_FIQ_DISABLED | CPSR_MODE_SUPERVISOR; } else { for (ite = 0; ite < CPU_FIQ_GPR_COUNT; ite++) { arm_priv(vcpu)->gpr_usr[ite] = 0x0; arm_priv(vcpu)->gpr_fiq[ite] = 0x0; } arm_priv(vcpu)->sp_usr = 0x0; arm_priv(vcpu)->lr_usr = 0x0; arm_priv(vcpu)->sp_svc = 0x0; arm_priv(vcpu)->lr_svc = 0x0; arm_priv(vcpu)->spsr_svc = 0x0; arm_priv(vcpu)->sp_mon = 0x0; arm_priv(vcpu)->lr_mon = 0x0; arm_priv(vcpu)->spsr_mon = 0x0; arm_priv(vcpu)->sp_abt = 0x0; arm_priv(vcpu)->lr_abt = 0x0; arm_priv(vcpu)->spsr_abt = 0x0; arm_priv(vcpu)->sp_und = 0x0; arm_priv(vcpu)->lr_und = 0x0; arm_priv(vcpu)->spsr_und = 0x0; arm_priv(vcpu)->sp_irq = 0x0; arm_priv(vcpu)->lr_irq = 0x0; arm_priv(vcpu)->spsr_irq = 0x0; arm_priv(vcpu)->sp_fiq = 0x0; arm_priv(vcpu)->lr_fiq = 0x0; arm_priv(vcpu)->spsr_fiq = 0x0; cpu_vcpu_cpsr_update(vcpu, arm_regs(vcpu), (CPSR_ZERO_MASK | CPSR_ASYNC_ABORT_DISABLED | CPSR_IRQ_DISABLED | CPSR_FIQ_DISABLED | CPSR_MODE_SUPERVISOR), CPSR_ALLBITS_MASK); } if (!vcpu->reset_count) { arm_priv(vcpu)->features = 0; switch (cpuid) { case ARM_CPUID_ARM926: arm_set_feature(vcpu, ARM_FEATURE_V5); arm_set_feature(vcpu, ARM_FEATURE_VFP); arm_set_feature(vcpu, ARM_FEATURE_DUMMY_C15_REGS); arm_set_feature(vcpu, ARM_FEATURE_CACHE_TEST_CLEAN); break; case ARM_CPUID_ARM11MPCORE: arm_set_feature(vcpu, ARM_FEATURE_V6); arm_set_feature(vcpu, ARM_FEATURE_V6K); arm_set_feature(vcpu, ARM_FEATURE_VFP); arm_set_feature(vcpu, ARM_FEATURE_VAPA); arm_set_feature(vcpu, ARM_FEATURE_DUMMY_C15_REGS); break; case ARM_CPUID_CORTEXA8: arm_set_feature(vcpu, ARM_FEATURE_V7); arm_set_feature(vcpu, ARM_FEATURE_VFP3); arm_set_feature(vcpu, ARM_FEATURE_NEON); arm_set_feature(vcpu, ARM_FEATURE_THUMB2EE); arm_set_feature(vcpu, ARM_FEATURE_DUMMY_C15_REGS); arm_set_feature(vcpu, ARM_FEATURE_TRUSTZONE); break; case ARM_CPUID_CORTEXA9: arm_set_feature(vcpu, ARM_FEATURE_V7); arm_set_feature(vcpu, ARM_FEATURE_VFP3); arm_set_feature(vcpu, ARM_FEATURE_VFP_FP16); arm_set_feature(vcpu, ARM_FEATURE_NEON); arm_set_feature(vcpu, ARM_FEATURE_THUMB2EE); arm_set_feature(vcpu, ARM_FEATURE_V7MP); arm_set_feature(vcpu, ARM_FEATURE_TRUSTZONE); break; default: break; }; /* Some features automatically imply others: */ if (arm_feature(vcpu, ARM_FEATURE_V7)) { arm_set_feature(vcpu, ARM_FEATURE_VAPA); arm_set_feature(vcpu, ARM_FEATURE_THUMB2); arm_set_feature(vcpu, ARM_FEATURE_MPIDR); if (!arm_feature(vcpu, ARM_FEATURE_M)) { arm_set_feature(vcpu, ARM_FEATURE_V6K); } else { arm_set_feature(vcpu, ARM_FEATURE_V6); } } if (arm_feature(vcpu, ARM_FEATURE_V6K)) { arm_set_feature(vcpu, ARM_FEATURE_V6); arm_set_feature(vcpu, ARM_FEATURE_MVFR); } if (arm_feature(vcpu, ARM_FEATURE_V6)) { arm_set_feature(vcpu, ARM_FEATURE_V5); if (!arm_feature(vcpu, ARM_FEATURE_M)) { arm_set_feature(vcpu, ARM_FEATURE_AUXCR); } } if (arm_feature(vcpu, ARM_FEATURE_V5)) { arm_set_feature(vcpu, ARM_FEATURE_V4T); } if (arm_feature(vcpu, ARM_FEATURE_M)) { arm_set_feature(vcpu, ARM_FEATURE_THUMB_DIV); } if (arm_feature(vcpu, ARM_FEATURE_ARM_DIV)) { arm_set_feature(vcpu, ARM_FEATURE_THUMB_DIV); } if (arm_feature(vcpu, ARM_FEATURE_VFP4)) { arm_set_feature(vcpu, ARM_FEATURE_VFP3); } if (arm_feature(vcpu, ARM_FEATURE_VFP3)) { arm_set_feature(vcpu, ARM_FEATURE_VFP); } if (arm_feature(vcpu, ARM_FEATURE_LPAE)) { arm_set_feature(vcpu, ARM_FEATURE_PXN); } } return cpu_vcpu_cp15_init(vcpu, cpuid); }