Path: blob/master/arch/powerpc/kvm/book3s_rmhandlers.S
10818 views
/*1* This program is free software; you can redistribute it and/or modify2* it under the terms of the GNU General Public License, version 2, as3* published by the Free Software Foundation.4*5* This program is distributed in the hope that it will be useful,6* but WITHOUT ANY WARRANTY; without even the implied warranty of7* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the8* GNU General Public License for more details.9*10* You should have received a copy of the GNU General Public License11* along with this program; if not, write to the Free Software12* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.13*14* Copyright SUSE Linux Products GmbH 200915*16* Authors: Alexander Graf <[email protected]>17*/1819#include <asm/ppc_asm.h>20#include <asm/kvm_asm.h>21#include <asm/reg.h>22#include <asm/page.h>23#include <asm/asm-offsets.h>2425#ifdef CONFIG_PPC_BOOK3S_6426#include <asm/exception-64s.h>27#endif2829/*****************************************************************************30* *31* Real Mode handlers that need to be in low physical memory *32* *33****************************************************************************/3435#if defined(CONFIG_PPC_BOOK3S_64)3637#define LOAD_SHADOW_VCPU(reg) GET_PACA(reg)38#define SHADOW_VCPU_OFF PACA_KVM_SVCPU39#define MSR_NOIRQ MSR_KERNEL & ~(MSR_IR | MSR_DR)40#define FUNC(name) GLUE(.,name)4142#elif defined(CONFIG_PPC_BOOK3S_32)4344#define LOAD_SHADOW_VCPU(reg) \45mfspr reg, SPRN_SPRG_THREAD; \46lwz reg, THREAD_KVM_SVCPU(reg); \47/* PPC32 can have a NULL pointer - let's check for that */ \48mtspr SPRN_SPRG_SCRATCH1, r12; /* Save r12 */ \49mfcr r12; \50cmpwi reg, 0; \51bne 1f; \52mfspr reg, SPRN_SPRG_SCRATCH0; \53mtcr r12; \54mfspr r12, SPRN_SPRG_SCRATCH1; \55b kvmppc_resume_\intno; \561:; \57mtcr r12; \58mfspr r12, SPRN_SPRG_SCRATCH1; \59tophys(reg, reg)6061#define SHADOW_VCPU_OFF 062#define MSR_NOIRQ MSR_KERNEL63#define FUNC(name) name6465#endif6667.macro INTERRUPT_TRAMPOLINE intno6869.global kvmppc_trampoline_\intno70kvmppc_trampoline_\intno:7172SET_SCRATCH0(r13) /* Save r13 */7374/*75* First thing to do is to find out if we're coming76* from a KVM guest or a Linux process.77*78* To distinguish, we check a magic byte in the PACA/current79*/80LOAD_SHADOW_VCPU(r13)81PPC_STL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)82mfcr r1283stw r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)84lbz r12, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13)85cmpwi r12, KVM_GUEST_MODE_NONE86bne ..kvmppc_handler_hasmagic_\intno87/* No KVM guest? Then jump back to the Linux handler! */88lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)89mtcr r1290PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)91GET_SCRATCH0(r13) /* r13 = original r13 */92b kvmppc_resume_\intno /* Get back original handler */9394/* Now we know we're handling a KVM guest */95..kvmppc_handler_hasmagic_\intno:9697/* Should we just skip the faulting instruction? */98cmpwi r12, KVM_GUEST_MODE_SKIP99beq kvmppc_handler_skip_ins100101/* Let's store which interrupt we're handling */102li r12, \intno103104/* Jump into the SLB exit code that goes to the highmem handler */105b kvmppc_handler_trampoline_exit106107.endm108109INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSTEM_RESET110INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK111INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE112INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE113INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL114#ifdef CONFIG_PPC_BOOK3S_64115INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL_HV116#endif117INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT118INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM119INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL120INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DECREMENTER121INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSCALL122INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_TRACE123INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PERFMON124INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC125126/* Those are only available on 64 bit machines */127128#ifdef CONFIG_PPC_BOOK3S_64129INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_SEGMENT130INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_SEGMENT131INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_VSX132#endif133134/*135* Bring us back to the faulting code, but skip the136* faulting instruction.137*138* This is a generic exit path from the interrupt139* trampolines above.140*141* Input Registers:142*143* R12 = free144* R13 = Shadow VCPU (PACA)145* SVCPU.SCRATCH0 = guest R12146* SVCPU.SCRATCH1 = guest CR147* SPRG_SCRATCH0 = guest R13148*149*/150kvmppc_handler_skip_ins:151152/* Patch the IP to the next instruction */153mfsrr0 r12154addi r12, r12, 4155mtsrr0 r12156157/* Clean up all state */158lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)159mtcr r12160PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)161GET_SCRATCH0(r13)162163/* And get back into the code */164RFI165166/*167* This trampoline brings us back to a real mode handler168*169* Input Registers:170*171* R5 = SRR0172* R6 = SRR1173* LR = real-mode IP174*175*/176.global kvmppc_handler_lowmem_trampoline177kvmppc_handler_lowmem_trampoline:178179mtsrr0 r5180mtsrr1 r6181blr182kvmppc_handler_lowmem_trampoline_end:183184/*185* Call a function in real mode186*187* Input Registers:188*189* R3 = function190* R4 = MSR191* R5 = scratch register192*193*/194_GLOBAL(kvmppc_rmcall)195LOAD_REG_IMMEDIATE(r5, MSR_NOIRQ)196mtmsr r5 /* Disable relocation and interrupts, so mtsrr197doesn't get interrupted */198sync199mtsrr0 r3200mtsrr1 r4201RFI202203#if defined(CONFIG_PPC_BOOK3S_32)204#define STACK_LR INT_FRAME_SIZE+4205206/* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */207#define MSR_EXT_START \208PPC_STL r20, _NIP(r1); \209mfmsr r20; \210LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \211andc r3,r20,r3; /* Disable DR,EE */ \212mtmsr r3; \213sync214215#define MSR_EXT_END \216mtmsr r20; /* Enable DR,EE */ \217sync; \218PPC_LL r20, _NIP(r1)219220#elif defined(CONFIG_PPC_BOOK3S_64)221#define STACK_LR _LINK222#define MSR_EXT_START223#define MSR_EXT_END224#endif225226/*227* Activate current's external feature (FPU/Altivec/VSX)228*/229#define define_load_up(what) \230\231_GLOBAL(kvmppc_load_up_ ## what); \232PPC_STLU r1, -INT_FRAME_SIZE(r1); \233mflr r3; \234PPC_STL r3, STACK_LR(r1); \235MSR_EXT_START; \236\237bl FUNC(load_up_ ## what); \238\239MSR_EXT_END; \240PPC_LL r3, STACK_LR(r1); \241mtlr r3; \242addi r1, r1, INT_FRAME_SIZE; \243blr244245define_load_up(fpu)246#ifdef CONFIG_ALTIVEC247define_load_up(altivec)248#endif249#ifdef CONFIG_VSX250define_load_up(vsx)251#endif252253.global kvmppc_trampoline_lowmem254kvmppc_trampoline_lowmem:255PPC_LONG kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START256257.global kvmppc_trampoline_enter258kvmppc_trampoline_enter:259PPC_LONG kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START260261#include "book3s_segment.S"262263264