KVM: PPC: booke: category E.HV (GS-mode) support
Chips such as e500mc that implement category E.HV in Power ISA 2.06 provide hardware virtualization features, including a new MSR mode for guest state. The guest OS can perform many operations without trapping into the hypervisor, including transitions to and from guest userspace. Since we can use SRR1[GS] to reliably tell whether an exception came from guest state, instead of messing around with IVPR, we use DO_KVM similarly to book3s. Current issues include: - Machine checks from guest state are not routed to the host handler. - The guest can cause a host oops by executing an emulated instruction in a page that lacks read permission. Existing e500/4xx support has the same problem. Includes work by Ashish Kalra <Ashish.Kalra@freescale.com>, Varun Sethi <Varun.Sethi@freescale.com>, and Liu Yu <yu.liu@freescale.com>. Signed-off-by: Scott Wood <scottwood@freescale.com> [agraf: remove pt_regs usage] Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
		
					parent
					
						
							
								cfac57847a
							
						
					
				
			
			
				commit
				
					
						d30f6e4800
					
				
			
		
					 18 changed files with 1058 additions and 67 deletions
				
			
		|  | @ -19,6 +19,7 @@ | ||||||
| 
 | 
 | ||||||
| #define PPC_DBELL_MSG_BRDCAST	(0x04000000) | #define PPC_DBELL_MSG_BRDCAST	(0x04000000) | ||||||
| #define PPC_DBELL_TYPE(x)	(((x) & 0xf) << (63-36)) | #define PPC_DBELL_TYPE(x)	(((x) & 0xf) << (63-36)) | ||||||
|  | #define PPC_DBELL_LPID(x)	((x) << (63 - 49)) | ||||||
| enum ppc_dbell { | enum ppc_dbell { | ||||||
| 	PPC_DBELL = 0,		/* doorbell */ | 	PPC_DBELL = 0,		/* doorbell */ | ||||||
| 	PPC_DBELL_CRIT = 1,	/* critical doorbell */ | 	PPC_DBELL_CRIT = 1,	/* critical doorbell */ | ||||||
|  |  | ||||||
|  | @ -48,6 +48,14 @@ | ||||||
| #define BOOKE_INTERRUPT_SPE_FP_DATA 33 | #define BOOKE_INTERRUPT_SPE_FP_DATA 33 | ||||||
| #define BOOKE_INTERRUPT_SPE_FP_ROUND 34 | #define BOOKE_INTERRUPT_SPE_FP_ROUND 34 | ||||||
| #define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35 | #define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35 | ||||||
|  | #define BOOKE_INTERRUPT_DOORBELL 36 | ||||||
|  | #define BOOKE_INTERRUPT_DOORBELL_CRITICAL 37 | ||||||
|  | 
 | ||||||
|  | /* booke_hv */ | ||||||
|  | #define BOOKE_INTERRUPT_GUEST_DBELL 38 | ||||||
|  | #define BOOKE_INTERRUPT_GUEST_DBELL_CRIT 39 | ||||||
|  | #define BOOKE_INTERRUPT_HV_SYSCALL 40 | ||||||
|  | #define BOOKE_INTERRUPT_HV_PRIV 41 | ||||||
| 
 | 
 | ||||||
| /* book3s */ | /* book3s */ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										49
									
								
								arch/powerpc/include/asm/kvm_booke_hv_asm.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								arch/powerpc/include/asm/kvm_booke_hv_asm.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright 2010-2011 Freescale Semiconductor, Inc. | ||||||
|  |  * | ||||||
|  |  * 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. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef ASM_KVM_BOOKE_HV_ASM_H | ||||||
|  | #define ASM_KVM_BOOKE_HV_ASM_H | ||||||
|  | 
 | ||||||
|  | #ifdef __ASSEMBLY__ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * All exceptions from guest state must go through KVM | ||||||
|  |  * (except for those which are delivered directly to the guest) -- | ||||||
|  |  * there are no exceptions for which we fall through directly to | ||||||
|  |  * the normal host handler. | ||||||
|  |  * | ||||||
|  |  * Expected inputs (normal exceptions): | ||||||
|  |  *   SCRATCH0 = saved r10 | ||||||
|  |  *   r10 = thread struct | ||||||
|  |  *   r11 = appropriate SRR1 variant (currently used as scratch) | ||||||
|  |  *   r13 = saved CR | ||||||
|  |  *   *(r10 + THREAD_NORMSAVE(0)) = saved r11 | ||||||
|  |  *   *(r10 + THREAD_NORMSAVE(2)) = saved r13 | ||||||
|  |  * | ||||||
|  |  * Expected inputs (crit/mcheck/debug exceptions): | ||||||
|  |  *   appropriate SCRATCH = saved r8 | ||||||
|  |  *   r8 = exception level stack frame | ||||||
|  |  *   r9 = *(r8 + _CCR) = saved CR | ||||||
|  |  *   r11 = appropriate SRR1 variant (currently used as scratch) | ||||||
|  |  *   *(r8 + GPR9) = saved r9 | ||||||
|  |  *   *(r8 + GPR10) = saved r10 (r10 not yet clobbered) | ||||||
|  |  *   *(r8 + GPR11) = saved r11 | ||||||
|  |  */ | ||||||
|  | .macro DO_KVM intno srr1 | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | BEGIN_FTR_SECTION | ||||||
|  | 	mtocrf	0x80, r11	/* check MSR[GS] without clobbering reg */ | ||||||
|  | 	bf	3, kvmppc_resume_\intno\()_\srr1 | ||||||
|  | 	b	kvmppc_handler_\intno\()_\srr1 | ||||||
|  | kvmppc_resume_\intno\()_\srr1: | ||||||
|  | END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) | ||||||
|  | #endif | ||||||
|  | .endm | ||||||
|  | 
 | ||||||
|  | #endif /*__ASSEMBLY__ */ | ||||||
|  | #endif /* ASM_KVM_BOOKE_HV_ASM_H */ | ||||||
|  | @ -106,6 +106,8 @@ struct kvm_vcpu_stat { | ||||||
| 	u32 dec_exits; | 	u32 dec_exits; | ||||||
| 	u32 ext_intr_exits; | 	u32 ext_intr_exits; | ||||||
| 	u32 halt_wakeup; | 	u32 halt_wakeup; | ||||||
|  | 	u32 dbell_exits; | ||||||
|  | 	u32 gdbell_exits; | ||||||
| #ifdef CONFIG_PPC_BOOK3S | #ifdef CONFIG_PPC_BOOK3S | ||||||
| 	u32 pf_storage; | 	u32 pf_storage; | ||||||
| 	u32 pf_instruc; | 	u32 pf_instruc; | ||||||
|  | @ -140,6 +142,7 @@ enum kvm_exit_types { | ||||||
| 	EMULATED_TLBSX_EXITS, | 	EMULATED_TLBSX_EXITS, | ||||||
| 	EMULATED_TLBWE_EXITS, | 	EMULATED_TLBWE_EXITS, | ||||||
| 	EMULATED_RFI_EXITS, | 	EMULATED_RFI_EXITS, | ||||||
|  | 	EMULATED_RFCI_EXITS, | ||||||
| 	DEC_EXITS, | 	DEC_EXITS, | ||||||
| 	EXT_INTR_EXITS, | 	EXT_INTR_EXITS, | ||||||
| 	HALT_WAKEUP, | 	HALT_WAKEUP, | ||||||
|  | @ -147,6 +150,8 @@ enum kvm_exit_types { | ||||||
| 	FP_UNAVAIL, | 	FP_UNAVAIL, | ||||||
| 	DEBUG_EXITS, | 	DEBUG_EXITS, | ||||||
| 	TIMEINGUEST, | 	TIMEINGUEST, | ||||||
|  | 	DBELL_EXITS, | ||||||
|  | 	GDBELL_EXITS, | ||||||
| 	__NUMBER_OF_KVM_EXIT_TYPES | 	__NUMBER_OF_KVM_EXIT_TYPES | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -217,10 +222,10 @@ struct kvm_arch_memory_slot { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct kvm_arch { | struct kvm_arch { | ||||||
|  | 	unsigned int lpid; | ||||||
| #ifdef CONFIG_KVM_BOOK3S_64_HV | #ifdef CONFIG_KVM_BOOK3S_64_HV | ||||||
| 	unsigned long hpt_virt; | 	unsigned long hpt_virt; | ||||||
| 	struct revmap_entry *revmap; | 	struct revmap_entry *revmap; | ||||||
| 	unsigned int lpid; |  | ||||||
| 	unsigned int host_lpid; | 	unsigned int host_lpid; | ||||||
| 	unsigned long host_lpcr; | 	unsigned long host_lpcr; | ||||||
| 	unsigned long sdr1; | 	unsigned long sdr1; | ||||||
|  | @ -345,6 +350,17 @@ struct kvm_vcpu_arch { | ||||||
| 	u64 vsr[64]; | 	u64 vsr[64]; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	u32 host_mas4; | ||||||
|  | 	u32 host_mas6; | ||||||
|  | 	u32 shadow_epcr; | ||||||
|  | 	u32 epcr; | ||||||
|  | 	u32 shadow_msrp; | ||||||
|  | 	u32 eplc; | ||||||
|  | 	u32 epsc; | ||||||
|  | 	u32 oldpir; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_PPC_BOOK3S | #ifdef CONFIG_PPC_BOOK3S | ||||||
| 	/* For Gekko paired singles */ | 	/* For Gekko paired singles */ | ||||||
| 	u32 qpr[32]; | 	u32 qpr[32]; | ||||||
|  | @ -428,6 +444,7 @@ struct kvm_vcpu_arch { | ||||||
| 	ulong queued_esr; | 	ulong queued_esr; | ||||||
| 	u32 tlbcfg[4]; | 	u32 tlbcfg[4]; | ||||||
| 	u32 mmucfg; | 	u32 mmucfg; | ||||||
|  | 	u32 epr; | ||||||
| #endif | #endif | ||||||
| 	gpa_t paddr_accessed; | 	gpa_t paddr_accessed; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -139,6 +139,9 @@ extern int kvmppc_core_prepare_memory_region(struct kvm *kvm, | ||||||
| extern void kvmppc_core_commit_memory_region(struct kvm *kvm, | extern void kvmppc_core_commit_memory_region(struct kvm *kvm, | ||||||
| 				struct kvm_userspace_memory_region *mem); | 				struct kvm_userspace_memory_region *mem); | ||||||
| 
 | 
 | ||||||
|  | extern int kvmppc_bookehv_init(void); | ||||||
|  | extern void kvmppc_bookehv_exit(void); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Cuts out inst bits with ordering according to spec. |  * Cuts out inst bits with ordering according to spec. | ||||||
|  * That means the leftmost bit is zero. All given bits are included. |  * That means the leftmost bit is zero. All given bits are included. | ||||||
|  |  | ||||||
|  | @ -104,6 +104,8 @@ | ||||||
| #define MAS4_TSIZED_MASK	0x00000f80	/* Default TSIZE */ | #define MAS4_TSIZED_MASK	0x00000f80	/* Default TSIZE */ | ||||||
| #define MAS4_TSIZED_SHIFT	7 | #define MAS4_TSIZED_SHIFT	7 | ||||||
| 
 | 
 | ||||||
|  | #define MAS5_SGS		0x80000000 | ||||||
|  | 
 | ||||||
| #define MAS6_SPID0		0x3FFF0000 | #define MAS6_SPID0		0x3FFF0000 | ||||||
| #define MAS6_SPID1		0x00007FFE | #define MAS6_SPID1		0x00007FFE | ||||||
| #define MAS6_ISIZE(x)		MAS1_TSIZE(x) | #define MAS6_ISIZE(x)		MAS1_TSIZE(x) | ||||||
|  | @ -118,6 +120,10 @@ | ||||||
| 
 | 
 | ||||||
| #define MAS7_RPN		0xFFFFFFFF | #define MAS7_RPN		0xFFFFFFFF | ||||||
| 
 | 
 | ||||||
|  | #define MAS8_TGS		0x80000000 /* Guest space */ | ||||||
|  | #define MAS8_VF			0x40000000 /* Virtualization Fault */ | ||||||
|  | #define MAS8_TLPID		0x000000ff | ||||||
|  | 
 | ||||||
| /* Bit definitions for MMUCFG */ | /* Bit definitions for MMUCFG */ | ||||||
| #define MMUCFG_MAVN	0x00000003	/* MMU Architecture Version Number */ | #define MMUCFG_MAVN	0x00000003	/* MMU Architecture Version Number */ | ||||||
| #define MMUCFG_MAVN_V1	0x00000000	/* v1.0 */ | #define MMUCFG_MAVN_V1	0x00000000	/* v1.0 */ | ||||||
|  |  | ||||||
|  | @ -243,6 +243,9 @@ struct thread_struct { | ||||||
| #ifdef CONFIG_KVM_BOOK3S_32_HANDLER | #ifdef CONFIG_KVM_BOOK3S_32_HANDLER | ||||||
| 	void*		kvm_shadow_vcpu; /* KVM internal data */ | 	void*		kvm_shadow_vcpu; /* KVM internal data */ | ||||||
| #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */ | #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */ | ||||||
|  | #if defined(CONFIG_KVM) && defined(CONFIG_BOOKE) | ||||||
|  | 	struct kvm_vcpu	*kvm_vcpu; | ||||||
|  | #endif | ||||||
| #ifdef CONFIG_PPC64 | #ifdef CONFIG_PPC64 | ||||||
| 	unsigned long	dscr; | 	unsigned long	dscr; | ||||||
| 	int		dscr_inherit; | 	int		dscr_inherit; | ||||||
|  |  | ||||||
|  | @ -257,7 +257,9 @@ | ||||||
| #define   LPCR_LPES_SH	2 | #define   LPCR_LPES_SH	2 | ||||||
| #define   LPCR_RMI     0x00000002      /* real mode is cache inhibit */ | #define   LPCR_RMI     0x00000002      /* real mode is cache inhibit */ | ||||||
| #define   LPCR_HDICE   0x00000001      /* Hyp Decr enable (HV,PR,EE) */ | #define   LPCR_HDICE   0x00000001      /* Hyp Decr enable (HV,PR,EE) */ | ||||||
|  | #ifndef SPRN_LPID | ||||||
| #define SPRN_LPID	0x13F	/* Logical Partition Identifier */ | #define SPRN_LPID	0x13F	/* Logical Partition Identifier */ | ||||||
|  | #endif | ||||||
| #define   LPID_RSVD	0x3ff		/* Reserved LPID for partn switching */ | #define   LPID_RSVD	0x3ff		/* Reserved LPID for partn switching */ | ||||||
| #define	SPRN_HMER	0x150	/* Hardware m? error recovery */ | #define	SPRN_HMER	0x150	/* Hardware m? error recovery */ | ||||||
| #define	SPRN_HMEER	0x151	/* Hardware m? enable error recovery */ | #define	SPRN_HMEER	0x151	/* Hardware m? enable error recovery */ | ||||||
|  |  | ||||||
|  | @ -61,18 +61,30 @@ extern u32 booke_wdt_period; | ||||||
| #define SPRN_SPRG7W	0x117	/* Special Purpose Register General 7 Write */ | #define SPRN_SPRG7W	0x117	/* Special Purpose Register General 7 Write */ | ||||||
| #define SPRN_EPCR	0x133	/* Embedded Processor Control Register */ | #define SPRN_EPCR	0x133	/* Embedded Processor Control Register */ | ||||||
| #define SPRN_DBCR2	0x136	/* Debug Control Register 2 */ | #define SPRN_DBCR2	0x136	/* Debug Control Register 2 */ | ||||||
|  | #define SPRN_MSRP	0x137	/* MSR Protect Register */ | ||||||
| #define SPRN_IAC3	0x13A	/* Instruction Address Compare 3 */ | #define SPRN_IAC3	0x13A	/* Instruction Address Compare 3 */ | ||||||
| #define SPRN_IAC4	0x13B	/* Instruction Address Compare 4 */ | #define SPRN_IAC4	0x13B	/* Instruction Address Compare 4 */ | ||||||
| #define SPRN_DVC1	0x13E	/* Data Value Compare Register 1 */ | #define SPRN_DVC1	0x13E	/* Data Value Compare Register 1 */ | ||||||
| #define SPRN_DVC2	0x13F	/* Data Value Compare Register 2 */ | #define SPRN_DVC2	0x13F	/* Data Value Compare Register 2 */ | ||||||
|  | #define SPRN_LPID	0x152	/* Logical Partition ID */ | ||||||
| #define SPRN_MAS8	0x155	/* MMU Assist Register 8 */ | #define SPRN_MAS8	0x155	/* MMU Assist Register 8 */ | ||||||
| #define SPRN_TLB0PS	0x158	/* TLB 0 Page Size Register */ | #define SPRN_TLB0PS	0x158	/* TLB 0 Page Size Register */ | ||||||
| #define SPRN_TLB1PS	0x159	/* TLB 1 Page Size Register */ | #define SPRN_TLB1PS	0x159	/* TLB 1 Page Size Register */ | ||||||
| #define SPRN_MAS5_MAS6	0x15c	/* MMU Assist Register 5 || 6 */ | #define SPRN_MAS5_MAS6	0x15c	/* MMU Assist Register 5 || 6 */ | ||||||
| #define SPRN_MAS8_MAS1	0x15d	/* MMU Assist Register 8 || 1 */ | #define SPRN_MAS8_MAS1	0x15d	/* MMU Assist Register 8 || 1 */ | ||||||
| #define SPRN_EPTCFG	0x15e	/* Embedded Page Table Config */ | #define SPRN_EPTCFG	0x15e	/* Embedded Page Table Config */ | ||||||
|  | #define SPRN_GSPRG0	0x170	/* Guest SPRG0 */ | ||||||
|  | #define SPRN_GSPRG1	0x171	/* Guest SPRG1 */ | ||||||
|  | #define SPRN_GSPRG2	0x172	/* Guest SPRG2 */ | ||||||
|  | #define SPRN_GSPRG3	0x173	/* Guest SPRG3 */ | ||||||
| #define SPRN_MAS7_MAS3	0x174	/* MMU Assist Register 7 || 3 */ | #define SPRN_MAS7_MAS3	0x174	/* MMU Assist Register 7 || 3 */ | ||||||
| #define SPRN_MAS0_MAS1	0x175	/* MMU Assist Register 0 || 1 */ | #define SPRN_MAS0_MAS1	0x175	/* MMU Assist Register 0 || 1 */ | ||||||
|  | #define SPRN_GSRR0	0x17A	/* Guest SRR0 */ | ||||||
|  | #define SPRN_GSRR1	0x17B	/* Guest SRR1 */ | ||||||
|  | #define SPRN_GEPR	0x17C	/* Guest EPR */ | ||||||
|  | #define SPRN_GDEAR	0x17D	/* Guest DEAR */ | ||||||
|  | #define SPRN_GPIR	0x17E	/* Guest PIR */ | ||||||
|  | #define SPRN_GESR	0x17F	/* Guest Exception Syndrome Register */ | ||||||
| #define SPRN_IVOR0	0x190	/* Interrupt Vector Offset Register 0 */ | #define SPRN_IVOR0	0x190	/* Interrupt Vector Offset Register 0 */ | ||||||
| #define SPRN_IVOR1	0x191	/* Interrupt Vector Offset Register 1 */ | #define SPRN_IVOR1	0x191	/* Interrupt Vector Offset Register 1 */ | ||||||
| #define SPRN_IVOR2	0x192	/* Interrupt Vector Offset Register 2 */ | #define SPRN_IVOR2	0x192	/* Interrupt Vector Offset Register 2 */ | ||||||
|  | @ -93,6 +105,13 @@ extern u32 booke_wdt_period; | ||||||
| #define SPRN_IVOR39	0x1B1	/* Interrupt Vector Offset Register 39 */ | #define SPRN_IVOR39	0x1B1	/* Interrupt Vector Offset Register 39 */ | ||||||
| #define SPRN_IVOR40	0x1B2	/* Interrupt Vector Offset Register 40 */ | #define SPRN_IVOR40	0x1B2	/* Interrupt Vector Offset Register 40 */ | ||||||
| #define SPRN_IVOR41	0x1B3	/* Interrupt Vector Offset Register 41 */ | #define SPRN_IVOR41	0x1B3	/* Interrupt Vector Offset Register 41 */ | ||||||
|  | #define SPRN_GIVOR2	0x1B8	/* Guest IVOR2 */ | ||||||
|  | #define SPRN_GIVOR3	0x1B9	/* Guest IVOR3 */ | ||||||
|  | #define SPRN_GIVOR4	0x1BA	/* Guest IVOR4 */ | ||||||
|  | #define SPRN_GIVOR8	0x1BB	/* Guest IVOR8 */ | ||||||
|  | #define SPRN_GIVOR13	0x1BC	/* Guest IVOR13 */ | ||||||
|  | #define SPRN_GIVOR14	0x1BD	/* Guest IVOR14 */ | ||||||
|  | #define SPRN_GIVPR	0x1BF	/* Guest IVPR */ | ||||||
| #define SPRN_SPEFSCR	0x200	/* SPE & Embedded FP Status & Control */ | #define SPRN_SPEFSCR	0x200	/* SPE & Embedded FP Status & Control */ | ||||||
| #define SPRN_BBEAR	0x201	/* Branch Buffer Entry Address Register */ | #define SPRN_BBEAR	0x201	/* Branch Buffer Entry Address Register */ | ||||||
| #define SPRN_BBTAR	0x202	/* Branch Buffer Target Address Register */ | #define SPRN_BBTAR	0x202	/* Branch Buffer Target Address Register */ | ||||||
|  | @ -245,6 +264,10 @@ extern u32 booke_wdt_period; | ||||||
| #define MCSR_LDG	0x00002000UL /* Guarded Load */ | #define MCSR_LDG	0x00002000UL /* Guarded Load */ | ||||||
| #define MCSR_TLBSYNC	0x00000002UL /* Multiple tlbsyncs detected */ | #define MCSR_TLBSYNC	0x00000002UL /* Multiple tlbsyncs detected */ | ||||||
| #define MCSR_BSL2_ERR	0x00000001UL /* Backside L2 cache error */ | #define MCSR_BSL2_ERR	0x00000001UL /* Backside L2 cache error */ | ||||||
|  | 
 | ||||||
|  | #define MSRP_UCLEP	0x04000000 /* Protect MSR[UCLE] */ | ||||||
|  | #define MSRP_DEP	0x00000200 /* Protect MSR[DE] */ | ||||||
|  | #define MSRP_PMMP	0x00000004 /* Protect MSR[PMM] */ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_E200 | #ifdef CONFIG_E200 | ||||||
|  | @ -599,6 +622,17 @@ extern u32 booke_wdt_period; | ||||||
| #define SPRN_EPCR_DMIUH		0x00400000	/* Disable MAS Interrupt updates | #define SPRN_EPCR_DMIUH		0x00400000	/* Disable MAS Interrupt updates | ||||||
| 						 * for hypervisor */ | 						 * for hypervisor */ | ||||||
| 
 | 
 | ||||||
|  | /* Bit definitions for EPLC/EPSC */ | ||||||
|  | #define EPC_EPR		0x80000000 /* 1 = user, 0 = kernel */ | ||||||
|  | #define EPC_EPR_SHIFT	31 | ||||||
|  | #define EPC_EAS		0x40000000 /* Address Space */ | ||||||
|  | #define EPC_EAS_SHIFT	30 | ||||||
|  | #define EPC_EGS		0x20000000 /* 1 = guest, 0 = hypervisor */ | ||||||
|  | #define EPC_EGS_SHIFT	29 | ||||||
|  | #define EPC_ELPID	0x00ff0000 | ||||||
|  | #define EPC_ELPID_SHIFT	16 | ||||||
|  | #define EPC_EPID	0x00003fff | ||||||
|  | #define EPC_EPID_SHIFT	0 | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * The IBM-403 is an even more odd special case, as it is much |  * The IBM-403 is an even more odd special case, as it is much | ||||||
|  |  | ||||||
|  | @ -116,6 +116,9 @@ int main(void) | ||||||
| #ifdef CONFIG_KVM_BOOK3S_32_HANDLER | #ifdef CONFIG_KVM_BOOK3S_32_HANDLER | ||||||
| 	DEFINE(THREAD_KVM_SVCPU, offsetof(struct thread_struct, kvm_shadow_vcpu)); | 	DEFINE(THREAD_KVM_SVCPU, offsetof(struct thread_struct, kvm_shadow_vcpu)); | ||||||
| #endif | #endif | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	DEFINE(THREAD_KVM_VCPU, offsetof(struct thread_struct, kvm_vcpu)); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | ||||||
| 	DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); | 	DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); | ||||||
|  | @ -387,6 +390,7 @@ int main(void) | ||||||
| #ifdef CONFIG_KVM | #ifdef CONFIG_KVM | ||||||
| 	DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); | 	DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); | ||||||
| 	DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); | 	DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); | ||||||
|  | 	DEFINE(VCPU_GUEST_PID, offsetof(struct kvm_vcpu, arch.pid)); | ||||||
| 	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); | 	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); | ||||||
| 	DEFINE(VCPU_VRSAVE, offsetof(struct kvm_vcpu, arch.vrsave)); | 	DEFINE(VCPU_VRSAVE, offsetof(struct kvm_vcpu, arch.vrsave)); | ||||||
| 	DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fpr)); | 	DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fpr)); | ||||||
|  | @ -429,9 +433,11 @@ int main(void) | ||||||
| 	DEFINE(VCPU_SHARED_MAS4, offsetof(struct kvm_vcpu_arch_shared, mas4)); | 	DEFINE(VCPU_SHARED_MAS4, offsetof(struct kvm_vcpu_arch_shared, mas4)); | ||||||
| 	DEFINE(VCPU_SHARED_MAS6, offsetof(struct kvm_vcpu_arch_shared, mas6)); | 	DEFINE(VCPU_SHARED_MAS6, offsetof(struct kvm_vcpu_arch_shared, mas6)); | ||||||
| 
 | 
 | ||||||
