1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun /* 3*4882a593Smuzhiyun * File: mca_asm.h 4*4882a593Smuzhiyun * Purpose: Machine check handling specific defines 5*4882a593Smuzhiyun * 6*4882a593Smuzhiyun * Copyright (C) 1999 Silicon Graphics, Inc. 7*4882a593Smuzhiyun * Copyright (C) Vijay Chander <vijay@engr.sgi.com> 8*4882a593Smuzhiyun * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com> 9*4882a593Smuzhiyun * Copyright (C) 2000 Hewlett-Packard Co. 10*4882a593Smuzhiyun * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> 11*4882a593Smuzhiyun * Copyright (C) 2002 Intel Corp. 12*4882a593Smuzhiyun * Copyright (C) 2002 Jenna Hall <jenna.s.hall@intel.com> 13*4882a593Smuzhiyun * Copyright (C) 2005 Silicon Graphics, Inc 14*4882a593Smuzhiyun * Copyright (C) 2005 Keith Owens <kaos@sgi.com> 15*4882a593Smuzhiyun */ 16*4882a593Smuzhiyun #ifndef _ASM_IA64_MCA_ASM_H 17*4882a593Smuzhiyun #define _ASM_IA64_MCA_ASM_H 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun #include <asm/percpu.h> 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun #define PSR_IC 13 22*4882a593Smuzhiyun #define PSR_I 14 23*4882a593Smuzhiyun #define PSR_DT 17 24*4882a593Smuzhiyun #define PSR_RT 27 25*4882a593Smuzhiyun #define PSR_MC 35 26*4882a593Smuzhiyun #define PSR_IT 36 27*4882a593Smuzhiyun #define PSR_BN 44 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun /* 30*4882a593Smuzhiyun * This macro converts a instruction virtual address to a physical address 31*4882a593Smuzhiyun * Right now for simulation purposes the virtual addresses are 32*4882a593Smuzhiyun * direct mapped to physical addresses. 33*4882a593Smuzhiyun * 1. Lop off bits 61 thru 63 in the virtual address 34*4882a593Smuzhiyun */ 35*4882a593Smuzhiyun #define INST_VA_TO_PA(addr) \ 36*4882a593Smuzhiyun dep addr = 0, addr, 61, 3 37*4882a593Smuzhiyun /* 38*4882a593Smuzhiyun * This macro converts a data virtual address to a physical address 39*4882a593Smuzhiyun * Right now for simulation purposes the virtual addresses are 40*4882a593Smuzhiyun * direct mapped to physical addresses. 41*4882a593Smuzhiyun * 1. Lop off bits 61 thru 63 in the virtual address 42*4882a593Smuzhiyun */ 43*4882a593Smuzhiyun #define DATA_VA_TO_PA(addr) \ 44*4882a593Smuzhiyun tpa addr = addr 45*4882a593Smuzhiyun /* 46*4882a593Smuzhiyun * This macro converts a data physical address to a virtual address 47*4882a593Smuzhiyun * Right now for simulation purposes the virtual addresses are 48*4882a593Smuzhiyun * direct mapped to physical addresses. 49*4882a593Smuzhiyun * 1. Put 0x7 in bits 61 thru 63. 50*4882a593Smuzhiyun */ 51*4882a593Smuzhiyun #define DATA_PA_TO_VA(addr,temp) \ 52*4882a593Smuzhiyun mov temp = 0x7 ;; \ 53*4882a593Smuzhiyun dep addr = temp, addr, 61, 3 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun #define GET_THIS_PADDR(reg, var) \ 56*4882a593Smuzhiyun mov reg = IA64_KR(PER_CPU_DATA);; \ 57*4882a593Smuzhiyun addl reg = THIS_CPU(var), reg 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun /* 60*4882a593Smuzhiyun * This macro jumps to the instruction at the given virtual address 61*4882a593Smuzhiyun * and starts execution in physical mode with all the address 62*4882a593Smuzhiyun * translations turned off. 63*4882a593Smuzhiyun * 1. Save the current psr 64*4882a593Smuzhiyun * 2. Make sure that all the upper 32 bits are off 65*4882a593Smuzhiyun * 66*4882a593Smuzhiyun * 3. Clear the interrupt enable and interrupt state collection bits 67*4882a593Smuzhiyun * in the psr before updating the ipsr and iip. 68*4882a593Smuzhiyun * 69*4882a593Smuzhiyun * 4. Turn off the instruction, data and rse translation bits of the psr 70*4882a593Smuzhiyun * and store the new value into ipsr 71*4882a593Smuzhiyun * Also make sure that the interrupts are disabled. 72*4882a593Smuzhiyun * Ensure that we are in little endian mode. 73*4882a593Smuzhiyun * [psr.{rt, it, dt, i, be} = 0] 74*4882a593Smuzhiyun * 75*4882a593Smuzhiyun * 5. Get the physical address corresponding to the virtual address 76*4882a593Smuzhiyun * of the next instruction bundle and put it in iip. 77*4882a593Smuzhiyun * (Using magic numbers 24 and 40 in the deposint instruction since 78*4882a593Smuzhiyun * the IA64_SDK code directly maps to lower 24bits as physical address 79*4882a593Smuzhiyun * from a virtual address). 80*4882a593Smuzhiyun * 81*4882a593Smuzhiyun * 6. Do an rfi to move the values from ipsr to psr and iip to ip. 82*4882a593Smuzhiyun */ 83*4882a593Smuzhiyun #define PHYSICAL_MODE_ENTER(temp1, temp2, start_addr, old_psr) \ 84*4882a593Smuzhiyun mov old_psr = psr; \ 85*4882a593Smuzhiyun ;; \ 86*4882a593Smuzhiyun dep old_psr = 0, old_psr, 32, 32; \ 87*4882a593Smuzhiyun \ 88*4882a593Smuzhiyun mov ar.rsc = 0 ; \ 89*4882a593Smuzhiyun ;; \ 90*4882a593Smuzhiyun srlz.d; \ 91*4882a593Smuzhiyun mov temp2 = ar.bspstore; \ 92*4882a593Smuzhiyun ;; \ 93*4882a593Smuzhiyun DATA_VA_TO_PA(temp2); \ 94*4882a593Smuzhiyun ;; \ 95*4882a593Smuzhiyun mov temp1 = ar.rnat; \ 96*4882a593Smuzhiyun ;; \ 97*4882a593Smuzhiyun mov ar.bspstore = temp2; \ 98*4882a593Smuzhiyun ;; \ 99*4882a593Smuzhiyun mov ar.rnat = temp1; \ 100*4882a593Smuzhiyun mov temp1 = psr; \ 101*4882a593Smuzhiyun mov temp2 = psr; \ 102*4882a593Smuzhiyun ;; \ 103*4882a593Smuzhiyun \ 104*4882a593Smuzhiyun dep temp2 = 0, temp2, PSR_IC, 2; \ 105*4882a593Smuzhiyun ;; \ 106*4882a593Smuzhiyun mov psr.l = temp2; \ 107*4882a593Smuzhiyun ;; \ 108*4882a593Smuzhiyun srlz.d; \ 109*4882a593Smuzhiyun dep temp1 = 0, temp1, 32, 32; \ 110*4882a593Smuzhiyun ;; \ 111*4882a593Smuzhiyun dep temp1 = 0, temp1, PSR_IT, 1; \ 112*4882a593Smuzhiyun ;; \ 113*4882a593Smuzhiyun dep temp1 = 0, temp1, PSR_DT, 1; \ 114*4882a593Smuzhiyun ;; \ 115*4882a593Smuzhiyun dep temp1 = 0, temp1, PSR_RT, 1; \ 116*4882a593Smuzhiyun ;; \ 117*4882a593Smuzhiyun dep temp1 = 0, temp1, PSR_I, 1; \ 118*4882a593Smuzhiyun ;; \ 119*4882a593Smuzhiyun dep temp1 = 0, temp1, PSR_IC, 1; \ 120*4882a593Smuzhiyun ;; \ 121*4882a593Smuzhiyun dep temp1 = -1, temp1, PSR_MC, 1; \ 122*4882a593Smuzhiyun ;; \ 123*4882a593Smuzhiyun mov cr.ipsr = temp1; \ 124*4882a593Smuzhiyun ;; \ 125*4882a593Smuzhiyun LOAD_PHYSICAL(p0, temp2, start_addr); \ 126*4882a593Smuzhiyun ;; \ 127*4882a593Smuzhiyun mov cr.iip = temp2; \ 128*4882a593Smuzhiyun mov cr.ifs = r0; \ 129*4882a593Smuzhiyun DATA_VA_TO_PA(sp); \ 130*4882a593Smuzhiyun DATA_VA_TO_PA(gp); \ 131*4882a593Smuzhiyun ;; \ 132*4882a593Smuzhiyun srlz.i; \ 133*4882a593Smuzhiyun ;; \ 134*4882a593Smuzhiyun nop 1; \ 135*4882a593Smuzhiyun nop 2; \ 136*4882a593Smuzhiyun nop 1; \ 137*4882a593Smuzhiyun nop 2; \ 138*4882a593Smuzhiyun rfi; \ 139*4882a593Smuzhiyun ;; 140*4882a593Smuzhiyun 141*4882a593Smuzhiyun /* 142*4882a593Smuzhiyun * This macro jumps to the instruction at the given virtual address 143*4882a593Smuzhiyun * and starts execution in virtual mode with all the address 144*4882a593Smuzhiyun * translations turned on. 145*4882a593Smuzhiyun * 1. Get the old saved psr 146*4882a593Smuzhiyun * 147*4882a593Smuzhiyun * 2. Clear the interrupt state collection bit in the current psr. 148*4882a593Smuzhiyun * 149*4882a593Smuzhiyun * 3. Set the instruction translation bit back in the old psr 150*4882a593Smuzhiyun * Note we have to do this since we are right now saving only the 151*4882a593Smuzhiyun * lower 32-bits of old psr.(Also the old psr has the data and 152*4882a593Smuzhiyun * rse translation bits on) 153*4882a593Smuzhiyun * 154*4882a593Smuzhiyun * 4. Set ipsr to this old_psr with "it" bit set and "bn" = 1. 155*4882a593Smuzhiyun * 156*4882a593Smuzhiyun * 5. Reset the current thread pointer (r13). 157*4882a593Smuzhiyun * 158*4882a593Smuzhiyun * 6. Set iip to the virtual address of the next instruction bundle. 159*4882a593Smuzhiyun * 160*4882a593Smuzhiyun * 7. Do an rfi to move ipsr to psr and iip to ip. 161*4882a593Smuzhiyun */ 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun #define VIRTUAL_MODE_ENTER(temp1, temp2, start_addr, old_psr) \ 164*4882a593Smuzhiyun mov temp2 = psr; \ 165*4882a593Smuzhiyun ;; \ 166*4882a593Smuzhiyun mov old_psr = temp2; \ 167*4882a593Smuzhiyun ;; \ 168*4882a593Smuzhiyun dep temp2 = 0, temp2, PSR_IC, 2; \ 169*4882a593Smuzhiyun ;; \ 170*4882a593Smuzhiyun mov psr.l = temp2; \ 171*4882a593Smuzhiyun mov ar.rsc = 0; \ 172*4882a593Smuzhiyun ;; \ 173*4882a593Smuzhiyun srlz.d; \ 174*4882a593Smuzhiyun mov r13 = ar.k6; \ 175*4882a593Smuzhiyun mov temp2 = ar.bspstore; \ 176*4882a593Smuzhiyun ;; \ 177*4882a593Smuzhiyun DATA_PA_TO_VA(temp2,temp1); \ 178*4882a593Smuzhiyun ;; \ 179*4882a593Smuzhiyun mov temp1 = ar.rnat; \ 180*4882a593Smuzhiyun ;; \ 181*4882a593Smuzhiyun mov ar.bspstore = temp2; \ 182*4882a593Smuzhiyun ;; \ 183*4882a593Smuzhiyun mov ar.rnat = temp1; \ 184*4882a593Smuzhiyun ;; \ 185*4882a593Smuzhiyun mov temp1 = old_psr; \ 186*4882a593Smuzhiyun ;; \ 187*4882a593Smuzhiyun mov temp2 = 1; \ 188*4882a593Smuzhiyun ;; \ 189*4882a593Smuzhiyun dep temp1 = temp2, temp1, PSR_IC, 1; \ 190*4882a593Smuzhiyun ;; \ 191*4882a593Smuzhiyun dep temp1 = temp2, temp1, PSR_IT, 1; \ 192*4882a593Smuzhiyun ;; \ 193*4882a593Smuzhiyun dep temp1 = temp2, temp1, PSR_DT, 1; \ 194*4882a593Smuzhiyun ;; \ 195*4882a593Smuzhiyun dep temp1 = temp2, temp1, PSR_RT, 1; \ 196*4882a593Smuzhiyun ;; \ 197*4882a593Smuzhiyun dep temp1 = temp2, temp1, PSR_BN, 1; \ 198*4882a593Smuzhiyun ;; \ 199*4882a593Smuzhiyun \ 200*4882a593Smuzhiyun mov cr.ipsr = temp1; \ 201*4882a593Smuzhiyun movl temp2 = start_addr; \ 202*4882a593Smuzhiyun ;; \ 203*4882a593Smuzhiyun mov cr.iip = temp2; \ 204*4882a593Smuzhiyun movl gp = __gp \ 205*4882a593Smuzhiyun ;; \ 206*4882a593Smuzhiyun DATA_PA_TO_VA(sp, temp1); \ 207*4882a593Smuzhiyun srlz.i; \ 208*4882a593Smuzhiyun ;; \ 209*4882a593Smuzhiyun nop 1; \ 210*4882a593Smuzhiyun nop 2; \ 211*4882a593Smuzhiyun nop 1; \ 212*4882a593Smuzhiyun rfi \ 213*4882a593Smuzhiyun ;; 214*4882a593Smuzhiyun 215*4882a593Smuzhiyun /* 216*4882a593Smuzhiyun * The MCA and INIT stacks in struct ia64_mca_cpu look like normal kernel 217*4882a593Smuzhiyun * stacks, except that the SAL/OS state and a switch_stack are stored near the 218*4882a593Smuzhiyun * top of the MCA/INIT stack. To support concurrent entry to MCA or INIT, as 219*4882a593Smuzhiyun * well as MCA over INIT, each event needs its own SAL/OS state. All entries 220*4882a593Smuzhiyun * are 16 byte aligned. 221*4882a593Smuzhiyun * 222*4882a593Smuzhiyun * +---------------------------+ 223*4882a593Smuzhiyun * | pt_regs | 224*4882a593Smuzhiyun * +---------------------------+ 225*4882a593Smuzhiyun * | switch_stack | 226*4882a593Smuzhiyun * +---------------------------+ 227*4882a593Smuzhiyun * | SAL/OS state | 228*4882a593Smuzhiyun * +---------------------------+ 229*4882a593Smuzhiyun * | 16 byte scratch area | 230*4882a593Smuzhiyun * +---------------------------+ <-------- SP at start of C MCA handler 231*4882a593Smuzhiyun * | ..... | 232*4882a593Smuzhiyun * +---------------------------+ 233*4882a593Smuzhiyun * | RBS for MCA/INIT handler | 234*4882a593Smuzhiyun * +---------------------------+ 235*4882a593Smuzhiyun * | struct task for MCA/INIT | 236*4882a593Smuzhiyun * +---------------------------+ <-------- Bottom of MCA/INIT stack 237*4882a593Smuzhiyun */ 238*4882a593Smuzhiyun 239*4882a593Smuzhiyun #define ALIGN16(x) ((x)&~15) 240*4882a593Smuzhiyun #define MCA_PT_REGS_OFFSET ALIGN16(KERNEL_STACK_SIZE-IA64_PT_REGS_SIZE) 241*4882a593Smuzhiyun #define MCA_SWITCH_STACK_OFFSET ALIGN16(MCA_PT_REGS_OFFSET-IA64_SWITCH_STACK_SIZE) 242*4882a593Smuzhiyun #define MCA_SOS_OFFSET ALIGN16(MCA_SWITCH_STACK_OFFSET-IA64_SAL_OS_STATE_SIZE) 243*4882a593Smuzhiyun #define MCA_SP_OFFSET ALIGN16(MCA_SOS_OFFSET-16) 244*4882a593Smuzhiyun 245*4882a593Smuzhiyun #endif /* _ASM_IA64_MCA_ASM_H */ 246