linux/arch/ia64/kernel/pal.S
<<
>>
Prefs
   1/*
   2 * PAL Firmware support
   3 * IA-64 Processor Programmers Reference Vol 2
   4 *
   5 * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
   6 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
   7 * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co
   8 *      David Mosberger <davidm@hpl.hp.com>
   9 *      Stephane Eranian <eranian@hpl.hp.com>
  10 *
  11 * 05/22/2000 eranian Added support for stacked register calls
  12 * 05/24/2000 eranian Added support for physical mode static calls
  13 */
  14
  15#include <asm/asmmacro.h>
  16#include <asm/processor.h>
  17
  18        .data
  19pal_entry_point:
  20        data8 ia64_pal_default_handler
  21        .text
  22
  23/*
  24 * Set the PAL entry point address.  This could be written in C code, but we
  25 * do it here to keep it all in one module (besides, it's so trivial that it's
  26 * not a big deal).
  27 *
  28 * in0          Address of the PAL entry point (text address, NOT a function
  29 *              descriptor).
  30 */
  31GLOBAL_ENTRY(ia64_pal_handler_init)
  32        alloc r3=ar.pfs,1,0,0,0
  33        movl r2=pal_entry_point
  34        ;;
  35        st8 [r2]=in0
  36        br.ret.sptk.many rp
  37END(ia64_pal_handler_init)
  38
  39/*
  40 * Default PAL call handler.  This needs to be coded in assembly because it
  41 * uses the static calling convention, i.e., the RSE may not be used and
  42 * calls are done via "br.cond" (not "br.call").
  43 */
  44GLOBAL_ENTRY(ia64_pal_default_handler)
  45        mov r8=-1
  46        br.cond.sptk.many rp
  47END(ia64_pal_default_handler)
  48
  49/*
  50 * Make a PAL call using the static calling convention.
  51 *
  52 * in0         Index of PAL service
  53 * in1 - in3   Remaining PAL arguments
  54 */
  55GLOBAL_ENTRY(ia64_pal_call_static)
  56        .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
  57        alloc loc1 = ar.pfs,4,5,0,0
  58        movl loc2 = pal_entry_point
  591:      {
  60          mov r28 = in0
  61          mov r29 = in1
  62          mov r8 = ip
  63        }
  64        ;;
  65        ld8 loc2 = [loc2]               // loc2 <- entry point
  66        adds r8 = 1f-1b,r8
  67        mov loc4=ar.rsc                 // save RSE configuration
  68        ;;
  69        mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
  70        mov loc3 = psr
  71        mov loc0 = rp
  72        .body
  73        mov r30 = in2
  74
  75        mov r31 = in3
  76        mov b7 = loc2
  77
  78        rsm psr.i
  79        ;;
  80        mov rp = r8
  81        br.cond.sptk.many b7
  821:      mov psr.l = loc3
  83        mov ar.rsc = loc4               // restore RSE configuration
  84        mov ar.pfs = loc1
  85        mov rp = loc0
  86        ;;
  87        srlz.d                          // seralize restoration of psr.l
  88        br.ret.sptk.many b0
  89END(ia64_pal_call_static)
  90
  91/*
  92 * Make a PAL call using the stacked registers calling convention.
  93 *
  94 * Inputs:
  95 *      in0         Index of PAL service
  96 *      in2 - in3   Remaining PAL arguments
  97 */
  98GLOBAL_ENTRY(ia64_pal_call_stacked)
  99        .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
 100        alloc loc1 = ar.pfs,4,4,4,0
 101        movl loc2 = pal_entry_point
 102
 103        mov r28  = in0                  // Index MUST be copied to r28
 104        mov out0 = in0                  // AND in0 of PAL function
 105        mov loc0 = rp
 106        .body
 107        ;;
 108        ld8 loc2 = [loc2]               // loc2 <- entry point
 109        mov out1 = in1
 110        mov out2 = in2
 111        mov out3 = in3
 112        mov loc3 = psr
 113        ;;
 114        rsm psr.i
 115        mov b7 = loc2
 116        ;;
 117        br.call.sptk.many rp=b7         // now make the call
 118.ret0:  mov psr.l  = loc3
 119        mov ar.pfs = loc1
 120        mov rp = loc0
 121        ;;
 122        srlz.d                          // serialize restoration of psr.l
 123        br.ret.sptk.many b0
 124END(ia64_pal_call_stacked)
 125
 126/*
 127 * Make a physical mode PAL call using the static registers calling convention.
 128 *
 129 * Inputs:
 130 *      in0         Index of PAL service
 131 *      in2 - in3   Remaining PAL arguments
 132 *
 133 * PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel.
 134 * So we don't need to clear them.
 135 */
 136#define PAL_PSR_BITS_TO_CLEAR                                                 \
 137        (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT  | IA64_PSR_DB | IA64_PSR_RT |\
 138         IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED |              \
 139         IA64_PSR_DFL | IA64_PSR_DFH)
 140
 141#define PAL_PSR_BITS_TO_SET                                                   \
 142        (IA64_PSR_BN)
 143
 144
 145GLOBAL_ENTRY(ia64_pal_call_phys_static)
 146        .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
 147        alloc loc1 = ar.pfs,4,7,0,0
 148        movl loc2 = pal_entry_point
 1491:      {
 150          mov r28  = in0                // copy procedure index
 151          mov r8   = ip                 // save ip to compute branch
 152          mov loc0 = rp                 // save rp
 153        }
 154        .body
 155        ;;
 156        ld8 loc2 = [loc2]               // loc2 <- entry point
 157        mov r29  = in1                  // first argument
 158        mov r30  = in2                  // copy arg2
 159        mov r31  = in3                  // copy arg3
 160        ;;
 161        mov loc3 = psr                  // save psr
 162        adds r8  = 1f-1b,r8             // calculate return address for call
 163        ;;
 164        mov loc4=ar.rsc                 // save RSE configuration
 165        dep.z loc2=loc2,0,61            // convert pal entry point to physical
 166        tpa r8=r8                       // convert rp to physical
 167        ;;
 168        mov b7 = loc2                   // install target to branch reg
 169        mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
 170        movl r16=PAL_PSR_BITS_TO_CLEAR
 171        movl r17=PAL_PSR_BITS_TO_SET
 172        ;;
 173        or loc3=loc3,r17                // add in psr the bits to set
 174        ;;
 175        andcm r16=loc3,r16              // removes bits to clear from psr
 176        br.call.sptk.many rp=ia64_switch_mode_phys
 177        mov rp = r8                     // install return address (physical)
 178        mov loc5 = r19
 179        mov loc6 = r20
 180        br.cond.sptk.many b7
 1811:
 182        mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
 183        mov r16=loc3                    // r16= original psr
 184        mov r19=loc5
 185        mov r20=loc6
 186        br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
 187        mov psr.l = loc3                // restore init PSR
 188
 189        mov ar.pfs = loc1
 190        mov rp = loc0
 191        ;;
 192        mov ar.rsc=loc4                 // restore RSE configuration
 193        srlz.d                          // seralize restoration of psr.l
 194        br.ret.sptk.many b0
 195END(ia64_pal_call_phys_static)
 196
 197/*
 198 * Make a PAL call using the stacked registers in physical mode.
 199 *
 200 * Inputs:
 201 *      in0         Index of PAL service
 202 *      in2 - in3   Remaining PAL arguments
 203 */
 204GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
 205        .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
 206        alloc   loc1 = ar.pfs,5,7,4,0
 207        movl    loc2 = pal_entry_point
 2081:      {
 209          mov r28  = in0                // copy procedure index
 210          mov loc0 = rp                 // save rp
 211        }
 212        .body
 213        ;;
 214        ld8 loc2 = [loc2]               // loc2 <- entry point
 215        mov loc3 = psr                  // save psr
 216        ;;
 217        mov loc4=ar.rsc                 // save RSE configuration
 218        dep.z loc2=loc2,0,61            // convert pal entry point to physical
 219        ;;
 220        mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
 221        movl r16=PAL_PSR_BITS_TO_CLEAR
 222        movl r17=PAL_PSR_BITS_TO_SET
 223        ;;
 224        or loc3=loc3,r17                // add in psr the bits to set
 225        mov b7 = loc2                   // install target to branch reg
 226        ;;
 227        andcm r16=loc3,r16              // removes bits to clear from psr
 228        br.call.sptk.many rp=ia64_switch_mode_phys
 229
 230        mov out0 = in0                  // first argument
 231        mov out1 = in1                  // copy arg2
 232        mov out2 = in2                  // copy arg3
 233        mov out3 = in3                  // copy arg3
 234        mov loc5 = r19
 235        mov loc6 = r20
 236
 237        br.call.sptk.many rp=b7         // now make the call
 238
 239        mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
 240        mov r16=loc3                    // r16= original psr
 241        mov r19=loc5
 242        mov r20=loc6
 243        br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
 244
 245        mov psr.l  = loc3               // restore init PSR
 246        mov ar.pfs = loc1
 247        mov rp = loc0
 248        ;;
 249        mov ar.rsc=loc4                 // restore RSE configuration
 250        srlz.d                          // seralize restoration of psr.l
 251        br.ret.sptk.many b0
 252END(ia64_pal_call_phys_stacked)
 253
 254/*
 255 * Save scratch fp scratch regs which aren't saved in pt_regs already
 256 * (fp10-fp15).
 257 *
 258 * NOTE: We need to do this since firmware (SAL and PAL) may use any of the
 259 * scratch regs fp-low partition.
 260 *
 261 * Inputs:
 262 *      in0     Address of stack storage for fp regs
 263 */
 264GLOBAL_ENTRY(ia64_save_scratch_fpregs)
 265        alloc r3=ar.pfs,1,0,0,0
 266        add r2=16,in0
 267        ;;
 268        stf.spill [in0] = f10,32
 269        stf.spill [r2]  = f11,32
 270        ;;
 271        stf.spill [in0] = f12,32
 272        stf.spill [r2]  = f13,32
 273        ;;
 274        stf.spill [in0] = f14,32
 275        stf.spill [r2]  = f15,32
 276        br.ret.sptk.many rp
 277END(ia64_save_scratch_fpregs)
 278
 279/*
 280 * Load scratch fp scratch regs (fp10-fp15)
 281 *
 282 * Inputs:
 283 *      in0     Address of stack storage for fp regs
 284 */
 285GLOBAL_ENTRY(ia64_load_scratch_fpregs)
 286        alloc r3=ar.pfs,1,0,0,0
 287        add r2=16,in0
 288        ;;
 289        ldf.fill  f10 = [in0],32
 290        ldf.fill  f11 = [r2],32
 291        ;;
 292        ldf.fill  f12 = [in0],32
 293        ldf.fill  f13 = [r2],32
 294        ;;
 295        ldf.fill  f14 = [in0],32
 296        ldf.fill  f15 = [r2],32
 297        br.ret.sptk.many rp
 298END(ia64_load_scratch_fpregs)
 299