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