| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2012 - Virtual Open Systems and Columbia University | 
					
						
							|  |  |  |  * Author: Christoffer Dall <c.dall@virtualopensystems.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License, version 2, as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef __ARM_KVM_EMULATE_H__
 | 
					
						
							|  |  |  | #define __ARM_KVM_EMULATE_H__
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/kvm_host.h>
 | 
					
						
							|  |  |  | #include <asm/kvm_asm.h>
 | 
					
						
							| 
									
										
										
										
											2013-01-20 18:43:58 -05:00
										 |  |  | #include <asm/kvm_mmio.h>
 | 
					
						
							| 
									
										
										
										
											2012-09-17 19:27:09 +01:00
										 |  |  | #include <asm/kvm_arm.h>
 | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-03 11:17:02 +01:00
										 |  |  | unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num); | 
					
						
							|  |  |  | unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu); | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-08 18:13:18 +00:00
										 |  |  | bool kvm_condition_valid(struct kvm_vcpu *vcpu); | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:09 -05:00
										 |  |  | void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr); | 
					
						
							|  |  |  | void kvm_inject_undefined(struct kvm_vcpu *vcpu); | 
					
						
							|  |  |  | void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); | 
					
						
							|  |  |  | void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:13 -05:00
										 |  |  | static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-03 11:17:02 +01:00
										 |  |  | static inline unsigned long *vcpu_pc(struct kvm_vcpu *vcpu) | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-03 11:17:02 +01:00
										 |  |  | 	return &vcpu->arch.regs.usr_regs.ARM_pc; | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-03 11:17:02 +01:00
										 |  |  | static inline unsigned long *vcpu_cpsr(struct kvm_vcpu *vcpu) | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-03 11:17:02 +01:00
										 |  |  | 	return &vcpu->arch.regs.usr_regs.ARM_cpsr; | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:13 -05:00
										 |  |  | static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	*vcpu_cpsr(vcpu) |= PSR_T_BIT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | static inline bool mode_has_spsr(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long cpsr_mode = vcpu->arch.regs.usr_regs.ARM_cpsr & MODE_MASK; | 
					
						
							|  |  |  | 	return (cpsr_mode > USR_MODE && cpsr_mode < SYSTEM_MODE); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool vcpu_mode_priv(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long cpsr_mode = vcpu->arch.regs.usr_regs.ARM_cpsr & MODE_MASK; | 
					
						
							|  |  |  | 	return cpsr_mode > USR_MODE;; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-17 19:27:09 +01:00
										 |  |  | static inline u32 kvm_vcpu_get_hsr(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return vcpu->arch.fault.hsr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline unsigned long kvm_vcpu_get_hfar(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return vcpu->arch.fault.hxfar; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline phys_addr_t kvm_vcpu_get_fault_ipa(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ((phys_addr_t)vcpu->arch.fault.hpfar & HPFAR_MASK) << 8; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline unsigned long kvm_vcpu_get_hyp_pc(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return vcpu->arch.fault.hyp_pc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 11:06:23 +01:00
										 |  |  | static inline bool kvm_vcpu_dabt_isvalid(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_ISV; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 11:12:26 +01:00
										 |  |  | static inline bool kvm_vcpu_dabt_iswrite(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_WNR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 11:23:02 +01:00
										 |  |  | static inline bool kvm_vcpu_dabt_issext(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_SSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 11:28:57 +01:00
										 |  |  | static inline int kvm_vcpu_dabt_get_rd(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (kvm_vcpu_get_hsr(vcpu) & HSR_SRT_MASK) >> HSR_SRT_SHIFT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 11:36:16 +01:00
										 |  |  | static inline bool kvm_vcpu_dabt_isextabt(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_DABT_EA; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 11:37:28 +01:00
										 |  |  | static inline bool kvm_vcpu_dabt_iss1tw(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_DABT_S1PTW; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 11:43:30 +01:00
										 |  |  | /* Get Access Size from a data abort */ | 
					
						
							|  |  |  | static inline int kvm_vcpu_dabt_get_as(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch ((kvm_vcpu_get_hsr(vcpu) >> 22) & 0x3) { | 
					
						
							|  |  |  | 	case 0: | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 		return 2; | 
					
						
							|  |  |  | 	case 2: | 
					
						
							|  |  |  | 		return 4; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		kvm_err("Hardware is weird: SAS 0b11 is reserved\n"); | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 12:07:06 +01:00
										 |  |  | /* This one is not specific to Data Abort */ | 
					
						
							|  |  |  | static inline bool kvm_vcpu_trap_il_is32bit(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_IL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 14:09:58 +01:00
										 |  |  | static inline u8 kvm_vcpu_trap_get_class(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) >> HSR_EC_SHIFT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-15 10:33:38 +01:00
										 |  |  | static inline bool kvm_vcpu_trap_is_iabt(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_trap_get_class(vcpu) == HSR_EC_IABT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-18 14:14:35 +01:00
										 |  |  | static inline u8 kvm_vcpu_trap_get_fault(struct kvm_vcpu *vcpu) | 
					
						
							| 
									
										
										
										
											2014-09-26 12:29:34 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_FSC; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline u8 kvm_vcpu_trap_get_fault_type(struct kvm_vcpu *vcpu) | 
					
						
							| 
									
										
										
										
											2012-09-18 14:14:35 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_FSC_TYPE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-21 11:26:10 -08:00
										 |  |  | static inline u32 kvm_vcpu_hvc_get_imm(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return kvm_vcpu_get_hsr(vcpu) & HSR_HVC_IMM_MASK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 18:19:03 +01:00
										 |  |  | static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return vcpu->arch.cp15[c0_MPIDR]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-05 14:12:15 +00:00
										 |  |  | static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	*vcpu_cpsr(vcpu) |= PSR_E_BIT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-12 12:40:22 +00:00
										 |  |  | static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return !!(*vcpu_cpsr(vcpu) & PSR_E_BIT); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu, | 
					
						
							|  |  |  | 						    unsigned long data, | 
					
						
							|  |  |  | 						    unsigned int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (kvm_vcpu_is_be(vcpu)) { | 
					
						
							|  |  |  | 		switch (len) { | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			return data & 0xff; | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			return be16_to_cpu(data & 0xffff); | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return be32_to_cpu(data); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-06-12 09:30:05 -07:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		switch (len) { | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			return data & 0xff; | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			return le16_to_cpu(data & 0xffff); | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return le32_to_cpu(data); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-02-12 12:40:22 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu, | 
					
						
							|  |  |  | 						    unsigned long data, | 
					
						
							|  |  |  | 						    unsigned int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (kvm_vcpu_is_be(vcpu)) { | 
					
						
							|  |  |  | 		switch (len) { | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			return data & 0xff; | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			return cpu_to_be16(data & 0xffff); | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return cpu_to_be32(data); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-06-12 09:30:05 -07:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		switch (len) { | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			return data & 0xff; | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			return cpu_to_le16(data & 0xffff); | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return cpu_to_le32(data); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-02-12 12:40:22 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-20 18:28:06 -05:00
										 |  |  | #endif /* __ARM_KVM_EMULATE_H__ */
 |