1/* 2 * 3 * This file is subject to the terms and conditions of the GNU General Public 4 * License. See the file "COPYING" in the main directory of this archive 5 * for more details. 6 * 7 * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) 8 * 9 */ 10#include <asm/assembly.h> 11#include <asm/psw.h> 12 13 .section .bss 14 .export real_stack 15 .export real32_stack 16 .export real64_stack 17 .align 64 18real_stack: 19real32_stack: 20real64_stack: 21 .block 8192 22 23#ifdef __LP64__ 24# define REG_SZ 8 25#else 26# define REG_SZ 4 27#endif 28 29#define N_SAVED_REGS 9 30 31save_cr_space: 32 .block REG_SZ * N_SAVED_REGS 33save_cr_end: 34 35 36/************************ 32-bit real-mode calls ***********************/ 37/* This can be called in both narrow and wide kernels */ 38 39 .text 40 41 .export real32_call_asm 42 43 /* unsigned long real32_call_asm(unsigned int *sp, 44 * unsigned int *arg0p, 45 * unsigned int iodc_fn) 46 * sp is value of stack pointer to adopt before calling PDC (virt) 47 * arg0p points to where saved arg values may be found 48 * iodc_fn is the IODC function to call 49 */ 50 51real32_call_asm: 52 STREG %rp, -RP_OFFSET(%sp) /* save RP */ 53#ifdef __LP64__ 54 callee_save 55 ldo 2*REG_SZ(%sp), %sp /* room for a couple more saves */ 56 STREG %r27, -1*REG_SZ(%sp) 57 STREG %r29, -2*REG_SZ(%sp) 58#endif 59 STREG %sp, -REG_SZ(%arg0) /* save SP on real-mode stack */ 60 copy %arg0, %sp /* adopt the real-mode SP */ 61 62 /* save iodc_fn */ 63 copy %arg2, %r31 64 65 /* load up the arg registers from the saved arg area */ 66 /* 32-bit calling convention passes first 4 args in registers */ 67 ldw 0(%arg1), %arg0 /* note overwriting arg0 */ 68 ldw -8(%arg1), %arg2 69 ldw -12(%arg1), %arg3 70 ldw -4(%arg1), %arg1 /* obviously must do this one last! */ 71 72 tophys_r1 %sp 73 74 b,l rfi_virt2real,%r2 75 nop 76 77 b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ 78 nop 79 80#ifdef __LP64__ 81 rsm PSW_SM_W, %r0 /* go narrow */ 82#endif 83 84 load32 PA(ric_ret), %r2 85 bv 0(%r31) 86 nop 87ric_ret: 88#ifdef __LP64__ 89 ssm PSW_SM_W, %r0 /* go wide */ 90#endif 91 /* restore CRs before going virtual in case we page fault */ 92 b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */ 93 nop 94 95 b,l rfi_real2virt,%r2 96 nop 97 98 tovirt_r1 %sp 99 LDREG -REG_SZ(%sp), %sp /* restore SP */ 100#ifdef __LP64__ 101 LDREG -1*REG_SZ(%sp), %r27 102 LDREG -2*REG_SZ(%sp), %r29 103 ldo -2*REG_SZ(%sp), %sp 104 callee_rest 105#endif 106 LDREG -RP_OFFSET(%sp), %rp /* restore RP */ 107 bv 0(%rp) 108 nop 109 110 111# define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where) 112# define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r 113 114 .text 115save_control_regs: 116 load32 PA(save_cr_space), %r28 117 PUSH_CR(%cr24, %r28) 118 PUSH_CR(%cr25, %r28) 119 PUSH_CR(%cr26, %r28) 120 PUSH_CR(%cr27, %r28) 121 PUSH_CR(%cr28, %r28) 122 PUSH_CR(%cr29, %r28) 123 PUSH_CR(%cr30, %r28) 124 PUSH_CR(%cr31, %r28) 125 PUSH_CR(%cr15, %r28) 126 bv 0(%r2) 127 nop 128 129restore_control_regs: 130 load32 PA(save_cr_end), %r26 131 POP_CR(%cr15, %r26) 132 POP_CR(%cr31, %r26) 133 POP_CR(%cr30, %r26) 134 POP_CR(%cr29, %r26) 135 POP_CR(%cr28, %r26) 136 POP_CR(%cr27, %r26) 137 POP_CR(%cr26, %r26) 138 POP_CR(%cr25, %r26) 139 POP_CR(%cr24, %r26) 140 bv 0(%r2) 141 nop 142 143/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for 144 * more general-purpose use by the several places which need RFIs 145 */ 146 .align 128 147 .text 148rfi_virt2real: 149 /* switch to real mode... */ 150 ssm 0,0 /* See "relied upon translation" */ 151 nop /* PA 2.0 Arch. F-5 */ 152 nop 153 nop 154 nop 155 nop 156 nop 157 nop 158 nop 159 160 rsm (PSW_SM_Q|PSW_SM_I),%r0 /* disable Q & I bits to load iia queue */ 161 mtctl %r0, %cr17 /* Clear IIASQ tail */ 162 mtctl %r0, %cr17 /* Clear IIASQ head */ 163 load32 PA(rfi_v2r_1), %r1 164 mtctl %r1, %cr18 /* IIAOQ head */ 165 ldo 4(%r1), %r1 166 mtctl %r1, %cr18 /* IIAOQ tail */ 167 load32 REAL_MODE_PSW, %r1 168 mtctl %r1, %cr22 169 rfi 170 171 nop 172 nop 173 nop 174 nop 175 nop 176 nop 177 nop 178 nop 179rfi_v2r_1: 180 tophys_r1 %r2 181 bv 0(%r2) 182 nop 183 184 .text 185 .align 128 186rfi_real2virt: 187 ssm 0,0 /* See "relied upon translation" */ 188 nop /* PA 2.0 Arch. F-5 */ 189 nop 190 nop 191 nop 192 nop 193 nop 194 nop 195 nop 196 197 rsm PSW_SM_Q,%r0 /* disable Q bit to load iia queue */ 198 mtctl %r0, %cr17 /* Clear IIASQ tail */ 199 mtctl %r0, %cr17 /* Clear IIASQ head */ 200 load32 (rfi_r2v_1), %r1 201 mtctl %r1, %cr18 /* IIAOQ head */ 202 ldo 4(%r1), %r1 203 mtctl %r1, %cr18 /* IIAOQ tail */ 204 load32 KERNEL_PSW, %r1 205 mtctl %r1, %cr22 206 rfi 207 208 nop 209 nop 210 nop 211 nop 212 nop 213 nop 214 nop 215 nop 216rfi_r2v_1: 217 tovirt_r1 %r2 218 bv 0(%r2) 219 nop 220 221#ifdef __LP64__ 222 223/************************ 64-bit real-mode calls ***********************/ 224/* This is only usable in wide kernels right now and will probably stay so */ 225 .text 226 .export real64_call_asm 227 /* unsigned long real64_call_asm(unsigned long *sp, 228 * unsigned long *arg0p, 229 * unsigned long fn) 230 * sp is value of stack pointer to adopt before calling PDC (virt) 231 * arg0p points to where saved arg values may be found 232 * iodc_fn is the IODC function to call 233 */ 234real64_call_asm: 235 std %rp, -0x10(%sp) /* save RP */ 236 std %sp, -8(%arg0) /* save SP on real-mode stack */ 237 copy %arg0, %sp /* adopt the real-mode SP */ 238 239 /* save fn */ 240 copy %arg2, %r31 241 242 /* set up the new ap */ 243 ldo 64(%arg1), %r29 244 245 /* load up the arg registers from the saved arg area */ 246 /* 32-bit calling convention passes first 4 args in registers */ 247 ldd 0*REG_SZ(%arg1), %arg0 /* note overwriting arg0 */ 248 ldd 2*REG_SZ(%arg1), %arg2 249 ldd 3*REG_SZ(%arg1), %arg3 250 ldd 4*REG_SZ(%arg1), %r22 251 ldd 5*REG_SZ(%arg1), %r21 252 ldd 6*REG_SZ(%arg1), %r20 253 ldd 7*REG_SZ(%arg1), %r19 254 ldd 1*REG_SZ(%arg1), %arg1 /* do this one last! */ 255 256 tophys_r1 %sp 257 258 b,l rfi_virt2real,%r2 259 nop 260 261 b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ 262 nop 263 264 load32 PA(r64_ret), %r2 265 bv 0(%r31) 266 nop 267r64_ret: 268 /* restore CRs before going virtual in case we page fault */ 269 b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */ 270 nop 271 272 b,l rfi_real2virt,%r2 273 nop 274 275 tovirt_r1 %sp 276 ldd -8(%sp), %sp /* restore SP */ 277 ldd -0x10(%sp), %rp /* restore RP */ 278 bv 0(%rp) 279 nop 280 281#endif 282 283 .export pc_in_user_space 284 .text 285 /* Doesn't belong here but I couldn't find a nicer spot. */ 286 /* Should never get called, only used by profile stuff in time.c */ 287pc_in_user_space: 288 bv,n 0(%rp) 289 nop 290 291 292 .export __canonicalize_funcptr_for_compare 293 .text 294 /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html 295 ** GCC 3.3 and later has a new function in libgcc.a for 296 ** comparing function pointers. 297 */ 298__canonicalize_funcptr_for_compare: 299#ifdef __LP64__ 300 bve (%r2) 301#else 302 bv %r0(%r2) 303#endif 304 copy %r26,%r28 305