|  | 	DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm)); | ||||||
|  | 	DEFINE(KVM_LPID, offsetof(struct kvm, arch.lpid)); | ||||||
|  | 
 | ||||||
| 	/* book3s */ | 	/* book3s */ | ||||||
| #ifdef CONFIG_KVM_BOOK3S_64_HV | #ifdef CONFIG_KVM_BOOK3S_64_HV | ||||||
| 	DEFINE(KVM_LPID, offsetof(struct kvm, arch.lpid)); |  | ||||||
| 	DEFINE(KVM_SDR1, offsetof(struct kvm, arch.sdr1)); | 	DEFINE(KVM_SDR1, offsetof(struct kvm, arch.sdr1)); | ||||||
| 	DEFINE(KVM_HOST_LPID, offsetof(struct kvm, arch.host_lpid)); | 	DEFINE(KVM_HOST_LPID, offsetof(struct kvm, arch.host_lpid)); | ||||||
| 	DEFINE(KVM_HOST_LPCR, offsetof(struct kvm, arch.host_lpcr)); | 	DEFINE(KVM_HOST_LPCR, offsetof(struct kvm, arch.host_lpcr)); | ||||||
|  | @ -446,7 +452,6 @@ int main(void) | ||||||
| 	DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar)); | 	DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar)); | ||||||
| #endif | #endif | ||||||
| #ifdef CONFIG_PPC_BOOK3S | #ifdef CONFIG_PPC_BOOK3S | ||||||
| 	DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm)); |  | ||||||
| 	DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id)); | 	DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id)); | ||||||
| 	DEFINE(VCPU_PURR, offsetof(struct kvm_vcpu, arch.purr)); | 	DEFINE(VCPU_PURR, offsetof(struct kvm_vcpu, arch.purr)); | ||||||
| 	DEFINE(VCPU_SPURR, offsetof(struct kvm_vcpu, arch.spurr)); | 	DEFINE(VCPU_SPURR, offsetof(struct kvm_vcpu, arch.spurr)); | ||||||
|  | @ -597,6 +602,12 @@ int main(void) | ||||||
| 	DEFINE(VCPU_HOST_SPEFSCR, offsetof(struct kvm_vcpu, arch.host_spefscr)); | 	DEFINE(VCPU_HOST_SPEFSCR, offsetof(struct kvm_vcpu, arch.host_spefscr)); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	DEFINE(VCPU_HOST_MAS4, offsetof(struct kvm_vcpu, arch.host_mas4)); | ||||||
|  | 	DEFINE(VCPU_HOST_MAS6, offsetof(struct kvm_vcpu, arch.host_mas6)); | ||||||
|  | 	DEFINE(VCPU_EPLC, offsetof(struct kvm_vcpu, arch.eplc)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_KVM_EXIT_TIMING | #ifdef CONFIG_KVM_EXIT_TIMING | ||||||
| 	DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu, | 	DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu, | ||||||
| 						arch.timing_exit.tv32.tbu)); | 						arch.timing_exit.tv32.tbu)); | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <asm/ptrace.h>	/* for STACK_FRAME_REGS_MARKER */ | #include <asm/ptrace.h>	/* for STACK_FRAME_REGS_MARKER */ | ||||||
| #include <asm/kvm_asm.h> | #include <asm/kvm_asm.h> | ||||||
|  | #include <asm/kvm_booke_hv_asm.h> | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Macros used for common Book-e exception handling |  * Macros used for common Book-e exception handling | ||||||
|  | @ -36,8 +37,9 @@ | ||||||
| 	stw	r11, THREAD_NORMSAVE(0)(r10);				     \ | 	stw	r11, THREAD_NORMSAVE(0)(r10);				     \ | ||||||
| 	stw	r13, THREAD_NORMSAVE(2)(r10);				     \ | 	stw	r13, THREAD_NORMSAVE(2)(r10);				     \ | ||||||
| 	mfcr	r13;			/* save CR in r13 for now	   */\ | 	mfcr	r13;			/* save CR in r13 for now	   */\ | ||||||
| 	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel    */\ | 	mfspr	r11, SPRN_SRR1;		                                     \ | ||||||
| 	andi.	r11,r11,MSR_PR;						     \ | 	DO_KVM	BOOKE_INTERRUPT_##intno SPRN_SRR1;			     \ | ||||||
|  | 	andi.	r11, r11, MSR_PR;	/* check whether user or kernel    */\ | ||||||
| 	mr	r11, r1;						     \ | 	mr	r11, r1;						     \ | ||||||
| 	beq	1f;							     \ | 	beq	1f;							     \ | ||||||
| 	/* if from user, start at top of this thread's kernel stack */       \ | 	/* if from user, start at top of this thread's kernel stack */       \ | ||||||
|  | @ -123,8 +125,9 @@ | ||||||
| 	stw	r10,GPR10(r8);						     \ | 	stw	r10,GPR10(r8);						     \ | ||||||
| 	stw	r11,GPR11(r8);						     \ | 	stw	r11,GPR11(r8);						     \ | ||||||
| 	stw	r9,_CCR(r8);		/* save CR on stack		   */\ | 	stw	r9,_CCR(r8);		/* save CR on stack		   */\ | ||||||
| 	mfspr	r10,exc_level_srr1;	/* check whether user or kernel    */\ | 	mfspr	r11,exc_level_srr1;	/* check whether user or kernel    */\ | ||||||
| 	andi.	r10,r10,MSR_PR;						     \ | 	DO_KVM	BOOKE_INTERRUPT_##intno exc_level_srr1;		             \ | ||||||
|  | 	andi.	r11,r11,MSR_PR;						     \ | ||||||
| 	mfspr	r11,SPRN_SPRG_THREAD;	/* if from user, start at top of   */\ | 	mfspr	r11,SPRN_SPRG_THREAD;	/* if from user, start at top of   */\ | ||||||
| 	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ | 	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ | ||||||
| 	addi	r11,r11,EXC_LVL_FRAME_OVERHEAD;	/* allocate stack frame    */\ | 	addi	r11,r11,EXC_LVL_FRAME_OVERHEAD;	/* allocate stack frame    */\ | ||||||
|  | @ -172,6 +175,23 @@ | ||||||
| 		EXC_LEVEL_EXCEPTION_PROLOG(MC, MACHINE_CHECK, \ | 		EXC_LEVEL_EXCEPTION_PROLOG(MC, MACHINE_CHECK, \ | ||||||
| 			SPRN_MCSRR0, SPRN_MCSRR1) | 			SPRN_MCSRR0, SPRN_MCSRR1) | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Guest Doorbell -- this is a bit odd in that uses GSRR0/1 despite | ||||||
|  |  * being delivered to the host.  This exception can only happen | ||||||
|  |  * inside a KVM guest -- so we just handle up to the DO_KVM rather | ||||||
|  |  * than try to fit this into one of the existing prolog macros. | ||||||
|  |  */ | ||||||
|  | #define GUEST_DOORBELL_EXCEPTION \ | ||||||
|  | 	START_EXCEPTION(GuestDoorbell);					     \ | ||||||
|  | 	mtspr	SPRN_SPRG_WSCRATCH0, r10;	/* save one register */	     \ | ||||||
|  | 	mfspr	r10, SPRN_SPRG_THREAD;					     \ | ||||||
|  | 	stw	r11, THREAD_NORMSAVE(0)(r10);				     \ | ||||||
|  | 	mfspr	r11, SPRN_SRR1;		                                     \ | ||||||
|  | 	stw	r13, THREAD_NORMSAVE(2)(r10);				     \ | ||||||
|  | 	mfcr	r13;			/* save CR in r13 for now	   */\ | ||||||
|  | 	DO_KVM	BOOKE_INTERRUPT_GUEST_DBELL SPRN_GSRR1;			     \ | ||||||
|  | 	trap | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Exception vectors. |  * Exception vectors. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -90,6 +90,9 @@ config KVM_BOOK3S_64_PR | ||||||
| 	depends on KVM_BOOK3S_64 && !KVM_BOOK3S_64_HV | 	depends on KVM_BOOK3S_64 && !KVM_BOOK3S_64_HV | ||||||
| 	select KVM_BOOK3S_PR | 	select KVM_BOOK3S_PR | ||||||
| 
 | 
 | ||||||
