1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * 4*4882a593Smuzhiyun * Copyright SUSE Linux Products GmbH 2009 5*4882a593Smuzhiyun * 6*4882a593Smuzhiyun * Authors: Alexander Graf <agraf@suse.de> 7*4882a593Smuzhiyun */ 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun#include <asm/ppc_asm.h> 10*4882a593Smuzhiyun#include <asm/kvm_asm.h> 11*4882a593Smuzhiyun#include <asm/reg.h> 12*4882a593Smuzhiyun#include <asm/mmu.h> 13*4882a593Smuzhiyun#include <asm/page.h> 14*4882a593Smuzhiyun#include <asm/asm-offsets.h> 15*4882a593Smuzhiyun#include <asm/asm-compat.h> 16*4882a593Smuzhiyun 17*4882a593Smuzhiyun#ifdef CONFIG_PPC_BOOK3S_64 18*4882a593Smuzhiyun#include <asm/exception-64s.h> 19*4882a593Smuzhiyun#endif 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun/***************************************************************************** 22*4882a593Smuzhiyun * * 23*4882a593Smuzhiyun * Real Mode handlers that need to be in low physical memory * 24*4882a593Smuzhiyun * * 25*4882a593Smuzhiyun ****************************************************************************/ 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun#if defined(CONFIG_PPC_BOOK3S_64) 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun#ifdef PPC64_ELF_ABI_v2 30*4882a593Smuzhiyun#define FUNC(name) name 31*4882a593Smuzhiyun#else 32*4882a593Smuzhiyun#define FUNC(name) GLUE(.,name) 33*4882a593Smuzhiyun#endif 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun#elif defined(CONFIG_PPC_BOOK3S_32) 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun#define FUNC(name) name 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun#define RFI_TO_KERNEL RFI 40*4882a593Smuzhiyun#define RFI_TO_GUEST RFI 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun.macro INTERRUPT_TRAMPOLINE intno 43*4882a593Smuzhiyun 44*4882a593Smuzhiyun.global kvmppc_trampoline_\intno 45*4882a593Smuzhiyunkvmppc_trampoline_\intno: 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun /* 50*4882a593Smuzhiyun * First thing to do is to find out if we're coming 51*4882a593Smuzhiyun * from a KVM guest or a Linux process. 52*4882a593Smuzhiyun * 53*4882a593Smuzhiyun * To distinguish, we check a magic byte in the PACA/current 54*4882a593Smuzhiyun */ 55*4882a593Smuzhiyun mfspr r13, SPRN_SPRG_THREAD 56*4882a593Smuzhiyun lwz r13, THREAD_KVM_SVCPU(r13) 57*4882a593Smuzhiyun /* PPC32 can have a NULL pointer - let's check for that */ 58*4882a593Smuzhiyun mtspr SPRN_SPRG_SCRATCH1, r12 /* Save r12 */ 59*4882a593Smuzhiyun mfcr r12 60*4882a593Smuzhiyun cmpwi r13, 0 61*4882a593Smuzhiyun bne 1f 62*4882a593Smuzhiyun2: mtcr r12 63*4882a593Smuzhiyun mfspr r12, SPRN_SPRG_SCRATCH1 64*4882a593Smuzhiyun mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ 65*4882a593Smuzhiyun b kvmppc_resume_\intno /* Get back original handler */ 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun1: tophys(r13, r13) 68*4882a593Smuzhiyun stw r12, HSTATE_SCRATCH1(r13) 69*4882a593Smuzhiyun mfspr r12, SPRN_SPRG_SCRATCH1 70*4882a593Smuzhiyun stw r12, HSTATE_SCRATCH0(r13) 71*4882a593Smuzhiyun lbz r12, HSTATE_IN_GUEST(r13) 72*4882a593Smuzhiyun cmpwi r12, KVM_GUEST_MODE_NONE 73*4882a593Smuzhiyun bne ..kvmppc_handler_hasmagic_\intno 74*4882a593Smuzhiyun /* No KVM guest? Then jump back to the Linux handler! */ 75*4882a593Smuzhiyun lwz r12, HSTATE_SCRATCH1(r13) 76*4882a593Smuzhiyun b 2b 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun /* Now we know we're handling a KVM guest */ 79*4882a593Smuzhiyun..kvmppc_handler_hasmagic_\intno: 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun /* Should we just skip the faulting instruction? */ 82*4882a593Smuzhiyun cmpwi r12, KVM_GUEST_MODE_SKIP 83*4882a593Smuzhiyun beq kvmppc_handler_skip_ins 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun /* Let's store which interrupt we're handling */ 86*4882a593Smuzhiyun li r12, \intno 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun /* Jump into the SLB exit code that goes to the highmem handler */ 89*4882a593Smuzhiyun b kvmppc_handler_trampoline_exit 90*4882a593Smuzhiyun 91*4882a593Smuzhiyun.endm 92*4882a593Smuzhiyun 93*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSTEM_RESET 94*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK 95*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE 96*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE 97*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL 98*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT 99*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM 100*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL 101*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DECREMENTER 102*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSCALL 103*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_TRACE 104*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PERFMON 105*4882a593SmuzhiyunINTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun/* 108*4882a593Smuzhiyun * Bring us back to the faulting code, but skip the 109*4882a593Smuzhiyun * faulting instruction. 110*4882a593Smuzhiyun * 111*4882a593Smuzhiyun * This is a generic exit path from the interrupt 112*4882a593Smuzhiyun * trampolines above. 113*4882a593Smuzhiyun * 114*4882a593Smuzhiyun * Input Registers: 115*4882a593Smuzhiyun * 116*4882a593Smuzhiyun * R12 = free 117*4882a593Smuzhiyun * R13 = Shadow VCPU (PACA) 118*4882a593Smuzhiyun * HSTATE.SCRATCH0 = guest R12 119*4882a593Smuzhiyun * HSTATE.SCRATCH1 = guest CR 120*4882a593Smuzhiyun * SPRG_SCRATCH0 = guest R13 121*4882a593Smuzhiyun * 122*4882a593Smuzhiyun */ 123*4882a593Smuzhiyunkvmppc_handler_skip_ins: 124*4882a593Smuzhiyun 125*4882a593Smuzhiyun /* Patch the IP to the next instruction */ 126*4882a593Smuzhiyun mfsrr0 r12 127*4882a593Smuzhiyun addi r12, r12, 4 128*4882a593Smuzhiyun mtsrr0 r12 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun /* Clean up all state */ 131*4882a593Smuzhiyun lwz r12, HSTATE_SCRATCH1(r13) 132*4882a593Smuzhiyun mtcr r12 133*4882a593Smuzhiyun PPC_LL r12, HSTATE_SCRATCH0(r13) 134*4882a593Smuzhiyun GET_SCRATCH0(r13) 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun /* And get back into the code */ 137*4882a593Smuzhiyun RFI_TO_KERNEL 138*4882a593Smuzhiyun#endif 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun/* 141*4882a593Smuzhiyun * Call kvmppc_handler_trampoline_enter in real mode 142*4882a593Smuzhiyun * 143*4882a593Smuzhiyun * On entry, r4 contains the guest shadow MSR 144*4882a593Smuzhiyun * MSR.EE has to be 0 when calling this function 145*4882a593Smuzhiyun */ 146*4882a593Smuzhiyun_GLOBAL_TOC(kvmppc_entry_trampoline) 147*4882a593Smuzhiyun mfmsr r5 148*4882a593Smuzhiyun LOAD_REG_ADDR(r7, kvmppc_handler_trampoline_enter) 149*4882a593Smuzhiyun toreal(r7) 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun li r6, MSR_IR | MSR_DR 152*4882a593Smuzhiyun andc r6, r5, r6 /* Clear DR and IR in MSR value */ 153*4882a593Smuzhiyun /* 154*4882a593Smuzhiyun * Set EE in HOST_MSR so that it's enabled when we get into our 155*4882a593Smuzhiyun * C exit handler function. 156*4882a593Smuzhiyun */ 157*4882a593Smuzhiyun ori r5, r5, MSR_EE 158*4882a593Smuzhiyun mtsrr0 r7 159*4882a593Smuzhiyun mtsrr1 r6 160*4882a593Smuzhiyun RFI_TO_KERNEL 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun#include "book3s_segment.S" 163