|  | config KVM_BOOKE_HV | ||||||
|  | 	bool | ||||||
|  | 
 | ||||||
| config KVM_440 | config KVM_440 | ||||||
| 	bool "KVM support for PowerPC 440 processors" | 	bool "KVM support for PowerPC 440 processors" | ||||||
| 	depends on EXPERIMENTAL && 44x | 	depends on EXPERIMENTAL && 44x | ||||||
|  |  | ||||||
|  | @ -17,6 +17,8 @@ | ||||||
|  * |  * | ||||||
|  * Authors: Hollis Blanchard <hollisb@us.ibm.com> |  * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||||||
|  *          Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> |  *          Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> | ||||||
|  |  *          Scott Wood <scottwood@freescale.com> | ||||||
|  |  *          Varun Sethi <varun.sethi@freescale.com> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <linux/errno.h> | #include <linux/errno.h> | ||||||
|  | @ -30,9 +32,12 @@ | ||||||
| #include <asm/cputable.h> | #include <asm/cputable.h> | ||||||
| #include <asm/uaccess.h> | #include <asm/uaccess.h> | ||||||
| #include <asm/kvm_ppc.h> | #include <asm/kvm_ppc.h> | ||||||
| #include "timing.h" |  | ||||||
| #include <asm/cacheflush.h> | #include <asm/cacheflush.h> | ||||||
|  | #include <asm/dbell.h> | ||||||
|  | #include <asm/hw_irq.h> | ||||||
|  | #include <asm/irq.h> | ||||||
| 
 | 
 | ||||||
|  | #include "timing.h" | ||||||
| #include "booke.h" | #include "booke.h" | ||||||
| 
 | 
 | ||||||
| unsigned long kvmppc_booke_handlers; | unsigned long kvmppc_booke_handlers; | ||||||
|  | @ -55,6 +60,8 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | ||||||
| 	{ "dec",        VCPU_STAT(dec_exits) }, | 	{ "dec",        VCPU_STAT(dec_exits) }, | ||||||
| 	{ "ext_intr",   VCPU_STAT(ext_intr_exits) }, | 	{ "ext_intr",   VCPU_STAT(ext_intr_exits) }, | ||||||
| 	{ "halt_wakeup", VCPU_STAT(halt_wakeup) }, | 	{ "halt_wakeup", VCPU_STAT(halt_wakeup) }, | ||||||
|  | 	{ "doorbell", VCPU_STAT(dbell_exits) }, | ||||||
|  | 	{ "guest doorbell", VCPU_STAT(gdbell_exits) }, | ||||||
| 	{ NULL } | 	{ NULL } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -121,6 +128,10 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr) | ||||||
| { | { | ||||||
| 	u32 old_msr = vcpu->arch.shared->msr; | 	u32 old_msr = vcpu->arch.shared->msr; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	new_msr |= MSR_GS; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	vcpu->arch.shared->msr = new_msr; | 	vcpu->arch.shared->msr = new_msr; | ||||||
| 
 | 
 | ||||||
| 	kvmppc_mmu_msr_notify(vcpu, old_msr); | 	kvmppc_mmu_msr_notify(vcpu, old_msr); | ||||||
|  | @ -195,6 +206,75 @@ void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, | ||||||
| 	clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions); | 	clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void set_guest_srr(struct kvm_vcpu *vcpu, unsigned long srr0, u32 srr1) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	mtspr(SPRN_GSRR0, srr0); | ||||||
|  | 	mtspr(SPRN_GSRR1, srr1); | ||||||
|  | #else | ||||||
|  | 	vcpu->arch.shared->srr0 = srr0; | ||||||
|  | 	vcpu->arch.shared->srr1 = srr1; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void set_guest_csrr(struct kvm_vcpu *vcpu, unsigned long srr0, u32 srr1) | ||||||
|  | { | ||||||
|  | 	vcpu->arch.csrr0 = srr0; | ||||||
|  | 	vcpu->arch.csrr1 = srr1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void set_guest_dsrr(struct kvm_vcpu *vcpu, unsigned long srr0, u32 srr1) | ||||||
|  | { | ||||||
|  | 	if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC)) { | ||||||
|  | 		vcpu->arch.dsrr0 = srr0; | ||||||
|  | 		vcpu->arch.dsrr1 = srr1; | ||||||
|  | 	} else { | ||||||
|  | 		set_guest_csrr(vcpu, srr0, srr1); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void set_guest_mcsrr(struct kvm_vcpu *vcpu, unsigned long srr0, u32 srr1) | ||||||
|  | { | ||||||
|  | 	vcpu->arch.mcsrr0 = srr0; | ||||||
|  | 	vcpu->arch.mcsrr1 = srr1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static unsigned long get_guest_dear(struct kvm_vcpu *vcpu) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	return mfspr(SPRN_GDEAR); | ||||||
|  | #else | ||||||
|  | 	return vcpu->arch.shared->dar; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void set_guest_dear(struct kvm_vcpu *vcpu, unsigned long dear) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	mtspr(SPRN_GDEAR, dear); | ||||||
|  | #else | ||||||
|  | 	vcpu->arch.shared->dar = dear; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static unsigned long get_guest_esr(struct kvm_vcpu *vcpu) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	return mfspr(SPRN_GESR); | ||||||
|  | #else | ||||||
|  | 	return vcpu->arch.shared->esr; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void set_guest_esr(struct kvm_vcpu *vcpu, u32 esr) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	mtspr(SPRN_GESR, esr); | ||||||
|  | #else | ||||||
|  | 	vcpu->arch.shared->esr = esr; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* Deliver the interrupt of the corresponding priority, if possible. */ | /* Deliver the interrupt of the corresponding priority, if possible. */ | ||||||
| static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | ||||||
|                                         unsigned int priority) |                                         unsigned int priority) | ||||||
|  | @ -206,6 +286,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | ||||||
| 	ulong crit_r1 = kvmppc_get_gpr(vcpu, 1); | 	ulong crit_r1 = kvmppc_get_gpr(vcpu, 1); | ||||||
| 	bool crit; | 	bool crit; | ||||||
| 	bool keep_irq = false; | 	bool keep_irq = false; | ||||||
|  | 	enum int_class int_class; | ||||||
| 
 | 
 | ||||||
| 	/* Truncate crit indicators in 32 bit mode */ | 	/* Truncate crit indicators in 32 bit mode */ | ||||||
| 	if (!(vcpu->arch.shared->msr & MSR_SF)) { | 	if (!(vcpu->arch.shared->msr & MSR_SF)) { | ||||||
|  | @ -241,16 +322,20 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | ||||||
| 	case BOOKE_IRQPRIO_AP_UNAVAIL: | 	case BOOKE_IRQPRIO_AP_UNAVAIL: | ||||||
| 	case BOOKE_IRQPRIO_ALIGNMENT: | 	case BOOKE_IRQPRIO_ALIGNMENT: | ||||||
| 		allowed = 1; | 		allowed = 1; | ||||||
| 		msr_mask = MSR_CE|MSR_ME|MSR_DE; | 		msr_mask = MSR_GS | MSR_CE | MSR_ME | MSR_DE; | ||||||
|  | 		int_class = INT_CLASS_NONCRIT; | ||||||
| 		break; | 		break; | ||||||
| 	case BOOKE_IRQPRIO_CRITICAL: | 	case BOOKE_IRQPRIO_CRITICAL: | ||||||
| 	case BOOKE_IRQPRIO_WATCHDOG: |  | ||||||
| 		allowed = vcpu->arch.shared->msr & MSR_CE; | 		allowed = vcpu->arch.shared->msr & MSR_CE; | ||||||
| 		msr_mask = MSR_ME; | 		allowed = allowed && !crit; | ||||||
|  | 		msr_mask = MSR_GS | MSR_ME; | ||||||
|  | 		int_class = INT_CLASS_CRIT; | ||||||
| 		break; | 		break; | ||||||
| 	case BOOKE_IRQPRIO_MACHINE_CHECK: | 	case BOOKE_IRQPRIO_MACHINE_CHECK: | ||||||
| 		allowed = vcpu->arch.shared->msr & MSR_ME; | 		allowed = vcpu->arch.shared->msr & MSR_ME; | ||||||
| 		msr_mask = 0; | 		allowed = allowed && !crit; | ||||||
|  | 		msr_mask = MSR_GS; | ||||||
|  | 		int_class = INT_CLASS_MC; | ||||||
| 		break; | 		break; | ||||||
| 	case BOOKE_IRQPRIO_DECREMENTER: | 	case BOOKE_IRQPRIO_DECREMENTER: | ||||||
| 	case BOOKE_IRQPRIO_FIT: | 	case BOOKE_IRQPRIO_FIT: | ||||||
|  | @ -259,28 +344,62 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | ||||||
| 	case BOOKE_IRQPRIO_EXTERNAL: | 	case BOOKE_IRQPRIO_EXTERNAL: | ||||||
| 		allowed = vcpu->arch.shared->msr & MSR_EE; | 		allowed = vcpu->arch.shared->msr & MSR_EE; | ||||||
| 		allowed = allowed && !crit; | 		allowed = allowed && !crit; | ||||||
| 		msr_mask = MSR_CE|MSR_ME|MSR_DE; | 		msr_mask = MSR_GS | MSR_CE | MSR_ME | MSR_DE; | ||||||
|  | 		int_class = INT_CLASS_NONCRIT; | ||||||
| 		break; | 		break; | ||||||
| 	case BOOKE_IRQPRIO_DEBUG: | 	case BOOKE_IRQPRIO_DEBUG: | ||||||
| 		allowed = vcpu->arch.shared->msr & MSR_DE; | 		allowed = vcpu->arch.shared->msr & MSR_DE; | ||||||
| 		msr_mask = MSR_ME; | 		allowed = allowed && !crit; | ||||||
|  | 		msr_mask = MSR_GS | MSR_ME; | ||||||
|  | 		int_class = INT_CLASS_CRIT; | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (allowed) { | 	if (allowed) { | ||||||
| 		vcpu->arch.shared->srr0 = vcpu->arch.pc; | 		switch (int_class) { | ||||||
| 		vcpu->arch.shared->srr1 = vcpu->arch.shared->msr; | 		case INT_CLASS_NONCRIT: | ||||||
|  | 			set_guest_srr(vcpu, vcpu->arch.pc, | ||||||
|  | 				      vcpu->arch.shared->msr); | ||||||
|  | 			break; | ||||||
|  | 		case INT_CLASS_CRIT: | ||||||
|  | 			set_guest_csrr(vcpu, vcpu->arch.pc, | ||||||
|  | 				       vcpu->arch.shared->msr); | ||||||
|  | 			break; | ||||||
|  | 		case INT_CLASS_DBG: | ||||||
|  | 			set_guest_dsrr(vcpu, vcpu->arch.pc, | ||||||
|  | 				       vcpu->arch.shared->msr); | ||||||
|  | 			break; | ||||||
|  | 		case INT_CLASS_MC: | ||||||
|  | 			set_guest_mcsrr(vcpu, vcpu->arch.pc, | ||||||
|  | 					vcpu->arch.shared->msr); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority]; | 		vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority]; | ||||||
| 		if (update_esr == true) | 		if (update_esr == true) | ||||||
| 			vcpu->arch.shared->esr = vcpu->arch.queued_esr; | 			set_guest_esr(vcpu, vcpu->arch.queued_esr); | ||||||
| 		if (update_dear == true) | 		if (update_dear == true) | ||||||
| 			vcpu->arch.shared->dar = vcpu->arch.queued_dear; | 			set_guest_dear(vcpu, vcpu->arch.queued_dear); | ||||||
| 		kvmppc_set_msr(vcpu, vcpu->arch.shared->msr & msr_mask); | 		kvmppc_set_msr(vcpu, vcpu->arch.shared->msr & msr_mask); | ||||||
| 
 | 
 | ||||||
| 		if (!keep_irq) | 		if (!keep_irq) | ||||||
| 			clear_bit(priority, &vcpu->arch.pending_exceptions); | 			clear_bit(priority, &vcpu->arch.pending_exceptions); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	/*
 | ||||||
|  | 	 * If an interrupt is pending but masked, raise a guest doorbell | ||||||
|  | 	 * so that we are notified when the guest enables the relevant | ||||||
|  | 	 * MSR bit. | ||||||
|  | 	 */ | ||||||
|  | 	if (vcpu->arch.pending_exceptions & BOOKE_IRQMASK_EE) | ||||||
|  | 		kvmppc_set_pending_interrupt(vcpu, INT_CLASS_NONCRIT); | ||||||
|  | 	if (vcpu->arch.pending_exceptions & BOOKE_IRQMASK_CE) | ||||||
|  | 		kvmppc_set_pending_interrupt(vcpu, INT_CLASS_CRIT); | ||||||
|  | 	if (vcpu->arch.pending_exceptions & BOOKE_IRQPRIO_MACHINE_CHECK) | ||||||
|  | 		kvmppc_set_pending_interrupt(vcpu, INT_CLASS_MC); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	return allowed; | 	return allowed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -344,6 +463,11 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (!current->thread.kvm_vcpu) { | ||||||
|  | 		WARN(1, "no vcpu\n"); | ||||||
|  | 		return -EPERM; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	local_irq_disable(); | 	local_irq_disable(); | ||||||
| 
 | 
 | ||||||
| 	kvmppc_core_prepare_to_enter(vcpu); | 	kvmppc_core_prepare_to_enter(vcpu); | ||||||
|  | @ -363,6 +487,38 @@ out: | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||||
|  | { | ||||||
|  | 	enum emulation_result er; | ||||||
|  | 
 | ||||||
|  | 	er = kvmppc_emulate_instruction(run, vcpu); | ||||||
|  | 	switch (er) { | ||||||
|  | 	case EMULATE_DONE: | ||||||
|  | 		/* don't overwrite subtypes, just account kvm_stats */ | ||||||
|  | 		kvmppc_account_exit_stat(vcpu, EMULATED_INST_EXITS); | ||||||
|  | 		/* Future optimization: only reload non-volatiles if
 | ||||||
|  | 		 * they were actually modified by emulation. */ | ||||||
|  | 		return RESUME_GUEST_NV; | ||||||
|  | 
 | ||||||
|  | 	case EMULATE_DO_DCR: | ||||||
|  | 		run->exit_reason = KVM_EXIT_DCR; | ||||||
|  | 		return RESUME_HOST; | ||||||
|  | 
 | ||||||
|  | 	case EMULATE_FAIL: | ||||||
|  | 		/* XXX Deliver Program interrupt to guest. */ | ||||||
|  | 		printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", | ||||||
|  | 		       __func__, vcpu->arch.pc, vcpu->arch.last_inst); | ||||||
|  | 		/* For debugging, encode the failing instruction and
 | ||||||
|  | 		 * report it to userspace. */ | ||||||
|  | 		run->hw.hardware_exit_reason = ~0ULL << 32; | ||||||
|  | 		run->hw.hardware_exit_reason |= vcpu->arch.last_inst; | ||||||
|  | 		return RESUME_HOST; | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		BUG(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * kvmppc_handle_exit |  * kvmppc_handle_exit | ||||||
|  * |  * | ||||||
|  | @ -371,12 +527,30 @@ out: | ||||||
| int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||||
|                        unsigned int exit_nr) |                        unsigned int exit_nr) | ||||||
| { | { | ||||||
| 	enum emulation_result er; |  | ||||||
| 	int r = RESUME_HOST; | 	int r = RESUME_HOST; | ||||||
| 
 | 
 | ||||||
| 	/* update before a new last_exit_type is rewritten */ | 	/* update before a new last_exit_type is rewritten */ | ||||||
| 	kvmppc_update_timing_stats(vcpu); | 	kvmppc_update_timing_stats(vcpu); | ||||||
| 
 | 
 | ||||||
|  | 	switch (exit_nr) { | ||||||
|  | 	case BOOKE_INTERRUPT_EXTERNAL: | ||||||
|  | 		do_IRQ(current->thread.regs); | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case BOOKE_INTERRUPT_DECREMENTER: | ||||||
|  | 		timer_interrupt(current->thread.regs); | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | #if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3E_64) | ||||||
|  | 	case BOOKE_INTERRUPT_DOORBELL: | ||||||
|  | 		doorbell_exception(current->thread.regs); | ||||||
|  | 		break; | ||||||
|  | #endif | ||||||
|  | 	case BOOKE_INTERRUPT_MACHINE_CHECK: | ||||||
|  | 		/* FIXME */ | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	local_irq_enable(); | 	local_irq_enable(); | ||||||
| 
 | 
 | ||||||
| 	run->exit_reason = KVM_EXIT_UNKNOWN; | 	run->exit_reason = KVM_EXIT_UNKNOWN; | ||||||
|  | @ -384,30 +558,56 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||||
| 
 | 
 | ||||||
| 	switch (exit_nr) { | 	switch (exit_nr) { | ||||||
| 	case BOOKE_INTERRUPT_MACHINE_CHECK: | 	case BOOKE_INTERRUPT_MACHINE_CHECK: | ||||||
| 		printk("MACHINE CHECK: %lx\n", mfspr(SPRN_MCSR)); | 		kvm_resched(vcpu); | ||||||
| 		kvmppc_dump_vcpu(vcpu); | 		r = RESUME_GUEST; | ||||||
| 		r = RESUME_HOST; |  | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	case BOOKE_INTERRUPT_EXTERNAL: | 	case BOOKE_INTERRUPT_EXTERNAL: | ||||||
| 		kvmppc_account_exit(vcpu, EXT_INTR_EXITS); | 		kvmppc_account_exit(vcpu, EXT_INTR_EXITS); | ||||||
| 		if (need_resched()) | 		kvm_resched(vcpu); | ||||||
| 			cond_resched(); |  | ||||||
| 		r = RESUME_GUEST; | 		r = RESUME_GUEST; | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	case BOOKE_INTERRUPT_DECREMENTER: | 	case BOOKE_INTERRUPT_DECREMENTER: | ||||||
| 		/* Since we switched IVPR back to the host's value, the host
 |  | ||||||
| 		 * handled this interrupt the moment we enabled interrupts. |  | ||||||
| 		 * Now we just offer it a chance to reschedule the guest. */ |  | ||||||
| 		kvmppc_account_exit(vcpu, DEC_EXITS); | 		kvmppc_account_exit(vcpu, DEC_EXITS); | ||||||
| 		if (need_resched()) | 		kvm_resched(vcpu); | ||||||
| 			cond_resched(); |  | ||||||
| 		r = RESUME_GUEST; | 		r = RESUME_GUEST; | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
|  | 	case BOOKE_INTERRUPT_DOORBELL: | ||||||
|  | 		kvmppc_account_exit(vcpu, DBELL_EXITS); | ||||||
|  | 		kvm_resched(vcpu); | ||||||
|  | 		r = RESUME_GUEST; | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case BOOKE_INTERRUPT_GUEST_DBELL_CRIT: | ||||||
|  | 		kvmppc_account_exit(vcpu, GDBELL_EXITS); | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * We are here because there is a pending guest interrupt | ||||||
|  | 		 * which could not be delivered as MSR_CE or MSR_ME was not | ||||||
|  | 		 * set.  Once we break from here we will retry delivery. | ||||||
|  | 		 */ | ||||||
|  | 		r = RESUME_GUEST; | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case BOOKE_INTERRUPT_GUEST_DBELL: | ||||||
|  | 		kvmppc_account_exit(vcpu, GDBELL_EXITS); | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * We are here because there is a pending guest interrupt | ||||||
|  | 		 * which could not be delivered as MSR_EE was not set.  Once | ||||||
|  | 		 * we break from here we will retry delivery. | ||||||
|  | 		 */ | ||||||
|  | 		r = RESUME_GUEST; | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case BOOKE_INTERRUPT_HV_PRIV: | ||||||
|  | 		r = emulation_exit(run, vcpu); | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
| 	case BOOKE_INTERRUPT_PROGRAM: | 	case BOOKE_INTERRUPT_PROGRAM: | ||||||
| 		if (vcpu->arch.shared->msr & MSR_PR) { | 		if (vcpu->arch.shared->msr & (MSR_PR | MSR_GS)) { | ||||||
| 			/* Program traps generated by user-level software must be handled
 | 			/* Program traps generated by user-level software must be handled
 | ||||||
| 			 * by the guest kernel. */ | 			 * by the guest kernel. */ | ||||||
| 			kvmppc_core_queue_program(vcpu, vcpu->arch.fault_esr); | 			kvmppc_core_queue_program(vcpu, vcpu->arch.fault_esr); | ||||||
|  | @ -416,32 +616,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		er = kvmppc_emulate_instruction(run, vcpu); | 		r = emulation_exit(run, vcpu); | ||||||
| 		switch (er) { |  | ||||||
| 		case EMULATE_DONE: |  | ||||||
| 			/* don't overwrite subtypes, just account kvm_stats */ |  | ||||||
| 			kvmppc_account_exit_stat(vcpu, EMULATED_INST_EXITS); |  | ||||||
| 			/* Future optimization: only reload non-volatiles if
 |  | ||||||
| 			 * they were actually modified by emulation. */ |  | ||||||
| 			r = RESUME_GUEST_NV; |  | ||||||
| 			break; |  | ||||||
| 		case EMULATE_DO_DCR: |  | ||||||
| 			run->exit_reason = KVM_EXIT_DCR; |  | ||||||
| 			r = RESUME_HOST; |  | ||||||
| 			break; |  | ||||||
| 		case EMULATE_FAIL: |  | ||||||
| 			/* XXX Deliver Program interrupt to guest. */ |  | ||||||
| 			printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", |  | ||||||
| 			       __func__, vcpu->arch.pc, vcpu->arch.last_inst); |  | ||||||
| 			/* For debugging, encode the failing instruction and
 |  | ||||||
| 			 * report it to userspace. */ |  | ||||||
| 			run->hw.hardware_exit_reason = ~0ULL << 32; |  | ||||||
| 			run->hw.hardware_exit_reason |= vcpu->arch.last_inst; |  | ||||||
| 			r = RESUME_HOST; |  | ||||||
| 			break; |  | ||||||
| 		default: |  | ||||||
| 			BUG(); |  | ||||||
| 		} |  | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	case BOOKE_INTERRUPT_FP_UNAVAIL: | 	case BOOKE_INTERRUPT_FP_UNAVAIL: | ||||||
|  | @ -506,6 +681,21 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||||
| 		r = RESUME_GUEST; | 		r = RESUME_GUEST; | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	case BOOKE_INTERRUPT_HV_SYSCALL: | ||||||
|  | 		if (!(vcpu->arch.shared->msr & MSR_PR)) { | ||||||
|  | 			kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu)); | ||||||
|  | 		} else { | ||||||
|  | 			/*
 | ||||||
|  | 			 * hcall from guest userspace -- send privileged | ||||||
|  | 			 * instruction program check. | ||||||
|  | 			 */ | ||||||
|  | 			kvmppc_core_queue_program(vcpu, ESR_PPR); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		r = RESUME_GUEST; | ||||||
|  | 		break; | ||||||
|  | #else | ||||||
| 	case BOOKE_INTERRUPT_SYSCALL: | 	case BOOKE_INTERRUPT_SYSCALL: | ||||||
| 		if (!(vcpu->arch.shared->msr & MSR_PR) && | 		if (!(vcpu->arch.shared->msr & MSR_PR) && | ||||||
| 		    (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) { | 		    (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) { | ||||||
|  | @ -519,6 +709,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||||
| 		kvmppc_account_exit(vcpu, SYSCALL_EXITS); | 		kvmppc_account_exit(vcpu, SYSCALL_EXITS); | ||||||
| 		r = RESUME_GUEST; | 		r = RESUME_GUEST; | ||||||
| 		break; | 		break; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	case BOOKE_INTERRUPT_DTLB_MISS: { | 	case BOOKE_INTERRUPT_DTLB_MISS: { | ||||||
| 		unsigned long eaddr = vcpu->arch.fault_dear; | 		unsigned long eaddr = vcpu->arch.fault_dear; | ||||||
|  | @ -659,12 +850,15 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	vcpu->arch.pc = 0; | 	vcpu->arch.pc = 0; | ||||||
| 	vcpu->arch.shared->msr = 0; |  | ||||||
| 	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS; |  | ||||||
| 	vcpu->arch.shared->pir = vcpu->vcpu_id; | 	vcpu->arch.shared->pir = vcpu->vcpu_id; | ||||||
| 	kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */ | 	kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */ | ||||||
|  | 	kvmppc_set_msr(vcpu, 0); | ||||||
| 
 | 
 | ||||||
|  | #ifndef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS; | ||||||
| 	vcpu->arch.shadow_pid = 1; | 	vcpu->arch.shadow_pid = 1; | ||||||
|  | 	vcpu->arch.shared->msr = 0; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	/* Eye-catching numbers so we know if the guest takes an interrupt
 | 	/* Eye-catching numbers so we know if the guest takes an interrupt
 | ||||||
| 	 * before it's programmed its own IVPR/IVORs. */ | 	 * before it's programmed its own IVPR/IVORs. */ | ||||||
|  | @ -745,8 +939,8 @@ static void get_sregs_base(struct kvm_vcpu *vcpu, | ||||||
| 	sregs->u.e.csrr0 = vcpu->arch.csrr0; | 	sregs->u.e.csrr0 = vcpu->arch.csrr0; | ||||||
| 	sregs->u.e.csrr1 = vcpu->arch.csrr1; | 	sregs->u.e.csrr1 = vcpu->arch.csrr1; | ||||||
| 	sregs->u.e.mcsr = vcpu->arch.mcsr; | 	sregs->u.e.mcsr = vcpu->arch.mcsr; | ||||||
| 	sregs->u.e.esr = vcpu->arch.shared->esr; | 	sregs->u.e.esr = get_guest_esr(vcpu); | ||||||
| 	sregs->u.e.dear = vcpu->arch.shared->dar; | 	sregs->u.e.dear = get_guest_dear(vcpu); | ||||||
| 	sregs->u.e.tsr = vcpu->arch.tsr; | 	sregs->u.e.tsr = vcpu->arch.tsr; | ||||||
| 	sregs->u.e.tcr = vcpu->arch.tcr; | 	sregs->u.e.tcr = vcpu->arch.tcr; | ||||||
| 	sregs->u.e.dec = kvmppc_get_dec(vcpu, tb); | 	sregs->u.e.dec = kvmppc_get_dec(vcpu, tb); | ||||||
|  | @ -763,8 +957,8 @@ static int set_sregs_base(struct kvm_vcpu *vcpu, | ||||||
| 	vcpu->arch.csrr0 = sregs->u.e.csrr0; | 	vcpu->arch.csrr0 = sregs->u.e.csrr0; | ||||||
| 	vcpu->arch.csrr1 = sregs->u.e.csrr1; | 	vcpu->arch.csrr1 = sregs->u.e.csrr1; | ||||||
| 	vcpu->arch.mcsr = sregs->u.e.mcsr; | 	vcpu->arch.mcsr = sregs->u.e.mcsr; | ||||||
| 	vcpu->arch.shared->esr = sregs->u.e.esr; | 	set_guest_esr(vcpu, sregs->u.e.esr); | ||||||
| 	vcpu->arch.shared->dar = sregs->u.e.dear; | 	set_guest_dear(vcpu, sregs->u.e.dear); | ||||||
| 	vcpu->arch.vrsave = sregs->u.e.vrsave; | 	vcpu->arch.vrsave = sregs->u.e.vrsave; | ||||||
| 	kvmppc_set_tcr(vcpu, sregs->u.e.tcr); | 	kvmppc_set_tcr(vcpu, sregs->u.e.tcr); | ||||||
| 
 | 
 | ||||||
|  | @ -961,14 +1155,17 @@ void kvmppc_decrementer_func(unsigned long data) | ||||||
| 
 | 
 | ||||||
| void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||||||
| { | { | ||||||
|  | 	current->thread.kvm_vcpu = vcpu; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu) | void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu) | ||||||
| { | { | ||||||
|  | 	current->thread.kvm_vcpu = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int __init kvmppc_booke_init(void) | int __init kvmppc_booke_init(void) | ||||||
| { | { | ||||||
|  | #ifndef CONFIG_KVM_BOOKE_HV | ||||||
| 	unsigned long ivor[16]; | 	unsigned long ivor[16]; | ||||||
| 	unsigned long max_ivor = 0; | 	unsigned long max_ivor = 0; | ||||||
| 	int i; | 	int i; | ||||||
|  | @ -1011,7 +1208,7 @@ int __init kvmppc_booke_init(void) | ||||||
| 	} | 	} | ||||||
| 	flush_icache_range(kvmppc_booke_handlers, | 	flush_icache_range(kvmppc_booke_handlers, | ||||||
| 	                   kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); | 	                   kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); | ||||||
| 
 | #endif /* !BOOKE_HV */ | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -48,7 +48,20 @@ | ||||||
| #define BOOKE_IRQPRIO_PERFORMANCE_MONITOR 19 | #define BOOKE_IRQPRIO_PERFORMANCE_MONITOR 19 | ||||||
| /* Internal pseudo-irqprio for level triggered externals */ | /* Internal pseudo-irqprio for level triggered externals */ | ||||||
| #define BOOKE_IRQPRIO_EXTERNAL_LEVEL 20 | #define BOOKE_IRQPRIO_EXTERNAL_LEVEL 20 | ||||||
| #define BOOKE_IRQPRIO_MAX 20 | #define BOOKE_IRQPRIO_DBELL 21 | ||||||
|  | #define BOOKE_IRQPRIO_DBELL_CRIT 22 | ||||||
|  | #define BOOKE_IRQPRIO_MAX 23 | ||||||
|  | 
 | ||||||
|  | #define BOOKE_IRQMASK_EE ((1 << BOOKE_IRQPRIO_EXTERNAL_LEVEL) | \ | ||||||
|  | 			  (1 << BOOKE_IRQPRIO_PERFORMANCE_MONITOR) | \ | ||||||
|  | 			  (1 << BOOKE_IRQPRIO_DBELL) | \ | ||||||
|  | 			  (1 << BOOKE_IRQPRIO_DECREMENTER) | \ | ||||||
|  | 			  (1 << BOOKE_IRQPRIO_FIT) | \ | ||||||
|  | 			  (1 << BOOKE_IRQPRIO_EXTERNAL)) | ||||||
|  | 
 | ||||||
|  | #define BOOKE_IRQMASK_CE ((1 << BOOKE_IRQPRIO_DBELL_CRIT) | \ | ||||||
|  | 			  (1 << BOOKE_IRQPRIO_WATCHDOG) | \ | ||||||
|  | 			  (1 << BOOKE_IRQPRIO_CRITICAL)) | ||||||
| 
 | 
 | ||||||
| extern unsigned long kvmppc_booke_handlers; | extern unsigned long kvmppc_booke_handlers; | ||||||
| 
 | 
 | ||||||
|  | @ -74,4 +87,13 @@ void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu); | ||||||
| void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu); | void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu); | ||||||
| void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu); | void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu); | ||||||
| 
 | 
 | ||||||
|  | enum int_class { | ||||||
|  | 	INT_CLASS_NONCRIT, | ||||||
|  | 	INT_CLASS_CRIT, | ||||||
|  | 	INT_CLASS_MC, | ||||||
|  | 	INT_CLASS_DBG, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void kvmppc_set_pending_interrupt(struct kvm_vcpu *vcpu, enum int_class type); | ||||||
|  | 
 | ||||||
| #endif /* __KVM_BOOKE_H__ */ | #endif /* __KVM_BOOKE_H__ */ | ||||||
|  |  | ||||||
|  | @ -99,6 +99,12 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||||
| 	return emulated; | 	return emulated; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * NOTE: some of these registers are not emulated on BOOKE_HV (GS-mode). | ||||||
|  |  * Their backing store is in real registers, and these functions | ||||||
|  |  * will return the wrong result if called for them in another context | ||||||
|  |  * (such as debugging). | ||||||
|  |  */ | ||||||
| int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||||||
| { | { | ||||||
| 	int emulated = EMULATE_DONE; | 	int emulated = EMULATE_DONE; | ||||||
|  | @ -122,9 +128,11 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||||||
| 		kvmppc_set_tcr(vcpu, spr_val); | 		kvmppc_set_tcr(vcpu, spr_val); | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	/* Note: SPRG4-7 are user-readable. These values are
 | 	/*
 | ||||||
| 	 * loaded into the real SPRGs when resuming the | 	 * Note: SPRG4-7 are user-readable. | ||||||
| 	 * guest. */ | 	 * These values are loaded into the real SPRGs when resuming the | ||||||
|  | 	 * guest (PR-mode only). | ||||||
|  | 	 */ | ||||||
| 	case SPRN_SPRG4: | 	case SPRN_SPRG4: | ||||||
| 		vcpu->arch.shared->sprg4 = spr_val; break; | 		vcpu->arch.shared->sprg4 = spr_val; break; | ||||||
| 	case SPRN_SPRG5: | 	case SPRN_SPRG5: | ||||||
|  | @ -136,6 +144,9 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||||||
| 
 | 
 | ||||||
| 	case SPRN_IVPR: | 	case SPRN_IVPR: | ||||||
| 		vcpu->arch.ivpr = spr_val; | 		vcpu->arch.ivpr = spr_val; | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 		mtspr(SPRN_GIVPR, spr_val); | ||||||
|  | #endif | ||||||
| 		break; | 		break; | ||||||
| 	case SPRN_IVOR0: | 	case SPRN_IVOR0: | ||||||
| 		vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] = spr_val; | 		vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] = spr_val; | ||||||
|  | @ -145,6 +156,9 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||||||
| 		break; | 		break; | ||||||
| 	case SPRN_IVOR2: | 	case SPRN_IVOR2: | ||||||
| 		vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE] = spr_val; | 		vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE] = spr_val; | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 		mtspr(SPRN_GIVOR2, spr_val); | ||||||
|  | #endif | ||||||
| 		break; | 		break; | ||||||
| 	case SPRN_IVOR3: | 	case SPRN_IVOR3: | ||||||
| 		vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE] = spr_val; | 		vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE] = spr_val; | ||||||
|  | @ -163,6 +177,9 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||||||
| 		break; | 		break; | ||||||
| 	case SPRN_IVOR8: | 	case SPRN_IVOR8: | ||||||
| 		vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL] = spr_val; | 		vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL] = spr_val; | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 		mtspr(SPRN_GIVOR8, spr_val); | ||||||
|  | #endif | ||||||
| 		break; | 		break; | ||||||
| 	case SPRN_IVOR9: | 	case SPRN_IVOR9: | ||||||
| 		vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL] = spr_val; | 		vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL] = spr_val; | ||||||
|  |  | ||||||
							
								
								
									
										587
									
								
								arch/powerpc/kvm/bookehv_interrupts.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										587
									
								
								arch/powerpc/kvm/bookehv_interrupts.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,587 @@ | ||||||
|  | /* | ||||||
|  |  * 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. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. | ||||||
|  |  * | ||||||
|  |  * Author: Varun Sethi <varun.sethi@freescale.com>
 | ||||||
|  |  * Author: Scott Wood <scotwood@freescale.com>
 | ||||||
|  |  * | ||||||
|  |  * This file is derived from arch/powerpc/kvm/booke_interrupts.S | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <asm/ppc_asm.h> | ||||||
|  | #include <asm/kvm_asm.h> | ||||||
|  | #include <asm/reg.h> | ||||||
|  | #include <asm/mmu-44x.h> | ||||||
|  | #include <asm/page.h> | ||||||
|  | #include <asm/asm-compat.h> | ||||||
|  | #include <asm/asm-offsets.h> | ||||||
|  | #include <asm/bitsperlong.h> | ||||||
|  | 
 | ||||||
|  | #include "../kernel/head_booke.h" /* for THREAD_NORMSAVE() */ | ||||||
|  | 
 | ||||||
|  | #define GET_VCPU(vcpu, thread)	\ | ||||||
|  | 	PPC_LL	vcpu, THREAD_KVM_VCPU(thread) | ||||||
|  | 
 | ||||||
|  | #define SET_VCPU(vcpu)		\ | ||||||
|  |         PPC_STL	vcpu, (THREAD + THREAD_KVM_VCPU)(r2) | ||||||
|  | 
 | ||||||
|  | #define LONGBYTES		(BITS_PER_LONG / 8) | ||||||
|  | 
 | ||||||
|  | #define VCPU_GPR(n)     	(VCPU_GPRS + (n * LONGBYTES)) | ||||||
|  | #define VCPU_GUEST_SPRG(n)	(VCPU_GUEST_SPRGS + (n * LONGBYTES)) | ||||||
|  | 
 | ||||||
|  | /* The host stack layout: */ | ||||||
|  | #define HOST_R1         (0 * LONGBYTES) /* Implied by stwu. */ | ||||||
|  | #define HOST_CALLEE_LR  (1 * LONGBYTES) | ||||||
|  | #define HOST_RUN        (2 * LONGBYTES) /* struct kvm_run */ | ||||||
|  | /* | ||||||
|  |  * r2 is special: it holds 'current', and it made nonvolatile in the | ||||||
|  |  * kernel with the -ffixed-r2 gcc option. | ||||||
|  |  */ | ||||||
|  | #define HOST_R2         (3 * LONGBYTES) | ||||||
|  | #define HOST_NV_GPRS    (4 * LONGBYTES) | ||||||
|  | #define HOST_NV_GPR(n)  (HOST_NV_GPRS + ((n - 14) * LONGBYTES)) | ||||||
|  | #define HOST_MIN_STACK_SIZE (HOST_NV_GPR(31) + LONGBYTES) | ||||||
|  | #define HOST_STACK_SIZE ((HOST_MIN_STACK_SIZE + 15) & ~15) /* Align. */ | ||||||
|  | #define HOST_STACK_LR   (HOST_STACK_SIZE + LONGBYTES) /* In caller stack frame. */ | ||||||
|  | 
 | ||||||
|  | #define NEED_EMU		0x00000001 /* emulation -- save nv regs */ | ||||||
|  | #define NEED_DEAR		0x00000002 /* save faulting DEAR */ | ||||||
|  | #define NEED_ESR		0x00000004 /* save faulting ESR */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * On entry: | ||||||
|  |  * r4 = vcpu, r5 = srr0, r6 = srr1 | ||||||
|  |  * saved in vcpu: cr, ctr, r3-r13 | ||||||
|  |  */ | ||||||
|  | .macro kvm_handler_common intno, srr0, flags | ||||||
|  | 	mfspr	r10, SPRN_PID | ||||||
|  | 	lwz	r8, VCPU_HOST_PID(r4) | ||||||
|  | 	PPC_LL	r11, VCPU_SHARED(r4) | ||||||
|  | 	PPC_STL	r14, VCPU_GPR(r14)(r4) /* We need a non-volatile GPR. */ | ||||||
|  | 	li	r14, \intno | ||||||
|  | 
 | ||||||
|  | 	stw	r10, VCPU_GUEST_PID(r4) | ||||||
|  | 	mtspr	SPRN_PID, r8 | ||||||
|  | 
 | ||||||
|  | 	.if	\flags & NEED_EMU | ||||||
|  | 	lwz	r9, VCPU_KVM(r4) | ||||||
|  | 	.endif | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_KVM_EXIT_TIMING | ||||||
|  | 	/* save exit time */ | ||||||
|  | 1:	mfspr	r7, SPRN_TBRU | ||||||
|  | 	mfspr	r8, SPRN_TBRL | ||||||
|  | 	mfspr	r9, SPRN_TBRU | ||||||
|  | 	cmpw	r9, r7 | ||||||
|  | 	PPC_STL	r8, VCPU_TIMING_EXIT_TBL(r4) | ||||||
|  | 	bne-	1b | ||||||
|  | 	PPC_STL	r9, VCPU_TIMING_EXIT_TBU(r4) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	oris	r8, r6, MSR_CE@h
 | ||||||
|  | #ifndef CONFIG_64BIT | ||||||
|  | 	stw	r6, (VCPU_SHARED_MSR + 4)(r11) | ||||||
|  | #else | ||||||
|  | 	std	r6, (VCPU_SHARED_MSR)(r11) | ||||||
|  | #endif | ||||||
|  | 	ori	r8, r8, MSR_ME | MSR_RI | ||||||
|  | 	PPC_STL	r5, VCPU_PC(r4) | ||||||
|  | 
 | ||||||
|  | 	/* | ||||||
|  | 	 * Make sure CE/ME/RI are set (if appropriate for exception type) | ||||||
|  | 	 * whether or not the guest had it set.  Since mfmsr/mtmsr are | ||||||
|  | 	 * somewhat expensive, skip in the common case where the guest | ||||||
|  | 	 * had all these bits set (and thus they're still set if | ||||||
|  | 	 * appropriate for the exception type). | ||||||
|  | 	 */ | ||||||
|  | 	cmpw	r6, r8 | ||||||
|  | 	.if	\flags & NEED_EMU | ||||||
|  | 	lwz	r9, KVM_LPID(r9) | ||||||
|  | 	.endif | ||||||
|  | 	beq	1f | ||||||
|  | 	mfmsr	r7 | ||||||
|  | 	.if	\srr0 != SPRN_MCSRR0 && \srr0 != SPRN_CSRR0 | ||||||
|  | 	oris	r7, r7, MSR_CE@h
 | ||||||
|  | 	.endif | ||||||
|  | 	.if	\srr0 != SPRN_MCSRR0 | ||||||
|  | 	ori	r7, r7, MSR_ME | MSR_RI | ||||||
|  | 	.endif | ||||||
|  | 	mtmsr	r7 | ||||||
|  | 1: | ||||||
|  | 
 | ||||||
|  | 	.if	\flags & NEED_EMU | ||||||
|  | 	/* | ||||||
|  | 	 * This assumes you have external PID support. | ||||||
|  | 	 * To support a bookehv CPU without external PID, you'll | ||||||
|  | 	 * need to look up the TLB entry and create a temporary mapping. | ||||||
|  | 	 * | ||||||
|  | 	 * FIXME: we don't currently handle if the lwepx faults.  PR-mode | ||||||
|  | 	 * booke doesn't handle it either.  Since Linux doesn't use | ||||||
|  | 	 * broadcast tlbivax anymore, the only way this should happen is | ||||||
|  | 	 * if the guest maps its memory execute-but-not-read, or if we | ||||||
|  | 	 * somehow take a TLB miss in the middle of this entry code and | ||||||
|  | 	 * evict the relevant entry.  On e500mc, all kernel lowmem is | ||||||
|  | 	 * bolted into TLB1 large page mappings, and we don't use | ||||||
|  | 	 * broadcast invalidates, so we should not take a TLB miss here. | ||||||
|  | 	 * | ||||||
|  | 	 * Later we'll need to deal with faults here.  Disallowing guest | ||||||
|  | 	 * mappings that are execute-but-not-read could be an option on | ||||||
|  | 	 * e500mc, but not on chips with an LRAT if it is used. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	mfspr	r3, SPRN_EPLC	/* will already have correct ELPID and EGS */ | ||||||
|  | 	PPC_STL	r15, VCPU_GPR(r15)(r4) | ||||||
|  | 	PPC_STL	r16, VCPU_GPR(r16)(r4) | ||||||
|  | 	PPC_STL	r17, VCPU_GPR(r17)(r4) | ||||||
|  | 	PPC_STL	r18, VCPU_GPR(r18)(r4) | ||||||
|  | 	PPC_STL	r19, VCPU_GPR(r19)(r4) | ||||||
|  | 	mr	r8, r3 | ||||||
|  | 	PPC_STL	r20, VCPU_GPR(r20)(r4) | ||||||
|  | 	rlwimi	r8, r6, EPC_EAS_SHIFT - MSR_IR_LG, EPC_EAS | ||||||
|  | 	PPC_STL	r21, VCPU_GPR(r21)(r4) | ||||||
|  | 	rlwimi	r8, r6, EPC_EPR_SHIFT - MSR_PR_LG, EPC_EPR | ||||||
|  | 	PPC_STL	r22, VCPU_GPR(r22)(r4) | ||||||
|  | 	rlwimi	r8, r10, EPC_EPID_SHIFT, EPC_EPID | ||||||
|  | 	PPC_STL	r23, VCPU_GPR(r23)(r4) | ||||||
|  | 	PPC_STL	r24, VCPU_GPR(r24)(r4) | ||||||
|  | 	PPC_STL	r25, VCPU_GPR(r25)(r4) | ||||||
|  | 	PPC_STL	r26, VCPU_GPR(r26)(r4) | ||||||
|  | 	PPC_STL	r27, VCPU_GPR(r27)(r4) | ||||||
|  | 	PPC_STL	r28, VCPU_GPR(r28)(r4) | ||||||
|  | 	PPC_STL	r29, VCPU_GPR(r29)(r4) | ||||||
|  | 	PPC_STL	r30, VCPU_GPR(r30)(r4) | ||||||
|  | 	PPC_STL	r31, VCPU_GPR(r31)(r4) | ||||||
|  | 	mtspr	SPRN_EPLC, r8 | ||||||
|  | 	isync | ||||||
|  | 	lwepx	r9, 0, r5 | ||||||
|  | 	mtspr	SPRN_EPLC, r3 | ||||||
|  | 	stw	r9, VCPU_LAST_INST(r4) | ||||||
|  | 	.endif | ||||||
|  | 
 | ||||||
|  | 	.if	\flags & NEED_ESR | ||||||
|  | 	mfspr	r8, SPRN_ESR | ||||||
|  | 	PPC_STL	r8, VCPU_FAULT_ESR(r4) | ||||||
|  | 	.endif | ||||||
|  | 
 | ||||||
|  | 	.if	\flags & NEED_DEAR | ||||||
|  | 	mfspr	r9, SPRN_DEAR | ||||||
|  | 	PPC_STL	r9, VCPU_FAULT_DEAR(r4) | ||||||
|  | 	.endif | ||||||
|  | 
 | ||||||
|  | 	b	kvmppc_resume_host | ||||||
|  | .endm | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h | ||||||
|  |  */ | ||||||
|  | .macro kvm_handler intno srr0, srr1, flags | ||||||
|  | _GLOBAL(kvmppc_handler_\intno\()_\srr1) | ||||||
|  | 	GET_VCPU(r11, r10) | ||||||
|  | 	PPC_STL r3, VCPU_GPR(r3)(r11) | ||||||
|  | 	mfspr	r3, SPRN_SPRG_RSCRATCH0 | ||||||
|  | 	PPC_STL	r4, VCPU_GPR(r4)(r11) | ||||||
|  | 	PPC_LL	r4, THREAD_NORMSAVE(0)(r10) | ||||||
|  | 	PPC_STL	r5, VCPU_GPR(r5)(r11) | ||||||
|  | 	PPC_STL	r13, VCPU_CR(r11) | ||||||
|  | 	mfspr	r5, \srr0 | ||||||
|  | 	PPC_STL	r3, VCPU_GPR(r10)(r11) | ||||||
|  | 	PPC_LL	r3, THREAD_NORMSAVE(2)(r10) | ||||||
|  | 	PPC_STL	r6, VCPU_GPR(r6)(r11) | ||||||
|  | 	PPC_STL	r4, VCPU_GPR(r11)(r11) | ||||||
|  | 	mfspr	r6, \srr1 | ||||||
|  | 	PPC_STL	r7, VCPU_GPR(r7)(r11) | ||||||
|  | 	PPC_STL	r8, VCPU_GPR(r8)(r11) | ||||||
|  | 	PPC_STL	r9, VCPU_GPR(r9)(r11) | ||||||
|  | 	PPC_STL r3, VCPU_GPR(r13)(r11) | ||||||
|  | 	mfctr	r7 | ||||||
|  | 	PPC_STL	r12, VCPU_GPR(r12)(r11) | ||||||
|  | 	PPC_STL	r7, VCPU_CTR(r11) | ||||||
|  | 	mr	r4, r11 | ||||||
|  | 	kvm_handler_common \intno, \srr0, \flags | ||||||
|  | .endm | ||||||
|  | 
 | ||||||
|  | .macro kvm_lvl_handler intno scratch srr0, srr1, flags | ||||||
|  | _GLOBAL(kvmppc_handler_\intno\()_\srr1) | ||||||
|  | 	mfspr	r10, SPRN_SPRG_THREAD | ||||||
|  | 	GET_VCPU(r11, r10) | ||||||
|  | 	PPC_STL r3, VCPU_GPR(r3)(r11) | ||||||
|  | 	mfspr	r3, \scratch | ||||||
|  | 	PPC_STL	r4, VCPU_GPR(r4)(r11) | ||||||
|  | 	PPC_LL	r4, GPR9(r8) | ||||||
|  | 	PPC_STL	r5, VCPU_GPR(r5)(r11) | ||||||
|  | 	PPC_STL	r9, VCPU_CR(r11) | ||||||
|  | 	mfspr	r5, \srr0 | ||||||
|  | 	PPC_STL	r3, VCPU_GPR(r8)(r11) | ||||||
|  | 	PPC_LL	r3, GPR10(r8) | ||||||
|  | 	PPC_STL	r6, VCPU_GPR(r6)(r11) | ||||||
|  | 	PPC_STL	r4, VCPU_GPR(r9)(r11) | ||||||
|  | 	mfspr	r6, \srr1 | ||||||
|  | 	PPC_LL	r4, GPR11(r8) | ||||||
|  | 	PPC_STL	r7, VCPU_GPR(r7)(r11) | ||||||
|  | 	PPC_STL	r8, VCPU_GPR(r8)(r11) | ||||||
|  | 	PPC_STL r3, VCPU_GPR(r10)(r11) | ||||||
|  | 	mfctr	r7 | ||||||
|  | 	PPC_STL	r12, VCPU_GPR(r12)(r11) | ||||||
|  | 	PPC_STL	r4, VCPU_GPR(r11)(r11) | ||||||
|  | 	PPC_STL	r7, VCPU_CTR(r11) | ||||||
|  | 	mr	r4, r11 | ||||||
|  | 	kvm_handler_common \intno, \srr0, \flags | ||||||
|  | .endm | ||||||
|  | 
 | ||||||
|  | kvm_lvl_handler BOOKE_INTERRUPT_CRITICAL, \ | ||||||
|  | 	SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, 0 | ||||||
|  | kvm_lvl_handler BOOKE_INTERRUPT_MACHINE_CHECK, \ | ||||||
|  | 	SPRN_SPRG_RSCRATCH_MC, SPRN_MCSRR0, SPRN_MCSRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_DATA_STORAGE, \ | ||||||
|  | 	SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR) | ||||||
|  | kvm_handler BOOKE_INTERRUPT_INST_STORAGE, SPRN_SRR0, SPRN_SRR1, NEED_ESR | ||||||
|  | kvm_handler BOOKE_INTERRUPT_EXTERNAL, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_ALIGNMENT, \ | ||||||
|  | 	SPRN_SRR0, SPRN_SRR1, (NEED_DEAR | NEED_ESR) | ||||||
|  | kvm_handler BOOKE_INTERRUPT_PROGRAM, SPRN_SRR0, SPRN_SRR1, NEED_ESR | ||||||
|  | kvm_handler BOOKE_INTERRUPT_FP_UNAVAIL, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_SYSCALL, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_AP_UNAVAIL, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_DECREMENTER, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_FIT, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_lvl_handler BOOKE_INTERRUPT_WATCHDOG, \ | ||||||
|  | 	SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_DTLB_MISS, \ | ||||||
|  | 	SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) | ||||||
|  | kvm_handler BOOKE_INTERRUPT_ITLB_MISS, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_DOORBELL, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_lvl_handler BOOKE_INTERRUPT_DOORBELL_CRITICAL, \ | ||||||
|  | 	SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_HV_PRIV, SPRN_SRR0, SPRN_SRR1, NEED_EMU | ||||||
|  | kvm_handler BOOKE_INTERRUPT_HV_SYSCALL, SPRN_SRR0, SPRN_SRR1, 0 | ||||||
|  | kvm_handler BOOKE_INTERRUPT_GUEST_DBELL, SPRN_GSRR0, SPRN_GSRR1, 0 | ||||||
|  | kvm_lvl_handler BOOKE_INTERRUPT_GUEST_DBELL_CRIT, \ | ||||||
|  | 	SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, 0 | ||||||
|  | kvm_lvl_handler BOOKE_INTERRUPT_DEBUG, \ | ||||||
|  | 	SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, 0 | ||||||
|  | kvm_lvl_handler BOOKE_INTERRUPT_DEBUG, \ | ||||||
|  | 	SPRN_SPRG_RSCRATCH_DBG, SPRN_DSRR0, SPRN_DSRR1, 0 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* Registers: | ||||||
|  |  *  SPRG_SCRATCH0: guest r10 | ||||||
|  |  *  r4: vcpu pointer | ||||||
|  |  *  r11: vcpu->arch.shared | ||||||
|  |  *  r14: KVM exit number | ||||||
|  |  */ | ||||||
|  | _GLOBAL(kvmppc_resume_host) | ||||||
|  | 	/* Save remaining volatile guest register state to vcpu. */ | ||||||
|  | 	mfspr	r3, SPRN_VRSAVE | ||||||
|  | 	PPC_STL	r0, VCPU_GPR(r0)(r4) | ||||||
|  | 	PPC_STL	r1, VCPU_GPR(r1)(r4) | ||||||
|  | 	mflr	r5 | ||||||
|  | 	mfspr	r6, SPRN_SPRG4 | ||||||
|  | 	PPC_STL	r2, VCPU_GPR(r2)(r4) | ||||||
|  | 	PPC_STL	r5, VCPU_LR(r4) | ||||||
|  | 	mfspr	r7, SPRN_SPRG5 | ||||||
|  | 	PPC_STL	r3, VCPU_VRSAVE(r4) | ||||||
|  | 	PPC_STL	r6, VCPU_SHARED_SPRG4(r11) | ||||||
|  | 	mfspr	r8, SPRN_SPRG6 | ||||||
|  | 	PPC_STL	r7, VCPU_SHARED_SPRG5(r11) | ||||||
|  | 	mfspr	r9, SPRN_SPRG7 | ||||||
|  | 	PPC_STL	r8, VCPU_SHARED_SPRG6(r11) | ||||||
|  | 	mfxer	r3 | ||||||
|  | 	PPC_STL	r9, VCPU_SHARED_SPRG7(r11) | ||||||
|  | 
 | ||||||
|  | 	/* save guest MAS registers and restore host mas4 & mas6 */ | ||||||
|  | 	mfspr	r5, SPRN_MAS0 | ||||||
|  | 	PPC_STL	r3, VCPU_XER(r4) | ||||||
|  | 	mfspr	r6, SPRN_MAS1 | ||||||
|  | 	stw	r5, VCPU_SHARED_MAS0(r11) | ||||||
|  | 	mfspr	r7, SPRN_MAS2 | ||||||
|  | 	stw	r6, VCPU_SHARED_MAS1(r11) | ||||||
|  | #ifndef CONFIG_64BIT | ||||||
|  | 	stw	r7, (VCPU_SHARED_MAS2 + 4)(r11) | ||||||
|  | #else | ||||||
|  | 	std	r7, (VCPU_SHARED_MAS2)(r11) | ||||||
|  | #endif | ||||||
|  | 	mfspr	r5, SPRN_MAS3 | ||||||
|  | 	mfspr	r6, SPRN_MAS4 | ||||||
|  | 	stw	r5, VCPU_SHARED_MAS7_3+4(r11) | ||||||
|  | 	mfspr	r7, SPRN_MAS6 | ||||||
|  | 	stw	r6, VCPU_SHARED_MAS4(r11) | ||||||
|  | 	mfspr	r5, SPRN_MAS7 | ||||||
|  | 	lwz	r6, VCPU_HOST_MAS4(r4) | ||||||
|  | 	stw	r7, VCPU_SHARED_MAS6(r11) | ||||||
|  | 	lwz	r8, VCPU_HOST_MAS6(r4) | ||||||
|  | 	mtspr	SPRN_MAS4, r6 | ||||||
|  | 	stw	r5, VCPU_SHARED_MAS7_3+0(r11) | ||||||
|  | 	mtspr	SPRN_MAS6, r8 | ||||||
|  | 	mfspr	r3, SPRN_EPCR | ||||||
|  | 	rlwinm	r3, r3, 0, ~SPRN_EPCR_DMIUH | ||||||
|  | 	mtspr	SPRN_EPCR, r3 | ||||||
|  | 	isync | ||||||
|  | 
 | ||||||
|  | 	/* Restore host stack pointer */ | ||||||
|  | 	PPC_LL	r1, VCPU_HOST_STACK(r4) | ||||||
|  | 	PPC_LL	r2, HOST_R2(r1) | ||||||
|  | 
 | ||||||
|  | 	/* Switch to kernel stack and jump to handler. */ | ||||||
|  | 	PPC_LL	r3, HOST_RUN(r1) | ||||||
|  | 	mr	r5, r14 /* intno */ | ||||||
|  | 	mr	r14, r4 /* Save vcpu pointer. */ | ||||||
|  | 	bl	kvmppc_handle_exit | ||||||
|  | 
 | ||||||
|  | 	/* Restore vcpu pointer and the nonvolatiles we used. */ | ||||||
|  | 	mr	r4, r14 | ||||||
|  | 	PPC_LL	r14, VCPU_GPR(r14)(r4) | ||||||
|  | 
 | ||||||
|  | 	andi.	r5, r3, RESUME_FLAG_NV | ||||||
|  | 	beq	skip_nv_load | ||||||
|  | 	PPC_LL	r15, VCPU_GPR(r15)(r4) | ||||||
|  | 	PPC_LL	r16, VCPU_GPR(r16)(r4) | ||||||
|  | 	PPC_LL	r17, VCPU_GPR(r17)(r4) | ||||||
|  | 	PPC_LL	r18, VCPU_GPR(r18)(r4) | ||||||
|  | 	PPC_LL	r19, VCPU_GPR(r19)(r4) | ||||||
|  | 	PPC_LL	r20, VCPU_GPR(r20)(r4) | ||||||
|  | 	PPC_LL	r21, VCPU_GPR(r21)(r4) | ||||||
|  | 	PPC_LL	r22, VCPU_GPR(r22)(r4) | ||||||
|  | 	PPC_LL	r23, VCPU_GPR(r23)(r4) | ||||||
|  | 	PPC_LL	r24, VCPU_GPR(r24)(r4) | ||||||
|  | 	PPC_LL	r25, VCPU_GPR(r25)(r4) | ||||||
|  | 	PPC_LL	r26, VCPU_GPR(r26)(r4) | ||||||
|  | 	PPC_LL	r27, VCPU_GPR(r27)(r4) | ||||||
|  | 	PPC_LL	r28, VCPU_GPR(r28)(r4) | ||||||
|  | 	PPC_LL	r29, VCPU_GPR(r29)(r4) | ||||||
|  | 	PPC_LL	r30, VCPU_GPR(r30)(r4) | ||||||
|  | 	PPC_LL	r31, VCPU_GPR(r31)(r4) | ||||||
|  | skip_nv_load: | ||||||
|  | 	/* Should we return to the guest? */ | ||||||
|  | 	andi.	r5, r3, RESUME_FLAG_HOST | ||||||
|  | 	beq	lightweight_exit | ||||||
|  | 
 | ||||||
|  | 	srawi	r3, r3, 2 /* Shift -ERR back down. */ | ||||||
|  | 
 | ||||||
|  | heavyweight_exit: | ||||||
|  | 	/* Not returning to guest. */ | ||||||
|  | 	PPC_LL	r5, HOST_STACK_LR(r1) | ||||||
|  | 
 | ||||||
|  | 	/* | ||||||
|  | 	 * We already saved guest volatile register state; now save the
 | ||||||
|  | 	 * non-volatiles. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	PPC_STL	r15, VCPU_GPR(r15)(r4) | ||||||
|  | 	PPC_STL	r16, VCPU_GPR(r16)(r4) | ||||||
|  | 	PPC_STL	r17, VCPU_GPR(r17)(r4) | ||||||
|  | 	PPC_STL	r18, VCPU_GPR(r18)(r4) | ||||||
|  | 	PPC_STL	r19, VCPU_GPR(r19)(r4) | ||||||
|  | 	PPC_STL	r20, VCPU_GPR(r20)(r4) | ||||||
|  | 	PPC_STL	r21, VCPU_GPR(r21)(r4) | ||||||
|  | 	PPC_STL	r22, VCPU_GPR(r22)(r4) | ||||||
|  | 	PPC_STL	r23, VCPU_GPR(r23)(r4) | ||||||
|  | 	PPC_STL	r24, VCPU_GPR(r24)(r4) | ||||||
|  | 	PPC_STL	r25, VCPU_GPR(r25)(r4) | ||||||
|  | 	PPC_STL	r26, VCPU_GPR(r26)(r4) | ||||||
|  | 	PPC_STL	r27, VCPU_GPR(r27)(r4) | ||||||
|  | 	PPC_STL	r28, VCPU_GPR(r28)(r4) | ||||||
|  | 	PPC_STL	r29, VCPU_GPR(r29)(r4) | ||||||
|  | 	PPC_STL	r30, VCPU_GPR(r30)(r4) | ||||||
|  | 	PPC_STL	r31, VCPU_GPR(r31)(r4) | ||||||
|  | 
 | ||||||
|  | 	/* Load host non-volatile register state from host stack. */ | ||||||
|  | 	PPC_LL	r14, HOST_NV_GPR(r14)(r1) | ||||||
|  | 	PPC_LL	r15, HOST_NV_GPR(r15)(r1) | ||||||
|  | 	PPC_LL	r16, HOST_NV_GPR(r16)(r1) | ||||||
|  | 	PPC_LL	r17, HOST_NV_GPR(r17)(r1) | ||||||
|  | 	PPC_LL	r18, HOST_NV_GPR(r18)(r1) | ||||||
|  | 	PPC_LL	r19, HOST_NV_GPR(r19)(r1) | ||||||
|  | 	PPC_LL	r20, HOST_NV_GPR(r20)(r1) | ||||||
|  | 	PPC_LL	r21, HOST_NV_GPR(r21)(r1) | ||||||
|  | 	PPC_LL	r22, HOST_NV_GPR(r22)(r1) | ||||||
|  | 	PPC_LL	r23, HOST_NV_GPR(r23)(r1) | ||||||
|  | 	PPC_LL	r24, HOST_NV_GPR(r24)(r1) | ||||||
|  | 	PPC_LL	r25, HOST_NV_GPR(r25)(r1) | ||||||
|  | 	PPC_LL	r26, HOST_NV_GPR(r26)(r1) | ||||||
|  | 	PPC_LL	r27, HOST_NV_GPR(r27)(r1) | ||||||
|  | 	PPC_LL	r28, HOST_NV_GPR(r28)(r1) | ||||||
|  | 	PPC_LL	r29, HOST_NV_GPR(r29)(r1) | ||||||
|  | 	PPC_LL	r30, HOST_NV_GPR(r30)(r1) | ||||||
|  | 	PPC_LL	r31, HOST_NV_GPR(r31)(r1) | ||||||
|  | 
 | ||||||
|  | 	/* Return to kvm_vcpu_run(). */ | ||||||
|  | 	mtlr	r5 | ||||||
|  | 	addi	r1, r1, HOST_STACK_SIZE | ||||||
|  | 	/* r3 still contains the return code from kvmppc_handle_exit(). */ | ||||||
|  | 	blr | ||||||
|  | 
 | ||||||
|  | /* Registers: | ||||||
|  |  *  r3: kvm_run pointer | ||||||
|  |  *  r4: vcpu pointer | ||||||
|  |  */ | ||||||
|  | _GLOBAL(__kvmppc_vcpu_run) | ||||||
|  | 	stwu	r1, -HOST_STACK_SIZE(r1) | ||||||
|  | 	PPC_STL	r1, VCPU_HOST_STACK(r4)	/* Save stack pointer to vcpu. */ | ||||||
|  | 
 | ||||||
|  | 	/* Save host state to stack. */ | ||||||
|  | 	PPC_STL	r3, HOST_RUN(r1) | ||||||
|  | 	mflr	r3 | ||||||
|  | 	PPC_STL	r3, HOST_STACK_LR(r1) | ||||||
|  | 
 | ||||||
|  | 	/* Save host non-volatile register state to stack. */ | ||||||
|  | 	PPC_STL	r14, HOST_NV_GPR(r14)(r1) | ||||||
|  | 	PPC_STL	r15, HOST_NV_GPR(r15)(r1) | ||||||
|  | 	PPC_STL	r16, HOST_NV_GPR(r16)(r1) | ||||||
|  | 	PPC_STL	r17, HOST_NV_GPR(r17)(r1) | ||||||
|  | 	PPC_STL	r18, HOST_NV_GPR(r18)(r1) | ||||||
|  | 	PPC_STL	r19, HOST_NV_GPR(r19)(r1) | ||||||
|  | 	PPC_STL	r20, HOST_NV_GPR(r20)(r1) | ||||||
|  | 	PPC_STL	r21, HOST_NV_GPR(r21)(r1) | ||||||
|  | 	PPC_STL	r22, HOST_NV_GPR(r22)(r1) | ||||||
|  | 	PPC_STL	r23, HOST_NV_GPR(r23)(r1) | ||||||
|  | 	PPC_STL	r24, HOST_NV_GPR(r24)(r1) | ||||||
|  | 	PPC_STL	r25, HOST_NV_GPR(r25)(r1) | ||||||
|  | 	PPC_STL	r26, HOST_NV_GPR(r26)(r1) | ||||||
|  | 	PPC_STL	r27, HOST_NV_GPR(r27)(r1) | ||||||
|  | 	PPC_STL	r28, HOST_NV_GPR(r28)(r1) | ||||||
|  | 	PPC_STL	r29, HOST_NV_GPR(r29)(r1) | ||||||
|  | 	PPC_STL	r30, HOST_NV_GPR(r30)(r1) | ||||||
|  | 	PPC_STL	r31, HOST_NV_GPR(r31)(r1) | ||||||
|  | 
 | ||||||
|  | 	/* Load guest non-volatiles. */ | ||||||
|  | 	PPC_LL	r14, VCPU_GPR(r14)(r4) | ||||||
|  | 	PPC_LL	r15, VCPU_GPR(r15)(r4) | ||||||
|  | 	PPC_LL	r16, VCPU_GPR(r16)(r4) | ||||||
|  | 	PPC_LL	r17, VCPU_GPR(r17)(r4) | ||||||
|  | 	PPC_LL	r18, VCPU_GPR(r18)(r4) | ||||||
|  | 	PPC_LL	r19, VCPU_GPR(r19)(r4) | ||||||
|  | 	PPC_LL	r20, VCPU_GPR(r20)(r4) | ||||||
|  | 	PPC_LL	r21, VCPU_GPR(r21)(r4) | ||||||
|  | 	PPC_LL	r22, VCPU_GPR(r22)(r4) | ||||||
|  | 	PPC_LL	r23, VCPU_GPR(r23)(r4) | ||||||
|  | 	PPC_LL	r24, VCPU_GPR(r24)(r4) | ||||||
|  | 	PPC_LL	r25, VCPU_GPR(r25)(r4) | ||||||
|  | 	PPC_LL	r26, VCPU_GPR(r26)(r4) | ||||||
|  | 	PPC_LL	r27, VCPU_GPR(r27)(r4) | ||||||
|  | 	PPC_LL	r28, VCPU_GPR(r28)(r4) | ||||||
|  | 	PPC_LL	r29, VCPU_GPR(r29)(r4) | ||||||
|  | 	PPC_LL	r30, VCPU_GPR(r30)(r4) | ||||||
|  | 	PPC_LL	r31, VCPU_GPR(r31)(r4) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | lightweight_exit: | ||||||
|  | 	PPC_STL	r2, HOST_R2(r1) | ||||||
|  | 
 | ||||||
|  | 	mfspr	r3, SPRN_PID | ||||||
|  | 	stw	r3, VCPU_HOST_PID(r4) | ||||||
|  | 	lwz	r3, VCPU_GUEST_PID(r4) | ||||||
|  | 	mtspr	SPRN_PID, r3 | ||||||
|  | 
 | ||||||
|  | 	/* Save vcpu pointer for the exception handlers | ||||||
|  | 	 * must be done before loading guest r2. | ||||||
|  | 	 */ | ||||||
|  | //	SET_VCPU(r4) | ||||||
|  | 
 | ||||||
|  | 	PPC_LL	r11, VCPU_SHARED(r4) | ||||||
|  | 	/* Save host mas4 and mas6 and load guest MAS registers */ | ||||||
|  | 	mfspr	r3, SPRN_MAS4 | ||||||
|  | 	stw	r3, VCPU_HOST_MAS4(r4) | ||||||
|  | 	mfspr	r3, SPRN_MAS6 | ||||||
|  | 	stw	r3, VCPU_HOST_MAS6(r4) | ||||||
|  | 	lwz	r3, VCPU_SHARED_MAS0(r11) | ||||||
|  | 	lwz	r5, VCPU_SHARED_MAS1(r11) | ||||||
|  | #ifndef CONFIG_64BIT | ||||||
|  | 	lwz	r6, (VCPU_SHARED_MAS2 + 4)(r11) | ||||||
|  | #else | ||||||
|  | 	ld	r6, (VCPU_SHARED_MAS2)(r11) | ||||||
|  | #endif | ||||||
|  | 	lwz	r7, VCPU_SHARED_MAS7_3+4(r11) | ||||||
|  | 	lwz	r8, VCPU_SHARED_MAS4(r11) | ||||||
|  | 	mtspr	SPRN_MAS0, r3 | ||||||
|  | 	mtspr	SPRN_MAS1, r5 | ||||||
|  | 	mtspr	SPRN_MAS2, r6 | ||||||
|  | 	mtspr	SPRN_MAS3, r7 | ||||||
|  | 	mtspr	SPRN_MAS4, r8 | ||||||
|  | 	lwz	r3, VCPU_SHARED_MAS6(r11) | ||||||
|  | 	lwz	r5, VCPU_SHARED_MAS7_3+0(r11) | ||||||
|  | 	mtspr	SPRN_MAS6, r3 | ||||||
|  | 	mtspr	SPRN_MAS7, r5 | ||||||
|  | 	/* Disable MAS register updates via exception */ | ||||||
|  | 	mfspr	r3, SPRN_EPCR | ||||||
|  | 	oris	r3, r3, SPRN_EPCR_DMIUH@h
 | ||||||
|  | 	mtspr	SPRN_EPCR, r3 | ||||||
|  | 
 | ||||||
|  | 	/* | ||||||
|  | 	 * Host interrupt handlers may have clobbered these guest-readable | ||||||
|  | 	 * SPRGs, so we need to reload them here with the guest's values. | ||||||
|  | 	 */ | ||||||
|  | 	lwz	r3, VCPU_VRSAVE(r4) | ||||||
|  | 	lwz	r5, VCPU_SHARED_SPRG4(r11) | ||||||
|  | 	mtspr	SPRN_VRSAVE, r3 | ||||||
|  | 	lwz	r6, VCPU_SHARED_SPRG5(r11) | ||||||
|  | 	mtspr	SPRN_SPRG4W, r5 | ||||||
|  | 	lwz	r7, VCPU_SHARED_SPRG6(r11) | ||||||
|  | 	mtspr	SPRN_SPRG5W, r6 | ||||||
|  | 	lwz	r8, VCPU_SHARED_SPRG7(r11) | ||||||
|  | 	mtspr	SPRN_SPRG6W, r7 | ||||||
|  | 	mtspr	SPRN_SPRG7W, r8 | ||||||
|  | 
 | ||||||
|  | 	/* Load some guest volatiles. */ | ||||||
|  | 	PPC_LL	r3, VCPU_LR(r4) | ||||||
|  | 	PPC_LL	r5, VCPU_XER(r4) | ||||||
|  | 	PPC_LL	r6, VCPU_CTR(r4) | ||||||
|  | 	PPC_LL	r7, VCPU_CR(r4) | ||||||
|  | 	PPC_LL	r8, VCPU_PC(r4) | ||||||
|  | #ifndef CONFIG_64BIT | ||||||
|  | 	lwz	r9, (VCPU_SHARED_MSR + 4)(r11) | ||||||
|  | #else | ||||||
|  | 	ld	r9, (VCPU_SHARED_MSR)(r11) | ||||||
|  | #endif | ||||||
|  | 	PPC_LL	r0, VCPU_GPR(r0)(r4) | ||||||
|  | 	PPC_LL	r1, VCPU_GPR(r1)(r4) | ||||||
|  | 	PPC_LL	r2, VCPU_GPR(r2)(r4) | ||||||
|  | 	PPC_LL	r10, VCPU_GPR(r10)(r4) | ||||||
|  | 	PPC_LL	r11, VCPU_GPR(r11)(r4) | ||||||
|  | 	PPC_LL	r12, VCPU_GPR(r12)(r4) | ||||||
|  | 	PPC_LL	r13, VCPU_GPR(r13)(r4) | ||||||
|  | 	mtlr	r3 | ||||||
|  | 	mtxer	r5 | ||||||
|  | 	mtctr	r6 | ||||||
|  | 	mtcr	r7 | ||||||
|  | 	mtsrr0	r8 | ||||||
|  | 	mtsrr1	r9 | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_KVM_EXIT_TIMING | ||||||
|  | 	/* save enter time */ | ||||||
|  | 1: | ||||||
|  | 	mfspr	r6, SPRN_TBRU | ||||||
|  | 	mfspr	r7, SPRN_TBRL | ||||||
|  | 	mfspr	r8, SPRN_TBRU | ||||||
|  | 	cmpw	r8, r6 | ||||||
|  | 	PPC_STL	r7, VCPU_TIMING_LAST_ENTER_TBL(r4) | ||||||
|  | 	bne	1b | ||||||
|  | 	PPC_STL	r8, VCPU_TIMING_LAST_ENTER_TBU(r4) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	/* Finish loading guest volatiles and jump to guest. */ | ||||||
|  | 	PPC_LL	r5, VCPU_GPR(r5)(r4) | ||||||
|  | 	PPC_LL	r6, VCPU_GPR(r6)(r4) | ||||||
|  | 	PPC_LL	r7, VCPU_GPR(r7)(r4) | ||||||
|  | 	PPC_LL	r8, VCPU_GPR(r8)(r4) | ||||||
|  | 	PPC_LL	r9, VCPU_GPR(r9)(r4) | ||||||
|  | 
 | ||||||
|  | 	PPC_LL	r3, VCPU_GPR(r3)(r4) | ||||||
|  | 	PPC_LL	r4, VCPU_GPR(r4)(r4) | ||||||
|  | 	rfi | ||||||
|  | @ -114,6 +114,11 @@ int kvmppc_sanity_check(struct kvm_vcpu *vcpu) | ||||||
| 		goto out; | 		goto out; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_KVM_BOOKE_HV | ||||||
|  | 	if (!cpu_has_feature(CPU_FTR_EMB_HV)) | ||||||
|  | 		goto out; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	r = true; | 	r = true; | ||||||
| 
 | 
 | ||||||
| out: | out: | ||||||
|  |  | ||||||
|  | @ -93,6 +93,12 @@ static inline void kvmppc_account_exit_stat(struct kvm_vcpu *vcpu, int type) | ||||||
| 	case SIGNAL_EXITS: | 	case SIGNAL_EXITS: | ||||||
| 		vcpu->stat.signal_exits++; | 		vcpu->stat.signal_exits++; | ||||||
| 		break; | 		break; | ||||||
|  | 	case DBELL_EXITS: | ||||||
|  | 		vcpu->stat.dbell_exits++; | ||||||
|  | 		break; | ||||||
|  | 	case GDBELL_EXITS: | ||||||
|  | 		vcpu->stat.gdbell_exits++; | ||||||
|  | 		break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Scott Wood
				Scott Wood